diff --git a/app/src/behaviors/behavior_hold_tap.c b/app/src/behaviors/behavior_hold_tap.c index 413806b4..f09006ed 100644 --- a/app/src/behaviors/behavior_hold_tap.c +++ b/app/src/behaviors/behavior_hold_tap.c @@ -612,6 +612,10 @@ static int position_state_changed_listener(const zmk_event_t *eh) { decide_hold_tap(undecided_hold_tap, HT_TIMER_EVENT); } + if (undecided_hold_tap == NULL) { + return ZMK_EV_EVENT_BUBBLE; + } + if (!ev->state && find_captured_keydown_event(ev->position) == NULL) { // no keydown event has been captured, let it bubble. // we'll catch modifiers later in modifier_state_changed_listener diff --git a/app/src/combo.c b/app/src/combo.c index 13ed1709..e434ae17 100644 --- a/app/src/combo.c +++ b/app/src/combo.c @@ -211,7 +211,7 @@ static int filter_timed_out_candidates(int64_t timestamp) { if (candidate->timeout_at > timestamp) { // reorder candidates so they're contiguous candidates[num_candidates].combo = candidate->combo; - candidates[num_candidates].timeout_at = candidates->timeout_at; + candidates[num_candidates].timeout_at = candidate->timeout_at; num_candidates++; } else { candidate->combo = NULL; diff --git a/app/src/event_manager.c b/app/src/event_manager.c index eef5d839..471432a8 100644 --- a/app/src/event_manager.c +++ b/app/src/event_manager.c @@ -25,6 +25,7 @@ int zmk_event_manager_handle_from(zmk_event_t *event, uint8_t start_index) { if (ev_sub->event_type != event->event) { continue; } + event->last_listener_index = i; ret = ev_sub->listener->callback(event); switch (ret) { case ZMK_EV_EVENT_BUBBLE: @@ -35,7 +36,6 @@ int zmk_event_manager_handle_from(zmk_event_t *event, uint8_t start_index) { goto release; case ZMK_EV_EVENT_CAPTURED: LOG_DBG("Listener captured the event"); - event->last_listener_index = i; // Listeners are expected to free events they capture return 0; default: diff --git a/app/tests/combo/combos-and-holdtaps-3/events.patterns b/app/tests/combo/combos-and-holdtaps-3/events.patterns new file mode 100644 index 00000000..833100f6 --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-3/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/combo/combos-and-holdtaps-3/keycode_events.snapshot b/app/tests/combo/combos-and-holdtaps-3/keycode_events.snapshot new file mode 100644 index 00000000..843832dd --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-3/keycode_events.snapshot @@ -0,0 +1,5 @@ +pressed: usage_page 0x07 keycode 0xE5 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/combos-and-holdtaps-3/native_posix_64.keymap b/app/tests/combo/combos-and-holdtaps-3/native_posix_64.keymap new file mode 100644 index 00000000..d4053793 --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-3/native_posix_64.keymap @@ -0,0 +1,40 @@ +#include +#include +#include + +&mt { + flavor = "hold-preferred"; +}; + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <40>; + key-positions = <0 1>; + bindings = <&kp X>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + label = "Default keymap"; + + default_layer { + bindings = < + &kp A &kp B + &mt RSHFT RET &kp C + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(0,1,50) + ZMK_MOCK_RELEASE(1,1,50) + >; +}; diff --git a/app/tests/combo/combos-and-holdtaps-4/events.patterns b/app/tests/combo/combos-and-holdtaps-4/events.patterns new file mode 100644 index 00000000..833100f6 --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-4/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/combo/combos-and-holdtaps-4/keycode_events.snapshot b/app/tests/combo/combos-and-holdtaps-4/keycode_events.snapshot new file mode 100644 index 00000000..f84bc761 --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-4/keycode_events.snapshot @@ -0,0 +1,4 @@ +pressed: usage_page 0x07 keycode 0xE1 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 +released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/combos-and-holdtaps-4/native_posix_64.keymap b/app/tests/combo/combos-and-holdtaps-4/native_posix_64.keymap new file mode 100644 index 00000000..ba6cecc6 --- /dev/null +++ b/app/tests/combo/combos-and-holdtaps-4/native_posix_64.keymap @@ -0,0 +1,46 @@ +#include +#include +#include + + +#define ZMK_COMBO(name, combo_bindings, keypos, combo_term) \ +/ { \ + combos { \ + compatible = "zmk,combos"; \ + combo_ ## name { \ + key-positions = ; \ + bindings = ; \ + timeout-ms = ; \ + }; \ + }; \ +}; + +ZMK_COMBO(qmark, &kp QMARK, 0 3, 30) +ZMK_COMBO(dllr, &kp DLLR, 1 3, 50) +ZMK_COMBO(tilde, &kp TILDE, 3 4, 50) + +/ { + keymap { + compatible = "zmk,keymap"; + label = "Default keymap"; + + default_layer { + bindings = < + &none &none + &kp A &mt LSHFT T + &none + >; + }; + }; +}; + +&kscan { + rows = <3>; + columns = <2>; + events = < + ZMK_MOCK_PRESS(1,1,500) + ZMK_MOCK_PRESS(1,0,100) + ZMK_MOCK_RELEASE(1,0,500) + ZMK_MOCK_RELEASE(1,1,0) + >; +}; \ No newline at end of file