refactor(hold-tap): Simplify logic with trace_id

The trace_id can easily be used to figure out if a key was pressed
before the hold-tap was pressed without searching through all events
that were captured.
This commit is contained in:
Okke Formsma 2021-02-07 19:33:11 +01:00
parent 25fd5b2402
commit fe5189adde

View file

@ -50,6 +50,7 @@ struct active_hold_tap {
uint32_t param_hold; uint32_t param_hold;
uint32_t param_tap; uint32_t param_tap;
int64_t timestamp; int64_t timestamp;
uint32_t trace_id;
bool is_decided; bool is_decided;
bool is_hold; bool is_hold;
const struct behavior_hold_tap_config *config; const struct behavior_hold_tap_config *config;
@ -95,25 +96,6 @@ static int capture_event(const zmk_event_t *event) {
return -ENOMEM; return -ENOMEM;
} }
static struct zmk_position_state_changed *find_captured_keydown_event(uint32_t position) {
struct zmk_position_state_changed *last_match = NULL;
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) {
const zmk_event_t *eh = captured_events[i];
if (eh == NULL) {
return last_match;
}
struct zmk_position_state_changed *position_event = as_zmk_position_state_changed(eh);
if (position_event == NULL) {
continue;
}
if (position_event->position == position && position_event->state) {
last_match = position_event;
}
}
return last_match;
}
const struct zmk_listener zmk_listener_behavior_hold_tap; const struct zmk_listener zmk_listener_behavior_hold_tap;
static void release_captured_events() { static void release_captured_events() {
@ -137,8 +119,7 @@ static void release_captured_events() {
// [null, k1_down, k1_up, mt2_up, null, ...] // [null, k1_down, k1_up, mt2_up, null, ...]
// ^ // ^
// k1_down is captured by the mt2 mod-tap // k1_down is captured by the mt2 mod-tap
// !note that searches for find_captured_keydown_event by the mt2 behavior will stop at the // [mt1_down, null, k1_up, mt2_up, null, ...]
// first null encountered [mt1_down, null, k1_up, mt2_up, null, ...]
// ^ // ^
// k1_up event is captured by the new hold-tap: // k1_up event is captured by the new hold-tap:
// [k1_down, k1_up, null, mt2_up, null, ...] // [k1_down, k1_up, null, mt2_up, null, ...]
@ -180,6 +161,7 @@ static struct active_hold_tap *find_hold_tap(uint32_t position) {
static struct active_hold_tap *store_hold_tap(uint32_t position, uint32_t param_hold, static struct active_hold_tap *store_hold_tap(uint32_t position, uint32_t param_hold,
uint32_t param_tap, int64_t timestamp, uint32_t param_tap, int64_t timestamp,
uint32_t trace_id,
const struct behavior_hold_tap_config *config) { const struct behavior_hold_tap_config *config) {
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) {
if (active_hold_taps[i].position != ZMK_BHV_HOLD_TAP_POSITION_NOT_USED) { if (active_hold_taps[i].position != ZMK_BHV_HOLD_TAP_POSITION_NOT_USED) {
@ -192,6 +174,7 @@ static struct active_hold_tap *store_hold_tap(uint32_t position, uint32_t param_
active_hold_taps[i].param_hold = param_hold; active_hold_taps[i].param_hold = param_hold;
active_hold_taps[i].param_tap = param_tap; active_hold_taps[i].param_tap = param_tap;
active_hold_taps[i].timestamp = timestamp; active_hold_taps[i].timestamp = timestamp;
active_hold_taps[i].trace_id = trace_id;
return &active_hold_taps[i]; return &active_hold_taps[i];
} }
return NULL; return NULL;
@ -342,8 +325,8 @@ static int on_hold_tap_binding_pressed(struct zmk_behavior_binding *binding,
return ZMK_BEHAVIOR_OPAQUE; return ZMK_BEHAVIOR_OPAQUE;
} }
struct active_hold_tap *hold_tap = struct active_hold_tap *hold_tap = store_hold_tap(
store_hold_tap(event.position, binding->param1, binding->param2, event.timestamp, cfg); event.position, binding->param1, binding->param2, event.timestamp, event.trace_id, cfg);
if (hold_tap == NULL) { if (hold_tap == NULL) {
LOG_ERR("unable to store hold-tap info, did you press more than %d hold-taps?", LOG_ERR("unable to store hold-tap info, did you press more than %d hold-taps?",
ZMK_BHV_HOLD_TAP_MAX_HELD); ZMK_BHV_HOLD_TAP_MAX_HELD);
@ -430,7 +413,7 @@ static int position_state_changed_listener(const zmk_event_t *eh) {
return ZMK_EV_EVENT_BUBBLE; return ZMK_EV_EVENT_BUBBLE;
} }
if (undecided_hold_tap->position == ev->position) { if (undecided_hold_tap->trace_id == ev->trace_id) {
if (ev->state) { // keydown if (ev->state) { // keydown
LOG_ERR("hold-tap listener should be called before before most other listeners!"); LOG_ERR("hold-tap listener should be called before before most other listeners!");
return ZMK_EV_EVENT_BUBBLE; return ZMK_EV_EVENT_BUBBLE;
@ -448,9 +431,9 @@ static int position_state_changed_listener(const zmk_event_t *eh) {
decide_hold_tap(undecided_hold_tap, HT_TIMER_EVENT); decide_hold_tap(undecided_hold_tap, HT_TIMER_EVENT);
} }
if (!ev->state && find_captured_keydown_event(ev->position) == NULL) { if (ev->trace_id < undecided_hold_tap->trace_id) {
// no keydown event has been captured, let it bubble. // this key was pressed before the hold-tap was pressed, let it bubble.
// we'll catch modifiers later in modifier_state_changed_listener // see scenarios 3a/b
LOG_DBG("%d bubbling %d %s event", undecided_hold_tap->position, ev->position, LOG_DBG("%d bubbling %d %s event", undecided_hold_tap->position, ev->position,
ev->state ? "down" : "up"); ev->state ? "down" : "up");
return ZMK_EV_EVENT_BUBBLE; return ZMK_EV_EVENT_BUBBLE;
@ -464,25 +447,16 @@ static int position_state_changed_listener(const zmk_event_t *eh) {
} }
static int keycode_state_changed_listener(const zmk_event_t *eh) { static int keycode_state_changed_listener(const zmk_event_t *eh) {
// we want to catch layer-up events too... how?
struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh); struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh);
if (undecided_hold_tap != NULL && is_mod(ev->usage_page, ev->keycode)) {
if (undecided_hold_tap == NULL) { // Catch mod up events for scenario 3a.
// LOG_DBG("0x%02X bubble (no undecided hold_tap active)", ev->keycode); LOG_DBG("%d capturing 0x%02X %s event", undecided_hold_tap->position, ev->keycode,
return ZMK_EV_EVENT_BUBBLE; ev->state ? "down" : "up");
capture_event(eh);
return ZMK_EV_EVENT_CAPTURED;
} }
if (!is_mod(ev->usage_page, ev->keycode)) { return ZMK_EV_EVENT_BUBBLE;
// LOG_DBG("0x%02X bubble (not a mod)", ev->keycode);
return ZMK_EV_EVENT_BUBBLE;
}
// only key-up events will bubble through position_state_changed_listener
// if a undecided_hold_tap is active.
LOG_DBG("%d capturing 0x%02X %s event", undecided_hold_tap->position, ev->keycode,
ev->state ? "down" : "up");
capture_event(eh);
return ZMK_EV_EVENT_CAPTURED;
} }
int behavior_hold_tap_listener(const zmk_event_t *eh) { int behavior_hold_tap_listener(const zmk_event_t *eh) {