mirror of
https://github.com/qmk/qmk_userspace.git
synced 2026-04-22 11:30:23 -04:00
Fix RPI: move timing to pre_process_record_user for correct physical-press measurement
Both previous approaches measured inter-key timing in process_record_user, which fires at tap/hold RESOLUTION time (not physical press time): - last_input_activity_elapsed(): always ≈ tapping_term → holds never worked - manual last_key_time: stale on return-false paths → CMD+key leak pre_process_record_user fires at the physical keypress moment, BEFORE the tapping state machine buffers the key. Flag the key position there, then check the flag in process_record_user at resolution time to force-tap. Agent-Logs-Url: https://github.com/timfee/qmk_userspace/sessions/40e6f36c-6ca7-4425-830c-0dac14106e87 Co-authored-by: timfee <3246342+timfee@users.noreply.github.com>
This commit is contained in:
parent
847d7313b1
commit
0d1521ad4b
1 changed files with 73 additions and 65 deletions
|
|
@ -5,17 +5,23 @@
|
||||||
#include "transactions.h"
|
#include "transactions.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ── State for require-prior-idle ──
|
// ── State for require-prior-idle (RPI) ──
|
||||||
// Manual timestamp of the last key processed through process_record_user.
|
// RPI must measure inter-key timing at PHYSICAL PRESS time, not at tap/hold
|
||||||
// This is intentionally NOT last_input_activity_elapsed() — that API reflects
|
// resolution time. For mod-tap keys, process_record_user fires only after
|
||||||
// the most recent matrix scan change, which includes the current mod-tap key's
|
// action_tapping.c resolves the key (≈tapping_term ms later), so any timing
|
||||||
// OWN press. Since process_record_user fires ~tapping_term ms after the
|
// measured there is wrong:
|
||||||
// physical press (after tap/hold resolution), the elapsed time would always be
|
// - last_input_activity_elapsed() ≈ tapping_term → always < threshold → holds never work
|
||||||
// ≈ tapping_term, which is less than the RPI thresholds — killing every hold.
|
// - manual timer in process_record_user → skipped on return-false paths → stale timing
|
||||||
// A manual variable updated at the END of process_record_user correctly
|
// causes the NEXT key to miss RPI and let QMK resolve as hold (CMD+key leak)
|
||||||
// captures the previous key's timing. This works for both halves because QMK
|
//
|
||||||
// split processes all key events on the master side.
|
// Fix: pre_process_record_user fires at physical press (before the tapping
|
||||||
static uint16_t last_key_time = 0;
|
// state machine buffers the key). We capture the inter-key elapsed there and
|
||||||
|
// tag the key position. Later, when process_record_user fires at resolution
|
||||||
|
// time, we check the tag and force-tap if it was flagged.
|
||||||
|
static uint16_t rpi_prev_press_time = 0;
|
||||||
|
static bool rpi_force_tap = false;
|
||||||
|
static uint8_t rpi_force_tap_row = 255;
|
||||||
|
static uint8_t rpi_force_tap_col = 255;
|
||||||
|
|
||||||
// ── Combos (matching Vial config) ──
|
// ── Combos (matching Vial config) ──
|
||||||
const uint16_t PROGMEM lparen_combo[] = {KC_R, KC_T, COMBO_END};
|
const uint16_t PROGMEM lparen_combo[] = {KC_R, KC_T, COMBO_END};
|
||||||
|
|
@ -199,6 +205,37 @@ void housekeeping_task_user(void) {
|
||||||
}
|
}
|
||||||
#endif // OLED_ENABLE
|
#endif // OLED_ENABLE
|
||||||
|
|
||||||
|
// ── Require-prior-idle: physical-press timing ──
|
||||||
|
// pre_process_record_user fires at the physical keypress moment, BEFORE the
|
||||||
|
// tapping state machine buffers the key. This is the correct place to measure
|
||||||
|
// inter-key timing for RPI.
|
||||||
|
bool pre_process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||||
|
if (record->event.pressed) {
|
||||||
|
uint16_t elapsed = timer_elapsed(rpi_prev_press_time);
|
||||||
|
|
||||||
|
uint16_t threshold = 0;
|
||||||
|
switch (keycode) {
|
||||||
|
case GU_SPC: threshold = RPI_SPACE; break;
|
||||||
|
case GU_BSP: threshold = RPI_BKSP; break;
|
||||||
|
case ESC_L2: threshold = RPI_ESC; break;
|
||||||
|
case MIN_L1: threshold = RPI_MINUS; break;
|
||||||
|
case CT_GRV: threshold = RPI_CTRL; break;
|
||||||
|
case CT_BSL: threshold = RPI_CTRL; break;
|
||||||
|
case AL_DEL: threshold = RPI_ALT; break;
|
||||||
|
case AL_ENT: threshold = RPI_ALT; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (threshold > 0 && elapsed < threshold) {
|
||||||
|
rpi_force_tap = true;
|
||||||
|
rpi_force_tap_row = record->event.key.row;
|
||||||
|
rpi_force_tap_col = record->event.key.col;
|
||||||
|
}
|
||||||
|
|
||||||
|
rpi_prev_press_time = timer_read();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// ── Require-prior-idle + OLED keypress tracking ──
|
// ── Require-prior-idle + OLED keypress tracking ──
|
||||||
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||||
#ifdef OLED_ENABLE
|
#ifdef OLED_ENABLE
|
||||||
|
|
@ -222,61 +259,32 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Require-prior-idle: force tap if pressed too soon after last key
|
// Require-prior-idle: if pre_process_record_user flagged this key
|
||||||
uint16_t elapsed = timer_elapsed(last_key_time);
|
// for force-tap (pressed too soon after the previous physical keypress),
|
||||||
|
// send the tap keycode now and suppress QMK's mod-tap/layer-tap handling.
|
||||||
|
if (rpi_force_tap &&
|
||||||
|
record->event.key.row == rpi_force_tap_row &&
|
||||||
|
record->event.key.col == rpi_force_tap_col) {
|
||||||
|
rpi_force_tap = false;
|
||||||
|
rpi_force_tap_row = 255;
|
||||||
|
rpi_force_tap_col = 255;
|
||||||
|
|
||||||
switch (keycode) {
|
uint16_t tap_kc = KC_NO;
|
||||||
case GU_SPC:
|
switch (keycode) {
|
||||||
if (elapsed < RPI_SPACE) {
|
case GU_SPC: tap_kc = KC_SPC; break;
|
||||||
tap_code(KC_SPC);
|
case GU_BSP: tap_kc = KC_BSPC; break;
|
||||||
return false;
|
case ESC_L2: tap_kc = KC_ESC; break;
|
||||||
}
|
case MIN_L1: tap_kc = KC_MINS; break;
|
||||||
break;
|
case CT_GRV: tap_kc = KC_GRV; break;
|
||||||
case GU_BSP:
|
case CT_BSL: tap_kc = KC_BSLS; break;
|
||||||
if (elapsed < RPI_BKSP) {
|
case AL_DEL: tap_kc = KC_DEL; break;
|
||||||
tap_code(KC_BSPC);
|
case AL_ENT: tap_kc = KC_ENT; break;
|
||||||
return false;
|
}
|
||||||
}
|
if (tap_kc != KC_NO) {
|
||||||
break;
|
tap_code(tap_kc);
|
||||||
case ESC_L2:
|
return false;
|
||||||
if (elapsed < RPI_ESC) {
|
}
|
||||||
tap_code(KC_ESC);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MIN_L1:
|
|
||||||
if (elapsed < RPI_MINUS) {
|
|
||||||
tap_code(KC_MINS);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CT_GRV:
|
|
||||||
if (elapsed < RPI_CTRL) {
|
|
||||||
tap_code(KC_GRV);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CT_BSL:
|
|
||||||
if (elapsed < RPI_CTRL) {
|
|
||||||
tap_code(KC_BSLS);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AL_DEL:
|
|
||||||
if (elapsed < RPI_ALT) {
|
|
||||||
tap_code(KC_DEL);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AL_ENT:
|
|
||||||
if (elapsed < RPI_ALT) {
|
|
||||||
tap_code(KC_ENT);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
last_key_time = timer_read();
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue