From de4979bf58a628692547b056c80a75678005a647 Mon Sep 17 00:00:00 2001 From: Okke Formsma Date: Mon, 5 Apr 2021 20:07:39 +0200 Subject: [PATCH] fix(behaviors): Fix sticky keys quick-release for normal keypresses Quick release for sticky keys failed for non-layer keys. The sticky key was released just before the key that was supposed to be modified was handled. The issue was caused by an error in the sticky key logic, which released the sticky key before handling the key up event. Fixes #696. --- app/src/behaviors/behavior_sticky_key.c | 11 +++++--- .../events.patterns | 1 + .../keycode_events.snapshot | 10 +++++++ .../native_posix.keymap | 26 +++++++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/events.patterns create mode 100644 app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/keycode_events.snapshot create mode 100644 app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/native_posix.keymap diff --git a/app/src/behaviors/behavior_sticky_key.c b/app/src/behaviors/behavior_sticky_key.c index 20af93a8..40ca3f89 100644 --- a/app/src/behaviors/behavior_sticky_key.c +++ b/app/src/behaviors/behavior_sticky_key.c @@ -177,6 +177,11 @@ static const struct behavior_driver_api behavior_sticky_key_driver_api = { .binding_released = on_sticky_key_binding_released, }; +static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh); + +ZMK_LISTENER(behavior_sticky_key, sticky_key_keycode_state_changed_listener); +ZMK_SUBSCRIPTION(behavior_sticky_key, zmk_keycode_state_changed); + static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) { struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh); if (ev == NULL) { @@ -212,7 +217,10 @@ static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) { if (sticky_key->timer_started) { stop_timer(sticky_key); if (sticky_key->config->quick_release) { + // continue processing the event. Release the sticky key afterwards. + ZMK_EVENT_RAISE_AFTER(eh, behavior_sticky_key); release_sticky_key_behavior(sticky_key, ev->timestamp); + return ZMK_EV_EVENT_CAPTURED; } } sticky_key->modified_key_usage_page = ev->usage_page; @@ -229,9 +237,6 @@ static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) { return ZMK_EV_EVENT_BUBBLE; } -ZMK_LISTENER(behavior_sticky_key, sticky_key_keycode_state_changed_listener); -ZMK_SUBSCRIPTION(behavior_sticky_key, zmk_keycode_state_changed); - void behavior_sticky_key_timer_handler(struct k_work *item) { struct active_sticky_key *sticky_key = CONTAINER_OF(item, struct active_sticky_key, release_timer); diff --git a/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/events.patterns b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/events.patterns new file mode 100644 index 00000000..833100f6 --- /dev/null +++ b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/keycode_events.snapshot b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/keycode_events.snapshot new file mode 100644 index 00000000..c85d8b49 --- /dev/null +++ b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/keycode_events.snapshot @@ -0,0 +1,10 @@ +pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/native_posix.keymap b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/native_posix.keymap new file mode 100644 index 00000000..33115453 --- /dev/null +++ b/app/tests/sticky-keys/2-os-dn-up-kcdn-kcup-quick-release/native_posix.keymap @@ -0,0 +1,26 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&sk { + quick-release; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + /* second key is pressed shortly after the first. It should not be capitalized. */ + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(1,1,10) + + /* repeat test to check if cleanup is done correctly */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file