diff --git a/docs/zh-cn/custom_quantum_functions.md b/docs/zh-cn/custom_quantum_functions.md index 42ceba9ca..f2c6098dc 100644 --- a/docs/zh-cn/custom_quantum_functions.md +++ b/docs/zh-cn/custom_quantum_functions.md @@ -1,31 +1,31 @@ -# 如何定制你键盘的功能 +# 濡備綍瀹氬埗浣犻敭鐩樼殑鍔熻兘 -对于很多人来说客制化键盘可不只是向你的电脑发送你按了那个件这么简单。你肯定想实现比简单按键和宏更复杂的功能。QMK有能让你注入代码的钩子, 覆盖功能, 另外,还可以自定义键盘在不同情况下的行为。 +瀵逛簬寰堝浜烘潵璇村鍒跺寲閿洏鍙笉鍙槸鍚戜綘鐨勭數鑴戝彂閫佷綘鎸変簡閭d釜浠惰繖涔堢畝鍗曘備綘鑲畾鎯冲疄鐜版瘮绠鍗曟寜閿拰瀹忔洿澶嶆潅鐨勫姛鑳姐俀MK鏈夎兘璁╀綘娉ㄥ叆浠g爜鐨勯挬瀛, 瑕嗙洊鍔熻兘, 鍙﹀锛岃繕鍙互鑷畾涔夐敭鐩樺湪涓嶅悓鎯呭喌涓嬬殑琛屼负銆 -本页不假定任何特殊的QMK知识,但阅读[理解QMK](understanding_qmk.md)将会在更基础的层面帮你理解发生了什么。 +鏈〉涓嶅亣瀹氫换浣曠壒娈婄殑QMK鐭ヨ瘑锛屼絾闃呰[鐞嗚ВQMK](understanding_qmk.md)灏嗕細鍦ㄦ洿鍩虹鐨勫眰闈㈠府浣犵悊瑙e彂鐢熶簡浠涔堛 -## A Word on Core vs 键盘 vs 布局 +## A Word on Core vs 閿洏 vs 甯冨眬 -我们把qmk组织成一个层次结构: +鎴戜滑鎶妐mk缁勭粐鎴愪竴涓眰娆$粨鏋勶細 * Core (`_quantum`) * Keyboard/Revision (`_kb`) * Keymap (`_user`) -下面描述的每一个函数都可以在定义上加一个`_kb()`或 `_user()` 后缀。 建议在键盘/修订层使用`_kb()`后缀,在布局层使用`_user()`后缀。 +涓嬮潰鎻忚堪鐨勬瘡涓涓嚱鏁伴兘鍙互鍦ㄥ畾涔変笂鍔犱竴涓猔_kb()`鎴 `_user()` 鍚庣紑銆 寤鸿鍦ㄩ敭鐩/淇灞備娇鐢╜_kb()`鍚庣紑锛屽湪甯冨眬灞備娇鐢╜_user()`鍚庣紑銆 -在键盘/修订层定义函数时,`_kb()`在执行任何代码前先调用`_user()`是必要的,不然布局层函数就不要被调用。 - -# 自定义键码 +鍦ㄩ敭鐩/淇灞傚畾涔夊嚱鏁版椂锛宍_kb()`鍦ㄦ墽琛屼换浣曚唬鐮佸墠鍏堣皟鐢╜_user()`鏄繀瑕佺殑锛屼笉鐒跺竷灞灞傚嚱鏁板氨涓嶈琚皟鐢ㄣ + +# 鑷畾涔夐敭鐮 -到目前为止,最常见的任务是更改现有键码的行为或创建新的键码。从代码角度来看这些操作都很相似。 +鍒扮洰鍓嶄负姝紝鏈甯歌鐨勪换鍔℃槸鏇存敼鐜版湁閿爜鐨勮涓烘垨鍒涘缓鏂扮殑閿爜銆備粠浠g爜瑙掑害鏉ョ湅杩欎簺鎿嶄綔閮藉緢鐩镐技銆 -## 定义一个新键码 +## 瀹氫箟涓涓柊閿爜 -创建键码第一步,先枚举出它全部,也就是给键码起个名字并分配唯一数值。QMK没有直接限制最大键码值大小,而是提供了一个`SAFE_RANGE`宏。你可以在枚举时用`SAFE_RANGE`来保证你取得了唯一的键码值。 +鍒涘缓閿爜绗竴姝ワ紝鍏堟灇涓惧嚭瀹冨叏閮紝涔熷氨鏄粰閿爜璧蜂釜鍚嶅瓧骞跺垎閰嶅敮涓鏁板笺俀MK娌℃湁鐩存帴闄愬埗鏈澶ч敭鐮佸煎ぇ灏忥紝鑰屾槸鎻愪緵浜嗕竴涓猔SAFE_RANGE`瀹忋備綘鍙互鍦ㄦ灇涓炬椂鐢╜SAFE_RANGE`鏉ヤ繚璇佷綘鍙栧緱浜嗗敮涓鐨勯敭鐮佸笺 -这有枚举两个键码的例子。把这块加到`keymap.c`的话你就在布局中能用`FOO`和`BAR`了。 +杩欐湁鏋氫妇涓や釜閿爜鐨勪緥瀛愩傛妸杩欏潡鍔犲埌`keymap.c`鐨勮瘽浣犲氨鍦ㄥ竷灞涓兘鐢╜FOO`鍜宍BAR`浜嗐 ```c enum my_keycodes { @@ -34,46 +34,46 @@ enum my_keycodes { }; ``` -## 为键码的行为编程 +## 涓洪敭鐮佺殑琛屼负缂栫▼ -当你覆盖一个已存在按键的行为时,或将这个行为赋给新键时,你要用`process_record_kb()`和`process_record_user()`函数。这俩函数在键处理中真实键事件被处理前被QMK调用。如果这俩函数返回`true`,QMK将会用正常的方式处理键码。这样可以很方便的扩展键码的功能而不是替换它。如果函数返回`false` QMK会跳过正常键处理,然后发送键子抬起还是按下事件就由你决定了。 +褰撲綘瑕嗙洊涓涓凡瀛樺湪鎸夐敭鐨勮涓烘椂锛屾垨灏嗚繖涓涓鸿祴缁欐柊閿椂锛屼綘瑕佺敤`process_record_kb()`鍜宍process_record_user()`鍑芥暟銆傝繖淇╁嚱鏁板湪閿鐞嗕腑鐪熷疄閿簨浠惰澶勭悊鍓嶈QMK璋冪敤銆傚鏋滆繖淇╁嚱鏁拌繑鍥瀈true`锛孮MK灏嗕細鐢ㄦ甯哥殑鏂瑰紡澶勭悊閿爜銆傝繖鏍峰彲浠ュ緢鏂逛究鐨勬墿灞曢敭鐮佺殑鍔熻兘鑰屼笉鏄浛鎹㈠畠銆傚鏋滃嚱鏁拌繑鍥瀈false` QMK浼氳烦杩囨甯搁敭澶勭悊锛岀劧鍚庡彂閫侀敭瀛愭姮璧疯繕鏄寜涓嬩簨浠跺氨鐢变綘鍐冲畾浜嗐 -当某个键按下或释放时这俩函数会被调用。 +褰撴煇涓敭鎸変笅鎴栭噴鏀炬椂杩欎咯鍑芥暟浼氳璋冪敤銆 -### process_record_user()`函数示例实现 +### process_record_user()`鍑芥暟绀轰緥瀹炵幇 -这个例子做了两个事。自定义了一个叫做`FOO`的键码的行为,并补充了在按下回车时播放音符。 +杩欎釜渚嬪瓙鍋氫簡涓や釜浜嬨傝嚜瀹氫箟浜嗕竴涓彨鍋歚FOO`鐨勯敭鐮佺殑琛屼负锛屽苟琛ュ厖浜嗗湪鎸変笅鍥炶溅鏃舵挱鏀鹃煶绗︺ ```c bool process_record_user(uint16_t keycode, keyrecord_t *record) { switch (keycode) { case FOO: if (record->event.pressed) { - // 按下时做些什么 + // 鎸変笅鏃跺仛浜涗粈涔 } else { - // 释放时做些什么 + // 閲婃斁鏃跺仛浜涗粈涔 } - return false; // 跳过此键的所有进一步处理 + return false; // 璺宠繃姝ら敭鐨勬墍鏈夎繘涓姝ュ鐞 case KC_ENTER: - // 当按下回车时播放音符 + // 褰撴寜涓嬪洖杞︽椂鎾斁闊崇 if (record->event.pressed) { PLAY_NOTE_ARRAY(tone_qwerty); } - return true; // 让QMK触发回车按下/释放事件 + return true; // 璁㏎MK瑙﹀彂鍥炶溅鎸変笅/閲婃斁浜嬩欢 default: - return true; // 正常处理其他键码 + return true; // 姝e父澶勭悊鍏朵粬閿爜 } } ``` -### `process_record_*` 函数文档 +### `process_record_*` 鍑芥暟鏂囨。 -* 键盘/修订: `bool process_record_kb(uint16_t keycode, keyrecord_t *record)` -* 布局: `bool process_record_user(uint16_t keycode, keyrecord_t *record)` +* 閿洏/淇: `bool process_record_kb(uint16_t keycode, keyrecord_t *record)` +* 甯冨眬: `bool process_record_user(uint16_t keycode, keyrecord_t *record)` -`keycode(键码)`参数是在布局上定义的,比如`MO(1)`, `KC_L`, 等等。 你要用 `switch...case` 块来处理这些事件。 +`keycode(閿爜)`鍙傛暟鏄湪甯冨眬涓婂畾涔夌殑锛屾瘮濡俙MO(1)`, `KC_L`, 绛夌瓑銆 浣犺鐢 `switch...case` 鍧楁潵澶勭悊杩欎簺浜嬩欢銆 -`record`参数含有实际按键的信息: +`record`鍙傛暟鍚湁瀹為檯鎸夐敭鐨勪俊鎭細 ```c keyrecord_t record { @@ -88,9 +88,9 @@ keyrecord_t record { } ``` -# LED控制 +# LED鎺у埗 -qmk提供了读取HID规范包含的5个LED的方法。: +qmk鎻愪緵浜嗚鍙朒ID瑙勮寖鍖呭惈鐨5涓狶ED鐨勬柟娉曘: * `USB_LED_NUM_LOCK` * `USB_LED_CAPS_LOCK` @@ -98,20 +98,20 @@ qmk * `USB_LED_COMPOSE` * `USB_LED_KANA` -这五个常量对应于主机LED状态的位置位。 -有两种方法可以获得主机LED状态: +杩欎簲涓父閲忓搴斾簬涓绘満LED鐘舵佺殑浣嶇疆浣嶃 +鏈変袱绉嶆柟娉曞彲浠ヨ幏寰椾富鏈篖ED鐘舵侊細 -* 通过执行 `led_set_user()` -* 通过调用 `host_keyboard_leds()` +* 閫氳繃鎵ц `led_set_user()` +* 閫氳繃璋冪敤 `host_keyboard_leds()` ## `led_set_user()` -当5个LED中任何一个的状态需要改变时,此函数将被调用。此函数通过参数输入LED参数。 -使用`IS_LED_ON(usb_led, led_name)`和`IS_LED_OFF(usb_led, led_name)`这两个宏来检查LED状态。 +褰5涓狶ED涓换浣曚竴涓殑鐘舵侀渶瑕佹敼鍙樻椂锛屾鍑芥暟灏嗚璋冪敤銆傛鍑芥暟閫氳繃鍙傛暟杈撳叆LED鍙傛暟銆 +浣跨敤`IS_LED_ON(usb_led, led_name)`鍜宍IS_LED_OFF(usb_led, led_name)`杩欎袱涓畯鏉ユ鏌ED鐘舵併 -!> `host_keyboard_leds()`可能会在`led_set_user()`被调用前返回新值。 +!> `host_keyboard_leds()`鍙兘浼氬湪`led_set_user()`琚皟鐢ㄥ墠杩斿洖鏂板笺 -### `led_set_user()`函数示例实现 +### `led_set_user()`鍑芥暟绀轰緥瀹炵幇 ```c void led_set_user(uint8_t usb_led) { @@ -143,59 +143,59 @@ void led_set_user(uint8_t usb_led) { } ``` -### `led_set_*`函数文档 +### `led_set_*`鍑芥暟鏂囨。 -* 键盘/修订: `void led_set_kb(uint8_t usb_led)` -* 布局: `void led_set_user(uint8_t usb_led)` +* 閿洏/淇: `void led_set_kb(uint8_t usb_led)` +* 甯冨眬: `void led_set_user(uint8_t usb_led)` ## `host_keyboard_leds()` -调用这个函数会返回最后收到的LED状态。这个函数在`led_set_*`之外读取LED状态时很有用,比如在[`matrix_scan_user()`](#矩阵扫描代码). -为了便捷,你可以用`IS_HOST_LED_ON(led_name)`和`IS_HOST_LED_OFF(led_name)` 宏,而不直接调用和检查`host_keyboard_leds()`。 +璋冪敤杩欎釜鍑芥暟浼氳繑鍥炴渶鍚庢敹鍒扮殑LED鐘舵併傝繖涓嚱鏁板湪`led_set_*`涔嬪璇诲彇LED鐘舵佹椂寰堟湁鐢紝姣斿鍦╗`matrix_scan_user()`](#鐭╅樀鎵弿浠g爜). +涓轰簡渚挎嵎锛屼綘鍙互鐢╜IS_HOST_LED_ON(led_name)`鍜宍IS_HOST_LED_OFF(led_name)` 瀹忥紝鑰屼笉鐩存帴璋冪敤鍜屾鏌host_keyboard_leds()`銆 -## 设置物理LED状态 +## 璁剧疆鐗╃悊LED鐘舵 -一些键盘实现了为设置物理LED的状态提供了方便的方法。 +涓浜涢敭鐩樺疄鐜颁簡涓鸿缃墿鐞哃ED鐨勭姸鎬佹彁渚涗簡鏂逛究鐨勬柟娉曘 ### Ergodox Boards -Ergodox实现了提供`ergodox_right_led_1`/`2`/`3_on`/`off()`来让每个LED开或关, 也可以用 `ergodox_right_led_on`/`off(uint8_t led)` 按索引打开或关闭他们。 +Ergodox瀹炵幇浜嗘彁渚沗ergodox_right_led_1`/`2`/`3_on`/`off()`鏉ヨ姣忎釜LED寮鎴栧叧, 涔熷彲浠ョ敤 `ergodox_right_led_on`/`off(uint8_t led)` 鎸夌储寮曟墦寮鎴栧叧闂粬浠 -此外,还可以使用`ergodox_led_all_set(uint8_t n)`指定所有LED的亮度级别;针对每个LED用`ergodox_right_led_1`/`2`/`3_set(uint8_t n)`;使用索引的话用`ergodox_right_led_set(uint8_t led, uint8_t n)`。 +姝ゅ锛岃繕鍙互浣跨敤`ergodox_led_all_set(uint8_t n)`鎸囧畾鎵鏈塋ED鐨勪寒搴︾骇鍒紱閽堝姣忎釜LED鐢╜ergodox_right_led_1`/`2`/`3_set(uint8_t n)`锛涗娇鐢ㄧ储寮曠殑璇濈敤`ergodox_right_led_set(uint8_t led, uint8_t n)`銆 -Ergodox boards 同时定义了最低亮度级别`LED_BRIGHTNESS_LO`和最高亮度级别`LED_BRIGHTNESS_HI`(默认最高). +Ergodox boards 鍚屾椂瀹氫箟浜嗘渶浣庝寒搴︾骇鍒玚LED_BRIGHTNESS_LO`鍜屾渶楂樹寒搴︾骇鍒玚LED_BRIGHTNESS_HI`(榛樿鏈楂). -# 键盘初始化代码 +# 閿洏鍒濆鍖栦唬鐮 -键盘初始化过程有几个步骤。你是用那个函数取决于你想要做什么。 +閿洏鍒濆鍖栬繃绋嬫湁鍑犱釜姝ラ銆備綘鏄敤閭d釜鍑芥暟鍙栧喅浜庝綘鎯宠鍋氫粈涔堛 -有三个主要初始化函数,按调用顺序列出。 +鏈変笁涓富瑕佸垵濮嬪寲鍑芥暟锛屾寜璋冪敤椤哄簭鍒楀嚭銆 -* `keyboard_pre_init_*` - 会在大多数其他东西运行前运行。适用于哪些需要提前运行的硬件初始化。 -* `matrix_init_*` - 在固件启动过程中间被调用。此时硬件已初始化,功能尚未初始化。 -* `keyboard_post_init_*` - 在固件启动过程最后被调用。大多数情况下,你的“客制化”代码都可以放在这里。 +* `keyboard_pre_init_*` - 浼氬湪澶у鏁板叾浠栦笢瑗胯繍琛屽墠杩愯銆傞傜敤浜庡摢浜涢渶瑕佹彁鍓嶈繍琛岀殑纭欢鍒濆鍖栥 +* `matrix_init_*` - 鍦ㄥ浐浠跺惎鍔ㄨ繃绋嬩腑闂磋璋冪敤銆傛鏃剁‖浠跺凡鍒濆鍖栵紝鍔熻兘灏氭湭鍒濆鍖栥 +* `keyboard_post_init_*` - 鍦ㄥ浐浠跺惎鍔ㄨ繃绋嬫渶鍚庤璋冪敤銆傚ぇ澶氭暟鎯呭喌涓嬶紝浣犵殑鈥滃鍒跺寲鈥濅唬鐮侀兘鍙互鏀惧湪杩欓噷銆 -!> 对于大多数人来说`keyboard_post_init_user`是你想要调用的函数。例如, 此时你可以设置RGB灯发光。 +!> 瀵逛簬澶у鏁颁汉鏉ヨ`keyboard_post_init_user`鏄綘鎯宠璋冪敤鐨勫嚱鏁般備緥濡, 姝ゆ椂浣犲彲浠ヨ缃甊GB鐏彂鍏夈 -## 键盘预初始化代码 +## 閿洏棰勫垵濮嬪寲浠g爜 -这代码极早运行,甚至都在USB初始化前运行。 +杩欎唬鐮佹瀬鏃╄繍琛岋紝鐢氳嚦閮藉湪USB鍒濆鍖栧墠杩愯銆 -在这之后不久矩阵就被初始化了。 +鍦ㄨ繖涔嬪悗涓嶄箙鐭╅樀灏辫鍒濆鍖栦簡銆 -对于大多数用户来说,这用不到,因为它主要是用于面向硬件的初始化。 +瀵逛簬澶у鏁扮敤鎴锋潵璇,杩欑敤涓嶅埌锛屽洜涓哄畠涓昏鏄敤浜庨潰鍚戠‖浠剁殑鍒濆鍖栥 -但如果你有硬件初始化的话放在这里再好不过了(比如初始化LED引脚一类的). +浣嗗鏋滀綘鏈夌‖浠跺垵濮嬪寲鐨勮瘽鏀惧湪杩欓噷鍐嶅ソ涓嶈繃浜(姣斿鍒濆鍖朙ED寮曡剼涓绫荤殑). -### `keyboard_pre_init_user()`函数示例实现 +### `keyboard_pre_init_user()`鍑芥暟绀轰緥瀹炵幇 -本例中在键盘级别,设定 B0, B1, B2, B3, 和 B4 是LED引脚。 +鏈緥涓湪閿洏绾у埆锛岃瀹 B0, B1, B2, B3, 鍜 B4 鏄疞ED寮曡剼銆 ```c void keyboard_pre_init_user(void) { - // 调用键盘预初始化代码 + // 璋冪敤閿洏棰勫垵濮嬪寲浠g爜 - // 设置LED引脚为输出模式 + // 璁剧疆LED寮曡剼涓鸿緭鍑烘ā寮 setPinOutput(B0); setPinOutput(B1); setPinOutput(B2); @@ -204,73 +204,73 @@ void keyboard_pre_init_user(void) { } ``` -### `keyboard_pre_init_*` 函数文档 +### `keyboard_pre_init_*` 鍑芥暟鏂囨。 -* 键盘/修订: `void keyboard_pre_init_kb(void)` -* 布局: `void keyboard_pre_init_user(void)` +* 閿洏/淇: `void keyboard_pre_init_kb(void)` +* 甯冨眬: `void keyboard_pre_init_user(void)` -## 矩阵初始化代码 +## 鐭╅樀鍒濆鍖栦唬鐮 -这将会在矩阵初始化时被调用,在某些硬件设置好后,但在一些功能被初始化前。 +杩欏皢浼氬湪鐭╅樀鍒濆鍖栨椂琚皟鐢紝鍦ㄦ煇浜涚‖浠惰缃ソ鍚庯紝浣嗗湪涓浜涘姛鑳借鍒濆鍖栧墠銆 -这在你设置其他地方会用到的东西的时候会很有用,但与硬件无关,也不依赖于它的启动位置。 +杩欏湪浣犺缃叾浠栧湴鏂逛細鐢ㄥ埌鐨勪笢瑗跨殑鏃跺欎細寰堟湁鐢紝浣嗕笌纭欢鏃犲叧锛屼篃涓嶄緷璧栦簬瀹冪殑鍚姩浣嶇疆銆 -### `matrix_init_*`函数文档 +### `matrix_init_*`鍑芥暟鏂囨。 -* 键盘/修订: `void matrix_init_kb(void)` -* 布局: `void matrix_init_user(void)` +* 閿洏/淇: `void matrix_init_kb(void)` +* 甯冨眬: `void matrix_init_user(void)` -## 键盘后初始化代码 +## 閿洏鍚庡垵濮嬪寲浠g爜 -这是键盘初始化过程中的最后一个任务。如果您想更改某些特性,这会很有用,因为此时应该对它们进行初始化。 +杩欐槸閿洏鍒濆鍖栬繃绋嬩腑鐨勬渶鍚庝竴涓换鍔°傚鏋滄偍鎯虫洿鏀规煇浜涚壒鎬э紝杩欎細寰堟湁鐢紝鍥犱负姝ゆ椂搴旇瀵瑰畠浠繘琛屽垵濮嬪寲銆 -### `keyboard_post_init_user()`示例实现 +### `keyboard_post_init_user()`绀轰緥瀹炵幇 -本示例在所有初始化完成后运行,配置RGB灯。 +鏈ず渚嬪湪鎵鏈夊垵濮嬪寲瀹屾垚鍚庤繍琛岋紝閰嶇疆RGB鐏 ```c void keyboard_post_init_user(void) { - // 调用后初始化代码 - rgblight_enable_noeeprom(); // 使能Rgb,不保存设置 - rgblight_sethsv_noeeprom(180, 255, 255); // 将颜色设置到蓝绿色(青色)不保存 - rgblight_mode_noeeprom(RGBLIGHT_MODE_BREATHING + 3); // 设置快速呼吸模式不保存 + // 璋冪敤鍚庡垵濮嬪寲浠g爜 + rgblight_enable_noeeprom(); // 浣胯兘Rgb锛屼笉淇濆瓨璁剧疆 + rgblight_sethsv_noeeprom(180, 255, 255); // 灏嗛鑹茶缃埌钃濈豢鑹(闈掕壊)涓嶄繚瀛 + rgblight_mode_noeeprom(RGBLIGHT_MODE_BREATHING + 3); // 璁剧疆蹇熷懠鍚告ā寮忎笉淇濆瓨 } ``` -### `keyboard_post_init_*` 函数文档 +### `keyboard_post_init_*` 鍑芥暟鏂囨。 -* 键盘/修订: `void keyboard_post_init_kb(void)` -* 布局: `void keyboard_post_init_user(void)` +* 閿洏/淇: `void keyboard_post_init_kb(void)` +* 甯冨眬: `void keyboard_post_init_user(void)` -# 矩阵扫描代码 +# 鐭╅樀鎵弿浠g爜 -可能的话你要用`process_record_*()`自定义键盘,以这种方式连接到事件中,以确保代码不会对键盘产生负面的性能影响。然而,在极少数情况下,有必要进行矩阵扫描。在这些函数中要特别注意代码的性能,因为它每秒至少被调用10次。 +鍙兘鐨勮瘽浣犺鐢╜process_record_*()`鑷畾涔夐敭鐩橈紝浠ヨ繖绉嶆柟寮忚繛鎺ュ埌浜嬩欢涓紝浠ョ‘淇濅唬鐮佷笉浼氬閿洏浜х敓璐熼潰鐨勬ц兘褰卞搷銆傜劧鑰岋紝鍦ㄦ瀬灏戞暟鎯呭喌涓嬶紝鏈夊繀瑕佽繘琛岀煩闃垫壂鎻忋傚湪杩欎簺鍑芥暟涓鐗瑰埆娉ㄦ剰浠g爜鐨勬ц兘锛屽洜涓哄畠姣忕鑷冲皯琚皟鐢10娆° -### `matrix_scan_*`示例实现 +### `matrix_scan_*`绀轰緥瀹炵幇 -这个例子被故意省略了。在hook这样一个对性能及其敏感的区域之前,您应该足够了解qmk的内部结构,以便在没有示例的情况下编写。如果你需要帮助,请[建立一个issue](https://github.com/qmk/qmk_firmware/issues/new)或[在Discord上与我们交流](https://discord.gg/Uq7gcHh). +杩欎釜渚嬪瓙琚晠鎰忕渷鐣ヤ簡銆傚湪hook杩欐牱涓涓鎬ц兘鍙婂叾鏁忔劅鐨勫尯鍩熶箣鍓嶏紝鎮ㄥ簲璇ヨ冻澶熶簡瑙mk鐨勫唴閮ㄧ粨鏋勶紝浠ヤ究鍦ㄦ病鏈夌ず渚嬬殑鎯呭喌涓嬬紪鍐欍傚鏋滀綘闇瑕佸府鍔╋紝璇穂寤虹珛涓涓猧ssue](https://github.com/qmk/qmk_firmware/issues/new)鎴朳鍦―iscord涓婁笌鎴戜滑浜ゆ祦](https://discord.gg/Uq7gcHh). -### `matrix_scan_*` 函数文档 +### `matrix_scan_*` 鍑芥暟鏂囨。 -* 键盘/修订: `void matrix_scan_kb(void)` -* 布局: `void matrix_scan_user(void)` +* 閿洏/淇: `void matrix_scan_kb(void)` +* 甯冨眬: `void matrix_scan_user(void)` -该函数在每次矩阵扫描时被调用,这基本与MCU处理能力上限相同。在这里写代码要谨慎,因为它会运行很多次。 +璇ュ嚱鏁板湪姣忔鐭╅樀鎵弿鏃惰璋冪敤锛岃繖鍩烘湰涓嶮CU澶勭悊鑳藉姏涓婇檺鐩稿悓銆傚湪杩欓噷鍐欎唬鐮佽璋ㄦ厧锛屽洜涓哄畠浼氳繍琛屽緢澶氭銆 -你会在自定义矩阵扫描代码时用到这个函数。这也可以用作自定义状态输出(比如LED灯或者屏幕)或者其他即便用户不输入你也想定期运行的功能。 +浣犱細鍦ㄨ嚜瀹氫箟鐭╅樀鎵弿浠g爜鏃剁敤鍒拌繖涓嚱鏁般傝繖涔熷彲浠ョ敤浣滆嚜瀹氫箟鐘舵佽緭鍑(姣斿LED鐏垨鑰呭睆骞)鎴栬呭叾浠栧嵆渚跨敤鎴蜂笉杈撳叆浣犱篃鎯冲畾鏈熻繍琛岀殑鍔熻兘銆 -# 键盘 空闲/唤醒 代码 +# 閿洏 绌洪棽/鍞ら啋 浠g爜 -如果键盘支持就可以通过停止一大票功能来达到"空闲"。RGB灯和背光就是很好的例子。这可以节约能耗,也可能让你键盘风味更佳。 +濡傛灉閿洏鏀寔灏卞彲浠ラ氳繃鍋滄涓澶хエ鍔熻兘鏉ヨ揪鍒"绌洪棽"銆俁GB鐏拰鑳屽厜灏辨槸寰堝ソ鐨勪緥瀛愩傝繖鍙互鑺傜害鑳借楋紝涔熷彲鑳借浣犻敭鐩橀鍛虫洿浣炽 -用两个函数控制: `suspend_power_down_*`和`suspend_wakeup_init_*`, 分别在系统板空闲和唤醒时调用。 +鐢ㄤ袱涓嚱鏁版帶鍒: `suspend_power_down_*`鍜宍suspend_wakeup_init_*`, 鍒嗗埆鍦ㄧ郴缁熸澘绌洪棽鍜屽敜閱掓椂璋冪敤銆 -### suspend_power_down_user()和suspend_wakeup_init_user()示例实现 +### suspend_power_down_user()鍜宻uspend_wakeup_init_user()绀轰緥瀹炵幇 ```c @@ -283,18 +283,18 @@ void suspend_wakeup_init_user(void) { } ``` -### 键盘 挂起/唤醒 函数文档 +### 閿洏 鎸傝捣/鍞ら啋 鍑芥暟鏂囨。 -* 键盘/修订: `void suspend_power_down_kb(void)` 和`void suspend_wakeup_init_user(void)` -* 布局: `void suspend_power_down_kb(void)` 和 `void suspend_wakeup_init_user(void)` +* 閿洏/淇: `void suspend_power_down_kb(void)` 鍜宍void suspend_wakeup_init_user(void)` +* 甯冨眬: `void suspend_power_down_kb(void)` 鍜 `void suspend_wakeup_init_user(void)` -# 层改变代码 +# 灞傛敼鍙樹唬鐮 -每当层改变这个就运行代码。这对于层指示或自定义层处理很有用。 +姣忓綋灞傛敼鍙樿繖涓氨杩愯浠g爜銆傝繖瀵逛簬灞傛寚绀烘垨鑷畾涔夊眰澶勭悊寰堟湁鐢ㄣ -### `layer_state_set_*` 示例实现 +### `layer_state_set_*` 绀轰緥瀹炵幇 -本例使用了Planck键盘示范了如何设置 [RGB背光灯](feature_rgblight.md)使之与层对应 +鏈緥浣跨敤浜哖lanck閿洏绀鸿寖浜嗗浣曡缃 [RGB鑳屽厜鐏痌(feature_rgblight.md)浣夸箣涓庡眰瀵瑰簲 ```c uint32_t layer_state_set_user(uint32_t state) { @@ -318,31 +318,31 @@ uint32_t layer_state_set_user(uint32_t state) { return state; } ``` -### `layer_state_set_*` 函数文档 +### `layer_state_set_*` 鍑芥暟鏂囨。 -* 键盘/修订: `uint32_t layer_state_set_kb(uint32_t state)` -* 布局: `uint32_t layer_state_set_user(uint32_t state)` +* 閿洏/淇: `uint32_t layer_state_set_kb(uint32_t state)` +* 甯冨眬: `uint32_t layer_state_set_user(uint32_t state)` -该`状态`是活动层的bitmask, 详见[布局概述](keymap.md#布局的层状态) +璇鐘舵乣鏄椿鍔ㄥ眰鐨刡itmask, 璇﹁[甯冨眬姒傝堪](keymap.md#甯冨眬鐨勫眰鐘舵) -# 掉电保存配置 (EEPROM) +# 鎺夌數淇濆瓨閰嶇疆 (EEPROM) -这会让你的配置长期的保存在键盘中。这些配置保存在你主控的EEPROM里,掉电不会消失。 设置可以用`eeconfig_read_kb`和`eeconfig_read_user`读取,可以用`eeconfig_update_kb`和`eeconfig_update_user`写入。这对于您希望能够切换的功能很有用(比如切换RGB层指示。此外,你可以用`eeconfig_init_kb`和`eeconfig_init_user`来设置EEPROM默认值。 +杩欎細璁╀綘鐨勯厤缃暱鏈熺殑淇濆瓨鍦ㄩ敭鐩樹腑銆傝繖浜涢厤缃繚瀛樺湪浣犱富鎺х殑EEPROM閲岋紝鎺夌數涓嶄細娑堝け銆 璁剧疆鍙互鐢╜eeconfig_read_kb`鍜宍eeconfig_read_user`璇诲彇锛屽彲浠ョ敤`eeconfig_update_kb`鍜宍eeconfig_update_user`鍐欏叆銆傝繖瀵逛簬鎮ㄥ笇鏈涜兘澶熷垏鎹㈢殑鍔熻兘寰堟湁鐢(姣斿鍒囨崲RGB灞傛寚绀恒傛澶栵紝浣犲彲浠ョ敤`eeconfig_init_kb`鍜宍eeconfig_init_user`鏉ヨ缃瓻EPROM榛樿鍊笺 -最复杂的部分可能是,有很多方法可以通过EEPROM存储和访问数据,并且并没有用哪种方法是“政治正确”的。你每个功能只有一个双字(四字节)空间。 +鏈澶嶆潅鐨勯儴鍒嗗彲鑳芥槸锛屾湁寰堝鏂规硶鍙互閫氳繃EEPROM瀛樺偍鍜岃闂暟鎹紝骞朵笖骞舵病鏈夌敤鍝鏂规硶鏄滄斂娌绘纭濈殑銆備綘姣忎釜鍔熻兘鍙湁涓涓弻瀛(鍥涘瓧鑺)绌洪棿銆 -记住EEPROM是有写入寿命的。尽管写入寿命很高,但是并不是只有设置写道EEPROM中。如果你写入频繁,你的MCU寿命将会变短。 +璁颁綇EEPROM鏄湁鍐欏叆瀵垮懡鐨勩傚敖绠″啓鍏ュ鍛藉緢楂橈紝浣嗘槸骞朵笉鏄彧鏈夎缃啓閬揈EPROM涓傚鏋滀綘鍐欏叆棰戠箒锛屼綘鐨凪CU瀵垮懡灏嗕細鍙樼煭銆 -* 如果您不理解这个例子,那么您可能希望避免使用这个特性,因为它相当复杂。 +* 濡傛灉鎮ㄤ笉鐞嗚В杩欎釜渚嬪瓙锛岄偅涔堟偍鍙兘甯屾湜閬垮厤浣跨敤杩欎釜鐗规э紝鍥犱负瀹冪浉褰撳鏉傘 -### 示例实现 +### 绀轰緥瀹炵幇 -本例讲解了如何添加设置,并且读写。本里使用了用户布局。这是一个复杂的函数,有很多事情要做。实际上,它使用了很多上述函数来工作! +鏈緥璁茶В浜嗗浣曟坊鍔犺缃紝骞朵笖璇诲啓銆傛湰閲屼娇鐢ㄤ簡鐢ㄦ埛甯冨眬銆傝繖鏄竴涓鏉傜殑鍑芥暟锛屾湁寰堝浜嬫儏瑕佸仛銆傚疄闄呬笂锛屽畠浣跨敤浜嗗緢澶氫笂杩板嚱鏁版潵宸ヤ綔锛 -在你的keymap.c文件中,将以下代码添加至顶部: +鍦ㄤ綘鐨刱eymap.c鏂囦欢涓紝灏嗕互涓嬩唬鐮佹坊鍔犺嚦椤堕儴: ```c typedef union { uint32_t raw; @@ -354,19 +354,19 @@ typedef union { user_config_t user_config; ``` -以上代码建立了一个结构体,该结构体可以存储设置并可用于写入EEPROM。如此这般将无需定义变量,因为在结构体中已然定义。要记住`bool` (布尔)值使用1位, `uint8_t`使用8位, `uint16_t`使用16位。你可以混合搭配使用,但是顺序记错可能会招致麻烦,因为那会改变写入写出的值。 +浠ヤ笂浠g爜寤虹珛浜嗕竴涓粨鏋勪綋锛岃缁撴瀯浣撳彲浠ュ瓨鍌ㄨ缃苟鍙敤浜庡啓鍏EPROM銆傚姝よ繖鑸皢鏃犻渶瀹氫箟鍙橀噺锛屽洜涓哄湪缁撴瀯浣撲腑宸茬劧瀹氫箟銆傝璁颁綇`bool` (甯冨皵)鍊间娇鐢1浣, `uint8_t`浣跨敤8浣, `uint16_t`浣跨敤16浣嶃備綘鍙互娣峰悎鎼厤浣跨敤锛屼絾鏄『搴忚閿欏彲鑳戒細鎷涜嚧楹荤儲锛屽洜涓洪偅浼氭敼鍙樺啓鍏ュ啓鍑虹殑鍊笺 - `layer_state_set_*`函数中使用了`rgb_layer_change`,使用了`keyboard_post_init_user`和`process_record_user`来配置一切。 + `layer_state_set_*`鍑芥暟涓娇鐢ㄤ簡`rgb_layer_change`锛屼娇鐢ㄤ簡`keyboard_post_init_user`鍜宍process_record_user`鏉ラ厤缃竴鍒囥 -首先要使用`keyboard_post_init_user,你要加入`eeconfig_read_user()`来填充你刚刚创建的结构体。然后您可以立即使用这个结构来控制您的布局中的功能。就像这样: +棣栧厛瑕佷娇鐢╜keyboard_post_init_user锛屼綘瑕佸姞鍏eeconfig_read_user()`鏉ュ~鍏呬綘鍒氬垰鍒涘缓鐨勭粨鏋勪綋銆傜劧鍚庢偍鍙互绔嬪嵆浣跨敤杩欎釜缁撴瀯鏉ユ帶鍒舵偍鐨勫竷灞涓殑鍔熻兘銆傚氨鍍忚繖鏍凤細 ```c void keyboard_post_init_user(void) { - // 调用布局级别的矩阵初始化 + // 璋冪敤甯冨眬绾у埆鐨勭煩闃靛垵濮嬪寲 - // 从EEPROM读用户配置 + // 浠嶦EPROM璇荤敤鎴烽厤缃 user_config.raw = eeconfig_read_user(); - // 如使能,设置默认层 + // 濡備娇鑳斤紝璁剧疆榛樿灞 if (user_config.rgb_layer_change) { rgblight_enable_noeeprom(); rgblight_sethsv_noeeprom_cyan(); @@ -374,7 +374,7 @@ void keyboard_post_init_user(void) { } } ``` -以上函数会在读EEPROM配置后立即使用该设置来设置默认层RGB颜色。"raw"的值是从你上面基于"union"创建的结构体中转换来的。 +浠ヤ笂鍑芥暟浼氬湪璇籈EPROM閰嶇疆鍚庣珛鍗充娇鐢ㄨ璁剧疆鏉ヨ缃粯璁ゅ眰RGB棰滆壊銆"raw"鐨勫兼槸浠庝綘涓婇潰鍩轰簬"union"鍒涘缓鐨勭粨鏋勪綋涓浆鎹㈡潵鐨勩 ```c uint32_t layer_state_set_user(uint32_t state) { @@ -391,86 +391,86 @@ uint32_t layer_state_set_user(uint32_t state) { case _ADJUST: if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom_white(); rgblight_mode_noeeprom(1); } break; - default: // 针对其他层或默认层 + default: // 閽堝鍏朵粬灞傛垨榛樿灞 if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom_cyan(); rgblight_mode_noeeprom(1); } break; } return state; } ``` -这样仅在值使能时会改变RGB背光灯。现在配置这个值, 为`process_record_user`创建一个新键码叫做`RGB_LYR`。我们要确保,如果使用正常的RGB代码,使用上面的示例将其关闭,请将其设置为: +杩欐牱浠呭湪鍊间娇鑳芥椂浼氭敼鍙楻GB鑳屽厜鐏傜幇鍦ㄩ厤缃繖涓, 涓篳process_record_user`鍒涘缓涓涓柊閿爜鍙仛`RGB_LYR`銆傛垜浠纭繚锛屽鏋滀娇鐢ㄦ甯哥殑RGB浠g爜锛屼娇鐢ㄤ笂闈㈢殑绀轰緥灏嗗叾鍏抽棴锛岃灏嗗叾璁剧疆涓猴細 ```c bool process_record_user(uint16_t keycode, keyrecord_t *record) { switch (keycode) { case FOO: if (record->event.pressed) { - // 按下时做点什么 + // 鎸変笅鏃跺仛鐐逛粈涔 } else { - // 释放时做点什么 + // 閲婃斁鏃跺仛鐐逛粈涔 } - return false; // 跳过此键的进一步处理 + return false; // 璺宠繃姝ら敭鐨勮繘涓姝ュ鐞 case KC_ENTER: - // 在按下回车时播放音符 + // 鍦ㄦ寜涓嬪洖杞︽椂鎾斁闊崇 if (record->event.pressed) { PLAY_NOTE_ARRAY(tone_qwerty); } - return true; // 让QMK产生回车按下/释放事件 - case RGB_LYR: // 本句让underglow作为层指示,或正常使用。 + return true; // 璁㏎MK浜х敓鍥炶溅鎸変笅/閲婃斁浜嬩欢 + case RGB_LYR: // 鏈彞璁﹗nderglow浣滀负灞傛寚绀猴紝鎴栨甯镐娇鐢ㄣ if (record->event.pressed) { - user_config.rgb_layer_change ^= 1; // 切换状态 - eeconfig_update_user(user_config.raw); // 向EEPROM写入新状态 - if (user_config.rgb_layer_change) { // 如果层状态被使能 - layer_state_set(layer_state); // 那么立刻更新层颜色 + user_config.rgb_layer_change ^= 1; // 鍒囨崲鐘舵 + eeconfig_update_user(user_config.raw); // 鍚慐EPROM鍐欏叆鏂扮姸鎬 + if (user_config.rgb_layer_change) { // 濡傛灉灞傜姸鎬佽浣胯兘 + layer_state_set(layer_state); // 閭d箞绔嬪埢鏇存柊灞傞鑹 } } return false; break; - case RGB_MODE_FORWARD ... RGB_MODE_GRADIENT: // 对于所有的RGB代码 (see quantum_keycodes.h, L400 可以参考) - if (record->event.pressed) { //本句失能层指示,假设你改变了这个…你要把它禁用 - if (user_config.rgb_layer_change) { // 仅当使能时 - user_config.rgb_layer_change = false; // 失能,然后 - eeconfig_update_user(user_config.raw); // 向EEPROM写入设置 + case RGB_MODE_FORWARD ... RGB_MODE_GRADIENT: // 瀵逛簬鎵鏈夌殑RGB浠g爜 (see quantum_keycodes.h, L400 鍙互鍙傝) + if (record->event.pressed) { //鏈彞澶辫兘灞傛寚绀猴紝鍋囪浣犳敼鍙樹簡杩欎釜鈥︿綘瑕佹妸瀹冪鐢 + if (user_config.rgb_layer_change) { // 浠呭綋浣胯兘鏃 + user_config.rgb_layer_change = false; // 澶辫兘锛岀劧鍚 + eeconfig_update_user(user_config.raw); // 鍚慐EPROM鍐欏叆璁剧疆 } } return true; break; default: - return true; // 按其他键正常 + return true; // 鎸夊叾浠栭敭姝e父 } } ``` -最后你要加入`eeconfig_init_user`函数,所以当EEPROM重置时,可以指定默认值, 甚至自定义操作。想强制重置EEPROM,请用`EEP_RST`键码或[Bootmagic](feature_bootmagic.md)函数。比如,如果要在默认情况下设置RGB层指示,并保存默认值 +鏈鍚庝綘瑕佸姞鍏eeconfig_init_user`鍑芥暟锛屾墍浠ュ綋EEPROM閲嶇疆鏃讹紝鍙互鎸囧畾榛樿鍊, 鐢氳嚦鑷畾涔夋搷浣溿傛兂寮哄埗閲嶇疆EEPROM锛岃鐢╜EEP_RST`閿爜鎴朳Bootmagic](feature_bootmagic.md)鍑芥暟銆傛瘮濡傦紝濡傛灉瑕佸湪榛樿鎯呭喌涓嬭缃甊GB灞傛寚绀猴紝骞朵繚瀛橀粯璁ゅ ```c -void eeconfig_init_user(void) { // EEPROM正被重置 +void eeconfig_init_user(void) { // EEPROM姝h閲嶇疆 user_config.raw = 0; - user_config.rgb_layer_change = true; // 我们想要默认使能 - eeconfig_update_user(user_config.raw); // 向EEPROM写入默认值 + user_config.rgb_layer_change = true; // 鎴戜滑鎯宠榛樿浣胯兘 + eeconfig_update_user(user_config.raw); // 鍚慐EPROM鍐欏叆榛樿鍊 - // use the non noeeprom versions, 还要向EEPROM写入这些值 - rgblight_enable(); // 默认使能RGB - rgblight_sethsv_cyan(); // 默认设置青色 - rgblight_mode(1); // 默认设置长亮 + // use the non noeeprom versions, 杩樿鍚慐EPROM鍐欏叆杩欎簺鍊 + rgblight_enable(); // 榛樿浣胯兘RGB + rgblight_sethsv_cyan(); // 榛樿璁剧疆闈掕壊 + rgblight_mode(1); // 榛樿璁剧疆闀夸寒 } ``` -然后就完事了。RGB层指示会在你想让它工作时工作。这个设置会一直保存,即便你拔下键盘。如果你使用其他RGB代码,层指示将失能,现在它可以做你所想了。 +鐒跺悗灏卞畬浜嬩簡銆俁GB灞傛寚绀轰細鍦ㄤ綘鎯宠瀹冨伐浣滄椂宸ヤ綔銆傝繖涓缃細涓鐩翠繚瀛橈紝鍗充究浣犳嫈涓嬮敭鐩樸傚鏋滀綘浣跨敤鍏朵粬RGB浠g爜锛屽眰鎸囩ず灏嗗け鑳斤紝鐜板湪瀹冨彲浠ュ仛浣犳墍鎯充簡銆 -### 'EECONFIG' 函数文档 +### 'EECONFIG' 鍑芥暟鏂囨。 -* 键盘/修订: `void eeconfig_init_kb(void)`, `uint32_t eeconfig_read_kb(void)`和`void eeconfig_update_kb(uint32_t val)` -* 布局: `void eeconfig_init_user(void)`, `uint32_t eeconfig_read_user(void)`和`void eeconfig_update_user(uint32_t val)` +* 閿洏/淇: `void eeconfig_init_kb(void)`, `uint32_t eeconfig_read_kb(void)`鍜宍void eeconfig_update_kb(uint32_t val)` +* 甯冨眬: `void eeconfig_init_user(void)`, `uint32_t eeconfig_read_user(void)`鍜宍void eeconfig_update_user(uint32_t val)` -`val` 是你想写入EEPROM的值,`eeconfig_read_*`函数会从EEPROM返回一个32位(双字)的值。 +`val` 鏄綘鎯冲啓鍏EPROM鐨勫硷紝`eeconfig_read_*`鍑芥暟浼氫粠EEPROM杩斿洖涓涓32浣(鍙屽瓧)鐨勫笺 -# 自定义击键-长按临界值(TAPPING_TERM) -默认情况下,击键-长按临界值是全球统一的,并且不能通过键进行配置。对于大多数用户来说这很好。但是在有些情况下,对于`LT`键来说按键延时对双功能键的提升更大,可能是因为有些键比其他的键更容易按住。为了不给每个都自定义键码,本功能可以为每个键定义`TAPPING_TERM`。 +# 鑷畾涔夊嚮閿-闀挎寜涓寸晫鍊(TAPPING_TERM) +榛樿鎯呭喌涓,鍑婚敭-闀挎寜涓寸晫鍊兼槸鍏ㄧ悆缁熶竴鐨勶紝骞朵笖涓嶈兘閫氳繃閿繘琛岄厤缃傚浜庡ぇ澶氭暟鐢ㄦ埛鏉ヨ杩欏緢濂姐備絾鏄湪鏈変簺鎯呭喌涓嬶紝瀵逛簬`LT`閿潵璇存寜閿欢鏃跺鍙屽姛鑳介敭鐨勬彁鍗囨洿澶э紝鍙兘鏄洜涓烘湁浜涢敭姣斿叾浠栫殑閿洿瀹规槗鎸変綇銆備负浜嗕笉缁欐瘡涓兘鑷畾涔夐敭鐮侊紝鏈姛鑳藉彲浠ヤ负姣忎釜閿畾涔塦TAPPING_TERM`銆 -想使能这个功能的话, 要先在`config.h`加上`#define TAPPING_TERM_PER_KEY`。 +鎯充娇鑳借繖涓姛鑳界殑璇, 瑕佸厛鍦╜config.h`鍔犱笂`#define TAPPING_TERM_PER_KEY`銆 -## `get_tapping_term`示例实现 +## `get_tapping_term`绀轰緥瀹炵幇 -想要修改基于键码的`TAPPING TERM`,你要向`keymap.c`文件添加如下代码: +鎯宠淇敼鍩轰簬閿爜鐨刞TAPPING TERM`,浣犺鍚慲keymap.c`鏂囦欢娣诲姞濡備笅浠g爜: ```c uint16_t get_tapping_term(uint16_t keycode) { @@ -485,6 +485,6 @@ uint16_t get_tapping_term(uint16_t keycode) { } ``` -### `get_tapping_term` 函数文档 +### `get_tapping_term` 鍑芥暟鏂囨。 -不像这篇的其他功能,这个不需要quantum或者键盘级别的函数,只要用户级函数即可。 +涓嶅儚杩欑瘒鐨勫叾浠栧姛鑳,杩欎釜涓嶉渶瑕乹uantum鎴栬呴敭鐩樼骇鍒殑鍑芥暟锛屽彧瑕佺敤鎴风骇鍑芥暟鍗冲彲銆