docs/ChangeLog/20251130.md
Speculative Hold makes mod-tap keys more responsive by applying the modifier instantly on keydown, before the tap-hold decision is made. This is especially useful for actions like Shift+click and Ctrl+scroll wheel with an external mouse, which can feel laggy with standard mod-taps.
The firmware holds the modifier speculatively. Once the key's behavior is settled:
Speculative Hold applies the modifier early but does not change the underlying tap-hold decision logic. Speculative Hold is compatible to use in combination with any other tap-hold options.
see the Speculative Hold documentation for more information.
| Old Keyboard Name | New Keyboard Name |
|---|---|
| 0xcb/splaytoraid/32u4 | 0xcb/splaytoraid |
| 0xcb/splaytoraid/rp2040_ce | 0xcb/splaytoraid |
| 1upkeyboards/sweet16v2/kb2040 | 1upkeyboards/sweet16v2 |
| 1upkeyboards/sweet16v2/pro_micro | 1upkeyboards/sweet16v2 |
| 40percentclub/gherkin/kb2040 | 40percentclub/gherkin |
| 40percentclub/gherkin/pro_micro | 40percentclub/gherkin |
| durgod/dgk6x/venus | durgod/dgk6x/venus_ansi |
The tap dance state has been separated from the action structure. Custom tap dance functions now receive the state as a separate parameter instead of accessing it through action->state.
If your keymap uses custom tap dance functions that access the tap dance state, you need to update your code.
action->state. Instead you need to call tap_dance_state_t *tap_dance_get_state(uint8_t tap_dance_idx) to get the state.-> notation rather than . notation to get fields from it.bool process_record_user(uint16_t keycode, keyrecord_t *record) {
tap_dance_action_t *action;
switch (keycode) {
case TD(CT_CLN):
action = tap_dance_get(QK_TAP_DANCE_GET_INDEX(keycode));
if (!record->event.pressed && action->state.count && !action->state.finished) {
tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)action->user_data;
tap_code16(tap_hold->tap);
}
}
return true;
}
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
tap_dance_action_t *action;
tap_dance_state_t* state;
switch (keycode) {
case TD(CT_CLN):
action = tap_dance_get(QK_TAP_DANCE_GET_INDEX(keycode));
state = tap_dance_get_state(QK_TAP_DANCE_GET_INDEX(keycode));
if (!record->event.pressed && state != NULL && state->count && !state->finished) {
tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)action->user_data;
tap_code16(tap_hold->tap);
}
}
return true;
}
In line with the notice period, deprecation notices for larger items are listed here.
#24649 implemented genetic behavior, including keycodes, to cycle flags.
Any overriding of existing keycodes that duplicate this behavior will be removed to ensure consistency with core functionality.
Core:
mod_t packed struct (#25168)CLI:
qmk userspace-doctor (#25775){RGB,LED}_MATRIX_DEFAULT_FLAGS (#25785)Submodule updates:
Keyboards:
atreus: restore intended matrix implementations (#24082)eeconfig_init_kb implementations to config (#25422)CUSTOM_MATRIX = lite without matrix_pins.custom (#25453)g_led_config to DD (0-9, A) (#25558)g_led_config to DD (B, C) (#25559)g_led_config to DD (D) (#25560)g_led_config to DD (E, F) (#25561)g_led_config to DD (G) (#25598)g_led_config to DD (H) (#25599)g_led_config to DD (I) (#25600)g_led_config to DD (JK1) (#25601)g_led_config to DD (K2) (#25602)g_led_config to DD (K3) (#25603)g_led_config to DD (K4) (#25605)g_led_config to DD (K5) (#25606)g_led_config to DD (K6) (#25607)40percentclub/gherkin (#25608)0xcb/splaytoraid (#25609)1upkeyboards/sweet16v2 (#25610)g_led_config to DD (K7) (#25616)g_led_config to DD (L) (#25617)g_led_config to DD (M1) (#25618)g_led_config to DD (M2) (#25619)g_led_config to DD (M3) (#25620)g_led_config to DD (NO) (#25621)g_led_config to DD (P) (#25622)g_led_config to DD (QR) (#25623)g_led_config to DD (S) (#25624)g_led_config to DD (TUW) (#25625)g_led_config to DD (YZ) (#25650)x1_layer_led function as weak (#25668)Keyboard fixes:
kprepublic/bm60hsrgb/rev2 (#25644)kprepublic/bm60hsrgb_iso/rev2 (#25648)kprepublic/bm60hsrgb_poker/rev2 (#25649)rgbkb/pan (#25678)_kb callbacks (#25774)Others:
Bugs: