QMK键盘固件自定义指南 - 打造你的专属键盘体验

news2025/5/13 2:26:25

QMK键盘固件自定义指南 - 打造你的专属键盘体验

🚀 前言

在机械键盘的世界里,QMK固件让你的键盘不再只是简单的输入设备,而是可以按照你的意愿定制的强大工具。本文将深入浅出地介绍如何自定义QMK键盘的行为,从基础概念到高级应用,带你玩转QMK!

📚 QMK的分层架构

QMK采用分层架构设计,从上到下依次为:

  • 核心层(_quantum):提供基础功能
  • 社区模块层(_<module>):提供扩展功能
    • 社区模块 -> 键盘/修订版(_<module>_kb)
    • 社区模块 -> 键盘映射(_<module>_user)
  • 键盘/修订版层(_kb):特定键盘的功能
  • 键盘映射层(_user):用户自定义配置

💡 小贴士:在键盘/修订版级别定义函数时,必须在适当位置调用_user(),否则键盘映射级别的函数将永远不会被执行。

🔑 自定义键码

定义新键码

创建自定义键码的第一步是枚举它们。QMK提供了SAFE_RANGE宏来确保你的自定义键码获得唯一的编号。

enum my_keycodes {
  FOO = SAFE_RANGE,
  BAR
};

通过这段代码,你可以在键盘映射中使用FOOBAR两个自定义键码。

编程键码行为

要控制键码的行为,你需要使用process_record_kb()process_record_user()函数。这些函数在按键处理过程中被调用:

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
  switch (keycode) {
    case FOO:
      if (record->event.pressed) {
        // 按下时执行的代码
      } else {
        // 释放时执行的代码
      }
      return false; // 跳过此键的后续处理
    case KC_ENTER:
      // 按下回车键时播放音效
      if (record->event.pressed) {
        PLAY_SONG(tone_qwerty);
      }
      return true; // 让QMK继续处理回车键的按下/释放事件
    default:
      return true; // 正常处理所有其他键码
  }
}

record参数包含按键事件的详细信息:

keyrecord_t record {
  keyevent_t event {
    keypos_t key {
      uint8_t col
      uint8_t row
    }
    bool     pressed
    uint16_t time
  }
}

⚙️ 键盘初始化流程

键盘初始化过程分为三个主要阶段:

  1. 键盘预初始化keyboard_pre_init_* - 在大多数功能初始化前执行,适合进行早期硬件设置
  2. 矩阵初始化matrix_init_* - 在固件启动过程中期执行
  3. 键盘后初始化keyboard_post_init_* - 在固件启动过程结束时执行,适合放置"自定义"代码

⚠️ 注意:对于大多数用户,keyboard_post_init_user是你想要实现的函数。例如,这是设置RGB底光的理想位置。

键盘预初始化示例

void keyboard_pre_init_user(void) {
  // 调用键盘预初始化代码

  // 设置LED引脚为输出模式
  gpio_set_pin_output(B0);
  gpio_set_pin_output(B1);
  gpio_set_pin_output(B2);
  gpio_set_pin_output(B3);
  gpio_set_pin_output(B4);
}

键盘后初始化示例

void keyboard_post_init_user(void) {
  // 调用后初始化代码
  rgblight_enable_noeeprom(); // 启用RGB灯光但不保存设置
  rgblight_sethsv_noeeprom(180, 255, 255); // 设置青色但不保存
  rgblight_mode_noeeprom(RGBLIGHT_MODE_BREATHING + 3); // 设置快速呼吸模式但不保存
}

🔄 矩阵扫描与内务管理

矩阵扫描

矩阵扫描函数在每次按键矩阵扫描时被调用,频率非常高。需要谨慎编写这部分代码以避免影响键盘性能。

void matrix_scan_user(void) {
  // 这里的代码将以MCU能处理的最高频率运行,请谨慎添加代码
}

键盘内务管理

内务管理函数在所有QMK处理结束后、开始下一次迭代前调用:

void housekeeping_task_user(void) {
  // 此时所有按键处理、层状态更新、USB报告发送、LED更新等已完成
}

下面是一个使用housekeeping_task_user实现RGB灯光超时关闭的示例:

#define RGBLIGHT_SLEEP  // 在keymap.c中启用rgblight_suspend()和rgblight_wakeup()
#define RGBLIGHT_TIMEOUT 900000  // RGB超时时间,900K毫秒即15分钟

static uint32_t key_timer;           // 最后键盘活动的计时器
static void refresh_rgb(void);       // 刷新活动计时器和RGB
static void check_rgb_timeout(void); // 检查RGB是否超时
bool is_rgb_timeout = false;         // 存储RGB是否已超时

void refresh_rgb(void) {
    key_timer = timer_read32(); // 存储最后刷新时间
    if (is_rgb_timeout)
    {
        is_rgb_timeout = false;
        rgblight_wakeup();
    }
}

void check_rgb_timeout(void) {
    if (!is_rgb_timeout && timer_elapsed32(key_timer) > RGBLIGHT_TIMEOUT) 
    {
        rgblight_suspend();
        is_rgb_timeout = true;
    }
}

/* 在QMK内置的后处理函数中调用上述函数 */
void housekeeping_task_user(void) {
#ifdef RGBLIGHT_TIMEOUT
    check_rgb_timeout();
#endif
}

/* 每次按键后检查是否有活动 */
void post_process_record_user(uint16_t keycode, keyrecord_t *record) {
#ifdef RGBLIGHT_TIMEOUT
    if (record->event.pressed)
        refresh_rgb();
#endif
}

/* 每次旋钮更新后检查是否有活动 */
void post_encoder_update_user(uint8_t index, bool clockwise) {
#ifdef RGBLIGHT_TIMEOUT
    refresh_rgb();
#endif
}

💤 键盘休眠与唤醒

如果你的键盘支持,可以通过以下函数控制键盘休眠状态:

void suspend_power_down_user(void) {
    // 键盘休眠时运行的代码,会被多次调用
}

void suspend_wakeup_init_user(void) {
    // 键盘唤醒时运行的代码
}

🔌 键盘关机与重启

当固件重置时(软重置或跳转到引导加载程序),会调用shutdown_*函数:

bool shutdown_kb(bool jump_to_bootloader) {
    if (!shutdown_user(jump_to_bootloader)) {
        return false;
    }
    
    if (jump_to_bootloader) {
        // 准备跳转到引导加载程序,设置红色
        rgb_matrix_set_color_all(RGB_RED);
    } else {
        // 软重置,关闭LED
        rgb_matrix_set_color_all(RGB_OFF);
    }
    // 强制刷新缓冲区
    rgb_matrix_update_pwm_buffers();
    return true;
}

⏱️ 延迟执行

QMK提供了延迟执行功能,可以在指定时间后执行回调。要启用此功能,在rules.mk中添加:

DEFERRED_EXEC_ENABLE = yes

延迟执行回调函数示例:

uint32_t my_callback(uint32_t trigger_time, void *cb_arg) {
    /* 执行一些操作 */
    bool repeat = my_deferred_functionality();
    return repeat ? 500 : 0; // 如果需要重复,返回500毫秒延迟,否则返回0
}

注册延迟执行:

deferred_token my_token = defer_exec(1500, my_callback, NULL);

📊 Keymap概述

键盘映射和图层

QMK中的键盘映射保存在const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS]数组中,最多可以定义32个图层(0-31),较高的图层具有优先权。

Keymap: 32 Layers                   Layer: action code matrix
-----------------                   ---------------------
stack of layers                     array_of_action_code[row][column]
       ____________ precedence               _______________________
      /           / | high                  / ESC / F1  / F2  / F3   ....
  31 /___________// |                      /-----/-----/-----/-----
  30 /___________// |                     / TAB /  Q  /  W  /  E   ....
  29 /___________/  |                    /-----/-----/-----/-----
   :   _:_:_:_:_:__ |               :   /LCtrl/  A  /  S  /  D   ....
   :  / : : : : : / |               :  /  :     :     :     :
   2 /___________// |               2 `--------------------------
   1 /___________// |               1 `--------------------------
   0 /___________/  V low           0 `--------------------------

键盘映射层状态由两个32位参数决定:

  • default_layer_state - 表示基本键盘映射层(0-31)
  • layer_state - 在其位中保存每个图层的开/关状态

图层优先级和透明度

较高层在图层堆栈中具有更高优先级。固件从最高活动层向下工作以查找键码。一旦找到非透明键码,就停止搜索。

如果在高层使用透明键码(KC_TRNS_______KC_TRANSPARENT),则会使用下层对应位置的键码。

Keymap.c文件解析

一个典型的keymap.c文件包含两个主要部分:

  1. 定义(包括自定义键码、图层名称等)
  2. 图层/键盘映射数据结构

定义部分示例:

#include QMK_KEYBOARD_H

// 有用的定义
#define GRAVE_MODS  (MOD_BIT(KC_LSFT)|MOD_BIT(KC_RSFT)|MOD_BIT(KC_LGUI)|MOD_BIT(KC_RGUI)|MOD_BIT(KC_LALT)|MOD_BIT(KC_RALT))

// 每个图层都有一个名称以提高可读性
enum layer_names {
    _BL, // 基础层
    _FL, // 功能层
    _CL, // 控制层
};

图层定义示例(基础层):

[_BL] = LAYOUT(
    F(0),    KC_1,    KC_2,   KC_3,   KC_4,   KC_5,   KC_6,   KC_7,   KC_8,   KC_9,    KC_0,     KC_MINS,  KC_EQL,   KC_GRV,  KC_BSPC,          KC_PGUP,
    KC_TAB,  KC_Q,    KC_W,   KC_E,   KC_R,   KC_T,   KC_Y,   KC_U,   KC_I,   KC_O,    KC_P,     KC_LBRC,  KC_RBRC,  KC_BSLS,                   KC_PGDN,
    KC_CAPS, KC_A,    KC_S,   KC_D,   KC_F,   KC_G,   KC_H,   KC_J,   KC_K,   KC_L,    KC_SCLN,  KC_QUOT,  KC_NUHS,  KC_ENT,
    KC_LSFT, KC_NUBS, KC_Z,   KC_X,   KC_C,   KC_V,   KC_B,   KC_N,   KC_M,   KC_COMM, KC_DOT,   KC_SLSH,  KC_INT1,  KC_RSFT,          KC_UP,
    KC_LCTL, KC_LGUI, KC_LALT, KC_INT5,          KC_SPC,KC_SPC,                        KC_INT4,  KC_RALT,  KC_RCTL,  MO(_FL), KC_LEFT, KC_DOWN, KC_RGHT
),

功能层示例:

[_FL] = LAYOUT(
    KC_GRV,  KC_F1,   KC_F2,  KC_F3,  KC_F4,  KC_F5,  KC_F6,  KC_F7,  KC_F8,  KC_F9,   KC_F10,   KC_F11,   KC_F12,   _______, KC_DEL,           BL_STEP,
    _______, _______, _______,_______,_______,_______,_______,_______,KC_PSCR,KC_SCRL, KC_PAUS,  _______,  _______,  _______,                   _______,
    _______, _______, MO(_CL),_______,_______,_______,_______,_______,_______,_______, _______,  _______,  _______,  _______,
    _______, _______, _______,_______,_______,_______,_______,_______,_______,_______, _______,  _______,  _______,  _______,          KC_PGUP,
    _______, _______, _______, _______,        _______,_______,                        _______,  _______,  _______,  MO(_FL), KC_HOME, KC_PGDN, KC_END
),

🔍 拓展知识

1. 社区模块

社区模块是QMK的扩展功能,允许第三方实现代码供他人导入。要添加社区模块到你的构建中,在keymap.json中添加:

{
    "modules": [
        "qmk/hello_world"
    ]
}

2. EEPROM持久配置

QMK可以使用EEPROM存储长期保持的配置,如默认图层、RGB灯效设置等。这使得设置可以在断电后保持。

3. Bootloader驱动安装

在Windows上刷写键盘固件时,有时需要为bootloader安装特殊驱动程序。推荐使用Zadig工具安装正确的驱动。

4. QMK键码类型

QMK支持多种类型的键码:

  • 基本键码:如KC_AKC_ENTER
  • 修饰键:如KC_LSHIFTKC_RALT
  • 图层切换:如MO()TG()TO()
  • 一键多用(Mod-Tap):如LCTL_T(KC_ESC)
  • 宏键:用户自定义的复杂功能

📝 总结

QMK提供了极其强大且灵活的键盘自定义能力,从简单的键位重映射到复杂的宏和功能。通过本文介绍的技术,你可以:

  1. 创建自定义键码并定义其行为
  2. 设置多层键盘映射实现不同功能
  3. 利用键盘初始化生命周期自定义键盘启动行为
  4. 使用矩阵扫描和内务管理函数添加特殊功能
  5. 实现节能休眠和唤醒功能
  6. 利用延迟执行实现定时任务

无论你是想要一个简单的QWERTY布局还是构建一个复杂的编程工作站,QMK都能满足你的需求。开始你的键盘自定义之旅吧!

🔗 相关资源

  • QMK官方文档
  • QMK键码列表
  • QMK Keymap常见问题
  • QMK社区

如果你对如何改进本文有任何建议,欢迎提交Issue!我们正在积极努力改进这些文档。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2374338.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

upload-labs靶场通关详解:第四关

一、分析源代码 可以看出这一关仍然是黑名单验证&#xff0c;但是它禁止了更多的后缀。像php3&#xff0c;php4这类后缀也被加入了黑名单&#xff0c;第三关的方法在这里显然就失效了。那么我们想一想&#xff0c;既然配置文件中存在将php3当作php来执行的功能&#xff0c;那么…

openharmony系统移植之gpu mesa3d适配

openharmony系统移植之gpu mesa3d适配 文章目录 openharmony系统移植之gpu mesa3d适配1. 环境说明2. gpu内核panfrost驱动2.1 使能panfrost驱动2.2 panfrost dts配置 3. buildroot下测试gpu驱动3.1 buildroot配置编译 4. ohos下mesa3d适配4.1 ohos下mesa3d编译调试4.1.2 编译4.…

Linux58 ssh服务配置 jumpserver 测试双网卡 为何不能ping通ip地址

判断为NAT模式网卡 能ping 通外网 ens34为仅主机模式网卡 [rootlocalhost network-scripts]# ip route show default default via 10.1.1.254 dev ens33 proto static metric 100 10.0.0.0/8 dev ens33 proto kernel scope link src 10.1.1.37 metric 100 11.0.0.0/8 dev…

web 自动化之 selenium+webdriver 环境搭建及原理讲解

文章目录 一、web 自动化测试学习说明二、什么 web 自动化测试三、selenium 简介四、web自动化测试环境搭建五、web 自动化测试第一个脚本六、selenium 原理及源码讲解 一、web 自动化测试学习说明 进阶 web 自动化测试学习&#xff1a;掌握 python 编程基础 二、什么 web 自…

2025ISCC练武校级赛部分题解WP

Web 战胜卞相壹 <!-- 路过的酒罐王柯洁九段说&#xff1a; --> <!-- 会叠棋子有什么用&#xff01;你得在棋盘内战胜他&#xff01;我教你个定式&#xff0c;要一直记得&#xff01;一直&#xff01; --> <!-- SGF B[ae];B[ce];B[df];B[cg];B[ag];B[ai];B[ci];…

PyTorch 版本、torchvision 版本和 Python 版本的对应关系

PyTorch 版本、torchvision 版本和 Python 版本的对应关系 在深度学习领域&#xff0c;PyTorch 及其配套库 torchvision 的使用极为广泛。但不同版本的 PyTorch、torchvision 与 Python 之间存在严格的对应关系&#xff0c;若版本搭配不当&#xff0c;会导致代码运行出错…

RS485和RS232 通信配置

RS232 目前硬件上支持RS232的有以下板卡&#xff1a; LubanCat-5IO底板&#xff08;含有RS232x2&#xff09; 7.1. 引脚定义 具体的引脚定义可以参考背面的丝印 LubanCat-5IO底板 引脚定义图 7.2. 跳帽配置 LubanCat-5IO底板 鲁班买5IO底板上的RS485和RS232是共用同一组…

zst-2001 历年真题 设计模式

设计模式 - 第1题 a 设计模式 - 第2题 一个产品可以产生多个就是抽象&#xff0c;一个就是工厂 比如这样 第二题a是意图 bc: d 设计模式 - 第3题 b 设计模式 - 第4题 类图里全是builder,疯狂暗示 设计模式 - 第5题 aa 设计模式 - 第6题 只有工厂方法是创…

鸿蒙NEXT开发动画案例4

1.创建空白项目 2.Page文件夹下面新建Spin.ets文件&#xff0c;代码如下&#xff1a; /*** TODO SpinKit动画组件 - 双粒子旋转缩放动画* author: CSDN-鸿蒙布道师* since: 2025/05/08*/ ComponentV2 export struct SpinFour {// 参数定义Require Param spinSize: number 36…

XML语言

XML语言 在开始介绍Mybatis之前&#xff0c;先介绍一下XML语言&#xff0c;XML语言发明最初是用于数据的存储和传输&#xff0c;它是由一个一个的标签嵌套而成 <?xml version"1.0" encoding"UTF-8" ?> <outer> <name>阿伟</name&…

基于SpringBoot的小区停车位管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

VR博物馆,足不出户云逛展

VR博物馆概念与特点 定义与由来 VR博物馆&#xff0c;即虚拟现实(Virtual Reality)博物馆&#xff0c;是利用计算机技术、互联网和虚拟现实技术&#xff0c;将实体博物馆及其藏品数字化&#xff0c;实现在虚拟空间中的展示和体验的新型博物馆形式。概念起源于20世纪90年代末&…

uniapp|实现多终端聊天对话组件、表情选择、消息发送

基于UniApp框架,实现跨平台多终端适配的聊天对话组件开发、表情选择交互设计及消息发送,支持文本与表情混合渲染。 目录 聊天界面静态组件实现消息列表布局消息气泡双向布局辅助元素定位与样式静态数据模拟与扩展性设计表情选择器静态模块浮层实现符号网格排列多端样式适配方…

73页最佳实践PPT《DeepSeek自学手册-从理论模型训练到实践模型应用》

这份文档是一份关于 DeepSeek 自学手册的详细指南&#xff0c;涵盖了 DeepSeek V3 和 R1 模型的架构、训练方法、性能表现以及使用技巧等内容。它介绍了 DeepSeek V3 作为强大的 MoE 语言模型在数学、代码等任务上的出色表现以及其训练过程中的创新架构如多头潜在注意力和多 To…

stm32 WDG看门狗

目录 stm32 WDG看门狗一、WDG基础知识1&#xff09;WDG&#xff08;Watchdog&#xff09;看门狗简介 二、IWDG独立看门狗1&#xff09;IWDG键寄存器2&#xff09;IWDG超时时间 三、WWDG窗口看门狗1&#xff09;WWDG框图2&#xff09;WWDG工作特性3&#xff09;WWDG超时时间4&am…

BUUCTF——Cookie is so stable

BUUCTF——Cookie is so stable 进入靶场 页面有点熟悉 跟之前做过的靶场有点像 先简单看一看靶场信息 有几个功能点 flag.php 随便输了个admin 根据题目提示 应该与cookie有关 抓包看看 构造payload Cookie: PHPSESSIDef0623af2c1a6d2012d57f3529427d52; user{{7*7}}有…

用go从零构建写一个RPC(仿gRPC,tRPC)--- 版本1(Client端)

这里我们来实现这个RPC的client端 为了实现RPC的效果&#xff0c;我们调用的Hello方法&#xff0c;即server端的方法&#xff0c;应该是由代理来调用&#xff0c;让proxy里面封装网络请求&#xff0c;消息的发送和接受处理。而上一篇文章提到的服务端的代理已经在.rpc.go文件中…

一文读懂 AI

2022年11月30日&#xff0c;OpenAI发布了ChatGPT&#xff0c;2023年3月15日&#xff0c;GPT-4引发全球轰动&#xff0c;让世界上很多人认识了ai这个词。如今已过去快两年半&#xff0c;AI产品层出不穷&#xff0c;如GPT-4、DeepSeek、Cursor、自动驾驶等&#xff0c;但很多人仍…

【LeetCode Hot100 | 每日刷题】二叉树的层序遍历

题目&#xff1a; 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],[9,20],[15,7]]示例 2&a…

SpringBoot3集成Oauth2——1(/oauth2/token方法的升级踩坑)

备注&#xff1a;本文适用于你在SpringBoot2.7以前集成过oauth2&#xff0c;并且项目已经正式投入使用的情况&#xff0c;否则&#xff0c;我建议你直接学习或者找资料学习最新的oauth2集成&#xff0c;就不要纠结于老版本的oauth2。 原因&#xff1a;Spring Security 5.x和Sp…