Skip to content

Commit

Permalink
fix(behaviors): Fix bug in nested sticky keys
Browse files Browse the repository at this point in the history
If multiple sticky keys with quick release were nested, only the first one
was properly released. This fix makes sure all of them are released properly.

Fixes zmkfirmware#1149
  • Loading branch information
okke-formsma authored and petejohanson committed Mar 16, 2022
1 parent b3591d2 commit 5bf7526
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 3 deletions.
14 changes: 11 additions & 3 deletions app/src/behaviors/behavior_sticky_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@ static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) {
if (ev == NULL) {
return ZMK_EV_EVENT_BUBBLE;
}

// keep track whether the event has been reraised, so we only reraise it once
bool event_reraised = false;
for (int i = 0; i < ZMK_BHV_STICKY_KEY_MAX_HELD; i++) {
struct active_sticky_key *sticky_key = &active_sticky_keys[i];
if (sticky_key->position == ZMK_BHV_STICKY_KEY_POSITION_FREE) {
Expand Down Expand Up @@ -223,10 +226,12 @@ 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);
// immediately release the sticky key after the key press is handled.
if (!event_reraised) {
ZMK_EVENT_RAISE_AFTER(eh, behavior_sticky_key);
event_reraised = true;
}
release_sticky_key_behavior(sticky_key, ev->timestamp);
return ZMK_EV_EVENT_CAPTURED;
}
}
sticky_key->modified_key_usage_page = ev->usage_page;
Expand All @@ -240,6 +245,9 @@ static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) {
}
}
}
if (event_reraised) {
return ZMK_EV_EVENT_CAPTURED;
}
return ZMK_EV_EVENT_BUBBLE;
}

Expand Down
1 change: 1 addition & 0 deletions app/tests/sticky-keys/10-sl-sl-kp/events.patterns
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
s/.*hid_listener_keycode_//p
8 changes: 8 additions & 0 deletions app/tests/sticky-keys/10-sl-sl-kp/keycode_events.snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
pressed: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00
released: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00
pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
pressed: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00
released: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00
pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
65 changes: 65 additions & 0 deletions app/tests/sticky-keys/10-sl-sl-kp/native_posix.keymap
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan-mock.h>

/*
sticky layers should quick-release.
Thus, the second keypress should be on the default layer, not on the lower_layer.
*/

/ {
keymap {
compatible = "zmk,keymap";
label ="Default keymap";

default_layer {
bindings = <
&sl 1 &kp A
&none &none>;
};

layer_1 {
bindings = <
&sl 2 &none
&none &none>;
};

layer_2 {
bindings = <
&none &kp NUM_1
&none &none>;
};
};
};

&kscan {
events = <
/* press sl 1 */
ZMK_MOCK_PRESS(0,0,10)
ZMK_MOCK_RELEASE(0,0,10)
/* press sl 2 */
ZMK_MOCK_PRESS(0,0,10)
ZMK_MOCK_RELEASE(0,0,10)
/* press 1 */
ZMK_MOCK_PRESS(0,1,10)
ZMK_MOCK_RELEASE(0,1,10)
/* press A */
ZMK_MOCK_PRESS(0,1,10)
ZMK_MOCK_RELEASE(0,1,10)

/* repeat test to check if cleanup is done correctly */
/* press sl 1 */
ZMK_MOCK_PRESS(0,0,10)
ZMK_MOCK_RELEASE(0,0,10)
/* press sl 2 */
ZMK_MOCK_PRESS(0,0,10)
ZMK_MOCK_RELEASE(0,0,10)
/* press 1 */
ZMK_MOCK_PRESS(0,1,10)
ZMK_MOCK_RELEASE(0,1,10)
/* press A */
ZMK_MOCK_PRESS(0,1,10)
ZMK_MOCK_RELEASE(0,1,10)

>;
};

0 comments on commit 5bf7526

Please sign in to comment.