macOS 的 CpLk 中英切换卡顿的元凶在 InputMethodKit 本身

很多中文打字用户,无论用原厂输入法、还是任何一款副厂输入法,都会有中英文混打的需求。

十几年前开始自从 macOS 10.12 Sierra 引入基于 CpLk 的中英文输入法切换功能以来,这个问题到现在就都没消停过:「敲 CpLk 切换中英文输入法时会卡顿」。每台电脑跑每个版本的 macOS 时的发病严重程度不一:有的可以忽略,有的卡到骂娘。

长久以来,对此问题的讨论,往往被归咎于输入法本身:要么是在用的副厂输入法本身被抱怨,要么是原厂中文输入法本身被抱怨。

其实,这是 InputMethodKit 的一个堪称陈年大粪的设计缺陷。

笔者是唯音输入法的开发者,本文只是经验谈。谢绝未经授权的转载。

笔者按顺序罗列这些事实。先讲两个技术层面的:

  • InputMethodKit 的 IMKInputController 所有 API 呼叫都是在 MainActor 上的。然而,因为 ObjC Header 层面曝露的 API 与 Swift Concurrency 不相容的缘故,如果你要给输入法做 Swift Concurrency Modernization 的话,你需要一些 Dirty Trick 方便将这些 API 传入的参数重新从 MainActor 强制解读。
  • macOS 10.7 开始引入 Objective-C ARC。这套 ARC 系统对 NSObject 副本的析构时机不可控,你无法用手动介入的方式使其暂缓析构或重新利用。而 InputMethodKit 的 API 在设计时是针对 macOS 10.5 Leopard 设计的。这就带来了一些与 ARC 有关的 MainActor 调度压力问题(甚至阻塞)。下文会提到具体的问题情形。

再来讨论使用者打字场景上的事实:

  • macOS 10.12 的这个 CpLk 切换功能的本质不是中英文打字模式切换,而是输入法切换。
  • macOS 哪怕英文打字也是由一个专门的输入法负责的。大部分英语键盘的电脑上,这个输入法叫 Apple ABC,对应美规键盘。
  • 每个输入法在刚被切换出来时,会触发这个输入法自身的 IMKInputController Instance 的创建以及其 activateServer 操作(以及可能有的一系列追加操作)。然后才是这个 Client 之前对接的输入法的 IMKInputController 副本的 Deactivation。
  • 很多中英文混合打字的用户经常会在 ABC 与中文输入法之间来回切换。由于这种情况下两者所服务的 IMKTextInput Client 是相同的,所以就出现了 MainActor 塞车。而且,过于高频的来回切换,会给 IMKInputController 所用的 Objective-C ARC 带来压力。ARC 废件释放与物件交互都发生在 MainActor 上,必然会发生塞车。
  • 「在同一个 client 切换输入法」的过程会牵涉到前后两个 IMKInputController 副本各自的对 client() 的操作。输入法开发者现在最佳的范式就是让 deactivateServer 在 MainActor 上 Async 脱手操作、且不在 deactivateServer 阶段做 client() API 的文字写入/内容显示交互,因为这种擦除操作会由系统代劳。但是,这个由系统代劳的擦除操作也是发生在 MainActor 上的。这就出现了 MainActor 的任务的时序冲突。InputMethodKit 内部应该是有自己的方式处理这个冲突,然而代价就是阻塞开销。
  • 有些输入法难免会在 activateServer 阶段引入与 client() 有关的交互,但这个开销可能在所难免,因为你可能必须得对 client 套用指定的 Ukelele 布局。再加上 client() 身为 IMKTextInput Client 没有真正意义上的 Async API,输入法开发者只能假设所有这类 Client 的这些操作都是 MainActor 阻塞操作,然后干瞪眼。

这就导致那些经常用 CpLk 超高频中英切换打字的使用者们必然会骂娘。但他们不知道问题烂在系统层面,于是就只能骂输入法。或骂系统内建注音烂,或骂自己在用的副厂输入法不修故障。

这个现状恐怕真的没有解决方法,要淘汰的是 macOS 的整个 InputMethodKit 体系。整个 API 交互体系都需要刮骨疗毒重新设计。

或者,自力救济(下述几条都很重要):

  • 所有 macOS 中文用户都请关掉以 CpLk(「中/英」键)切换中英文输入法的特性,让系统遵循 macOS 10.11 El Capitan 为止的 CpLk 行为。
  • 中文输入法开发者们都请集体给自己的输入法实装 CpLk 英打模式。英打模式下的 Layout 同步问题也可以用 client().overrideKeyboard() 来解决,不过这是个阻塞操作。而且,如果接收打字的视窗是输入法自己的视窗的话,务必 MainActor Async 执行 client().overrideKeyboard(),否则必然会卡死几十秒。
  • IMKInputController Subclass 不要拥有任何物件。所有与打字有关的业务模组全部塞到 singleton 或者可以复用的 instance 里面。instance 与 IMKInputController Subclass 之间可以使用其他通讯交互手段。

P.S.: macOS 26 在 AppKit / InputMethodKit 的 NSObject Types 的 ARC 回收方面的效率低下之故障反而放大了这个问题。

$ EOF.

相关推荐
xiayutian_c2 小时前
如虎添翼-MacOS
macos
m0_737302583 小时前
iOS IPA 安装 Plist 文件生成工具
macos·objective-c·cocoa
独隅4 小时前
macOS 查看与安装 Java JDK 全面指南(2026年版)
java·开发语言·macos
黑果魏叔13 小时前
手滑点错更新也不怕!超详细 Mac 系统更新屏蔽指南(附安全恢复方案)
安全·macos
yuyousheng1 天前
mac 电脑复制粘贴剪切逻辑
macos
旭日跑马踏云飞1 天前
【macOS】相关
macos
lichao8904272 天前
MacOS 上部署 OpenClaw 的全界面操作方案
macos·docker·容器
美酒没故事°2 天前
mac电脑安装OpenClaw步骤
人工智能·macos