背景
我在2016年12月的时候,在闲鱼上买到一块没线的 Kinesis Contoured 键盘,其实我在写这篇文章之前,并没有仔细查过准确型号,我一直以为我买到的是 Kinesis Advantage 之类的,毕竟造型几乎一样,但是从接口和残余键帽的颜色来判断,应该是Kinesis Contoured,这已经是1992年发布的老古董了,不过其实也可以算得上是 Advantage 系列,更像是这个系列改名了,现在都有无线的 Kinesis Advantage 360 了,499美刀,贵到离谱。
在此前的2016年6月,我正开始接触人体工学键盘,并了解到TMK这一类自定义固件(那时候QMK还不是主流?),当时折腾键盘买了乱七八糟的单片机,也尝试做了几块飞线键盘,手上还有一块80块钱买的 Teensy ++ 2.0,有48个IO接口,128KB闪存。
当时对TMK这类固件实在是折腾不明白,做键盘用的固件是 Easy AVR ,相对TMK来说算比较简单。
最后就用 Kinesis Contoured + Teensy ++ 2.0 + EasyAVR 做了这块键盘,还买了膜重新贴了一下表面,后面这把键盘也拿到公司去用了相当长的一段时间。
现在又打算重新折腾新的键盘,了解到 Vial 这种不需要每次改建都重刷的免刷固件,打算尝试一下,刚好 Teensy ++ 2.0 的闪存还够大,先拿这个老伙计练练手。
提示
快速介绍DIY键盘的基础知识:
键盘一般都是以行(Rows)列(Columns)组合的矩阵扫描的方式来工作的,每个按键都坐落在这个矩阵某行某列的某个交叉点上。
各行各列分别连接到微控制器的IO接口上,在固件中做好各个IO口分别属于什么行什么列。
假设当你定义好了第3行、第2列的键是A键,当按下这个位置上的键时,微控制器通过扫描发现矩阵的第3行、第2列对应的IO口连通,就知道A键被按下了。
这种矩阵设计可以用很少的IO线路支持大量按键,例如17个IO线路就能支持5x12=60个键,这种方式降低了硬件的复杂度和成本。
同时,为了防止按下多个按键时,电流可能会在矩阵中“抄近路”反向流动,导致微控制器错误识别出实际并未按下的键(“鬼键”)。在每个按键后串联一个二极管,利用二极管的单向导电性防止电流倒灌,从而确保每次按键都能被准确识别,二极管串联的方式有可能是行到列,也可能是列到行。
而 QMK
是一个开源键盘固件,你可以把它理解为键盘的操作系统,它适配了常见的带USB功能的微处理器,最常用的功能是:
按键映射(Keymap):可以随意给每个按键分配功能,比如把CapsLock键改成更常用的Ctrl或Esc键。
多层(Layers):这是QMK最强大的功能之一。设置不同的功能层。通过按住特定的修饰键,瞬间切换到另一层,类似于笔记本上的Fn键。
宏(Macros):一键输出一串字符或执行复杂操作,例如一键输入常用的邮箱用户名、一键按下Ctrl+Alt+Del、一键自动打开终端。
二合一(Mod-Tap):短按时,它像一个普通按键,例如A键,长按时则成为一个修饰键,例如 Shift、Ctrl、 Alt、 Win 或 Fn。
除此之外,QMK还有很功能,这里就不多做介绍了。
而 Vial 是 Via 的改版,Via 是 QMK 的改版,Vial 最大好处是不需要重新刷写固件,就可以图形化修改键盘映射,使用方便。
硬件信息
基础结构
精减原电路板处理后的 Kinesis Contoured 键盘。保留了外壳、按键及PCB结构、加了点热熔胶修复、重新贴了膜。
开发板
- 8 位 AVR 处理器 (AT90USB1286)
- 128K 闪存,8K RAM,4K EEPROM
- 46 个数位 I/O 引脚
提示
QMK固件推荐使用64K或者以上的闪存,Vial固件推荐128K或者以上闪存。
ATMEGA32U4 这种32K的,IO又少的现在是真的不推荐了。(虽然我之前折腾58键配列的键盘买了不少,现在还有几块没用过的。)
推荐PR2040(2MB)、STM32F103CBT6(128K)、 STM32F103C8T6(64KB)
连线结构
因为保留了原有的PCB,所以是直接飞线接到了PCB上面,使用了PCB原来的布局,所以并不是严格直观的行列划分。
一共使用了 7行 12列
行(Row)端口:D1、D2、D3、D4、D5、D6、D7
列(Col)端口:C1、C2、C3、C4、C5、C6、F1、F2、F3、F4、F5、F6
二极管方向:行到列,Row2Col
QMK
参考资料:QMK 教程 - docs.qmk.fm
搭建环境
Windows用户折腾QMK,请先安装 QMK MSYS ,默认选项一路下一步就可以了。
本文撰写时,QMK MSYS 版本为 1.11.0,QMK MSYS 安装教程:开始安装 QMK MSYS
安装完成,在开始菜单找到 QMK MSYS,打开后效果如图
在打开 QMK MSYS 后,运行 qmk setup
命令:
1[Xin@DESKTOP-XXXXXXX ~]$ qmk setup
2
3☒ Could not find qmk_firmware!
4Would you like to clone qmk/qmk_firmware to C:/Users/Xin/qmk_firmware? [y/n] y
5正克隆到 '/c/Users/Xin/qmk_firmware'...
6正在更新文件: 0% (148/22285)
7...
8正在更新文件: 100% (22285/22285), 完成.
9...
10Ψ Successfully cloned https://github.com/qmk/qmk_firmware to C:/Users/Xin/qmk_firmware!
11Ψ Added https://github.com/qmk/qmk_firmware as remote upstream.
12Ψ QMK Doctor is checking your environment.
13Ψ CLI version: 1.1.8
14Ψ QMK home: C:/Users/Xin/qmk_firmware
15Ψ Detected Windows 10 (10.0.19044).
16Ψ QMK MSYS version: 1.11.0
17Ψ Userspace enabled: False
18Ψ Git branch: master
19Ψ Repo version: 0.29.12
20...
21Ψ Submodule status:
22Ψ - lib/chibios: 2025-05-15 08:25:11 +0000 -- (8bd61b8043)
23Ψ - lib/chibios-contrib: 2025-01-08 21:03:31 +0100 -- (3ac181e4)
24Ψ - lib/googletest: 2021-06-11 06:37:43 -0700 -- (e2239ee6)
25Ψ - lib/lufa: 2022-08-26 12:09:55 +1000 -- (549b97320)
26Ψ - lib/vusb: 2022-06-13 09:18:17 +1000 -- (819dbc1)
27Ψ - lib/printf: 2022-06-29 23:59:58 +0300 -- (c2e3b4e)
28Ψ - lib/pico-sdk: 2025-04-20 21:24:29 +1000 -- (d0c5cac)
29Ψ - lib/lvgl: 2022-04-11 04:44:53 -0600 -- (e19410f8)
30Ψ QMK is ready to go
注意它克隆到的路径,我这里是 C:/Users/Xin/qmk_firmware
这就是我QMK相关的文件夹了,后续产生的文件都基本在这个目录下。
注意
如果克隆不动,你可以先使用上网妙妙工具优化一下,使用代理访问,例如:
1# 设置 http、https 全局代理
2[Xin@DESKTOP-XXXXXXX ~]$ git config --global http.proxy 127.0.0.1:7890
3[Xin@DESKTOP-XXXXXXX ~]$ git config --global https.proxy 127.0.0.1:7890
4
5# 取消 http、https 全局代理
6[Xin@DESKTOP-XXXXXXX ~]$ git config --global --unset http.proxy
7[Xin@DESKTOP-XXXXXXX ~]$ git config --global --unset https.proxy
或者 Watt Toolkit(Steam++) 之类的加速GitHub的访问。
提示
由于我们最终目的是Vial固件,所以也可以直接选择克隆 Vial 的 QMK 分支项目,来避免后面的 Vial 环节还要重新克隆。
1[Xin@DESKTOP-XXXXXXX ~]$ git clone https://github.com/vial-kb/vial-qmk
2……
3[Xin@DESKTOP-XXXXXXX ~]$ cd vial-qmk
4……
5[Xin@DESKTOP-XXXXXXX vial-qmk]$ qmk doctor
6……
7Would you like to clone the submodules? [Y/n] y
具体命令可以先跳到下面的 Vial - 搭建环境 部分查看,使用 Vial 克隆分支的话,后续的操作要注意在 [Xin@DESKTOP-XXXXXXX vial-qmk]$
下操作
创建新键盘
在 QMK MSYS 中,运行 qmk new-keyboard
命令来创建新键盘,并按提示填写参数,输错了可以直接 Ctrl+C
结束重来。
1[Xin@DESKTOP-XXXXXXX ~]$ qmk new-keyboard
2Ψ Generating a new QMK keyboard directory
3
4Ψ Name Your Keyboard Project
5Ψ For more information, see:
6https://docs.qmk.fm/hardware_keyboard_guidelines#naming-your-keyboard-project
7Keyboard Name?
提示输入键盘名,我这里取名叫 kinesis_advantage_teensy_pp2
就是键盘布局+主控型号
1Keyboard Name? kinesis_advantage_teensy_pp2
2Ψ Attribution
3Ψ Used for maintainer, copyright, etc.
4Your GitHub Username?
提示输入GitHub名字,我这里输入的是 tjxwork
,接着又问你的真实名字,直接回车就会使用上面输入的GitHub名字
1Your GitHub Username? tjxwork
2Ψ More Attribution
3Ψ Used for maintainer, copyright, etc.
4Your Real Name? [tjxwork]
5Ψ Pick Base Layout
6Ψ As a starting point, one of the common layouts can be used to
7bootstrap the process
接着会问你的键盘配列布局,因为我用的不是人家已经提交上去的方案,所以直接回车选择默认的 65. none of the above
“以上都不是”
1bootstrap the process
2Default Layout?
3 1. 60_abnt2
4 2. 60_ansi
5 3. 60_ansi_arrow
6 4. 60_ansi_wkl
7 5. 60_hhkb
8...
9 61. tkl_iso_wkl
10 62. tkl_jis
11 63. tkl_nofrow_ansi
12 64. tkl_nofrow_iso
13 65. none of the above
14Please enter your choice: [65]
接下来问你没有使用开发板,有y
,没有n
,虽然我的确有使用开发板,但是QMK里面没有 Teensy ++ 2.0 这张开发板的选项,只能输入n
1Ψ What Powers Your Project
2Ψ Is your board using a separate development board, such as a Pro Micro,
3or is the microcontroller integrated onto the PCB?
4
5For more information, see:
6https://docs.qmk.fm/compatible_microcontrollers
7Using a Development Board? [y/n] n
提示
当前版本QMK提供的开发板的选项,如果使用的刚好是对应的开发板的话,可以输入y
来使用,
1Using a Development Board? [y/n] y
2Ψ Select Development Board
3Ψ For more information, see:
4https://docs.qmk.fm/compatible_microcontrollers
5Development Board?
6 1. bit_c_pro
7 2. blackpill_f401
8 3. blackpill_f411
9 4. blok
10 5. bluepill
11 6. bonsai_c4
12 7. elite_c
13 8. elite_pi
14 9. helios
15 10. imera
16 11. kb2040
17 12. liatris
18 13. michi
19 14. promicro
20 15. promicro_rp2040
21 16. proton_c
22 17. stemcell
23 18. svlinky
输入n
,选择没有使用开发板后,会出让你选择微控制器的选项列表,前面已经介绍过 Teensy ++ 2.0
是使用的 AT90USB1286
,所以我这里选择对应的 2
1Using a Development Board? [y/n] n
2Ψ Select Microcontroller
3Ψ For more information, see:
4https://docs.qmk.fm/compatible_microcontrollers
5Microcontroller?
6 1. AT32F415
7 2. at90usb1286
8 3. at90usb1287
9 4. at90usb162
10 5. at90usb646
11 6. at90usb647
12 7. atmega16u2
13 8. atmega16u4
14 9. atmega328
15 10. atmega328p
16 11. atmega32a
17 12. atmega32u2
18 13. atmega32u4
19 14. attiny85
20 15. GD32VF103
21 16. MK20DX128
22 17. MK20DX256
23 18. MK64FX512
24 19. MK66FX1M0
25 20. MKL26Z64
26 21. RP2040
27 22. STM32F042
28 23. STM32F072
29 24. STM32F103
30 25. STM32F303
31 26. STM32F401
32 27. STM32F405
33 28. STM32F407
34 29. STM32F411
35 30. STM32F446
36 31. STM32G0B1
37 32. STM32G431
38 33. STM32G474
39 34. STM32H723
40 35. STM32H733
41 36. STM32L412
42 37. STM32L422
43 38. STM32L432
44 39. STM32L433
45 40. STM32L442
46 41. STM32L443
47 42. WB32F3G71
48 43. WB32FQ95
49Please enter your choice: [13] 2
50Ψ Created a new keyboard called kinesis_advantage_teensy_pp2.
51Ψ Build Command: qmk compile -kb kinesis_advantage_teensy_pp2 -km default.
52Ψ Project Location: C:/Users/Xin/qmk_firmware/keyboards/kinesis_advantage_teensy_pp2.
53Ψ Now update the config files to match the hardware!
好了,到这里基础的创建引导就结束了,QMK会帮忙创建一个包含基础内容的键盘项目,返回的信息告诉我们:
编译固件命令:qmk compile -kb kinesis_advantage_teensy_pp2 -km default
键盘项目路径:C:/Users/Xin/qmk_firmware/keyboards/kinesis_advantage_teensy_pp2
1Ψ Created a new keyboard called kinesis_advantage_teensy_pp2.
2Ψ Build Command: qmk compile -kb kinesis_advantage_teensy_pp2 -km default.
3Ψ Project Location: C:/Users/Xin/qmk_firmware/keyboards/kinesis_advantage_teensy_pp2.
4Ψ Now update the config files to match the hardware!
键盘映射定义
接下来就要用文本编辑器来编辑,刚刚生成的键盘项目源代码文件了,推荐使用 Visual Studio Code 或者任意你顺手的文本编辑器。
C:/Users/Xin/qmk_firmware/keyboards/kinesis_advantage_teensy_pp2
的文件结构如下:
1├── keymaps
2│ └── default
3│ └── keymap.c
4├── keyboard.json
5└── readme.md
使用 VSCode 打开 C:/Users/Xin/qmk_firmware/keyboards/kinesis_advantage_teensy_pp2
文件夹的效果如下:
主要需要编辑修改的文件是 keyboard.json
、 keymap.c
这两个文件。
我们先来看一下创建键盘向导的生成的 keyboard.json
1// QMK创建新键盘项目的向导生成的 keyboard.json
2{
3 "manufacturer": "tjxwork",// 制造商署名
4 "keyboard_name": "kinesis_advantage_teensy_pp2",//键盘名,系统键盘名称
5 "maintainer": "tjxwork",//制造者名称,影响系统如何称呼该设备
6 "bootloader": "atmel-dfu",//Bootloader的型号
7 "diode_direction": "COL2ROW",//矩阵键盘扫描二极管方向,默认是列到行
8 "features": { //键盘支持的特性
9 "bootmagic": true, //支持快捷键进入Bootloader模式
10 "extrakey": true, //支持额外的按键,音量加减和媒体控制键等
11 "mousekey": true, //支持键盘输出鼠标按键信号
12 "nkro": true //支持N-Key Rollover(全键无冲)功能
13 },
14 "matrix_pins": { //定义矩阵键盘的行列分别使用的IO口编号
15 "cols": ["C2", "C2", "C2", "C2"], //使用的列IO
16 "rows": ["D1", "D1", "D1", "D1"] //使用的行IO
17 },
18 "processor": "at90usb1286", //主控微处理器型号
19 "url": "", //设计者的主页地址
20 "usb": {
21 "device_version": "1.0.0", //设备版本号
22 "pid": "0x0000", //可以理解为设备的型号
23 "vid": "0xFEED" //可以理解为厂家的编号
24 },
25 "layouts": {
26 "LAYOUT": { //键盘使用的矩阵名称,要和 keymap.c 那边对应,建议保持默认
27 "layout": [ //"layout": []相当于一个数组,你怎么排版不影响,但是要注意,它和 keymap.c 那边的 "[0] = LAYOUT" 的数量和顺序要是对应的。
28 {"matrix": [0, 0], "x": 0, "y": 0}, //每组{}定义每个按键在矩阵的位置,空间坐标和大小
29 {"matrix": [0, 1], "x": 1, "y": 0}, //"matrix": [0, 1], 就是0行,1列,这个矩阵交叉点上有一个按键
30 {"matrix": [0, 2], "x": 2, "y": 0}, //"x": 2, "y": 0,就是这个按钮在逻辑上的大概位置
31 {"matrix": [0, 3], "x": 3, "y": 0}, //还可以定义 "h":2 高度、"w":2 宽度
32 {"matrix": [1, 0], "x": 0, "y": 1}, //至于后面的 x y 之类参数,对于 kinesis advantage 这种非严格直上直下的布局,只有参考作用
33 {"matrix": [1, 1], "x": 1, "y": 1}, //建议按正常思路从上到下,从左到右来填写。
34 {"matrix": [1, 2], "x": 2, "y": 1}, //其实上面的 连线结构 那里就已经提前写好了每个按钮的[行,列]值,直接抄就可以了。
35 {"matrix": [1, 3], "x": 3, "y": 1},
36 {"matrix": [2, 0], "x": 0, "y": 2},
37 {"matrix": [2, 1], "x": 1, "y": 2},
38 {"matrix": [2, 2], "x": 2, "y": 2},
39 {"matrix": [2, 3], "x": 3, "y": 2},
40 {"matrix": [3, 0], "x": 0, "y": 3},
41 {"matrix": [3, 1], "x": 1, "y": 3},
42 {"matrix": [3, 2], "x": 2, "y": 3},
43 {"matrix": [3, 3], "x": 3, "y": 3}
44 ]
45 }
46 }
47}
小心
注意,默认情况下json文件是不支持注释的,这里为了方便演示加了注释而已,实际使用中请不要注释。
配合实际的二极管方向、IO接口、键盘矩阵结构对 keyboard.json
进行修改后:
1{
2 "manufacturer": "tjxwork",
3 "keyboard_name": "kinesis_advantage_teensy_pp2",
4 "maintainer": "tjxwork",
5 "bootloader": "atmel-dfu",
6 "diode_direction": "ROW2COL",
7 "features": {
8 "bootmagic": true,
9 "extrakey": true,
10 "mousekey": true,
11 "nkro": true
12 },
13 "matrix_pins": {
14 "cols": ["F1", "F2", "F3", "F4", "F5", "F6", "C1", "C2", "C3", "C4", "C5", "C6"],
15 "rows": ["D1", "D2", "D3", "D4", "D5", "D6", "D7"]
16 },
17 "processor": "at90usb1286",
18 "url": "",
19 "usb": {
20 "device_version": "1.0.0",
21 "pid": "0x0000",
22 "vid": "0xFEED"
23 },
24 "layouts": {
25 "LAYOUT": {
26 "layout": [
27 {"matrix": [0, 0], "x": 0, "y": 0},
28 {"matrix": [0, 1], "x": 1, "y": 0},
29 {"matrix": [0, 2], "x": 2, "y": 0},
30 {"matrix": [0, 3], "x": 3, "y": 0},
31 {"matrix": [0, 4], "x": 4, "y": 0},
32 {"matrix": [0, 5], "x": 5, "y": 0},
33 {"matrix": [0, 6], "x": 12, "y": 0},
34 {"matrix": [0, 7], "x": 13, "y": 0},
35 {"matrix": [0, 8], "x": 14, "y": 0},
36 {"matrix": [0, 9], "x": 15, "y": 0},
37 {"matrix": [0,10], "x": 16, "y": 0},
38 {"matrix": [0,11], "x": 17, "y": 0},
39
40 {"matrix": [1, 0], "x": 0, "y": 1},
41 {"matrix": [1, 1], "x": 1, "y": 1},
42 {"matrix": [1, 2], "x": 2, "y": 1},
43 {"matrix": [1, 3], "x": 3, "y": 1},
44 {"matrix": [1, 4], "x": 4, "y": 1},
45 {"matrix": [1, 5], "x": 5, "y": 1},
46 {"matrix": [1, 6], "x": 12, "y": 1},
47 {"matrix": [1, 7], "x": 13, "y": 1},
48 {"matrix": [1, 8], "x": 14, "y": 1},
49 {"matrix": [1, 9], "x": 15, "y": 1},
50 {"matrix": [1,10], "x": 16, "y": 1},
51 {"matrix": [1,11], "x": 17, "y": 1},
52
53 {"matrix": [2, 0], "x": 0, "y": 2},
54 {"matrix": [2, 1], "x": 1, "y": 2},
55 {"matrix": [2, 2], "x": 2, "y": 2},
56 {"matrix": [2, 3], "x": 3, "y": 2},
57 {"matrix": [2, 4], "x": 4, "y": 2},
58 {"matrix": [2, 5], "x": 5, "y": 2},
59 {"matrix": [2, 6], "x": 12, "y": 2},
60 {"matrix": [2, 7], "x": 13, "y": 2},
61 {"matrix": [2, 8], "x": 14, "y": 2},
62 {"matrix": [2, 9], "x": 15, "y": 2},
63 {"matrix": [2,10], "x": 16, "y": 2},
64 {"matrix": [2,11], "x": 17, "y": 2},
65
66 {"matrix": [3, 0], "x": 0, "y": 3},
67 {"matrix": [3, 1], "x": 1, "y": 3},
68 {"matrix": [3, 2], "x": 2, "y": 3},
69 {"matrix": [3, 3], "x": 3, "y": 3},
70 {"matrix": [3, 4], "x": 4, "y": 3},
71 {"matrix": [3, 5], "x": 5, "y": 3},
72 {"matrix": [3, 6], "x": 12, "y": 3},
73 {"matrix": [3, 7], "x": 13, "y": 3},
74 {"matrix": [3, 8], "x": 14, "y": 3},
75 {"matrix": [3, 9], "x": 15, "y": 3},
76 {"matrix": [3,10], "x": 16, "y": 3},
77 {"matrix": [3,11], "x": 17, "y": 3},
78
79 {"matrix": [4, 1], "x": 1, "y": 4},
80 {"matrix": [4, 2], "x": 2, "y": 4},
81 {"matrix": [4, 3], "x": 3, "y": 4},
82 {"matrix": [4, 5], "x": 5, "y": 4},
83 {"matrix": [4, 6], "x": 12, "y": 4},
84 {"matrix": [4, 8], "x": 14, "y": 4},
85 {"matrix": [4, 9], "x": 15, "y": 4},
86 {"matrix": [4,10], "x": 16, "y": 4},
87
88 {"matrix": [5, 5], "x": 7, "y": 5},
89 {"matrix": [6, 5], "x": 8, "y": 5},
90 {"matrix": [6, 6], "x": 9, "y": 5},
91 {"matrix": [5, 8], "x": 10, "y": 5},
92
93 {"matrix": [5, 2], "x": 6, "y": 6, "h":2},
94 {"matrix": [5, 3], "x": 7, "y": 6},
95 {"matrix": [6, 2], "x": 8, "y": 6},
96 {"matrix": [6, 8], "x": 9, "y": 6},
97 {"matrix": [5, 9], "x": 10, "y": 6},
98 {"matrix": [5,10], "x": 11, "y": 6, "h":2},
99
100 {"matrix": [6, 1], "x": 8, "y": 7},
101 {"matrix": [6,10], "x": 9, "y": 7}
102 ]
103 }
104 }
105}
接下来要修改 keymap.c
,先看一下生成的模板
1// QMK创建新键盘项目的向导生成的 keymap.c
2
3// Copyright 2023 QMK
4// SPDX-License-Identifier: GPL-2.0-or-later
5
6#include QMK_KEYBOARD_H
7
8const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
9 /*
10 * ┌───┬───┬───┬───┐ //可以看到默认给的一个数字小键盘的布局
11 * │ 7 │ 8 │ 9 │ / │
12 * ├───┼───┼───┼───┤
13 * │ 4 │ 5 │ 6 │ * │
14 * ├───┼───┼───┼───┤
15 * │ 1 │ 2 │ 3 │ - │
16 * ├───┼───┼───┼───┤
17 * │ 0 │ . │Ent│ + │
18 * └───┴───┴───┴───┘
19 */
20 [0] = LAYOUT( //LAYOUT() 这个名字也是和 keyboard.json 里面的 "LAYOUT": {} 是对应的
21 KC_P7, KC_P8, KC_P9, KC_PSLS, //还要注意这里是和 keyboard.json 里面的 "layout": [] 的键位数量是对应的,都是16个。
22 KC_P4, KC_P5, KC_P6, KC_PAST, //这里它排成了4x4的排版,但是怎么排版都不影响作用的,只看顺序,和 "layout": [] 那边是对应的
23 KC_P1, KC_P2, KC_P3, KC_PMNS,
24 KC_P0, KC_PDOT, KC_PENT, KC_PPLS
25 )
26 //默认的初始布局只定义了一个基础层,0层,就是 [0] = LAYOUT
27 //要更多层布局就复制一份,把前面的数值增加,比如 [1] = LAYOUT,这个就是1层
28 //有多种方法在 0层 里面定义按键用于切换到 1层,比如 MO(1),按下后临时切换到1层
29 //keyboard.json 里面的 "layout": [] 有多少键位数量,这边的每一层就得有多少个按键。
30 //实在不知道用什么,你可以禁用这个键 KC_NO ,也可以使用切换层之前的键 KC_TRNS
31 //具体的按键定义请看QMK文档:https://docs.qmk.fm/#/keycodes
32};
我设想中的键位配列,按下L1,即可切换到红色的1层
根据 keyboard.json
和设想中的键位配列修改keymap.c
1// Copyright 2023 QMK
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include QMK_KEYBOARD_H
5
6const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
7 /*
8 * ,-------------------------------------------- --------------------------------------------.
9 * | ESC | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | - |
10 * |--------+------+------+------+------+------- +------+------+------+------+------+--------|
11 * | TAB | Q | W | E | R | T | | Y | U | I | O | P | [ |
12 * |--------+------+------+------+------+------| |------+------+------+------+------+--------|
13 * | Ctrl | A | S | D | F | G | | H | J | K | L | ; | ' |
14 * |--------+------+------+------+------+------| |------+------+------+------+------+--------|
15 * | LShift | Z | X | C | V | B | | N | M | , | . | / | RShift |
16 * `--------+------+------+------+------+------- -------+------+------+------+------+--------'
17 * | L1 | LEFT | RGHT | ALT | | = | ` | \ | L1 |
18 * ----------------------------' `----------------------------
19 * ,-------------. ,-------------.
20 * | L1 | DEL | | APP | L1 |
21 * ,------|------|------| |------+------+------.
22 * | | | Home | | End | | |
23 * | Spac | Back |------| |------| Ent | Spac |
24 * | | | LGUI | | CAPS | | |
25 * `--------------------' `--------------------'
26 */
27 [0] = LAYOUT(
28 KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS,
29 KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC,
30 KC_LCTL, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT,
31 KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT,
32 MO(1), KC_LEFT, KC_RGHT, KC_LALT, KC_EQL, KC_GRV, KC_BSLS, MO(1),
33
34 MO(1), KC_DEL, KC_APP, MO(1),
35 KC_SPC, KC_BSPC, KC_HOME, KC_END, KC_ENT, KC_SPC,
36 KC_LGUI, KC_CAPS
37 ),
38
39
40 /*
41 * ,-------------------------------------------- --------------------------------------------.
42 * | | F1 | F2 | F3 | F4 | F5 | | F6 | F7 | F8 | F9 | F10 | F11 |
43 * |--------+------+------+------+------+------- +------+------+------+------+------+--------|
44 * | | PGUP | HOME | UP | END | PSCR | | P* | P7 | P8 | P9 | P/ | ] |
45 * |--------+------+------+------+------+------| |------+------+------+------+------+--------|
46 * | | PGDN | LEFT | DOWN | RGHT | SLCK | | P+ | P4 | P5 | P6 | P- | F12 |
47 * |--------+------+------+------+------+------| |------+------+------+------+------+--------|
48 * | | ` | APP | INS | DEL | PPLS | | P0 | P1 | P2 | P3 | \ | |
49 * `--------+------+------+------+------+------- -------+------+------+------+------+--------'
50 * | | | | | | P0 | P. | PEnt | |
51 * ----------------------------' `----------------------------
52 * ,-------------. ,-------------.
53 * | L2 | | | | |
54 * ,------|------|------| |------+------+------.
55 * | | | | | | | |
56 * | | Ent |------| |------| Back | |
57 * | | | | | NLCK | | |
58 * `--------------------' `--------------------'
59 */
60 [1] = LAYOUT(
61 KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11,
62 KC_TRNS, KC_PGUP, KC_HOME, KC_UP, KC_END, KC_PSCR, KC_PAST, KC_P7, KC_P8, KC_P9, KC_PSLS, KC_RBRC,
63 KC_TRNS, KC_PGDN, KC_LEFT, KC_DOWN, KC_RGHT,KC_SCRL, KC_PPLS, KC_P4, KC_P5, KC_P6, KC_PMNS, KC_F12,
64 KC_TRNS, KC_GRV, KC_APP, KC_INS, KC_DEL, KC_PAUS, KC_P0, KC_P1, KC_P2, KC_P3, KC_BSLS, KC_TRNS,
65 KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_P0, KC_PDOT, KC_PENT, KC_TRNS,
66
67 MO(2), KC_TRNS, KC_TRNS, KC_TRNS,
68 KC_TRNS, KC_ENT, KC_TRNS, KC_TRNS, KC_BSPC, KC_TRNS,
69 KC_TRNS, KC_NUM
70 ),
71
72 /*
73 * ,-------------------------------------------- --------------------------------------------.
74 * | | | | | | | | | | | | | |
75 * |--------+------+------+------+------+------- +------+------+------+------+------+--------|
76 * | | | | | | | | | | | | | |
77 * |--------+------+------+------+------+------| |------+------+------+------+------+--------|
78 * | | | | | | | | | | | | | |
79 * |--------+------+------+------+------+------| |------+------+------+------+------+--------|
80 * | | | | | | | | | | | | | |
81 * `--------+------+------+------+------+------- -------+------+------+------+------+--------'
82 * | | | | | | | | | |
83 * ----------------------------' `----------------------------
84 * ,-------------. ,-------------.
85 * | | | | | BOOT |
86 * ,------|------|------| |------+------+------.
87 * | | | | | | | |
88 * | | |------| |------| | |
89 * | | | | | | | |
90 * `--------------------' `--------------------'
91 */
92 [2] = LAYOUT(
93 KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
94 KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
95 KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
96 KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
97 KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
98
99 KC_TRNS, KC_TRNS, KC_TRNS, QK_BOOT,
100 KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
101 KC_TRNS, KC_TRNS
102 )
103};
注意
再次提醒, [x] = LAYOUT()
里面的排版格式不影响实际工作,它只考虑顺序。并且是和 keyboard.json
里面的 "layout": []
是对应的。
提示
为了方便刷固件,和防止误触,我额外在1层里面,多添加了一个2层的切换,然后在2层又定义了一个 QK_BOOT
用来进入 bootloader 引导加载程序模式,
编译固件
回到 QMK MSYS 中,输入 qmk compile -kb kinesis_advantage_teensy_pp2 -km default
这个命令在创建新键盘的时候有提示的。编译固件是比较花时间,耐心等待。
1[Xin@DESKTOP-XXXXXXX ~]$ qmk compile -kb kinesis_advantage_teensy_pp2 -km default
2Ψ Compiling keymap with make -r -R -f builddefs/build_keyboard.mk -s KEYBOARD=kinesis_advantage_teensy_pp2 KEYMAP=default KEYBOARD_FILESAF E=kinesis_advantage_teensy_pp2 TARGET=kinesis_advantage_teensy_pp2_default VERBOSE=false COLOR=true SILENT=false QMK_BIN="qmk"
3
4avr-gcc.exe (GCC) 15.1.0
5Copyright (C) 2025 Free Software Foundation, Inc.
6This is free software; see the source for copying conditions. There is NO
7warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8
9Compiling: quantum/keymap_introspection.c [OK]
10...
11Compiling: tmk_core/protocol/lufa/usb_util.c [OK]
12Linking: .build/kinesis_advantage_teensy_pp2_default.elf [OK]
13Creating load file for flashing: .build/kinesis_advantage_teensy_pp2_default.hex [OK]
14Copying kinesis_advantage_teensy_pp2_default.hex to qmk_firmware folder [OK]
15Checking file size of kinesis_advantage_teensy_pp2_default.hex [OK]
16 * The firmware size is fine - 15888/122880 (12%, 106992 bytes free)
编译完成后,在 C:/Users/Xin/qmk_firmware/
下的 .build
文件夹,可以找到格式为 键盘名_default.hex
的文件,这个就是我们要编译完成的固件。
可以看到默认出来的QMK固件体积有44KB,所以才不建议使用闪存只有32KB的32U4,要精简功能才能放得下去。
刷入固件
下载 QMK Toolbox ,打开运行后,
点 Open
选择上面生成的固件,点右边的下拉选择对应的 AT90USB1286
,勾选 Auto-Flash
,
按一下开发板上的 Reset
按钮,或者用之前键盘上定义过的快捷键进入 bootloader
模式,随后就会自动刷入固件。
提示
如果你使用的是 PR2040 的话,不需要 QMK Toolbox 就可以刷入固件 PR2040 刷入固件方式
你可以点击 QMK Toolbox 上面 Tools
菜单中的 Key Tester
来测试一下键盘是否正常工作。
至此,QMK固件就算制作完成了。
Vial
参考资料:Vial移植指南 - get.vial.today
创建键盘定义 JSON
首先我们要先创建 Vial 要用到的键位分布位置信息,在正常情况下,这些信息最终会以 vial.json
这个文件名出现在键盘项目里面。
访问 keyboard-layout-editor 键盘布局编辑器
,点击上面的 Preset
里面刚好有 Kinesis Advantage 系列的配列,可以基于这个配列修改,不需要重头开始摆了,点击切换后如图
删除多余的键,然后在每个按钮的 Properties
中的 Top Legend
属性中,填上键盘矩阵中对应的 行数值,列数值
提示
你可以点击下方的 Tools
标签页,然后再点击 Remoe Legends:
下的 All
来直接清除所有的键空内容
这张图是不是有点眼熟,其实就是前面提到的 连线结构 里面的示意图
全部调整完后,点击右上角的 Download
,再点击 Download JSON
下载编辑好的配列文件,把里面内容复制到官方的vial.json
模板里面。
1// 官方的 vial.json 模板
2{
3 "lighting": "none", //键盘的背光方式
4 "matrix": {
5 "rows": 0, //输入键盘的行数
6 "cols": 0 //输入键盘的列数
7 },
8 "layouts": {
9 "labels": //如果您的键盘没有任何变种布局选项,应该删除此行。
10 "keymap": //将上一步中下载的 JSON 的完整内容粘贴到冒号符号之后
11 }
12}
小心
注意,默认情况下json文件是不支持注释的,这里为了方便演示加了注释而已,实际使用中请不要注释。
修改后,并添加了keyboard-layout-editor
数据的 vial.json
文件内容,注意保存好,后面要用。
1{
2 "lighting": "none",
3 "matrix": {
4 "rows": 7,
5 "cols": 12
6 },
7 "layouts": {
8 "keymap": [
9 [
10 {
11 "y": 1,
12 "x": 2.25,
13 "f": 5
14 },
15 "0,2",
16 "0,3",
17 "0,4",
18 "0,5",
19 {
20 "x": 5.5
21 },
22 "0,6",
23 "0,7",
24 "0,8",
25 "0,9"
26 ],
27 [
28 {
29 "y": -0.75,
30 "w": 1.25
31 },
32 "0,0",
33 "0,1",
34 {
35 "x": 13.5
36 },
37 "0,10",
38 {
39 "w": 1.25
40 },
41 "0,11"
42 ],
43 [
44 {
45 "y": -0.25,
46 "x": 2.25
47 },
48 "1,2",
49 "1,3",
50 "1,4",
51 "1,5",
52 {
53 "x": 5.5
54 },
55 "1,6",
56 "1,7",
57 "1,8",
58 "1,9"
59 ],
60 [
61 {
62 "y": -0.75,
63 "w": 1.25
64 },
65 "1,0",
66 "1,1",
67 {
68 "x": 13.5
69 },
70 "1,10",
71 {
72 "w": 1.25
73 },
74 "1,11"
75 ],
76 [
77 {
78 "y": -0.25,
79 "x": 2.25
80 },
81 "2,2",
82 "2,3",
83 "2,4",
84 "2,5",
85 {
86 "x": 5.5
87 },
88 "2,6",
89 "2,7",
90 "2,8",
91 "2,9"
92 ],
93 [
94 {
95 "y": -0.75,
96 "w": 1.25
97 },
98 "2,0",
99 "2,1",
100 {
101 "x": 13.5
102 },
103 "2,10",
104 {
105 "w": 1.25
106 },
107 "2,11"
108 ],
109 [
110 {
111 "y": -0.25,
112 "x": 2.25
113 },
114 "3,2",
115 "3,3",
116 "3,4",
117 "3,5",
118 {
119 "x": 5.5
120 },
121 "3,6",
122 "3,7",
123 "3,8",
124 "3,9"
125 ],
126 [
127 {
128 "y": -0.75,
129 "w": 1.25
130 },
131 "3,0",
132 "3,1",
133 {
134 "x": 13.5
135 },
136 "3,10",
137 {
138 "w": 1.25
139 },
140 "3,11"
141 ],
142 [
143 {
144 "y": -0.25,
145 "x": 2.25
146 },
147 "4,2",
148 "4,3",
149 "4,5",
150 {
151 "x": 7.5
152 },
153 "4,6",
154 "4,8",
155 "4,9"
156 ],
157 [
158 {
159 "y": -0.75,
160 "x": 1.25
161 },
162 "4,1",
163 {
164 "x": 13.5
165 },
166 "4,10"
167 ],
168 [
169 {
170 "r": 15,
171 "rx": 5.25,
172 "ry": 4,
173 "y": 0.75,
174 "x": 2
175 },
176 "5,5",
177 "6,5"
178 ],
179 [
180 {
181 "x": 1,
182 "h": 2
183 },
184 "5,2",
185 {
186 "h": 2
187 },
188 "5,3",
189 "6,2"
190 ],
191 [
192 {
193 "x": 3
194 },
195 "6,1"
196 ],
197 [
198 {
199 "r": -15,
200 "rx": 12.75,
201 "y": 0.75,
202 "x": -4
203 },
204 "6,6",
205 "5,8"
206 ],
207 [
208 {
209 "x": -4
210 },
211 "6,8",
212 {
213 "h": 2
214 },
215 "5,9",
216 {
217 "h": 2
218 },
219 "5,10"
220 ],
221 [
222 {
223 "x": -4
224 },
225 "6,10"
226 ]
227 ]
228 }
229}
下载 Vial 软件
,运行后,点击 File
-> Load dummy JSON
加载上面处理好的 vial.json
文件,加载成功后,应该会显示之前编辑好的布局。
提示
加载后没显示可以点一下右边的 Refresh
按钮
搭建环境
这里假设你已经装好了 QMK MSYS
先克隆 Vial 的 QMK 分支项目 git clone https://github.com/vial-kb/vial-qmk
1[Xin@DESKTOP-XXXXXXX ~]$ git clone https://github.com/vial-kb/vial-qmk
2正克隆到 'vial-qmk'...
3remote: Enumerating objects: 584396, done.
4remote: Counting objects: 100% (31879/31879), done.
5remote: Compressing objects: 100% (1439/1439), done.
6remote: Total 584396 (delta 31240), reused 30445 (delta 30440), pack-reused 552517 (from 2)
7接收对象中: 100% (584396/584396), 277.89 MiB | 13.08 MiB/s, 完成.
8处理 delta 中: 100% (306283/306283), 完成.
9正在更新文件: 100% (25186/25186), 完成.
克隆完成后,cd vial-qmk
把目录切到 vial-qmk
下面
1[Xin@DESKTOP-XXXXXXX ~]$ cd vial-qmk
2[Xin@DESKTOP-XXXXXXX vial-qmk]$
检查环境 qmk doctor
1[Xin@DESKTOP-XXXXXXX vial-qmk]$ qmk doctor
2
3Ψ QMK Doctor is checking your environment.
4Ψ CLI version: 1.1.8
5Ψ QMK home: C:/Users/Xin/vial-qmk
6Ψ Detected Windows 10 (10.0.19044).
7Ψ QMK MSYS version: 1.11.0
8Ψ Userspace enabled: False
9Ψ Git branch: vial
10⚠ The official repository does not seem to be configured as git remote "upstream".
11Ψ All dependencies are installed.
12Ψ Found arm-none-eabi-gcc version 13.3.0
13Ψ Successfully compiled using arm-none-eabi-gcc
14Ψ Successfully tested arm-none-eabi-binutils using arm-none-eabi-size
15Ψ Found avr-gcc version 15.1.0
16Ψ Successfully compiled using avr-gcc
17Ψ Successfully tested avr-binutils using avr-size
18Ψ Found avrdude version 8.0-2025011
19Ψ Found dfu-programmer version 1.1.0
20Ψ Found dfu-util version 0.11
21Would you like to clone the submodules? [Y/n]
出现提示克隆 submodules
输入 y
回车继续,这个过程会比较久。
1Would you like to clone the submodules? [Y/n] y
2Ψ Submodule status:
3Ψ - lib/chibios: 2025-05-15 08:25:11 +0000 -- (8bd61b8043)
4Ψ - lib/chibios-contrib: 2025-01-08 21:03:31 +0100 -- (3ac181e4)
5Ψ - lib/googletest: 2021-06-11 06:37:43 -0700 -- (e2239ee6)
6Ψ - lib/lufa: 2022-08-26 12:09:55 +1000 -- (549b97320)
7Ψ - lib/vusb: 2022-06-13 09:18:17 +1000 -- (819dbc1)
8Ψ - lib/printf: 2022-06-29 23:59:58 +0300 -- (c2e3b4e)
9Ψ - lib/pico-sdk: 2025-04-20 21:24:29 +1000 -- (d0c5cac)
10Ψ - lib/lvgl: 2022-04-11 04:44:53 -0600 -- (e19410f8)
11Ψ QMK is ready to go, but minor problems were found
修改新键盘映射
因为在上面已经创建过QMK的键盘项目了,我们可以把上面的QMK键盘项目的文件复制过来使用。
如果没有,请先按照上面的QMK流程创建一个新键盘项目。
把 C:\Users\Xin\qmk_firmware\keyboards\kinesis_advantage_teensy_pp2
文件夹手动复制到 C:\Users\Xin\vial-qmk\keyboards\
下面。
或者用命令行复制。
1[Xin@DESKTOP-XXXXXXX vial-qmk]$ cp -r /c/Users/Xin/qmk_firmware/keyboards/kinesis_advantage_teensy_pp2 /c/Users/Xin/vial-qmk/keyboards
提示
建议直接使用 VSCode 打开 C:\Users\Xin\vial-qmk\keyboards\kinesis_advantage_teensy_pp2
文件夹
直接复制一份 \kinesis_advantage_teensy_pp2\keymaps\
下面的 default
文件夹,并且重命名为 vial
1├── keymaps
2│ └── default
3│ │ └── keymap.c
4│ └── vial
5│ └── keymap.c
6├── keyboard.json
7└── readme.md
把上面 创建键盘定义JSON 得到的 vial.json
文件复制到 vial
文件下
1├── keymaps
2│ └── default
3│ │ └── keymap.c
4│ └── vial
5│ │── keymap.c
6│ └── vial.json
7├── keyboard.json
8└── readme.md
在 vial
文件夹下,创建一个 rules.mk
文件,里面填写
1VIA_ENABLE = yes
2VIAL_ENABLE = yes
回到 QMK MSYS 下,运行命令 python3 util/vial_generate_keyboard_uid.py
以生成键盘唯一ID
1[Xin@DESKTOP-XXXXXXX vial-qmk]$ python3 util/vial_generate_keyboard_uid.py
2#define VIAL_KEYBOARD_UID {0x53, 0x21, 0xDA, 0xFB, 0x9E, 0x57, 0x5A, 0x9E}
在 vial
文件夹下,创建一个 config.h
文件,里面填写如下内容,其中第3行就是上面获取到的键盘唯一ID
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2
3#pragma once
4
5#define VIAL_KEYBOARD_UID {0x53, 0x21, 0xDA, 0xFB, 0x9E, 0x57, 0x5A, 0x9E}
Vial 建议为了安全起见,需要一个至少2键的组合键用于解锁刷写权限。如果你不想按解锁组合键,可以在 rules.mk
文件里面添加一条 VIAL_INSECURE = yes
这里我还是按官方推荐用上解锁组合键,就把外侧用于切换层的2个"L1"键,定义成解锁组合键吧,矩阵位置分别是 4,1
4,10
所以需要在 config.h
文件中,追加上这最后两行信息:
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2
3#pragma once
4
5#define VIAL_KEYBOARD_UID {0x53, 0x21, 0xDA, 0xFB, 0x9E, 0x57, 0x5A, 0x9E}
6#define VIAL_UNLOCK_COMBO_ROWS {4, 4 }
7#define VIAL_UNLOCK_COMBO_COLS {1, 10}
编译固件
回到 QMK MSYS 中,输入 qmk compile -kb kinesis_advantage_teensy_pp2 -km vial
这个命令把最后的 default
改了对应的 vial
,也就是默认的 default
映射,改成了 vial
映射
1[Xin@DESKTOP-XXXXXXX vial-qmk]$ qmk compile -kb kinesis_advantage_teensy_pp2 -km vial
2Ψ Compiling keymap with make -r -R -f builddefs/build_keyboard.mk -s KEYBOARD=kinesis_advantage_teensy_pp2 KEYMAP=vial KEYBOARD_FILESAFE=k inesis_advantage_teensy_pp2 TARGET=kinesis_advantage_teensy_pp2_vial VERBOSE=false COLOR=true SILENT=false QMK_BIN="qmk"
3
4
5Generating: .build/obj_kinesis_advantage_teensy_pp2_vial/src/info_deps.d [OK]
6Generating: .build/obj_kinesis_advantage_teensy_pp2_vial/src/community_modules.c [OK]
7avr-gcc.exe (GCC) 15.1.0
8Copyright (C) 2025 Free Software Foundation, Inc.
9This is free software; see the source for copying conditions. There is NO
10warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
12Generating: .build/obj_kinesis_advantage_teensy_pp2_vial/src/community_modules.h [OK]
13...
14Compiling: tmk_core/protocol/lufa/usb_util.c [OK]
15Linking: .build/kinesis_advantage_teensy_pp2_vial.elf [OK]
16Creating load file for flashing: .build/kinesis_advantage_teensy_pp2_vial.hex [OK]
17Copying kinesis_advantage_teensy_pp2_vial.hex to qmk_firmware folder [OK]
18Checking file size of kinesis_advantage_teensy_pp2_vial.hex [OK]
19 * The firmware size is fine - 35354/122880 (28%, 87526 bytes free)
编译完成后,在 C:\Users\Xin\vial-qmkf\
下的 .build
文件夹,可以找到格式为 键盘名_vial.hex
的文件,这个就是我们编译完成的vial固件。
可以看到默认出来的Vial固件体积有98KB,所以才建议使用 Vial 闪存要128KB起步,64KB都不够用。
真想塞进小闪存里面,可以看看 Vial 如何减小固件体积 。
刷入固件
找到 QMK Toolbox ,打开运行后
点 Open
选择上面生成的 Vial 固件,点右边的下拉选择对应的 AT90USB1286
,勾选 Auto-Flash
,
按一下开发板上的 Reset
按钮,或者用之前键盘上定义过的快捷键进入 bootloader
模式,随后就会自动刷入固件。
提示
如果你使用的是 PR2040 的话,不需要 QMK Toolbox 就可以刷入固件 PR2040 刷入固件方式
键盘映射修改
刷完固件之后,打开 Vial 软件,可以看到 Vial 直接就识别出来键盘,默认的键位配列就是QMK固件里面定义好的。
在这个界面可以直接修改按键并直接生效,不需要重新刷入固件,对于正在摸索改进自己键盘映射的用户十分方便。
Vial 的使用和功能我这里就不再赘述,请自行搜索了解。
我们可以试一下矩阵测试和定义的解锁键是否正常。
点击 Matrix tester
标签页,点击右下角的 Unlock
,按弹窗提示,长按对应位置的按键即可完成解锁。
完成解锁后,就可以测试整个键盘的按键,Vial 矩阵测试的好处是,切换层这种没有输出键值的按键也可以测试到。
至此,Vial固件就算制作完成了。
杂谈
人体工学键盘大概需要多少个键?
我觉得我们可以推导一下,手指以标准指法放在键盘上,大部分人除拇指外,每根手指能舒适按到大概有3个键吧。
举个例子,右手食指默认放在J
键上,除了J
键还能舒服按到的键还有,手指向前伸展的U
键,手指向后收缩的M
键。
虽然常规键盘里面,标准指法在不移动手的情况下,给拇指按的只有1个空格。
但可以以此类推,拇指在舒适的放松状态的下的位置定为1个键,伸展的情况下定为1个键,收缩的情况下定为1个键,这样我们也得到了拇指对应的3个键。
10根手指,每根手指3个键,(4x3+3)*2 = 30,那是不是30个键就是最理想的数量?
如果当年的机械打字机直接就按人体工学键位来做,如果后面IBM也按人体工学键位和切换层的思路来做键盘标准。
那也许30键真的就是最理想的数量了,手指完全不用大幅度移动。
但是这基本不太可能的,就算没有机械打字机QWERT布局的影响,出于学习成本和制作成本的考虑,还是会增加更多的按键,也不会做切换层的功能。
历史无法改变,在不考虑兼容各种已有的、常见的键盘组合键和用法,在配合切换层的情况下,克服了学习成本和兼容性问题,30键的键盘确可以用。
现在的人体工学键盘,为兼容已有传统的布局以及放下更多的功能,也会在上面30键基础上,食指和小指区域都向外多增加了一例,由4x3变成了6x3。
为了更高的兼容性,上面也可以加1行数字行,那就由6x3变成了6x4,然后空着也是空着,拇指区的3个键的边上也可以也再加几个键。
SofleKeyboard 键盘是 6×4+5 键,列交错的分体式键盘。基于 Lily58 、Corne 和 Helix 键盘。上面这个是 Sofle v2
这就是现在90%的人体工学键盘的核心布局,大部分布局都是在此基础上的微调:列交错的幅度,要不要数字行,拇指区给几个键、怎么放,要不要做成立体的。
在这个思路上,我认为人体工学键盘在考虑到舒适度和兼容性的情况下,(6x4+4)* 2 = 56键 是一个相对合适的基准线。
tjx58 键盘是 6×4+4+1 键,我没有正式发布出来,一开始叫T58,原谅我多年前的拍摄条件。
我第二把DIY键盘 tjx58 也是如此思路,每个手指负责4个键,小指和食指多负责1列,还多加了1个键来给手掌按压。共(6x4+4+1)* 2 = 58键。
不增加额外手指负担、不增加脚踏之类的外设的情况下,这是我觉得比较好的增加输入键的方式了,我觉得这个键当成层切换键(FN)用非常合适。
后记
写这篇的文章的原意是为了防止自己日后忘记,避免重新摸索。
结果这篇文章前后拖了一周多才写完,当我好不容易写完之后,我不禁反问自己:
我真的还有精力和必要去重头开始折腾一个新的键盘布局吗?
当年在折腾这把 Kinesis Contoured 之前,我已经DIY过两把人体工学键盘,都不超过60键。
第一把是分体,第二把是把分体的布局合并在了一起后微调了一下,就是上面的 tjx58。
当时因为是为了验证布局的合理性与测试是否习惯,两把DIY键盘都没有做PCB,直接找淘宝商家切割铝定位板后飞线做的。
后面也一直想着确定好布局之后,再去做PCB板做一个完全体,期间甚至想搞台3D打印机来做布局验证。
结果快十年了,我用得最多的就是 tjx58 和 改造版Kinesis Contoured,我一直没有确定好理想中的完全体,我也一直没有学完过怎么画PCB。
我的 tjx58 实际上和现在常见的 Corne、Sofle 已经非常相似了,比起自己重头做,貌似直接选择他们的套件可能是更好的选择……
妄想一下:我在做 tjx58的时候,Corne、Sofle 应该还没出现,也许当年我应该完善点发出来?搞不好在DIY键盘历史上能留下点我的痕迹……
Sofle 的作者在 2023年搞了一个 Stáňa (AKA Sofle Unsplit)单块的键盘,像是合并起来的Sofle,和我 tjx58几乎只有一个键的差异。
参考资料
教程
QMK新手开发教程 - bilibili.com/video/BV1h34y137YN
工具
QMK Toolbox 工具箱- github.com/qmk/qmk_toolbox
键盘布局编辑器 - keyboard-layout-editor.com
ai03 定位板生成器 - kbplate.ai03.com
打印常见的人体工学键盘到纸上体验布局 - jhelvy.shinyapps.io
QMK 热图生成器 - precondition.github.io
更好看的键盘布局设计规划 - jaroslaw-weber.github.io
USB 设备树查看器 USB Device Tree Viewer
文章
我的第一个键盘 PCB 设计 - freemind.pluskid.org
较完整的记录了一个DIY键盘完整的制作过程
用拇指按 E ? - precondition.github.io
可能对有大量英文输入的人比较有意义
Jonas Hietala T-34 配列改进思路 - jonashietala.se )
键位少的用户可以看一下他的分配思路
基键修饰指南 - precondition.github.io
A guide to home row mods 在字母区二合一修饰键的复用思路
减小 QMK 中的固件大小 – thomasbaart.nl
万一你的开发板真的不够大
配列
DIY 机械键盘以及在哪里可以找到它们 - github.com/help-14/mechanical-keyboard
Yellow After life 的人体工学键盘列表数据库 - yal-tools.github.io
符合人体工程学的分体式键盘⌨的集合 - github.com/diimdeep/awesome-split-keyboards
微处理器
Raspberry Pi 树莓派 RP2040 - pidoc.cn)
原文作者:tjxwork
原文链接:https://www.tjxblog.com/blog/2025-0001
起稿时间:2025-08-28
完稿时间:2025-09-09
发布时间:2025-09-11
原来用的 Hexo + Stellar 主题,太久不用,各种莫名其妙的小Bug,花了两天时间改成 Hugo + Narrow 主题,并修改了部分样式……
评论