[Core] Enhance Flow Tap to work better for rolls over multiple tap-hold keys. (#25200)

* Flow Tap revision for rolling press.

* Remove debugging cruft.

* Formatting fix.
This commit is contained in:
Pascal Getreuer 2025-04-28 00:52:20 -07:00 committed by GitHub
parent 7fa65aa877
commit c26449e64f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 1395 additions and 13 deletions

View file

@ -103,10 +103,11 @@ __attribute__((weak)) bool get_hold_on_other_key_press(uint16_t keycode, keyreco
# endif
# if defined(FLOW_TAP_TERM)
static uint32_t flow_tap_prev_time = 0;
static uint16_t flow_tap_prev_keycode = KC_NO;
static uint16_t flow_tap_prev_time = 0;
static bool flow_tap_expired = true;
static bool flow_tap_key_if_within_term(keyrecord_t *record);
static bool flow_tap_key_if_within_term(keyrecord_t *record, uint16_t prev_time);
# endif // defined(FLOW_TAP_TERM)
static keyrecord_t tapping_key = {};
@ -159,6 +160,12 @@ void action_tapping_process(keyrecord_t record) {
}
if (IS_EVENT(record.event)) {
ac_dprintf("\n");
} else {
# ifdef FLOW_TAP_TERM
if (!flow_tap_expired && TIMER_DIFF_16(record.event.time, flow_tap_prev_time) >= INT16_MAX / 2) {
flow_tap_expired = true;
}
# endif // FLOW_TAP_TERM
}
}
@ -240,7 +247,7 @@ bool process_tapping(keyrecord_t *keyp) {
// into the "pressed" tapping key state
# if defined(FLOW_TAP_TERM)
if (flow_tap_key_if_within_term(keyp)) {
if (flow_tap_key_if_within_term(keyp, flow_tap_prev_time)) {
return true;
}
# endif // defined(FLOW_TAP_TERM)
@ -281,6 +288,27 @@ bool process_tapping(keyrecord_t *keyp) {
// copy tapping state
keyp->tap = tapping_key.tap;
# if defined(FLOW_TAP_TERM)
// Now that tapping_key has settled as tapped, check whether
// Flow Tap applies to following yet-unsettled keys.
uint16_t prev_time = tapping_key.event.time;
for (; waiting_buffer_tail != waiting_buffer_head; waiting_buffer_tail = (waiting_buffer_tail + 1) % WAITING_BUFFER_SIZE) {
keyrecord_t *record = &waiting_buffer[waiting_buffer_tail];
if (!record->event.pressed) {
break;
}
const int16_t next_time = record->event.time;
if (!is_tap_record(record)) {
process_record(record);
} else if (!flow_tap_key_if_within_term(record, prev_time)) {
break;
}
prev_time = next_time;
}
debug_waiting_buffer();
# endif // defined(FLOW_TAP_TERM)
// enqueue
return false;
}
@ -557,7 +585,7 @@ bool process_tapping(keyrecord_t *keyp) {
} else if (is_tap_record(keyp)) {
// Sequential tap can be interfered with other tap key.
# if defined(FLOW_TAP_TERM)
if (flow_tap_key_if_within_term(keyp)) {
if (flow_tap_key_if_within_term(keyp, flow_tap_prev_time)) {
tapping_key = (keyrecord_t){0};
debug_tapping_key();
return true;
@ -791,11 +819,11 @@ static void waiting_buffer_process_regular(void) {
# ifdef FLOW_TAP_TERM
void flow_tap_update_last_event(keyrecord_t *record) {
const uint16_t keycode = get_record_keycode(record, false);
// Don't update while a tap-hold key is unsettled.
if (waiting_buffer_tail != waiting_buffer_head || (tapping_key.event.pressed && tapping_key.tap.count == 0)) {
if (record->tap.count == 0 && (waiting_buffer_tail != waiting_buffer_head || (tapping_key.event.pressed && tapping_key.tap.count == 0))) {
return;
}
const uint16_t keycode = get_record_keycode(record, false);
// Ignore releases of modifiers and held layer switches.
if (!record->event.pressed) {
switch (keycode) {
@ -826,20 +854,25 @@ void flow_tap_update_last_event(keyrecord_t *record) {
}
flow_tap_prev_keycode = keycode;
flow_tap_prev_time = timer_read32();
flow_tap_prev_time = record->event.time;
flow_tap_expired = false;
}
static bool flow_tap_key_if_within_term(keyrecord_t *record) {
static bool flow_tap_key_if_within_term(keyrecord_t *record, uint16_t prev_time) {
const uint16_t idle_time = TIMER_DIFF_16(record->event.time, prev_time);
if (flow_tap_expired || idle_time >= 500) {
return false;
}
const uint16_t keycode = get_record_keycode(record, false);
if (is_mt_or_lt(keycode)) {
const uint32_t idle_time = timer_elapsed32(flow_tap_prev_time);
uint16_t term = get_flow_tap_term(keycode, record, flow_tap_prev_keycode);
uint16_t term = get_flow_tap_term(keycode, record, flow_tap_prev_keycode);
if (term > 500) {
term = 500;
}
if (idle_time < 500 && idle_time < term) {
if (idle_time < term) {
debug_event(record->event);
ac_dprintf(" within flow tap term (%u < %u) considered a tap\n", (int16_t)idle_time, term);
ac_dprintf(" within flow tap term (%u < %u) considered a tap\n", idle_time, term);
record->tap.count = 1;
registered_taps_add(record->event.key);
debug_registered_taps();