From 9f1a7de44387e6e61b8fcd0cf23001d536a4416b Mon Sep 17 00:00:00 2001 From: Sviatoslav Bulbakha Date: Wed, 30 Oct 2024 11:46:50 +0400 Subject: [PATCH] PR 2494: Fix other key releasing breaking combo Squashed commit of the following: commit 1fdd5d6369b847aa02b3d2423fe67f45d147e5a6 Author: Sviatoslav Bulbakha Date: Sun Sep 22 20:12:24 2024 +0400 Adjust failing tap tance test for the new combo behavior commit 3578717e04ecbf14193259f2b59f37ebc8afc19b Author: Sviatoslav Bulbakha Date: Sun Sep 22 06:58:51 2024 +0400 Cleanup combo timer only when affected keys are released. commit c7b56538f21f05a221c9a7a61063fb68b1165d11 Author: Sviatoslav Bulbakha Date: Wed Jul 17 03:55:22 2024 +0400 Add failing test --- app/src/combo.c | 58 +++++++++++++++---- .../combo/other-key-release/events.patterns | 1 + .../other-key-release/keycode_events.snapshot | 4 ++ .../other-key-release/native_posix_64.keymap | 41 +++++++++++++ .../3b-tap-int-seq/keycode_events.snapshot | 4 +- 5 files changed, 95 insertions(+), 13 deletions(-) create mode 100644 app/tests/combo/other-key-release/events.patterns create mode 100644 app/tests/combo/other-key-release/keycode_events.snapshot create mode 100644 app/tests/combo/other-key-release/native_posix_64.keymap diff --git a/app/src/combo.c b/app/src/combo.c index c3334bdb7542..5da2bdc22998 100644 --- a/app/src/combo.c +++ b/app/src/combo.c @@ -459,19 +459,55 @@ static int position_state_down(const zmk_event_t *ev, struct zmk_position_state_ } } +static bool is_key_part_of_candidate(int32_t position) { + for (int i = 0; i < CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY; i++) { + struct combo_candidate *candidate = &candidates[i]; + if (candidate->combo == NULL) { + continue; + } + + for (int j = 0; j < candidate->combo->key_position_len; j++) { + if (candidate->combo->key_positions[j] == position) { + return true; + } + } + } + return false; +} + +static bool is_key_part_of_active_combo(int32_t position) { + for (int i = 0; i < active_combo_count; i++) { + struct active_combo *active_combo = &active_combos[i]; + for (int j = 0; j < active_combo->key_positions_pressed_count; j++) { + if (active_combo->key_positions_pressed[j].data.position == position) { + return true; + } + } + } + return false; +} + +static bool is_key_part_of_any_combo(int32_t position) { + return is_key_part_of_candidate(position) || is_key_part_of_active_combo(position); +} + static int position_state_up(const zmk_event_t *ev, struct zmk_position_state_changed *data) { - int released_keys = cleanup(); - if (release_combo_key(data->position, data->timestamp)) { - return ZMK_EV_EVENT_HANDLED; - } - if (released_keys > 1) { - // The second and further key down events are re-raised. To preserve - // correct order for e.g. hold-taps, reraise the key up event too. - struct zmk_position_state_changed_event dupe_ev = - copy_raised_zmk_position_state_changed(data); - ZMK_EVENT_RAISE(dupe_ev); - return ZMK_EV_EVENT_CAPTURED; + // Check if the released key is part of any combo candidate or active combo + if (is_key_part_of_any_combo(data->position)) { + int released_keys = cleanup(); + if (release_combo_key(data->position, data->timestamp)) { + return ZMK_EV_EVENT_HANDLED; + } + if (released_keys > 1) { + // The second and further key down events are re-raised. To preserve + // correct order for e.g. hold-taps, reraise the key up event too. + struct zmk_position_state_changed_event dupe_ev = + copy_raised_zmk_position_state_changed(data); + ZMK_EVENT_RAISE(dupe_ev); + return ZMK_EV_EVENT_CAPTURED; + } } + return ZMK_EV_EVENT_BUBBLE; } diff --git a/app/tests/combo/other-key-release/events.patterns b/app/tests/combo/other-key-release/events.patterns new file mode 100644 index 000000000000..b1342af4d971 --- /dev/null +++ b/app/tests/combo/other-key-release/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p diff --git a/app/tests/combo/other-key-release/keycode_events.snapshot b/app/tests/combo/other-key-release/keycode_events.snapshot new file mode 100644 index 000000000000..3c8dc1381b13 --- /dev/null +++ b/app/tests/combo/other-key-release/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x06 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 diff --git a/app/tests/combo/other-key-release/native_posix_64.keymap b/app/tests/combo/other-key-release/native_posix_64.keymap new file mode 100644 index 000000000000..f0210f177334 --- /dev/null +++ b/app/tests/combo/other-key-release/native_posix_64.keymap @@ -0,0 +1,41 @@ +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + + combo_d { + timeout-ms = <50>; + key-positions = <0 1>; + bindings = <&kp D>; + }; + + // not actuated combo to test behavior + combo_g { + timeout-ms = <50>; + key-positions = <2 3>; + bindings = <&kp G>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = <&kp A &kp B &kp C &kp D>; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,2,10) // C + ZMK_MOCK_PRESS(0,0,10) // A + ZMK_MOCK_RELEASE(0,2,10) // C + ZMK_MOCK_PRESS(0,1,10) // B + ZMK_MOCK_RELEASE(0,0,0) // A + ZMK_MOCK_RELEASE(0,1,0) // B + >; +}; diff --git a/app/tests/tap-dance/3b-tap-int-seq/keycode_events.snapshot b/app/tests/tap-dance/3b-tap-int-seq/keycode_events.snapshot index 31113ffc4aa9..38b560dbfdeb 100644 --- a/app/tests/tap-dance/3b-tap-int-seq/keycode_events.snapshot +++ b/app/tests/tap-dance/3b-tap-int-seq/keycode_events.snapshot @@ -1,10 +1,10 @@ td_binding_pressed: 2 created new tap dance td_binding_pressed: 2 tap dance pressed +td_binding_released: 2 tap dance keybind released kp_pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 td_binding_pressed: 1 created new tap dance td_binding_pressed: 1 tap dance pressed kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 -td_binding_released: 2 tap dance keybind released -kp_released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00 td_binding_released: 1 tap dance keybind released kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00