在 macOS 上用 Karabiner-Elements 和 Herdr 做一套顺手的终端导航键位
Contents
本文记录一套已经在当前机器落地的键盘方案:用
Caps+T进入 Herdr 前缀模式,Ctrl+1..9切换当前 Space 内的 Tab,Alt+1..9切换 Space,Caps+Alt+A在 Agent 之间轮询。重点不只是最终配置,还包括中间踩过的坑,以及为什么最后要让 Karabiner 和 Herdr 各做一半工作。
环境快照
这套配置整理于 2026 年 8 月,当前机器上的主要版本如下:
| 组件 | 当前状态 |
|---|---|
| 操作系统 | macOS |
| Herdr | 0.8.2 |
| Goku | 0.5.7 |
| 终端 | Ghostty、iTerm2 |
| Ghostty Bundle ID | com.mitchellh.ghostty |
| iTerm2 Bundle ID | com.googlecode.iterm2 |
| Herdr Session | default,持久运行 |
| 已安装 Herdr 插件 | herdr-sidebar 0.8.1 |
本文只摘录与 Herdr 有关的 Karabiner 规则。原文件中还有应用启动、文本编辑、窗口控制和其他自动化,其中可能包含私人信息,不适合直接放进公开博客。
想解决什么问题
Herdr 的默认前缀是 Ctrl+B。它和 tmux 很像,但在 Agent、Shell、编辑器之间频繁移动时,我更想要一个不占用常用控制键、又容易按到的入口。
实际目标有四个:
- 用
Caps+T代替Ctrl+B,但保留 Caps 单击为Esc的习惯。 - 用
Ctrl+1..9直接切换当前 Space 内的 Tab。 - 用
Alt+1..9直接切换 Space。 - 用
Caps+Alt+A聚焦下一个 Agent,重复按就继续轮询。
看起来只是几条快捷键,真正麻烦的是它们要经过三层系统。
| |
Karabiner 看得到前台应用,却看不到终端内部究竟运行的是 Herdr、普通 Shell 还是 Neovim。Herdr 正好相反:它很清楚自己的 Space、Tab、Pane 和 Agent,但拿不到 macOS 在输入法层已经转换掉的原始 Option 组合。最终方案必须顺着这条事件链设计。
先把 Herdr 的对象关系理清
Herdr 界面里的 Space,在 CLI 和配置文档里叫 Workspace。它们的层级是:
| |
因此,Ctrl+数字 和 Alt+数字 虽然看起来相似,作用域并不一样:
Ctrl+1..9只在当前 Space 内选择 Tab。Alt+1..9选择整个 Session 中的 Space。- Agent 轮询可能跨越 Space、Tab 和 Pane。
为什么选择 F13 作为前缀
我没有直接把 Herdr 前缀设成一串 Hyper 修饰键,而是让 Karabiner 把 Caps+T 翻译为 F13:
| |
Herdr 再把 F13 解释为 prefix:
| |
这样做有几个实际好处:
F13在当前 Karabiner 配置中没有其他用途。- 它不抢占 Shell 的
Ctrl+A、Ctrl+E、Ctrl+W等编辑键。 - Ghostty 和 iTerm2 都能把功能键事件交给 Herdr。
- Caps 仍然保留原来的双重角色:单击是
Esc,按住进入 Hyper layer。
最终操作是先按住 Caps,点一下 T,松开后再按 Herdr 动作键。这个动作比五个修饰键同时按下稳定得多。
第一个坑:Alt+数字变成了特殊字符
最初我在 Herdr 里直接写:
| |
结果按下 Alt+1..9 后,终端里出现了:
| |
这不是 Herdr 的解析错误。macOS 把 Option 当作字符输入修饰键,按键还没到 Herdr,就已经被 US 键盘布局转换成特殊字符。
修复方法不是继续调整 Herdr,而是在 Karabiner 这一层拦截按键。只有当前应用是 Ghostty 或 iTerm2 时,Alt+数字 才会被转换为两个连续事件:
| |
Herdr 收到后,等价于“进入 prefix 模式,然后选择编号对应的 Space”。
第二个坑:为了兼容键位交换,误伤了 Command
第一版还为 quickfire 设备补了 Command+1..9 规则。当时的想法是:这些键盘在已有配置中交换了 Command 和 Option,所以同时接收逻辑 Command,可以兼容物理 Alt。
问题是 Karabiner 的 from 条件匹配原始修饰键事件。这 18 条补偿规则不是在识别“交换后的 Alt”,而是在明确劫持左右 Command:
| |
结果就是 Command+1..9 和 Alt+1..9 都会切换 Space。修正时删除所有 Herdr 规则中的 C/Q 补偿,数字和 Agent 轮询都只监听 O/E。设备原有的 Command/Option 交换规则不在本次修改范围内,这样其他应用中的既有键位习惯不会一起变化。
第三个坑:Caps+Alt+A 没有反应
第一版 Agent 快捷键把 Caps+Alt+A 映射成 F14,再让 Herdr 直接监听 F14。配置能生成,Herdr 也能重载,但实际按键没有形成可靠的完整链路。
最后没有继续堆补丁,而是复用已经验证过的 F13 前缀:
| |
这少了一种新的功能键语义,调试也简单很多。使用时最好先按住 Caps,再按 Alt+A,让 Hyper layer 先进入激活状态。
Karabiner 配置
当前配置使用 Goku 的 EDN 格式,源文件位于:
| |
当前机器把几把外接键盘归入 quickfire 设备组,并在其他规则中交换了 Command 与 Option:
| |
如果复制到另一台机器,应从 Karabiner-EventViewer 读取自己的 vendor_id 和 product_id,不要照搬这些数字。
终端应用条件
先声明 Ghostty、iTerm2 和一个组合条件:
| |
这里故意使用准确的 Bundle ID,而不是按应用名称猜测。可以用下面的命令重新确认:
| |
Caps Hyper layer 与 F13
当前机器的 Caps 单击为 Esc,按住后进入 Hyper layer:
| |
与 Herdr 相关的 Hyper 规则如下:
| |
Goku 配置顶部对修饰键缩写的约定是:
| 缩写 | 含义 |
|---|---|
O | Left Option |
E | Right Option |
C | Left Command |
Q | Right Command |
! | 该修饰键必须存在 |
Alt+1..9 到 Space 的映射
下面是当前机器实际使用的规则,共 18 条,只覆盖左右 Option。这里有意不监听 C 和 Q,确保左右 Command 继续交给终端或当前应用处理。
| |
Herdr 配置
Herdr 配置位于:
| |
当前文件很短,完整内容如下:
| |
这几行和 Karabiner 规则正好拼起来:
Caps+T产生F13,进入 Herdr prefix 模式。Ctrl+数字被 Herdr 直接截获,用于切换 Tab。Alt+数字先被 Karabiner 改写成F13,数字,再触发switch_workspace。Caps+Alt+A被改写成F13,A,再触发next_agent。- Agent 面板按 Space 分组,轮询时更容易预判下一个目标。
如何生成、加载和验证
修改 karabiner.edn 后,先让 Goku 生成 Karabiner-Elements 配置:
| |
成功时输出:
| |
然后重新加载 Herdr:
| |
当前机器的成功返回是:
| |
仅看“命令成功”还不够。最好继续验证 Goku 生成后的 JSON,而不是只检查 EDN 源文件:
| |
还要单独确认这组规则没有监听 Command。下面的检查应返回 true:
| |
查看 Herdr 是否真的识别到了 Agent:
| |
查看当前 Space:
| |
最后的成品
最终的按键表很简单:
| 动作 | 实际按键 | 生效范围 | 内部事件 |
|---|---|---|---|
| Herdr prefix | Caps+T | 全局 Karabiner;Herdr 内消费 | F13 |
| 切换当前 Space 的 Tab | Ctrl+1..9 | Herdr | ctrl+1..9 |
| 切换 Space | Alt+1..9 | Ghostty、iTerm2 | F13,1..9 |
| 聚焦下一个 Agent | Caps+Alt+A | Ghostty、iTerm2 | F13,A |
| Caps 单击 | Caps | 全局 | Esc |
Command+1..9 不参与 Herdr 映射,继续保留终端和应用原有行为。
这套设计最重要的不是某一个键,而是分工:Karabiner 只负责修正 macOS 和硬件键盘带来的输入差异,Herdr 只负责理解 Space、Tab 和 Agent。两边通过一个冷门但稳定的 F13 事件连接起来。
边界和已知限制
Karabiner 不能识别终端内部的 Herdr
应用条件只能判断前台窗口属于 Ghostty 或 iTerm2。它无法读取终端子进程的 HERDR_ENV=1,所以在这两个终端的普通 Shell 中按 Alt+数字,同样会发送 F13,数字。
如果这个副作用不可接受,就只能把 Space 切换恢复成显式的 Herdr prefix 操作,或者为不同终端 Profile 使用独立 Karabiner 变量。仅靠 frontmost_application_if 做不到“只在 Herdr 进程内生效”。
Caps+Alt+A 对按键顺序更敏感
这条规则依赖 Caps 的 hyper-mode 先被激活。实际操作时,先按住 Caps,再按 Alt+A,比三个键完全同时落下更稳定。
不要直接公开完整 Karabiner 配置
个人 Karabiner 文件常常混有应用路径、设备 ID、文本宏、自动输入内容和工作流名称。写博客时只摘录与主题相关的规则,并检查代码块中是否混入账号、手机号、Token 或固定文本。
还能继续怎么扩展
Herdr 本身已有 goto 会话导航器,默认动作是 prefix+g。它可以搜索 Workspace、Tab、Pane,并用键盘定位。如果想要更接近 Vim 的全局 Jump,可以考虑以下插件:
Herdr Navigator
Herdr Navigator 可以从同一个模糊搜索界面跳到 Workspace、Agent、Project、Session、Remote、目录或 Action,并支持 vim_mode = true。
| |
建议绑定:
| |
Herdr 与 Neovim split 互通
herdr-splits.nvim 和 vim-herdr-navigation 都能让 Ctrl+h/j/k/l 在 Neovim split 与 Herdr pane 之间移动。前者还支持 resize、边缘 wrap 和 auto-unzoom。
从 Agent 输出跳到文件
termscope 会扫描当前 Pane 的可见文本,把其中真实存在的文件、行号和链接做成选择器。Agent 刚输出 src/main.ts:42 时,不需要复制路径,可以直接跳进 Neovim 对应位置。
Neovim 窗口内的标签跳转
如果需求只发生在 Neovim 内部,flash.nvim 更合适。它支持搜索标签、多窗口跳转和 Treesitter 节点选择,但它不会跨越 Herdr Pane。
参考资料
Author Allen
LastMod 2026-08-26