From a144e20304dc72593d64ea2a07880c01a8225055 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Mon, 10 Oct 2022 11:27:29 +0800 Subject: [PATCH] SessionCtl // Make PCB, tooltip, and candidate window instances dynamic. --- Source/Modules/SessionCtl_Core.swift | 10 +++--- Source/Modules/SessionCtl_Delegates.swift | 2 +- Source/Modules/SessionCtl_HandleDisplay.swift | 34 +++++++++--------- Source/Modules/SessionCtl_HandleEvent.swift | 4 +-- Source/Modules/SessionCtl_HandleStates.swift | 35 ++++++++++--------- 5 files changed, 43 insertions(+), 42 deletions(-) diff --git a/Source/Modules/SessionCtl_Core.swift b/Source/Modules/SessionCtl_Core.swift index ead8bc66..f885eccf 100644 --- a/Source/Modules/SessionCtl_Core.swift +++ b/Source/Modules/SessionCtl_Core.swift @@ -28,7 +28,7 @@ class SessionCtl: IMKInputController { static var areWeNerfing = false /// 目前在用的的選字窗副本。 - static var ctlCandidateCurrent: CtlCandidateProtocol = { + var ctlCandidateCurrent: CtlCandidateProtocol = { let direction: NSUserInterfaceLayoutOrientation = PrefMgr.shared.useHorizontalCandidateList ? .horizontal : .vertical if #available(macOS 10.15, *) { @@ -39,11 +39,11 @@ class SessionCtl: IMKInputController { } }() - /// 工具提示視窗的共用副本。 - static var tooltipInstance = TooltipUI() + /// 工具提示視窗的副本。 + var tooltipInstance = TooltipUI() - /// 浮動組字窗的共用副本。 - static var popupCompositionBuffer = PopupCompositionBuffer() + /// 浮動組字窗的副本。 + var popupCompositionBuffer = PopupCompositionBuffer() // MARK: - diff --git a/Source/Modules/SessionCtl_Delegates.swift b/Source/Modules/SessionCtl_Delegates.swift index 1f3842fb..2b42d90c 100644 --- a/Source/Modules/SessionCtl_Delegates.swift +++ b/Source/Modules/SessionCtl_Delegates.swift @@ -16,7 +16,7 @@ extension SessionCtl: KeyHandlerDelegate { return client.bundleIdentifier() ?? "" } - func candidateController() -> CtlCandidateProtocol { Self.ctlCandidateCurrent } + func candidateController() -> CtlCandidateProtocol { ctlCandidateCurrent } func candidateSelectionCalledByKeyHandler(at index: Int) { candidatePairSelected(at: index) diff --git a/Source/Modules/SessionCtl_HandleDisplay.swift b/Source/Modules/SessionCtl_HandleDisplay.swift index 359d1c17..f02587b4 100644 --- a/Source/Modules/SessionCtl_HandleDisplay.swift +++ b/Source/Modules/SessionCtl_HandleDisplay.swift @@ -56,14 +56,14 @@ extension SessionCtl { }() // 強制重新初期化,因為 NSAttributedTextView 有顯示滯後性。 do { - Self.tooltipInstance.hide() - Self.tooltipInstance = .init() + tooltipInstance.hide() + tooltipInstance = .init() if state.type == .ofMarking { - Self.tooltipInstance.setColor(state: state.data.tooltipColorState) + tooltipInstance.setColor(state: state.data.tooltipColorState) } } // 再設定其文字顯示內容並顯示。 - Self.tooltipInstance.show( + tooltipInstance.show( tooltip: tooltip, at: finalOrigin, bottomOutOfScreenAdjustmentHeight: delta, direction: tooltipContentDirection ) @@ -74,34 +74,34 @@ extension SessionCtl { state.isVerticalCandidateWindow = (isVerticalTyping || !PrefMgr.shared.useHorizontalCandidateList) /// 無論是田所選字窗還是 IMK 選字窗,在這裡都有必要重新初期化。 - Self.ctlCandidateCurrent.delegate = nil + ctlCandidateCurrent.delegate = nil let candidateLayout: NSUserInterfaceLayoutOrientation = ((isVerticalTyping || !PrefMgr.shared.useHorizontalCandidateList) ? .vertical : .horizontal) if #available(macOS 10.15, *) { - Self.ctlCandidateCurrent = + ctlCandidateCurrent = PrefMgr.shared.useIMKCandidateWindow ? CtlCandidateIMK(candidateLayout) : CtlCandidateTDK(candidateLayout) - if let candidateTDK = Self.ctlCandidateCurrent as? CtlCandidateTDK { + if let candidateTDK = ctlCandidateCurrent as? CtlCandidateTDK { candidateTDK.maxLinesPerPage = isVerticalTyping ? 1 : 3 } } else { - Self.ctlCandidateCurrent = CtlCandidateIMK(candidateLayout) + ctlCandidateCurrent = CtlCandidateIMK(candidateLayout) } - Self.ctlCandidateCurrent.candidateFont = Self.candidateFont( + ctlCandidateCurrent.candidateFont = Self.candidateFont( name: PrefMgr.shared.candidateTextFontName, size: PrefMgr.shared.candidateListTextSize ) if state.type == .ofAssociates { - Self.ctlCandidateCurrent.tooltip = + ctlCandidateCurrent.tooltip = isVerticalTyping ? "⇧" : NSLocalizedString("Hold ⇧ to choose associates.", comment: "") } - Self.ctlCandidateCurrent.useLangIdentifier = PrefMgr.shared.handleDefaultCandidateFontsByLangIdentifier - Self.ctlCandidateCurrent.locale = { + ctlCandidateCurrent.useLangIdentifier = PrefMgr.shared.handleDefaultCandidateFontsByLangIdentifier + ctlCandidateCurrent.locale = { switch inputMode { case .imeModeCHS: return "zh-Hans" case .imeModeCHT: @@ -115,25 +115,25 @@ extension SessionCtl { if #available(macOS 10.14, *) { // Spotlight 視窗會擋住 IMK 選字窗,所以需要特殊處理。 - if let ctlCandidateCurrent = Self.ctlCandidateCurrent as? CtlCandidateIMK { + if let ctlCandidateCurrent = ctlCandidateCurrent as? CtlCandidateIMK { while ctlCandidateCurrent.windowLevel() <= client.windowLevel() { ctlCandidateCurrent.setWindowLevel(UInt64(max(0, client.windowLevel() + 1000))) } } } - Self.ctlCandidateCurrent.delegate = self // 會自動觸發田所選字窗的資料重載。 - Self.ctlCandidateCurrent.visible = true + ctlCandidateCurrent.delegate = self // 會自動觸發田所選字窗的資料重載。 + ctlCandidateCurrent.visible = true if isVerticalTyping { - Self.ctlCandidateCurrent.set( + ctlCandidateCurrent.set( windowTopLeftPoint: NSPoint( x: lineHeightRect().origin.x + lineHeightRect().size.width + 4.0, y: lineHeightRect().origin.y - 4.0 ), bottomOutOfScreenAdjustmentHeight: lineHeightRect().size.height + 4.0 ) } else { - Self.ctlCandidateCurrent.set( + ctlCandidateCurrent.set( windowTopLeftPoint: NSPoint(x: lineHeightRect().origin.x, y: lineHeightRect().origin.y - 4.0), bottomOutOfScreenAdjustmentHeight: lineHeightRect().size.height + 4.0 ) diff --git a/Source/Modules/SessionCtl_HandleEvent.swift b/Source/Modules/SessionCtl_HandleEvent.swift index ea444b78..d4335676 100644 --- a/Source/Modules/SessionCtl_HandleEvent.swift +++ b/Source/Modules/SessionCtl_HandleEvent.swift @@ -173,7 +173,7 @@ extension SessionCtl { // 這樣可以讓 interpretKeyEvents() 函式自行判斷: // - 是就地交給 imkCandidates.interpretKeyEvents() 處理? // - 還是藉由 delegate 扔回 SessionCtl 給 KeyHandler 處理? - if let imkCandidates = Self.ctlCandidateCurrent as? CtlCandidateIMK, imkCandidates.visible { + if let imkCandidates = ctlCandidateCurrent as? CtlCandidateIMK, imkCandidates.visible { let event: NSEvent = CtlCandidateIMK.replaceNumPadKeyCodes(target: eventToDeal) ?? eventToDeal // Shift+Enter 是個特殊情形,不提前攔截處理的話、會有垃圾參數傳給 delegate 的 keyHandler 從而崩潰。 @@ -207,7 +207,7 @@ extension SessionCtl { private func imkCandidatesEventSubHandler(event: NSEvent) -> Bool { let eventArray = [event] - guard let imkC = Self.ctlCandidateCurrent as? CtlCandidateIMK else { return false } + guard let imkC = ctlCandidateCurrent as? CtlCandidateIMK else { return false } if event.isEsc || event.isBackSpace || event.isDelete || (event.isShiftHold && !event.isSpace) { return commonEventHandler(event) } else if event.isSymbolMenuPhysicalKey { diff --git a/Source/Modules/SessionCtl_HandleStates.swift b/Source/Modules/SessionCtl_HandleStates.swift index 9ecf3b74..e491db2e 100644 --- a/Source/Modules/SessionCtl_HandleStates.swift +++ b/Source/Modules/SessionCtl_HandleStates.swift @@ -22,9 +22,10 @@ extension SessionCtl { state = newState switch state.type { case .ofDeactivated: - Self.ctlCandidateCurrent.delegate = nil - Self.ctlCandidateCurrent.visible = false - Self.tooltipInstance.hide() + ctlCandidateCurrent.delegate = nil + ctlCandidateCurrent.visible = false + popupCompositionBuffer.hide() + tooltipInstance.hide() if previous.hasComposition { commit(text: previous.displayedText) } @@ -37,29 +38,29 @@ extension SessionCtl { state = IMEState.ofEmpty() previous = state } - Self.ctlCandidateCurrent.visible = false - Self.tooltipInstance.hide() + ctlCandidateCurrent.visible = false + tooltipInstance.hide() // 全專案用以判斷「.Abortion」的地方僅此一處。 if previous.hasComposition, state.type != .ofAbortion { commit(text: previous.displayedText) } // 在這裡手動再取消一次選字窗與工具提示的顯示,可謂雙重保險。 - Self.ctlCandidateCurrent.visible = false - Self.tooltipInstance.hide() + ctlCandidateCurrent.visible = false + tooltipInstance.hide() clearInlineDisplay() // 最後一道保險 keyHandler.clear() case .ofCommitting: - Self.ctlCandidateCurrent.visible = false - Self.tooltipInstance.hide() + ctlCandidateCurrent.visible = false + tooltipInstance.hide() let textToCommit = state.textToCommit if !textToCommit.isEmpty { commit(text: textToCommit) } clearInlineDisplay() // 最後一道保險 keyHandler.clear() case .ofInputting: - Self.ctlCandidateCurrent.visible = false - Self.tooltipInstance.hide() + ctlCandidateCurrent.visible = false + tooltipInstance.hide() let textToCommit = state.textToCommit if !textToCommit.isEmpty { commit(text: textToCommit) } setInlineDisplayWithCursor() @@ -67,27 +68,27 @@ extension SessionCtl { show(tooltip: state.tooltip) } case .ofMarking: - Self.ctlCandidateCurrent.visible = false + ctlCandidateCurrent.visible = false setInlineDisplayWithCursor() if state.tooltip.isEmpty { - Self.tooltipInstance.hide() + tooltipInstance.hide() } else { show(tooltip: state.tooltip) } case .ofCandidates, .ofAssociates, .ofSymbolTable: - Self.tooltipInstance.hide() + tooltipInstance.hide() setInlineDisplayWithCursor() showCandidates() default: break } // 浮動組字窗的顯示判定 if state.hasComposition, PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier) { - Self.popupCompositionBuffer.isTypingDirectionVertical = isVerticalTyping - Self.popupCompositionBuffer.show( + popupCompositionBuffer.isTypingDirectionVertical = isVerticalTyping + popupCompositionBuffer.show( state: state, at: lineHeightRect(zeroCursor: true).origin ) } else { - Self.popupCompositionBuffer.hide() + popupCompositionBuffer.hide() } }