macOS 平台第三方输入法的生命周期到底是怎样的?

一转眼落格输入法都已经做到第三代了,令人惊讶的是我似乎从来没有认真的思考过题目中的这个问题。一直以来我先入为主的认为 macOSiOS 一样就是为每个输入框创建一个输入法实例,而第三方输入法的 Controller,全局只有一个,由系统负责 XPC 调用。

后来尽管我发现 Controller 不会在输入框失去焦点后立即销毁,但我依旧认为系统会为每个输入框获得焦点时生成全新的 Controller。

网上关于 macOS 第三方输入法的生命周期并没有很多讨论,也是因为上文中我模棱两可的认知,导致了新版落格输入法遇到一些难以处理的问题,这次彻底把这个工作搞清楚了。

首先,我们看 IMKInputController 的声明,里边有说:

The IMKServer class which is allocated in an input method’s main function creates a controller class for each input session created by a client application. Therefore for every input session there is a corresponding IMKInputController.

所以实际上是每一个“输入会话”会有一个 Controller 对象,尽管通常我们输入的时候都只有唯一的输入框得到焦点(你不可能同时给两个输入框打字对吧?)

那么,这个“输入会话(input session)”又是个什么呢?经过我的实际测试,实际上就是对应的 App 了,不论有多少个输入框,一般一个 App 就会有一个会话,在极端情况下可能会有两个(这就解释了一些落格输入法中切换中英文的奇怪情况),但实际使用的仍然是最新生成的那个。

所以,这么综合来看,就可以得到如下结论:

输入法由系统启动,进程只有一个。通过系统调用,会为每一个 App 创建一个会话,会话会创建对应的 Controller,然后一般来说这个 Controller 会一直存在,直到这个 App 关闭。

所以这样一来,你就要小心使用全局变量或者是单件(由于我们确实不可能同时给多个输入框获得焦点,所以绝大多数情况下是安全的),因为在某些情况下,一旦发生竟用,则很有可能按键信号被多个 Controller 得到,这些共享的全局变量就会受到影响。

不过了解了输入法的生命周期后,解决方案也不难,其实 Controller 是有激活和反激活回调的,虽然 Controller 对象常驻内存,但我们可以依靠这个回调来判断用户当前是不是在用这个 Controller(也就是有没有在这个输入框中打字),如果有, func activateServer(_ sender: Any!) 会被调用,如果输入框失去焦点,则 func deactivateServer(_ sender: Any!) 会被调用,我们可以自己创建一个属性来追踪这个状态,这样在需要处理全局通知时,判断自己如果是未激活,就不要响应即可。落格输入法 macOS 3 就是这样解决了中英文切换时灵时不灵的问题。

说实在的,我至今依旧在用一个全局变量追踪当前的活跃 Controller 😅 但最重要的部分已经替换掉了……

 

本文由 落格博客 原创撰写:落格博客 » macOS 平台第三方输入法的生命周期到底是怎样的?

转载请保留出处和原文链接:https://www.logcg.com/archives/3563.html

About the Author

落格博客

如非声明,本人所著文章均为原创手打,转载请注明本页面链接和我的名字。

发表回复

您的电子邮箱地址不会被公开。