diff --git a/DataCompiler/dataCompiler.swift b/DataCompiler/dataCompiler.swift index 5e0a97ee..8448ba6f 100644 --- a/DataCompiler/dataCompiler.swift +++ b/DataCompiler/dataCompiler.swift @@ -102,7 +102,7 @@ private let urlMiscNonKanji: String = "./components/common/char-misc-nonkanji.tx private let urlOutputCHS: String = "./data-chs.txt" private let urlOutputCHT: String = "./data-cht.txt" -// MARK: - 載入詞組檔案且輸出數組 +// MARK: - 載入詞組檔案且輸出陣列 func rawDictForPhrases(isCHS: Bool) -> [Entry] { var arrEntryRAW: [Entry] = [] @@ -181,7 +181,7 @@ func rawDictForPhrases(isCHS: Bool) -> [Entry] { return arrEntryRAW } -// MARK: - 載入單字檔案且輸出數組 +// MARK: - 載入單字檔案且輸出陣列 func rawDictForKanjis(isCHS: Bool) -> [Entry] { var arrEntryRAW: [Entry] = [] @@ -258,7 +258,7 @@ func rawDictForKanjis(isCHS: Bool) -> [Entry] { return arrEntryRAW } -// MARK: - 載入非漢字檔案且輸出數組 +// MARK: - 載入非漢字檔案且輸出陣列 func rawDictForNonKanjis(isCHS: Bool) -> [Entry] { var arrEntryRAW: [Entry] = [] diff --git a/README.md b/README.md index 09331239..e54d30af 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ ## 應用授權 -小麥注音引擎程式版權(MIT 授權):© 2011-2021 OpenVanilla 專案團隊。 +小麥注音引擎程式版權(MIT 授權):© 2011-2021 OpenVanilla 專案團隊(Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, 等)。 威注音輸入法 macOS 版以 MIT-NTL License 授權釋出 (與 MIT 相容):© 2021-2022 vChewing 專案。 diff --git a/Source/Data b/Source/Data index 42829b59..2d0c040a 160000 --- a/Source/Data +++ b/Source/Data @@ -1 +1 @@ -Subproject commit 42829b5969c6edfda6624d4073903ed41d88f14f +Subproject commit 2d0c040a95621f382a13664667fa5d1c43d172ee diff --git a/Source/Modules/ControllerModules/KeyHandler.h b/Source/Modules/ControllerModules/KeyHandler.h index 787f8e86..1c40ce61 100644 --- a/Source/Modules/ControllerModules/KeyHandler.h +++ b/Source/Modules/ControllerModules/KeyHandler.h @@ -59,8 +59,6 @@ struct BufferStatePackage - (void)fixNodeWithValue:(NSString *)value NS_SWIFT_NAME(fixNode(value:)); - (void)clear; -- (nullable InputState *)buildAssociatePhraseStateWithKey:(NSString *)key useVerticalMode:(BOOL)useVerticalMode; - @property(strong, nonatomic) InputMode inputMode; @property(weak, nonatomic) id delegate; @@ -74,6 +72,7 @@ struct BufferStatePackage - (BOOL)ifLangModelHasUnigramsForKey:(NSString *)reading; - (BOOL)isPhoneticReadingBufferEmpty; - (BOOL)isPrintable:(UniChar)charCode; +- (NSArray *)buildAssociatePhraseArrayWithKey:(NSString *)key; - (NSArray *)getCandidatesArray; - (NSInteger)getBuilderCursorIndex; - (NSInteger)getBuilderLength; diff --git a/Source/Modules/ControllerModules/KeyHandler.mm b/Source/Modules/ControllerModules/KeyHandler.mm index 503f188e..88d8a974 100644 --- a/Source/Modules/ControllerModules/KeyHandler.mm +++ b/Source/Modules/ControllerModules/KeyHandler.mm @@ -167,7 +167,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; // NON-SWIFTIFIABLE - (void)fixNodeWithValue:(NSString *)value { - NSInteger cursorIndex = [self _actualCandidateCursorIndex]; + NSInteger cursorIndex = [self getActualCandidateCursorIndex]; std::string stringValue(value.UTF8String); Gramambular::NodeAnchor selectedNode = _builder->grid().fixNodeSelectedCandidate(cursorIndex, stringValue); if (!mgrPrefs.useSCPCTypingMode) @@ -405,23 +405,20 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; } // NON-SWIFTIFIABLE -- (nullable InputState *)buildAssociatePhraseStateWithKey:(NSString *)key useVerticalMode:(BOOL)useVerticalMode +- (NSArray *)buildAssociatePhraseArrayWithKey:(NSString *)key { + NSMutableArray *array = [NSMutableArray array]; std::string cppKey = std::string(key.UTF8String); if (_languageModel->hasAssociatedPhrasesForKey(cppKey)) { std::vector phrases = _languageModel->associatedPhrasesForKey(cppKey); - NSMutableArray *array = [NSMutableArray array]; for (auto phrase : phrases) { NSString *item = [[NSString alloc] initWithUTF8String:phrase.c_str()]; [array addObject:item]; } - InputStateAssociatedPhrases *associatedPhrases = - [[InputStateAssociatedPhrases alloc] initWithCandidates:array useVerticalMode:useVerticalMode]; - return associatedPhrases; } - return nil; + return array; } #pragma mark - 必須用 ObjCpp 處理的部分: Mandarin @@ -558,6 +555,8 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; - (void)dealWithOverrideModelSuggestions { + // 讓 grid 知道目前的游標候選字判定是前置還是後置 + _builder->grid().setHaninInputEnabled(!mgrPrefs.selectPhraseAfterCursorAsCandidate); // 這一整段都太 C++ 且只出現一次,就整個端過來了。 // 拆開封裝的話,只會把問題搞得更麻煩而已。 std::string overrideValue = (mgrPrefs.useSCPCTypingMode) @@ -567,7 +566,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; if (!overrideValue.empty()) { - NSInteger cursorIndex = [self _actualCandidateCursorIndex]; + NSInteger cursorIndex = [self getActualCandidateCursorIndex]; std::vector nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex); double highestScore = FindHighestScore(nodes, kEpsilon); _builder->grid().overrideNodeScoreForSelectedCandidate(cursorIndex, overrideValue, @@ -602,9 +601,12 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; - (NSArray *)getCandidatesArray { + // 讓 grid 知道目前的游標候選字判定是前置還是後置 + _builder->grid().setHaninInputEnabled(!mgrPrefs.selectPhraseAfterCursorAsCandidate); + NSMutableArray *candidatesArray = [[NSMutableArray alloc] init]; - NSInteger cursorIndex = [self _actualCandidateCursorIndex]; + NSInteger cursorIndex = [self getActualCandidateCursorIndex]; std::vector nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex); // sort the nodes, so that longer nodes (representing longer phrases) are placed at the top of the candidate list diff --git a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift index ac892219..42746492 100644 --- a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift +++ b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift @@ -2,357 +2,362 @@ // Refactored from the ObjCpp-version of this class by: // (c) 2011 and onwards The OpenVanilla Project (MIT License). /* - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - the Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: - 1. The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. +1. The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - 2. No trademark license is granted to use the trade names, trademarks, service - marks, or product names of Contributor, except as required to fulfill notice - requirements above. +2. No trademark license is granted to use the trade names, trademarks, service +marks, or product names of Contributor, except as required to fulfill notice +requirements above. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ import Cocoa // MARK: - § Handle Candidate State. @objc extension KeyHandler { - func _handleCandidateState( - _ state: InputState, + func handleCandidate( + state: InputState, input: InputHandler, stateCallback: @escaping (InputState) -> Void, errorCallback: @escaping () -> Void ) -> Bool { let inputText = input.inputText let charCode: UniChar = input.charCode - let ctlCandidateCurrent = delegate!.ctlCandidate(for: self) as! ctlCandidate + if let ctlCandidateCurrent = delegate!.ctlCandidate(for: self) as? ctlCandidate { + // MARK: Cancel Candidate - // MARK: Cancel Candidate + let cancelCandidateKey = + input.isBackSpace || input.isESC || input.isDelete + || ((input.isCursorBackward || input.isCursorForward) && input.isShiftHold) - 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()) + if cancelCandidateKey { + if (state is InputState.AssociatedPhrases) + || mgrPrefs.useSCPCTypingMode + || isBuilderEmpty() + { + // 如果此時發現當前組字緩衝區為真空的情況的話, + // 就將當前的組字緩衝區析構處理、強制重設輸入狀態。 + // 否則,一個本不該出現的真空組字緩衝區會使前後方向鍵與 BackSpace 鍵失靈。 + // 所以這裡需要對 isBuilderEmpty() 做判定。 + clear() + stateCallback(InputState.EmptyIgnoringPreviousState()) + } else { + stateCallback(buildInputtingState()) + } return true } - delegate!.keyHandler( - self, - didSelectCandidateAt: Int(ctlCandidateCurrent.selectedCandidateIndex), - ctlCandidate: ctlCandidateCurrent - ) - return true - } - // MARK: Tab + // MARK: Enter - 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() + if input.isEnter { + if state is InputState.AssociatedPhrases { + clear() + stateCallback(InputState.EmptyIgnoringPreviousState()) + return true + } + delegate!.keyHandler( + self, + didSelectCandidateAt: Int(ctlCandidateCurrent.selectedCandidateIndex), + ctlCandidate: ctlCandidateCurrent + ) + return true } - return true - } - // MARK: Space + // MARK: Tab - 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 { - if ctlCandidateCurrent is ctlCandidateHorizontal { - let updated: Bool = ctlCandidateCurrent.highlightPreviousCandidate() + if input.isTab { + let updated: Bool = + mgrPrefs.specifyShiftTabKeyBehavior + ? (input.isShiftHold + ? ctlCandidateCurrent.showPreviousPage() + : ctlCandidateCurrent.showNextPage()) + : (input.isShiftHold + ? ctlCandidateCurrent.highlightPreviousCandidate() + : ctlCandidateCurrent.highlightNextCandidate()) if !updated { - IME.prtDebugIntel("1145148D") + IME.prtDebugIntel("9B691919") errorCallback() } - } else { - let updated: Bool = ctlCandidateCurrent.showPreviousPage() + 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("1919810D") + IME.prtDebugIntel("A11C781F") errorCallback() } + return true } - return true - } - // MARK: EmacsKey Backward + // MARK: PgDn - if input.emacsKey == vChewingEmacsKey.backward { - let updated: Bool = ctlCandidateCurrent.highlightPreviousCandidate() - if !updated { - IME.prtDebugIntel("9B89308D") - errorCallback() - } - return true - } - - // MARK: Right Arrow - - if input.isRight { - if ctlCandidateCurrent is ctlCandidateHorizontal { - let updated: Bool = ctlCandidateCurrent.highlightNextCandidate() - if !updated { - IME.prtDebugIntel("9B65138D") - errorCallback() - } - } else { + if input.isPageDown || input.emacsKey == vChewingEmacsKey.nextPage { let updated: Bool = ctlCandidateCurrent.showNextPage() if !updated { - IME.prtDebugIntel("9244908D") + IME.prtDebugIntel("9B691919") errorCallback() } + return true } - return true - } - // MARK: EmacsKey Forward + // MARK: PgUp - if input.emacsKey == vChewingEmacsKey.forward { - let updated: Bool = ctlCandidateCurrent.highlightNextCandidate() - if !updated { - IME.prtDebugIntel("9B2428D") - errorCallback() - } - return true - } - - // MARK: Up Arrow - - if input.isUp { - if ctlCandidateCurrent is ctlCandidateHorizontal { + if input.isPageUp { let updated: Bool = ctlCandidateCurrent.showPreviousPage() if !updated { - IME.prtDebugIntel("9B614524") + IME.prtDebugIntel("9569955D") errorCallback() } - } else { + return true + } + + // MARK: Left Arrow + + if input.isLeft { + if ctlCandidateCurrent is ctlCandidateHorizontal { + let updated: Bool = ctlCandidateCurrent.highlightPreviousCandidate() + if !updated { + IME.prtDebugIntel("1145148D") + errorCallback() + } + } else { + let updated: Bool = ctlCandidateCurrent.showPreviousPage() + if !updated { + IME.prtDebugIntel("1919810D") + errorCallback() + } + } + return true + } + + // MARK: EmacsKey Backward + + if input.emacsKey == vChewingEmacsKey.backward { let updated: Bool = ctlCandidateCurrent.highlightPreviousCandidate() if !updated { - IME.prtDebugIntel("ASD9908D") + IME.prtDebugIntel("9B89308D") errorCallback() } + return true } - return true - } - // MARK: Down Arrow + // MARK: Right Arrow - if input.isDown { - if ctlCandidateCurrent is ctlCandidateHorizontal { - let updated: Bool = ctlCandidateCurrent.showNextPage() - if !updated { - IME.prtDebugIntel("92B990DD") - errorCallback() + if input.isRight { + if ctlCandidateCurrent is ctlCandidateHorizontal { + let updated: Bool = ctlCandidateCurrent.highlightNextCandidate() + if !updated { + IME.prtDebugIntel("9B65138D") + errorCallback() + } + } else { + let updated: Bool = ctlCandidateCurrent.showNextPage() + if !updated { + IME.prtDebugIntel("9244908D") + errorCallback() + } } - } else { + return true + } + + // MARK: EmacsKey Forward + + if input.emacsKey == vChewingEmacsKey.forward { let updated: Bool = ctlCandidateCurrent.highlightNextCandidate() if !updated { - IME.prtDebugIntel("6B99908D") + IME.prtDebugIntel("9B2428D") 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 } - return true - } + // MARK: Up Arrow - var candidates: [String]! + if input.isUp { + if ctlCandidateCurrent is ctlCandidateHorizontal { + let updated: Bool = ctlCandidateCurrent.showPreviousPage() + if !updated { + IME.prtDebugIntel("9B614524") + errorCallback() + } + } else { + let updated: Bool = ctlCandidateCurrent.highlightPreviousCandidate() + if !updated { + IME.prtDebugIntel("ASD9908D") + errorCallback() + } + } + return true + } - if state is InputState.ChoosingCandidate { - candidates = (state as! InputState.ChoosingCandidate).candidates - } else if state is InputState.AssociatedPhrases { - candidates = (state as! InputState.AssociatedPhrases).candidates - } + // MARK: Down Arrow - // MARK: End Key + if input.isDown { + if ctlCandidateCurrent is ctlCandidateHorizontal { + let updated: Bool = ctlCandidateCurrent.showNextPage() + if !updated { + IME.prtDebugIntel("92B990DD") + errorCallback() + } + } else { + let updated: Bool = ctlCandidateCurrent.highlightNextCandidate() + if !updated { + IME.prtDebugIntel("6B99908D") + errorCallback() + } + } + return true + } - if candidates.isEmpty { - return false - } else { // 這裡不用「count > 0」,因為該整數變數只要「!isEmpty」那就必定滿足這個條件。 - if input.isEnd || input.emacsKey == vChewingEmacsKey.end { - if ctlCandidateCurrent.selectedCandidateIndex == UInt(candidates.count - 1) { - IME.prtDebugIntel("9B69AAAD") + // MARK: Home Key + + if input.isHome || input.emacsKey == vChewingEmacsKey.home { + if ctlCandidateCurrent.selectedCandidateIndex == 0 { + IME.prtDebugIntel("9B6EDE8D") errorCallback() } else { - ctlCandidateCurrent.selectedCandidateIndex = UInt(candidates.count - 1) + ctlCandidateCurrent.selectedCandidateIndex = 0 } + return true } - } - // MARK: - Associated Phrases + // MARK: End Key - if state is InputState.AssociatedPhrases { - if !input.isShiftHold { return false } - } + var candidates: [String]! - 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 + if let state = state as? InputState.ChoosingCandidate { + candidates = state.candidates + } else if let state = state as? InputState.AssociatedPhrases { + candidates = state.candidates } - j += 1 - } - if index != NSNotFound { - let candidateIndex: UInt = ctlCandidateCurrent.candidateIndexAtKeyLabelIndex(UInt(index)) - if candidateIndex != UInt.max { - delegate!.keyHandler(self, didSelectCandidateAt: Int(candidateIndex), ctlCandidate: ctlCandidateCurrent) - return true + if candidates.isEmpty { + return false + } else { // 這裡不用「count > 0」,因為該整數變數只要「!isEmpty」那就必定滿足這個條件。 + if input.isEnd || input.emacsKey == vChewingEmacsKey.end { + if ctlCandidateCurrent.selectedCandidateIndex == UInt(candidates.count - 1) { + IME.prtDebugIntel("9B69AAAD") + errorCallback() + } else { + ctlCandidateCurrent.selectedCandidateIndex = UInt(candidates.count - 1) + } + } } - } - if state is InputState.AssociatedPhrases { return false } + // MARK: - Associated Phrases - // MARK: SCPC Mode Processing + if state is InputState.AssociatedPhrases { + if !input.isShiftHold { return false } + } - if mgrPrefs.useSCPCTypingMode { - var punctuationNamePrefix = "" - - if input.isOptionHold { - punctuationNamePrefix = "_alt_punctuation_" - } else if input.isControlHold { - punctuationNamePrefix = "_ctrl_punctuation_" - } else if mgrPrefs.halfWidthPunctuationEnabled { - punctuationNamePrefix = "_half_punctuation_" + var index: Int = NSNotFound + var match: String! + if state is InputState.AssociatedPhrases { + match = input.inputTextIgnoringModifiers } else { - punctuationNamePrefix = "_punctuation_" + match = inputText } - let parser = getCurrentMandarinParser() - - 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 = - chkKeyValidity(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 } + 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 shouldAutoSelectCandidate { - let candidateIndex: UInt = ctlCandidateCurrent.candidateIndexAtKeyLabelIndex(0) + if index != NSNotFound { + let candidateIndex: UInt = ctlCandidateCurrent.candidateIndexAtKeyLabelIndex(UInt(index)) if candidateIndex != UInt.max { delegate!.keyHandler( - self, - didSelectCandidateAt: Int(candidateIndex), - ctlCandidate: ctlCandidateCurrent - ) - clear() - let empty = InputState.EmptyIgnoringPreviousState() - stateCallback(empty) - return handle( - input: input, state: empty, stateCallback: stateCallback, errorCallback: errorCallback + self, didSelectCandidateAt: Int(candidateIndex), ctlCandidate: ctlCandidateCurrent ) + return true } - return true } - } + + if state is InputState.AssociatedPhrases { return false } + + // MARK: SCPC Mode Processing + + if mgrPrefs.useSCPCTypingMode { + var punctuationNamePrefix = "" + + if input.isOptionHold { + punctuationNamePrefix = "_alt_punctuation_" + } else if input.isControlHold { + punctuationNamePrefix = "_ctrl_punctuation_" + } else if mgrPrefs.halfWidthPunctuationEnabled { + punctuationNamePrefix = "_half_punctuation_" + } else { + punctuationNamePrefix = "_punctuation_" + } + + let parser = getCurrentMandarinParser() + + 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 = + chkKeyValidity(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: UInt = ctlCandidateCurrent.candidateIndexAtKeyLabelIndex(0) + if candidateIndex != UInt.max { + delegate!.keyHandler( + self, + didSelectCandidateAt: Int(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() diff --git a/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift b/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift index 2d60b22a..39dac754 100644 --- a/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift +++ b/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift @@ -80,8 +80,7 @@ import Cocoa } // Commit the entire input buffer. - let committingState = InputState.Committing(poppedText: inputText.lowercased()) - stateCallback(committingState) + stateCallback(InputState.Committing(poppedText: inputText.lowercased())) stateCallback(InputState.Empty()) return true @@ -95,8 +94,7 @@ import Cocoa { clear() stateCallback(InputState.Empty()) - let committing = InputState.Committing(poppedText: inputText.lowercased()) - stateCallback(committing) + stateCallback(InputState.Committing(poppedText: inputText.lowercased())) stateCallback(InputState.Empty()) return true } @@ -105,18 +103,17 @@ import Cocoa // MARK: Handle Candidates. if state is InputState.ChoosingCandidate { - return _handleCandidateState( - state, input: input, stateCallback: stateCallback, errorCallback: errorCallback + return handleCandidate( + state: state, input: input, stateCallback: stateCallback, errorCallback: errorCallback ) } // MARK: Handle Associated Phrases. if state is InputState.AssociatedPhrases { - let result = _handleCandidateState( - state, input: input, stateCallback: stateCallback, errorCallback: errorCallback - ) - if result { + if handleCandidate( + state: state, input: input, stateCallback: stateCallback, errorCallback: errorCallback + ) { return true } else { stateCallback(InputState.Empty()) @@ -125,16 +122,13 @@ import Cocoa // MARK: Handle Marking. - if state is InputState.Marking { - let marking = state as! InputState.Marking - - if _handleMarkingState( - state as! InputState.Marking, input: input, stateCallback: stateCallback, + if let marking = state as? InputState.Marking { + if handleMarkingState( + marking, input: input, stateCallback: stateCallback, errorCallback: errorCallback ) { return true } - state = marking.convertToInputting() stateCallback(state) } @@ -153,8 +147,7 @@ import Cocoa // update the composing buffer. composeReading = checkWhetherToneMarkerConfirmsPhoneticReadingBuffer() if !composeReading { - let inputting = buildInputtingState() - stateCallback(inputting) + stateCallback(buildInputtingState()) return true } } @@ -169,8 +162,7 @@ import Cocoa if !ifLangModelHasUnigrams(forKey: reading) { IME.prtDebugIntel("B49C0979") errorCallback() - let inputting = buildInputtingState() - stateCallback(inputting) + stateCallback(buildInputtingState()) return true } @@ -191,25 +183,24 @@ import Cocoa stateCallback(inputting) if mgrPrefs.useSCPCTypingMode { - let choosingCandidates: InputState.ChoosingCandidate = _buildCandidateState( - inputting, + let choosingCandidates: InputState.ChoosingCandidate = buildCandidate( + state: inputting, useVerticalMode: input.useVerticalMode ) if choosingCandidates.candidates.count == 1 { clear() let text: String = choosingCandidates.candidates.first ?? "" - let committing = InputState.Committing(poppedText: text) - stateCallback(committing) + stateCallback(InputState.Committing(poppedText: text)) if !mgrPrefs.associatedPhrasesEnabled { stateCallback(InputState.Empty()) } else { - let associatedPhrases = + if let associatedPhrases = buildAssociatePhraseState( withKey: text, useVerticalMode: input.useVerticalMode - ) as? InputState.AssociatedPhrases - if let associatedPhrases = associatedPhrases { + ), !associatedPhrases.candidates.isEmpty + { stateCallback(associatedPhrases) } else { stateCallback(InputState.Empty()) @@ -224,54 +215,49 @@ import Cocoa // MARK: Calling candidate window using Space or Down or PageUp / PageDn. - if isPhoneticReadingBufferEmpty() && (state is InputState.NotEmpty) - && (input.isExtraChooseCandidateKey || input.isExtraChooseCandidateKeyReverse || input.isSpace - || input.isPageDown || input.isPageUp || input.isTab - || (input.useVerticalMode && (input.isVerticalModeOnlyChooseCandidateKey))) - { - if input.isSpace { - // If the Space key is NOT set to be a selection key - if input.isShiftHold || !mgrPrefs.chooseCandidateUsingSpace { - if getBuilderCursorIndex() >= getBuilderLength() { - let composingBuffer = (state as! InputState.NotEmpty).composingBuffer - if (composingBuffer.count) != 0 { - let committing = InputState.Committing(poppedText: composingBuffer) - stateCallback(committing) + if let currentState = state as? InputState.NotEmpty { + if isPhoneticReadingBufferEmpty(), + input.isExtraChooseCandidateKey || input.isExtraChooseCandidateKeyReverse || input.isSpace + || input.isPageDown || input.isPageUp || input.isTab + || (input.useVerticalMode && (input.isVerticalModeOnlyChooseCandidateKey)) + { + if input.isSpace { + // If the Space key is NOT set to be a selection key + if input.isShiftHold || !mgrPrefs.chooseCandidateUsingSpace { + if getBuilderCursorIndex() >= getBuilderLength() { + let composingBuffer = currentState.composingBuffer + if (composingBuffer.count) != 0 { + stateCallback(InputState.Committing(poppedText: composingBuffer)) + } + clear() + stateCallback(InputState.Committing(poppedText: " ")) + stateCallback(InputState.Empty()) + } else if ifLangModelHasUnigrams(forKey: " ") { + insertReadingToBuilder(atCursor: " ") + let poppedText = _popOverflowComposingTextAndWalk() + let inputting = buildInputtingState() + inputting.poppedText = poppedText + stateCallback(inputting) } - clear() - let committing = InputState.Committing(poppedText: " ") - stateCallback(committing) - let empty = InputState.Empty() - stateCallback(empty) - } else if ifLangModelHasUnigrams(forKey: " ") { - insertReadingToBuilder(atCursor: " ") - let poppedText = _popOverflowComposingTextAndWalk() - let inputting = buildInputtingState() - inputting.poppedText = poppedText - stateCallback(inputting) + return true } - return true } + stateCallback(buildCandidate(state: currentState, useVerticalMode: input.useVerticalMode)) + return true } - let choosingCandidates = _buildCandidateState( - state as! InputState.NotEmpty, - useVerticalMode: input.useVerticalMode - ) - stateCallback(choosingCandidates) - return true } // MARK: - // MARK: Esc - if input.isESC { return _handleEscWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) } + if input.isESC { return handleEsc(state: state, stateCallback: stateCallback, errorCallback: errorCallback) } // MARK: Cursor backward if input.isCursorBackward || input.emacsKey == vChewingEmacsKey.backward { - return _handleBackwardWithState( - state, + return handleBackward( + state: state, input: input, stateCallback: stateCallback, errorCallback: errorCallback @@ -281,59 +267,59 @@ import Cocoa // MARK: Cursor forward if input.isCursorForward || input.emacsKey == vChewingEmacsKey.forward { - return _handleForwardWithState( - state, input: input, stateCallback: stateCallback, errorCallback: errorCallback + return handleForward( + state: state, input: input, stateCallback: stateCallback, errorCallback: errorCallback ) } // MARK: Home if input.isHome || input.emacsKey == vChewingEmacsKey.home { - return _handleHomeWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) + return handleHome(state: state, stateCallback: stateCallback, errorCallback: errorCallback) } // MARK: End if input.isEnd || input.emacsKey == vChewingEmacsKey.end { - return _handleEndWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) + return handleEnd(state: state, stateCallback: stateCallback, errorCallback: errorCallback) } // MARK: Ctrl+PgLf or Shift+PgLf if (input.isControlHold || input.isShiftHold) && (input.isOptionHold && input.isLeft) { - return _handleHomeWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) + return handleHome(state: state, stateCallback: stateCallback, errorCallback: errorCallback) } // MARK: Ctrl+PgRt or Shift+PgRt if (input.isControlHold || input.isShiftHold) && (input.isOptionHold && input.isRight) { - return _handleEndWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) + return handleEnd(state: state, stateCallback: stateCallback, errorCallback: errorCallback) } // MARK: AbsorbedArrowKey if input.isAbsorbedArrowKey || input.isExtraChooseCandidateKey || input.isExtraChooseCandidateKeyReverse { - return _handleAbsorbedArrowKeyWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) + return handleAbsorbedArrowKey(state: state, stateCallback: stateCallback, errorCallback: errorCallback) } // MARK: Backspace if input.isBackSpace { - return _handleBackspaceWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) + return handleBackspace(state: state, stateCallback: stateCallback, errorCallback: errorCallback) } // MARK: Delete if input.isDelete || input.emacsKey == vChewingEmacsKey.delete { - return _handleDeleteWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) + return handleDelete(state: state, stateCallback: stateCallback, errorCallback: errorCallback) } // MARK: Enter if input.isEnter { return (input.isCommandHold && input.isControlHold) - ? _handleCtrlCommandEnterWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) - : _handleEnterWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) + ? handleCtrlCommandEnter(state: state, stateCallback: stateCallback, errorCallback: errorCallback) + : handleEnter(state: state, stateCallback: stateCallback, errorCallback: errorCallback) } // MARK: - @@ -349,9 +335,7 @@ import Cocoa let inputting = buildInputtingState() inputting.poppedText = poppedText stateCallback(inputting) - let choosingCandidate = - _buildCandidateState(inputting, useVerticalMode: input.useVerticalMode) - stateCallback(choosingCandidate) + stateCallback(buildCandidate(state: inputting, useVerticalMode: input.useVerticalMode)) } else { // If there is still unfinished bpmf reading, ignore the punctuation IME.prtDebugIntel("17446655") errorCallback() @@ -362,11 +346,8 @@ import Cocoa // 得在這裡先 commit buffer,不然會導致「在摁 ESC 離開符號選單時會重複輸入上一次的組字區的內容」的不當行為。 // 於是這裡用「模擬一次 Enter 鍵的操作」使其代為執行這個 commit buffer 的動作。 // 這裡不需要該函數所傳回的 bool 結果,所以用「_ =」解消掉。 - _ = _handleEnterWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) - let root: SymbolNode! = SymbolNode.root - let symbolState = - InputState.SymbolTable(node: root, useVerticalMode: input.useVerticalMode) - stateCallback(symbolState) + _ = handleEnter(state: state, stateCallback: stateCallback, errorCallback: errorCallback) + stateCallback(InputState.SymbolTable(node: SymbolNode.root, useVerticalMode: input.useVerticalMode)) return true } } @@ -392,7 +373,7 @@ import Cocoa punctuationNamePrefix, parser, String(format: "%c", CChar(charCode)), ] let customPunctuation: String = arrCustomPunctuations.joined(separator: "") - if _handlePunctuation( + if handlePunctuation( customPunctuation, state: state, usingVerticalMode: input.useVerticalMode, @@ -406,7 +387,7 @@ import Cocoa let arrPunctuations: [String] = [punctuationNamePrefix, String(format: "%c", CChar(charCode))] let punctuation: String = arrPunctuations.joined(separator: "") - if _handlePunctuation( + if handlePunctuation( punctuation, state: state, usingVerticalMode: input.useVerticalMode, @@ -419,7 +400,7 @@ import Cocoa // 這裡不使用小麥注音 2.2 版的組字區處理方式,而是直接由詞庫負責。 if input.isUpperCaseASCIILetterKey { let letter: String! = String(format: "%@%c", "_letter_", CChar(charCode)) - if _handlePunctuation( + if handlePunctuation( letter, state: state, usingVerticalMode: input.useVerticalMode, diff --git a/Source/Modules/ControllerModules/KeyHandler_Misc.swift b/Source/Modules/ControllerModules/KeyHandler_Misc.swift index 9abf05b2..9228d065 100644 --- a/Source/Modules/ControllerModules/KeyHandler_Misc.swift +++ b/Source/Modules/ControllerModules/KeyHandler_Misc.swift @@ -33,7 +33,7 @@ import Cocoa mgrPrefs.mandarinParserName + "_" } - func _actualCandidateCursorIndex() -> Int { + func getActualCandidateCursorIndex() -> Int { var cursorIndex = getBuilderCursorIndex() // MS Phonetics IME style, phrase is *after* the cursor. // (i.e. the cursor is always *before* the phrase.) diff --git a/Source/Modules/ControllerModules/KeyHandler_States.swift b/Source/Modules/ControllerModules/KeyHandler_States.swift index 488d05ef..06258158 100644 --- a/Source/Modules/ControllerModules/KeyHandler_States.swift +++ b/Source/Modules/ControllerModules/KeyHandler_States.swift @@ -32,7 +32,7 @@ import Cocoa // MARK: - 構築狀態(State Building) func buildInputtingState() -> InputState.Inputting { - // 觸發資料封裝更新,否則下文拿到的數據會是錯的。 + // 觸發資料封裝更新,否則下文拿到的資料會是過期的。 packageBufferStateMaterials() // 獲取封裝好的資料 let composedText = getComposedText() @@ -63,34 +63,48 @@ import Cocoa return newState } - // MARK: - 用以生成候選詞數組 + // MARK: - 用以生成候選詞陣列及狀態 - func _buildCandidateState( - _ currentState: InputState.NotEmpty, + func buildCandidate( + state currentState: InputState.NotEmpty, useVerticalMode: Bool ) -> InputState.ChoosingCandidate { - let candidatesArray = getCandidatesArray() - - let state = InputState.ChoosingCandidate( + InputState.ChoosingCandidate( composingBuffer: currentState.composingBuffer, cursorIndex: currentState.cursorIndex, - candidates: candidatesArray, + candidates: getCandidatesArray(), useVerticalMode: useVerticalMode ) - return state + } + + // MARK: - 用以接收聯想詞陣列且生成狀態 + + // 這次重寫時,針對「buildAssociatePhraseStateWithKey」這個(用以生成帶有 + // 聯想詞候選清單的結果的狀態回呼的)函數進行了小幅度的重構處理,使其始終 + // 可以從 ObjC 部分的「buildAssociatePhraseArray」函數獲取到一個內容類型 + // 為「String」的標準 Swift 陣列。這樣一來,該聯想詞狀態回呼函數將始終能 + // 夠傳回正確的結果形態、永遠也無法傳回 nil。於是,所有在用到該函數時以 + // 回傳結果類型判斷作為合法性判斷依據的函數,全都將依據改為檢查傳回的陣列 + // 是否為空:如果陣列為空的話,直接回呼一個空狀態。 + func buildAssociatePhraseState( + withKey key: String!, + useVerticalMode: Bool + ) -> InputState.AssociatedPhrases! { + // 上一行必須要用驚嘆號,否則 Xcode 會誤導你砍掉某些實際上必需的語句。 + InputState.AssociatedPhrases( + candidates: buildAssociatePhraseArray(withKey: key), useVerticalMode: useVerticalMode) } // MARK: - 用以處理就地新增自訂語彙時的行為 - func _handleMarkingState( + func handleMarkingState( _ state: InputState.Marking, input: InputHandler, stateCallback: @escaping (InputState) -> Void, errorCallback: @escaping () -> Void ) -> Bool { if input.isESC { - let inputting = buildInputtingState() - stateCallback(inputting) + stateCallback(buildInputtingState()) return true } @@ -103,9 +117,7 @@ import Cocoa return true } } - - let inputting = buildInputtingState() - stateCallback(inputting) + stateCallback(buildInputtingState()) return true } @@ -121,13 +133,7 @@ import Cocoa readings: state.readings ) marking.tooltipForInputting = state.tooltipForInputting - - if marking.markedRange.length == 0 { - let inputting = marking.convertToInputting() - stateCallback(inputting) - } else { - stateCallback(marking) - } + stateCallback(marking.markedRange.length == 0 ? marking.convertToInputting() : marking) } else { IME.prtDebugIntel("1149908D") errorCallback() @@ -150,12 +156,7 @@ import Cocoa readings: state.readings ) marking.tooltipForInputting = state.tooltipForInputting - if marking.markedRange.length == 0 { - let inputting = marking.convertToInputting() - stateCallback(inputting) - } else { - stateCallback(marking) - } + stateCallback(marking.markedRange.length == 0 ? marking.convertToInputting() : marking) } else { IME.prtDebugIntel("9B51408D") errorCallback() @@ -168,7 +169,7 @@ import Cocoa // MARK: - 標點輸入處理 - func _handlePunctuation( + func handlePunctuation( _ customPunctuation: String, state: InputState, usingVerticalMode useVerticalMode: Bool, @@ -187,17 +188,15 @@ import Cocoa stateCallback(inputting) if mgrPrefs.useSCPCTypingMode, isPhoneticReadingBufferEmpty() { - let candidateState = _buildCandidateState( - inputting, useVerticalMode: useVerticalMode + let candidateState = buildCandidate( + state: inputting, + useVerticalMode: useVerticalMode ) if candidateState.candidates.count == 1 { clear() if let strPoppedText: String = candidateState.candidates.first { - let committing = - InputState.Committing(poppedText: strPoppedText) as InputState.Committing - stateCallback(committing) - let empty = InputState.Empty() - stateCallback(empty) + stateCallback(InputState.Committing(poppedText: strPoppedText) as InputState.Committing) + stateCallback(InputState.Empty()) } else { stateCallback(candidateState) } @@ -217,8 +216,8 @@ import Cocoa // MARK: - Enter 鍵處理 - @discardableResult func _handleEnterWithState( - _ state: InputState, + func handleEnter( + state: InputState, stateCallback: @escaping (InputState) -> Void, errorCallback _: @escaping () -> Void ) -> Bool { @@ -228,20 +227,18 @@ import Cocoa clear() - let current = state as! InputState.Inputting - let composingBuffer = current.composingBuffer + if let current = state as? InputState.Inputting { + stateCallback(InputState.Committing(poppedText: current.composingBuffer)) + } - let committing = InputState.Committing(poppedText: composingBuffer) - stateCallback(committing) - let empty = InputState.Empty() - stateCallback(empty) + stateCallback(InputState.Empty()) return true } // MARK: - CMD+Enter 鍵處理 - func _handleCtrlCommandEnterWithState( - _ state: InputState, + func handleCtrlCommandEnter( + state: InputState, stateCallback: @escaping (InputState) -> Void, errorCallback _: @escaping () -> Void ) -> Bool { @@ -257,17 +254,15 @@ import Cocoa clear() - let committing = InputState.Committing(poppedText: composingBuffer) - stateCallback(committing) - let empty = InputState.Empty() - stateCallback(empty) + stateCallback(InputState.Committing(poppedText: composingBuffer)) + stateCallback(InputState.Empty()) return true } // MARK: - 處理 Backspace (macOS Delete) 按鍵行為 - func _handleBackspaceWithState( - _ state: InputState, + func handleBackspace( + state: InputState, stateCallback: @escaping (InputState) -> Void, errorCallback: @escaping () -> Void ) -> Bool { @@ -290,19 +285,17 @@ import Cocoa } if isPhoneticReadingBufferEmpty(), getBuilderLength() == 0 { - let empty = InputState.EmptyIgnoringPreviousState() - stateCallback(empty) + stateCallback(InputState.EmptyIgnoringPreviousState()) } else { - let inputting = buildInputtingState() - stateCallback(inputting) + stateCallback(buildInputtingState()) } return true } // MARK: - 處理 PC Delete (macOS Fn+BackSpace) 按鍵行為 - func _handleDeleteWithState( - _ state: InputState, + func handleDelete( + state: InputState, stateCallback: @escaping (InputState) -> Void, errorCallback: @escaping () -> Void ) -> Bool { @@ -317,8 +310,7 @@ import Cocoa let inputting = buildInputtingState() // 這裡不用「count > 0」,因為該整數變數只要「!isEmpty」那就必定滿足這個條件。 if !inputting.composingBuffer.isEmpty { - let empty = InputState.EmptyIgnoringPreviousState() - stateCallback(empty) + stateCallback(InputState.EmptyIgnoringPreviousState()) } else { stateCallback(inputting) } @@ -338,8 +330,8 @@ import Cocoa // MARK: - 處理與當前文字輸入排版前後方向呈 90 度的那兩個方向鍵的按鍵行為 - func _handleAbsorbedArrowKeyWithState( - _ state: InputState, + func handleAbsorbedArrowKey( + state: InputState, stateCallback: @escaping (InputState) -> Void, errorCallback: @escaping () -> Void ) -> Bool { @@ -356,8 +348,8 @@ import Cocoa // MARK: - 處理 Home 鍵行為 - func _handleHomeWithState( - _ state: InputState, + func handleHome( + state: InputState, stateCallback: @escaping (InputState) -> Void, errorCallback: @escaping () -> Void ) -> Bool { @@ -374,8 +366,7 @@ import Cocoa if getBuilderCursorIndex() != 0 { setBuilderCursorIndex(0) - let inputting = buildInputtingState() - stateCallback(inputting) + stateCallback(buildInputtingState()) } else { IME.prtDebugIntel("66D97F90") errorCallback() @@ -387,8 +378,8 @@ import Cocoa // MARK: - 處理 End 鍵行為 - func _handleEndWithState( - _ state: InputState, + func handleEnd( + state: InputState, stateCallback: @escaping (InputState) -> Void, errorCallback: @escaping () -> Void ) -> Bool { @@ -405,8 +396,7 @@ import Cocoa if getBuilderCursorIndex() != getBuilderLength() { setBuilderCursorIndex(getBuilderLength()) - let inputting = buildInputtingState() - stateCallback(inputting) + stateCallback(buildInputtingState()) } else { IME.prtDebugIntel("9B69908E") errorCallback() @@ -418,8 +408,8 @@ import Cocoa // MARK: - 處理 Esc 鍵行為 - func _handleEscWithState( - _ state: InputState, + func handleEsc( + state: InputState, stateCallback: @escaping (InputState) -> Void, errorCallback _: @escaping () -> Void ) -> Bool { @@ -433,18 +423,15 @@ import Cocoa // is by default in macOS 10.0-10.5 built-in Panasonic Hanin and later macOS Zhuyin. // Some Windows users hate this design, hence the option here to disable it. clear() - let empty = InputState.EmptyIgnoringPreviousState() - stateCallback(empty) + stateCallback(InputState.EmptyIgnoringPreviousState()) } else { // If reading is not empty, we cancel the reading. if !isPhoneticReadingBufferEmpty() { clearPhoneticReadingBuffer() if getBuilderLength() == 0 { - let empty = InputState.Empty() - stateCallback(empty) + stateCallback(InputState.Empty()) } else { - let inputting = buildInputtingState() - stateCallback(inputting) + stateCallback(buildInputtingState()) } } } @@ -453,8 +440,8 @@ import Cocoa // MARK: - 處理向前方向鍵的行為 - func _handleForwardWithState( - _ state: InputState, + func handleForward( + state: InputState, input: InputHandler, stateCallback: @escaping (InputState) -> Void, errorCallback: @escaping () -> Void @@ -468,44 +455,44 @@ import Cocoa return true } - let currentState = state as! InputState.Inputting - - if input.isShiftHold { - // Shift + Right - if currentState.cursorIndex < (currentState.composingBuffer as NSString).length { - let nextPosition = (currentState.composingBuffer as NSString).nextUtf16Position( - for: Int(currentState.cursorIndex)) - let marking: InputState.Marking! = InputState.Marking( - composingBuffer: currentState.composingBuffer, - cursorIndex: currentState.cursorIndex, - markerIndex: UInt(nextPosition), - readings: _currentReadings() - ) - marking.tooltipForInputting = currentState.tooltip - stateCallback(marking) + if let currentState = state as? InputState.Inputting { + if input.isShiftHold { + // Shift + Right + if currentState.cursorIndex < (currentState.composingBuffer as NSString).length { + let nextPosition = (currentState.composingBuffer as NSString).nextUtf16Position( + for: Int(currentState.cursorIndex)) + let marking: InputState.Marking! = InputState.Marking( + composingBuffer: currentState.composingBuffer, + cursorIndex: currentState.cursorIndex, + markerIndex: UInt(nextPosition), + readings: _currentReadings() + ) + marking.tooltipForInputting = currentState.tooltip + stateCallback(marking) + } else { + IME.prtDebugIntel("BB7F6DB9") + errorCallback() + stateCallback(state) + } } else { - IME.prtDebugIntel("BB7F6DB9") - errorCallback() - stateCallback(state) - } - } else { - if getBuilderCursorIndex() < getBuilderLength() { - setBuilderCursorIndex(getBuilderCursorIndex() + 1) - let inputting = buildInputtingState() - stateCallback(inputting) - } else { - IME.prtDebugIntel("A96AAD58") - errorCallback() - stateCallback(state) + if getBuilderCursorIndex() < getBuilderLength() { + setBuilderCursorIndex(getBuilderCursorIndex() + 1) + stateCallback(buildInputtingState()) + } else { + IME.prtDebugIntel("A96AAD58") + errorCallback() + stateCallback(state) + } } } + return true } // MARK: - 處理向後方向鍵的行為 - func _handleBackwardWithState( - _ state: InputState, + func handleBackward( + state: InputState, input: InputHandler, stateCallback: @escaping (InputState) -> Void, errorCallback: @escaping () -> Void @@ -519,37 +506,37 @@ import Cocoa return true } - let currentState = state as! InputState.Inputting - - if input.isShiftHold { - // Shift + left - if currentState.cursorIndex > 0 { - let previousPosition = (currentState.composingBuffer as NSString).previousUtf16Position( - for: Int(currentState.cursorIndex)) - let marking: InputState.Marking! = InputState.Marking( - composingBuffer: currentState.composingBuffer, - cursorIndex: currentState.cursorIndex, - markerIndex: UInt(previousPosition), - readings: _currentReadings() - ) - marking.tooltipForInputting = currentState.tooltip - stateCallback(marking) + if let currentState = state as? InputState.Inputting { + if input.isShiftHold { + // Shift + left + if currentState.cursorIndex > 0 { + let previousPosition = (currentState.composingBuffer as NSString).previousUtf16Position( + for: Int(currentState.cursorIndex)) + let marking: InputState.Marking! = InputState.Marking( + composingBuffer: currentState.composingBuffer, + cursorIndex: currentState.cursorIndex, + markerIndex: UInt(previousPosition), + readings: _currentReadings() + ) + marking.tooltipForInputting = currentState.tooltip + stateCallback(marking) + } else { + IME.prtDebugIntel("D326DEA3") + errorCallback() + stateCallback(state) + } } else { - IME.prtDebugIntel("D326DEA3") - errorCallback() - stateCallback(state) - } - } else { - if getBuilderCursorIndex() > 0 { - setBuilderCursorIndex(getBuilderCursorIndex() - 1) - let inputting = buildInputtingState() - stateCallback(inputting) - } else { - IME.prtDebugIntel("7045E6F3") - errorCallback() - stateCallback(state) + if getBuilderCursorIndex() > 0 { + setBuilderCursorIndex(getBuilderCursorIndex() - 1) + stateCallback(buildInputtingState()) + } else { + IME.prtDebugIntel("7045E6F3") + errorCallback() + stateCallback(state) + } } } + return true } } diff --git a/Source/Modules/IMEModules/ctlInputMethod.swift b/Source/Modules/IMEModules/ctlInputMethod.swift index bdc3d9c6..8bf699bf 100644 --- a/Source/Modules/IMEModules/ctlInputMethod.swift +++ b/Source/Modules/IMEModules/ctlInputMethod.swift @@ -626,8 +626,7 @@ extension ctlInputMethod: ctlCandidateDelegate { if mgrPrefs.associatedPhrasesEnabled, let associatePhrases = keyHandler.buildAssociatePhraseState( withKey: composingBuffer, useVerticalMode: state.useVerticalMode - ) - as? InputState.AssociatedPhrases + ), !associatePhrases.candidates.isEmpty { handle(state: associatePhrases, client: client) } else { @@ -645,8 +644,7 @@ extension ctlInputMethod: ctlCandidateDelegate { if mgrPrefs.associatedPhrasesEnabled, let associatePhrases = keyHandler.buildAssociatePhraseState( withKey: selectedValue, useVerticalMode: state.useVerticalMode - ) - as? InputState.AssociatedPhrases + ), !associatePhrases.candidates.isEmpty { handle(state: associatePhrases, client: client) } else { diff --git a/Source/Modules/LanguageParsers/Gramambular/Grid.h b/Source/Modules/LanguageParsers/Gramambular/Grid.h index 0244d076..52b3e7da 100644 --- a/Source/Modules/LanguageParsers/Gramambular/Grid.h +++ b/Source/Modules/LanguageParsers/Gramambular/Grid.h @@ -44,6 +44,9 @@ class Grid void insertNode(const Node &node, size_t location, size_t spanningLength); bool hasNodeAtLocationSpanningLengthMatchingKey(size_t location, size_t spanningLength, const std::string &key); + void setHaninInputEnabled(bool enabled); + bool HaninInputEnabled(); + void expandGridByOneAtLocation(size_t location); void shrinkGridByOneAtLocation(size_t location); @@ -116,8 +119,19 @@ class Grid protected: std::vector m_spans; + bool m_bolHaninEnabled; }; +inline void Grid::setHaninInputEnabled(bool enabled) +{ + m_bolHaninEnabled = enabled; +} + +inline bool Grid::HaninInputEnabled() +{ + return m_bolHaninEnabled; +} + inline void Grid::clear() { m_spans.clear(); @@ -234,7 +248,9 @@ inline std::vector Grid::nodesCrossingOrEndingAt(size_t location) { for (size_t j = 1, m = span.maximumLength(); j <= m; j++) { - if (i + j < location) + // 左半是漢音模式,已經自威注音 1.5.2 版開始解決了可以在詞中間叫出候選字的問題。 + // TODO: 右半是微軟新注音模式,仍有可以在詞中間叫出候選字的問題。 + if (((i + j != location) && m_bolHaninEnabled) || ((i + j < location) && !m_bolHaninEnabled)) { continue; } diff --git a/Source/Resources/Base.lproj/Localizable.strings b/Source/Resources/Base.lproj/Localizable.strings index 540c3ddc..dc635a2f 100644 --- a/Source/Resources/Base.lproj/Localizable.strings +++ b/Source/Resources/Base.lproj/Localizable.strings @@ -56,6 +56,9 @@ "Symbol & Emoji Input" = "Symbol & Emoji Input"; "Edit User Symbol & Emoji Data…" = "Edit User Symbol & Emoji Data…"; "Choose your desired user data folder." = "Choose your desired user data folder."; +"Cursor is after \"%@\"." = "Cursor is after \"%@\"."; +"Cursor is before \"%@\"." = "Cursor is before \"%@\"."; +"Cursor is between \"%@\" and \"%@\"." = "Cursor is between \"%@\" and \"%@\"."; // The followings are the category names used in the Symbol menu. "catCommonSymbols" = "CommonSymbols"; diff --git a/Source/Resources/en.lproj/Localizable.strings b/Source/Resources/en.lproj/Localizable.strings index 540c3ddc..dc635a2f 100644 --- a/Source/Resources/en.lproj/Localizable.strings +++ b/Source/Resources/en.lproj/Localizable.strings @@ -56,6 +56,9 @@ "Symbol & Emoji Input" = "Symbol & Emoji Input"; "Edit User Symbol & Emoji Data…" = "Edit User Symbol & Emoji Data…"; "Choose your desired user data folder." = "Choose your desired user data folder."; +"Cursor is after \"%@\"." = "Cursor is after \"%@\"."; +"Cursor is before \"%@\"." = "Cursor is before \"%@\"."; +"Cursor is between \"%@\" and \"%@\"." = "Cursor is between \"%@\" and \"%@\"."; // The followings are the category names used in the Symbol menu. "catCommonSymbols" = "CommonSymbols"; diff --git a/Source/Resources/ja.lproj/Localizable.strings b/Source/Resources/ja.lproj/Localizable.strings index 8129b74d..89663856 100644 --- a/Source/Resources/ja.lproj/Localizable.strings +++ b/Source/Resources/ja.lproj/Localizable.strings @@ -56,6 +56,9 @@ "Symbol & Emoji Input" = "符号&絵文字入力"; "Edit User Symbol & Emoji Data…" = "ユーザー符号&絵文字辞書を編集…"; "Choose your desired user data folder." = "欲しがるユーザー辞書フォルダをお選びください。"; +"Cursor is after \"%@\"." = "カーソルは「%@」の後に。"; +"Cursor is before \"%@\"." = "カーソル「%@」の前に。"; +"Cursor is between \"%@\" and \"%@\"." = "カーソルは「%@」と「%@」に間れ。"; // The followings are the category names used in the Symbol menu. "catCommonSymbols" = "常用"; diff --git a/Source/Resources/zh-Hans.lproj/Localizable.strings b/Source/Resources/zh-Hans.lproj/Localizable.strings index a6dbdc3e..dc745a2d 100644 --- a/Source/Resources/zh-Hans.lproj/Localizable.strings +++ b/Source/Resources/zh-Hans.lproj/Localizable.strings @@ -56,6 +56,9 @@ "Symbol & Emoji Input" = "符号&绘文字输入"; "Edit User Symbol & Emoji Data…" = "编辑自订符号&绘文字资料…"; "Choose your desired user data folder." = "请选择您想指定的使用者语汇档案目录。"; +"Cursor is after \"%@\"." = "游标在「%@」之后。"; +"Cursor is before \"%@\"." = "游标在「%@」之前。"; +"Cursor is between \"%@\" and \"%@\"." = "游标介于「%@」与「%@」之间。"; // The followings are the category names used in the Symbol menu. "catCommonSymbols" = "常用"; @@ -78,11 +81,11 @@ "(Shift+)Space:" = "(Shift+)空格键:"; "An accomodation for elder computer users." = "针对年长使用者的习惯而提供。"; "Apple ABC (equivalent to English US)" = "Apple ABC (与 Apple 美规键盘等价)"; -"Apple Chewing - Dachen" = "Apple 大千注音键盘配列"; -"Apple Chewing - Eten Traditional" = "Apple 倚天传统键盘配列"; -"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple 动态注音键盘布局(大千与倚天)要求普通话/国音分析器得配置为大千配列。"; +"Apple Chewing - Dachen" = "Apple 大千注音键盘排列"; +"Apple Chewing - Eten Traditional" = "Apple 倚天传统键盘排列"; +"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple 动态注音键盘布局(大千与倚天)要求普通话/国音分析器得配置为大千排列。"; "Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" = "自动将繁体中文字转为日文 JIS 新字体"; -"Auto-convert traditional Chinese glyphs to KangXi characters" = "自动将繁体中文字转为康熙字"; +"Auto-convert traditional Chinese glyphs to KangXi characters" = "自动将繁体中文字转为康熙正体字"; "Automatically reload user data files if changes detected" = "自动检测并载入使用者语汇档案变更"; "Basic Keyboard Layout:" = "基础键盘布局:"; "Candidate Layout:" = "候选字窗布局:"; @@ -95,11 +98,11 @@ "Choose the behavior of (Shift+)Tab key in the candidate window." = "指定 (Shift+)Tab 在选字窗内的轮替操作对象。"; "Choose the cursor position where you want to list possible candidates." = "请选择用以触发选字的游标相对位置。"; "Choose the macOS-level basic keyboard layout." = "请选择 macOS 基础键盘布局。"; -"Choose the phonetic layout for Mandarin parser." = "请指定普通话/国音分析器所使用的注音配列。"; +"Choose the phonetic layout for Mandarin parser." = "请指定普通话/国音分析器所使用的注音排列。"; "Choose your desired user data folder path. Will be omitted if invalid." = "请在此指定您想指定的使用者语汇档案目录。无效值会被忽略。"; "Choose your preferred layout of the candidate window." = "选择您所偏好的候选字窗布局。"; "Cursor Selection:" = "选字游标:"; -"Dachen (Microsoft Standard / Wang / 01, etc.)" = "大千配列 (微软标准/王安/零壹/仲鼎/国乔)"; +"Dachen (Microsoft Standard / Wang / 01, etc.)" = "大千排列 (微软标准/王安/零壹/仲鼎/国乔)"; "Debug Mode" = "侦错模式"; "Dictionary" = "辞典"; "Emulating select-candidate-per-character mode" = "模拟 90 年代前期注音逐字选字输入风格"; @@ -107,25 +110,25 @@ "Enable Space key for calling candidate window" = "敲空格键以呼出候选字窗"; "Enable symbol input support (incl. certain emoji symbols)" = "启用包括少许绘文字在内的符号输入支援"; "English" = "英语"; -"Eten 26" = "倚天忘形配列 (26 键)"; -"Eten Traditional" = "倚天传统配列"; +"Eten 26" = "倚天忘形排列 (26 键)"; +"Eten Traditional" = "倚天传统排列"; "Experience" = "体验"; -"Fake Seigyou" = "伪精业配列"; +"Fake Seigyou" = "伪精业排列"; "Follow OS settings" = "依系统设定"; "for cycling candidates" = "轮替候选字"; "for cycling pages" = "轮替页面"; "General" = "通用"; "Hanyu Pinyin with Numeral Intonation" = "汉语拼音+数字标调"; "Horizontal" = "横向布局"; -"Hsu" = "许氏国音自然配列"; -"IBM" = "IBM 配列"; +"Hsu" = "许氏国音自然排列"; +"IBM" = "IBM 排列"; "Japanese" = "和语"; "Keyboard" = "键盘"; "Misc Settings:" = "杂项:"; -"MiTAC" = "神通配列"; -"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "QWERTY 以外的英数布局是为了汉语拼音配列使用者而准备的。"; +"MiTAC" = "神通排列"; +"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "QWERTY 以外的英数布局是为了汉语拼音排列使用者而准备的。"; "Output Settings:" = "输出设定:"; -"Phonetic Parser:" = "注音配列:"; +"Phonetic Parser:" = "注音排列:"; "Push the cursor to the front of the phrase after selection" = "在选字后将游标置于该字词的前方"; "Selection Keys:" = "选字键:"; "Show page buttons in candidate window" = "在选字窗内显示翻页按钮"; @@ -133,7 +136,7 @@ "Space & ESC Key:" = "ESC 与空格键:"; "Space to +cycle candidates, Shift+Space to +cycle pages" = "Shift+空格键 换下一页,空格键 换选下一个后选字"; "Space to +cycle pages, Shift+Space to +cycle candidates" = "空格键 换下一页,Shift+空格键 换选下一个后选字"; -"Stop farting (when typed phonetic combination is invalid, etc.)" = "不要放屁 // 例:当输入的音韵有误时,等"; +"Stop farting (when typed phonetic combination is invalid, etc.)" = "廉耻模式 // 取消勾选的话,敲错字时会有异音"; "to the front of the phrase (like Matsushita Hanin IME)" = "将游标置于词语前方 // 松下汉音风格"; "to the rear of the phrase (like MS New-Phonetic IME)" = "将游标置于词语后方 // 微软新注音风格"; "Traditional Chinese" = "繁体中文"; diff --git a/Source/Resources/zh-Hant.lproj/Localizable.strings b/Source/Resources/zh-Hant.lproj/Localizable.strings index 98ff5818..42073f9d 100644 --- a/Source/Resources/zh-Hant.lproj/Localizable.strings +++ b/Source/Resources/zh-Hant.lproj/Localizable.strings @@ -56,6 +56,9 @@ "Symbol & Emoji Input" = "符號&繪文字輸入"; "Edit User Symbol & Emoji Data…" = "編輯自訂符號&繪文字資料…"; "Choose your desired user data folder." = "請選擇您想指定的使用者語彙檔案目錄。"; +"Cursor is after \"%@\"." = "游標在「%@」之後。"; +"Cursor is before \"%@\"." = "游標在「%@」之前。"; +"Cursor is between \"%@\" and \"%@\"." = "游標介於「%@」與「%@」之間。"; // The followings are the category names used in the Symbol menu. "catCommonSymbols" = "常用"; @@ -80,9 +83,9 @@ "Apple ABC (equivalent to English US)" = "Apple ABC (與 Apple 美規鍵盤等價)"; "Apple Chewing - Dachen" = "Apple 大千注音鍵盤佈局"; "Apple Chewing - Eten Traditional" = "Apple 倚天傳統鍵盤佈局"; -"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple 動態注音鍵盤佈局(大千與倚天)要求普通話/國音分析器得配置為大千配列。"; +"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple 動態注音鍵盤佈局(大千與倚天)要求普通話/國音分析器得配置為大千排列。"; "Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" = "自動將繁體中文字轉為日文 JIS 新字體"; -"Auto-convert traditional Chinese glyphs to KangXi characters" = "自動將繁體中文字轉為康熙字"; +"Auto-convert traditional Chinese glyphs to KangXi characters" = "自動將繁體中文字轉為康熙正體字"; "Automatically reload user data files if changes detected" = "自動檢測並載入使用者語彙檔案變更"; "Basic Keyboard Layout:" = "基礎鍵盤佈局:"; "Candidate Layout:" = "候選字窗佈局:"; @@ -95,11 +98,11 @@ "Choose the behavior of (Shift+)Tab key in the candidate window." = "指定 (Shift+)Tab 在選字窗內的輪替操作對象。"; "Choose the cursor position where you want to list possible candidates." = "請選擇用以觸發選字的游標相對位置。"; "Choose the macOS-level basic keyboard layout." = "請選擇 macOS 基礎鍵盤佈局。"; -"Choose the phonetic layout for Mandarin parser." = "請指定普通話/國音分析器所使用的注音配列。"; +"Choose the phonetic layout for Mandarin parser." = "請指定普通話/國音分析器所使用的注音排列。"; "Choose your desired user data folder path. Will be omitted if invalid." = "請在此指定您想指定的使用者語彙檔案目錄。無效值會被忽略。"; "Choose your preferred layout of the candidate window." = "選擇您所偏好的候選字窗佈局。"; "Cursor Selection:" = "選字游標:"; -"Dachen (Microsoft Standard / Wang / 01, etc.)" = "大千配列 (微軟標準/王安/零壹/仲鼎/國喬)"; +"Dachen (Microsoft Standard / Wang / 01, etc.)" = "大千排列 (微軟標準/王安/零壹/仲鼎/國喬)"; "Debug Mode" = "偵錯模式"; "Dictionary" = "辭典"; "Emulating select-candidate-per-character mode" = "模擬 90 年代前期注音逐字選字輸入風格"; @@ -107,25 +110,25 @@ "Enable Space key for calling candidate window" = "敲空格鍵以呼出候選字窗"; "Enable symbol input support (incl. certain emoji symbols)" = "啟用包括少許繪文字在內的符號輸入支援"; "English" = "英語"; -"Eten 26" = "倚天忘形配列 (26 鍵)"; -"Eten Traditional" = "倚天傳統配列"; +"Eten 26" = "倚天忘形排列 (26 鍵)"; +"Eten Traditional" = "倚天傳統排列"; "Experience" = "體驗"; -"Fake Seigyou" = "偽精業配列"; +"Fake Seigyou" = "偽精業排列"; "Follow OS settings" = "依系統設定"; "for cycling candidates" = "輪替候選字"; "for cycling pages" = "輪替頁面"; "General" = "通用"; "Hanyu Pinyin with Numeral Intonation" = "漢語拼音+數字標調"; "Horizontal" = "橫向佈局"; -"Hsu" = "許氏國音自然配列"; -"IBM" = "IBM 配列"; +"Hsu" = "許氏國音自然排列"; +"IBM" = "IBM 排列"; "Japanese" = "和語"; "Keyboard" = "鍵盤"; "Misc Settings:" = "雜項:"; -"MiTAC" = "神通配列"; -"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "QWERTY 以外的英數佈局是為了漢語拼音配列使用者而準備的。"; +"MiTAC" = "神通排列"; +"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "QWERTY 以外的英數佈局是為了漢語拼音排列使用者而準備的。"; "Output Settings:" = "輸出設定:"; -"Phonetic Parser:" = "注音配列:"; +"Phonetic Parser:" = "注音排列:"; "Push the cursor to the front of the phrase after selection" = "在選字後將游標置於該字詞的前方"; "Selection Keys:" = "選字鍵:"; "Show page buttons in candidate window" = "在選字窗內顯示翻頁按鈕"; @@ -133,7 +136,7 @@ "Space & ESC Key:" = "ESC 與空格鍵:"; "Space to +cycle candidates, Shift+Space to +cycle pages" = "Shift+空格鍵 換下一頁,空格鍵 換選下一個後選字"; "Space to +cycle pages, Shift+Space to +cycle candidates" = "空格鍵 換下一頁,Shift+空格鍵 換選下一個後選字"; -"Stop farting (when typed phonetic combination is invalid, etc.)" = "不要放屁 // 例:當輸入的音韻有誤時,等"; +"Stop farting (when typed phonetic combination is invalid, etc.)" = "廉恥模式 // 取消勾選的話,敲錯字時會有異音"; "to the front of the phrase (like Matsushita Hanin IME)" = "將游標置於詞語前方 // 松下漢音風格"; "to the rear of the phrase (like MS New-Phonetic IME)" = "將游標置於詞語後方 // 微軟新注音風格"; "Traditional Chinese" = "繁體中文"; diff --git a/Source/WindowNIBs/ja.lproj/frmPrefWindow.strings b/Source/WindowNIBs/ja.lproj/frmPrefWindow.strings index b8ab1fba..bb3f1699 100644 --- a/Source/WindowNIBs/ja.lproj/frmPrefWindow.strings +++ b/Source/WindowNIBs/ja.lproj/frmPrefWindow.strings @@ -120,10 +120,10 @@ "ArK-Vk-OoT.title" = "漢字1つづつ全候補選択入力モード"; /* Class = "NSButtonCell"; title = "Auto-convert traditional Chinese glyphs to KangXi characters"; ObjectID = "BSK-bH-Gct"; */ -"BSK-bH-Gct.title" = "自動的に繁体漢字を康熙文字と変換する"; +"BSK-bH-Gct.title" = "入力した繁体字を康熙字体と自動変換"; /* Class = "NSButtonCell"; title = "Auto-convert traditional Chinese glyphs to KangXi characters"; ObjectID = "eia-1F-Do0"; */ -"eia-1F-Do0.title" = "自動的に繁体漢字をJIS 新字体と変換する"; +"eia-1F-Do0.title" = "入力した繁体字を日文 JIS 新字体と自動変換"; /* Class = "NSBox"; title = "Advanced Settings"; ObjectID = "E1l-m8-xgb"; */ "E1l-m8-xgb.title" = "詳細設定"; diff --git a/Source/WindowNIBs/zh-Hans.lproj/frmPrefWindow.strings b/Source/WindowNIBs/zh-Hans.lproj/frmPrefWindow.strings index fbaf9196..ba660e97 100644 --- a/Source/WindowNIBs/zh-Hans.lproj/frmPrefWindow.strings +++ b/Source/WindowNIBs/zh-Hans.lproj/frmPrefWindow.strings @@ -111,7 +111,7 @@ "2pS-nv-te4.title" = "选择您所偏好的用来选字的按键组合。"; /* Class = "NSButtonCell"; title = "Stop farting (when typed phonetic combination is invalid, etc.)"; ObjectID = "62u-jY-BRh"; */ -"62u-jY-BRh.title" = "不要放屁 // 例:当输入的音韵有误时,等"; +"62u-jY-BRh.title" = "廉耻模式 // 取消勾选的话,敲错字时会有异音"; /* Class = "NSTextFieldCell"; title = "UI language setting:"; ObjectID = "9DS-Rc-TXq"; */ "9DS-Rc-TXq.title" = "接口语言设定:"; @@ -120,7 +120,7 @@ "ArK-Vk-OoT.title" = "仿真 90 年代前期注音逐字选字输入风格"; /* Class = "NSButtonCell"; title = "Auto-convert traditional Chinese glyphs to KangXi characters"; ObjectID = "BSK-bH-Gct"; */ -"BSK-bH-Gct.title" = "自动将繁体中文字转换为康熙字"; +"BSK-bH-Gct.title" = "自动将繁体中文字转换为康熙正体字"; /* Class = "NSButtonCell"; title = "Auto-convert traditional Chinese glyphs to KangXi characters"; ObjectID = "eia-1F-Do0"; */ "eia-1F-Do0.title" = "自动将繁体中文字转换为日本简化字(JIS 新字体)"; @@ -141,7 +141,7 @@ "QUQ-oY-4Hc.label" = "一般"; /* Class = "NSTextFieldCell"; title = "Choose your preferred keyboard layout and phonetic parser."; ObjectID = "RQ6-MS-m4C"; */ -"RQ6-MS-m4C.title" = "选择您所偏好的系统键盘布局与注音分析器配列。"; +"RQ6-MS-m4C.title" = "选择您所偏好的系统键盘布局与注音分析器排列。"; /* Class = "NSButtonCell"; title = "Push the cursor to the front of the phrase after selection"; ObjectID = "RUG-ls-KyA"; */ "RUG-ls-KyA.title" = "在选字后将光标置于该字词的前方"; @@ -201,7 +201,7 @@ "2iG-Ic-gbl.label" = "辞典"; /* Class = "NSTextFieldCell"; title = "Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional."; ObjectID = "wQ9-px-b07"; */ -"wQ9-px-b07.title" = "Apple 动态注音键盘布局(大千与倚天)要求普通话/国音分析器的注音配列得配置为大千配列。"; +"wQ9-px-b07.title" = "Apple 动态注音键盘布局(大千与倚天)要求普通话/国音分析器的注音排列得配置为大千排列。"; /* Class = "NSTextFieldCell"; title = "Choose the behavior of (Shift+)Tab key in the candidate window."; ObjectID = "ueU-Rz-a1C"; */ "ueU-Rz-a1C.title" = "指定 (Shift+)Tab 热键在选字窗内的轮替操作对象。"; diff --git a/Source/WindowNIBs/zh-Hant.lproj/frmPrefWindow.strings b/Source/WindowNIBs/zh-Hant.lproj/frmPrefWindow.strings index e1704d83..c1174921 100644 --- a/Source/WindowNIBs/zh-Hant.lproj/frmPrefWindow.strings +++ b/Source/WindowNIBs/zh-Hant.lproj/frmPrefWindow.strings @@ -24,7 +24,7 @@ "10.title" = "漢語拼音二式(字母拼音+數字標調)"; /* Class = "NSTextFieldCell"; title = "BPMF Parser:"; ObjectID = "12"; */ -"12.title" = "注音配列:"; +"12.title" = "注音排列:"; /* Class = "NSTextFieldCell"; title = "Choose the cursor position where you want to list possible candidates."; ObjectID = "14"; */ "14.title" = "用以觸發選字的游標相對位置:"; @@ -111,7 +111,7 @@ "2pS-nv-te4.title" = "選擇您所偏好的用來選字的按鍵組合。"; /* Class = "NSButtonCell"; title = "Stop farting (when typed phonetic combination is invalid, etc.)"; ObjectID = "62u-jY-BRh"; */ -"62u-jY-BRh.title" = "不要放屁 // 例:當輸入的音韻有誤時,等"; +"62u-jY-BRh.title" = "廉恥模式 // 取消勾選的話,敲錯字時會有異音"; /* Class = "NSTextFieldCell"; title = "UI language setting:"; ObjectID = "9DS-Rc-TXq"; */ "9DS-Rc-TXq.title" = "介面語言設定:"; @@ -120,7 +120,7 @@ "ArK-Vk-OoT.title" = "模擬 90 年代前期注音逐字選字輸入風格"; /* Class = "NSButtonCell"; title = "Auto-convert traditional Chinese glyphs to KangXi characters"; ObjectID = "BSK-bH-Gct"; */ -"BSK-bH-Gct.title" = "自動將繁體中文字轉換為康熙字"; +"BSK-bH-Gct.title" = "自動將繁體中文字轉換為康熙正體字"; /* Class = "NSButtonCell"; title = "Auto-convert traditional Chinese glyphs to KangXi characters"; ObjectID = "eia-1F-Do0"; */ "eia-1F-Do0.title" = "自動將繁體中文字轉換為日本簡化字(JIS 新字體)"; @@ -141,7 +141,7 @@ "QUQ-oY-4Hc.label" = "一般"; /* Class = "NSTextFieldCell"; title = "Choose your preferred keyboard layout and phonetic parser."; ObjectID = "RQ6-MS-m4C"; */ -"RQ6-MS-m4C.title" = "選擇您所偏好的系統鍵盤佈局與注音分析器配列。"; +"RQ6-MS-m4C.title" = "選擇您所偏好的系統鍵盤佈局與注音分析器排列。"; /* Class = "NSButtonCell"; title = "Push the cursor to the front of the phrase after selection"; ObjectID = "RUG-ls-KyA"; */ "RUG-ls-KyA.title" = "在選字後將游標置於該字詞的前方"; @@ -201,7 +201,7 @@ "2iG-Ic-gbl.label" = "辭典"; /* Class = "NSTextFieldCell"; title = "Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional."; ObjectID = "wQ9-px-b07"; */ -"wQ9-px-b07.title" = "Apple 動態注音鍵盤佈局(大千與倚天)要求普通話/國音分析器的注音配列得配置為大千配列。"; +"wQ9-px-b07.title" = "Apple 動態注音鍵盤佈局(大千與倚天)要求普通話/國音分析器的注音排列得配置為大千排列。"; /* Class = "NSTextFieldCell"; title = "Choose the behavior of (Shift+)Tab key in the candidate window."; ObjectID = "ueU-Rz-a1C"; */ "ueU-Rz-a1C.title" = "指定 (Shift+)Tab 熱鍵在選字窗內的輪替操作對象。"; diff --git a/Update-Info.plist b/Update-Info.plist index f8dde7db..03971dfc 100644 --- a/Update-Info.plist +++ b/Update-Info.plist @@ -3,9 +3,9 @@ CFBundleShortVersionString - 1.5.1 + 1.5.2 CFBundleVersion - 1951 + 1952 UpdateInfoEndpoint https://gitee.com/vchewing/vChewing-macOS/raw/main/Update-Info.plist UpdateInfoSite diff --git a/UserPhraseEditor/Resources/Base.lproj/Main.storyboard b/UserPhraseEditor/Resources/Base.lproj/Main.storyboard index 50dc3c4d..c6716cfd 100755 --- a/UserPhraseEditor/Resources/Base.lproj/Main.storyboard +++ b/UserPhraseEditor/Resources/Base.lproj/Main.storyboard @@ -657,8 +657,9 @@ - + + @@ -686,12 +687,12 @@ - + - + diff --git a/vChewing.pkgproj b/vChewing.pkgproj index dfe17fc3..26725464 100644 --- a/vChewing.pkgproj +++ b/vChewing.pkgproj @@ -726,7 +726,7 @@ USE_HFS+_COMPRESSION VERSION - 1.5.1 + 1.5.2 TYPE 0 diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index e7dfca17..aa061f9f 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -1324,7 +1324,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1951; + CURRENT_PROJECT_VERSION = 1952; DEBUG_INFORMATION_FORMAT = dwarf; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; @@ -1347,7 +1347,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.11.5; - MARKETING_VERSION = 1.5.1; + MARKETING_VERSION = 1.5.2; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor; @@ -1380,7 +1380,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1951; + CURRENT_PROJECT_VERSION = 1952; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -1399,7 +1399,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.11.5; - MARKETING_VERSION = 1.5.1; + MARKETING_VERSION = 1.5.2; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor; @@ -1513,7 +1513,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1951; + CURRENT_PROJECT_VERSION = 1952; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -1548,7 +1548,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.11.5; - MARKETING_VERSION = 1.5.1; + MARKETING_VERSION = 1.5.2; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1580,7 +1580,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1951; + CURRENT_PROJECT_VERSION = 1952; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = ""; @@ -1610,7 +1610,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.11.5; - MARKETING_VERSION = 1.5.1; + MARKETING_VERSION = 1.5.2; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1693,7 +1693,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1951; + CURRENT_PROJECT_VERSION = 1952; DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; @@ -1718,7 +1718,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.11.5; - MARKETING_VERSION = 1.5.1; + MARKETING_VERSION = 1.5.2; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1745,7 +1745,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1951; + CURRENT_PROJECT_VERSION = 1952; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -1765,7 +1765,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.11.5; - MARKETING_VERSION = 1.5.1; + MARKETING_VERSION = 1.5.2; PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "";