diff --git a/app/src/combo.c b/app/src/combo.c index 3f78878f01f9..fb64fff0ae38 100644 --- a/app/src/combo.c +++ b/app/src/combo.c @@ -453,19 +453,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/native_posix_64.keymap b/app/tests/combo/other-key-release/native_posix_64.keymap index 79f7b4e9ebe8..f0210f177334 100644 --- a/app/tests/combo/other-key-release/native_posix_64.keymap +++ b/app/tests/combo/other-key-release/native_posix_64.keymap @@ -11,13 +11,20 @@ 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>; + bindings = <&kp A &kp B &kp C &kp D>; }; }; };