簡要描述 Bug:
TL;DR (EN): #1140 / #1142 fixed the switch-away half of this macOS 26 regression. The symmetric half appears to remain: when the input source is switched into Squirrel out-of-process via TISSelectInputSource, IMK often fails to activate SquirrelInputController — keystrokes pass straight through as raw ASCII and the input menu renders empty (a placeholder ellipsis instead of Deploy / Sync user data). Switching via the menu bar always works; switching to another app and back immediately restores it. Not 100% deterministic — high probability; please repeat the steps a few times.
#1140 报告的是切走方向(候选框残留、编码不上屏),已由 #1142 修复。本 issue 报告的是同一个 macOS 26 回归的对称另一半:切入方向。当由另一个进程调用 TISSelectInputSource 把输入源切回鼠鬚管时,IMK 往往不会激活 SquirrelInputController,按键以原始 ASCII 直接上屏。因为 #1140 已关闭且其原始症状确已修复,故另开一条跟踪。
⚠️ 这个问题不是必现,而是高概率触发。 同样的操作偶尔也会一切正常。我暂时没能识别出决定性的附加条件,怀疑与切换时机、前台 App 的焦点状态等因素有关。建议把复现步骤重复 3–5 次,我这边基本都能在几次之内触发。
預期行爲:
由另一进程调用 TISSelectInputSource 切回鼠鬚管后,SquirrelInputController 应被激活,按键进入 Rime 引擎,正常出候选框;输入菜单应显示「重新部署 / 同步用户资料 / 偏好设定…」。走菜单栏原生切换时即是此行为。
實際行爲:
三个互相独立的信号同时出现:
- 敲字母无候选框,原始字母直接上屏 —— 按键根本没进 Rime 引擎;
- 菜单栏输入法菜单只剩一个省略号占位,正常应有的菜单项全部消失。该菜单由
IMKInputController.menu() 提供,菜单为空说明 IMK 侧没有活动的 input controller —— 这条最能定位问题层次;
- 切到别的 App 再切回,立即恢复正常 —— 一次正常的 activate 就能把坏状态冲掉。
此时 TISCopyCurrentKeyboardInputSource() 返回的确实是 im.rime.inputmethod.Squirrel.Hans,即输入源切换本身是成功的,坏的只是激活。
環境
我試過:
复现步骤
- 当前输入源为鼠鬚管,输入正常;
- 由另一个进程调用
TISSelectInputSource 切到 com.apple.keylayout.US;
- 再由该进程调用
TISSelectInputSource 切回 im.rime.inputmethod.Squirrel.Hans;
- 立刻在前台 App 里敲字母。
无需 macism / Input Source Pro / Karabiner 等任何第三方工具。下面是一段可直接复制运行的完整脚本(只依赖 Xcode Command Line Tools 提供的 swiftc,若没有请先跑 xcode-select --install):
#!/bin/bash
# rime-switch-repro.sh —— 复现「程序化切入鼠鬚管后 input controller 未激活」
# 用法:bash rime-switch-repro.sh (可重复运行几次,非必现)
set -euo pipefail
WORK=$(mktemp -d)
trap 'rm -rf "$WORK"' EXIT
cat > "$WORK/tis-select.swift" <<'SWIFT'
import Carbon
import Foundation
func inputSource(_ id: String) -> TISInputSource? {
guard let list = TISCreateInputSourceList(nil, true)?.takeRetainedValue() as? [TISInputSource] else { return nil }
return list.first {
guard let p = TISGetInputSourceProperty($0, kTISPropertyInputSourceID) else { return false }
return (Unmanaged<CFString>.fromOpaque(p).takeUnretainedValue() as String) == id
}
}
func currentID() -> String {
guard let s = TISCopyCurrentKeyboardInputSource()?.takeRetainedValue(),
let p = TISGetInputSourceProperty(s, kTISPropertyInputSourceID) else { return "?" }
return Unmanaged<CFString>.fromOpaque(p).takeUnretainedValue() as String
}
let target = CommandLine.arguments[1]
guard let src = inputSource(target) else {
FileHandle.standardError.write("找不到输入源: \(target)\n".data(using: .utf8)!)
exit(1)
}
let ok = TISSelectInputSource(src) == noErr
usleep(300_000)
print(" select \(target) -> \(ok ? "ok" : "FAIL"); current = \(currentID())")
SWIFT
echo "编译中…"
swiftc -O -o "$WORK/tis-select" "$WORK/tis-select.swift"
RIME="im.rime.inputmethod.Squirrel.Hans"
ABC="com.apple.keylayout.US"
echo
echo "请把光标点进任意输入框(浏览器地址栏、备忘录皆可),然后不要切换窗口。"
echo "10 秒后开始程序化切换。"
for i in $(seq 10 -1 1); do printf "\r T-%2ds " "$i"; sleep 1; done
echo
echo "切到 U.S. :"
"$WORK/tis-select" "$ABC"
sleep 1
echo "切回鼠鬚管:"
"$WORK/tis-select" "$RIME"
echo
echo "===> 现在立刻敲 a s d f,并观察:"
echo " 1) 有没有候选框?还是原始字母直接上屏?"
echo " 2) 点菜单栏输入法图标,菜单是完整的还是空的?"
echo " (非必现,若这次正常,请重复运行本脚本几次)"
对照组与排除项
边界说明(避免过度声称)
- 没能直接观测到
activateServer 未被调用 —— 上述结论是由三个独立现象共同推出的推断,不是直接证据。(曾尝试用 --getascii 做 controller 活性探针,但对照组不成立:切到 U.S. 后它照样应答,故该探针已作废。)
- 非必现,见开头的概率说明。
- 目前只在一台机器上验证过,欢迎其他 macOS 26 用户交叉验证。
一点想法
#1142 的思路是在 kTISNotifySelectedKeyboardInputSourceChanged 里对「切走」做兜底。既然该通知在 out-of-process 切换时是正常派发的(#1140 中已实测),是否可以在同一个 handler 里对称地处理「切入」:当 currentInputSourceID 以 im.rime.inputmethod.Squirrel 开头时,主动补一次激活?不确定 IMK 侧在 controller 尚未实例化的情况下前端能做到多少,如果方向可行我可以帮忙测试验证。
Disclaimer
本问题由我在日常使用中真实遇到并首先发现;随后的现场取证、对照实验、日志分析与本文撰写,由 Claude Code(Anthropic 的 AI 编程助手)协助完成。文中所有复现步骤与现象均已在我本机实测确认,不是模型凭空推测;但正如「边界说明」一节所述,「activateServer 未被调用」这一层是推断而非直接观测,复现概率也并非 100%。如有表述不准确之处,欢迎直接指出,我可以配合补做实验。
簡要描述 Bug:
TL;DR (EN): #1140 / #1142 fixed the switch-away half of this macOS 26 regression. The symmetric half appears to remain: when the input source is switched into Squirrel out-of-process via
TISSelectInputSource, IMK often fails to activateSquirrelInputController— keystrokes pass straight through as raw ASCII and the input menu renders empty (a placeholder ellipsis instead of Deploy / Sync user data). Switching via the menu bar always works; switching to another app and back immediately restores it. Not 100% deterministic — high probability; please repeat the steps a few times.#1140 报告的是切走方向(候选框残留、编码不上屏),已由 #1142 修复。本 issue 报告的是同一个 macOS 26 回归的对称另一半:切入方向。当由另一个进程调用
TISSelectInputSource把输入源切回鼠鬚管时,IMK 往往不会激活SquirrelInputController,按键以原始 ASCII 直接上屏。因为 #1140 已关闭且其原始症状确已修复,故另开一条跟踪。預期行爲:
由另一进程调用
TISSelectInputSource切回鼠鬚管后,SquirrelInputController应被激活,按键进入 Rime 引擎,正常出候选框;输入菜单应显示「重新部署 / 同步用户资料 / 偏好设定…」。走菜单栏原生切换时即是此行为。實際行爲:
三个互相独立的信号同时出现:
IMKInputController.menu()提供,菜单为空说明 IMK 侧没有活动的 input controller —— 这条最能定位问题层次;此时
TISCopyCurrentKeyboardInputSource()返回的确实是im.rime.inputmethod.Squirrel.Hans,即输入源切换本身是成功的,坏的只是激活。環境
latest,构建于 2026-06-28(commit2158538),已包含 Finalize stranded composition when input source is switched away programmatically (#1140) #1142(52d3bc3,2026-06-12 合入)我試過:
朙月拼音)後問題仍存在: 未测。本问题发生在 input controller 的激活层,按键根本没进引擎,判断与方案无关的可能性很高,但我没有实测,故不勾选TISSelectInputSource切入。走菜单栏原生切换则完全正常复现步骤
TISSelectInputSource切到com.apple.keylayout.US;TISSelectInputSource切回im.rime.inputmethod.Squirrel.Hans;无需 macism / Input Source Pro / Karabiner 等任何第三方工具。下面是一段可直接复制运行的完整脚本(只依赖 Xcode Command Line Tools 提供的
swiftc,若没有请先跑xcode-select --install):对照组与排除项
deactivateServer正常触发」的不对称完全一致。TISSelectInputSource调用。ascii_mode均为reset: 0。grammar.yaml,无害);Squirrel 进程存活、无崩溃报告,采样显示主线程在 run loop 正常空转,非死锁。边界说明(避免过度声称)
activateServer未被调用 —— 上述结论是由三个独立现象共同推出的推断,不是直接证据。(曾尝试用--getascii做 controller 活性探针,但对照组不成立:切到 U.S. 后它照样应答,故该探针已作废。)一点想法
#1142 的思路是在
kTISNotifySelectedKeyboardInputSourceChanged里对「切走」做兜底。既然该通知在 out-of-process 切换时是正常派发的(#1140 中已实测),是否可以在同一个 handler 里对称地处理「切入」:当currentInputSourceID以im.rime.inputmethod.Squirrel开头时,主动补一次激活?不确定 IMK 侧在 controller 尚未实例化的情况下前端能做到多少,如果方向可行我可以帮忙测试验证。Disclaimer
本问题由我在日常使用中真实遇到并首先发现;随后的现场取证、对照实验、日志分析与本文撰写,由 Claude Code(Anthropic 的 AI 编程助手)协助完成。文中所有复现步骤与现象均已在我本机实测确认,不是模型凭空推测;但正如「边界说明」一节所述,「
activateServer未被调用」这一层是推断而非直接观测,复现概率也并非 100%。如有表述不准确之处,欢迎直接指出,我可以配合补做实验。