diff --git a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift index a770892c..a57d3bc3 100644 --- a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift +++ b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift @@ -37,341 +37,345 @@ extension KeyHandler { ) -> Bool { let inputText = input.inputText let charCode: UniChar = input.charCode - if let ctlCandidateCurrent = delegate?.ctlCandidate() { - // MARK: Cancel Candidate + guard let ctlCandidateCurrent = delegate?.ctlCandidate() else { + IME.prtDebugIntel("06661F6E") + errorCallback() + return true + } - let cancelCandidateKey = - input.isBackSpace || input.isESC || input.isDelete - || ((input.isCursorBackward || input.isCursorForward) && input.isShiftHold) + // MARK: Cancel Candidate - if cancelCandidateKey { - if (state is InputState.AssociatedPhrases) - || mgrPrefs.useSCPCTypingMode - || isBuilderEmpty - { - // 如果此時發現當前組字緩衝區為真空的情況的話, - // 就將當前的組字緩衝區析構處理、強制重設輸入狀態。 - // 否則,一個本不該出現的真空組字緩衝區會使前後方向鍵與 BackSpace 鍵失靈。 - // 所以這裡需要對 isBuilderEmpty 做判定。 - clear() - stateCallback(InputState.EmptyIgnoringPreviousState()) - } else { - stateCallback(buildInputtingState) - } + let cancelCandidateKey = + input.isBackSpace || input.isESC || input.isDelete + || ((input.isCursorBackward || input.isCursorForward) && input.isShiftHold) + + if cancelCandidateKey { + if (state is InputState.AssociatedPhrases) + || mgrPrefs.useSCPCTypingMode + || isBuilderEmpty + { + // 如果此時發現當前組字緩衝區為真空的情況的話, + // 就將當前的組字緩衝區析構處理、強制重設輸入狀態。 + // 否則,一個本不該出現的真空組字緩衝區會使前後方向鍵與 BackSpace 鍵失靈。 + // 所以這裡需要對 isBuilderEmpty 做判定。 + clear() + stateCallback(InputState.EmptyIgnoringPreviousState()) + } else { + stateCallback(buildInputtingState) + } + return true + } + + // MARK: Enter + + if input.isEnter { + if state is InputState.AssociatedPhrases { + clear() + stateCallback(InputState.EmptyIgnoringPreviousState()) return true } + delegate!.keyHandler( + self, + didSelectCandidateAt: ctlCandidateCurrent.selectedCandidateIndex, + ctlCandidate: ctlCandidateCurrent + ) + return true + } - // MARK: Enter + // MARK: Tab - if input.isEnter { - if state is InputState.AssociatedPhrases { - clear() - stateCallback(InputState.EmptyIgnoringPreviousState()) - return true + if input.isTab { + let updated: Bool = + mgrPrefs.specifyShiftTabKeyBehavior + ? (input.isShiftHold + ? ctlCandidateCurrent.showPreviousPage() + : ctlCandidateCurrent.showNextPage()) + : (input.isShiftHold + ? ctlCandidateCurrent.highlightPreviousCandidate() + : ctlCandidateCurrent.highlightNextCandidate()) + if !updated { + IME.prtDebugIntel("9B691919") + errorCallback() + } + return true + } + + // MARK: Space + + if input.isSpace { + let updated: Bool = + mgrPrefs.specifyShiftSpaceKeyBehavior + ? (input.isShiftHold + ? ctlCandidateCurrent.highlightNextCandidate() + : ctlCandidateCurrent.showNextPage()) + : (input.isShiftHold + ? ctlCandidateCurrent.showNextPage() + : ctlCandidateCurrent.highlightNextCandidate()) + if !updated { + IME.prtDebugIntel("A11C781F") + errorCallback() + } + return true + } + + // MARK: PgDn + + if input.isPageDown || input.emacsKey == vChewingEmacsKey.nextPage { + let updated: Bool = ctlCandidateCurrent.showNextPage() + if !updated { + IME.prtDebugIntel("9B691919") + errorCallback() + } + return true + } + + // MARK: PgUp + + if input.isPageUp { + let updated: Bool = ctlCandidateCurrent.showPreviousPage() + if !updated { + IME.prtDebugIntel("9569955D") + errorCallback() + } + return true + } + + // MARK: Left Arrow + + if input.isLeft { + switch ctlCandidateCurrent.currentLayout { + case .horizontal: + do { + if !ctlCandidateCurrent.highlightPreviousCandidate() { + IME.prtDebugIntel("1145148D") + errorCallback() + } + } + case .vertical: + do { + if !ctlCandidateCurrent.showPreviousPage() { + IME.prtDebugIntel("1919810D") + errorCallback() + } + } + } + return true + } + + // MARK: EmacsKey Backward + + if input.emacsKey == vChewingEmacsKey.backward { + let updated: Bool = ctlCandidateCurrent.highlightPreviousCandidate() + if !updated { + IME.prtDebugIntel("9B89308D") + errorCallback() + } + return true + } + + // MARK: Right Arrow + + if input.isRight { + switch ctlCandidateCurrent.currentLayout { + case .horizontal: + do { + if !ctlCandidateCurrent.highlightNextCandidate() { + IME.prtDebugIntel("9B65138D") + errorCallback() + } + } + case .vertical: + do { + if !ctlCandidateCurrent.showNextPage() { + IME.prtDebugIntel("9244908D") + errorCallback() + } + } + } + return true + } + + // MARK: EmacsKey Forward + + if input.emacsKey == vChewingEmacsKey.forward { + let updated: Bool = ctlCandidateCurrent.highlightNextCandidate() + if !updated { + IME.prtDebugIntel("9B2428D") + errorCallback() + } + return true + } + + // MARK: Up Arrow + + if input.isUp { + switch ctlCandidateCurrent.currentLayout { + case .horizontal: + do { + if !ctlCandidateCurrent.showPreviousPage() { + IME.prtDebugIntel("9B614524") + errorCallback() + } + } + case .vertical: + do { + if !ctlCandidateCurrent.highlightPreviousCandidate() { + IME.prtDebugIntel("ASD9908D") + errorCallback() + } + } + } + return true + } + + // MARK: Down Arrow + + if input.isDown { + switch ctlCandidateCurrent.currentLayout { + case .horizontal: + do { + if !ctlCandidateCurrent.showNextPage() { + IME.prtDebugIntel("92B990DD") + errorCallback() + } + } + case .vertical: + do { + if !ctlCandidateCurrent.highlightNextCandidate() { + IME.prtDebugIntel("6B99908D") + errorCallback() + } + } + } + return true + } + + // MARK: Home Key + + if input.isHome || input.emacsKey == vChewingEmacsKey.home { + if ctlCandidateCurrent.selectedCandidateIndex == 0 { + IME.prtDebugIntel("9B6EDE8D") + errorCallback() + } else { + ctlCandidateCurrent.selectedCandidateIndex = 0 + } + + return true + } + + // MARK: End Key + + var candidates: [String]! + + if let state = state as? InputState.ChoosingCandidate { + candidates = state.candidates + } else if let state = state as? InputState.AssociatedPhrases { + candidates = state.candidates + } + + if candidates.isEmpty { + return false + } else { // 這裡不用「count > 0」,因為該整數變數只要「!isEmpty」那就必定滿足這個條件。 + if input.isEnd || input.emacsKey == vChewingEmacsKey.end { + if ctlCandidateCurrent.selectedCandidateIndex == candidates.count - 1 { + IME.prtDebugIntel("9B69AAAD") + errorCallback() + } else { + ctlCandidateCurrent.selectedCandidateIndex = candidates.count - 1 } + } + } + + // MARK: - Associated Phrases + + if state is InputState.AssociatedPhrases { + if !input.isShiftHold { return false } + } + + var index: Int = NSNotFound + var match: String! + if state is InputState.AssociatedPhrases { + match = input.inputTextIgnoringModifiers + } else { + match = inputText + } + + var j = 0 + while j < ctlCandidateCurrent.keyLabels.count { + let label: CandidateKeyLabel = ctlCandidateCurrent.keyLabels[j] + if match.compare(label.key, options: .caseInsensitive, range: nil, locale: .current) == .orderedSame { + index = j + break + } + j += 1 + } + + if index != NSNotFound { + let candidateIndex = ctlCandidateCurrent.candidateIndexAtKeyLabelIndex(index) + if candidateIndex != Int.max { delegate!.keyHandler( - self, - didSelectCandidateAt: ctlCandidateCurrent.selectedCandidateIndex, - ctlCandidate: ctlCandidateCurrent + self, didSelectCandidateAt: candidateIndex, ctlCandidate: ctlCandidateCurrent ) return true } + } - // MARK: Tab + if state is InputState.AssociatedPhrases { return false } - if input.isTab { - let updated: Bool = - mgrPrefs.specifyShiftTabKeyBehavior - ? (input.isShiftHold - ? ctlCandidateCurrent.showPreviousPage() - : ctlCandidateCurrent.showNextPage()) - : (input.isShiftHold - ? ctlCandidateCurrent.highlightPreviousCandidate() - : ctlCandidateCurrent.highlightNextCandidate()) - if !updated { - IME.prtDebugIntel("9B691919") - errorCallback() - } - return true - } + // MARK: SCPC Mode Processing - // MARK: Space + if mgrPrefs.useSCPCTypingMode { + var punctuationNamePrefix = "" - if input.isSpace { - let updated: Bool = - mgrPrefs.specifyShiftSpaceKeyBehavior - ? (input.isShiftHold - ? ctlCandidateCurrent.highlightNextCandidate() - : ctlCandidateCurrent.showNextPage()) - : (input.isShiftHold - ? ctlCandidateCurrent.showNextPage() - : ctlCandidateCurrent.highlightNextCandidate()) - if !updated { - IME.prtDebugIntel("A11C781F") - errorCallback() - } - return true - } - - // MARK: PgDn - - if input.isPageDown || input.emacsKey == vChewingEmacsKey.nextPage { - let updated: Bool = ctlCandidateCurrent.showNextPage() - if !updated { - IME.prtDebugIntel("9B691919") - errorCallback() - } - return true - } - - // MARK: PgUp - - if input.isPageUp { - let updated: Bool = ctlCandidateCurrent.showPreviousPage() - if !updated { - IME.prtDebugIntel("9569955D") - errorCallback() - } - return true - } - - // MARK: Left Arrow - - if input.isLeft { - switch ctlCandidateCurrent.currentLayout { - case .horizontal: - do { - if !ctlCandidateCurrent.highlightPreviousCandidate() { - IME.prtDebugIntel("1145148D") - errorCallback() - } - } - case .vertical: - do { - if !ctlCandidateCurrent.showPreviousPage() { - IME.prtDebugIntel("1919810D") - errorCallback() - } - } - } - return true - } - - // MARK: EmacsKey Backward - - if input.emacsKey == vChewingEmacsKey.backward { - let updated: Bool = ctlCandidateCurrent.highlightPreviousCandidate() - if !updated { - IME.prtDebugIntel("9B89308D") - errorCallback() - } - return true - } - - // MARK: Right Arrow - - if input.isRight { - switch ctlCandidateCurrent.currentLayout { - case .horizontal: - do { - if !ctlCandidateCurrent.highlightNextCandidate() { - IME.prtDebugIntel("9B65138D") - errorCallback() - } - } - case .vertical: - do { - if !ctlCandidateCurrent.showNextPage() { - IME.prtDebugIntel("9244908D") - errorCallback() - } - } - } - return true - } - - // MARK: EmacsKey Forward - - if input.emacsKey == vChewingEmacsKey.forward { - let updated: Bool = ctlCandidateCurrent.highlightNextCandidate() - if !updated { - IME.prtDebugIntel("9B2428D") - errorCallback() - } - return true - } - - // MARK: Up Arrow - - if input.isUp { - switch ctlCandidateCurrent.currentLayout { - case .horizontal: - do { - if !ctlCandidateCurrent.showPreviousPage() { - IME.prtDebugIntel("9B614524") - errorCallback() - } - } - case .vertical: - do { - if !ctlCandidateCurrent.highlightPreviousCandidate() { - IME.prtDebugIntel("ASD9908D") - errorCallback() - } - } - } - return true - } - - // MARK: Down Arrow - - if input.isDown { - switch ctlCandidateCurrent.currentLayout { - case .horizontal: - do { - if !ctlCandidateCurrent.showNextPage() { - IME.prtDebugIntel("92B990DD") - errorCallback() - } - } - case .vertical: - do { - if !ctlCandidateCurrent.highlightNextCandidate() { - IME.prtDebugIntel("6B99908D") - errorCallback() - } - } - } - return true - } - - // MARK: Home Key - - if input.isHome || input.emacsKey == vChewingEmacsKey.home { - if ctlCandidateCurrent.selectedCandidateIndex == 0 { - IME.prtDebugIntel("9B6EDE8D") - errorCallback() - } else { - ctlCandidateCurrent.selectedCandidateIndex = 0 - } - - return true - } - - // MARK: End Key - - var candidates: [String]! - - if let state = state as? InputState.ChoosingCandidate { - candidates = state.candidates - } else if let state = state as? InputState.AssociatedPhrases { - candidates = state.candidates - } - - if candidates.isEmpty { - return false - } else { // 這裡不用「count > 0」,因為該整數變數只要「!isEmpty」那就必定滿足這個條件。 - if input.isEnd || input.emacsKey == vChewingEmacsKey.end { - if ctlCandidateCurrent.selectedCandidateIndex == candidates.count - 1 { - IME.prtDebugIntel("9B69AAAD") - errorCallback() - } else { - ctlCandidateCurrent.selectedCandidateIndex = candidates.count - 1 - } - } - } - - // MARK: - Associated Phrases - - if state is InputState.AssociatedPhrases { - if !input.isShiftHold { return false } - } - - var index: Int = NSNotFound - var match: String! - if state is InputState.AssociatedPhrases { - match = input.inputTextIgnoringModifiers + if input.isOptionHold && !input.isControlHold { + punctuationNamePrefix = "_alt_punctuation_" + } else if input.isControlHold && !input.isOptionHold { + punctuationNamePrefix = "_ctrl_punctuation_" + } else if input.isControlHold && input.isOptionHold { + punctuationNamePrefix = "_alt_ctrl_punctuation_" + } else if mgrPrefs.halfWidthPunctuationEnabled { + punctuationNamePrefix = "_half_punctuation_" } else { - match = inputText + punctuationNamePrefix = "_punctuation_" } - var j = 0 - while j < ctlCandidateCurrent.keyLabels.count { - let label: CandidateKeyLabel = ctlCandidateCurrent.keyLabels[j] - if match.compare(label.key, options: .caseInsensitive, range: nil, locale: .current) == .orderedSame { - index = j - break - } - j += 1 + let parser = currentMandarinParser + + let arrCustomPunctuations: [String] = [ + punctuationNamePrefix, parser, String(format: "%c", CChar(charCode)), + ] + let customPunctuation: String = arrCustomPunctuations.joined(separator: "") + + let arrPunctuations: [String] = [punctuationNamePrefix, String(format: "%c", CChar(charCode))] + let punctuation: String = arrPunctuations.joined(separator: "") + + var shouldAutoSelectCandidate: Bool = + _composer.inputValidityCheck(key: charCode) || ifLangModelHasUnigrams(forKey: customPunctuation) + || ifLangModelHasUnigrams(forKey: punctuation) + + if !shouldAutoSelectCandidate, input.isUpperCaseASCIILetterKey { + let letter: String! = String(format: "%@%c", "_letter_", CChar(charCode)) + if ifLangModelHasUnigrams(forKey: letter) { shouldAutoSelectCandidate = true } } - if index != NSNotFound { - let candidateIndex = ctlCandidateCurrent.candidateIndexAtKeyLabelIndex(index) + if shouldAutoSelectCandidate { + let candidateIndex = ctlCandidateCurrent.candidateIndexAtKeyLabelIndex(0) if candidateIndex != Int.max { delegate!.keyHandler( - self, didSelectCandidateAt: candidateIndex, ctlCandidate: ctlCandidateCurrent + self, + didSelectCandidateAt: candidateIndex, + ctlCandidate: ctlCandidateCurrent + ) + clear() + let empty = InputState.EmptyIgnoringPreviousState() + stateCallback(empty) + return handle( + input: input, state: empty, stateCallback: stateCallback, errorCallback: errorCallback ) - return true } + return true } - - if state is InputState.AssociatedPhrases { return false } - - // MARK: SCPC Mode Processing - - if mgrPrefs.useSCPCTypingMode { - var punctuationNamePrefix = "" - - if input.isOptionHold && !input.isControlHold { - punctuationNamePrefix = "_alt_punctuation_" - } else if input.isControlHold && !input.isOptionHold { - punctuationNamePrefix = "_ctrl_punctuation_" - } else if input.isControlHold && input.isOptionHold { - punctuationNamePrefix = "_alt_ctrl_punctuation_" - } else if mgrPrefs.halfWidthPunctuationEnabled { - punctuationNamePrefix = "_half_punctuation_" - } else { - punctuationNamePrefix = "_punctuation_" - } - - let parser = currentMandarinParser - - let arrCustomPunctuations: [String] = [ - punctuationNamePrefix, parser, String(format: "%c", CChar(charCode)), - ] - let customPunctuation: String = arrCustomPunctuations.joined(separator: "") - - let arrPunctuations: [String] = [punctuationNamePrefix, String(format: "%c", CChar(charCode))] - let punctuation: String = arrPunctuations.joined(separator: "") - - var shouldAutoSelectCandidate: Bool = - _composer.inputValidityCheck(key: charCode) || ifLangModelHasUnigrams(forKey: customPunctuation) - || ifLangModelHasUnigrams(forKey: punctuation) - - if !shouldAutoSelectCandidate, input.isUpperCaseASCIILetterKey { - let letter: String! = String(format: "%@%c", "_letter_", CChar(charCode)) - if ifLangModelHasUnigrams(forKey: letter) { shouldAutoSelectCandidate = true } - } - - if shouldAutoSelectCandidate { - let candidateIndex = ctlCandidateCurrent.candidateIndexAtKeyLabelIndex(0) - if candidateIndex != Int.max { - delegate!.keyHandler( - self, - didSelectCandidateAt: candidateIndex, - ctlCandidate: ctlCandidateCurrent - ) - clear() - let empty = InputState.EmptyIgnoringPreviousState() - stateCallback(empty) - return handle( - input: input, state: empty, stateCallback: stateCallback, errorCallback: errorCallback - ) - } - return true - } - } - } // END: "if let ctlCandidateCurrent" + } IME.prtDebugIntel("172A0F81") errorCallback()