diff --git a/app/src/combo.c b/app/src/combo.c index 72535b29..16091cdd 100644 --- a/app/src/combo.c +++ b/app/src/combo.c @@ -188,8 +188,15 @@ static int64_t first_candidate_timeout() { static inline bool candidate_is_completely_pressed(struct combo_cfg *candidate) { // this code assumes set(pressed_keys) <= set(candidate->key_positions) // this invariant is enforced by filter_candidates - // the only thing we need to do is check if len(pressed_keys) == len(combo->key_positions) - return pressed_keys[candidate->key_position_len - 1] != NULL; + // since events may have been reraised after clearing one or more slots at + // the start of pressed_keys (see: release_pressed_keys), we have to check + // that each key needed to trigger the combo was pressed, not just the last. + for (int i = 0; i < candidate->key_position_len; i++) { + if (pressed_keys[i] == NULL) { + return false; + } + } + return true; } static int cleanup(); @@ -496,4 +503,4 @@ static int combo_init() { SYS_INIT(combo_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); -#endif \ No newline at end of file +#endif diff --git a/app/tests/combo/press-release-long-combo-wrong-last-key/events.patterns b/app/tests/combo/press-release-long-combo-wrong-last-key/events.patterns new file mode 100644 index 00000000..b1342af4 --- /dev/null +++ b/app/tests/combo/press-release-long-combo-wrong-last-key/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/combo/press-release-long-combo-wrong-last-key/keycode_events.snapshot b/app/tests/combo/press-release-long-combo-wrong-last-key/keycode_events.snapshot new file mode 100644 index 00000000..d1b9db96 --- /dev/null +++ b/app/tests/combo/press-release-long-combo-wrong-last-key/keycode_events.snapshot @@ -0,0 +1,6 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/press-release-long-combo-wrong-last-key/native_posix.keymap b/app/tests/combo/press-release-long-combo-wrong-last-key/native_posix.keymap new file mode 100644 index 00000000..b8117187 --- /dev/null +++ b/app/tests/combo/press-release-long-combo-wrong-last-key/native_posix.keymap @@ -0,0 +1,37 @@ +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <80>; + key-positions = <0 1 2>; + bindings = <&kp Z>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp C &kp D + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,100) + ZMK_MOCK_RELEASE(0,1,100) + ZMK_MOCK_RELEASE(0,0,100) + >; +};