常见的 QWERTY 键盘会将 CapsLock 键放在 Home row 的最左侧,也是最靠近左手小指的地方,如下图所示:
但在日常使用中,CapsLock 的使用频率很低。让这么一个使用频率低的键占据一个很方便按到的位置(最靠近左手小指),实际上是一种浪费。 你可以想想,如果是 Ctrl 或者 Esc 放在 CapsLock 的位置,是不是日常使用就不需要伸手指去“够”它们?只要挪一下小指就行了。 特别是对于 Vim/Neovim/Emacs 等用户来说,更是如虎添翼。
而且我们还可以做到更灵活的映射,即点按(tap)CapsLock 时是 Esc,长按(hold)则是 Ctrl。 这样在使用 Vim/Neovim 的时候会更方便,无论是切换 mode 还是按键序列。
在 Linux 上可以用 xcape1,而在 macOS 上则可以使用 karabiner-elements2 来实现。 在 Windows 上并没有简单易用的方案,只有基于 AutoHotkey 的方案3和这个软件 dual-key-remap。 但是我测试下来都不起作用,所以在 Windows 上一直没用上这种灵活的 CapsLock 映射。
直到最近我发现了一个用 Rust 写的跨平台软件 kanata。 接下来我就简单介绍一下如何使用 kanata 来实现 CapsLock 的灵活映射。
安装
首先需要安装 kanata,其实也没有特别复杂的操作,参考 README 就行。 可以选择下载预编译好的包,也可以通过包管理器进行下载。 我在 Windows 上使用 Scoop 来进行安装,命令如下:
scoop install kanata
kanata 默认不会在后台跑,而且它也没有什么托盘图标,需要在命令行里启动:
kanata --cfg kanata.kbd
如果需要托盘图标的话,可以使用这个库 kanata-tray。
也可以使用 v1.7.0-prerelease-1 版本。 内置了 Windows 下的托盘图标,详见这个 PR。
如果想让它开机自启的话,那么可以通过在 %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup
目录下创建一个 Shortcut 来实现。在 Target 这一栏填入下面这一行命令:
C:\Windows\System32\conhost.exe --headless <path-to-your-kanata.exe> --cfg <path-to-your-kanata.kbd>
配置
kanata 的配置使用的是 LISP 的语法来编写的,可以参考这篇 Guide 和 cfg_samples。 另外 kanata 的作者还提供了一个在线的模拟器来让你测试配置。
和 LISP 不同的地方是,;
不是单行注释符,而是按键 ;,单行注释符是 ;;
。另外块注释则是 #|
和 |#
。
简单来说,kanata 的配置需要有且仅有一个
defsrc
以及至少一个
deflayer
。
前者定义了键盘物理按键的位置,后者则定义了物理按键的映射规则,叫做层(layer)。
层可以有多个,默认会激活第一个 deflayer
所定义的层。
如果想将一个按键映射到另一个按键,则需要使用 defalias
。
defsrc
例如一个 QWERTY 键盘 60 配列的键盘配置如下:
1;; QWERTY 键盘 60 配列
2(defsrc
3 grv 1 2 3 4 5 6 7 8 9 0 - = bspc
4 tab q w e r t y u i o p [ ] \
5 caps a s d f g h j k l ; ' ret
6 lsft z x c v b n m , . / rsft
7 lctl lmet lalt spc ralt rmet rctl
8)
其中 lmet
和 rmet
分别是左 Meta 键和右 Meta 键,也就是 Windows 键。
如果是键盘上没有的按键,在 defsrc
里可以省略。另外如果是键盘自带的特殊键,也可以省略。
比如我使用的的键盘就没有 rmet
,同时多了两个 Fn 和 Pn,我的配置如下:
1(defsrc
2 esc 1 2 3 4 5 6 7 8 9 0 - = bspc
3 tab q w e r t y u i o p [ ] \
4 caps a s d f g h j k l ; ' ret
5 lsft z x c v b n m , . / rsft
6 lctl lmet lalt spc ralt rctl
7)
deflayer
例如在 QWERTY 键盘上定义一个 Dvorak 布局层:
1;; QWERTY 键盘 60 配列
2(defsrc
3 grv 1 2 3 4 5 6 7 8 9 0 - = bspc
4 tab q w e r t y u i o p [ ] \
5 caps a s d f g h j k l ; ' ret
6 lsft z x c v b n m , . / rsft
7 lctl lmet lalt spc ralt rmet rctl
8)
9
10;; Dvorak 布局
11(deflayer dvorak
12 grv 1 2 3 4 5 6 7 8 9 0 [ ] bspc
13 tab ' , . p y f g c r l / = \
14 caps a o e u i d h t n s - ret
15 lsft ; q j k x b m w v z rsft
16 lctl lmet lalt spc ralt rmet rctl
17)
defalias & tap-hold
想要实现按下 CapsLock 是 Esc,长按是 Ctrl
则需要使用 defalias
和 tap-hold
这个动作来实现。
defalias
需要一个
alias 和一个
action,
然后需要在 deflayer
里使用 @alias
来将这个动作映射到某个按键上面。
tap-hold
这个动作接受以下 4 个参数:
- tap timeout (unit: ms)
- hold timeout (unit: ms)
- tap action
- hold action
tap-hold
还有两个变体动作:
tap-hold-press
或tap⬓↓
tap-hold-release
或tap⬓↑
这两个变体动作用于让按键响应更加灵敏而不受 hold timeout 的限制。
我们可以使用 tap-hold-press
来实现,代码如下:
1;; tap for escape, hold for left ctrl
2(defalias cap (tap-hold-press 200 200 esc lctl))
tap-dance
如果真的需要用上 CapsLock 的话,可以使用
tap-dance
来将之映射到另一个按键下,短按两下触发。
比如映射到 Esc 上,代码如下:
1(defalias
2 ;; 1 tap : "Escape"
3 ;; 2 tap : "Caps Lock"
4 eca (tap-dance 200 (esc caps))
5)
kanata.kbd
将以下代码保存为 .kbd
文件,就可以让 kanata 加载这份配置文件,实现更灵活的 CapsLock:
1;; QWERTY 键盘 60 配列
2(defsrc
3 grv 1 2 3 4 5 6 7 8 9 0 - = bspc
4 tab q w e r t y u i o p [ ] \
5 caps a s d f g h j k l ; ' ret
6 lsft z x c v b n m , . / rsft
7 lctl lmet lalt spc ralt rmet rctl
8)
9
10;; QWERTY 布局 + 灵活的 CapsLock
11(deflayer qwerty
12 grv 1 2 3 4 5 6 7 8 9 0 - = bspc
13 tab q w e r t y u i o p [ ] \
14 @cap a s d f g h j k l ; ' ret
15 lsft z x c v b n m , . / rsft
16 lctl lmet lalt spc ralt rmet rctl
17)
18
19;; 按一下 CapsLock 是 Esc,按住则是左 Ctrl 键
20(defalias cap (tap-hold-press 200 200 esc lctl))