diff --git a/Source/Modules/SessionCtl_Core.swift b/Source/Modules/SessionCtl_Core.swift index 7709179b..7b26af7b 100644 --- a/Source/Modules/SessionCtl_Core.swift +++ b/Source/Modules/SessionCtl_Core.swift @@ -25,8 +25,6 @@ import UpdateSputnik /// 輸入會話創建一個控制器型別。因此,對於每個輸入會話,都有一個對應的 IMKInputController。 @objc(SessionCtl) // 必須加上 ObjC,因為 IMK 是用 ObjC 寫的。 public class SessionCtl: IMKInputController { - public static var allInstances: NSMutableOrderedSet = .init() - /// 標記狀態來聲明目前新增的詞彙是否需要賦以非常低的權重。 public static var areWeNerfing = false @@ -121,6 +119,15 @@ public class SessionCtl: IMKInputController { /// 重置輸入調度模組。 resetInputHandler(forceComposerCleanup: true) } + // 特殊處理:deactivateServer() 可能會遲於另一個客體會話的 activateServer() 執行。 + // 雖然所有在這個函式內影響到的變數都改為動態變數了(不會出現跨副本波及的情況), + // 但 IMKCandidates 是有內部共用副本的、會被波及。所以在這裡糾偏一下。 + if PrefMgr.shared.useIMKCandidateWindow { + guard let imkC = ctlCandidateCurrent as? CtlCandidateIMK else { return } + if state.isCandidateContainer, !imkC.visible { + handle(state: state, replace: false) + } + } } } @@ -184,7 +191,7 @@ extension SessionCtl { public override func activateServer(_ sender: Any!) { _ = sender // 防止格式整理工具毀掉與此對應的參數。 DispatchQueue.main.async { [self] in - if Self.allInstances.contains(self) { return } + if isActivated { return } // 因為偶爾會收到與 activateServer 有關的以「強制拆 nil」為理由的報錯, // 所以這裡添加這句、來試圖應對這種情況。 @@ -207,7 +214,6 @@ extension SessionCtl { state = IMEState.ofEmpty() isActivated = true // 登記啟用狀態。 - Self.allInstances.insert(self, at: 0) setKeyLayout() } } @@ -220,7 +226,6 @@ extension SessionCtl { isActivated = false resetInputHandler() // 這條會自動搞定 Empty 狀態。 switchState(IMEState.ofDeactivated()) - Self.allInstances.remove(self) } } diff --git a/Source/Modules/SessionCtl_HandleStates.swift b/Source/Modules/SessionCtl_HandleStates.swift index 7683b293..cfa81421 100644 --- a/Source/Modules/SessionCtl_HandleStates.swift +++ b/Source/Modules/SessionCtl_HandleStates.swift @@ -42,24 +42,12 @@ extension SessionCtl { if replace { state = newState } switch newState.type { case .ofDeactivated: + // 這裡移除一些處理,轉而交給 commitComposition() 代為執行。 + // 這裡不需要 clearInlineDisplay() ,否則會觸發無限迴圈。 + // 對於 IMK 選字窗的顯示狀態糾正的行為交給 inputMode.didSet() 來處理。 ctlCandidateCurrent.visible = false popupCompositionBuffer.hide() tooltipInstance.hide() - // 這裡移除一些處理,轉而交給 commitComposition() 代為執行。 - // 這裡不需要 clearInlineDisplay() ,否則會觸發無限迴圈。 - // 特殊處理:deactivateServer() 可能會遲於另一個客體會話的 activateServer() 執行。 - // 雖然所有在這個函式內影響到的變數都改為動態變數了(不會出現跨副本波及的情況), - // 但 IMKCandidates 是有內部共用副本的、會被波及。 - // 所以在這裡糾偏一下、讓所有開啟了選字窗的會話重新顯示選字窗。 - if PrefMgr.shared.useIMKCandidateWindow { - for instance in Self.allInstances { - guard let instance = instance as? SessionCtl else { continue } - guard let imkC = instance.ctlCandidateCurrent as? CtlCandidateIMK else { continue } - if instance.state.isCandidateContainer, !imkC.visible { - instance.handle(state: instance.state, replace: false) - } - } - } case .ofEmpty, .ofAbortion, .ofCommitting: innerCircle: switch newState.type { case .ofAbortion: