feat(behaviors): Allow mod-morph to swallow mods

Revert "fix(hid): Implicit mods on non-key page events"

This reverts commit 6ef1e7034f.

masked mods

Unrevert "fix(hid): Implicit mods on non-key page events"

Fix docs

Lint code with clang-format
This commit is contained in:
Kostas Karachalios 2022-02-03 19:00:03 +01:00
parent edbbbc7540
commit 2cac694fa2
5 changed files with 37 additions and 3 deletions

View file

@ -14,3 +14,6 @@ properties:
mods:
type: int
required: true
masked_mods:
type: int
required: false

View file

@ -229,6 +229,8 @@ int zmk_hid_register_mods(zmk_mod_flags_t explicit_modifiers);
int zmk_hid_unregister_mods(zmk_mod_flags_t explicit_modifiers);
int zmk_hid_implicit_modifiers_press(zmk_mod_flags_t implicit_modifiers);
int zmk_hid_implicit_modifiers_release();
int zmk_hid_masked_modifiers_set(zmk_mod_flags_t masked_modifiers);
int zmk_hid_masked_modifiers_clear();
int zmk_hid_keyboard_press(zmk_key_t key);
int zmk_hid_keyboard_release(zmk_key_t key);
void zmk_hid_keyboard_clear();

View file

@ -27,6 +27,7 @@ struct behavior_mod_morph_config {
struct zmk_behavior_binding normal_binding;
struct zmk_behavior_binding morph_binding;
zmk_mod_flags_t mods;
zmk_mod_flags_t masked_mods;
};
struct behavior_mod_morph_data {
@ -45,6 +46,8 @@ static int on_mod_morph_binding_pressed(struct zmk_behavior_binding *binding,
}
if (zmk_hid_get_explicit_mods() & cfg->mods) {
zmk_mod_flags_t trigger_mods = zmk_hid_get_explicit_mods() & cfg->mods;
zmk_hid_masked_modifiers_set(cfg->masked_mods);
data->pressed_binding = (struct zmk_behavior_binding *)&cfg->morph_binding;
} else {
data->pressed_binding = (struct zmk_behavior_binding *)&cfg->normal_binding;
@ -64,6 +67,7 @@ static int on_mod_morph_binding_released(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding *pressed_binding = data->pressed_binding;
data->pressed_binding = NULL;
zmk_hid_masked_modifiers_clear();
return behavior_keymap_binding_released(pressed_binding, event);
}
@ -88,6 +92,8 @@ static int behavior_mod_morph_init(const struct device *dev) { return 0; }
.normal_binding = _TRANSFORM_ENTRY(0, n), \
.morph_binding = _TRANSFORM_ENTRY(1, n), \
.mods = DT_INST_PROP(n, mods), \
.masked_mods = COND_CODE_0(DT_INST_NODE_HAS_PROP(n, masked_mods), (0), \
(DT_INST_PROP(n, masked_mods))), \
}; \
static struct behavior_mod_morph_data behavior_mod_morph_data_##n = {}; \
DEVICE_DT_INST_DEFINE(n, behavior_mod_morph_init, device_pm_control_nop, \

View file

@ -19,10 +19,12 @@ static struct zmk_hid_consumer_report consumer_report = {.report_id = 2, .body =
// Only release the modifier if the count is 0.
static int explicit_modifier_counts[8] = {0, 0, 0, 0, 0, 0, 0, 0};
static zmk_mod_flags_t explicit_modifiers = 0;
static zmk_mod_flags_t implicit_modifiers = 0;
static zmk_mod_flags_t masked_modifiers = 0;
#define SET_MODIFIERS(mods) \
{ \
keyboard_report.body.modifiers = mods; \
keyboard_report.body.modifiers = (mods | implicit_modifiers) & ~masked_modifiers; \
LOG_DBG("Modifiers set to 0x%02X", keyboard_report.body.modifiers); \
}
@ -136,13 +138,29 @@ static inline int deselect_keyboard_usage(zmk_key_t usage) {
} \
}
int zmk_hid_implicit_modifiers_press(zmk_mod_flags_t implicit_modifiers) {
int zmk_hid_implicit_modifiers_press(zmk_mod_flags_t new_implicit_modifiers) {
implicit_modifiers = new_implicit_modifiers;
zmk_mod_flags_t current = GET_MODIFIERS;
SET_MODIFIERS(explicit_modifiers | implicit_modifiers);
SET_MODIFIERS(explicit_modifiers);
return current == GET_MODIFIERS ? 0 : 1;
}
int zmk_hid_implicit_modifiers_release() {
implicit_modifiers = 0;
zmk_mod_flags_t current = GET_MODIFIERS;
SET_MODIFIERS(explicit_modifiers);
return current == GET_MODIFIERS ? 0 : 1;
}
int zmk_hid_masked_modifiers_set(zmk_mod_flags_t new_masked_modifiers) {
masked_modifiers = new_masked_modifiers;
zmk_mod_flags_t current = GET_MODIFIERS;
SET_MODIFIERS(explicit_modifiers);
return current == GET_MODIFIERS ? 0 : 1;
}
int zmk_hid_masked_modifiers_clear() {
masked_modifiers = 0;
zmk_mod_flags_t current = GET_MODIFIERS;
SET_MODIFIERS(explicit_modifiers);
return current == GET_MODIFIERS ? 0 : 1;

View file

@ -16,6 +16,10 @@ The Mod-Morph behavior acts as one of two keycodes, depending on if the required
When the modifier is being held it is sent along with the morphed keycode. This can cause problems when the morphed keycode and modifier have an existing relationship (such as `shift-delete` or `ctrl-v` on many operating systems).
As a remedy, you can add the optional attribute `masked_mods`, containing
the bitwise OR of the modifiers that should be disabled while the key is held,
so that they are not included in the report sent to the host.
### Configuration
An example of how to implement the mod-morph "Grave Escape":
@ -29,6 +33,7 @@ An example of how to implement the mod-morph "Grave Escape":
#binding-cells = <0>;
bindings = <&kp ESC>, <&kp GRAVE>;
mods = <(MOD_LGUI|MOD_LSFT|MOD_RGUI|MOD_RSFT)>;
masked_mods = <(MOD_LGUI|MOD_LSFT)>; // don't send left modifiers
};
};