diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 3da50b57..b21a5a34 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -39,6 +39,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) target_sources(app PRIVATE src/hid.c) target_sources(app PRIVATE src/behaviors/behavior_key_press.c) target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_KEY_TOGGLE app PRIVATE src/behaviors/behavior_key_toggle.c) + target_sources(app PRIVATE src/behaviors/behavior_key_tap.c) target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c) target_sources(app PRIVATE src/behaviors/behavior_sticky_key.c) target_sources(app PRIVATE src/behaviors/behavior_caps_word.c) diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi index b3502cbb..4f156896 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -18,4 +19,4 @@ #include #include #include -#include \ No newline at end of file +#include diff --git a/app/dts/behaviors/key_tap.dtsi b/app/dts/behaviors/key_tap.dtsi new file mode 100644 index 00000000..c6635d4c --- /dev/null +++ b/app/dts/behaviors/key_tap.dtsi @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + behaviors { + /omit-if-no-ref/ kt: behavior_key_tap { + compatible = "zmk,behavior-key-tap"; + label = "KEY_TAP"; + #binding-cells = <1>; + }; + }; +}; diff --git a/app/dts/bindings/behaviors/zmk,behavior-key-tap.yaml b/app/dts/bindings/behaviors/zmk,behavior-key-tap.yaml new file mode 100644 index 00000000..b8bec655 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-key-tap.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Key press/immediate release behavior + +compatible: "zmk,behavior-key-tap" + +include: one_param.yaml diff --git a/app/src/behaviors/behavior_key_tap.c b/app/src/behaviors/behavior_key_tap.c new file mode 100644 index 00000000..105908a1 --- /dev/null +++ b/app/src/behaviors/behavior_key_tap.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_key_tap + +#include +#include +#include + +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +static int behavior_key_tap_init(const struct device *dev) { return 0; }; + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + int ret = ZMK_EVENT_RAISE( + zmk_keycode_state_changed_from_encoded(binding->param1, true, event.timestamp)); + if (ret != 0) { + return ret; + } + return ZMK_EVENT_RAISE( + zmk_keycode_state_changed_from_encoded(binding->param1, false, event.timestamp)); +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + return 0; +} + +static const struct behavior_driver_api behavior_key_tap_driver_api = { + .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; + +#define KT_INST(n) \ + DEVICE_DT_INST_DEFINE(n, behavior_key_tap_init, device_pm_control_nop, NULL, NULL, \ + APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &behavior_key_tap_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KT_INST) diff --git a/app/tests/key-tap/behavior_keymap.dtsi b/app/tests/key-tap/behavior_keymap.dtsi new file mode 100644 index 00000000..3a79bc4f --- /dev/null +++ b/app/tests/key-tap/behavior_keymap.dtsi @@ -0,0 +1,17 @@ +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &kt LBRC &kt LBKT + &none &none + >; + }; + }; +}; diff --git a/app/tests/key-tap/kt-press-release/events.patterns b/app/tests/key-tap/kt-press-release/events.patterns new file mode 100644 index 00000000..833100f6 --- /dev/null +++ b/app/tests/key-tap/kt-press-release/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/key-tap/kt-press-release/keycode_events.snapshot b/app/tests/key-tap/kt-press-release/keycode_events.snapshot new file mode 100644 index 00000000..3e8bb3e8 --- /dev/null +++ b/app/tests/key-tap/kt-press-release/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x2f implicit_mods 0x02 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x2f implicit_mods 0x02 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x2f implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x2f implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/key-tap/kt-press-release/native_posix.keymap b/app/tests/key-tap/kt-press-release/native_posix.keymap new file mode 100644 index 00000000..9c592679 --- /dev/null +++ b/app/tests/key-tap/kt-press-release/native_posix.keymap @@ -0,0 +1,10 @@ +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; diff --git a/docs/docs/behaviors/key-tap.md b/docs/docs/behaviors/key-tap.md new file mode 100644 index 00000000..dc95b115 --- /dev/null +++ b/docs/docs/behaviors/key-tap.md @@ -0,0 +1,31 @@ +--- +title: Key Tap Behavior +sidebar_label: Key Tap +--- + +## Summary + +The key tap behavior is similar to [key press](key-press.md), but key tap will press _and then immediately release_ the key (even if the physical key remains held down). + +All [keycodes](../codes/index.mdx) (including modifiers) can be used the same way as with the [key press](key-press.md) behavior. + +:::tip + +Key tap is useful if you experience issues when rolling keys that share a base keycode. + +For example, a common programming bigram is `+=`. Behind the scenes, `+` is produced with `SHIFT` and `=`. So typing the keys `+` and `=` too quickly can sometimes result in one of them being ignored since the base-key is still pressed. However, by immediately releasing the key with key tap this issue is circumvented. + +See [zmkfirmware/zmk #1076](https://github.com/zmkfirmware/zmk/issues/1076) for a thread tracking this. + +::: + +### Behavior Binding + +- Reference: `&kt` +- Parameter: The keycode usage ID from the usage page, e.g. `PLUS` or `A` + +Example: + +``` +&kt LBKT +``` diff --git a/docs/sidebars.js b/docs/sidebars.js index a52f3302..d1d888e5 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -35,6 +35,7 @@ module.exports = { "behaviors/tap-dance", "behaviors/caps-word", "behaviors/key-repeat", + "behaviors/key-tap", "behaviors/reset", "behaviors/bluetooth", "behaviors/outputs",