← 返回博客

macOS 键盘快捷键本地化

2024 年 11 月 8 日

在 Zed 0.162 中,我们对键盘快捷键进行了一些更改,使其适用于每个人,无论他们使用何种键盘布局。

A hypothetical keyboard, credit Google Gemini
一个假想的键盘,图片来源 Google Gemini

问题

您能轻松输入的字符取决于您的键盘布局。Zed 的默认绑定是基于您可以仅使用 Shift 修饰键轻松输入 U+0033 (!) 到 U+007A (~) 之间的所有字符(ASCII 图形范围)的假设。

事实证明,这对于三类人来说是不正确的

  1. 您使用的西里尔(或其他非拉丁字母)键盘默认不提供 a-z 或 A-Z。
  2. 您使用的日语(或其他基于 IME 的)键盘默认不输入任何内容
  3. 您使用的非美式拉丁字母键盘(如法语、德语等)不提供某些 ASCII 标点符号,因为这些键需要用于 ü 或 ß 等字母。

还有一个额外的(完全是自作自受的)问题,就是我们将一些键盘快捷键绑定到 option-X(其中 X 是任意 ASCII 字符)。这对于很少使用 option 修饰键生成的字符的美国英语使用者来说通常没问题,但阻止了一些键盘上的用户输入 {@ 等基本字符。

解决方案

最后一个问题最容易解决。我们不再将快捷键绑定到 option-X(其中 X 是一个字母)。相反,字母快捷键需要 Command 或 Control 键。(请在此处查看更改列表)。

除此之外,我们希望 Zed 对熟悉 macOS 的人来说感觉自然。因此,我们进行了一些更改,使其更密切地模仿操作系统级别的默认工作方式。

对于基于 IME 的输入源,我们现在在调用 IME 系统之前触发快捷键。因此,如果启用了日语输入模式并输入 cmd-a,它将选择全部。如果 IME 系统当前处于活动状态,那么它将首先处理键盘输入。这意味着您可以在 Vim 普通模式下使用 a 进行插入;但如果您正在输入基于 あ 的内容,那么我们将不会干扰。

对于非拉丁键盘,macOS 提供了一个拉丁语布局,当按住 Command 键时激活。此布局通常只是 QWERTY,因此您可以在亚美尼亚键盘上输入 cmd-ա,Zed 将接收 cmd-a。然而,我们更进一步,即使没有按住 Command 键,也使用此布局进行快捷键操作。这确保了绑定到 ctrl-a(或在 Vim 模式下,甚至只是 a)的快捷键仍然有效。

对于非美式拉丁键盘,解决方案更为棘手。虽然您可以在这些键盘上输入完整的 ASCII 范围,但您可能需要按住 Option 键才能访问某些字符。不幸的是,Option 键在快捷键中具有特殊含义:如果您需要按住 Option 键才能输入 [,我们无法判断您是想触发 cmd-[ 还是 cmd-option-[

等效键

自 macOS Catalina 以来,Apple 通过自动快捷键本地化提供了这个问题的解决方案。在底层,这会将一些快捷键重新分配给无需 Option 键即可输入的等效键。尽管如果您使用 SwiftUI 的内置菜单组件,这会自动发生,但 Zed 需要对我们使用的快捷键进行更严格的控制。

等效键的分配方式似乎是围绕几个限制设计的

  • 如果可以输入快捷键,则不应更改。因此,在 QWERTZ 键盘上,cmd-+ 仍然是 cmd-+,尽管 + 键在键盘上的位置不同。
  • 如果快捷键成对出现,它们会保持成对。因此,在 QWERTZ 键盘上,cmd-[cmd-] 变为 cmd-öcmd-ä
  • 否则,如果可能,快捷键会保留在与 QWERTY 相同的键上。例如,cmd-<cmd->,由于它们是系统窗口切换快捷键而无法使用,因此在 QWERTZ 键盘上会移动到 cmd-;cmd-:

不幸的是,Apple 似乎没有发布等效键表,也不清楚如何以编程方式提取它们。因此,我们编写了一个小型 Swift 应用程序来查找此类键盘布局,渲染一个包含所有快捷键的 SwiftUI 菜单,并检查菜单以查看快捷键已映射到哪些键。由此产生的规则可在此处找到

死键

最后一个障碍是处理死键。例如,在 AZERTY 键盘上,^ 是一个死键——它不会直接产生字符,而是将 IME 置于一种模式,在该模式下,下一个字符会不同。例如,输入 ^ a 可能会输入 â。为了允许在这些键盘上绑定到 cmd-^,我们使用与 Chrome 相同的方法,并使用两次调用 UCKeyTranslate——等同于输入 ^ space 以获取键的有效字符。

死键还会导致另一个问题,即与 Vim 的键盘处理存在轻微的不兼容性。Vim 不查看输入的键,只查看生成的字符。这意味着要在 Vim 中删除引号内的内容(在 QWERTY 键盘上通常是 d i "),在巴西键盘上,您需要输入 d i " space。“ 将您置于死键模式,空格生成 "。我们以前会模拟这个,但使用新代码,在巴西键盘上输入 d i " 会在按下空格之前触发快捷键。

尽管一些用户抱怨 Vim 版本令人困惑,但我认为我们可能会(在未来的版本中)恢复更像 Vim 的行为。这部分是因为 Vim 模式的主要前提是避免重新学习如何打字,部分是因为它引入了一个恼人的不一致性。如果你要删除到下一个引号,你仍然需要输入 d t " space,因为 t 的参数是任何输入的字符(而 i 的参数是快捷键...)。

后续步骤

以上所有内容仅适用于 macOS。我们正在计划对 Linux(和 Windows)进行类似的更改,但细节可能略有不同,以保持应用程序的平台原生感觉。在 Linux 上,我们在处理非拉丁键盘方面存在一些需要解决的错误;并且我们有很多关于与各种 IME 子系统交互的知识需要学习。在 Windows 上,我们可能会使用虚拟键码,并且不会对扩展拉丁布局进行重新分配。

正如俗话所说:欢迎提交 PR!如果您认为应该工作但目前没有工作的问题,请务必提交错误报告。


正在寻找更好的编辑器吗?

您今天就可以在 macOS、Windows 或 Linux 上试用 Zed。立即下载


我们正在招聘!

如果您对我们博客中涵盖的主题充满热情,请考虑加入我们的团队,帮助我们实现软件开发的未来。