1 - Capslock 原生版
很多年里,Capslock 是一份配置文件:先安装 Karabiner-Elements,再导入一组规则,Caps Lock 就变成轻按为 Escape、按住为 Hyper 的键;配合 Command、Option、Control 和 Shift,可以用到十六个平面上的快捷键,覆盖光标、编辑、窗口、应用和鼠标。
这套方案能用,但有两个代价。为了改一个键,得先装上 Karabiner-Elements,连同它的驱动和权限; 而布局本身是一份 JSON 文件:改绑定要改文件,学布局要一直开着一张键盘图。
新的 Capslock 是一个原生 macOS 应用。它为同一套布局而生,也为去掉这两个代价而生。
同一套布局,周边什么也不用装
Capslock 内置完整的 Capslock Classic 布局:357 个绑定,从 ⇪ H J K L 方向键到数字行上的五个额外剪贴板。最后一个 Karabiner 版本中的每条规则都有原生对应,一条也没有丢。打开应用、睡眠和剪贴板槽位过去依赖 Shell 命令,现在都是内置动作,因此默认布局完全不运行脚本。
应用只需要一项权限:辅助功能。它不安装内核扩展、驱动、守护进程或特权 Helper。这如何做到, 见 Capslock 如何工作。
用编辑器代替 JSON 文件
「键盘」页画出你的键盘,每个动作都标在对应的键上。点按一个键,就能改绑、停用、恢复
Classic 默认,或查看它的 YAML。映射可以带 App 规则,于是 ⇪ N 在别处删除一个词,在终端里则发送 ⌃W。每次修改都作为一个事务生效;配置仍是普通的 YAML 文件,可以导出、导入,也可以纳入版本管理。
Shell 命令依然可用,但运行前需要你确认;随导入文件而来的命令在你复核之前一律停用。
内置学习
按住 Caps Lock 稍等,屏幕上就会显示当前平面。Playground 里有跟随你自己映射的简短课程; 安全练习模式只预览有副作用的动作而不执行;自由练习显示最近一次按键做了什么,但不记录你输入的内容。
总有退路
一个接管 Caps Lock 的工具,必须能可靠地把它还回来。Capslock 只改动它自己添加的那一条按键映射,在暂停和退出时恢复原状,不碰其他工具的映射;崩溃后由一个小助手负责恢复。如果 Karabiner-Elements 或其他工具已经占用了 Caps Lock,Capslock 不会启动,并由诊断页说明需要改什么。
两种 Hyper
Karabiner 布局让 Caps Lock 在所有应用眼中都像是 ⌃⌥⇧⌘,很多人在此基础上设置了 Alfred、 Raycast 或 Moom 快捷键。Capslock 把这种行为保留为默认的「经典」模式;「原生」模式则让 Hyper 只在 Capslock 内部生效,适合不希望其他应用看到它的人。
现状
Capslock 0.4.0 是候选发布版。完成 Developer ID 签名与公证、干净账户测试、Intel 与 macOS 14 测试,并验证更新通道之后,才会开放下载。在此之前,文档描述的就是即将发布的应用, 发布状态见下载页。
Karabiner-Elements 配置仍以 Karabiner 版的形式免费提供。
2 - Capslock 如何工作:F18、事件钩子,以及只归还自己改动的映射
Caps Lock 占着键盘上最好的位置,干着最没用的活。Capslock 给它换了一份工作:轻按是 Escape,按住是 Hyper,再与四个修饰键组合,得到十六个控制平面。本文解释一个原生应用如何在 macOS 上做到这一点,而不需要内核扩展、驱动或特权 Helper。
Caps Lock 不是修饰键
macOS 并不把 Caps Lock 报告为「按下、抬起」的一对事件,而是报告一个来回翻转的锁定状态,还加了一小段延迟,防止误触切换大小写。这对输入大写字母没问题,对一个需要按住的修饰键却毫无用处。
所以 Capslock 先做一次映射:启用时通过 hidutil 让物理 Caps Lock 发送 F18——
一个苹果键盘上根本不存在的键。F18 以普通的按下、抬起事件到达,应用可以据此判断「按住」和「松开」。
F18 还有第二个好处:它不是系统修饰键。按住 Caps 和 Shift 再按 H,到达的是「F18 按住、 Shift 按住、H」。macOS 不会把 F18 与 Shift 合成别的东西,于是四个修饰键都可以零成本地叠加在 Caps 之上。
用事件钩子读取按键
Capslock 在 HID 层级、队列最前端安装一个主动的 CGEventTap。「主动」意味着它可以修改或丢弃事件,而不只是旁观。macOS 用辅助功能权限管控这一能力;它不需要输入监控权限,
那只适用于只读的监听钩子。
如果启动时还没有授权,应用会持续重试;你一授权,钩子立即安装,无需重启应用。钩子运行在独立线程上,回调里几乎只做整数比较,不会拖慢打字。
解析组合键
F18 按下时,应用记录「Caps 已按住」并吞掉这个事件;F18 抬起时,它判断这次按键是哪一种:
- 轻按:期间没有按其他键,执行轻按动作。默认配置里是 Escape。
- 组合键:Caps 加另一个键,执行该键在当前平面上映射的动作,原始按键不会到达前台应用。
- 双击:如果某个映射定义了双击,就执行双击动作。单击会等过双击窗口,两者不会同时触发。
平面由你与 Caps 一起按住的修饰键决定。每个修饰键是一位:Command 1、Option 2、 Control 4、Shift 8,它们的和对应十六个平面之一,从单独按 Caps 的 0 号到四键全按的 15 号。匹配是精确的:多按了一个修饰键的组合,绝不会退回到更宽泛的平面。因此给导航键加上 Shift 可以表示「选择」,而不会在别处带来意外。
Capslock 合成的每个事件都带有标记,钩子会跳过带标记的事件。否则 Caps+H 发出的方向键会立刻又被钩子截回来。
两种 Hyper
早期的 Capslock 布局通过按住右侧四个修饰键来实现 Hyper。Alfred、Moom 等启动器和窗口管理工具会监听这个组合,很多人的快捷键也建立在它之上。
Capslock 把它做成一个选项,而不是实现细节:
- 经典兼容:Caps 按住期间持续按住右侧 Command、Option、Control 与 Shift,其他应用照旧能看到 Hyper。
- 原生纯净:Hyper 只在 Capslock 内部生效。按住 Caps 时其他应用什么也看不到,只能看到它产生的动作。
两种模式下,平面都由你实际按下的修饰键计算;Capslock 为兼容而按住的右侧修饰键会被排除,否则每个组合键都会落到 15 号平面。
只拥有自己改动的部分
hidutil property --set 会整体替换用户键位映射。最直接的实现是启动时写入自己的列表、退出时清空,这会删掉其他工具或用户自己设置的映射。Capslock 把已有映射当作别人的东西:
- 读取当前映射;如果已有条目重映射了 Caps Lock,就拒绝启动。
- 改动之前,先写一份恢复日志,记录原来的映射和即将添加的那一个条目。
- 只合并自己的条目,并回读结果确认写入成功。
- 暂停或退出时,只移除这一条并恢复原映射——除非期间有别人改过它。
如果运行期间有其他程序修改了映射,Capslock 会停止并报告冲突,而不是去抢最后一次写入。睡眠唤醒、插入键盘、切换用户会话之后,它都会重新核对。这也是为什么「暂停」会还给你一个真正的 Caps Lock,而不是一个被透传的 F18。
应用没有正常退出时
崩溃或强制退出会跳过第 4 步的清理。有两道保障:应用内嵌一个小型看门狗,它读取恢复日志并盯住父进程,如果应用退出时没有释放映射,就恢复原来的映射;下次启动时,应用也会在安装钩子之前先核对遗留的日志。
如果需要手动清除,请使用应用自带的命令,它只移除自己添加的 Caps Lock 条目:
不要用空列表重置映射:那是全局操作,会把其他工具的映射一并删掉。何况这份映射本来就不会在重启后保留。
一切留在本地
以上所有处理都在你的 Mac 上完成。Capslock 不含分析或广告 SDK,不会把按键、映射、剪贴板内容或使用数据发送到任何地方。诊断日志不记录输入的文字、剪贴板内容、Shell 输出和应用历史。存储了什么、何时联网,见隐私说明。