Cocoa 文本组合键:macOS 中隐藏的 Emacs 情怀
2023-7-21 18:2:1 Author: sspai.com(查看原文) 阅读量:15 收藏

快,五秒钟内回答:macOS 和 Emacs 有什么共同点?

你可能说,太简单了,两个名字里都有一个 MAC?

没毛病……但考虑到本文的主题不是化妆品,我们还是看看苹果自己的回答

[macOS 的] 文本系统具有一套通用的组合键机制,完全可由用户重新设定,[…] 标准组合键包含大量与 Emacs 兼容的 Control 组合键 […]

如果你是 macOS 的老用户,可能已经知道这是在说什么:在 macOS 上编辑文本时,除了人尽皆知的 Command-C/V/X/A 等等,系统还支持一整套涵盖了光标移动、文本选择、编辑插入等功能的组合键(keybindings),其中很多来源于经典编辑器 Emacs,并且从八九十年代的 macOS 前身 NeXTSTEP 一直延续至今。

45 年前的 Emacs 使用手册,其中很多在 macOS 中可以直接使用

初试身手

那么,这些组合键都能做什么,相比于如今更常用的版本有什么优势呢?下面这张动图可以帮你建立一个初步印象:

不难看出,这些组合键的特点是都以 Control 键为基础,而且虽然涉及很多移动光标操作,但都没有用到任何方向键。因此,掌握熟练之后,可以省去很多移动手腕去摸鼠标和方向键的功夫,减少疲劳并提高编辑效率。


插曲:交换 Control 和 Caps Lock 键

在继续跟随后文上手之前,我非常建议通过系统设置把 Control 和 Caps Lock 键交换位置。需要承认,这肯定不是一个特别大众的设置方法,但据我观察不乏拥趸,而且用过的很少不说好。

为什么建议这么改?如你应该已经发现的那样,Cocoa 文本组合键重度依赖 Control。因此,如果你习惯使用这套组合键,将 Control 键放在 Caps Lock 键的位置,比每次都伸出「兰花指」去键盘左下角的原键位要舒服得多。事实上,这也是早期 IBM 电脑用过的经典布局,后来又被 HHKB 等品牌沿用——甚至苹果的官方支持都将它作为改法示例。

要修改这个设置,首先打开「系统设置」的「键盘」部分,点按右侧的「键盘快捷键」,然后选择左侧列表中的「修饰键」。在弹出的面板中,先确认上方选择的是当前使用的键盘,然后将 Control 键和 Caps Lock 键的操作分别改为对方即可。


乍看起来,使用这些组合键要记一堆字母,有一定学习门槛。但只要掌握了规律,记起来其实是很快的:

首先,大多操作都是「Control-字母键」的组合,其中的字母基本就是操作对应的单词首字母:向后(backward)、向前(forward)、上一行(previous)、下一行(next)、行尾(end)、删除(delete)、交换前后字符(transpose)、插入换行并使光标留在原地(open-line)等。一个例外是移动到行首的 Control-A,据当事人回忆,这只是因为……A 是字母表之首而已。很多历史就是这么任性。

其次,更复杂的组合键主要是在移动操作的基础上演变而来:加上 Shift,就变成了移动光标并选择;加上 Option,就变成了以单词为单位移动(甚至支持基础的中文分词)。如果同时加上 Option 和 Shift?当然就是以单词为单位移动并选择。

一组比较有年代感、可能需要额外解释的操作是 Control-K 和 Control-Y。K 的意思是 kill,功能是从当前光标处删除到段尾,并把删除的内容暂存到一个称为 kill ring 的容器中;Y 的意思是 yank,把之前 kill 的东西「抽」出来,放回当前光标位置。(如果连续按多次 Control-K 后再按 Control-Y,之前吃掉的多行会被合并在一起放出来。)

抛开这对莫名其妙的术语——上世纪七八十年代黑客有些独特的脑回路是可以理解的——可以姑且将其理解成独立于系统剪贴板、只适用于当前窗口的特殊剪切和粘贴。对于长文和代码编辑场景,这种从一行中间往后剪切、同时又不挤占剪贴板的能力是很实用的。

追本溯源

当然,即使你之前完全没有听说过这些组合键,这也不是你的问题。

一方面,它们确实年代久远、讨论不多;另一方面,macOS 也几乎没有给它们提供任何「曝光」的机会:不仅没有在菜单栏中列举,连「系统设置」中的快捷键设置都难觅踪影,唯一比较正式的提及也藏在官方「Mac 键盘快捷键」列表的深处,可能主要只有 Emacs 的真爱粉能通过肌肉记忆偶然发现。

但就算这套组合键再隐晦,既然存在于系统中,它总得有个来头,也总得在什么地方留下些痕迹吧?

答案是肯定的。操作系统的主要任务之一就是为应用程序做好各种「幕后工作」。而这些幕后工作中,很重要的一项就是文本处理,包括字符显示、格式排版、文本编辑等等。

在 macOS 中,负责文本处理的组件称为「Cocoa 文本系统」(Cocoa text system),是 Cocoa(macOS 原生应用 API)的一部分。本文介绍的这套 Emacs 风格组合键,就是由 Cocoa 文本系统负责响应的。

至于系统默认的组合键,上面介绍的只是冰山一角,完整的「目录」位于 /System/Library/Frameworks/AppKit.framework/Resources/StandardKeyBinding.dict。这是一个二进制编码的属性列表(plist)文件,本身不方便阅读。如果你安装了 Xcode,可以直接双击打开查看内容。或者,也可以运行:

plutil -convert json -o - /System/Library/Frameworks/AppKit.framework/Resources/StandardKeyBinding.dict | jq --ascii-output --sort-keys . > StandardKeyBinding.dict

其中,plutil 将原文件转化为 JSON 格式,打印到标准输出;jq(需要安装)转换其中的一些特殊字符为 Unicode 码位,并按键名排序;最后写入当前目录。(想偷懒可以直接看我保存的结果。)

StandardKeyBinding.dict 片段

这里乱七八糟的符号有点多,但仍然有章法。大致的格式是:每个组合键用一个键—值对表示,键名是指定物理按键的字符串,值是一个数组,表示按下该组合键时要调用的一个或一组操作(称为「选择器」[selector])。

其中,表示物理按键的字符主要是:

符号 含义
^ Control
~ Option
$ Shift
@ Command
小写字母 对应字母键本身
大写字母 Shift 加对应字母键
\u 开头的 Unicode 码位序列 对应的 ASCII 控制字符按键苹果的私有保留码位按键

更完整的说明可参见 Jacob Rus 最早写于 2006 年的指南;事实上,Rus 此文基本是网络上所有介绍 Cocoa 文本组合键文章的共同参考资料。

至于按键要对应的操作,则都是驼峰拼写、冒号结尾的方法,命名均来自 AppKit 中负责响应输入的 NSResponder(有个文档,虽然内容少到等于没有);但其实一般用户并不需要关注这些开发上的细节,看单词就足以猜出大部分意思。

照此「翻译」,我们就得知了所有 macOS 中「隐藏」的 Cocoa 文本组合键(排除了一些过于常见、没有实际功能和现代 Mac 上找不到的组合键):

更完整 Cocoa 文本操作整理仍然可参考 Rus 的列表。从中也可以看出,这些操作几乎涵盖了文本编辑的方方面面:除了插入、删除、剪切、大小写转换、翻页、选中等通用文本操作,还包括针对富文本格的字体、样式和版式操作,甚至还有保存和关闭文档、调节窗口位置和大小等针对文本编辑环境的操作;系统内置的组合键只用到其中很小一部分。


插曲:自动重复多次组合键

Vim 用户一定很喜欢它用「数字 + 操作键」重复多次操作的功能,例如 10j 就可以下移光标 10 次,5dw 就可以向前删除 5 个单词等等。

对此,Cocoa 文本系统表示……我也行。但需要做一个设置。打开终端,执行:

defaults write -g NSRepeatCountBinding -string "^r"

然后重新登录让修改生效,就可以启用重复组合键功能,并将 Control-R 设置为引导组合键(也可以自己指定,语法如上文所述)。以后,只要先按下 Control-R,然后按下需要重复的次数,最后按要重复的组合键,就可以连续「开火」了。

在下面的例子中,我们使用 Control-R 引导,分别重复了 5 次 Control-N(向下一行)和 10 次 Control-K(删除到行尾)操作。


改出花样

既然默认组合键是以配置文件的形式储存的,一个自然的想法就是:能不能自定义这些组合键配置呢?

当然可以。正如苹果在文档中所说,用户可以通过在 ~/Library/KeyBindings/ 创建一个名为 DefaultKeyBinding.dict 的 plist 文件,自定义新的组合键(或者覆盖自带组合键)。


文章来源: https://sspai.com/prime/story/cocoa-text-keybindings
如有侵权请联系:admin#unsafe.sh