feat(q5_max): Add speculative hold for caps_mod key
This commit is contained in:
@@ -17,7 +17,16 @@
|
|||||||
// COMM+DOT+SLSH fallback combo fires regardless of the active layer.
|
// COMM+DOT+SLSH fallback combo fires regardless of the active layer.
|
||||||
#define COMBO_ONLY_FROM_LAYER 0
|
#define COMBO_ONLY_FROM_LAYER 0
|
||||||
|
|
||||||
|
// Pressing the Shift key continues Caps Word and inverts the shift state
|
||||||
|
#define CAPS_WORD_INVERT_ON_SHIFT
|
||||||
|
|
||||||
// Default tapping term for mod-tap, layer-tap, and tap-dance keys.
|
// Default tapping term for mod-tap, layer-tap, and tap-dance keys.
|
||||||
#define TAPPING_TERM 200
|
#define TAPPING_TERM 200
|
||||||
// Allow per-key overrides via get_tapping_term() in keymap.c.
|
// Allow per-key overrides via get_tapping_term() in keymap.c.
|
||||||
#define TAPPING_TERM_PER_KEY
|
#define TAPPING_TERM_PER_KEY
|
||||||
|
|
||||||
|
// Use right CTRL key to neutralize modifier taps when cancelled.
|
||||||
|
#define DUMMY_MOD_NEUTRALIZER_KEYCODE KC_RIGHT_CTRL
|
||||||
|
|
||||||
|
// Neutralize left ALT and left GUI (Default value)
|
||||||
|
#define MODS_TO_NEUTRALIZE {MOD_BIT(KC_LEFT_ALT), MOD_BIT(KC_LEFT_GUI)}
|
||||||
|
|||||||
@@ -41,10 +41,11 @@ enum custom_keycodes {
|
|||||||
LCK_FN4, // Lock/unlock FN4
|
LCK_FN4, // Lock/unlock FN4
|
||||||
LCK_CTL, // Lock/unlock KEEB_CTL
|
LCK_CTL, // Lock/unlock KEEB_CTL
|
||||||
LCK_BASE, // Clear all locks and return to BASE
|
LCK_BASE, // Clear all locks and return to BASE
|
||||||
CAPS_MOD, // Tap=ESC, hold=Ctrl, Shift=CapsLock, Alt=CapsWord, GUI=Autocorrect
|
|
||||||
BSP_DEL, // Tap=Backspace, Shift+Tap=Delete
|
BSP_DEL, // Tap=Backspace, Shift+Tap=Delete
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define CAPS_MOD MT(MOD_LCTL, KC_ESC)
|
||||||
|
|
||||||
// Declare layers early so the HID functions below can reference KEEB_CTL.
|
// Declare layers early so the HID functions below can reference KEEB_CTL.
|
||||||
enum layers {
|
enum layers {
|
||||||
BASE,
|
BASE,
|
||||||
@@ -192,10 +193,7 @@ bool kc_raw_hid_rx_kb(uint8_t *data, uint8_t length) {
|
|||||||
resp[HID_OFF_SRC] = HID_DEV_Q5MAX;
|
resp[HID_OFF_SRC] = HID_DEV_Q5MAX;
|
||||||
resp[HID_OFF_FLAGS] = HID_FLAG_RESPONSE;
|
resp[HID_OFF_FLAGS] = HID_FLAG_RESPONSE;
|
||||||
#ifdef LK_WIRELESS_ENABLE
|
#ifdef LK_WIRELESS_ENABLE
|
||||||
resp[HID_PAYLOAD(HID_BATT_OFF_LEVEL)] =
|
resp[HID_PAYLOAD(HID_BATT_OFF_LEVEL)] = (get_transport() & TRANSPORT_WIRELESS) ? battery_get_percentage() : HID_BATT_UNAVAILABLE;
|
||||||
(get_transport() & TRANSPORT_WIRELESS)
|
|
||||||
? battery_get_percentage()
|
|
||||||
: HID_BATT_UNAVAILABLE;
|
|
||||||
#else
|
#else
|
||||||
resp[HID_PAYLOAD(HID_BATT_OFF_LEVEL)] = HID_BATT_UNAVAILABLE;
|
resp[HID_PAYLOAD(HID_BATT_OFF_LEVEL)] = HID_BATT_UNAVAILABLE;
|
||||||
#endif
|
#endif
|
||||||
@@ -211,9 +209,7 @@ bool kc_raw_hid_rx_kb(uint8_t *data, uint8_t length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CAPS_MOD state: tap=ESC, hold=Ctrl, Shift+tap=CapsLock, Alt+tap=CapsWord, GUI+tap=Autocorrect
|
// CAPS_MOD state: tap=ESC, hold=Ctrl, Shift+tap=CapsLock, Alt+tap=CapsWord, GUI+tap=Autocorrect
|
||||||
static bool caps_mod_held = false;
|
// (Refactored to use MT(MOD_LCTL, KC_ESC) with custom tap logic)
|
||||||
static bool caps_mod_ctrl_registered = false;
|
|
||||||
static uint16_t caps_mod_timer = 0;
|
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||||
@@ -350,38 +346,28 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
|||||||
|
|
||||||
switch (keycode) {
|
switch (keycode) {
|
||||||
case CAPS_MOD:
|
case CAPS_MOD:
|
||||||
if (record->event.pressed) {
|
// Custom tap logic: only intercept if it's a TAP AND a modifier is held.
|
||||||
caps_mod_held = true;
|
// If it's a pure hold (Ctrl) or a pure tap (Esc), return true to let
|
||||||
caps_mod_timer = timer_read();
|
// the MT() core handle it.
|
||||||
// If a real modifier is held, send a dummy key so the OS sees
|
if (record->tap.count > 0 && record->event.pressed) {
|
||||||
// modifier+key rather than a bare modifier hold/tap. Without
|
|
||||||
// this, the OS never receives any keycode while the modifier is
|
|
||||||
// down and treats the eventual modifier release as a tap (e.g.
|
|
||||||
// GUI opening the app menu). KC_F24 is harmless and universally
|
|
||||||
// ignored by applications.
|
|
||||||
if (get_mods() & (MOD_MASK_GUI | MOD_MASK_ALT | MOD_MASK_SHIFT)) {
|
|
||||||
register_code(KC_F24);
|
|
||||||
unregister_code(KC_F24);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (caps_mod_ctrl_registered) {
|
|
||||||
unregister_code(KC_LCTL);
|
|
||||||
caps_mod_ctrl_registered = false;
|
|
||||||
} else {
|
|
||||||
uint8_t mods = get_mods();
|
uint8_t mods = get_mods();
|
||||||
|
if (mods & (MOD_MASK_GUI | MOD_MASK_ALT)) {
|
||||||
|
// Neutralize the modifier hold so releasing GUI/Alt doesn't
|
||||||
|
// trigger an OS "tap" action (like opening the Start menu).
|
||||||
|
tap_code(DUMMY_MOD_NEUTRALIZER_KEYCODE);
|
||||||
|
|
||||||
if (mods & MOD_MASK_GUI) {
|
if (mods & MOD_MASK_GUI) {
|
||||||
autocorrect_toggle();
|
autocorrect_toggle();
|
||||||
} else if (mods & MOD_MASK_ALT) {
|
|
||||||
caps_word_toggle();
|
|
||||||
} else if (mods & MOD_MASK_SHIFT) {
|
|
||||||
tap_code(KC_CAPS); // Shift still held → host sees Shift+CapsLock (toggles on most OSes)
|
|
||||||
} else {
|
} else {
|
||||||
tap_code(KC_ESC);
|
caps_word_toggle();
|
||||||
|
}
|
||||||
|
return false; // suppress default Esc tap
|
||||||
|
} else if (mods & MOD_MASK_SHIFT) {
|
||||||
|
tap_code(KC_CAPS);
|
||||||
|
return false; // suppress default Esc tap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
caps_mod_held = false; // cleared in both hold and tap paths
|
return true; // let core handle Esc tap or Ctrl hold
|
||||||
}
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case LCK_FN1:
|
case LCK_FN1:
|
||||||
case LCK_FN2:
|
case LCK_FN2:
|
||||||
@@ -466,10 +452,6 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void matrix_scan_user(void) {
|
void matrix_scan_user(void) {
|
||||||
if (caps_mod_held && !caps_mod_ctrl_registered && timer_elapsed(caps_mod_timer) > TAPPING_TERM) {
|
|
||||||
caps_mod_ctrl_registered = true;
|
|
||||||
register_code(KC_LCTL);
|
|
||||||
}
|
|
||||||
if (alt_tab_active && timer_elapsed(alt_tab_timer) > ALT_TAB_TIMEOUT) {
|
if (alt_tab_active && timer_elapsed(alt_tab_timer) > ALT_TAB_TIMEOUT) {
|
||||||
unregister_code(KC_LALT);
|
unregister_code(KC_LALT);
|
||||||
alt_tab_active = false;
|
alt_tab_active = false;
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
"nkro" : true,
|
"nkro" : true,
|
||||||
"rgb_matrix": true,
|
"rgb_matrix": true,
|
||||||
"raw" : true,
|
"raw" : true,
|
||||||
"send_string": true
|
"send_string": true,
|
||||||
|
"speculative_hold": true
|
||||||
},
|
},
|
||||||
"matrix_pins": {
|
"matrix_pins": {
|
||||||
"cols": ["C6", "C7", "C8", "A14", "A15", "C10", "C11", "C13", "C14", "C15", "C0", "C1", "C2", "C3", "A0", "A1", "A2", "A3", "B10"],
|
"cols": ["C6", "C7", "C8", "A14", "A15", "C10", "C11", "C13", "C14", "C15", "C0", "C1", "C2", "C3", "A0", "A1", "A2", "A3", "B10"],
|
||||||
|
|||||||
Reference in New Issue
Block a user