diff --git a/Source/Modules/ControllerModules/KeyHandler_Core.swift b/Source/Modules/ControllerModules/KeyHandler_Core.swift index 4ba339b2..519c8b30 100644 --- a/Source/Modules/ControllerModules/KeyHandler_Core.swift +++ b/Source/Modules/ControllerModules/KeyHandler_Core.swift @@ -43,11 +43,11 @@ protocol KeyHandlerDelegate { class KeyHandler { let kEpsilon: Double = 0.000001 let kMaxComposingBufferNeedsToWalkSize: Int = 10 - var _composer: Tekkon.Composer = .init() - var _languageModel: vChewing.LMInstantiator = .init() - var _userOverrideModel: vChewing.LMUserOverride = .init() - var _builder: Megrez.BlockReadingBuilder - var _walkedNodes: [Megrez.NodeAnchor] = [] + var composer: Tekkon.Composer = .init() + var compositor: Megrez.Compositor + var currentLM: vChewing.LMInstantiator = .init() + var currentUOM: vChewing.LMUserOverride = .init() + var walkedAnchors: [Megrez.NodeAnchor] = [] var delegate: KeyHandlerDelegate? @@ -59,29 +59,29 @@ class KeyHandler { let isCHS: Bool = (newValue == InputMode.imeModeCHS) // Reinitiate language models if necessary - _languageModel = isCHS ? mgrLangModel.lmCHS : mgrLangModel.lmCHT - _userOverrideModel = isCHS ? mgrLangModel.uomCHS : mgrLangModel.uomCHT + currentLM = isCHS ? mgrLangModel.lmCHS : mgrLangModel.lmCHT + currentUOM = isCHS ? mgrLangModel.uomCHS : mgrLangModel.uomCHT // Synchronize the sub-languageModel state settings to the new LM. syncBaseLMPrefs() // Create new grid builder and clear the composer. createNewBuilder() - _composer.clear() + composer.clear() } } public init() { - _builder = Megrez.BlockReadingBuilder(lm: _languageModel, separator: "-") + compositor = Megrez.Compositor(lm: currentLM, separator: "-") ensureParser() // 下面這句必須用 defer,否則不會觸發其 willSet 部分的內容。 defer { inputMode = IME.currentInputMode } } func clear() { - _composer.clear() - _builder.clear() - _walkedNodes.removeAll() + composer.clear() + compositor.clear() + walkedAnchors.removeAll() } // MARK: - Functions dealing with Megrez. @@ -91,11 +91,11 @@ class KeyHandler { // of the best possible Mandarin characters given the input syllables, // using the Viterbi algorithm implemented in the Megrez library. // The walk() traces the grid to the end. - _walkedNodes = _builder.walk() + walkedAnchors = compositor.walk() // if DEBUG mode is enabled, a GraphViz file is written to kGraphVizOutputfile. if mgrPrefs.isDebugModeEnabled { - let result = _builder.grid.dumpDOT + let result = compositor.grid.dumpDOT do { try result.write( toFile: "/private/var/tmp/vChewing-visualization.dot", @@ -117,13 +117,13 @@ class KeyHandler { // (i.e. popped out.) var poppedText = "" - if _builder.grid.width > mgrPrefs.composingBufferSize { - if !_walkedNodes.isEmpty { - let anchor: Megrez.NodeAnchor = _walkedNodes[0] + if compositor.grid.width > mgrPrefs.composingBufferSize { + if !walkedAnchors.isEmpty { + let anchor: Megrez.NodeAnchor = walkedAnchors[0] if let theNode = anchor.node { poppedText = theNode.currentKeyValue.value } - _builder.removeHeadReadings(count: anchor.spanningLength) + compositor.removeHeadReadings(count: anchor.spanningLength) } } walk() @@ -132,17 +132,17 @@ class KeyHandler { func buildAssociatePhraseArray(withKey key: String) -> [String] { var arrResult: [String] = [] - if _languageModel.hasAssociatedPhrasesForKey(key) { - arrResult.append(contentsOf: _languageModel.associatedPhrasesForKey(key)) + if currentLM.hasAssociatedPhrasesForKey(key) { + arrResult.append(contentsOf: currentLM.associatedPhrasesForKey(key)) } return arrResult } func fixNode(value: String, respectCursorPushing: Bool = true) { let cursorIndex = min(actualCandidateCursorIndex + (mgrPrefs.useRearCursorMode ? 1 : 0), builderLength) - _builder.grid.fixNodeSelectedCandidate(location: cursorIndex, value: value) + compositor.grid.fixNodeSelectedCandidate(location: cursorIndex, value: value) // // 因半衰模組失能,故禁用之。 - // let selectedNode: Megrez.NodeAnchor = _builder.grid.fixNodeSelectedCandidate( + // let selectedNode: Megrez.NodeAnchor = compositor.grid.fixNodeSelectedCandidate( // location: cursorIndex, value: value // ) // // 不要針對逐字選字模式啟用臨時半衰記憶模型。 @@ -166,8 +166,8 @@ class KeyHandler { // } // if addToUserOverrideModel { // IME.prtDebugIntel("UOM: Start Observation.") - // _userOverrideModel.observe( - // walkedNodes: _walkedNodes, cursorIndex: cursorIndex, candidate: value, + // currentUOM.observe( + // walkedNodes: walkedAnchors, cursorIndex: cursorIndex, candidate: value, // timestamp: NSDate().timeIntervalSince1970 // ) // } @@ -176,7 +176,7 @@ class KeyHandler { if mgrPrefs.moveCursorAfterSelectingCandidate, respectCursorPushing { var nextPosition = 0 - for node in _walkedNodes { + for node in walkedAnchors { if nextPosition >= cursorIndex { break } nextPosition += node.spanningLength } @@ -215,15 +215,15 @@ class KeyHandler { let overrideValue = mgrPrefs.useSCPCTypingMode ? "" - : _userOverrideModel.suggest( - walkedNodes: _walkedNodes, cursorIndex: builderCursorIndex, + : currentUOM.suggest( + walkedNodes: walkedAnchors, cursorIndex: builderCursorIndex, timestamp: NSDate().timeIntervalSince1970 ) if !overrideValue.isEmpty { IME.prtDebugIntel( "UOM: Suggestion retrieved, overriding the node score of the selected candidate.") - _builder.grid.overrideNodeScoreForSelectedCandidate( + compositor.grid.overrideNodeScoreForSelectedCandidate( location: min(actualCandidateCursorIndex + (mgrPrefs.useRearCursorMode ? 1 : 0), builderLength), value: overrideValue, overridingScore: findHighestScore(nodes: rawNodes, epsilon: kEpsilon) @@ -251,89 +251,89 @@ class KeyHandler { func ensureParser() { switch mgrPrefs.mandarinParser { case MandarinParser.ofStandard.rawValue: - _composer.ensureParser(arrange: .ofDachen) + composer.ensureParser(arrange: .ofDachen) case MandarinParser.ofDachen26.rawValue: - _composer.ensureParser(arrange: .ofDachen26) + composer.ensureParser(arrange: .ofDachen26) case MandarinParser.ofETen.rawValue: - _composer.ensureParser(arrange: .ofETen) + composer.ensureParser(arrange: .ofETen) case MandarinParser.ofHsu.rawValue: - _composer.ensureParser(arrange: .ofHsu) + composer.ensureParser(arrange: .ofHsu) case MandarinParser.ofETen26.rawValue: - _composer.ensureParser(arrange: .ofETen26) + composer.ensureParser(arrange: .ofETen26) case MandarinParser.ofIBM.rawValue: - _composer.ensureParser(arrange: .ofIBM) + composer.ensureParser(arrange: .ofIBM) case MandarinParser.ofMiTAC.rawValue: - _composer.ensureParser(arrange: .ofMiTAC) + composer.ensureParser(arrange: .ofMiTAC) case MandarinParser.ofFakeSeigyou.rawValue: - _composer.ensureParser(arrange: .ofFakeSeigyou) + composer.ensureParser(arrange: .ofFakeSeigyou) case MandarinParser.ofHanyuPinyin.rawValue: - _composer.ensureParser(arrange: .ofHanyuPinyin) + composer.ensureParser(arrange: .ofHanyuPinyin) case MandarinParser.ofSecondaryPinyin.rawValue: - _composer.ensureParser(arrange: .ofSecondaryPinyin) + composer.ensureParser(arrange: .ofSecondaryPinyin) case MandarinParser.ofYalePinyin.rawValue: - _composer.ensureParser(arrange: .ofYalePinyin) + composer.ensureParser(arrange: .ofYalePinyin) case MandarinParser.ofHualuoPinyin.rawValue: - _composer.ensureParser(arrange: .ofHualuoPinyin) + composer.ensureParser(arrange: .ofHualuoPinyin) case MandarinParser.ofUniversalPinyin.rawValue: - _composer.ensureParser(arrange: .ofUniversalPinyin) + composer.ensureParser(arrange: .ofUniversalPinyin) default: - _composer.ensureParser(arrange: .ofDachen) + composer.ensureParser(arrange: .ofDachen) mgrPrefs.mandarinParser = MandarinParser.ofStandard.rawValue } - _composer.clear() + composer.clear() } // MARK: - Extracted methods and functions (Megrez). - var isBuilderEmpty: Bool { _builder.grid.width == 0 } + var isBuilderEmpty: Bool { compositor.grid.width == 0 } var rawNodes: [Megrez.NodeAnchor] { /// 警告:不要對游標前置風格使用 nodesCrossing,否則會導致游標行為與 macOS 內建注音輸入法不一致。 /// 微軟新注音輸入法的游標後置風格也是不允許 nodeCrossing 的。 mgrPrefs.useRearCursorMode - ? _builder.grid.nodesBeginningAt(location: actualCandidateCursorIndex) - : _builder.grid.nodesEndingAt(location: actualCandidateCursorIndex) + ? compositor.grid.nodesBeginningAt(location: actualCandidateCursorIndex) + : compositor.grid.nodesEndingAt(location: actualCandidateCursorIndex) } func syncBaseLMPrefs() { - _languageModel.isPhraseReplacementEnabled = mgrPrefs.phraseReplacementEnabled - _languageModel.isCNSEnabled = mgrPrefs.cns11643Enabled - _languageModel.isSymbolEnabled = mgrPrefs.symbolInputEnabled + currentLM.isPhraseReplacementEnabled = mgrPrefs.phraseReplacementEnabled + currentLM.isCNSEnabled = mgrPrefs.cns11643Enabled + currentLM.isSymbolEnabled = mgrPrefs.symbolInputEnabled } func createNewBuilder() { // Each Mandarin syllable is separated by a hyphen. - _builder = Megrez.BlockReadingBuilder(lm: _languageModel, separator: "-") + compositor = Megrez.Compositor(lm: currentLM, separator: "-") } - var currentReadings: [String] { _builder.readings } + var currentReadings: [String] { compositor.readings } func ifLangModelHasUnigrams(forKey reading: String) -> Bool { - _languageModel.hasUnigramsFor(key: reading) + currentLM.hasUnigramsFor(key: reading) } func insertReadingToBuilderAtCursor(reading: String) { - _builder.insertReadingAtCursor(reading: reading) + compositor.insertReadingAtCursor(reading: reading) } var builderCursorIndex: Int { - get { _builder.cursorIndex } - set { _builder.cursorIndex = newValue } + get { compositor.cursorIndex } + set { compositor.cursorIndex = newValue } } var builderLength: Int { - _builder.length + compositor.length } func deleteBuilderReadingInFrontOfCursor() { - _builder.deleteReadingAtTheRearOfCursor() + compositor.deleteReadingAtTheRearOfCursor() } func deleteBuilderReadingToTheFrontOfCursor() { - _builder.deleteReadingToTheFrontOfCursor() + compositor.deleteReadingToTheFrontOfCursor() } var keyLengthAtIndexZero: Int { - _walkedNodes[0].node?.currentKeyValue.value.count ?? 0 + walkedAnchors[0].node?.currentKeyValue.value.count ?? 0 } } diff --git a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift index a57d3bc3..19447499 100644 --- a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift +++ b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift @@ -350,7 +350,7 @@ extension KeyHandler { let punctuation: String = arrPunctuations.joined(separator: "") var shouldAutoSelectCandidate: Bool = - _composer.inputValidityCheck(key: charCode) || ifLangModelHasUnigrams(forKey: customPunctuation) + composer.inputValidityCheck(key: charCode) || ifLangModelHasUnigrams(forKey: customPunctuation) || ifLangModelHasUnigrams(forKey: punctuation) if !shouldAutoSelectCandidate, input.isUpperCaseASCIILetterKey { diff --git a/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift b/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift index a0895d56..18d797e8 100644 --- a/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift +++ b/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift @@ -146,37 +146,37 @@ extension KeyHandler { let skipPhoneticHandling = input.isReservedKey || input.isControlHold || input.isOptionHold // See if Phonetic reading is valid. - if !skipPhoneticHandling && _composer.inputValidityCheck(key: charCode) { - _composer.receiveKey(fromCharCode: charCode) + if !skipPhoneticHandling && composer.inputValidityCheck(key: charCode) { + composer.receiveKey(fromCharCode: charCode) keyConsumedByReading = true // If we have a tone marker, we have to insert the reading to the // builder in other words, if we don't have a tone marker, we just // update the composing buffer. - let composeReading = _composer.hasToneMarker() + let composeReading = composer.hasToneMarker() if !composeReading { stateCallback(buildInputtingState) return true } } - var composeReading = _composer.hasToneMarker() // 這裡不需要做排他性判斷。 + var composeReading = composer.hasToneMarker() // 這裡不需要做排他性判斷。 // See if we have composition if Enter/Space is hit and buffer is not empty. // We use "|=" conditioning so that the tone marker key is also taken into account. // However, Swift does not support "|=". - composeReading = composeReading || (!_composer.isEmpty && (input.isSpace || input.isEnter)) + composeReading = composeReading || (!composer.isEmpty && (input.isSpace || input.isEnter)) if composeReading { - if input.isSpace, !_composer.hasToneMarker() { - _composer.receiveKey(fromString: " ") // 補上空格。 + if input.isSpace, !composer.hasToneMarker() { + composer.receiveKey(fromString: " ") // 補上空格。 } - let reading = _composer.getComposition() + let reading = composer.getComposition() // See whether we have a unigram for this... if !ifLangModelHasUnigrams(forKey: reading) { IME.prtDebugIntel("B49C0979:語彙庫內無「\(reading)」的匹配記錄。") errorCallback() - _composer.clear() + composer.clear() stateCallback((builderLength == 0) ? InputState.EmptyIgnoringPreviousState() : buildInputtingState) return true } @@ -191,7 +191,7 @@ extension KeyHandler { // dealWithOverrideModelSuggestions() // 暫時禁用,因為無法使其生效。 // ... then update the text. - _composer.clear() + composer.clear() let inputting = buildInputtingState inputting.poppedText = poppedText @@ -240,7 +240,7 @@ extension KeyHandler { // MARK: Calling candidate window using Up / Down or PageUp / PageDn. - if let currentState = state as? InputState.NotEmpty, _composer.isEmpty, + if let currentState = state as? InputState.NotEmpty, composer.isEmpty, input.isExtraChooseCandidateKey || input.isExtraChooseCandidateKeyReverse || input.isSpace || input.isPageDown || input.isPageUp || (input.isTab && mgrPrefs.specifyShiftTabKeyBehavior) || (input.isTypingVertical && (input.isverticalTypingOnlyChooseCandidateKey)) @@ -362,7 +362,7 @@ extension KeyHandler { if input.isSymbolMenuPhysicalKey && !input.isShiftHold { if input.isOptionHold { if ifLangModelHasUnigrams(forKey: "_punctuation_list") { - if _composer.isEmpty { + if composer.isEmpty { insertReadingToBuilderAtCursor(reading: "_punctuation_list") let poppedText: String! = popOverflowComposingTextAndWalk let inputting = buildInputtingState @@ -453,7 +453,7 @@ extension KeyHandler { // "thinking" that the key is not actually consumed. // 砍掉這一段會導致「F1-F12 按鍵干擾組字區」的問題。 // 暫時只能先恢復這段,且補上偵錯彙報機制,方便今後排查故障。 - if (state is InputState.NotEmpty) || !_composer.isEmpty { + if (state is InputState.NotEmpty) || !composer.isEmpty { IME.prtDebugIntel( "Blocked data: charCode: \(charCode), keyCode: \(input.keyCode)") IME.prtDebugIntel("A9BFF20E") diff --git a/Source/Modules/ControllerModules/KeyHandler_States.swift b/Source/Modules/ControllerModules/KeyHandler_States.swift index 6c516dbc..e0b76cca 100644 --- a/Source/Modules/ControllerModules/KeyHandler_States.swift +++ b/Source/Modules/ControllerModules/KeyHandler_States.swift @@ -41,7 +41,7 @@ extension KeyHandler { // We must do some Unicode codepoint counting to find the actual cursor location for the client // i.e. we need to take UTF-16 into consideration, for which a surrogate pair takes 2 UniChars // locations. Since we are using Swift, we use .utf16 as the equivalent of NSString.length(). - for walkedNode in _walkedNodes { + for walkedNode in walkedAnchors { if let theNode = walkedNode.node { let strNodeValue = theNode.currentKeyValue.value composingBuffer += strNodeValue @@ -78,14 +78,14 @@ extension KeyHandler { // Example in McBopomofo: Typing 王建民 (3 readings) gets a tree emoji. // Example in vChewing: Typing 義麵 (2 readings) gets a pasta emoji. switch builderCursorIndex { - case _builder.readings.count...: - tooltipParameterRef[0] = _builder.readings[_builder.readings.count - 1] + case compositor.readings.count...: + tooltipParameterRef[0] = compositor.readings[compositor.readings.count - 1] case 0: - tooltipParameterRef[1] = _builder.readings[builderCursorIndex] + tooltipParameterRef[1] = compositor.readings[builderCursorIndex] default: do { - tooltipParameterRef[0] = _builder.readings[builderCursorIndex - 1] - tooltipParameterRef[1] = _builder.readings[builderCursorIndex] + tooltipParameterRef[0] = compositor.readings[builderCursorIndex - 1] + tooltipParameterRef[1] = compositor.readings[builderCursorIndex] } } } @@ -109,7 +109,7 @@ extension KeyHandler { } let head = String(utf16CodeUnits: arrHead, count: arrHead.count) - let reading = _composer.getInlineCompositionForIMK(isHanyuPinyin: mgrPrefs.showHanyuPinyinInCompositionBuffer) + let reading = composer.getInlineCompositionForIMK(isHanyuPinyin: mgrPrefs.showHanyuPinyinInCompositionBuffer) let tail = String(utf16CodeUnits: arrTail, count: arrTail.count) let composedText = head + reading + tail let cursorIndex = composedStringCursorIndex + reading.utf16.count @@ -259,14 +259,14 @@ extension KeyHandler { return false } - if _composer.isEmpty { + if composer.isEmpty { insertReadingToBuilderAtCursor(reading: customPunctuation) let poppedText = popOverflowComposingTextAndWalk let inputting = buildInputtingState inputting.poppedText = poppedText stateCallback(inputting) - if mgrPrefs.useSCPCTypingMode, _composer.isEmpty { + if mgrPrefs.useSCPCTypingMode, composer.isEmpty { let candidateState = buildCandidate( state: inputting, isTypingVertical: isTypingVertical @@ -345,7 +345,7 @@ extension KeyHandler { var composed = "" - for theAnchor in _walkedNodes { + for theAnchor in walkedAnchors { if let node = theAnchor.node { var key = node.currentKeyValue.key if mgrPrefs.inlineDumpPinyinInLieuOfZhuyin { @@ -382,9 +382,9 @@ extension KeyHandler { ) -> Bool { guard state is InputState.Inputting else { return false } - if _composer.hasToneMarker(withNothingElse: true) { - _composer.clear() - } else if _composer.isEmpty { + if composer.hasToneMarker(withNothingElse: true) { + composer.clear() + } else if composer.isEmpty { if builderCursorIndex >= 0 { deleteBuilderReadingInFrontOfCursor() walk() @@ -395,10 +395,10 @@ extension KeyHandler { return true } } else { - _composer.doBackSpace() + composer.doBackSpace() } - if _composer.isEmpty, builderLength == 0 { + if composer.isEmpty, builderLength == 0 { stateCallback(InputState.EmptyIgnoringPreviousState()) } else { stateCallback(buildInputtingState) @@ -415,7 +415,7 @@ extension KeyHandler { ) -> Bool { guard state is InputState.Inputting else { return false } - if _composer.isEmpty { + if composer.isEmpty { if builderCursorIndex != builderLength { deleteBuilderReadingToTheFrontOfCursor() walk() @@ -448,7 +448,7 @@ extension KeyHandler { errorCallback: @escaping () -> Void ) -> Bool { guard state is InputState.Inputting else { return false } - if !_composer.isEmpty { + if !composer.isEmpty { IME.prtDebugIntel("9B6F908D") errorCallback() } @@ -465,7 +465,7 @@ extension KeyHandler { ) -> Bool { guard state is InputState.Inputting else { return false } - if !_composer.isEmpty { + if !composer.isEmpty { IME.prtDebugIntel("ABC44080") errorCallback() stateCallback(state) @@ -493,7 +493,7 @@ extension KeyHandler { ) -> Bool { guard state is InputState.Inputting else { return false } - if !_composer.isEmpty { + if !composer.isEmpty { IME.prtDebugIntel("9B69908D") errorCallback() stateCallback(state) @@ -532,8 +532,8 @@ extension KeyHandler { stateCallback(InputState.EmptyIgnoringPreviousState()) } else { // If reading is not empty, we cancel the reading. - if !_composer.isEmpty { - _composer.clear() + if !composer.isEmpty { + composer.clear() if builderLength == 0 { stateCallback(InputState.EmptyIgnoringPreviousState()) } else { @@ -554,7 +554,7 @@ extension KeyHandler { ) -> Bool { guard let currentState = state as? InputState.Inputting else { return false } - if !_composer.isEmpty { + if !composer.isEmpty { IME.prtDebugIntel("B3BA5257") errorCallback() stateCallback(state) @@ -603,7 +603,7 @@ extension KeyHandler { ) -> Bool { guard let currentState = state as? InputState.Inputting else { return false } - if !_composer.isEmpty { + if !composer.isEmpty { IME.prtDebugIntel("6ED95318") errorCallback() stateCallback(state) @@ -660,7 +660,7 @@ extension KeyHandler { return false } - guard _composer.isEmpty else { + guard composer.isEmpty else { IME.prtDebugIntel("A2DAF7BC") errorCallback() return true @@ -679,7 +679,7 @@ extension KeyHandler { let cursorIndex = min( actualCandidateCursorIndex + (mgrPrefs.useRearCursorMode ? 1 : 0), builderLength ) - for anchor in _walkedNodes { + for anchor in walkedAnchors { length += anchor.spanningLength if length >= cursorIndex { currentAnchor = anchor