Finalize stranded composition when input source is switched away programmatically (#1140)#1142
Merged
LEOYoon-Tsaw merged 3 commits intoJun 12, 2026
Conversation
…rammatically macOS 26 does not call deactivateServer when another process switches the input source via TISSelectInputSource() (as macism, Input Source Pro and im-select-style vim tools do): the pending composition is stranded and the candidate panel is left orphaned on screen, while subsequent keystrokes already go to the new input source. Switching via the menu bar Input menu still works correctly. The input-source-changed distributed notification is still delivered on that path, so hook the existing kTISNotifySelectedKeyboardInputSourceChanged observer: when the selected source is no longer Squirrel and a composition is pending, commit the raw input and hide the panel, exactly as deactivateServer would have. When deactivateServer did run (menu bar switching), the composition is already empty and this is a no-op. Fixes rime#1140 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lotem
reviewed
Jun 12, 2026
| func finalizeStrandedComposition() { | ||
| let id = SquirrelInstaller.currentInputSourceID() ?? "" | ||
| guard !id.hasPrefix("im.rime.inputmethod.Squirrel") else { return } | ||
| panel?.inputController?.finalizeStrandedComposition() |
LEOYoon-Tsaw
left a comment
Member
There was a problem hiding this comment.
Changed to use deactivateServer instead
| func finalizeStrandedComposition() { | ||
| let id = SquirrelInstaller.currentInputSourceID() ?? "" | ||
| guard !id.hasPrefix("im.rime.inputmethod.Squirrel") else { return } | ||
| panel?.inputController?.finalizeStrandedComposition() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1140
TL;DR (EN): On macOS 26, switching the input source away from Squirrel via an out-of-process
TISSelectInputSource()never triggersdeactivateServer, stranding the pending composition with an orphaned candidate panel. ThekTISNotifySelectedKeyboardInputSourceChangednotification is still delivered (verified in #1140), so this PR hooks the existing observer to finalize the composition — commit raw input + hide the panel, exactly whatdeactivateServerwould have done.实现说明(如 #1140 讨论的方案):
SquirrelInputController.finalizeStrandedComposition():仅当 session 确有未上屏编码时动作,动作与deactivateServer一致(hidePalettes()+commitComposition,即原始编码上屏);SquirrelApplicationDelegate复用addObservers()里已有的kTISNotifySelectedKeyboardInputSourceChangedobserver,多调一行:当前选中源已非鼠须管时,让panel.inputController(showPanel时即指向正在 composing 的 controller)收口;deactivateServer已触发)下 composition 已空,整个调用是 no-op,不改变现有行为。验证计划:我手头有 #1140 用的自动化复现 harness(GUI 模拟输入 + CGWindowList 候选框窗口探针 + 程序化/菜单栏双路径对照)。等 CI 出包后我会在 macOS 26.5.1 实机装包跑修复前后对照,把结果贴在这里,然后转出 draft。