diff --git a/Source/Modules/InputHandler_Core.swift b/Source/Modules/InputHandler_Core.swift index a3532e41..2fc1a093 100644 --- a/Source/Modules/InputHandler_Core.swift +++ b/Source/Modules/InputHandler_Core.swift @@ -40,7 +40,7 @@ public protocol InputHandlerDelegate { func switchState(_ newState: IMEStateProtocol) func candidateController() -> CtlCandidateProtocol func candidateSelectionCalledByInputHandler(at index: Int) - func performUserPhraseOperation(with state: IMEStateProtocol, addToFilter: Bool) + func performUserPhraseOperation(addToFilter: Bool) -> Bool } diff --git a/Source/Modules/InputHandler_HandleCandidate.swift b/Source/Modules/InputHandler_HandleCandidate.swift index d23183c5..006e4e6e 100644 --- a/Source/Modules/InputHandler_HandleCandidate.swift +++ b/Source/Modules/InputHandler_HandleCandidate.swift @@ -17,11 +17,9 @@ extension InputHandler { /// 當且僅當選字窗出現時,對於經過初次篩選處理的輸入訊號的處理均藉由此函式來進行。 /// - Parameters: /// - input: 輸入訊號。 - /// - state: 給定狀態(通常為當前狀態)。 /// - errorCallback: 錯誤回呼。 /// - Returns: 告知 IMK「該按鍵是否已經被輸入法攔截處理」。 func handleCandidate( - state: IMEStateProtocol, input: InputSignalProtocol, errorCallback: @escaping (String) -> Void ) -> Bool { @@ -31,6 +29,7 @@ extension InputHandler { } var ctlCandidate = delegate.candidateController() + let state = delegate.state // MARK: 取消選字 (Cancel Candidate) @@ -287,9 +286,7 @@ extension InputHandler { if candidateIndex != -114_514 { delegate.candidateSelectionCalledByInputHandler(at: candidateIndex) delegate.switchState(IMEState.ofAbortion()) - return handleInput( - event: input, state: IMEState.ofEmpty(), errorCallback: errorCallback - ) + return handleInput(event: input, errorCallback: errorCallback) } return true } diff --git a/Source/Modules/InputHandler_HandleComposition.swift b/Source/Modules/InputHandler_HandleComposition.swift index 63dd1bb7..c1dbe232 100644 --- a/Source/Modules/InputHandler_HandleComposition.swift +++ b/Source/Modules/InputHandler_HandleComposition.swift @@ -126,7 +126,7 @@ extension InputHandler { /// 逐字選字模式的處理。 if prefs.useSCPCTypingMode { - let candidateState: IMEStateProtocol = generateStateOfCandidates(state: inputting) + let candidateState: IMEStateProtocol = generateStateOfCandidates() switch candidateState.candidates.count { case 2...: delegate.switchState(candidateState) case 1: diff --git a/Source/Modules/InputHandler_HandleEvent.swift b/Source/Modules/InputHandler_HandleEvent.swift index f06df3c0..c01248ed 100644 --- a/Source/Modules/InputHandler_HandleEvent.swift +++ b/Source/Modules/InputHandler_HandleEvent.swift @@ -25,8 +25,7 @@ extension InputHandler { /// 再根據返回的 result bool 數值來告知 IMK「這個按鍵事件是被處理了還是被放行了」。 /// 這裡不用 handleCandidate() 是因為需要針對聯想詞輸入狀態做額外處理。 private func doHandleInput(_ event: NSEvent) -> Bool { - guard let delegate = delegate else { return false } - return handleInput(event: event, state: delegate.state) { errorString in + handleInput(event: event) { errorString in vCLog(errorString) IMEApp.buzz() } diff --git a/Source/Modules/InputHandler_HandleInput.swift b/Source/Modules/InputHandler_HandleInput.swift index 48c78f5e..5beaf177 100644 --- a/Source/Modules/InputHandler_HandleInput.swift +++ b/Source/Modules/InputHandler_HandleInput.swift @@ -20,12 +20,10 @@ extension InputHandler { /// - Remark: 送入該函式處理之前,先用 inputHandler.handleEvent() 分診、來判斷是否需要交給 IMKCandidates 處理。 /// - Parameters: /// - input: 輸入訊號。 - /// - state: 給定狀態(通常為當前狀態)。 /// - errorCallback: 錯誤回呼。 /// - Returns: 告知 IMK「該按鍵是否已經被輸入法攔截處理」。 func handleInput( event input: InputSignalProtocol, - state: IMEStateProtocol, errorCallback: @escaping (String) -> Void ) -> Bool { // 如果按鍵訊號內的 inputTest 是空的話,則忽略該按鍵輸入,因為很可能是功能修飾鍵。 @@ -34,7 +32,7 @@ extension InputHandler { guard !input.text.isEmpty, input.charCode.isPrintable, let delegate = delegate else { return false } let inputText: String = input.text - var state = state // 常數轉變數。 + var state = delegate.state // 常數轉變數。 // 提前過濾掉一些不合規的按鍵訊號輸入,免得相關按鍵訊號被送給 Megrez 引發輸入法崩潰。 if input.isInvalid { @@ -107,17 +105,13 @@ extension InputHandler { // MARK: 處理候選字詞 (Handle Candidates) if [.ofCandidates, .ofSymbolTable].contains(state.type) { - return handleCandidate( - state: state, input: input, errorCallback: errorCallback - ) + return handleCandidate(input: input, errorCallback: errorCallback) } // MARK: 處理聯想詞 (Handle Associated Phrases) if state.type == .ofAssociates { - if handleCandidate( - state: state, input: input, errorCallback: errorCallback - ) { + if handleCandidate(input: input, errorCallback: errorCallback) { return true } else { delegate.switchState(IMEState.ofEmpty()) @@ -127,12 +121,7 @@ extension InputHandler { // MARK: 處理標記範圍、以便決定要把哪個範圍拿來新增使用者(濾除)語彙 (Handle Marking) if state.type == .ofMarking { - if handleMarkingState( - state, input: input, - errorCallback: errorCallback - ) { - return true - } + if handleMarkingState(input: input, errorCallback: errorCallback) { return true } state = state.convertedToInputting delegate.switchState(state) } @@ -172,13 +161,10 @@ extension InputHandler { } return true } else if input.isShiftHold { // 臉書等網站會攔截 Tab 鍵,所以用 Shift+Command+Space 對候選字詞做正向/反向輪替。 - return handleInlineCandidateRotation( - state: state, reverseModifier: input.isCommandHold, - errorCallback: errorCallback - ) + return handleInlineCandidateRotation(reverseOrder: input.isCommandHold, errorCallback: errorCallback) } } - let candidateState: IMEStateProtocol = generateStateOfCandidates(state: state) + let candidateState: IMEStateProtocol = generateStateOfCandidates() if candidateState.candidates.isEmpty { errorCallback("3572F238") } else { @@ -191,56 +177,46 @@ extension InputHandler { if let keyCodeType = KeyCode(rawValue: input.keyCode) { switch keyCodeType { - case .kEscape: return handleEsc(state: state) + case .kEscape: return handleEsc() case .kTab: - return handleInlineCandidateRotation( - state: state, reverseModifier: input.isShiftHold, errorCallback: errorCallback - ) + return handleInlineCandidateRotation(reverseOrder: input.isShiftHold, errorCallback: errorCallback) case .kUpArrow, .kDownArrow, .kLeftArrow, .kRightArrow: if (input.isControlHold || input.isShiftHold) && (input.isOptionHold) { if input.isLeft { // Ctrl+PgLf / Shift+PgLf - return handleHome(state: state, errorCallback: errorCallback) + return handleHome(errorCallback: errorCallback) } else if input.isRight { // Ctrl+PgRt or Shift+PgRt - return handleEnd(state: state, errorCallback: errorCallback) + return handleEnd(errorCallback: errorCallback) } } if input.isCursorBackward { // Forward - return handleBackward( - state: state, input: input, errorCallback: errorCallback - ) + return handleBackward(input: input, errorCallback: errorCallback) } if input.isCursorForward { // Backward - return handleForward( - state: state, input: input, errorCallback: errorCallback - ) + return handleForward(input: input, errorCallback: errorCallback) } if input.isCursorClockLeft || input.isCursorClockRight { // Clock keys if input.isOptionHold, state.type == .ofInputting { if input.isCursorClockRight { - return handleInlineCandidateRotation( - state: state, reverseModifier: false, errorCallback: errorCallback - ) + return handleInlineCandidateRotation(reverseOrder: false, errorCallback: errorCallback) } if input.isCursorClockLeft { - return handleInlineCandidateRotation( - state: state, reverseModifier: true, errorCallback: errorCallback - ) + return handleInlineCandidateRotation(reverseOrder: true, errorCallback: errorCallback) } } - return handleClockKey(state: state, errorCallback: errorCallback) + return handleClockKey(errorCallback: errorCallback) } - case .kHome: return handleHome(state: state, errorCallback: errorCallback) - case .kEnd: return handleEnd(state: state, errorCallback: errorCallback) + case .kHome: return handleHome(errorCallback: errorCallback) + case .kEnd: return handleEnd(errorCallback: errorCallback) case .kBackSpace: - return handleBackSpace(state: state, input: input, errorCallback: errorCallback) + return handleBackSpace(input: input, errorCallback: errorCallback) case .kWindowsDelete: - return handleDelete(state: state, input: input, errorCallback: errorCallback) + return handleDelete(input: input, errorCallback: errorCallback) case .kCarriageReturn, .kLineFeed: return (input.isCommandHold && input.isControlHold) ? (input.isOptionHold - ? handleCtrlOptionCommandEnter(state: state) - : handleCtrlCommandEnter(state: state)) - : handleEnter(state: state) + ? handleCtrlOptionCommandEnter() + : handleCtrlCommandEnter()) + : handleEnter() default: break } } @@ -258,7 +234,7 @@ extension InputHandler { var inputting = generateStateOfInputting() inputting.textToCommit = textToCommit delegate.switchState(inputting) - let candidateState = generateStateOfCandidates(state: inputting) + let candidateState = generateStateOfCandidates() if candidateState.candidates.isEmpty { errorCallback("B5127D8A") } else { @@ -273,7 +249,7 @@ extension InputHandler { // 得在這裡先 commit buffer,不然會導致「在摁 ESC 離開符號選單時會重複輸入上一次的組字區的內容」的不當行為。 // 於是這裡用「模擬一次 Enter 鍵的操作」使其代為執行這個 commit buffer 的動作。 // 這裡不需要該函式所傳回的 bool 結果,所以用「_ =」解消掉。 - _ = handleEnter(state: state) + _ = handleEnter() delegate.switchState(IMEState.ofSymbolTable(node: CandidateNode.root)) return true } @@ -304,11 +280,7 @@ extension InputHandler { let parser = currentKeyboardParser let arrCustomPunctuations: [String] = [punctuationNamePrefix, parser, input.text] let customPunctuation: String = arrCustomPunctuations.joined() - if handlePunctuation( - customPunctuation, - state: state, - errorCallback: errorCallback - ) { + if handlePunctuation(customPunctuation, errorCallback: errorCallback) { return true } @@ -317,11 +289,7 @@ extension InputHandler { let arrPunctuations: [String] = [punctuationNamePrefix, input.text] let punctuation: String = arrPunctuations.joined() - if handlePunctuation( - punctuation, - state: state, - errorCallback: errorCallback - ) { + if handlePunctuation(punctuation, errorCallback: errorCallback) { return true } @@ -354,11 +322,7 @@ extension InputHandler { return true default: // 包括 case 0,直接塞給組字區。 let letter = "_letter_\(inputText)" - if handlePunctuation( - letter, - state: state, - errorCallback: errorCallback - ) { + if handlePunctuation(letter, errorCallback: errorCallback) { return true } } diff --git a/Source/Modules/InputHandler_States.swift b/Source/Modules/InputHandler_States.swift index c86ea1d6..2b831bdf 100644 --- a/Source/Modules/InputHandler_States.swift +++ b/Source/Modules/InputHandler_States.swift @@ -84,15 +84,12 @@ extension InputHandler { /// 拿著給定的候選字詞陣列資料內容,切換至選字狀態。 /// - Parameters: - /// - currentState: 當前狀態。 /// - Returns: 回呼一個新的選詞狀態,來就給定的候選字詞陣列資料內容顯示選字窗。 - func generateStateOfCandidates( - state currentState: IMEStateProtocol - ) -> IMEStateProtocol { + func generateStateOfCandidates() -> IMEStateProtocol { IMEState.ofCandidates( candidates: generateArrayOfCandidates(fixOrder: prefs.useFixecCandidateOrderOnSelection), displayTextSegments: compositor.walkedNodes.values, - cursor: currentState.cursor + cursor: delegate?.state.cursor ?? generateStateOfInputting().cursor ) } @@ -110,9 +107,7 @@ extension InputHandler { /// - Parameters: /// - key: 給定的索引鍵(也就是給定的聯想詞的開頭字)。 /// - Returns: 回呼一個新的聯想詞狀態,來就給定的聯想詞陣列資料內容顯示選字窗。 - public func generateStateOfAssociates( - withPair pair: Megrez.Compositor.KeyValuePaired - ) -> IMEStateProtocol { + public func generateStateOfAssociates(withPair pair: Megrez.Compositor.KeyValuePaired) -> IMEStateProtocol { IMEState.ofAssociates( candidates: generateArrayOfAssociates(withPair: pair)) } @@ -121,16 +116,15 @@ extension InputHandler { /// 用以處理就地新增自訂語彙時的行為。 /// - Parameters: - /// - state: 當前狀態。 /// - input: 輸入按鍵訊號。 /// - errorCallback: 錯誤回呼。 /// - Returns: 將按鍵行為「是否有處理掉」藉由 SessionCtl 回報給 IMK。 func handleMarkingState( - _ state: IMEStateProtocol, input: InputSignalProtocol, errorCallback: @escaping (String) -> Void ) -> Bool { guard let delegate = delegate else { return false } + let state = delegate.state if input.isEsc { delegate.switchState(generateStateOfInputting()) @@ -154,7 +148,7 @@ extension InputHandler { errorCallback("9AAFAC00") return true } - if !delegate.performUserPhraseOperation(with: state, addToFilter: false) { + if !delegate.performUserPhraseOperation(addToFilter: false) { errorCallback("5B69CC8D") return true } @@ -168,7 +162,7 @@ extension InputHandler { errorCallback("1F88B191") return true } - if !delegate.performUserPhraseOperation(with: state, addToFilter: true) { + if !delegate.performUserPhraseOperation(addToFilter: true) { errorCallback("68D3C6C8") return true } @@ -231,10 +225,10 @@ extension InputHandler { /// - Returns: 將按鍵行為「是否有處理掉」藉由 SessionCtl 回報給 IMK。 func handlePunctuation( _ customPunctuation: String, - state: IMEStateProtocol, errorCallback: @escaping (String) -> Void ) -> Bool { guard let delegate = delegate else { return false } + let state = delegate.state if !currentLM.hasUnigramsFor(key: customPunctuation) { return false @@ -258,7 +252,7 @@ extension InputHandler { // 從這一行之後開始,就是針對逐字選字模式的單獨處理。 guard prefs.useSCPCTypingMode, composer.isEmpty else { return true } - let candidateState = generateStateOfCandidates(state: inputting) + let candidateState = generateStateOfCandidates() switch candidateState.candidates.count { case 2...: delegate.switchState(candidateState) case 1: @@ -278,12 +272,10 @@ extension InputHandler { /// Enter 鍵的處理。 /// - Parameters: - /// - state: 當前狀態。 /// - Returns: 將按鍵行為「是否有處理掉」藉由 SessionCtl 回報給 IMK。 - func handleEnter( - state: IMEStateProtocol - ) -> Bool { + func handleEnter() -> Bool { guard let delegate = delegate else { return false } + let state = delegate.state guard state.type == .ofInputting else { return false } delegate.switchState(IMEState.ofCommitting(textToCommit: state.displayedText)) @@ -295,12 +287,10 @@ extension InputHandler { /// Command+Enter 鍵的處理(注音文)。 /// - Parameters: - /// - state: 當前狀態。 /// - Returns: 將按鍵行為「是否有處理掉」藉由 SessionCtl 回報給 IMK。 - func handleCtrlCommandEnter( - state: IMEStateProtocol - ) -> Bool { + func handleCtrlCommandEnter() -> Bool { guard let delegate = delegate else { return false } + let state = delegate.state guard state.type == .ofInputting else { return false } var displayedText = compositor.keys.joined(separator: "-") @@ -322,12 +312,10 @@ extension InputHandler { /// Command+Option+Enter 鍵的處理(網頁 Ruby 注音文標記)。 /// - Parameters: - /// - state: 當前狀態。 /// - Returns: 將按鍵行為「是否有處理掉」藉由 SessionCtl 回報給 IMK。 - func handleCtrlOptionCommandEnter( - state: IMEStateProtocol - ) -> Bool { + func handleCtrlOptionCommandEnter() -> Bool { guard let delegate = delegate else { return false } + let state = delegate.state guard state.type == .ofInputting else { return false } var composed = "" @@ -357,16 +345,15 @@ extension InputHandler { /// 處理 BackSpace (macOS Delete) 按鍵行為。 /// - Parameters: - /// - state: 當前狀態。 /// - input: 輸入按鍵訊號。 /// - errorCallback: 錯誤回呼。 /// - Returns: 將按鍵行為「是否有處理掉」藉由 SessionCtl 回報給 IMK。 func handleBackSpace( - state: IMEStateProtocol, input: InputSignalProtocol, errorCallback: @escaping (String) -> Void ) -> Bool { guard let delegate = delegate else { return false } + let state = delegate.state guard state.type == .ofInputting else { return false } // 引入 macOS 內建注音輸入法的行為,允許用 Shift+BackSpace 解構前一個漢字的讀音。 @@ -418,16 +405,15 @@ extension InputHandler { /// 處理 PC Delete (macOS Fn+BackSpace) 按鍵行為。 /// - Parameters: - /// - state: 當前狀態。 /// - input: 輸入按鍵訊號。 /// - errorCallback: 錯誤回呼。 /// - Returns: 將按鍵行為「是否有處理掉」藉由 SessionCtl 回報給 IMK。 func handleDelete( - state: IMEStateProtocol, input: InputSignalProtocol, errorCallback: @escaping (String) -> Void ) -> Bool { guard let delegate = delegate else { return false } + let state = delegate.state guard state.type == .ofInputting else { return false } if input.isShiftHold { @@ -462,14 +448,13 @@ extension InputHandler { /// 處理與當前文字輸入排版前後方向呈 90 度的那兩個方向鍵的按鍵行為。 /// - Parameters: - /// - state: 當前狀態。 /// - errorCallback: 錯誤回呼。 /// - Returns: 將按鍵行為「是否有處理掉」藉由 SessionCtl 回報給 IMK。 func handleClockKey( - state: IMEStateProtocol, errorCallback: @escaping (String) -> Void ) -> Bool { guard let delegate = delegate else { return false } + let state = delegate.state guard state.type == .ofInputting else { return false } if !composer.isEmpty { errorCallback("9B6F908D") @@ -482,14 +467,13 @@ extension InputHandler { /// 處理 Home 鍵的行為。 /// - Parameters: - /// - state: 當前狀態。 /// - errorCallback: 錯誤回呼。 /// - Returns: 將按鍵行為「是否有處理掉」藉由 SessionCtl 回報給 IMK。 func handleHome( - state: IMEStateProtocol, errorCallback: @escaping (String) -> Void ) -> Bool { guard let delegate = delegate else { return false } + let state = delegate.state guard state.type == .ofInputting else { return false } if !composer.isEmpty { @@ -513,14 +497,13 @@ extension InputHandler { /// 處理 End 鍵的行為。 /// - Parameters: - /// - state: 當前狀態。 /// - errorCallback: 錯誤回呼。 /// - Returns: 將按鍵行為「是否有處理掉」藉由 SessionCtl 回報給 IMK。 func handleEnd( - state: IMEStateProtocol, errorCallback: @escaping (String) -> Void ) -> Bool { guard let delegate = delegate else { return false } + let state = delegate.state guard state.type == .ofInputting else { return false } if !composer.isEmpty { @@ -544,12 +527,10 @@ extension InputHandler { /// 處理 Esc 鍵的行為。 /// - Parameters: - /// - state: 當前狀態。 /// - Returns: 將按鍵行為「是否有處理掉」藉由 SessionCtl 回報給 IMK。 - func handleEsc( - state: IMEStateProtocol - ) -> Bool { + func handleEsc() -> Bool { guard let delegate = delegate else { return false } + let state = delegate.state guard state.type == .ofInputting else { return false } if prefs.escToCleanInputBuffer { @@ -573,16 +554,15 @@ extension InputHandler { /// 處理向前方向鍵的行為。 /// - Parameters: - /// - state: 當前狀態。 /// - input: 輸入按鍵訊號。 /// - errorCallback: 錯誤回呼。 /// - Returns: 將按鍵行為「是否有處理掉」藉由 SessionCtl 回報給 IMK。 func handleForward( - state: IMEStateProtocol, input: InputSignalProtocol, errorCallback: @escaping (String) -> Void ) -> Bool { guard let delegate = delegate else { return false } + let state = delegate.state guard state.type == .ofInputting else { return false } if !composer.isEmpty { @@ -612,7 +592,7 @@ extension InputHandler { } } else if input.isOptionHold { if input.isControlHold { - return handleEnd(state: state, errorCallback: errorCallback) + return handleEnd(errorCallback: errorCallback) } // 游標跳轉動作無論怎樣都會執行,但如果出了執行失敗的結果的話則觸發報錯流程。 if !compositor.jumpCursorBySpan(to: .front) { @@ -641,16 +621,15 @@ extension InputHandler { /// 處理向後方向鍵的行為。 /// - Parameters: - /// - state: 當前狀態。 /// - input: 輸入按鍵訊號。 /// - errorCallback: 錯誤回呼。 /// - Returns: 將按鍵行為「是否有處理掉」藉由 SessionCtl 回報給 IMK。 func handleBackward( - state: IMEStateProtocol, input: InputSignalProtocol, errorCallback: @escaping (String) -> Void ) -> Bool { guard let delegate = delegate else { return false } + let state = delegate.state guard state.type == .ofInputting else { return false } if !composer.isEmpty { @@ -680,7 +659,7 @@ extension InputHandler { } } else if input.isOptionHold { if input.isControlHold { - return handleHome(state: state, errorCallback: errorCallback) + return handleHome(errorCallback: errorCallback) } // 游標跳轉動作無論怎樣都會執行,但如果出了執行失敗的結果的話則觸發報錯流程。 if !compositor.jumpCursorBySpan(to: .rear) { @@ -709,16 +688,15 @@ extension InputHandler { /// 以給定之參數來處理上下文候選字詞之輪替。 /// - Parameters: - /// - state: 當前狀態。 - /// - reverseModifier: 是否有控制輪替方向的修飾鍵輸入。 + /// - reverseOrder: 是否有控制輪替方向的修飾鍵輸入。 /// - errorCallback: 錯誤回呼。 /// - Returns: 將按鍵行為「是否有處理掉」藉由 SessionCtl 回報給 IMK。 func handleInlineCandidateRotation( - state: IMEStateProtocol, - reverseModifier: Bool, + reverseOrder: Bool, errorCallback: @escaping (String) -> Void ) -> Bool { guard let delegate = delegate else { return false } + let state = delegate.state if composer.isEmpty, compositor.isEmpty || compositor.walkedNodes.isEmpty { return false } guard state.type == .ofInputting else { guard state.type == .ofEmpty else { @@ -772,12 +750,12 @@ extension InputHandler { if candidates[0] == currentPaired { /// 如果第一個候選字詞是當前節點的候選字詞的值的話, /// 那就切到下一個(或上一個,也就是最後一個)候選字詞。 - currentIndex = reverseModifier ? candidates.count - 1 : 1 + currentIndex = reverseOrder ? candidates.count - 1 : 1 } } else { for candidate in candidates { if candidate == currentPaired { - if reverseModifier { + if reverseOrder { if currentIndex == 0 { currentIndex = candidates.count - 1 } else { diff --git a/Source/Modules/SessionCtl_Delegates.swift b/Source/Modules/SessionCtl_Delegates.swift index dbd06c11..1c0db9d2 100644 --- a/Source/Modules/SessionCtl_Delegates.swift +++ b/Source/Modules/SessionCtl_Delegates.swift @@ -22,9 +22,7 @@ extension SessionCtl: InputHandlerDelegate { candidatePairSelected(at: index) } - public func performUserPhraseOperation(with state: IMEStateProtocol, addToFilter: Bool) - -> Bool - { + public func performUserPhraseOperation(addToFilter: Bool) -> Bool { guard state.type == .ofMarking else { return false } if !LMMgr.writeUserPhrase( state.data.userPhraseDumped, inputMode: inputMode,