键盘上总有一些按键是我们不常用的,比如说 Caps Lock 。但偏偏它还占据着键盘上非常好的位置,相比之下,更常用的 Esc 的位置却比较难够到。一直以来,注重效率的人,都会把这两个键调换位置。
不仅如此,为了设置一个和任何应用都不冲突的快捷键,大家往往会用 ⌃Control + ⌥Option + ⇧Shift + ⌘Command 的组合,它也被称为 Hyper 键。虽然这个组合看起来很难按,但我们实际上可以用一个键代替这个组合。
要做到上面说的这两点,就需要改键。通过改键,我们不仅能分别做到这两点,我们还可以做到。当我们单次按下 Caps Lock 时,它的功能是 Esc 但是当我们按下 Caps Lock 并且再按其它键,也就是拿 Caps Lock 当作修饰键时,它又可以直接代替 ⌃Control + ⌥Option + ⇧Shift + ⌘Command 的组合,称为 Hyper 键。
这篇文章将教会大家使用改键工具 Karabiner-Elements 做到这两点,并且为大家展示这个工具的其它核心功能。
安装步骤
安装完成后会出现两个应用,Karabiner-Elements(简称「KE」,下同)和 Karabiner-EventViewer(简称「EventViewer」,下同)。KE 是我们使用的主要应用;EventViewer 则是一个辅助应用,除了可以查看改键效果,还可以帮助我们确定按键名称(即下文代码中的 key_code)以及各种参数。
第一次打开 KE 会出现一个弹窗,提示我们系统阻止了 KE 的内核扩展。这是因为 KE 直接作用于底层硬件,所以需要我们手动允许。按照提示,点击「Open System Preferences - Security & Privacy」跳转到设置界面,再点击「允许」即可。
继续回到 KE,这时会出现「键盘设置助理」,这是为了让 KE 识别我们使用的键盘类型,按照提示完成后,我们就可以开始使用 KE 了。
创建一个简单映射
在这部分,我将为大家介绍如何使用 KE 将 Caps Lock 改为 Esc。
在开始介绍之前,为了避免引起歧义,我们来做一些约定:
将我们实际按下的按键称作原始按键;
将我们真正想执行的按键称作目标按键;
将原始按键改为目标按键这一用法,称为一条映射。
我们要将 Caps Lock 改为 Esc,那么称:
想要实现这条映射也很简单,打开 KE,在「Simple Modifications(简单映射)」下,点击左下角「Add item(添加映射)」,然后在「from key(即原始按键)」中选择 Caps Lock,在「to key(即目标按键)」中选择 Esc,我们的第一条映射就创建成功了。
选择好后,我们按一下 Caps Lock,用来指示 Caps Lock 状态的小绿灯不会亮起;再按一下 Esc,这次小绿灯亮了起来,证明我们改键成功。
简单映射里只能进行一些基础改键,并不能发挥出 KE 真正的实力,复杂映射才是 KE 的魅力所在。
创建一个复杂映射
用 Mac 的人慢慢都会培养起快捷键的习惯,很多人刚接触 Mac 就会被 ⌘Command 键吸引。也正因为如此,基本上容易按到的快捷键,都已经被各种软件使用了。
所以人们就在想,怎么样搞一个快捷键组合,能和谁都不冲突?一个终极答案就是拿 ⌃Control + ⌥Option + ⇧Shift + ⌘Command 的组合键作为修饰键,不会和其他任何应用的快捷键冲突。
但我们也发现,同时按下这四个按键实在是太难了,所以我们需要用 KE 来帮助我们,把这 4 个键映射到 1 个键上。相当于我们按下这一个键,就相当于按下了这 4 个键。
导入复杂映射
这个做法和之前的简单映射有所不同,属于复杂映射。所以我们需要切换到「Complex Modifications(复杂映射)」选项卡,这里有两个选项卡,「Rules(映射1 )」和「Parameters(参数)」。我们暂时不看「参数」,先看「映射」。
界面左下角仍有「Add rule(添加映射)」,但点击后只能导入开发者制作好的映射,并不能让我们自由地添加映射。
图中黑色框中「Change caps_lock to command+control+option+shift.」就是我们想要的映射。
因为现在我们要把 Caps Lock 改为 Hyper 键,和刚才把 Caps Lock 改为 Esc 的做法冲突,所以目前需要删除我们刚才在「简单映射」中创建的映射,再点击「Enable(启用)」启用这条映射。
使用 EventViewer 来检查效果
打开 EventViewer 后,我们随便敲几个字母,可以发现 EventViewer 会记录我们的每一次按键。比如我们依次按下 Q、W、E 键,结果如图。
然后我们按下 Caps Lock,结果如图。这就代表我们改键成功了。
创建一个进阶的复杂映射
现在,我们要把两者融合,做到:
要做到这点,就要进行更高的自定义,所以还是要先删除刚才的配置,把我们在「复杂映射」里启用的映射给删除。
修改 KE 配置文件
我们先来看一下创建自定义复杂映射的全过程,其中的代码解释我们在下一节中展开。
因为 KE 界面没有提供给我们自己创建映射的办法,所以我们通过修改 KE 配置文件实现我们的目标。
KE 配置文件是 karabiner.json,默认路径是 ~/.config/karabiner/karabiner.json。复制好路径后,打开「访达」,在顶部状态栏点击「前往 - 前往文件夹」,粘贴路径前往后就找到了 KE 配置文件。
为避免直接修改原文件,我们将其拷贝到「下载」文件夹中,然后使用「文本编辑器」打开。虽然看起来很复杂,但其实我们需要关注的只是红色方框部分。
只需复制下文中提供的代码,粘贴到红色方框中方括号 [] 里,我们就完成了 KE 配置文件的修改。这里是修改后的配置文件 karabiner.json,大家可以参考,也可以拿来直接使用。 {
"description": "Change Caps Lock to Hyper",
"manipulators": [
{
"from": {
"key_code": "caps_lock",
"modifiers": {
"optional": [
"any"
]
}
},
"to_if_alone": [
{
"key_code": "escape"
}
],
"to_if_held_down": [
{
"key_code": "left_shift",
"modifiers": [
"left_command",
"left_control",
"left_option"
]
}
],
"type": "basic"
}
]
}复制修改后的 karabiner.json,前往 ~/.config/karabiner/karabiner.json,替换原文件,至此,我们成功创建了自己的复杂映射。再次打开 KE,可以发现「映射」里多出了「Change Caps Lock to Hyper」映射,我们将其简称为映射 1。
成功创建了 Caps Lock 到 Hyper 的映射
打开 EventViewer 后,首先短按 Caps Lock 键,最后长按 Caps Lock 键,结果如图。
通过「参数」优化体验
如果经过 EventViewer 的测试后,发现想要实现组合键时,需要长按很长时间,那么我们可以通过调整参数来优化体验。
切换到「复杂映射」下的「参数」选项卡,这里有四条参数,我们只需关注前两条参数。因为我们将按下 Caps Lock 键分为了短按和长按,所以我们需要告诉 KE 多长时间内是短按,超过多长时间是长按,这两条参数就是控制这些时间的。
这些参数默认单位都是毫秒,设置时只要保证短按时间小于等于长按时间即可。我习惯全部设置为 200 毫秒,大家可以利用 EventViewer 多做尝试,找到适合自己的阈值。
代码解释
在配置文件中,像 parameters 和 rules 这些字符两边必须添加 "",下文中为了写作方便不再添加。现在,我们来看一下,添加在配置文件中的代码究竟是什么。
complex_modifications 代码
再来看一下这张图片,在之前的基础上,我又添加了黄色方框和蓝色方框。
蓝色方框标记的地方,即 "complex_modifications": {} 部分,正如名称所言,复杂映射中的所有内容,全部包含在这段代码中。
对照图片可以看出,"complex_modifications": {} 中代码分为两部分:
显然,这和 KE 界面中,「复杂映射」下的「参数」和「映射」对应了起来。
既然黄色方框中 "parameters": {} 代码可以直接在「参数」选项卡里修改,那么我们只需关注红色方框中负责「映射」代码的 "rules": [] 即可。
我们添加的所有映射,正是包含在 "rules": [] 中。
rules 代码
现在我们来看实际添加的代码。
对照图片蓝色方框部分,我们可以看出,在 rules: [] 中包含一段代码,对应我们添加的映射 1。
对照图片黄色方框部分,我们可以看出,映射 1 也有两部分,分别是:
其中,description 中的内容会显示在「映射」选项卡下,帮助我们确定每一条映射是什么,可以简单的理解为,为我们的映射取个名字。我们的重点内容则是在 manipulators 下。
manipulators 代码
对照图片红色方框部分,我们可以看出,在每段 manipulators 下有三个部分,分别是:
from:输入部分,用来告诉 KE 监测哪些按键被按下,即我们的原始按键。
to…:2 输出部分,用来告诉 KE 执行哪些按键,即我们的目标按键。
type:映射类型,所有映射类型均为 basic。
我们使用到的 to… 代码有两种类型,分别是:
知道这些后,如何写代码告诉 KE 我们想要的效果,会有一个大致的思路。比如我们的映射 1,大致思路就是:
利用 from 中代码告诉 KE 监测是否按下原始按键 Caps Lock;
利用 to_if_alone 中代码告诉 KE 短按原始按键时输出目标按键 Esc;
利用 to_if_helf_down 中代码告诉 KE 长按原始按键时输出目标按键组合键。
很简单对不对?剩下的问题就是如何让 KE 明白,我们的原始按键和目标按键是什么。这就是 key_code 和 modifiers 的作用。
key_code 代码
key_code 是按键名称,用来告诉 KE 要监测和执行的按键是什么。key_code 可以在 EventViewer 中查看。比如按下左侧 ⇧Shift,EventViewer 中 name 一栏显示的 left_shift 就是左侧 ⇧Shift 的 key_code。
仍以映射 1 为例,确定了原始按键和目标按键以后,只需在 from 和 to… 中分别加入 key_code 即可。
这时我们会发现一个问题,长按 Caps Lock 想要实现的组合键,该如何表示呢?这就需要 modifiers 了。
modifiers 代码
modifiers 是修饰键,用来配合 key_code。如果只有 key_code 可用,那么 KE 只能监测或者输出一个按键,不能实现更多效果,就像我们的映射 1,但是配合上 modifiers 就不同了,我们一起来看。
from 中的修饰键
在 from 代码中,共有三种修饰键情况:
没有 modifiers :只有单独按下 key_code 才触发代码;
mandatory 选项:只有该修饰键和 key_code 按下才触发代码;
option 选项:该修饰键是可选的,有没有按下它不影响代码匹配情况。
比如我们只想监测 ⌥Option + Q 的组合键,Q 单独按下时不做反应。这种情况下 ⌥Option 是必须的,所以在 from 中的代码就应该是:
"key_code": "q",
"modifiers": {
"mandatory": ["option"]
}另外,因为 q 有大小写之分(即打开 Caps Lock 时),我们想不论大小写都监测成功,那么我们还需添加上 optional: caps_lock 的选项:
"key_code": "q",
"modifiers": {
"mandatory": ["option"],
"optional": ["caps_lock"]
}
除了一般的按键名称外,optional 还有一个特殊值 any,optional: [any] 表示任何修饰键都是可选的。我们的映射 1 就添加了 optional: [any] 代码,用来扩大使用范围。
to… 中的修饰键
在 to… 代码中,modifiers 则很简单了,直接添加就可以。
这里有一个小细节,如果我们想要 ⌘Command 作为修饰键,在 modifiers 中,我们不可以直接写 command,而是要随便指定为左侧或右侧 ⌘Command 的 key_code。
比如映射 1 想要实现的组合键,就可以这样写。
"key_code": "left_shift",
"modifiers": [
"left_command",
"left_control",
"left_option"
]复习代码
我们已经将使用到的所有代码学完了,现在我们总的来看一下映射 1 输入输出部分的代码,检查我们是否看得懂它在说什么。
"from": {
"key_code": "caps_lock",
"modifiers": {
"optional": [
"any"
]
}
},
"to_if_alone": [
{
"key_code": "escape"
}
],
"to_if_held_down": [
{
"key_code": "left_shift",
"modifiers": [
"left_command",
"left_control",
"left_option"
]
}
],
由输入部分看出,这条映射监测的是 Caps Lock 键,修饰键可以任意。
由输出部分看出,KE 分别监测 Caps Lock 的短按和长按行为。短按的话,执行 Esc 按键操作;长按的话,在左侧 ⌘Command、⌃Control、⌥Option 的修饰下,执行左侧 ⇧Shift 按键操作,即组合键。
映射的优先级
现在我们已经将 Caps Lock 改为 Hyper 键了,不过考虑到我们偶尔需要用到 Caps Lock,所以将 Esc 改为 Caps Lock。
这是一个简单映射,我们直接在「简单映射」里添加好后,打开 EventViewer 检验一下。当我们按下 Esc 时,出现的结果并不是我们期待的 Caps Lock,而是 Esc;当我们长按 Esc 时,发现却是组合键的效果。
这是因为 KE 并不会判断我们的目标按键究竟是什么,只会先运行「简单映射」,再运行「复杂映射」。所以当我们按下 Esc 时,「简单映射」首先起作用,将 Esc 改为 Caps Lock。但是 KE 并不是直接执行 Caps Lock 动作,而是将其继续发送到「复杂映射」中,这就相当于我们直接按下的是 Caps Lock,所以出现上图这种情况。
所以为避免带来不必要的麻烦,当「简单映射」和「复杂映射」中的按键存在某种联系时,不要在「简单映射」中添加映射,而是添加在「复杂映射」里。这同样很简单,只不过这次输出部分使用新的 to 4 代码而已。
下面给出将 Esc 改为 Caps Lock 的映射完整代码,简称为映射 2,相信大家都可以看明白。
{
"description": "Change Esc to Caps Lock",
"manipulators": [
{
"from": {
"key_code": "escape",
"modifiers": {
"optional": [
"any"
]
}
},
"to": [
{
"key_code": "caps_lock"
}
],
"type": "basic"
}
]
}进阶代码
看到这里,大家应该发现,「复杂映射」里并没有「目标设备」这一选项,如果我们想要针对某个设备来改键的话该怎么办呢?KE 仍然可以做到。
为复杂映射添加目标设备
我们以映射 2 为例,只想让它作用在我的外置键盘上。这相当于为映射 2 添加了一个条件,只有在条件满足的时候才起作用。
在 KE 代码中,条件是用 conditions 控制的。常用的 conditions 类型有 device(设备)、variable(变量) 等,这里我们使用设备变量。
device 条件结构包括两部分:
可以发现,我们只需要找到外置键盘的识别条件,然后填写在 identifiers 里,条件代码部分就完成了。
而我们想要的识别条件同样方便查找。连接好我们的外置键盘后,打开 KE 的「Devices(设备)」选项卡,KE 已经成功识别我们的设备。
在红色标记中找到外置键盘的 Vendor ID,图中为 3727,该数值,这就是我们要找的条件。一般情况下,我们只需要 Vendor ID 或者 Product ID 中的一个即可。
至于图中蓝色标记,如果勾中选项,那么设备连接到 Mac 后,Mac 内置键盘将不再起作用,只有靠外置键盘输入;将设备断开或者取消勾选后,Mac 键盘恢复。
我们已经找到了 identifiers 的内容,现在根据 device 的结构将整个代码写出。Vendor ID 的值不需要加 ""。
"conditions": [
{
"type": "device_if",
"identifiers": [
{
"vendor_id": 3727
}
]
}
]
写好后,将这段代码添加在映射 2 输出部分的最后,另外,因为 JSON 的数据结构,需要在上一行结尾加一个英文逗号 ,。这样,我们就为映射 2 添加了一个条件,使其只作用在外置键盘上。
实现双击按键
看过了 device 条件,我们再来看 variable 条件。我们以映射 3:双击右侧 ⇧Shift 改为 Mission Control 7 为例。
variable 条件的结构有三部分:
除此之外,我们还要学习一个新的输出动作,to_delayed_action(延迟动作),它在原始按键按下 500 毫米8 后开始执行,包括两种情况:
我们对照映射 3 中,manipulators 的完整代码来学习,共分为两段代码。
当第一次按右侧 ⇧Shift 时,红色方框中代码,不满足变量 right_shift pressed 值为 1,所以不执行该段代码,转而开始进行蓝色方框中代码测试;满足蓝色方框,设定变量 right_shift pressed 值为 1,并输出一次右侧 ⇧Shift。
此时,有两种情况,我们分别来看。
立刻再次按下右侧 ⇧Shift 时
若 500 毫秒内再次按下右侧 ⇧Shift,变量 right_shift pressed 值仍为 1,所以红色框中代码执行,输出 misson_control 键。500 毫秒后,to_if_invoked 动作执行,将变量 right_shift pressed 值清零。
不按或者按下其他键时
若 500 毫秒内按下其他按键,或者超过 500 毫秒后,to_if_canceled 动作执行,变量 right_shift pressed 值为 0,即使再次按下右侧 ⇧Shift,也只是再次执行蓝色方框中代码。
KE 的应用界面
KE 的应用界面一共有 7 个选项卡。常用的除了「简单映射」和「复杂映射」,还有「Profiles(配置)」和「Misc(杂项)」。
在「配置」里,我们可以创建多个配置,在每个配置里改键互不干扰。
比如创建游戏、办公两个配置。游戏配置里 Caps Lock 改为技能释放键9 ,办公配置中则将 Caps Lock 改为 Esc。使用时可以通过状态栏快速切换到相应配置。
在「杂项」中,只需注意「System Default Configuration」。默认情况下,Karabiner-Elements 修改的键位只会作用在当前用户下,更改用户后仍然是系统默认键位。
点击「Copy the current configuration to the system default configuration」后,Karabiner-Elements 将作用在该电脑所有用户上。
结语
说起 Mac 上改键,有一个开发者是绕不开的,他就是 @tekezo。 从最早开发的 KeyRemap4MacBook,到更名后的 Karabiner,每个都是精且专的改键利器。macOS Sierra 更新后,因为系统底层的变动使得 Karabiner 无法继续在新系统下工作,作者转而开始 Karabiner-Elements 的开发。
改键的需求并不会随着系统更新而减弱。在等待 Karabiner-Elements 开发的过程中,不少人开始寻找替代方案,不论是使用 Hammerspoon 还是 Keyboard Maestro 都比 Karabiner 少了点简洁。如今,不断开发的 Karabiner-Elements 已经足够强大,足以满足我们日常的改键需求,改键再次只需这一个软件。
虽然 Karabiner-Elements 只能通过配置文件来增添复杂映射,但实际代码并不复杂,需要我们掌握的只是 from 和 to… 部分。与其能带给我们的便利相比,花费一点点时间去掌握其写法是非常值得的。
最后在这里做一个简单总结,当我们想要创建一个复杂映射时:
确定输入部分原始按键,修饰键;
确定监控原始按键的哪些行为;
根据行为确定输出部分共有几段;
在每段行为里,写入目标按键。
完成这四步后,只需粘贴在配置文件中,Karabiner-Elements 便会立即按照我们的想法开始工作了。