QMK鍵盤固件自定義指南 - 打造你的專屬鍵盤體驗

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 coluint8_t row}bool     presseduint16_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_TIMEOUTcheck_rgb_timeout();
#endif
}/* 每次按鍵后檢查是否有活動 */
void post_process_record_user(uint16_t keycode, keyrecord_t *record) {
#ifdef RGBLIGHT_TIMEOUTif (record->event.pressed)refresh_rgb();
#endif
}/* 每次旋鈕更新后檢查是否有活動 */
void post_encoder_update_user(uint8_t index, bool clockwise) {
#ifdef RGBLIGHT_TIMEOUTrefresh_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 {// 軟重置,關閉LEDrgb_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.pswp.cn/web/79280.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/79280.shtml
英文地址,請注明出處:http://en.pswp.cn/web/79280.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

5.9培訓

文件上傳 先找文件上傳的地方&#xff0c;打開代理鏈接BP&#xff0c;它需要一個xls文件 我們創建一個sqzr.xls bp攔截了之后&#xff0c;我們修改請求&#xff0c;把后綴改成php&#xff0c;發送請求 找到我們的靜態資源所在的位置 訪問http://192.168.1.100:81/static/upload…

【FAQ】HarmonyOS SDK 閉源開放能力 — PDF Kit

1.問題描述&#xff1a; 預覽PDF文件&#xff0c;文檔上所描述的loadDocument接口&#xff0c;可以返回文件的狀態&#xff0c;并無法實現PDF的預覽&#xff0c;是否有能預覽PDF相關接口&#xff1f; 解決方案&#xff1a; 1、執行loadDocument進行加載PDF文件后&#xff0c…

AutoDL實現端口映射與遠程連接AutoDL與Pycharm上傳文件到遠程服務器(李沐老師的環境)

文章目錄 以上配置的作用前提AutoDL實現端口映射遠程連接AutoDLPycharm上傳文件到遠程服務器以上配置的作用 使用AutoDL的實例:因本地沒有足夠強的算力,所以需要使用AutoDL AutoDL端口映射:當在實例上安裝深度學習的環境,但因為實例的linux系統問題,無法圖形化顯示d2l中的文件…

【Linux系列】跨平臺安裝與配置 Vim 文本編輯器

&#x1f49d;&#x1f49d;&#x1f49d;歡迎來到我的博客&#xff0c;很高興能夠在這里和您見面&#xff01;希望您在這里可以感受到一份輕松愉快的氛圍&#xff0c;不僅可以獲得有趣的內容和知識&#xff0c;也可以暢所欲言、分享您的想法和見解。 推薦:kwan 的首頁,持續學…

CountDownLatch 并發編程中的同步利器

CountDownLatch 并發編程中的同步利器 文章目錄 CountDownLatch 并發編程中的同步利器一、CountDownLatch 基礎概念1.1 什么是 CountDownLatch&#xff1f;1.2 CountDownLatch 的核心方法1.3 基本使用示例 二、CountDownLatch 實戰應用2.1 應用場景一&#xff1a;并行任務協調2…

Linux 內核鏈表宏的詳細解釋

&#x1f527; Linux 內核鏈表結構概覽 Linux 內核中的鏈表結構定義在頭文件 <linux/list.h> 中。核心結構是&#xff1a; struct list_head {struct list_head *next, *prev; }; 它表示一個雙向循環鏈表的節點。鏈表的所有操作都圍繞這個結構體展開。 &#x1f9e9; …

分書問題的遞歸枚舉算法

分數問題的遞歸枚舉算法 一、問題引入二、解題步驟1.問題分析思維導圖2.解題步驟 三、代碼實現1.代碼2.復雜度分析 四、個人總結 一、問題引入 分書問題是指&#xff1a;已知 n 個人對 m 本書的喜好&#xff08;n≤m&#xff09;&#xff0c;現要將 m 本書分給 n 個人&#xf…

密碼學--AES

一、實驗目的 1、完成AES算法中1輪加密和解密操作 2、掌握AES的4個基本處理步驟 3、理解對稱加密算法的“對稱”思想 二、實驗內容 1、題目內容描述 &#xff08;1&#xff09;利用C語言實現字節代換和逆向字節代換&#xff0c;字節查S盒代換 &#xff08;2&#xff09;利…

【工具記錄分享】提取bilibili視頻字幕

F12大法 教程很多 但方法比較統一 例快速提取視頻字幕&#xff01;適用B站、AI字幕等等。好用 - 嗶哩嗶哩 無腦小工具 嗶哩嗶哩B站字幕下載_在線字幕解析-飛魚視頻下載助手 把鏈接扔進去就會自動生成srt文件 需要txt可以配合&#xff1a; SRT轉為TXT

使用fdisk 、gdisk管理分區

用 fdisk 管理分區 fdisk 命令工具默認將磁盤劃分為 mbr 格式的分區 命令&#xff1a; fdisk 設備名 fdisk 命令以交互方式進行操作的&#xff0c;在菜單中選擇相應功能鍵即可 [rootlocalhost ~]# fdisk /dev/sda # 對 sda 進行分區 Command (m for help): # 進入 fdis…

【Linux基礎】程序和軟件安裝管理命令

目錄 install命令 which命令 install命令 作用&#xff1a;它是用于安裝或復制文件到指定位置&#xff0c;并且可以同時設置文件的權限、所有者和所屬組等屬性。它通常用于腳本中&#xff0c;用于自動化安裝程序或配置文件的部署。 基本用法&#xff1a; install [選項] 源…

C++模板梳理

目錄 函數模板 類模板 變量模板 模板全特化 模板偏特化 模板顯式實例化解決文件分離問題 折疊表達式 模板的二階段編譯 待決名(dependent name) SFINAE 概念與約束 函數模板 函數模板不是函數&#xff0c;只有實例化的函數模板&#xff0c;編譯器才能生成實際的函數…

數據鏈共享:從印巴空戰到工業控制的跨越性應用

摘要 本文通過對印巴空戰中數據鏈共享發揮關鍵作用的分析&#xff0c;引出數據鏈共享在工業控制領域同樣具有重大價值的觀點。深入闡述 DIOS 工業控制操作系統作為工業數據鏈共享基礎技術的特點、架構及應用優勢&#xff0c;對比空戰場景與工業控制場景下數據鏈共享的相…

巡檢機器人數據處理技術的創新與實踐

摘要 隨著科技的飛速發展&#xff0c;巡檢機器人在各行業中逐漸取代人工巡檢&#xff0c;展現出高效、精準、安全等顯著優勢。當前&#xff0c;巡檢機器人已從單純的數據采集階段邁向對采集數據進行深度分析的新階段。本文探討了巡檢機器人替代人工巡檢的現狀及優勢&#xff0c…

在 Flink + Kafka 實時數倉中,如何確保端到端的 Exactly-Once

在 Flink Kafka 構建實時數倉時&#xff0c;確保端到端的 Exactly-Once&#xff08;精確一次&#xff09; 需要從 數據消費&#xff08;Source&#xff09;、處理&#xff08;Processing&#xff09;、寫入&#xff08;Sink&#xff09; 三個階段協同設計&#xff0c;結合 Fli…

當可視化遇上 CesiumJS:突破傳統,打造前沿生產配套方案

CesiumJS 技術基礎介紹 CesiumJS 是一款基于 JavaScript 的開源庫&#xff0c;專門用于創建動態、交互式的地理空間可視化。它利用 WebGL 技術&#xff0c;能夠在網頁瀏覽器中流暢地渲染高分辨率的三維地球和地圖場景。CesiumJS 支持多種地理空間數據格式&#xff0c;包括但不…

RabbitMQ深入學習

繼續上一節的學習&#xff0c;上一節學習了RabbitMQ的基本內容&#xff0c;本節學習RabbitMQ的高級特性。 RocketMQ的高級特性學習見這篇博客 目錄 1.消息可靠性1.1生產者消息確認1.2消息持久化1.3消費者消息確認1.4消費失敗重試機制1.5消息可靠性保證總結 2.什么是死信交換機…

Linux系統:虛擬文件系統與文件緩沖區(語言級內核級)

本節重點 初步理解一切皆文件理解文件緩沖區的分類用戶級文件緩沖區與內核級文件緩沖區用戶級文件緩沖區的刷新機制兩級緩沖區的分層協作 一、虛擬文件系統 1.1 理解“一切皆文件” 我們都知道操作系統訪問不同的外部設備&#xff08;顯示器、磁盤、鍵盤、鼠標、網卡&#…

在c++中老是碰到string,這是什么意思?

定義一個string類型變量的引用&#xff0c;相當于給現有變量起個別名&#xff0c;與指針還是不一樣的。比如string a;string& ba;這兩句&#xff0c;b與a實際上是一回事&#xff0c;表示的是同一塊內存。 std是系統的一個命名空間(有關命名空間可以參閱namespace_百度百科)…

Day21 奇異值分解(SVD)全面解析

一、奇異值分解概述 奇異值分解是線性代數中一個重要的矩陣分解方法&#xff0c;對于任何矩陣&#xff0c;無論是結構化數據轉化成的“樣本 * 特征”矩陣&#xff0c;還是天然以矩陣形式存在的圖像數據&#xff0c;都能進行等價的奇異值分解&#xff08;SVD&#xff09;。 二…