From cb50620f9fd3d0766054d573c36bd12f4053da59 Mon Sep 17 00:00:00 2001 From: Marco Sterbik Date: Mon, 21 Feb 2022 22:56:19 +0100 Subject: [PATCH 1/6] Behaviours: add key-tap behavior This is a solution for keys that use the same keycode but different modifiers (see #1076 as an example, also { and [ or ] and } might occur quite often). The new key behavior introduced here is a simple tap that immediately sends a release event, so that a keypress of the same keycode with a different modifier can be detected immediately. --- app/CMakeLists.txt | 1 + app/dts/behaviors.dtsi | 3 +- app/dts/behaviors/key_tap.dtsi | 15 ++++++ .../behaviors/zmk,behavior-key-tap.yaml | 8 ++++ app/src/behaviors/behavior_key_tap.c | 47 +++++++++++++++++++ 5 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 app/dts/behaviors/key_tap.dtsi create mode 100644 app/dts/bindings/behaviors/zmk,behavior-key-tap.yaml create mode 100644 app/src/behaviors/behavior_key_tap.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 4b61fc72..0e707dc1 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..fd1d68f9 --- /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 = 0; + ret = ZMK_EVENT_RAISE(zmk_keycode_state_changed_from_encoded(binding->param1, true, event.timestamp)); + if(ret != 0) { + return 0; + } + 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) From 919178a38ea2804c4a123b0fa9e70e2687accaed Mon Sep 17 00:00:00 2001 From: Marco Sterbik Date: Mon, 21 Feb 2022 23:25:36 +0100 Subject: [PATCH 2/6] Behaviors: add tests for key-tap Test covers left brace/bracket combination. --- app/tests/key-tap/behavior_keymap.dtsi | 17 +++++++++++++++++ .../key-tap/kt-press-release/events.patterns | 1 + .../kt-press-release/keycode_events.snapshot | 4 ++++ .../kt-press-release/native_posix.keymap | 10 ++++++++++ 4 files changed, 32 insertions(+) create mode 100644 app/tests/key-tap/behavior_keymap.dtsi create mode 100644 app/tests/key-tap/kt-press-release/events.patterns create mode 100644 app/tests/key-tap/kt-press-release/keycode_events.snapshot create mode 100644 app/tests/key-tap/kt-press-release/native_posix.keymap 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) + >; +}; From b9645e74f4832b08c88bc9d3ab05d2baf5a388f4 Mon Sep 17 00:00:00 2001 From: Marco Sterbik Date: Mon, 14 Mar 2022 22:33:42 +0100 Subject: [PATCH 3/6] behaviour key-tap: fix returned error-codes --- app/src/behaviors/behavior_key_tap.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/behaviors/behavior_key_tap.c b/app/src/behaviors/behavior_key_tap.c index fd1d68f9..4dc8f039 100644 --- a/app/src/behaviors/behavior_key_tap.c +++ b/app/src/behaviors/behavior_key_tap.c @@ -21,10 +21,9 @@ 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 = 0; - ret = ZMK_EVENT_RAISE(zmk_keycode_state_changed_from_encoded(binding->param1, true, event.timestamp)); + int ret = ZMK_EVENT_RAISE(zmk_keycode_state_changed_from_encoded(binding->param1, true, event.timestamp)); if(ret != 0) { - return 0; + return ret; } return ZMK_EVENT_RAISE(zmk_keycode_state_changed_from_encoded(binding->param1, false, event.timestamp)); From 79eb001e0a84be0720888b236d68cc7942b553fa Mon Sep 17 00:00:00 2001 From: Marco Sterbik Date: Mon, 4 Apr 2022 22:10:20 +0200 Subject: [PATCH 4/6] behaviour-keytap: apply clang-format --- app/src/behaviors/behavior_key_tap.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/behaviors/behavior_key_tap.c b/app/src/behaviors/behavior_key_tap.c index 4dc8f039..105908a1 100644 --- a/app/src/behaviors/behavior_key_tap.c +++ b/app/src/behaviors/behavior_key_tap.c @@ -21,12 +21,13 @@ 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) { + 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)); - + 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, @@ -39,7 +40,7 @@ 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, \ + 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); From 76689e70f7079c64a08446c7fbbfbcc1a3ce5f9e Mon Sep 17 00:00:00 2001 From: Marco Sterbik Date: Thu, 26 May 2022 22:12:38 +0200 Subject: [PATCH 5/6] behaviour-keytap: add documentation --- docs/docs/behaviors/key-tap.md | 27 +++++++++++++++++++++++++++ docs/sidebars.js | 1 + 2 files changed, 28 insertions(+) create mode 100644 docs/docs/behaviors/key-tap.md diff --git a/docs/docs/behaviors/key-tap.md b/docs/docs/behaviors/key-tap.md new file mode 100644 index 00000000..5b8ecef0 --- /dev/null +++ b/docs/docs/behaviors/key-tap.md @@ -0,0 +1,27 @@ +--- +title: Key Tap Behavior +sidebar_label: Key Tap +--- + +## Summary + +The key tap behavior is a combination of key press and release on just pressing the key. + +All keycodes including modifiers can be used the same way as with the key press behavior (so standard keycodes are sent for press/release). + +It is usefull if you want to make a layout that has the same keycode with and without a modifier close together, e.g. `[` and `{`. + +Since `LBRC` is basically just `LSHIFT(LBKT)` it can happen, that you still hold `{` while using `[` which leads to a missed keycode since the base-key is still pressed. + +By immediately releasing the key with key tap this is circumvented. + +### Behavior Binding + +- Reference: `&kt` +- Parameter: The keycode usage ID from the usage page, e.g. `LBTK` or `A` + +Example: + +``` +&kt LBKT +``` diff --git a/docs/sidebars.js b/docs/sidebars.js index e7d05850..643a5420 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -34,6 +34,7 @@ module.exports = { "behaviors/tap-dance", "behaviors/caps-word", "behaviors/key-repeat", + "behaviors/key-tap", "behaviors/reset", "behaviors/bluetooth", "behaviors/outputs", From c0fce25b31625d31eb1cbc0a4401fa203634fb92 Mon Sep 17 00:00:00 2001 From: marcoster Date: Sat, 4 Jun 2022 18:00:39 +0200 Subject: [PATCH 6/6] behaviour-keytap: improve documentation after feedback Thanks to @dxmh for the great feedback. Co-authored-by: Dom H --- docs/docs/behaviors/key-tap.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/docs/behaviors/key-tap.md b/docs/docs/behaviors/key-tap.md index 5b8ecef0..dc95b115 100644 --- a/docs/docs/behaviors/key-tap.md +++ b/docs/docs/behaviors/key-tap.md @@ -5,20 +5,24 @@ sidebar_label: Key Tap ## Summary -The key tap behavior is a combination of key press and release on just pressing the key. +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 including modifiers can be used the same way as with the key press behavior (so standard keycodes are sent for press/release). +All [keycodes](../codes/index.mdx) (including modifiers) can be used the same way as with the [key press](key-press.md) behavior. -It is usefull if you want to make a layout that has the same keycode with and without a modifier close together, e.g. `[` and `{`. +:::tip -Since `LBRC` is basically just `LSHIFT(LBKT)` it can happen, that you still hold `{` while using `[` which leads to a missed keycode since the base-key is still pressed. +Key tap is useful if you experience issues when rolling keys that share a base keycode. -By immediately releasing the key with key tap this is circumvented. +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. `LBTK` or `A` +- Parameter: The keycode usage ID from the usage page, e.g. `PLUS` or `A` Example: