上一篇博文用修改 ~/Library/KeyBindings/DefaultKeyBinding.dict
的方法修改按键绑定,但很多地方依然无法响应新的键位设置,体验比较割裂,于是换到 Karabiner。
实现方式的区别
DefaultKeyBinding
在 DefaultKeyBinding.dict
中,用 Ctrl+h 来向左移动,macOS 是通过这样实现的:
"^h" = "moveBackward:";
如果想继续实现 Shift+left(向左移动时选中文本)这个功能,还得需要调用另一个方法:
"^H" = "moveBackwardAndModifySelection:";
苹果原生的方式是直接作用的,比如删除到行首(Ctrl + u)就等于一步操作:直接删除到行首。
Karabiner
Karabiner 要实现删除到行首,它是先通过 Command + Shift + left 来选中光标之前所有的文本,再按下删除键,这样的方式来实现的。
影响可能是有的,比如终端上无法响应,如果自己定义了一个 Ctrl + u,反而还覆盖了其本身正常的功能,不过可以屏蔽掉不需要的 App。
另外无须单独实现带选区的那种,因为 Ctrl+h 已经被映射为左箭头了,自己再加上 Shift 就可以了。
Karabiner 还可以实现更多的功能,比如作者直接写了个全局 Vim 映射,还可以启动 App,设置只限定特定设备、特定 App 等等,功能着实强大,还开源免费。
简单使用
- Simple Modifications,可以简单映射,比如 CapsLock → Control
- Complex Modifications,可以引用别人已经写好了的规则。
- 或者打开
~/.config/karabiner/assets/complex_modifications
增加自己的规则。
- 或者打开
- Devices,选择要应用到的设备,比如内置键盘。
- Profiles,定义多套方案,按需选择。
官方文档:https://karabiner-elements.pqrs.org/docs/
社区分享:https://ke-complex-modifications.pqrs.org/
建议查看官方文档熟悉一点小例子,然后下载别人实现类似的功能的 JSON 代码来参考。
文档最下面有个 External JSON generators,比如用这个 Karabiner Complex Modification 可以自动生成 JSON,不过简单的映射还是直接写 JSON 方便。
我的键位设置
原始的 Emacs-like 键位:
Ctrl + ...
a 移动到行首
e 移动到行尾
b 左
f 右
p 上
n 下
h 往左删除一个
d 往右删除一个
w 往左删除单词
u 往左删除到行首
k 往右删除到行尾
自定义的的键位:
Ctrl + ...
a 移动到行首
e 移动到行尾
h 左
l 右
k 上
j 下
o 插入一行
s 往左删除一个
d 往右删除一个
u 往左删除到行首
i 往右删除到行尾
w 往左删除单词
pnbf 仍然可以使用,没有冲突。
a e 不进行任何改动,我还没有发现有不支持的地方。
w u 的功能虽然和上面一样,但有些地方比如 Typora 就不支持,自己实现一遍确保全局有效。
代码
- (1) CapsLock 短按为 Esc,组合为 Control
- (2) Ctrl + hjkl 移动光标,排除 JetBrains
- 上下左右修改为 hjkl,与原来的 pnbf 不冲突,仍然可以使用;
- 排除 JetBrains,IDEA 自己单独实现普通模式和插入模式不同的行为。
- (3) Ctrl + aeosduiw,排除 JetBrains 和终端
- ae 不改动,wu 重新实现了一遍;
- o 和 Vim 的功能类似,在本行的任何位置直接新建一行并切换过去;
- 增加了 s、i 两个键位在原来的 d、u 旁边,左边的往左删,右边的往右删,很好记忆;
- 排除 JetBrains 和终端。
- (4) Option + [Shift] + hjkl
- 可以用 Option [+ Shift] + Ctrl + h/l,但按键太多,改成直接按 h/l 也生效;
- Option + j/k 用于 VSCode 默认快捷键,上下移动此行;
- Option + Shift + j/k 用于 VSCode 默认快捷键,复制一行;
将代码保存到 ~/.config/karabiner/assets/complex_modifications
。
因为这个 issue#2774 没有解决,还不能全局限定或屏蔽某 App,代码像面条一样,frontmost_application_unless
相关配置每次修改时都需要同时改动多处地方。
{
"title": "Dvel's hjkl",
"rules": [
{
"description": "(1) CapsLock 短按为 Esc,组合为 Control",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "caps_lock",
"modifiers": {
"optional": [
"any"
]
}
},
"to": [
{
"key_code": "left_control",
"lazy": true
}
],
"to_if_alone": [
{
"key_code": "escape"
}
]
}
]
},
{
"description": "(2) Ctrl + hjkl 移动光标,排除 JetBrains",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "h",
"modifiers": {
"mandatory": [
"left_control"
],
"optional": [
"any"
]
}
},
"to": [
{
"key_code": "left_arrow"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "j",
"modifiers": {
"mandatory": [
"left_control"
],
"optional": [
"any"
]
}
},
"to": [
{
"key_code": "down_arrow"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "k",
"modifiers": {
"mandatory": [
"left_control"
],
"optional": [
"any"
]
}
},
"to": [
{
"key_code": "up_arrow"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "l",
"modifiers": {
"mandatory": [
"left_control"
],
"optional": [
"any"
]
}
},
"to": [
{
"key_code": "right_arrow"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains"
]
}
]
}
]
},
{
"description": "(3) Ctrl + aeosduiw,排除 JetBrains 和终端",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "o",
"modifiers": {
"mandatory": [
"left_control"
]
}
},
"to": [
{
"key_code": "right_arrow",
"modifiers": [
"left_command"
]
},
{
"key_code": "return_or_enter"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains",
"Terminal",
"iterm",
"Warp"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "s",
"modifiers": {
"mandatory": [
"left_control"
]
}
},
"to": [
{
"key_code": "delete_or_backspace"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains",
"Terminal",
"iterm",
"Warp"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "d",
"modifiers": {
"mandatory": [
"left_control"
]
}
},
"to": [
{
"key_code": "delete_forward"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains",
"Terminal",
"iterm",
"Warp"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "u",
"modifiers": {
"mandatory": [
"left_control"
]
}
},
"to": [
{
"key_code": "left_arrow",
"modifiers": [
"left_command",
"left_shift"
]
},
{
"key_code": "delete_or_backspace"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains",
"Terminal",
"iterm",
"Warp"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "i",
"modifiers": {
"mandatory": [
"left_control"
]
}
},
"to": [
{
"key_code": "right_arrow",
"modifiers": [
"left_command",
"left_shift"
]
},
{
"key_code": "delete_forward"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains",
"Terminal",
"iterm",
"Warp"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "w",
"modifiers": {
"mandatory": [
"left_control"
]
}
},
"to": [
{
"key_code": "left_arrow",
"modifiers": [
"option",
"shift"
]
},
{
"key_code": "delete_or_backspace"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": [
"jetbrains",
"Terminal",
"iterm",
"Warp"
]
}
]
}
]
},
{
"description": "(4) Option [+ Shift] + hjkl",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "h",
"modifiers": {
"mandatory": [
"option"
],
"optional": [
"shift"
]
}
},
"to": [
{
"key_code": "left_arrow",
"modifiers": [
"option"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "j",
"modifiers": {
"mandatory": [
"option"
],
"optional": [
"shift"
]
}
},
"to": [
{
"key_code": "down_arrow",
"modifiers": [
"option"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "k",
"modifiers": {
"mandatory": [
"option"
],
"optional": [
"shift"
]
}
},
"to": [
{
"key_code": "up_arrow",
"modifiers": [
"option"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "l",
"modifiers": {
"mandatory": [
"option"
],
"optional": [
"shift"
]
}
},
"to": [
{
"key_code": "right_arrow",
"modifiers": [
"option"
]
}
]
}
]
}
]
}