ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

QMK Key Overrides 完全指南:用自定义组合键改写修饰键行为

QMK Key Overrides 完全指南:用自定义组合键改写修饰键行为 QMK Key Overrides 完全指南用自定义组合键改写修饰键行为【免费下载链接】qmk_firmwareOpen-source keyboard firmware for Atmel AVR and Arm USB families项目地址: https://gitcode.com/GitHub_Trending/qm/qmk_firmwareKey Overrides按键覆写是 QMK 固件提供的一项高级功能当用户按下某个“修饰键 普通键”组合时固件可以在键盘报告中用另一组“修饰键 按键”甚至完全自定义的动作来替换它。本指南以docs/features/key_overrides.md为核心结合quantum/process_keycode/process_key_override.c等源码实现完整讲解 Key Overrides 的启用方式、四种初始化宏、全部结构体与选项位含义、三层激活/去激活原理、按键重复延迟机制以及“中性化闪烁修饰键”等实战技巧。读完本文你将能够为任意键盘编写精确到层、修饰键组合和激活时机的自定义快捷键。Key Overrides 是什么Key Overrides 允许你覆写修饰键组合将其替换为另一组“修饰键 按键”或者执行完全自定义的动作。例如不想让Shift1在你的电脑上打出!可以用一个 Key Override 让键盘在你按下Shift1时输出别的字符。其通用行为可以概括为如果按下了修饰键 w键 x就在键盘报告中用修饰键 y键 z替换这些按键源码见 quantum/process_keycode/process_key_override.c。你可以像使用临时层/Fn 键一样用 Key Overrides 激活自定义键码或快捷键同时享受若干额外好处完全保留修饰键的原有功能修饰键按下时本身仍是修饰键只是组合触发时被改写省掉 Fn 键不必为键盘专门分配一个 Fn 层切换键节省键位空间可配置“修饰键组合”多个修饰键同时按下可以触发与单个修饰键不同的动作。一些入门示例后续有完整代码按下Ctrl音量加减时发送屏幕亮度加减按下Shift退格时发送删除创建自定义快捷键或改写已有快捷键例如按下CtrlY时发送CtrlShiftZ按下CtrlAltEsc时运行自定义代码。启用与基础配置启用该功能需要两步在键盘的rules.mk中添加KEY_OVERRIDE_ENABLE yes在keymap.c中定义全局的key_overrides配置数组下文详述。源码在编译期通过#if defined(KEY_OVERRIDE_ENABLE)决定是否编译该功能见 quantum/keymap_introspection.c数组大小由key_override_count_raw()通过ARRAY_SIZE(key_overrides)取得并有静态断言防止数组异常过大。创建 Key Overrides四个初始化宏key_override_t结构体拥有众多可精细调节的字段完整参考见下文。官方建议优先使用以下四个专用初始化宏定义见 quantum/process_keycode/process_key_override.h而不是手动构造结构体。ko_make_basic(modifiers, key, replacement)返回一个key_override_t当key与modifiers全部按下时发送replacement可以是“键 修饰键”组合。注意此宏生成的 override 在额外按住其他未指定的修饰键时依然会激活如需限制请使用带 negative_mods 的变体。内部实现等价于ko_make_with_layers(modifiers, key, replacement, ~0)即默认在所有层上生效。ko_make_with_layers(modifiers, key, replacement, layers)在上一宏的基础上额外接受一个layer_state_t类型的位掩码layers用于指定该 override 在哪些层上生效第i层对应第i位即1 i。内部等价于ko_make_with_layers_and_negmods(..., 0)即无负向修饰键限制。ko_make_with_layers_and_negmods(modifiers, key, replacement, layers, negative_mods)再增加一个位掩码negative_mods用于定义哪些修饰键按下时该 override 不得激活。ko_make_with_layers_negmods_and_options(modifiers, key, replacement, layers, negative_mods, options)在上一宏基础上再增加options位掩码用于指定额外行为选项见下文ko_option_t参考。该宏是所有便捷宏的最终落地实现它把suppressed_mods默认设为trigger_mods即默认抑制触发修饰键custom_action与context置为NULLenabled置为NULL始终启用。当上述宏仍不满足需求时可以直接构造key_override_t结构体实现更复杂的定制如“修饰键当作层键”示例。简单示例示例一Shift Backspace Deleteconst key_override_t delete_key_override ko_make_basic(MOD_MASK_SHIFT, KC_BSPC, KC_DEL); // 全局定义所有 key overrides const key_override_t *key_overrides[] { delete_key_override };示例二分号与冒号互换ANSI 及多数布局这个示例反转分号与冒号单独按键发送Shift分号即S(KP_SCLN)别名KC_COLN输出:而按下 Shift 时 Shift 被抑制见下文suppressed_mods只发送分号KC_SCLNconst key_override_t semicolon_colon_key_override ko_make_basic(MOD_MASK_SHIFT, KC_COLN, KC_SCLN); // 全局定义所有 key overrides const key_override_t *key_overrides[] { semicolon_colon_key_override };中级示例媒体控制与屏幕亮度下面的例子让一个按键同时承担媒体、音量和亮度控制键位本身发送播放/暂停配合不同的修饰键组合改写为其他功能。组合结果Ctrl播放/暂停下一曲CtrlShift播放/暂停上一曲Alt播放/暂停音量加AltShift播放/暂停音量减CtrlAlt播放/暂停亮度加CtrlAltShift播放/暂停亮度减const key_override_t next_track_override ko_make_with_layers_negmods_and_options( MOD_MASK_CTRL, // 触发修饰键ctrl KC_MPLY, // 触发键播放/暂停 KC_MNXT, // 替换键 ~0, // 在所有层上生效 MOD_MASK_SA, // shift 或 alt 按下时不激活 ko_option_no_reregister_trigger); // 松开 ctrl 后不再重新注册播放键 const key_override_t prev_track_override ko_make_with_layers_negmods_and_options(MOD_MASK_CS, KC_MPLY, KC_MPRV, ~0, MOD_MASK_ALT, ko_option_no_reregister_trigger); const key_override_t vol_up_override ko_make_with_layers_negmods_and_options(MOD_MASK_ALT, KC_MPLY, KC_VOLU, ~0, MOD_MASK_CS, ko_option_no_reregister_trigger); const key_override_t vol_down_override ko_make_with_layers_negmods_and_options(MOD_MASK_SA, KC_MPLY, KC_VOLD, ~0, MOD_MASK_CTRL, ko_option_no_reregister_trigger); const key_override_t brightness_up_override ko_make_with_layers_negmods_and_options(MOD_MASK_CA, KC_MPLY, KC_BRIU, ~0, MOD_MASK_SHIFT, ko_option_no_reregister_trigger); const key_override_t brightness_down_override ko_make_basic(MOD_MASK_CSA, KC_MPLY, KC_BRID); // 全局定义所有 key overrides const key_override_t *key_overrides[] { next_track_override, prev_track_override, vol_up_override, vol_down_override, brightness_up_override, brightness_down_override };注意每个组合都通过negative_mod_mask排除了相邻组合例如“下一曲”排除了 Shift 和 Alt避免被“上一曲”“音量加”等误触发并大量使用ko_option_no_reregister_trigger保证松开修饰键后播放/暂停不会再次输出。灵活的 macOS 友好型 Grave EscapeGrave Escape 功能 可配置性有限且 在 macOS 上存在已知缺陷。用 Key Overrides 可以实现类似功能且无 macOS 兼容问题// Shift esc ~ const key_override_t tilde_esc_override ko_make_basic(MOD_MASK_SHIFT, KC_ESC, S(KC_GRV)); // GUI esc const key_override_t grave_esc_override ko_make_basic(MOD_MASK_GUI, KC_ESC, KC_GRV); const key_override_t *key_overrides[] { tilde_esc_override, grave_esc_override };除避开 macOS 的意外缺陷外行为也可任意调整比如把GUIESC改为CtrlESC只需替换触发修饰键即可。高级示例把修饰键当作层键是否真的需要一个专用键来切换 fn 层借助 Key Overrides 也许不需要。下面的例子用rGUIrAlt右 GUI 右 Alt临时进入一个 fn 层从而完全省去专用层键。修饰键的选择可按需更换rGUIrAlt仅作示例。// 当 override 激活/去激活时被调用激活时打开 fn 层去激活时关闭 bool momentary_layer(bool key_down, void *layer) { if (key_down) { layer_on((uint8_t)(uintptr_t)layer); } else { layer_off((uint8_t)(uintptr_t)layer); } return false; } const key_override_t fn_override {.trigger_mods MOD_BIT(KC_RGUI) | MOD_BIT(KC_RALT), // .layers ~(1 LAYER_FN), // .suppressed_mods MOD_BIT(KC_RGUI) | MOD_BIT(KC_RALT), // .options ko_option_no_unregister_on_other_key_down, // .negative_mod_mask (uint8_t) ~(MOD_BIT(KC_RGUI) | MOD_BIT(KC_RALT)), // .custom_action momentary_layer, // .context (void *)LAYER_FN, // .trigger KC_NO, // .replacement KC_NO, // .enabled NULL};这里custom_action返回false表示不再注册/注销替换键——因为本示例根本不需要发送任何按键只需切换层trigger与replacement均为KC_NO即“无触发键、无替换键”仅靠修饰键组合驱动。控制 Key Overrides 的键码键码别名说明QK_KEY_OVERRIDE_TOGGLEKO_TOGG切换 Key Overrides 开/关QK_KEY_OVERRIDE_ONKO_ON开启 Key OverridesQK_KEY_OVERRIDE_OFFKO_OFF关闭 Key Overrides这些键码定义于 quantum/keycodes.h别名见 quantum/keycodes.h在 process_key_override.c 的process_key_override()中处理分别调用key_override_toggle()、key_override_on()、key_override_off()。开关状态保存在静态变量enabled中默认开启当前未持久化到 EEPROM见 process_key_override.c。key_override_t结构体完整参考高级用户需要比ko_make宏更细的控制时可直接构造key_override_t并设置全部成员。各成员含义如下源码定义见 process_key_override.h成员说明uint16_t trigger触发 override 的非修饰键键码。该键码与必需修饰键trigger_mods必须被按下才会激活。设为KC_NO表示只需按下必需的修饰键、无需非修饰键即可激活。uint8_t trigger_mods激活所需按下的修饰键。若同时设置了左右两侧如左 Ctrl 与右 Ctrl则只需其一被按下例如左 Ctrl 即可。请使用MOD_MASK_XXX与MOD_BIT()宏。layer_state_t layers位掩码!定义该 override 适用的层。要在第i层使用则设置第i位(1 i)。uint8_t negative_mod_mask不得按下的修饰键。必须满足(active_modifiers negative_mod_mask) 0否则 override 不会激活一旦已激活的 override 不再满足该条件会被立刻去激活。uint8_t suppressed_mods激活期间要“抑制”的修饰键。抑制意味着即使该修饰键被按住主机系统也认为它未被按下。一个简单例子就是抑制触发修饰键本身。uint16_t replacement触发时发送的复合键码。可以是简单键码、键 修饰键组合如C(KC_A)或KC_NO不注册任何替换键码。可配合suppressed_mods得到正确的修饰键输出。ko_option_t options控制 override 行为的选项位见下节。bool (*custom_action)(bool activated, void *context)若非 NULL在替换键注册之前调用传入提供的 context 与一个表示 override 被激活还是去激活的布尔值。用于为特定 override 执行自定义动作。返回false时不按常规注册/注销替换键返回true则正常注册与注销。void *context传给 custom_action 函数的上下文。bool *enabled若指向false则该 override 不生效。设为NULL表示始终启用。ko_option_t选项位完整参考ko_option_t是一个位域枚举定义见 process_key_override.h值说明ko_option_activation_trigger_down允许在触发键按下时激活。ko_option_activation_required_mod_down允许在必需修饰键按下时激活。ko_option_activation_negative_mod_up允许在负向修饰键释放时激活。ko_option_one_mod若设置trigger_mods中任意一个修饰键按下即可激活逻辑 OR若未设置trigger_mods中所有修饰键都必须按下逻辑 AND。ko_option_no_unregister_on_other_key_down若设置另一个键按下时 override 不会被去激活。仅在你确实需要时才使用。ko_option_no_reregister_trigger若设置override 去激活后触发键将永远不会被重新注册。ko_options_defaultko_make_xxx系列函数使用的默认选项即ko_options_all_activations允许上述三种激活事件中的全部三种。源码中 check_activation_event() 依据这些激活相关选项判断当前按键事件是否允许触发激活修饰键按下对应ko_option_activation_required_mod_down修饰键释放对应ko_option_activation_negative_mod_up非修饰键按下对应ko_option_activation_trigger_down。若 options 中三种激活位全为 0实现会回退为默认的全部激活方式。进阶原理Key Overrides 的内部工作机制透彻理解各成员在何时发挥作用是充分驾驭全部选项的前提。本部分结合 process_key_override.c 的实现展开。激活当必需的按键trigger_modstrigger被按下时override 被“激活”替换键replacement被注册进键盘报告同时trigger键从报告中移除suppressed_mods指定的触发修饰键也可在激活时从报告中移除。若任一negative_modifiers被按下override 不会激活。override 可以在三种情况下激活触发键被按下且必需修饰键已经在按下状态某个必需修饰键被按下而触发键与其他必需修饰键已经在按下状态某个负向修饰键被释放而所有必需修饰键与触发键都已在按下状态。用options成员可定制上述哪些事件允许激活默认三种都允许。无论哪种情况override 只在trigger键是“最后按下的非修饰键”时才会激活。这是为了模拟主流操作系统macOS、Windows、Linux处理普通按键输入的行为——例如按住a再按住b然后按住shift会打出B而不会打出A。对应实现中process_key_override()用last_key_down记录最后按下的非修饰键try_activating_override() 中last_key_down override-trigger是激活的必要条件之一。去激活当以下任一情况发生时override 被“去激活”触发键trigger_mods或trigger被松开另一个非修饰键被按下某个negative_modifiers被按下。去激活时replacement键从键盘报告中移除仍按住的suppressed_mods被重新加入报告。默认情况下若触发键仍被按住且自那以后没有按下其他非修饰键trigger键会被重新加入报告。这同样模拟了操作系统行为——例如按住a再按住b再按住shift然后松开b即使仍按住a和shift也不会打出A。可用ko_option_no_reregister_trigger选项在一切情况下阻止重新注册触发键。去激活逻辑在 clear_active_override() 中实现先清除抑制修饰键再注销弱覆写修饰键按需调用custom_action(false, ...)最后按reregister_trigger的判定条件允许重注册、未设置no_reregister_trigger、触发键仍按下、非KC_NO、小于SAFE_RANGE决定是否把触发键排入延迟注册。按键重复延迟Key Repeat DelayKey Overrides 模拟标准 OS 处理修饰键输入的第三种方式就是“按键重复延迟”。再次回顾普通输入若按住a后再按shift会先打出a然后短暂停顿再开始重复输出A。虽然shift在a之后很快按下但A要过一会儿才出现——这正是按键重复延迟用于防止误输出重复字符。释放修饰键同理按住shift再按a会打出A若先松开shift、稍后松开a你不会看到a被输出即便短暂时间里你确实只按着a——因为未经过按键重复延迟就不会输出被修饰的字符。Key Overrides 完整实现了这一行为若存在Shiftab的 override按住a后再按shiftb不会立即输出而是从触发键a按下的时刻起等待按键重复延迟结束后才延迟输出。延迟时长由KEY_OVERRIDE_REPEAT_DELAY宏控制在config.h中定义即可修改默认 500ms。源码中该宏默认值见 process_key_override.c延迟逻辑在 schedule_deferred_register() 中实现若自触发键按下未满KEY_OVERRIDE_REPEAT_DELAY则等待至满否则仅延迟 50ms防止修饰键事件紧邻非修饰键事件时误激活实际注册由周期调用的 key_override_task() 完成。与 Combos 的区别注意 Key Overrides 与 Combos组合键 有本质区别Combos要求几乎同时按下多个键且可用于任意非修饰键组合Key Overrides像键盘快捷键如CtrlZ由多个修饰键 一个非修饰键组成然后执行自定义动作。Key Overrides 在按键顺序、时机与其它按键的交互上被精心实现行为与普通键盘快捷键一致并且还有一系列可选设置用于微调每个 override。另外使用 Key Overrides不会像 Combos 那样延迟普通按键的输入Combos 天然存在这种延迟可能不受欢迎。解决“闪烁修饰键”Flashing Modifiers问题如果你使用的程序把“点按修饰键”绑定为动作例如点按左 GUI 打开应用程序菜单、点按左 Alt 聚焦菜单栏那么使用带suppressed_mods的 Key Overrides 时可能会误触发这些动作。对策是在config.h中定义DUMMY_MOD_NEUTRALIZER_KEYCODE固件会在被抑制修饰键的注册与注销事件之间发送该“哑键码”从而让宿主程序不再把 Key Overrides 造成的修饰抑制误判为一次单独的修饰键点按。#define DUMMY_MOD_NEUTRALIZER_KEYCODE KC_RIGHT_CTRL使用技巧必须选择一个未绑定任何键盘快捷键的键码推荐KC_RIGHT_CTRL或KC_F18DUMMY_MOD_NEUTRALIZER_KEYCODE必须是基础的、无修饰的 HID 键码因此KC_NO、KC_TRANSPARENT、KC_PIPE即S(KC_BACKSLASH)这类值都不允许。编译期在 quantum/action_util.h 中通过静态断言强制校验要求处于KC_A至QK_BASIC_MAX之间默认仅对左 Alt 与左 GUI 生效。若要修改适用的修饰键掩码列表在config.h中定义#define MODS_TO_NEUTRALIZE { mod_mask_1, mod_mask_2, ... }示例#define DUMMY_MOD_NEUTRALIZER_KEYCODE KC_RIGHT_CTRL // 中和左 alt 和左 GUI默认值 #define MODS_TO_NEUTRALIZE { MOD_BIT(KC_LEFT_ALT), MOD_BIT(KC_LEFT_GUI) } // 中和左 alt、左 GUI、右 GUI 和 左 ControlShift #define MODS_TO_NEUTRALIZE { MOD_BIT(KC_LEFT_ALT), MOD_BIT(KC_LEFT_GUI), MOD_BIT(KC_RIGHT_GUI), MOD_BIT(KC_LEFT_CTRL)|MOD_BIT(KC_LEFT_SHIFT) }::: warning 不要使用MOD_xxx常量如MOD_LSFT、MOD_RALT因为它们是 5 位打包位数组而MODS_TO_NEUTRALIZE期望 8 位打包位数组。请使用MOD_BIT(kc)或MOD_MASK_xxx。 :::该机制的核心实现在 quantum/action_util.c 的neutralize_flashing_modifiers()中将当前激活修饰键与MODS_TO_NEUTRALIZE列表逐一比对命中则tap_code(DUMMY_MOD_NEUTRALIZER_KEYCODE)。除了 Key Overridesprocess_key_override.c 在激活前调用它同样被 Retro Tapping 等需要先注销再注册修饰键的功能复用见 quantum/action.c 与 quantum/action_tapping.c。源码与测试佐证全部实现位于 quantum/process_keycode/process_key_override.c 与 quantum/process_keycode/process_key_override.h全局数组key_overrides的遍历与大小通过弱函数key_override_count()/key_override_get()由 quantum/keymap_introspection.c 提供便于其他模块或测试注入自定义实现测试工程 tests/tap_hold_configurations/speculative_hold/default/test.mk 开启了KEY_OVERRIDE_ENABLE yes其 test_keymap.c 中定义了ko_make_basic(MOD_MASK_SHIFT, KC_ESC, KC_HOME)的 Home/Esc override并在 test_tap_hold.cpp 中以key_overrides测试用例验证了该功能与 Tap-Hold 配置的协同行为。小结Key Overrides 为 QMK 键盘提供了接近操作系统快捷键级别的按键改写能力四个ko_make_*宏覆盖绝大多数场景key_override_t与ko_option_t的完整字段/选项则支撑从“修饰键组合触发”“负向修饰排除”“修饰键抑制”到“自定义动作回调”“按层/按开关启用”的全部精细控制激活、去激活与按键重复延迟三重机制确保其行为与主流操作系统对快捷键的处理高度一致。配合DUMMY_MOD_NEUTRALIZER_KEYCODE可规避宿主程序的修饰键点按误触发使该功能在真实桌面环境中稳定可用。【免费下载链接】qmk_firmwareOpen-source keyboard firmware for Atmel AVR and Arm USB families项目地址: https://gitcode.com/GitHub_Trending/qm/qmk_firmware创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表