import { _ as _export_sfc, c as createElementBlock, o as openBlock, a8 as createStaticVNode } from "./chunks/framework.B9AX-CPi.js"; const __pageData = JSON.parse('{"title":"QMK Breaking Changes - 2023 February 26 Changelog","description":"","frontmatter":{},"headers":[],"relativePath":"ChangeLog/20230226.md","filePath":"ChangeLog/20230226.md"}'); const _sfc_main = { name: "ChangeLog/20230226.md" }; const _hoisted_1 = /* @__PURE__ */ createStaticVNode('

QMK Breaking Changes - 2023 February 26 Changelog

Changes Requiring User Action

IGNORE_MOD_TAP_INTERRUPT behaviour changes (#15741)

IGNORE_MOD_TAP_INTERRUPT_PER_KEY has been removed and IGNORE_MOD_TAP_INTERRUPT deprecated as a stepping stone towards making IGNORE_MOD_TAP_INTERRUPT the new default behavior for mod-taps in the future.

In place of the now removed IGNORE_MOD_TAP_INTERRUPT_PER_KEY, one must use the pre-existing HOLD_ON_OTHER_KEY_PRESS option.

In most cases, updating get_ignore_mod_tap_interrupt to get_hold_on_other_key_press is simply a matter of renaming the function and swapping every true by false and vice versa. The one subtlety you may need to look out for is that the get_ignore_mod_tap_interrupt was only ever called with mod-taps passed in as the keycode argument, while the keycode argument of get_hold_on_other_key_press can be any dual-role key. This includes not only mod-taps, but also layer-taps, one shot keys, TT(layer) and more. This has an impact on the effect of the default case in a typical per-key configuration making use of a switch(keycode) statement.

To illustrate, let's take the example of a configuration where we'd want all mod-taps to activate the modifier if another key is pressed while held with the exception of LCTL_T(KC_A), which should ignore keys pressed while it is held and activate the modifier only if it has been held for longer than the tapping term. In addition, we would like to keep the default "ignore-interrupt" behavior of layer taps.

An old way to do this would be via the following code:

c
bool get_ignore_mod_tap_interrupt(uint16_t keycode, keyrecord_t *record) {\n    switch(keycode) {\n        case LCTL_T(KC_A):\n            return true;\n        default:\n            return false;\n    }\n}

The correct way to update this code without accidentally changing how the layer-taps work would be the following:

c
bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {\n    switch(keycode) {\n        // Capture all mod-tap keycodes.\n        case QK_MOD_TAP ... QK_MOD_TAP_MAX:\n            if (keycode == LCTL_T(KC_A)) {\n                // Disable HOLD_ON_OTHER_KEY_PRESS for LCTL_T(KC_A)\n                // aka enable IGNORE_MOD_TAP_INTERRUPT for LCTL_T(KC_A).\n                return false;\n            } else {\n                // Enable HOLD_ON_OTHER_KEY_PRESS for every other mod-tap keycode.\n                return true;\n            }\n        default:\n            return false;\n    }\n}

For more information, you are invited to read the sections on IGNORE_MOD_TAP_INTERRUPT and HOLD_ON_OTHER_KEY_PRESS in the page on Tap-Hold configuration options.

TAPPING_FORCE_HOLD => QUICK_TAP_TERM (#17007)

TAPPING_FORCE_HOLD feature is now replaced by QUICK_TAP_TERM. Instead of turning off auto-repeat completely, user will have the option to configure a QUICK_TAP_TERM in milliseconds. When the user holds a tap-hold key after tapping it within QUICK_TAP_TERM, QMK will send the tap keycode to the host, enabling auto-repeat.

Its value is set to TAPPING_TERM by default and it can be reduced to match typing habits to avoid false triggers. To disable auto-repeat completely, set QUICK_TAP_TERM to zero.

TAPPING_FORCE_HOLD_PER_KEY is also deprecated and replaced by QUICK_TAP_TERM_PER_KEY. The old granular control function for tapping force hold is:

c
bool get_tapping_force_hold(uint16_t keycode, keyrecord_t *record) {\n    switch (keycode) {\n        case LT(1, KC_BSPC):\n            return true;\n        default:\n            return false;\n    }\n}

That function can be replaced with:

c
uint16_t get_quick_tap_term(uint16_t keycode, keyrecord_t *record) {\n    switch (keycode) {\n        case SFT_T(KC_SPC):\n            return 0;\n        default:\n            return QUICK_TAP_TERM;\n    }\n}

For more details, please read the updated documentation section on Quick Tap Term.

Leader Key Rework {#leader-key-rework (#19632)}

The Leader Key feature API has been significantly improved, along with some bugfixes and added tests.

Instead of defining your leader sequences in matrix_scan_user(), they are now handled in the leader_end_user() callback, and the LEADER_EXTERNS()/LEADER_DICTIONARY() macros are no longer needed:

c
void leader_end_user(void) {\n    if (leader_sequence_one_key(KC_F)) {\n        // Leader, f => Types the below string\n        SEND_STRING("QMK is awesome.");\n    } else if (leader_sequence_two_keys(KC_D, KC_D)) {\n        // Leader, d, d => Ctrl+A, Ctrl+C\n        SEND_STRING(SS_LCTL("a") SS_LCTL("c"));\n    } else if (leader_sequence_three_keys(KC_D, KC_D, KC_S)) {\n        // Leader, d, d, s => Types the below string\n        SEND_STRING("https://start.duckduckgo.com\\n");\n    } else if (leader_sequence_two_keys(KC_A, KC_S)) {\n        // Leader, a, s => GUI+S\n        tap_code16(LGUI(KC_S));\n    }\n}

For more information please see the Leader Key documentation.

Updated Keyboard Codebases

The following keyboards have had their source moved within QMK:

Old Keyboard NameNew Keyboard Name
ramonimbao/aelithrmi_kb/aelith
ramonimbao/herringbone/prormi_kb/herringbone/pro
ramonimbao/herringbone/v1rmi_kb/herringbone/v1
ramonimbao/mona/v1_1rmi_kb/mona/v1_1
ramonimbao/mona/v1rmi_kb/mona/v1
ramonimbao/mona/v32armi_kb/mona/v32a
ramonimbao/squishy65rmi_kb/squishy65
ramonimbao/squishytklrmi_kb/squishytkl
ramonimbao/tkl_ffrmi_kb/tkl_ff
ramonimbao/tkl_ff/v1rmi_kb/tkl_ff/v1
ramonimbao/tkl_ff/v2rmi_kb/tkl_ff/v2
ramonimbao/wete/v1rmi_kb/wete/v1
ramonimbao/wete/v2rmi_kb/wete/v2
the_unistenothe_uni
xelus/xs60xelus/xs60/soldered

Notable core changes

As per last breaking changes cycle, there has been a lot of emphasis on behind-the-scenes changes, mainly around consolidation of core subsystems and constant values, as well as addressing tech debt. Whilst not outwardly visible, this cleanup and refactoring should start paying dividends as it simplifies future development and maintenance.

A handful of examples:

Full changelist

Core:

CLI:

Submodule updates:

Keyboards:

Keyboard fixes:

Others:

Bugs:

', 47); const _hoisted_48 = [ _hoisted_1 ]; function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { return openBlock(), createElementBlock("div", null, _hoisted_48); } const _20230226 = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]); export { __pageData, _20230226 as default };