Fix mod-morph
This is an updated version of https://github.com/zmkfirmware/zmk/pull/1114. It builds on @aumuell's masked-mods fix 241f82e6cefc3661de4698a6eef4ee511fa8580b. Notable differences with respect to https://github.com/zmkfirmware/zmk/pull/1114 are:
- fixes issue where modifiers in the binding are ignored by allowing
masked-modsto be overwritten by implicit mods - fixes issue where masked mods does not work when the behavior is bind to a hold-tap
- fixes issue where masked mods are unmasked before key release
- added unit tests
- added documentation
- new default: modifiers won't be passed along with the morphed binding (fixes https://github.com/zmkfirmware/zmk/issues/683 without the need to specify
masked-mods)
Important change: the config option has been renamed from masked_mods to masked-mods
Quick ping @petejohanson: I think this is ready for review if you get the chance. Below a quick summary of the technical implementation to, hopefully, facilitate the review process.
At its core, the PR does a bit of refactoring of how mods are handled in hid.c. In addition to explicit_modifiers, it adds two new persistent state variables: implicit_modifiers and masked_modifiers.
Any change in modifiers; i.e., any call to one of the following functions:
zmk_hid_register_mod()zmk_hid_unregister_mod()zmk_hid_implicit_modifiers_press()zmk_hid_implicit_modifiers_release()zmk_hid_masked_modifiers_set()zmk_hid_masked_modifiers_clear()
updates the corresponding state variable and then calls SET_MODIFIERS(). The SET_MODIFIERS() macro in turn sets the modifiers as follows:
keyboard_report.body.modifiers = (mods & ~masked_modifiers) | implicit_modifiers;
Using the refactored hid functions, behavior_mod_morph.c updates the state of masked_modifiers when a mod-morph is triggered (by default to the mods that trigger it). And after the mod-morph is done, it clears masked_modifiers.
lgtm