From 852eed07e29002046c0c296cb25c333dc90d880c Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Mon, 20 Mar 2023 14:38:44 +0800 Subject: [PATCH] SessionCtl // Use GCD for certain state tasks. --- Source/Modules/SessionCtl_Core.swift | 3 ++ Source/Modules/SessionCtl_HandleStates.swift | 31 +++++++++++++------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Source/Modules/SessionCtl_Core.swift b/Source/Modules/SessionCtl_Core.swift index 6c036158..6fb0b6c6 100644 --- a/Source/Modules/SessionCtl_Core.swift +++ b/Source/Modules/SessionCtl_Core.swift @@ -43,6 +43,9 @@ public class SessionCtl: IMKInputController { /// 當前副本的客體是否是輸入法本體? public var isServingIMEItself: Bool = false + /// 專門用來記錄處理狀態的執行緒記錄槽。 + public var stateQueueSet = [String]() + /// 用以存儲客體的 bundleIdentifier。 /// 由於每次動態獲取都會耗時,所以這裡直接靜態記載之。 public var clientBundleIdentifier: String = "" { diff --git a/Source/Modules/SessionCtl_HandleStates.swift b/Source/Modules/SessionCtl_HandleStates.swift index bfab44fd..b7745979 100644 --- a/Source/Modules/SessionCtl_HandleStates.swift +++ b/Source/Modules/SessionCtl_HandleStates.swift @@ -12,6 +12,20 @@ import Shared // MARK: - 狀態調度 (State Handling) public extension SessionCtl { + private func performStateTask(_ doTask: @escaping () -> Void) { + let queueID = UUID().uuidString + DispatchQueue.main.async { [self] in + stateQueueSet.append(queueID) + while stateQueueSet.first != queueID { + Thread.sleep(forTimeInterval: 0.001) + } + doTask() + if stateQueueSet.first == queueID { + stateQueueSet.removeFirst() + } + } + } + /// 針對傳入的新狀態進行調度、且將當前會話控制器的狀態切換至新狀態。 /// /// 先將舊狀態單獨記錄起來,再將新舊狀態作為參數, @@ -43,11 +57,8 @@ public extension SessionCtl { switch newState.type { case .ofDeactivated: // 這裡移除一些處理,轉而交給 commitComposition() 代為執行。 - // 這裡不需要 clearInlineDisplay() ,否則會觸發無限迴圈。 // 對於 IMK 選字窗的顯示狀態糾正的行為交給 inputMode.didSet() 來處理。 - candidateUI?.visible = false - popupCompositionBuffer.hide() - tooltipInstance.hide() + hidePalettes() inputHandler?.clear() if ![.ofAbortion, .ofEmpty].contains(previous.type), !previous.displayedText.isEmpty { clearInlineDisplay() @@ -68,23 +79,23 @@ public extension SessionCtl { commit(text: previous.displayedText) } // 會在工具提示為空的時候自動消除顯示。 - showTooltip(newState.tooltip, duration: newState.tooltipDuration) + performStateTask { self.showTooltip(newState.tooltip, duration: newState.tooltipDuration) } clearInlineDisplay() inputHandler?.clear() case .ofInputting: candidateUI?.visible = false if !newState.textToCommit.isEmpty { commit(text: newState.textToCommit) } - setInlineDisplayWithCursor() // 會在工具提示為空的時候自動消除顯示。 - showTooltip(newState.tooltip, duration: newState.tooltipDuration) + performStateTask { self.showTooltip(newState.tooltip, duration: newState.tooltipDuration) } + setInlineDisplayWithCursor() case .ofMarking: candidateUI?.visible = false + performStateTask { self.showTooltip(newState.tooltip) } setInlineDisplayWithCursor() - showTooltip(newState.tooltip) case .ofCandidates, .ofAssociates, .ofSymbolTable: - tooltipInstance.hide() + performStateTask { self.showCandidates() } setInlineDisplayWithCursor() - showCandidates() + tooltipInstance.hide() } // 浮動組字窗的顯示判定 updatePopupDisplayWithCursor()