惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
SegmentFault 最新的问题
博客园 - 三生石上(FineUI控件)
WordPress大学
WordPress大学
博客园 - 【当耐特】
月光博客
月光博客
Vercel News
Vercel News
D
Docker
I
InfoQ
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 叶小钗
MongoDB | Blog
MongoDB | Blog
GbyAI
GbyAI
有赞技术团队
有赞技术团队
雷峰网
雷峰网
博客园 - 聂微东
小众软件
小众软件
Y
Y Combinator Blog
腾讯CDC
L
LangChain Blog
The GitHub Blog
The GitHub Blog
宝玉的分享
宝玉的分享
Stack Overflow Blog
Stack Overflow Blog
大猫的无限游戏
大猫的无限游戏
T
The Blog of Author Tim Ferriss

Dvel's Blog

Rime 全拼双拼混输 CHD 油猴脚本:每日签到自动答题 Rime 配置:雾凇拼音 Hammerspoon 自动切换输入法 修复 Hugo 本地图片的累计布局偏移(CLS)问题 macOS 修改 Emacs 键位为 Vim 键位 Surge 配置 汉字的混乱 Netflix 中英双语字幕的好办法 优化 Rime 英文输入体验 判断字符是否为简体字或繁体字 Cloudflare 转入域名提示「出现了问题。请重试转移此域。尚未向您收费。」 图片压缩:Squoosh、TinyPNG、ImageOptim、WebP macOS grep + sed 批量替换多个文件的内容 在 macOS 根目录创建文件夹 博客图床小妙招 折腾 Hugo & PaperMod 主题 利用 Cloudflare Workers 进行批量 301 重定向 将博客部署在 Cloudflare Pages Alfred File Navigation(文件导航器)详解 在 Hugo Goldmark Markdown 中设置以新标签打开链接 日期与时间(UTC、GMT、时间戳、时区) 让 Alfred 以新标签的方式打开 Finder 用 git filter-branch 给 Git 仓库瘦身 qBittorrent 设置教程 联通光猫破解+桥接记录 配置 Mac 终端走代理 Steam for Mac 中文游戏推荐 我的 Mac 软件/工具列表 《Flask Web 开发》笔记
macOS 利用 Karabiner 修改 Emacs 键位为 Vim 键位
Dvel · 2022-11-25 · via Dvel's Blog

上一篇博文用修改 ~/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"
              ]
            }
          ]
        }
      ]
    }
  ]
}