QMK Firmware 2026-02-22 破坏性变更解析:移除废弃 GPIO 定义与 isLeftHand,附完整变更清单
2026/9/13 13:17:17 网站建设 项目流程

QMK Firmware 2026-02-22 破坏性变更解析:移除废弃 GPIO 定义与 isLeftHand,附完整变更清单

【免费下载链接】qmk_firmwareOpen-source keyboard firmware for Atmel AVR and Arm USB families项目地址: https://gitcode.com/GitHub_Trending/qm/qmk_firmware

本文围绕 QMK Firmware 2026 年 2 月 22 日发布的破坏性变更(Breaking Changes)周期展开,核心讲解两个被彻底移除的废弃 API——Arduino 风格的 GPIO 宏定义和isLeftHand变量——的迁移方案与源码级原理,并完整梳理本次周期中 Core、CLI、Keyboards 与 Bug 修复的全部变更清单。读完后,你可以准确完成老代码向新 API 的迁移,理解 QMK GPIO 抽象层与 Split 键盘左右手判定机制的底层实现,并掌握该版本引入的 CLI 与构建系统改动。

一、变更背景:为什么 QMK 会做破坏性变更

QMK 的破坏性变更集中记录在 docs/ChangeLog 目录下的按日期命名的文件中,从20190830.md一直延续到20260531.md,本周期对应的文档即 docs/ChangeLog/20260222.md。QMK 采用季度节奏发布 Breaking Changes:先提供兼容性过渡期(deprecated 警告),再在后续周期正式移除。本周期移除的两个目标,正是之前几个周期中已发出弃用通知的旧接口,这符合 QMK 的弃用策略——过渡期结束后不再保留向后兼容层。

二、移除废弃的 GPIO 定义(PR #26028)

2.1 问题背景

QMK 长期使用 Arduino 风格的 GPIO 命名习惯(例如DDxPORTxPINx这类寄存器级宏)。随着平台演进,这类命名不断出现新的变体,也导致用户误以为 QMK 兼容整个 Arduino 生态。为此,QMK 决定将 GPIO 操作函数统一重命名为符合 QMK Firmware 自身代码风格的gpio_*系列函数,并在本周期移除了全部向后兼容的旧定义

2.2 现行 GPIO 抽象层 API

官方推荐的替代接口完整收录于 GPIO 控制文档,其核心宏定义位于platforms/<platform>/gpio.h(每个平台一份实现,抽象层与具体微控制器无关)。常用宏及语义如下:

说明
gpio_set_pin_input(pin)设置为高阻态输入(High-Z)
gpio_set_pin_input_high(pin)设置为带内部上拉电阻的输入
gpio_set_pin_input_low(pin)设置为带内部下拉电阻的输入(AVR 上不可用)
gpio_set_pin_output(pin)设置为输出(gpio_set_pin_output_push_pull的别名)
gpio_set_pin_output_push_pull(pin)设置为推挽输出
gpio_set_pin_output_open_drain(pin)设置为开漏输出(AVR 上不可用)
gpio_write_pin_high(pin)/gpio_write_pin_low(pin)将输出引脚电平置高 / 置低
gpio_write_pin(pin, level)按给定电平写输出引脚
gpio_read_pin(pin)读取引脚电平
gpio_toggle_pin(pin)翻转输出引脚电平

对于架构相关的进阶需求,抽象层并不限制直接使用平台原生接口:AVR 使用标准avr/io.h库,STM32(ChibiOS)使用 PAL 库。

2.3 原子性注意事项

需要提醒的是,上述函数并不保证原子性。若在多个 GPIO 操作组合中不希望被中断打断,应使用ATOMIC_BLOCK_FORCEON宏包裹关键段,例如:

void some_function(void) { // some process ATOMIC_BLOCK_FORCEON { // Atomic Processing } // some process }

ATOMIC_BLOCK_FORCEON会无条件在块执行前关中断、执行完毕后开中断,因此仅在你确定进入块前中断是开启的、且块结束时允许开中断的场景下使用。

从源码结构看,这套 API 已被广泛用于 QMK 内部。例如 split_util.c 中读取 Split 键盘左右手判定引脚时就调用了gpio_set_pin_inputgpio_read_pin,说明新命名规范不仅是对外接口,也是内部实现的一致标准。

三、移除废弃的 isLeftHand(PR #25897)

3.1 迁移方式

使用 Split 键盘的用户应从全局变量isLeftHand迁移到 split_util.h 提供的is_keyboard_left()函数。官方给出的典型迁移示例(OLED 旋转角度按左右手区分):

oled_rotation_t oled_init_user(oled_rotation_t rotation) { - return isLeftHand ? OLED_ROTATION_180 : OLED_ROTATION_0; + return is_keyboard_left() ? OLED_ROTATION_180 : OLED_ROTATION_0; }

原文档说明,废弃变量isLeftHand将在下一个破坏性变更周期被移除。而从当前仓库快照看,quantum/tmk_core/目录下已搜索不到isLeftHand的任何定义或引用,可以推断该变量在后续周期(本仓库 ChangeLog 序列中已有更晚的20260531.md)中已被彻底清除,迁移到函数式 API 已无退路。

3.2 源码级原理:is_keyboard_left() 是如何计算的

is_keyboard_left()的声明位于 quantum/keyboard.h,其实现与判定逻辑集中在 quantum/split_common/split_util.c。核心结构是一个"弱符号 + 初始化时固化"的设计:

  1. is_keyboard_left_impl()(弱符号,可被键盘覆写):按编译期宏依次采用不同判定策略——
    • SPLIT_HAND_PIN:将引脚设为输入,等待 100us 后读取电平;SPLIT_HAND_PIN_LOW_IS_LEFT可反转高低电平含义;
    • SPLIT_HAND_MATRIX_GRID:直接窥视矩阵交点peek_matrix_intersection(),即利用矩阵中的某个按键组合区分左右手;
    • EE_HANDS:从 EEPROM 读取手性配置(eeconfig_read_handedness()),并支持INIT_EE_HANDS_LEFT/RIGHT的初始伪造逻辑;
    • MASTER_RIGHT:以"是否为主侧"取反判定;
    • 默认(无宏定义):左右手等价于主从侧(is_keyboard_master())。
  2. split_pre_init()固化配置:在键盘完全初始化之前,先调用is_keyboard_master_impl()is_keyboard_left_impl(),把结果写入全局结构split_config.master/split_config.left。其中is_keyboard_master_impl()通过usb_bus_detected()判断哪一侧连着 USB 线。
  3. is_keyboard_left()本体:只是一个弱符号,默认返回split_config.left,即"启动时算一次、之后 O(1) 读取",避免在高频调用路径上反复读引脚。

这套机制的调用面很广,从源码可以确认它被用于:矩阵扫描的半侧行偏移计算(quantum/matrix.c 与 quantum/matrix_common.c)、Bootmagic 功能仅在右手侧启用(quantum/bootmagic/bootmagic.c)、RGB 矩阵左右侧 LED 索引裁剪(quantum/rgb_matrix/rgb_matrix.c)、LED 矩阵侧向裁剪(quantum/led_matrix/led_matrix.h)以及 Split 传输事务(quantum/split_common/transactions.c)。这正是"变量改函数"迁移的价值:函数式接口可以统一走split_config缓存,并允许用户在用户空间以 weak symbol 覆写方式自定义判定逻辑,而一个裸全局变量无法提供这种扩展点。

四、Core 核心变更清单

本次 Core 层变更共 10 项,全部继承自原文档并补充上下文:

  • 重构 Makefile 中定位 keymap 的逻辑(#25808):keymap 查找流程收敛到 builddefs/locate_keymap.mk 等构建定义文件中,属于构建系统内部重构;
  • 将关机延迟移入 audio 特性(#25859):SHUTDOWN_DELAY_MS相关行为从通用启动路径归位到 audio 模块,未启用音频的构建不再承担该逻辑;
  • 重构核心代码中对废弃isLeftHand的使用(#25888):即上文第三节的内部迁移;
  • 允许社区模块自定义数据同步(#25955):community modules 的data sync(跨侧同步变量)机制开放给第三方模块定制;
  • 移除一个不可达的 break 语句(#26006);
  • 移除重复的 host.h(#26007);
  • 移除冗余的 EEPROM 更新(#26008):减少 Flash/EEPROM 写入,与磨损均衡方向一致;
  • 移除apa102_set_brightness中冗余的无符号比较(#26010);
  • 移除未使用的头文件(#26011);
  • 分配失败时返回INVALID_DEFERRED_TOKEN(#26012):Deferred 键码(如DT(M)延迟宏)在动态内存分配失败时的返回值由静默失败变为显式无效 token,行为更可预测;
  • 移除废弃的 GPIO 定义(#26028):本周期最重要的破坏性变更,见第二节。

五、CLI 工具链变更

qmk命令行工具(Python)本周期改动 11 项,对使用 CLI 开发流程的用户影响最大:

  • 格式化文件时强制 EOL(#24989):qmk format输出的换行风格保持一致;
  • 允许 keymap.json 关闭配置项(#25502):keymap 级配置可以显式 disable 某些 feature flag,而不仅是 enable;
  • 移除未使用的qmk.keymap.write_file/qmk.keymap.write_json内部接口(#25854);
  • version.h 中加入 userspace 版本号(QMK_USERSPACE_VERSION(#25882):使用外部 userspace 时,烧录出的固件版本字符串可以区分 userspace 版本;
  • 对越界 bootmagic 配置执行 lint 校验(#25899),并与第六节的 bootmagic 越界修复(#25898)配套;
  • qmk doctor报告权限问题(#25931):环境诊断命令能提示文件权限导致的异常;
  • CLI 格式化命令的排版微调(#25946);
  • lint 新增 keymap 名称合法性校验(#25969):不合规的 keymap 命名会在 lint 阶段报错;
  • new-keyboard的开发板提示增加"以上都不是"选项(#25998);
  • 生成的 info.json 不再包含config_h_features(#26024):info.json 字段收敛,feature 开关统一由构建系统推导;
  • defaults 重复检查从警告提升为错误(#26025):KEYMAPLAYOUT_宏重复等冲突配置将直接导致构建失败而非静默选择。

六、Keyboards 层变更与 Bug 修复

6.1 键盘定义与代码整理

  • 新增Soldered Macro Pad键盘(#25834),对应目录 keyboards/soldered;
  • 从各键盘.json中移除冗余 URL 字段(#25856);
  • projectcain/vault*增加编码器行为的守卫条件(#25864),避免特定构建下编码器配置冲突;
  • 重构键盘与 keymap 中对废弃isLeftHand的使用(#25891):即键盘层面的迁移;
  • 移除部分不必要的 matrix extern 声明(#25975);
  • ROW_SHIFTER迁移到核心MATRIX_ROW_SHIFTER(#25977):行移位扫描不再依赖键盘侧定义,统一由核心矩阵处理,减少各键盘重复实现。

6.2 Bug 修复(对稳定性影响最大的一节)

  • 修复 Flash 磨损均衡的扇区计算错误(#24776):影响 drivers/wear_leveling 模块在多次 EEPROM 写入后的扇区轮转;
  • 修复 Split 键盘上 WS2812 的 LED 索引错误(#25407):左右两侧 LED 编号拼接逻辑修正,与RGBLED_SPLIT裁剪机制相关;
  • qmk new-keymap能正确解析键盘别名(#25570):通过 alias 引用的键盘在创建 keymap 时不再解析失败;
  • 修复 is31fl3729 LED 矩阵驱动的 off-by-one 错误(#25902):SPI LED 矩阵(IS31FL3729)行列边界偏差修正;
  • Match Key 覆写索引类型与边界类型对齐,防止溢出(#25939):MATCH_KEY匹配覆写的索引计算改为与边界检查相同的有符号类型,消除负值比较绕过问题。

6.3 其他变更

  • 为 DD(double tap,双重触发)键码定义补充缺失的标签(#25503),改善键码文档与自动补全;
  • 新增面向 Pull Request 的 Copilot 协作说明(#25857),属于协作流程改进,不影响固件行为。

七、给开发者的落地检查清单

  1. 全局搜索旧 GPIO 宏:在你的 keymap、keyboard 与 userspace 中搜索DD[A-Z]PORT[A-Z]PIN[A-Z]_HIGH/_LOW等 Arduino 风格用法,全部替换为第二节表格中的gpio_*函数;
  2. 搜索isLeftHand:替换为is_keyboard_left(),并确认头文件包含来自split_util.h的声明路径(quantum/keyboard.h 亦可作为声明来源);
  3. 升级后跑一遍qmk lintqmk doctor:本周期 lint 新增了 keymap 名称与 bootmagic 越界检查,qmk doctor增加了权限诊断,能提前暴露配置问题;
  4. 注意构建失败语义变化:defaults 重复等过去仅是警告的场景现在会直接报错(#26025),CI 中若有"忽略警告"的宽松策略需要更新;
  5. 关注 info.json 消费方:若你有脚本解析键盘info.jsonconfig_h_features字段,需要适配该字段的移除(#26024)。

本次变更周期的完整原始记录见 docs/ChangeLog/20260222.md,GPIO 抽象层详细说明见 docs/drivers/gpio.md,GPIO 各平台实现位于 platforms 目录下对应平台的gpio.h

【免费下载链接】qmk_firmwareOpen-source keyboard firmware for Atmel AVR and Arm USB families项目地址: https://gitcode.com/GitHub_Trending/qm/qmk_firmware

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询