qmk_firmware/docs/zh-cn/keymap.md

210 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 键映射总览
<!---
original document: 0.15.12:docs/keymap.md
git diff 0.15.12 HEAD -- docs/keymap.md | cat
-->
QMK键映射定义在C源文件中其数据结构上是一个容纳了数组的数组。外层数组容纳了各个层内层各数组则为层内的键列表。基本所有键盘都通过定义 `LAYOUT()` 宏来创建该两级数组。
## 键映射与配列 :id=keymap-and-layers
在QMK中, **`const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS]`** 容纳了多个 **层** 每个**层**下包含了由**16位**的**动作码**所组成的键映射信息。 最多可以定义**32个层**。
对于常规键的定义,其**动作码**的高8位皆为0低8位保存了USB HID中使用的各个键对应的**键码**。
不同的层可以同时生效层的编号从0至31编号越高的层优先级越高。
译注由于是ascii图掺杂中文会导致排版错乱各翻译标注在图下方。下同
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 `--------------------------
翻译:
|原文 |译文 |
|--------------------------|-------------|
|Keymap: 32 Layers | 键映射32个层|
|stack of layers | 层堆栈 |
|precedence | 优先级 |
|high/low | 高/低 |
|layer: action code matrix | 层:动作码矩阵|
|row/column | 行/列 |
有时键映射中存储的动作码在一些文档中也被称作键码主要是由TMK沿袭而来的习惯。
### 键映射的层状态 :id=keymap-layer-status
键映射的层状态由两个32位参数决定
* **`default_layer_state`** 指向一个总是可用的键映射层0-31即默认层
* **`layer_state`** 每一位标记对应层的启用/停用状态。
通常键映射中的'0'层为 `default_layer默认层`,其它层在启动时会被固件置为停用状态,不过这些可以通过 `config.h` 进行配置。当你换了一个按键布局时可用于更改 `default_layer`比如从Qwerty布局切换到了Colemak布局。
Initial state of Keymap Change base layout
----------------------- ------------------
31 31
30 30
29 29
: :
: : ____________
2 ____________ 2 / /
1 / / ,->1 /___________/
,->0 /___________/ | 0
| |
`--- default_layer = 0 `--- default_layer = 1
layer_state = 0x00000001 layer_state = 0x00000002
翻译:
|原文 |译文 |
|-----------------------|-------------|
|Initial state of Keymap| 键映射原始状态|
|Change base layout | 更改了基础层 |
另外,可以通过修改 `layer_state` 做到其他层对基础层的覆盖以实现诸如导航键、功能键F1-F12、多媒体键等特殊动作。
Overlay feature layer
--------------------- bit|status
____________ ---+------
31 / / 31 | 0
30 /___________// -----> 30 | 1
29 /___________/ -----> 29 | 1
: : | :
: ____________ : | :
2 / / 2 | 0
,->1 /___________/ -----> 1 | 1
| 0 0 | 0
| +
`--- default_layer = 1 |
layer_state = 0x60000002 <-'
### 层优先级及穿透
须记住**层堆栈中更高的层有着更高的优先级**。固件会从最高的活跃层开始向下找键码,一旦固件在活跃层上找到了一个非 `KC_TRNS`(穿透)键码,就会停止查找,再往下的层级不会被查看。
____________
/ / <--- 较高的层
/ KC_TRNS //
/___________// <--- 较低的层 (KC_A)
/___________/
这个场景中,较高层级中的非穿透键是可用的,如果定义为 `KC_TRNS`(及同等效果的),较低层级的键码 `KC_A` 将被采纳。
**注意:** 在层中定义合法的穿透键的方法有:
* `KC_TRANSPARENT`
* `KC_TRNS`(别名)
* `_______`(别名)
这些键码允许在搜索非穿透键码时可以穿透当前层下落到更低层去。
## `keymap.c` 文件解析
本例中我们将深入到[Clueboard 66%的一款旧版的默认键映射](https://github.com/qmk/qmk_firmware/blob/ca01d94005f67ec4fa9528353481faa622d949ae/keyboards/clueboard/keymaps/default/keymap.c)方案中去。将该文件在另一个浏览器窗口中打开,以便对照本文进行同步阅览。
在一个 `keymap.c` 文件中会有三个你可能会关心的部分:
* [预定义](#definitions)
* [层/键映射数据结构](#layers-and-keymaps)
* [自定义函数](#custom-functions),若有的话
### 预定义
文件头部可以看到:
#include QMK_KEYBOARD_H
// Helpful defines
// 译:便捷性的宏定义
#define GRAVE_MODS (MOD_BIT(KC_LSHIFT)|MOD_BIT(KC_RSHIFT)|MOD_BIT(KC_LGUI)|MOD_BIT(KC_RGUI)|MOD_BIT(KC_LALT)|MOD_BIT(KC_RALT))
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* You can use _______ in place for KC_TRNS (transparent) *
* Or you can use XXXXXXX for KC_NO (NOOP) *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// 译:可以用 _______ 替代 KC_TRNS(穿透),用 XXXXXXX 替代 KC_NO (空操作)
// Each layer gets a name for readability.
// The underscores don't mean anything - you can
// have a layer called STUFF or any other name.
// Layer names don't all need to be of the same
// length, and you can also skip them entirely
// and just use numbers.
// 译:每一层为了便于识别可以起一个名字,下划线没有实际意义 - STUFF之类的也行的,
// 译:层名不需要都一样长,甚至不定义这些直接用层号也是可以的
#define _BL 0
#define _FL 1
#define _CL 2
以上是一些便于编写键映射及自定义函数时可用的预定义,`GRAVE_MODS` 后续会用在自定义函数中,之后的 `_BL`, `_FL` `_CL` 便于我们在代码中引用这些层。
注:在一些更早的键映射文件中,你可能会发现一些形如 `_______` `XXXXXXX` 的定义,这些可以分别代替 `KC_TRNS` `KC_NO`,这样可以更清楚地分辨出各层中定义了哪些键的键值。现在这些定义是不需要的,因为我们默认已经提供了这些定义。
### 层和键映射
这个文件中最主要的部分是 `keymaps[]` 定义,这里须列出你的层以及层中的内容。这一部分应该以如下定义起始:
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
之后是一个LAYOUT()宏组成的列表,一个LAYOUT()下定义了一个层中的键列表,一般你需要至少一个“基础层”(如QWERTYDvorakColemak),之后是在其之上的多个“功能”层。受限于对层的处理顺序,较低的层无法覆盖在较高的层上。
QMK `keymaps[][MATRIX_ROWS][MATRIX_COLS]` 中保存着16位的动作码(有些时候也被称作键码),对于与常规键一致的键码,其高字节为0,低字节为USB HID 键盘所使用的键码值。
> QMK的前身TMK中使用 `const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS]` 来存储8位的键码一些键码被保留用于引用执行 `fn_actions[]` 数组中的特定功能。
#### 基础层
以下示例是Clueboard的基础层定义:
/* Keymap _BL: Base Layer (Default Layer)
*/
[_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_RO, KC_RSFT, KC_UP, \
KC_LCTL, KC_LGUI, KC_LALT, KC_MHEN, KC_SPC,KC_SPC, KC_HENK, KC_RALT, KC_RCTL, MO(_FL), KC_LEFT, KC_DOWN, KC_RGHT),
这里有一些值得留意的地方:
* 站在C语言源代码的角度看,这只是一个数组,但我们掺杂了大量括号使得每个键可以在视觉上与物理设备对齐。
* 常规的键盘扫描码以KC_起始,而那些“特殊”键则不是。
* 最左上的键可以触发自定义函数0`F(0)`
* "Fn"键定义为 `MO(_FL)`,当按住该键时会切换到 `_FL` 层。
#### 功能覆盖层
对于功能层,从代码角度讲与基础层没有任何区别。但在概念上讲,应该将其作为覆盖层而非替代层来定义。对大部分人来讲这个区别不重要,但当你构建越来越复杂的层结构时,其重要性会越来越凸显。
[_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_SLCK, KC_PAUS, _______, _______, _______, _______, \
_______, _______, MO(_CL),_______,_______,_______,_______,_______,_______,_______, _______, _______, _______, _______, \
_______, _______, _______,_______,_______,_______,_______,_______,_______,_______, _______, _______, _______, _______, KC_PGUP, \
_______, _______, _______, _______, _______,_______, _______, _______, _______, MO(_FL), KC_HOME, KC_PGDN, KC_END),
这里值得留意的有:
* 我们使用 `_______` 定义来替代 `KC_TRNS` 以便凸显在该层中有变化的那些键。
* 对于这一层来讲,如果点击的是一个 `_______` 键,实际生效的将是其下的活跃层中的键。
# 核心细节
在阅读完本节后,你应该掌握了构建自己的键映射的基础能力,更多的资料请参见:
* [键码](zh-cn/keycodes.md)
* [键映射FAQ](zh-cn/faq_keymap.md)
我们仍在优化这份文档,如果你有更好的优化建议,请[提交一份issue](https://github.com/qmk/qmk_firmware/issues/new)