mirror of
https://github.com/qmk/qmk_userspace.git
synced 2026-04-22 11:30:23 -04:00
Enable chordal hold, remove RPI and permissive_hold
- Define CHORDAL_HOLD in config.h (replaces PERMISSIVE_HOLD_PER_KEY) - Add chordal_hold_layout[8][7] with L/R/*/0 hand assignments - Remove all require-prior-idle (RPI) state and logic - Remove get_permissive_hold callback - Remove RPI threshold defines from timfee.h - Chordal hold handles the opposite-hands rule at the firmware level: same-hand chord = tap, opposite-hand chord = hold Agent-Logs-Url: https://github.com/timfee/qmk_userspace/sessions/f112c532-9be7-4612-8000-d680cd50c50c Co-authored-by: timfee <3246342+timfee@users.noreply.github.com>
This commit is contained in:
parent
989f5f1049
commit
0ae44543fa
3 changed files with 19 additions and 129 deletions
|
|
@ -5,7 +5,7 @@
|
||||||
#define TAPPING_TERM_PER_KEY
|
#define TAPPING_TERM_PER_KEY
|
||||||
#define QUICK_TAP_TERM 90
|
#define QUICK_TAP_TERM 90
|
||||||
#define QUICK_TAP_TERM_PER_KEY
|
#define QUICK_TAP_TERM_PER_KEY
|
||||||
#define PERMISSIVE_HOLD_PER_KEY
|
#define CHORDAL_HOLD
|
||||||
#define HOLD_ON_OTHER_KEY_PRESS_PER_KEY
|
#define HOLD_ON_OTHER_KEY_PRESS_PER_KEY
|
||||||
#define RETRO_TAPPING
|
#define RETRO_TAPPING
|
||||||
#define RETRO_TAPPING_PER_KEY
|
#define RETRO_TAPPING_PER_KEY
|
||||||
|
|
|
||||||
|
|
@ -5,24 +5,22 @@
|
||||||
#include "transactions.h"
|
#include "transactions.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ── State for require-prior-idle (RPI) ──
|
// ── Chordal Hold layout ──
|
||||||
// RPI must measure inter-key timing at PHYSICAL PRESS time, not at tap/hold
|
// Defines hand assignments for the "opposite hands" tap-hold rule.
|
||||||
// resolution time. For mod-tap keys, process_record_user fires only after
|
// 'L' = left hand, 'R' = right hand, '*' = either (thumb keys).
|
||||||
// action_tapping.c resolves the key (≈tapping_term ms later), so any timing
|
// Matrix: 8 rows × 7 cols (4 rows per half, split keyboard).
|
||||||
// measured there is wrong:
|
// Rows 0-2: left finger rows Rows 4-6: right finger rows
|
||||||
// - last_input_activity_elapsed() ≈ tapping_term → always < threshold → holds never work
|
// Row 3: left thumb Row 7: right thumb
|
||||||
// - manual timer in process_record_user → skipped on return-false paths → stale timing
|
const char chordal_hold_layout[MATRIX_ROWS][MATRIX_COLS] PROGMEM = {
|
||||||
// causes the NEXT key to miss RPI and let QMK resolve as hold (CMD+key leak)
|
{'L', 'L', 'L', 'L', 'L', 'L', 'L'}, // row 0: left top
|
||||||
//
|
{'L', 'L', 'L', 'L', 'L', 'L', 'L'}, // row 1: left mid
|
||||||
// Fix: pre_process_record_user fires at physical press (before the tapping
|
{'L', 'L', 'L', 'L', 'L', 'L', 0 }, // row 2: left bot
|
||||||
// state machine buffers the key). We capture the inter-key elapsed there and
|
{ 0, 0, 0, '*', '*', '*', 0 }, // row 3: left thumb
|
||||||
// tag the key position. Later, when process_record_user fires at resolution
|
{'R', 'R', 'R', 'R', 'R', 'R', 'R'}, // row 4: right top
|
||||||
// time, we check the tag and force-tap if it was flagged.
|
{'R', 'R', 'R', 'R', 'R', 'R', 'R'}, // row 5: right mid
|
||||||
static uint16_t rpi_prev_press_time = 0;
|
{'R', 'R', 'R', 'R', 'R', 'R', 0 }, // row 6: right bot
|
||||||
static uint8_t rpi_prev_press_row = 255;
|
{ 0, 0, 0, '*', '*', '*', 0 }, // row 7: right thumb
|
||||||
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};
|
||||||
|
|
@ -206,54 +204,7 @@ void housekeeping_task_user(void) {
|
||||||
}
|
}
|
||||||
#endif // OLED_ENABLE
|
#endif // OLED_ENABLE
|
||||||
|
|
||||||
// ── Require-prior-idle: physical-press timing ──
|
// ── OLED keypress tracking ──
|
||||||
// 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.
|
|
||||||
//
|
|
||||||
// RPI only applies when the current key is on the SAME HAND as the previous
|
|
||||||
// key. Cross-hand sequences (e.g. right-thumb space → left-thumb CMD+V) skip
|
|
||||||
// RPI because accidental mod-holds from cross-hand rolling are rare and
|
|
||||||
// permissive_hold already guards against them.
|
|
||||||
bool pre_process_record_user(uint16_t keycode, keyrecord_t *record) {
|
|
||||||
if (record->event.pressed) {
|
|
||||||
uint16_t elapsed = timer_elapsed(rpi_prev_press_time);
|
|
||||||
|
|
||||||
// Determine if this key is on the same hand as the previous key
|
|
||||||
bool same_hand = false;
|
|
||||||
if (rpi_prev_press_row != 255) {
|
|
||||||
bool prev_left = rpi_prev_press_row < MATRIX_ROWS / 2;
|
|
||||||
bool curr_left = record->event.key.row < MATRIX_ROWS / 2;
|
|
||||||
same_hand = (prev_left == curr_left);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t threshold = 0;
|
|
||||||
if (same_hand) {
|
|
||||||
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();
|
|
||||||
rpi_prev_press_row = record->event.key.row;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── 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
|
||||||
g_user_ontime = timer_read32();
|
g_user_ontime = timer_read32();
|
||||||
|
|
@ -261,7 +212,6 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||||
|
|
||||||
if (record->event.pressed) {
|
if (record->event.pressed) {
|
||||||
#ifdef OLED_ENABLE
|
#ifdef OLED_ENABLE
|
||||||
// Track every keypress for OLED (before RPI may intercept)
|
|
||||||
g_last_keycode = keycode;
|
g_last_keycode = keycode;
|
||||||
if (record->event.key.row < MATRIX_ROWS / 2) {
|
if (record->event.key.row < MATRIX_ROWS / 2) {
|
||||||
g_press_left++;
|
g_press_left++;
|
||||||
|
|
@ -275,33 +225,6 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||||
(void)transaction_rpc_send(USER_SYNC_PRESSES, sizeof(ppkt), &ppkt);
|
(void)transaction_rpc_send(USER_SYNC_PRESSES, sizeof(ppkt), &ppkt);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Require-prior-idle: if pre_process_record_user flagged this key
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
uint16_t tap_kc = KC_NO;
|
|
||||||
switch (keycode) {
|
|
||||||
case GU_SPC: tap_kc = KC_SPC; break;
|
|
||||||
case GU_BSP: tap_kc = KC_BSPC; break;
|
|
||||||
case ESC_L2: tap_kc = KC_ESC; break;
|
|
||||||
case MIN_L1: tap_kc = KC_MINS; break;
|
|
||||||
case CT_GRV: tap_kc = KC_GRV; break;
|
|
||||||
case CT_BSL: tap_kc = KC_BSLS; break;
|
|
||||||
case AL_DEL: tap_kc = KC_DEL; break;
|
|
||||||
case AL_ENT: tap_kc = KC_ENT; break;
|
|
||||||
}
|
|
||||||
if (tap_kc != KC_NO) {
|
|
||||||
tap_code(tap_kc);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -317,33 +240,8 @@ uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Per-key permissive hold ──
|
|
||||||
// Layer-taps (pinky keys) and thumb mod-taps benefit from permissive
|
|
||||||
// hold: a nested tap (press+release another key within the hold)
|
|
||||||
// immediately selects the hold action.
|
|
||||||
bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) {
|
|
||||||
switch (keycode) {
|
|
||||||
case ESC_L2:
|
|
||||||
case MIN_L1:
|
|
||||||
case GU_BSP:
|
|
||||||
case GU_SPC:
|
|
||||||
case CT_GRV:
|
|
||||||
case CT_BSL:
|
|
||||||
case AL_DEL:
|
|
||||||
case AL_ENT:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Per-key hold on other key press ──
|
// ── Per-key hold on other key press ──
|
||||||
// Disabled for all keys. We rely on permissive_hold instead, which only
|
// Disabled; chordal hold handles the opposite-hands rule.
|
||||||
// resolves as hold when another key completes a full tap (press+release)
|
|
||||||
// within the hold — not just a press. This prevents the "release overlap"
|
|
||||||
// problem where rolling from a quick backspace tap into the next letter
|
|
||||||
// triggers CMD+letter instead of backspace+letter, while still making
|
|
||||||
// shortcuts like CMD+Z and CMD+SHIFT+V reliable (they are nested taps).
|
|
||||||
bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
|
bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,3 @@
|
||||||
#define GU_SPC RGUI_T(KC_SPC)
|
#define GU_SPC RGUI_T(KC_SPC)
|
||||||
#define AL_ENT RALT_T(KC_ENT)
|
#define AL_ENT RALT_T(KC_ENT)
|
||||||
#define CT_BSL RCTL_T(KC_BSLS)
|
#define CT_BSL RCTL_T(KC_BSLS)
|
||||||
|
|
||||||
// ── Require-prior-idle thresholds (ms) ──
|
|
||||||
#define RPI_SPACE 150
|
|
||||||
#define RPI_BKSP 150
|
|
||||||
#define RPI_ESC 125
|
|
||||||
#define RPI_MINUS 150
|
|
||||||
#define RPI_CTRL 125
|
|
||||||
#define RPI_ALT 150
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue