QMK Firmware 2022 年 5 月 28 日破坏性变更解读Caps Word、Quantum Painter 与编码器映射【免费下载链接】qmk_firmwareOpen-source keyboard firmware for Atmel AVR and Arm USB families项目地址: https://gitcode.com/GitHub_Trending/qm/qmk_firmware本文解读 QMK Firmware 发布于 2022 年 5 月 28 日的 Breaking Changes 变更日志docs/ChangeLog/20220528.md系统梳理该版本引入的三大核心新特性Caps Word、Quantum Painter、Encoder Mapping、需要用户手动处理的破坏性变更RESET更名、Sendstring 键码重构、Pillow 依赖以及键盘代码库目录迁移与完整 PR 清单。读者在读完本文后将能够理解这些特性的工作原理、在自己的keymap.c与rules.mk中正确启用和配置它们并顺利完成旧版本固件的升级迁移。概览本次破坏性变更的核心内容QMK 的 Breaking Changes 周期用于合并那些无法向后兼容、需要用户主动配合的改动。2022 年 5 月 28 日的这一批变更主要由三个大型特性合并推动Caps Word#16588一种“到词尾自动关闭”的 Caps Lock 替代方案作为核心特性合入。Quantum Painter#10174面向 ARM/RISC-V 平台的新绘图子系统支持大尺寸 RGB LCD/OLED、图片、字体与动画。Encoder Mapping#13286允许用户在keymap.c中像定义普通键位一样定义编码器旋钮行为。此外还有大量底层重构、驱动更新、键盘目录迁移和 Bug 修复本文逐一展开。新特性一Caps Word 词首字母大写功能什么是 Caps WordCaps Word 是一种“现代替代 Caps Lock”的输入特性开启后字母会被自动大写直到“这个词结束”为止。它非常适合输入 QMK 这类缩写、或代码中KC_SPC这样的常量标识符——无需全程按住 Shift也无需手动关闭 Caps Lock。典型使用流程想输入 QMK 时同时轻点左右两个 Shift或双击 Shift进入 Caps Word 状态然后直接输入小写的qmk即可当按下除a–z、0–9、-、_、Delete、Backspace 之外的任意键时Caps Word 自动恢复为正常输入状态。与 Caps Lock 的关键区别从 docs/features/caps_word.md 和 quantum/process_keycode/process_caps_word.c 的源码可以看到该特性不依赖KC_CAPS键码而是通过“弱修饰键weak mods”临时给下一个按键附加 Shift 来实现在 Caps Word 激活期间caps_word_press_user()默认对KC_A–KC_Z和KC_MINS调用add_weak_mods(MOD_BIT(KC_LSFT))再返回true继续当前“词”对KC_1–KC_0、KC_BSPC、KC_DEL、KC_UNDS直接返回true继续但不加 Shift其余键返回false从而关闭 Caps Word。因为不经过系统 Caps Lock即使你在操作系统层面把 Caps Lock 重映射为 CtrlEmacs/Vim 用户常见做法Caps Word 依然有效。副作用是它受 OS 键盘布局影响例如 Dvorak 布局中DV_COMM即KC_W会被当作字母 W 处理而被 Shift西班牙语布局的 Ñ 键ES_NTIL即KC_SCLN不会被大写而美式布局的连字符KC_MINS在普通 Caps Lock 下不受影响、在 Caps Word 下却会被 Shift。这些都可以通过自定义caps_word_press_user()回调调整。如何启用 Caps Word在键盘或 keymap 的rules.mk中加入CAPS_WORD_ENABLE yes然后在keymap.c中通过以下任一方式激活激活方式配置方法专用按键在键位中使用QK_CAPS_WORD_TOGGLE简写CW_TOGG同时按左右 Shift在config.h定义BOTH_SHIFTS_TURNS_ON_CAPS_WORD双击左 Shift在config.h定义DOUBLE_TAP_SHIFT_TURNS_ON_CAPS_WORD代码激活调用caps_word_on()可用于 combo、tap dance 等从 process_caps_word.c 的入口逻辑可以看到process_caps_word()首先拦截QK_CAPS_WORD_TOGGLE并调用caps_word_toggle()随后在BOTH_SHIFTS_TURNS_ON_CAPS_WORD分支中判断mods MOD_MASK_SHIFT同时按住左右 Shift时调用caps_word_on()在DOUBLE_TAP_SHIFT_TURNS_ON_CAPS_WORD分支中利用GET_TAPPING_TERM()宏判断两次按下左 Shift 的时间间隔是否在 tapping term 之内。与 Command 功能的冲突处理同时使用BOTH_SHIFTS_TURNS_ON_CAPS_WORD时编译期可能出现如下提示BOTH_SHIFTS_TURNS_ON_CAPS_WORD and Command should not be enabled at the same time, since both use the Left Shift Right Shift key combination.因为 QMK 的 Command 功能默认也用“左 Shift 右 Shift”组合激活。对应的源码判断见 process_caps_word.c其中对defined(COMMAND_ENABLE) !defined(IS_COMMAND)的情况会输出#pragma message警告。解决方式二选一# rules.mk COMMAND_ENABLE no或重新定义 Command 的触发组合// config.h改用左 Ctrl 右 Ctrl 激活 Command #define IS_COMMAND() (get_mods() MOD_MASK_CTRL)可配置选项以下选项均在config.h中定义// 按 Shift 时不退出 Caps Word而是反转大小写状态 // 例如输入 P, D, F, ShiftS 得到 PDFs #define CAPS_WORD_INVERT_ON_SHIFT // 空闲超时毫秒默认 50005 秒设为 0 表示永不超时 #define CAPS_WORD_IDLE_TIMEOUT 3000对应源码中CAPS_WORD_IDLE_TIMEOUT 0时每次按键都会caps_word_reset_idle_timer()重置空闲计时器process_caps_word.cCAPS_WORD_INVERT_ON_SHIFT分支则会维护held_mods并通过set_weak_mods(get_weak_mods() ^ MOD_BIT(KC_LSFT))翻转 Shift 状态。编程接口与状态回调函数作用caps_word_on()开启 Caps Wordcaps_word_off()关闭 Caps Wordcaps_word_toggle()切换 Caps Wordis_caps_word_on()返回 Caps Word 当前是否开启自定义“哪些键算词中断”的回调默认实现见 process_caps_word.cbool caps_word_press_user(uint16_t keycode) { switch (keycode) { case KC_A ... KC_Z: case KC_MINS: add_weak_mods(MOD_BIT(KC_LSFT)); // 继续并附加 Shift return true; case KC_1 ... KC_0: case KC_BSPC: case KC_DEL: case KC_UNDS: return true; // 继续但不加 Shift default: return false; // 词中断关闭 Caps Word } }通过caps_word_set_user(bool active)可以在状态变化时获得回调用于点亮 LED 或播放提示音void caps_word_set_user(bool active) { if (active) { // Caps Word 激活时 } else { // Caps Word 关闭时 } }新特性二Quantum Painter 绘图子系统背景与能力QMK 此前仅支持 SSD1306/SH1106 等小型 OLED 面板。Quantum Painter 是一套全新的、标准化的图形显示 API适用于合适的 ARM 与 RISC-V 板子可以驱动大尺寸 RGB LCD 和 RGB OLED 面板并提供更丰富的绘制 API线条、矩形、圆、椭圆、文本、图片甚至动画。QMK CLI 也新增了对应命令用于把图片、GIF 动画和字体转换成 Quantum Painter 可消费的格式。重要限制由于复杂度和体积原因Quantum Painter 不支持 AVR 平台。ProMicro、Elite-C 这类基于 AVR 的板子无法使用docs/quantum_painter.md。启用方式与支持的设备在rules.mk中加入总开关与具体驱动QUANTUM_PAINTER_ENABLE yes QUANTUM_PAINTER_DRIVERS ili9341_spi从 drivers/painter 目录的驱动子目录gc9xxx、ili9xxx、ld7032、sh1106、sh1107、ssd1351、st77xx、tft_panel等可以看出驱动按面板厂商组织。主要支持的面板与驱动变量对应如下显示面板面板类型尺寸通信方式驱动变量GC9A01RGB LCD圆形240x240SPI D/C RSTgc9a01_spiILI9163RGB LCD128x128SPI D/C RSTili9163_spiILI9341RGB LCD240x320SPI D/C RSTili9341_spiILI9486 / ILI9488RGB LCD320x480SPI D/C RSTili9486_spi/ili9488_spiLD7032单色 OLED128x40SPI / I2Cld7032_spi/ld7032_i2cSSD1351RGB OLED128x128SPI D/C RSTssd1351_spiST7735RGB LCD132x162 / 80x160SPI D/C RSTst7735_spiST7789RGB LCD240x320 / 240x240SPI D/C RSTst7789_spiSH1106 / SSD1306单色 OLED128x64 等SPI / I2Csh1106_spi/sh1106_i2cSurface虚拟面板用户定义无surface全局配置项以下选项在config.h中配置选项默认值作用QUANTUM_PAINTER_DISPLAY_TIMEOUT30000最后一次用户输入后屏幕保持点亮的时间毫秒0表示常亮QUANTUM_PAINTER_TASK_THROTTLE1内部任务两次执行之间的等待时间毫秒影响动画、显示超时与 LVGL 时序QUANTUM_PAINTER_NUM_IMAGES8同一时刻最多加载的图片/动画数量QUANTUM_PAINTER_NUM_FONTS4同一时刻最多加载的字体数量QUANTUM_PAINTER_CONCURRENT_ANIMATIONS4同一时刻可同时运行的动画数量QUANTUM_PAINTER_LOAD_FONTS_TO_RAMFALSE是否将字体加载到 RAM适用于外部 Flash 等片外存储的字体QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE1024单次传输到屏幕的像素数据上限越大越占 MCU RAMQUANTUM_PAINTER_SUPPORTS_256_PALETTEFALSE是否支持 256 色板会显著增加 RAM 占用QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORSFALSE是否支持原生色深rgb565/rgb888会显著增加 RAM 占用QUANTUM_PAINTER_DEBUG未设置向 CONSOLE 输出大量调试信息会明显降低性能仅用于调试QUANTUM_PAINTER_DEBUG_ENABLE_FLUSH_TASK_OUTPUT未设置默认在内部任务刷屏期间关闭调试输出如需保留可定义此项注意会刷爆 ConsoleCLI 工具图片、动画与字体转换Quantum Painter 的核心工作流是先用 CLI 把素材转换为 QGF图片与 QFF字体格式。qmk painter-convert-graphics用于把图片/动画转换为 QGFusage: qmk painter-convert-graphics [-h] [-w] [-d] [-r] -f FORMAT [-o OUTPUT] -i INPUT [-v] 选项 -w, --raw 以裸数据形式输出 QGF 文件而非 c/h 组合 -d, --no-deltas 编码动画时禁用 delta 帧 -r, --no-rle 编码图片时禁用 RLE 压缩 -f, --format FORMAT 输出格式rgb888, rgb565, pal256, pal16, pal4, pal2, mono256, mono16, mono4, mono2 -o, --output OUTPUT 输出目录默认与输入同目录 -i, --input INPUT 输入图片文件PNG、Animated GIF 等 Pillow 可加载的格式 -v, --verbose 输出详细信息FORMAT与固件配置的对应关系格式含义需要的固件开关rgb8881677 万色8-8-8QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORSrgb56565536 色5-6-5QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORSpal256/mono256256 色/灰度QUANTUM_PAINTER_SUPPORTS_256_PALETTEpal16/mono1616 色/灰度无pal4/mono44 色/灰度无pal2/mono22 色/灰度无示例cd keyboards/my_keeb qmk painter-convert-graphics -f mono16 -i my_image.gif -o ./generated/ # 生成 my_image.qgf.h 与 my_image.qgf.c字体转换分为两步先用qmk painter-make-font-image把 TTF 字体渲染为中间 PNG再将其转换为 QFFqmk painter-make-font-image [-a] [-u UNICODE_GLYPHS] [-n] [-s SIZE] -o OUTPUT -f FONT-a, --no-aa禁用抗锯齿-u, --unicode-glyphs额外生成指定 Unicode 字形-n, --no-ascii只输出指定字形不包含完整 ASCII 字符集0x20..0x7E-s, --size字号默认 12-o, --output输出图片路径-f, --font输入 TTF 字体文件示例qmk painter-make-font-image --font NotoSans-ExtraCondensedBold.ttf --size 11 -o noto11.png --unicode-glyphs ĄȽɂɻɣɈʣ此外文档还提示Quantum Painter 目前尚未与系统级操作如键盘进入 suspend集成用户当前需要自行处理显示关闭逻辑。新特性三Encoder Mapping 编码器映射传统编码器配置方式在引入映射之前编码器需要在config.h中定义引脚再通过回调函数手工分发行为# rules.mk ENCODER_ENABLE yes// config.h单个编码器 #define ENCODER_A_PINS { B12 } #define ENCODER_B_PINS { B13 }多个编码器用数组定义#define ENCODER_A_PINS { encoder1a, encoder2a } #define ENCODER_B_PINS { encoder1b, encoder2b }常用配置项还包括// 旋转方向反了时交换 A/B 定义或直接 #define ENCODER_DIRECTION_FLIP // 每个卡位之间需要多少脉冲 #define ENCODER_RESOLUTION 4 // 也可按编码器分别指定 #define ENCODER_RESOLUTIONS { 4, 2 } // 4 倍编码器在换向丢脉冲时指定默认位置例如两脚默认都是高电平 #define ENCODER_DEFAULT_POS 0x3分体键盘可以分别定义左右半边的引脚与分辨率未定义_RIGHT版本时左右共用同一配置某半边无编码器时可用空数组表示例如只有右侧有编码器#define ENCODER_A_PINS { } #define ENCODER_B_PINS { } #define ENCODER_RESOLUTIONS { } #define ENCODER_A_PINS_RIGHT { B12 } #define ENCODER_B_PINS_RIGHT { B13 } #define ENCODER_RESOLUTIONS_RIGHT { 4 }注意修改编码器分辨率后需要重新刷写受影响的那一半固件。Encoder Map 新方案#13286引入的 Encoder Mapping 让编码器可以像普通键位一样按“层 × 编码器 × 方向”组织。启用方式# keymap 的 rules.mk ENCODER_MAP_ENABLE yes然后在keymap.c中定义encoder_map以下示例为 4 层 × 2 个编码器#if defined(ENCODER_MAP_ENABLE) const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] { [0] { ENCODER_CCW_CW(MS_WHLU, MS_WHLD), ENCODER_CCW_CW(KC_VOLD, KC_VOLU) }, [1] { ENCODER_CCW_CW(UG_HUED, UG_HUEU), ENCODER_CCW_CW(UG_SATD, UG_SATU) }, [2] { ENCODER_CCW_CW(UG_VALD, UG_VALU), ENCODER_CCW_CW(UG_SPDD, UG_SPDU) }, [3] { ENCODER_CCW_CW(UG_PREV, UG_NEXT), ENCODER_CCW_CW(KC_RIGHT, KC_LEFT) }, }; #endif注意ENCODER_MAP_ENABLE只应在 keymap 层面启用。从 quantum/encoder.c 的实现可以看到启用ENCODER_MAP_ENABLE后编码器事件不再走encoder_update_kb()回调而是通过MAKE_ENCODER_CW_EVENT/MAKE_ENCODER_CCW_EVENT构造按下/抬起事件经action_exec()推入正常的 QMK 键码处理管线即编码器动作会经过process_record_xxxxx()等既有处理流程。在两次事件之间可以配置延迟以兼容 Windows 等系统// config.h设置编码器 keyup 与 keydown 之间的毫秒数 #define ENCODER_MAP_KEY_DELAY 10默认值取自TAP_CODE_DELAY源码见 encoder.c 中#ifndef ENCODER_MAP_KEY_DELAY的兜底定义。回调方式不使用 Encoder Map 时未启用ENCODER_MAP_ENABLE时默认行为是顺时针音量加、逆时针音量减见 encoder.c 中encoder_update_kb()的默认实现其按EXTRAKEY_ENABLE/MOUSEKEY_ENABLE依次选择KC_VOLU/KC_VOLD、滚轮、翻页。需要自定义时在keyboard.c中定义bool encoder_update_kb(uint8_t index, bool clockwise) { if (!encoder_update_user(index, clockwise)) { return false; /* 用户函数存在且返回 false 时不再继续处理 */ } if (index 0) { /* 第一个编码器 */ if (clockwise) { tap_code(KC_PGDN); } else { tap_code(KC_PGUP); } } else if (index 1) { /* 第二个编码器 */ if (clockwise) { rgb_matrix_increase_hue(); } else { rgb_matrix_decrease_hue(); } } return true; }或在keymap.c中定义encoder_update_user()实现同样的分发逻辑。需要用户操作的破坏性变更RESET键码更名为QK_BOOT#17037为了给未来新硬件平台的支持让路避免命名冲突#17037将大多数默认风格键位中的RESET替换为新的键码QK_BOOT。在 quantum/keycodes.h 可以看到QK_BOOTLOADER 0x7C00而QK_BOOT就是它的别名同文件 L1397 附近。迁移要求旧键码在本周期内仍然可用但预计在下一个破坏性变更周期被移除。用户键位中凡用到RESET的都应改用QK_BOOT。Sendstring 键码重构#16941用于SEND_STRING及其相关功能的部分键码被标记为废弃deprecated未来可能移除旧键码。迁移方法是查阅文档中给出的废弃键码清单位于提交ebd4027时的 quantum/send_string_keycodes.h 区域逐行比对#define行——将第一个标识符旧名替换为同一行上的第二个标识符新名。以修饰键为例当前仓库的 quantum/send_string/send_string_keycodes.h 展示了新命名风格X_LCTL、X_LSFT、X_LALT、X_LGUI、X_RCTL、X_RSFT、X_RALT、X_RGUI等并保留X_ALGR等价X_RIGHT_ALT等别名字符串宏层面SS_RALT()、SS_ALGR()、SS_ROPT()均指向X_RIGHT_ALT同文件 L440-L443。用户应检查自己的SEND_STRING宏参数是否使用了旧命名并同步更新。Pillow 依赖安装#17133Quantum Painter 的合入给 QMK CLI 带来了新的 Python 依赖最主要是Pillow图片处理库。已有安装需要按平台执行命令WindowsQMK MSYS / MSYS2pacman --needed --noconfirm --disable-download-timeout -S mingw-w64-x86_64-python-pillow python3 -m pip install --upgrade qmkmacOSbrew update brew upgrade qmk/qmk/qmkLinux 或 WSLpython3 -m pip install --user --upgrade qmk键盘代码库目录迁移以下键盘的源码路径发生了移动用户自定义 keymap 若引用旧路径需要同步更新旧键盘名新键盘名absinthekeyhive/absintheamj40 / amj60 / amj96 / amjpadamjkeyboard/amj40 / amj60 / amj96 / amjpadat101_bhviktus/at101_bhergosauruskeyhive/ergosaurusgmmk/pro/ansigmmk/pro/rev1/ansigmmk/pro/isogmmk/pro/rev1/isohoneycombkeyhive/honeycomblattice60keyhive/lattice60melody96ymdk/melody96mt40 / mt64rgb / mt84 / mt980mt/mt40 / mt64rgb / mt84 / mt980navi10keyhive/navi10omnikey_bhviktus/omnikey_bhopuskeyhive/opussmallicekeyhive/smallicesouthpolekeyhive/southpoleunokeyhive/unout472keyhive/ut472wheatfield/blocked65mt/blocked65wheatfield/split75mt/split75z150_bhviktus/z150_bh这些迁移在仓库当前结构中均有对应目录可验证例如 keyboards/amjkeyboard、keyboards/keyhive、keyboards/viktus、keyboards/ymdk、keyboards/mt、keyboards/gmmk 等。完整变更清单速览本次周期的其余核心改动按类别摘录Core 核心多开关/电磁阀支持#15657、compile/make宏#15959、Reboot 键码#15990、pmw3360 多传感器支持#15996、非对称编码器及测试#16068、AVR 最小 printf 库#16266、AVR-mrelax/-mcall-prologues体积优化#16269、SN74x154 驱动器#16331、可定制 snake/knight 动画增量#16337、HD44780 驱动重构#16370、移除send_unicode_hex_string()#16518、UF2 bootloader 的:flash目标#16525、has_mouse_report_changed移入report.c#16543、TICK更名TICK_EVENT#16649、GET_TAPPING_TERM宏#16681、IS31FL3737B PWM 频率可调#16718、Joystick 特性更新#16732、#16926、STM32F303xE 模拟 EEPROM#16737、XAP secure 核心需求#16843、硬件唯一 ID API#16869、Wb32fq95 支持#16871、bluepill 更优默认配置#16909、keymap_extras 头文件统一命名#16939、LTO 警告调整到 arm_atsam#17106等。CLIgenerate-api改用.build目录#16441、qmk info支持 keymap 层覆盖#16702、数据驱动的g_led_config#16728、开发板预设框架#16637、#16785、#16806、格式化范围扩展至*.hpp#16997等。Submodule 更新ChibiOS 21.11.1#16251、ChibiOS-Contrib#16915。键盘相关GMMK Pro 支持多版本#16423、Helix rev2 迁移到 split common#16723、usb_usb 转换器社区布局支持#16773、gboards/gergoplex 将COMBO_ENABLE移到 keymap 层#16667、DESCRIPTION数据驱动为字符串字面量#16523等。Bug 修复one-shot 锁定修饰键#16114、One ShotOS_ON/OS_OFF逻辑修复#16617、#16630、Mousekeys 修复#16640、AVR 背光呼吸灯越界修复#16770、USB 读取循环修复#16827、QP 调色板 BPP 检查#16863、kinetic mouse 模式修复与回退#16951、#17095、Secure 特性增强修复#16958、-Werrorarray-boundsAVR 问题规避#17136、Caps Word 在按住 AltGr右 Alt时继续生效的修复#17156等。迁移与升级建议综合本次变更用户升级固件时应按以下顺序自查键位中的RESET全部替换为QK_BOOT#17037。SEND_STRING相关宏参数对照废弃清单更新为新命名#16941。QMK CLI 环境按平台安装/升级 Pillow 依赖确保qmk painter-convert-graphics等新命令可用#17133。若引用了被迁移的键盘路径同步更新为新的厂商目录结构见上文迁移表。需要图形显示能力的 ARM/RISC-V 板子可按本文第二节配置 Quantum PainterAVR 板子ProMicro、Elite-C 等不适用。希望用旋钮替代传统回调的用户可在 keymap 层启用ENCODER_MAP_ENABLE并定义encoder_map注意该方案目前不受 QMK Configurator 支持未来也不太可能被 VIA 支持。通过以上步骤即可平滑迁移到 2022 年 5 月 28 日破坏性变更后的 QMK 版本并立即使用 Caps Word、Quantum Painter 与 Encoder Mapping 三项新特性。【免费下载链接】qmk_firmwareOpen-source keyboard firmware for Atmel AVR and Arm USB families项目地址: https://gitcode.com/GitHub_Trending/qm/qmk_firmware创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考