KeyHandler // Simplify member variable names.

This commit is contained in:
ShikiSuen 2022-06-15 14:02:31 +08:00
parent bb2ffe4c50
commit 4b83af377d
4 changed files with 98 additions and 98 deletions

View File

@ -43,11 +43,11 @@ protocol KeyHandlerDelegate {
class KeyHandler { class KeyHandler {
let kEpsilon: Double = 0.000001 let kEpsilon: Double = 0.000001
let kMaxComposingBufferNeedsToWalkSize: Int = 10 let kMaxComposingBufferNeedsToWalkSize: Int = 10
var _composer: Tekkon.Composer = .init() var composer: Tekkon.Composer = .init()
var _languageModel: vChewing.LMInstantiator = .init() var compositor: Megrez.Compositor
var _userOverrideModel: vChewing.LMUserOverride = .init() var currentLM: vChewing.LMInstantiator = .init()
var _builder: Megrez.BlockReadingBuilder var currentUOM: vChewing.LMUserOverride = .init()
var _walkedNodes: [Megrez.NodeAnchor] = [] var walkedAnchors: [Megrez.NodeAnchor] = []
var delegate: KeyHandlerDelegate? var delegate: KeyHandlerDelegate?
@ -59,29 +59,29 @@ class KeyHandler {
let isCHS: Bool = (newValue == InputMode.imeModeCHS) let isCHS: Bool = (newValue == InputMode.imeModeCHS)
// Reinitiate language models if necessary // Reinitiate language models if necessary
_languageModel = isCHS ? mgrLangModel.lmCHS : mgrLangModel.lmCHT currentLM = isCHS ? mgrLangModel.lmCHS : mgrLangModel.lmCHT
_userOverrideModel = isCHS ? mgrLangModel.uomCHS : mgrLangModel.uomCHT currentUOM = isCHS ? mgrLangModel.uomCHS : mgrLangModel.uomCHT
// Synchronize the sub-languageModel state settings to the new LM. // Synchronize the sub-languageModel state settings to the new LM.
syncBaseLMPrefs() syncBaseLMPrefs()
// Create new grid builder and clear the composer. // Create new grid builder and clear the composer.
createNewBuilder() createNewBuilder()
_composer.clear() composer.clear()
} }
} }
public init() { public init() {
_builder = Megrez.BlockReadingBuilder(lm: _languageModel, separator: "-") compositor = Megrez.Compositor(lm: currentLM, separator: "-")
ensureParser() ensureParser()
// defer willSet // defer willSet
defer { inputMode = IME.currentInputMode } defer { inputMode = IME.currentInputMode }
} }
func clear() { func clear() {
_composer.clear() composer.clear()
_builder.clear() compositor.clear()
_walkedNodes.removeAll() walkedAnchors.removeAll()
} }
// MARK: - Functions dealing with Megrez. // MARK: - Functions dealing with Megrez.
@ -91,11 +91,11 @@ class KeyHandler {
// of the best possible Mandarin characters given the input syllables, // of the best possible Mandarin characters given the input syllables,
// using the Viterbi algorithm implemented in the Megrez library. // using the Viterbi algorithm implemented in the Megrez library.
// The walk() traces the grid to the end. // 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 DEBUG mode is enabled, a GraphViz file is written to kGraphVizOutputfile.
if mgrPrefs.isDebugModeEnabled { if mgrPrefs.isDebugModeEnabled {
let result = _builder.grid.dumpDOT let result = compositor.grid.dumpDOT
do { do {
try result.write( try result.write(
toFile: "/private/var/tmp/vChewing-visualization.dot", toFile: "/private/var/tmp/vChewing-visualization.dot",
@ -117,13 +117,13 @@ class KeyHandler {
// (i.e. popped out.) // (i.e. popped out.)
var poppedText = "" var poppedText = ""
if _builder.grid.width > mgrPrefs.composingBufferSize { if compositor.grid.width > mgrPrefs.composingBufferSize {
if !_walkedNodes.isEmpty { if !walkedAnchors.isEmpty {
let anchor: Megrez.NodeAnchor = _walkedNodes[0] let anchor: Megrez.NodeAnchor = walkedAnchors[0]
if let theNode = anchor.node { if let theNode = anchor.node {
poppedText = theNode.currentKeyValue.value poppedText = theNode.currentKeyValue.value
} }
_builder.removeHeadReadings(count: anchor.spanningLength) compositor.removeHeadReadings(count: anchor.spanningLength)
} }
} }
walk() walk()
@ -132,17 +132,17 @@ class KeyHandler {
func buildAssociatePhraseArray(withKey key: String) -> [String] { func buildAssociatePhraseArray(withKey key: String) -> [String] {
var arrResult: [String] = [] var arrResult: [String] = []
if _languageModel.hasAssociatedPhrasesForKey(key) { if currentLM.hasAssociatedPhrasesForKey(key) {
arrResult.append(contentsOf: _languageModel.associatedPhrasesForKey(key)) arrResult.append(contentsOf: currentLM.associatedPhrasesForKey(key))
} }
return arrResult return arrResult
} }
func fixNode(value: String, respectCursorPushing: Bool = true) { func fixNode(value: String, respectCursorPushing: Bool = true) {
let cursorIndex = min(actualCandidateCursorIndex + (mgrPrefs.useRearCursorMode ? 1 : 0), builderLength) 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 // location: cursorIndex, value: value
// ) // )
// // // //
@ -166,8 +166,8 @@ class KeyHandler {
// } // }
// if addToUserOverrideModel { // if addToUserOverrideModel {
// IME.prtDebugIntel("UOM: Start Observation.") // IME.prtDebugIntel("UOM: Start Observation.")
// _userOverrideModel.observe( // currentUOM.observe(
// walkedNodes: _walkedNodes, cursorIndex: cursorIndex, candidate: value, // walkedNodes: walkedAnchors, cursorIndex: cursorIndex, candidate: value,
// timestamp: NSDate().timeIntervalSince1970 // timestamp: NSDate().timeIntervalSince1970
// ) // )
// } // }
@ -176,7 +176,7 @@ class KeyHandler {
if mgrPrefs.moveCursorAfterSelectingCandidate, respectCursorPushing { if mgrPrefs.moveCursorAfterSelectingCandidate, respectCursorPushing {
var nextPosition = 0 var nextPosition = 0
for node in _walkedNodes { for node in walkedAnchors {
if nextPosition >= cursorIndex { break } if nextPosition >= cursorIndex { break }
nextPosition += node.spanningLength nextPosition += node.spanningLength
} }
@ -215,15 +215,15 @@ class KeyHandler {
let overrideValue = let overrideValue =
mgrPrefs.useSCPCTypingMode mgrPrefs.useSCPCTypingMode
? "" ? ""
: _userOverrideModel.suggest( : currentUOM.suggest(
walkedNodes: _walkedNodes, cursorIndex: builderCursorIndex, walkedNodes: walkedAnchors, cursorIndex: builderCursorIndex,
timestamp: NSDate().timeIntervalSince1970 timestamp: NSDate().timeIntervalSince1970
) )
if !overrideValue.isEmpty { if !overrideValue.isEmpty {
IME.prtDebugIntel( IME.prtDebugIntel(
"UOM: Suggestion retrieved, overriding the node score of the selected candidate.") "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), location: min(actualCandidateCursorIndex + (mgrPrefs.useRearCursorMode ? 1 : 0), builderLength),
value: overrideValue, value: overrideValue,
overridingScore: findHighestScore(nodes: rawNodes, epsilon: kEpsilon) overridingScore: findHighestScore(nodes: rawNodes, epsilon: kEpsilon)
@ -251,89 +251,89 @@ class KeyHandler {
func ensureParser() { func ensureParser() {
switch mgrPrefs.mandarinParser { switch mgrPrefs.mandarinParser {
case MandarinParser.ofStandard.rawValue: case MandarinParser.ofStandard.rawValue:
_composer.ensureParser(arrange: .ofDachen) composer.ensureParser(arrange: .ofDachen)
case MandarinParser.ofDachen26.rawValue: case MandarinParser.ofDachen26.rawValue:
_composer.ensureParser(arrange: .ofDachen26) composer.ensureParser(arrange: .ofDachen26)
case MandarinParser.ofETen.rawValue: case MandarinParser.ofETen.rawValue:
_composer.ensureParser(arrange: .ofETen) composer.ensureParser(arrange: .ofETen)
case MandarinParser.ofHsu.rawValue: case MandarinParser.ofHsu.rawValue:
_composer.ensureParser(arrange: .ofHsu) composer.ensureParser(arrange: .ofHsu)
case MandarinParser.ofETen26.rawValue: case MandarinParser.ofETen26.rawValue:
_composer.ensureParser(arrange: .ofETen26) composer.ensureParser(arrange: .ofETen26)
case MandarinParser.ofIBM.rawValue: case MandarinParser.ofIBM.rawValue:
_composer.ensureParser(arrange: .ofIBM) composer.ensureParser(arrange: .ofIBM)
case MandarinParser.ofMiTAC.rawValue: case MandarinParser.ofMiTAC.rawValue:
_composer.ensureParser(arrange: .ofMiTAC) composer.ensureParser(arrange: .ofMiTAC)
case MandarinParser.ofFakeSeigyou.rawValue: case MandarinParser.ofFakeSeigyou.rawValue:
_composer.ensureParser(arrange: .ofFakeSeigyou) composer.ensureParser(arrange: .ofFakeSeigyou)
case MandarinParser.ofHanyuPinyin.rawValue: case MandarinParser.ofHanyuPinyin.rawValue:
_composer.ensureParser(arrange: .ofHanyuPinyin) composer.ensureParser(arrange: .ofHanyuPinyin)
case MandarinParser.ofSecondaryPinyin.rawValue: case MandarinParser.ofSecondaryPinyin.rawValue:
_composer.ensureParser(arrange: .ofSecondaryPinyin) composer.ensureParser(arrange: .ofSecondaryPinyin)
case MandarinParser.ofYalePinyin.rawValue: case MandarinParser.ofYalePinyin.rawValue:
_composer.ensureParser(arrange: .ofYalePinyin) composer.ensureParser(arrange: .ofYalePinyin)
case MandarinParser.ofHualuoPinyin.rawValue: case MandarinParser.ofHualuoPinyin.rawValue:
_composer.ensureParser(arrange: .ofHualuoPinyin) composer.ensureParser(arrange: .ofHualuoPinyin)
case MandarinParser.ofUniversalPinyin.rawValue: case MandarinParser.ofUniversalPinyin.rawValue:
_composer.ensureParser(arrange: .ofUniversalPinyin) composer.ensureParser(arrange: .ofUniversalPinyin)
default: default:
_composer.ensureParser(arrange: .ofDachen) composer.ensureParser(arrange: .ofDachen)
mgrPrefs.mandarinParser = MandarinParser.ofStandard.rawValue mgrPrefs.mandarinParser = MandarinParser.ofStandard.rawValue
} }
_composer.clear() composer.clear()
} }
// MARK: - Extracted methods and functions (Megrez). // MARK: - Extracted methods and functions (Megrez).
var isBuilderEmpty: Bool { _builder.grid.width == 0 } var isBuilderEmpty: Bool { compositor.grid.width == 0 }
var rawNodes: [Megrez.NodeAnchor] { var rawNodes: [Megrez.NodeAnchor] {
/// 使 nodesCrossing macOS /// 使 nodesCrossing macOS
/// nodeCrossing /// nodeCrossing
mgrPrefs.useRearCursorMode mgrPrefs.useRearCursorMode
? _builder.grid.nodesBeginningAt(location: actualCandidateCursorIndex) ? compositor.grid.nodesBeginningAt(location: actualCandidateCursorIndex)
: _builder.grid.nodesEndingAt(location: actualCandidateCursorIndex) : compositor.grid.nodesEndingAt(location: actualCandidateCursorIndex)
} }
func syncBaseLMPrefs() { func syncBaseLMPrefs() {
_languageModel.isPhraseReplacementEnabled = mgrPrefs.phraseReplacementEnabled currentLM.isPhraseReplacementEnabled = mgrPrefs.phraseReplacementEnabled
_languageModel.isCNSEnabled = mgrPrefs.cns11643Enabled currentLM.isCNSEnabled = mgrPrefs.cns11643Enabled
_languageModel.isSymbolEnabled = mgrPrefs.symbolInputEnabled currentLM.isSymbolEnabled = mgrPrefs.symbolInputEnabled
} }
func createNewBuilder() { func createNewBuilder() {
// Each Mandarin syllable is separated by a hyphen. // 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 { func ifLangModelHasUnigrams(forKey reading: String) -> Bool {
_languageModel.hasUnigramsFor(key: reading) currentLM.hasUnigramsFor(key: reading)
} }
func insertReadingToBuilderAtCursor(reading: String) { func insertReadingToBuilderAtCursor(reading: String) {
_builder.insertReadingAtCursor(reading: reading) compositor.insertReadingAtCursor(reading: reading)
} }
var builderCursorIndex: Int { var builderCursorIndex: Int {
get { _builder.cursorIndex } get { compositor.cursorIndex }
set { _builder.cursorIndex = newValue } set { compositor.cursorIndex = newValue }
} }
var builderLength: Int { var builderLength: Int {
_builder.length compositor.length
} }
func deleteBuilderReadingInFrontOfCursor() { func deleteBuilderReadingInFrontOfCursor() {
_builder.deleteReadingAtTheRearOfCursor() compositor.deleteReadingAtTheRearOfCursor()
} }
func deleteBuilderReadingToTheFrontOfCursor() { func deleteBuilderReadingToTheFrontOfCursor() {
_builder.deleteReadingToTheFrontOfCursor() compositor.deleteReadingToTheFrontOfCursor()
} }
var keyLengthAtIndexZero: Int { var keyLengthAtIndexZero: Int {
_walkedNodes[0].node?.currentKeyValue.value.count ?? 0 walkedAnchors[0].node?.currentKeyValue.value.count ?? 0
} }
} }

View File

@ -350,7 +350,7 @@ extension KeyHandler {
let punctuation: String = arrPunctuations.joined(separator: "") let punctuation: String = arrPunctuations.joined(separator: "")
var shouldAutoSelectCandidate: Bool = var shouldAutoSelectCandidate: Bool =
_composer.inputValidityCheck(key: charCode) || ifLangModelHasUnigrams(forKey: customPunctuation) composer.inputValidityCheck(key: charCode) || ifLangModelHasUnigrams(forKey: customPunctuation)
|| ifLangModelHasUnigrams(forKey: punctuation) || ifLangModelHasUnigrams(forKey: punctuation)
if !shouldAutoSelectCandidate, input.isUpperCaseASCIILetterKey { if !shouldAutoSelectCandidate, input.isUpperCaseASCIILetterKey {

View File

@ -146,37 +146,37 @@ extension KeyHandler {
let skipPhoneticHandling = input.isReservedKey || input.isControlHold || input.isOptionHold let skipPhoneticHandling = input.isReservedKey || input.isControlHold || input.isOptionHold
// See if Phonetic reading is valid. // See if Phonetic reading is valid.
if !skipPhoneticHandling && _composer.inputValidityCheck(key: charCode) { if !skipPhoneticHandling && composer.inputValidityCheck(key: charCode) {
_composer.receiveKey(fromCharCode: charCode) composer.receiveKey(fromCharCode: charCode)
keyConsumedByReading = true keyConsumedByReading = true
// If we have a tone marker, we have to insert the reading to the // 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 // builder in other words, if we don't have a tone marker, we just
// update the composing buffer. // update the composing buffer.
let composeReading = _composer.hasToneMarker() let composeReading = composer.hasToneMarker()
if !composeReading { if !composeReading {
stateCallback(buildInputtingState) stateCallback(buildInputtingState)
return true 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. // 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. // We use "|=" conditioning so that the tone marker key is also taken into account.
// However, Swift does not support "|=". // However, Swift does not support "|=".
composeReading = composeReading || (!_composer.isEmpty && (input.isSpace || input.isEnter)) composeReading = composeReading || (!composer.isEmpty && (input.isSpace || input.isEnter))
if composeReading { if composeReading {
if input.isSpace, !_composer.hasToneMarker() { if input.isSpace, !composer.hasToneMarker() {
_composer.receiveKey(fromString: " ") // composer.receiveKey(fromString: " ") //
} }
let reading = _composer.getComposition() let reading = composer.getComposition()
// See whether we have a unigram for this... // See whether we have a unigram for this...
if !ifLangModelHasUnigrams(forKey: reading) { if !ifLangModelHasUnigrams(forKey: reading) {
IME.prtDebugIntel("B49C0979語彙庫內無「\(reading)」的匹配記錄。") IME.prtDebugIntel("B49C0979語彙庫內無「\(reading)」的匹配記錄。")
errorCallback() errorCallback()
_composer.clear() composer.clear()
stateCallback((builderLength == 0) ? InputState.EmptyIgnoringPreviousState() : buildInputtingState) stateCallback((builderLength == 0) ? InputState.EmptyIgnoringPreviousState() : buildInputtingState)
return true return true
} }
@ -191,7 +191,7 @@ extension KeyHandler {
// dealWithOverrideModelSuggestions() // 使 // dealWithOverrideModelSuggestions() // 使
// ... then update the text. // ... then update the text.
_composer.clear() composer.clear()
let inputting = buildInputtingState let inputting = buildInputtingState
inputting.poppedText = poppedText inputting.poppedText = poppedText
@ -240,7 +240,7 @@ extension KeyHandler {
// MARK: Calling candidate window using Up / Down or PageUp / PageDn. // 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.isExtraChooseCandidateKey || input.isExtraChooseCandidateKeyReverse || input.isSpace
|| input.isPageDown || input.isPageUp || (input.isTab && mgrPrefs.specifyShiftTabKeyBehavior) || input.isPageDown || input.isPageUp || (input.isTab && mgrPrefs.specifyShiftTabKeyBehavior)
|| (input.isTypingVertical && (input.isverticalTypingOnlyChooseCandidateKey)) || (input.isTypingVertical && (input.isverticalTypingOnlyChooseCandidateKey))
@ -362,7 +362,7 @@ extension KeyHandler {
if input.isSymbolMenuPhysicalKey && !input.isShiftHold { if input.isSymbolMenuPhysicalKey && !input.isShiftHold {
if input.isOptionHold { if input.isOptionHold {
if ifLangModelHasUnigrams(forKey: "_punctuation_list") { if ifLangModelHasUnigrams(forKey: "_punctuation_list") {
if _composer.isEmpty { if composer.isEmpty {
insertReadingToBuilderAtCursor(reading: "_punctuation_list") insertReadingToBuilderAtCursor(reading: "_punctuation_list")
let poppedText: String! = popOverflowComposingTextAndWalk let poppedText: String! = popOverflowComposingTextAndWalk
let inputting = buildInputtingState let inputting = buildInputtingState
@ -453,7 +453,7 @@ extension KeyHandler {
// "thinking" that the key is not actually consumed. // "thinking" that the key is not actually consumed.
// F1-F12 // F1-F12
// 便 // 便
if (state is InputState.NotEmpty) || !_composer.isEmpty { if (state is InputState.NotEmpty) || !composer.isEmpty {
IME.prtDebugIntel( IME.prtDebugIntel(
"Blocked data: charCode: \(charCode), keyCode: \(input.keyCode)") "Blocked data: charCode: \(charCode), keyCode: \(input.keyCode)")
IME.prtDebugIntel("A9BFF20E") IME.prtDebugIntel("A9BFF20E")

View File

@ -41,7 +41,7 @@ extension KeyHandler {
// We must do some Unicode codepoint counting to find the actual cursor location for the client // 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 // 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(). // 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 { if let theNode = walkedNode.node {
let strNodeValue = theNode.currentKeyValue.value let strNodeValue = theNode.currentKeyValue.value
composingBuffer += strNodeValue composingBuffer += strNodeValue
@ -78,14 +78,14 @@ extension KeyHandler {
// Example in McBopomofo: Typing (3 readings) gets a tree emoji. // Example in McBopomofo: Typing (3 readings) gets a tree emoji.
// Example in vChewing: Typing (2 readings) gets a pasta emoji. // Example in vChewing: Typing (2 readings) gets a pasta emoji.
switch builderCursorIndex { switch builderCursorIndex {
case _builder.readings.count...: case compositor.readings.count...:
tooltipParameterRef[0] = _builder.readings[_builder.readings.count - 1] tooltipParameterRef[0] = compositor.readings[compositor.readings.count - 1]
case 0: case 0:
tooltipParameterRef[1] = _builder.readings[builderCursorIndex] tooltipParameterRef[1] = compositor.readings[builderCursorIndex]
default: default:
do { do {
tooltipParameterRef[0] = _builder.readings[builderCursorIndex - 1] tooltipParameterRef[0] = compositor.readings[builderCursorIndex - 1]
tooltipParameterRef[1] = _builder.readings[builderCursorIndex] tooltipParameterRef[1] = compositor.readings[builderCursorIndex]
} }
} }
} }
@ -109,7 +109,7 @@ extension KeyHandler {
} }
let head = String(utf16CodeUnits: arrHead, count: arrHead.count) 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 tail = String(utf16CodeUnits: arrTail, count: arrTail.count)
let composedText = head + reading + tail let composedText = head + reading + tail
let cursorIndex = composedStringCursorIndex + reading.utf16.count let cursorIndex = composedStringCursorIndex + reading.utf16.count
@ -259,14 +259,14 @@ extension KeyHandler {
return false return false
} }
if _composer.isEmpty { if composer.isEmpty {
insertReadingToBuilderAtCursor(reading: customPunctuation) insertReadingToBuilderAtCursor(reading: customPunctuation)
let poppedText = popOverflowComposingTextAndWalk let poppedText = popOverflowComposingTextAndWalk
let inputting = buildInputtingState let inputting = buildInputtingState
inputting.poppedText = poppedText inputting.poppedText = poppedText
stateCallback(inputting) stateCallback(inputting)
if mgrPrefs.useSCPCTypingMode, _composer.isEmpty { if mgrPrefs.useSCPCTypingMode, composer.isEmpty {
let candidateState = buildCandidate( let candidateState = buildCandidate(
state: inputting, state: inputting,
isTypingVertical: isTypingVertical isTypingVertical: isTypingVertical
@ -345,7 +345,7 @@ extension KeyHandler {
var composed = "" var composed = ""
for theAnchor in _walkedNodes { for theAnchor in walkedAnchors {
if let node = theAnchor.node { if let node = theAnchor.node {
var key = node.currentKeyValue.key var key = node.currentKeyValue.key
if mgrPrefs.inlineDumpPinyinInLieuOfZhuyin { if mgrPrefs.inlineDumpPinyinInLieuOfZhuyin {
@ -382,9 +382,9 @@ extension KeyHandler {
) -> Bool { ) -> Bool {
guard state is InputState.Inputting else { return false } guard state is InputState.Inputting else { return false }
if _composer.hasToneMarker(withNothingElse: true) { if composer.hasToneMarker(withNothingElse: true) {
_composer.clear() composer.clear()
} else if _composer.isEmpty { } else if composer.isEmpty {
if builderCursorIndex >= 0 { if builderCursorIndex >= 0 {
deleteBuilderReadingInFrontOfCursor() deleteBuilderReadingInFrontOfCursor()
walk() walk()
@ -395,10 +395,10 @@ extension KeyHandler {
return true return true
} }
} else { } else {
_composer.doBackSpace() composer.doBackSpace()
} }
if _composer.isEmpty, builderLength == 0 { if composer.isEmpty, builderLength == 0 {
stateCallback(InputState.EmptyIgnoringPreviousState()) stateCallback(InputState.EmptyIgnoringPreviousState())
} else { } else {
stateCallback(buildInputtingState) stateCallback(buildInputtingState)
@ -415,7 +415,7 @@ extension KeyHandler {
) -> Bool { ) -> Bool {
guard state is InputState.Inputting else { return false } guard state is InputState.Inputting else { return false }
if _composer.isEmpty { if composer.isEmpty {
if builderCursorIndex != builderLength { if builderCursorIndex != builderLength {
deleteBuilderReadingToTheFrontOfCursor() deleteBuilderReadingToTheFrontOfCursor()
walk() walk()
@ -448,7 +448,7 @@ extension KeyHandler {
errorCallback: @escaping () -> Void errorCallback: @escaping () -> Void
) -> Bool { ) -> Bool {
guard state is InputState.Inputting else { return false } guard state is InputState.Inputting else { return false }
if !_composer.isEmpty { if !composer.isEmpty {
IME.prtDebugIntel("9B6F908D") IME.prtDebugIntel("9B6F908D")
errorCallback() errorCallback()
} }
@ -465,7 +465,7 @@ extension KeyHandler {
) -> Bool { ) -> Bool {
guard state is InputState.Inputting else { return false } guard state is InputState.Inputting else { return false }
if !_composer.isEmpty { if !composer.isEmpty {
IME.prtDebugIntel("ABC44080") IME.prtDebugIntel("ABC44080")
errorCallback() errorCallback()
stateCallback(state) stateCallback(state)
@ -493,7 +493,7 @@ extension KeyHandler {
) -> Bool { ) -> Bool {
guard state is InputState.Inputting else { return false } guard state is InputState.Inputting else { return false }
if !_composer.isEmpty { if !composer.isEmpty {
IME.prtDebugIntel("9B69908D") IME.prtDebugIntel("9B69908D")
errorCallback() errorCallback()
stateCallback(state) stateCallback(state)
@ -532,8 +532,8 @@ extension KeyHandler {
stateCallback(InputState.EmptyIgnoringPreviousState()) stateCallback(InputState.EmptyIgnoringPreviousState())
} else { } else {
// If reading is not empty, we cancel the reading. // If reading is not empty, we cancel the reading.
if !_composer.isEmpty { if !composer.isEmpty {
_composer.clear() composer.clear()
if builderLength == 0 { if builderLength == 0 {
stateCallback(InputState.EmptyIgnoringPreviousState()) stateCallback(InputState.EmptyIgnoringPreviousState())
} else { } else {
@ -554,7 +554,7 @@ extension KeyHandler {
) -> Bool { ) -> Bool {
guard let currentState = state as? InputState.Inputting else { return false } guard let currentState = state as? InputState.Inputting else { return false }
if !_composer.isEmpty { if !composer.isEmpty {
IME.prtDebugIntel("B3BA5257") IME.prtDebugIntel("B3BA5257")
errorCallback() errorCallback()
stateCallback(state) stateCallback(state)
@ -603,7 +603,7 @@ extension KeyHandler {
) -> Bool { ) -> Bool {
guard let currentState = state as? InputState.Inputting else { return false } guard let currentState = state as? InputState.Inputting else { return false }
if !_composer.isEmpty { if !composer.isEmpty {
IME.prtDebugIntel("6ED95318") IME.prtDebugIntel("6ED95318")
errorCallback() errorCallback()
stateCallback(state) stateCallback(state)
@ -660,7 +660,7 @@ extension KeyHandler {
return false return false
} }
guard _composer.isEmpty else { guard composer.isEmpty else {
IME.prtDebugIntel("A2DAF7BC") IME.prtDebugIntel("A2DAF7BC")
errorCallback() errorCallback()
return true return true
@ -679,7 +679,7 @@ extension KeyHandler {
let cursorIndex = min( let cursorIndex = min(
actualCandidateCursorIndex + (mgrPrefs.useRearCursorMode ? 1 : 0), builderLength actualCandidateCursorIndex + (mgrPrefs.useRearCursorMode ? 1 : 0), builderLength
) )
for anchor in _walkedNodes { for anchor in walkedAnchors {
length += anchor.spanningLength length += anchor.spanningLength
if length >= cursorIndex { if length >= cursorIndex {
currentAnchor = anchor currentAnchor = anchor