V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
neptuno
V2EX  ›  Apple

macos 有时候切换回中文输入法失效(搜狗+自带输入法均失效),有人遇到过吗

  •  
  •   neptuno · 341 天前 · 751 次点击
    这是一个创建于 341 天前的主题,其中的信息可能已经有所发展或是发生改变。

    能切换到搜狗,但输出来的还是英文,点击菜单,显示几个点,猜测是进程挂了,有人遇到过吗? https://i.imgur.com/k8xh9gz.png

    12 条回复    2023-05-24 23:51:23 +08:00
    ychen997
        1
    ychen997  
       341 天前 via iPhone
    我遇到过,用的是 rime ,切换过去也失效
    ShikiSuen
        2
    ShikiSuen  
       341 天前
    推测:

    这些输入法(在你的电脑上)内建的 IMKInputController SubClass 的副本在 activateServer 的时候可能出了故障,导致完全无法响应。抑或是副本与 IMKTextInput Client 失联。
    ShikiSuen
        3
    ShikiSuen  
       341 天前
    这种问题可以考虑一下 XHacker ,但我不知道他是不是被公司禁止回答这些与 IMK 有关的问题。
    反正我跟他提过好几次 IMK 的 Bug ,没见他有任何响应。
    总觉得 Apple 狗逼规矩特别多,宁愿不解决问题、也要规避任何可能的所谓的「泄密风险」。
    ShikiSuen
        4
    ShikiSuen  
       341 天前
    订正:「考虑一下」->「考虑问一下」。
    上述吐槽不是针对 XHacker ,而是针对 Apple 的这些「规矩」。
    jorneyr
        5
    jorneyr  
       341 天前
    使用系统快捷键切换输入法没遇到过这个问题,使用 Hammerspoon 调用函数切换输入法在 webview 的页面里如 Safari 的 Input 里切换输入法有时候会遇到,让 Input 失去焦点再点击 Input 使其得到焦点输入状态又正常了。

    Hammerspoon 切换输入法代码:`hs.keycodes.currentSourceID("com.apple.inputmethod.SCIM.ITABC")`
    neptuno
        6
    neptuno  
    OP
       341 天前
    @ShikiSuen #3 那看来没法解决了,难受,概率倒是也不高,偶尔切换到中文会出现。然后多切换几次就正常了
    @jorneyr
    neptuno
        7
    neptuno  
    OP
       341 天前
    ShikiSuen
        8
    ShikiSuen  
       340 天前
    @neptuno

    你说多切几次就正常了,我想起了原因。

    如果切到输入法的时候、输入法正在运行、且有对当前 IMKTextInput Client 创建控制会话副本、且该副本正常的话,执行的会是 这个副本的 setValue(),传入的参数是当前输入法安装副本的 identifier (有些输入法会有多个安装副本,对应不同的输入模式,比如系统内建简体中文输入法就有全拼或双拼模式、内建繁体中文输入法会有注音或仓颉模式,等)。setValue 在被呼叫的时候,如果发现这个控制会话副本没有被正确 activateServer 的话,可能会重新 activateServer() 一遍。

    如果切到输入法的时候、输入法尚未运行(或尚未对当前 IMKTextInput Client 创建控制会话副本)的话,会启动副本。但此时因为副本是直接 init() 的,没有跑 activateServer(),所以无法视为正常启动,输入法自然也就无法正常工作、需要你重新切一下。

    怎么说呢,activateServer() 实际上是 IMKInputController 的两个建构子( Constructor )之一。很多 macOS 副厂输入法开发者不知道这玩意另有这么一个不需要任何参数的建构子。

    很多 mac 平台的输入法都需要一个扩充设计、来应对这个情况。我开发的威注音输入法对此的应对策略是这样的:

    一、给 IMKInputController 另写一个共用的建构子:

    ```
    /// 所有建構子都會執行的共用部分,在 super.init() 之後執行。
    private func construct(client theClient: (IMKTextInput & NSObjectProtocol)? = nil) {
    DispatchQueue.main.async { [self] in
    // 威注音限定:设定 inputHandler 以及同步核心词库偏好设定。
    inputHandler = InputHandler(
    lm: LMMgr.currentLM, uom: LMMgr.currentUOM, pref: PrefMgr.shared
    )
    inputHandler?.delegate = self
    syncBaseLMPrefs() // 同步核心词库偏好设定。

    // 所有输入法共用:下述兩行很有必要,否則輸入法會在手動重啟之後無法立刻生效。
    let maybeClient = theClient ?? client() // 注意:这样过后仍旧是 nullable IMKTextInput 类型。
    // 这里 client 是不是 nil 都无所谓,activateServer() 自己会处理:只要是 null ,就可以啥也不做(或者仅载入词库)。
    activateServer(maybeClient)

    // 威注音限定:GCD 會觸發 inputMode 的 didSet ,所以不用擔心。
    inputMode = .init(rawValue: PrefMgr.shared.mostRecentInputMode) ?? .imeModeNULL
    }
    }
    ```

    二、给 IMKInputController 实作 .init() 这个无参数的建构子。

    ```
    /// 對用以設定委任物件的控制器型別進行初期化處理。
    override public init() {
    super.init()
    construct(client: client())
    }
    ```

    三、让 IMKInputController 的 .init(server:delegate:client:) 这个有参数的建构子也利用 construct()。

    这样区分的原因是:有参数的建构子会接收系统传入的变数;而无参数的建构子会主动读取 client()。

    ```
    /// 對用以設定委任物件的控制器型別進行初期化處理。
    ///
    /// inputClient 參數是客體應用側存在的用以藉由 IMKServer 伺服器向輸入法傳訊的物件。該物件始終遵守 IMKTextInput 協定。
    /// - Remark: 所有由委任物件實裝的「被協定要求實裝的方法」都會有一個用來接受客體物件的參數。在 IMKInputController 內部的型別不需要接受這個參數,因為已經有「 client()」這個參數存在了。
    /// - Parameters:
    /// - server: IMKServer
    /// - delegate: 客體物件
    /// - inputClient: 用以接受輸入的客體應用物件
    override public init!(server: IMKServer!, delegate: Any!, client inputClient: Any!) {
    super.init(server: server, delegate: delegate, client: inputClient)
    let theClient = inputClient as? (IMKTextInput & NSObjectProtocol)
    construct(client: theClient)
    }
    ```

    思路大致如此。
    ShikiSuen
        9
    ShikiSuen  
       340 天前
    @neptuno V2EX 回帖无法使用 markdown ,我另开一个讨论串了:

    https://v2ex.com/t/942237#reply0
    neptuno
        10
    neptuno  
    OP
       340 天前
    @ShikiSuen #8 哇,谢谢回复!我现在解决方案就是,使用 keyboard maestro 快捷键切换输入法(先切换至中文,然后模拟两次 command+空格),这样目前还没出现中文失效的问题
    ychen997
        11
    ychen997  
       339 天前
    @jorneyr 和你一样。如果用系统设置的快捷键,不管是⌃ + Space 还是设置 Caps lock 或者是左下脚的小地球都没有这个问题,但是我在 Karabiner 里面设置了 shift (in pressed only)来切换输入法,用的是 karabiner 自带的切换功能"select_input_source": "input_mode_id": "im.rime.inputmethod.Squirrel", 在这种情况下会有无法切换成功的情况,需要从别的窗口再转移一下才可以,看了你的例子我觉得应该是调用这些第三方工具来切换输入法不靠谱,所以我重新用 Karabiner Map 了 Shift 到"apple_vendor_top_case_key_code": "keyboard_fn",也就是自带键盘左下角的地球键(按下去屏幕中间会有切换输入法提示),或者 Map 到 caps lock(启用 caps lock 切换输入法),或者 Map 到⌃ + Space ,这三种情况都能成功切换,目前没有发现有任何问题。
    jorneyr
        12
    jorneyr  
       339 天前
    @ychen997
    我用 Hammerspoon 切换输入法的目的是切换的时候在屏幕上显示输入法的名字,方便是中文还是英文输入状态。

    后来是绑定一个 Hammerspoon 的快捷键映射到系统切换输入法的快捷键,切换后输出输入法的名字解决了,没有直接使用 Hammerspoon 切换输入法了,算是曲线救国。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5622 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 03:21 · PVG 11:21 · LAX 20:21 · JFK 23:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.