InputHandler // +Enum: TypingMethod.

This commit is contained in:
ShikiSuen 2024-02-11 20:29:38 +08:00
parent 28e53c27ad
commit e1b7a4df9f
6 changed files with 193 additions and 170 deletions

View File

@ -22,7 +22,6 @@ public protocol InputHandlerProtocol {
var currentLM: vChewingLM.LMInstantiator { get set } var currentLM: vChewingLM.LMInstantiator { get set }
var currentUOM: vChewingLM.LMUserOverride { get set } var currentUOM: vChewingLM.LMUserOverride { get set }
var delegate: InputHandlerDelegate? { get set } var delegate: InputHandlerDelegate? { get set }
var composer: Tekkon.Composer { get set }
var keySeparator: String { get } var keySeparator: String { get }
static var keySeparator: String { get } static var keySeparator: String { get }
var isCompositorEmpty: Bool { get } var isCompositorEmpty: Bool { get }
@ -89,13 +88,17 @@ public class InputHandler: InputHandlerProtocol {
/// ///
var backupCursor: Int? var backupCursor: Int?
///
var currentTypingMethod: TypingMethod = .vChewingFactory
/// ///
let kEpsilon: Double = 0.000_001 let kEpsilon: Double = 0.000_001
public var calligrapher = "" // var strCodePointBuffer = "" //
public var composer: Tekkon.Composer = .init() // var calligrapher = "" //
public var compositor: Megrez.Compositor // var composer: Tekkon.Composer = .init() //
var compositor: Megrez.Compositor //
public var currentUOM: vChewingLM.LMUserOverride public var currentUOM: vChewingLM.LMUserOverride
public var currentLM: vChewingLM.LMInstantiator { public var currentLM: vChewingLM.LMInstantiator {
didSet { didSet {
@ -120,43 +123,13 @@ public class InputHandler: InputHandlerProtocol {
public func clear() { public func clear() {
clearComposerAndCalligrapher() clearComposerAndCalligrapher()
compositor.clear() compositor.clear()
isCodePointInputMode = false currentTypingMethod = .vChewingFactory
isHaninKeyboardSymbolMode = false
backupCursor = nil backupCursor = nil
} }
/// / /// /
var isConsideredEmptyForNow: Bool { var isConsideredEmptyForNow: Bool {
compositor.isEmpty && isComposerOrCalligrapherEmpty && !isCodePointInputMode && !isHaninKeyboardSymbolMode compositor.isEmpty && isComposerOrCalligrapherEmpty && currentTypingMethod == .vChewingFactory
}
// MARK: - Hanin Keyboard Symbol Mode.
var isHaninKeyboardSymbolMode = false
static let tooltipHaninKeyboardSymbolMode: String = "\("Hanin Keyboard Symbol Input.".localized)"
// MARK: - Codepoint Input Buffer.
var isCodePointInputMode = false {
willSet {
strCodePointBuffer.removeAll()
}
}
var strCodePointBuffer = ""
var tooltipCodePointInputMode: String {
let commonTerm = NSMutableString()
commonTerm.insert("Code Point Input.".localized, at: 0)
if !(delegate?.isVerticalTyping ?? false) {
switch IMEApp.currentInputMode {
case .imeModeCHS: commonTerm.insert("[GB] ", at: 0)
case .imeModeCHT: commonTerm.insert("[Big5] ", at: 0)
default: break
}
}
return commonTerm.description
} }
// MARK: - Functions dealing with Megrez. // MARK: - Functions dealing with Megrez.

View File

@ -311,7 +311,8 @@ extension InputHandler {
if !updated { delegate.callError("66F3477B") } if !updated { delegate.callError("66F3477B") }
return true return true
case .option where state.type == .ofSymbolTable: case .option where state.type == .ofSymbolTable:
return handleHaninKeyboardSymbolModeToggle() //
return revolveTypingMethod(to: .haninKeyboardSymbol)
default: break default: break
} }
} }

View File

@ -17,37 +17,29 @@ extension InputHandler {
/// - Parameter input: /// - Parameter input:
/// - Returns: IMK /// - Returns: IMK
func handleComposition(input: InputSignalProtocol) -> Bool? { func handleComposition(input: InputSignalProtocol) -> Bool? {
guard let delegate = delegate else { return nil }
// //
guard !input.text.isEmpty, input.charCode.isPrintable else { return nil } let hardRequirementMet = !input.text.isEmpty && input.charCode.isPrintable
if isCodePointInputMode { return handleCodePointComposition(input: input) } switch currentTypingMethod {
if prefs.cassetteEnabled { case .codePoint where hardRequirementMet:
// `%quick` return handleCodePointComposition(input: input)
var handleQuickCandidate = true case .haninKeyboardSymbol where [[], .shift].contains(input.keyModifierFlags):
if currentLM.areCassetteCandidateKeysShiftHeld { handleQuickCandidate = input.isShiftHold } return handleHaninKeyboardSymbolModeInput(input: input)
let hasQuickCandidates: Bool = delegate.state.type == .ofInputting && delegate.state.isCandidateContainer case .vChewingFactory where hardRequirementMet && prefs.cassetteEnabled:
// `%symboldef`
if handleCassetteSymbolTable(input: input) {
return true
} else if hasQuickCandidates, input.text != currentLM.cassetteWildcardKey {
// `%quick` `%symboldef`
guard !(handleQuickCandidate && handleCandidate(input: input, ignoringModifiers: true)) else { return true }
} else {
// `%quick`
guard !(hasQuickCandidates && handleQuickCandidate && handleCandidate(input: input)) else { return true }
}
return handleCassetteComposition(input: input) return handleCassetteComposition(input: input)
case .vChewingFactory where hardRequirementMet && !prefs.cassetteEnabled:
return handlePhonabetComposition(input: input)
default: return nil
} }
return handlePhonabetComposition(input: input)
} }
}
// MARK: (Handle BPMF Keys) // MARK: - (Handle BPMF Keys)
private extension InputHandler {
/// InputHandler.HandleInput() /// InputHandler.HandleInput()
/// - Parameter input: /// - Parameter input:
/// - Returns: IMK /// - Returns: IMK
private func handlePhonabetComposition(input: InputSignalProtocol) -> Bool? { func handlePhonabetComposition(input: InputSignalProtocol) -> Bool? {
guard let delegate = delegate else { return nil } guard let delegate = delegate else { return nil }
var inputText = (input.inputTextIgnoringModifiers ?? input.text) var inputText = (input.inputTextIgnoringModifiers ?? input.text)
inputText = inputText.lowercased().applyingTransformFW2HW(reverse: false) inputText = inputText.lowercased().applyingTransformFW2HW(reverse: false)
@ -241,13 +233,31 @@ extension InputHandler {
// MARK: - // MARK: -
extension InputHandler { private extension InputHandler {
/// InputHandler.HandleInput() /// InputHandler.HandleInput()
/// - Parameter input: /// - Parameter input:
/// - Returns: IMK /// - Returns: IMK
private func handleCassetteComposition(input: InputSignalProtocol) -> Bool? { func handleCassetteComposition(input: InputSignalProtocol) -> Bool? {
guard let delegate = delegate else { return nil } guard let delegate = delegate else { return nil }
let state = delegate.state let state = delegate.state
// `%quick`
var handleQuickCandidate = true
if currentLM.areCassetteCandidateKeysShiftHeld { handleQuickCandidate = input.isShiftHold }
let hasQuickCandidates: Bool = state.type == .ofInputting && state.isCandidateContainer
// `%symboldef`
if handleCassetteSymbolTable(input: input) {
return true
} else if hasQuickCandidates, input.text != currentLM.cassetteWildcardKey {
// `%quick` `%symboldef`
guard !(handleQuickCandidate && handleCandidate(input: input, ignoringModifiers: true)) else { return true }
} else {
// `%quick`
guard !(hasQuickCandidates && handleQuickCandidate && handleCandidate(input: input)) else { return true }
}
//
var wildcardKey: String { currentLM.cassetteWildcardKey } // var wildcardKey: String { currentLM.cassetteWildcardKey } //
let inputText = input.text let inputText = input.text
let isWildcardKeyInput: Bool = (inputText == wildcardKey && !wildcardKey.isEmpty) let isWildcardKeyInput: Bool = (inputText == wildcardKey && !wildcardKey.isEmpty)
@ -266,7 +276,7 @@ extension InputHandler {
calligrapher.count >= currentLM.maxCassetteKeyLength || isLongestPossibleKeyFormed calligrapher.count >= currentLM.maxCassetteKeyLength || isLongestPossibleKeyFormed
} }
prehandling: if !skipStrokeHandling && currentLM.isThisCassetteKeyAllowed(key: inputText) { prehandling: if !skipStrokeHandling && currentLM.isThisCassetteKeyAllowed(key: inputText) {
if calligrapher.isEmpty, isWildcardKeyInput { if calligrapher.isEmpty, isWildcardKeyInput {
delegate.callError("3606B9C0") delegate.callError("3606B9C0")
if input.beganWithLetter { if input.beganWithLetter {
@ -385,16 +395,17 @@ extension InputHandler {
// SessionCtl IMK // SessionCtl IMK
return true return true
} }
return nil return nil
} }
}
// MARK: (Handle Code Point Input) // MARK: - (Handle Code Point Input)
private extension InputHandler {
/// InputHandler.HandleInput() /// InputHandler.HandleInput()
/// - Parameter input: /// - Parameter input:
/// - Returns: IMK /// - Returns: IMK
private func handleCodePointComposition(input: InputSignalProtocol) -> Bool? { func handleCodePointComposition(input: InputSignalProtocol) -> Bool? {
guard !input.isReservedKey else { return nil } guard !input.isReservedKey else { return nil }
guard let delegate = delegate, input.text.count == 1 else { return nil } guard let delegate = delegate, input.text.count == 1 else { return nil }
guard !input.text.compactMap(\.hexDigitValue).isEmpty else { guard !input.text.compactMap(\.hexDigitValue).isEmpty else {
@ -407,7 +418,7 @@ extension InputHandler {
strCodePointBuffer.append(input.text) strCodePointBuffer.append(input.text)
var updatedState = generateStateOfInputting(guarded: true) var updatedState = generateStateOfInputting(guarded: true)
updatedState.tooltipDuration = 0 updatedState.tooltipDuration = 0
updatedState.tooltip = tooltipCodePointInputMode updatedState.tooltip = TypingMethod.codePoint.getTooltip(vertical: delegate.isVerticalTyping)
delegate.switchState(updatedState) delegate.switchState(updatedState)
return true return true
} }
@ -427,7 +438,7 @@ extension InputHandler {
updatedState.tooltipDuration = 0 updatedState.tooltipDuration = 0
updatedState.tooltip = "Invalid Code Point.".localized updatedState.tooltip = "Invalid Code Point.".localized
delegate.switchState(updatedState) delegate.switchState(updatedState)
isCodePointInputMode = true currentTypingMethod = .codePoint
return true return true
} }
// macOS // macOS
@ -435,14 +446,46 @@ extension InputHandler {
delegate.switchState(IMEState.ofCommitting(textToCommit: char)) delegate.switchState(IMEState.ofCommitting(textToCommit: char))
var updatedState = generateStateOfInputting(guarded: true) var updatedState = generateStateOfInputting(guarded: true)
updatedState.tooltipDuration = 0 updatedState.tooltipDuration = 0
updatedState.tooltip = tooltipCodePointInputMode updatedState.tooltip = TypingMethod.codePoint.getTooltip(vertical: delegate.isVerticalTyping)
delegate.switchState(updatedState) delegate.switchState(updatedState)
isCodePointInputMode = true currentTypingMethod = .codePoint
return true return true
default: default:
delegate.switchState(generateStateOfInputting()) delegate.switchState(generateStateOfInputting())
isCodePointInputMode = true currentTypingMethod = .codePoint
return true return true
} }
} }
} }
// MARK: - Handle Hanin Keyboard Symbol Inputs
private extension InputHandler {
///
/// - Parameters:
/// - input:
/// - Returns: SessionCtl IMK
func handleHaninKeyboardSymbolModeInput(input: InputSignalProtocol) -> Bool {
guard let delegate = delegate, delegate.state.type != .ofDeactivated else { return false }
let charText = input.text.lowercased().applyingTransformFW2HW(reverse: false)
guard CandidateNode.mapHaninKeyboardSymbols.keys.contains(charText) else {
return revolveTypingMethod(to: .vChewingFactory)
}
guard
charText.count == 1, let symbols = CandidateNode.queryHaninKeyboardSymbols(char: charText)
else {
delegate.callError("C1A760C7")
return true
}
// commit buffer ESC
let textToCommit = generateStateOfInputting(sansReading: true).displayedText
delegate.switchState(IMEState.ofCommitting(textToCommit: textToCommit))
if symbols.members.count == 1 {
delegate.switchState(IMEState.ofCommitting(textToCommit: symbols.members.map(\.name).joined()))
} else {
delegate.switchState(IMEState.ofSymbolTable(node: symbols))
}
currentTypingMethod = .vChewingFactory // toggle
return true
}
}

View File

@ -27,17 +27,18 @@ extension InputHandler {
if isConsideredEmptyForNow, !guarded { return IMEState.ofAbortion() } if isConsideredEmptyForNow, !guarded { return IMEState.ofAbortion() }
restoreBackupCursor() // Inputting restoreBackupCursor() // Inputting
var segHighlightedAt: Int? var segHighlightedAt: Int?
let cpInput = isCodePointInputMode && !sansReading let handleAsCodePointInput = currentTypingMethod == .codePoint && !sansReading
/// (Update the composing buffer) /// (Update the composing buffer)
/// IMEStateData NSAttributeString /// IMEStateData NSAttributeString
var displayTextSegments: [String] = cpInput var displayTextSegments: [String] = handleAsCodePointInput
? [strCodePointBuffer] ? [strCodePointBuffer]
: compositor.walkedNodes.values : compositor.walkedNodes.values
var cursor = cpInput var cursor = handleAsCodePointInput
? displayTextSegments.joined().count ? displayTextSegments.joined().count
: convertCursorForDisplay(compositor.cursor) : convertCursorForDisplay(compositor.cursor)
let cursorSansReading = cursor let cursorSansReading = cursor
let reading: String = (sansReading || isCodePointInputMode) ? "" : readingForDisplay // //
let reading: String = (sansReading || currentTypingMethod == .codePoint) ? "" : readingForDisplay
if !reading.isEmpty { if !reading.isEmpty {
var newDisplayTextSegments = [String]() var newDisplayTextSegments = [String]()
var temporaryNode = "" var temporaryNode = ""
@ -361,8 +362,9 @@ extension InputHandler {
guard let delegate = delegate else { return false } guard let delegate = delegate else { return false }
let state = delegate.state let state = delegate.state
if isHaninKeyboardSymbolMode { return handleHaninKeyboardSymbolModeToggle() } guard currentTypingMethod == .vChewingFactory else {
if isCodePointInputMode { return handleCodePointInputToggle() } return revolveTypingMethod(to: .vChewingFactory)
}
guard state.type == .ofInputting else { return false } guard state.type == .ofInputting else { return false }
@ -470,31 +472,28 @@ extension InputHandler {
guard let delegate = delegate else { return false } guard let delegate = delegate else { return false }
let state = delegate.state let state = delegate.state
guard state.type == .ofInputting else { guard state.type == .ofInputting else {
isCodePointInputMode = false currentTypingMethod = .vChewingFactory
return false return false
} }
if isCodePointInputMode { if currentTypingMethod == .codePoint {
if !strCodePointBuffer.isEmpty { if !strCodePointBuffer.isEmpty {
func refreshState() { func refreshState() {
var updatedState = generateStateOfInputting(guarded: true) var updatedState = generateStateOfInputting(guarded: true)
updatedState.tooltipDuration = 0 updatedState.tooltipDuration = 0
updatedState.tooltip = tooltipCodePointInputMode updatedState.tooltip = delegate.state.tooltip
delegate.switchState(updatedState) delegate.switchState(updatedState)
} }
strCodePointBuffer = strCodePointBuffer.dropLast(1).description strCodePointBuffer = strCodePointBuffer.dropLast(1).description
if input.commonKeyModifierFlags == .option { if input.commonKeyModifierFlags == .option {
strCodePointBuffer.removeAll() return revolveTypingMethod(to: .codePoint)
refreshState()
isCodePointInputMode = true
return true
} }
if !strCodePointBuffer.isEmpty { if !strCodePointBuffer.isEmpty {
refreshState() refreshState()
return true return true
} }
} }
return handleCodePointInputToggle() return revolveTypingMethod(to: .vChewingFactory)
} }
// macOS Shift+BackSpace // macOS Shift+BackSpace
@ -575,8 +574,9 @@ extension InputHandler {
guard let delegate = delegate else { return false } guard let delegate = delegate else { return false }
let state = delegate.state let state = delegate.state
if isHaninKeyboardSymbolMode { return handleHaninKeyboardSymbolModeToggle() } guard currentTypingMethod == .vChewingFactory else {
if isCodePointInputMode { return handleCodePointInputToggle() } return revolveTypingMethod(to: .vChewingFactory)
}
guard state.type == .ofInputting else { return false } guard state.type == .ofInputting else { return false }
@ -684,8 +684,9 @@ extension InputHandler {
guard let delegate = delegate else { return false } guard let delegate = delegate else { return false }
let state = delegate.state let state = delegate.state
if isHaninKeyboardSymbolMode { return handleHaninKeyboardSymbolModeToggle() } guard currentTypingMethod == .vChewingFactory else {
if isCodePointInputMode { return handleCodePointInputToggle() } return revolveTypingMethod(to: .vChewingFactory)
}
guard state.type == .ofInputting else { return false } guard state.type == .ofInputting else { return false }
@ -920,73 +921,6 @@ extension InputHandler {
return true return true
} }
// MARK: - CodePoint Input Toggle
@discardableResult func handleCodePointInputToggle() -> Bool {
guard let delegate = delegate, delegate.state.type != .ofDeactivated else { return false }
if isCodePointInputMode {
isCodePointInputMode = false
delegate.switchState(IMEState.ofAbortion())
return true
}
var updatedState = generateStateOfInputting(sansReading: true)
delegate.switchState(IMEState.ofCommitting(textToCommit: updatedState.displayedText))
updatedState = generateStateOfInputting(guarded: true)
updatedState.tooltipDuration = 0
updatedState.tooltip = tooltipCodePointInputMode
delegate.switchState(updatedState)
isCodePointInputMode = true
return true
}
// MARK: - Hanin Pallete
@discardableResult func handleHaninKeyboardSymbolModeToggle() -> Bool {
guard let delegate = delegate, delegate.state.type != .ofDeactivated else { return false }
if isCodePointInputMode { isCodePointInputMode = false }
if isHaninKeyboardSymbolMode {
isHaninKeyboardSymbolMode = false
delegate.switchState(IMEState.ofAbortion())
return true
}
var updatedState = generateStateOfInputting(sansReading: true)
delegate.switchState(IMEState.ofCommitting(textToCommit: updatedState.displayedText))
updatedState = generateStateOfInputting(guarded: true)
updatedState.tooltipDuration = 0
updatedState.tooltip = Self.tooltipHaninKeyboardSymbolMode
delegate.switchState(updatedState)
isHaninKeyboardSymbolMode = true
return true
}
///
/// - Parameters:
/// - input:
/// - Returns: SessionCtl IMK
func handleHaninKeyboardSymbolModeInput(input: InputSignalProtocol) -> Bool {
guard let delegate = delegate, delegate.state.type != .ofDeactivated else { return false }
let charText = input.text.lowercased().applyingTransformFW2HW(reverse: false)
guard CandidateNode.mapHaninKeyboardSymbols.keys.contains(charText) else {
return handleHaninKeyboardSymbolModeToggle()
}
guard
charText.count == 1, let symbols = CandidateNode.queryHaninKeyboardSymbols(char: charText)
else {
delegate.callError("C1A760C7")
return true
}
// commit buffer ESC
let textToCommit = generateStateOfInputting(sansReading: true).displayedText
delegate.switchState(IMEState.ofCommitting(textToCommit: textToCommit))
if symbols.members.count == 1 {
delegate.switchState(IMEState.ofCommitting(textToCommit: symbols.members.map(\.name).joined()))
} else {
delegate.switchState(IMEState.ofSymbolTable(node: symbols))
}
isHaninKeyboardSymbolMode = false // toggle
return true
}
// MARK: - Symbol Menu Input // MARK: - Symbol Menu Input
/// ///

View File

@ -48,7 +48,7 @@ public extension InputHandler {
case .kCarriageReturn, .kLineFeed: case .kCarriageReturn, .kLineFeed:
let frontNode = compositor.walkedNodes.last let frontNode = compositor.walkedNodes.last
return handleEnter(input: input) { return handleEnter(input: input) {
guard !self.isHaninKeyboardSymbolMode, !self.isCodePointInputMode else { return [] } guard self.currentTypingMethod == .vChewingFactory else { return [] }
guard let frontNode = frontNode else { return [] } guard let frontNode = frontNode else { return [] }
let pair = Megrez.KeyValuePaired(keyArray: frontNode.keyArray, value: frontNode.value) let pair = Megrez.KeyValuePaired(keyArray: frontNode.keyArray, value: frontNode.value)
let associates = self.generateArrayOfAssociates(withPair: pair) let associates = self.generateArrayOfAssociates(withPair: pair)
@ -62,13 +62,7 @@ public extension InputHandler {
case [.option, .shift]: case [.option, .shift]:
return handlePunctuationList(alternative: true, isJIS: isJIS) return handlePunctuationList(alternative: true, isJIS: isJIS)
case .option: case .option:
switch (isCodePointInputMode, isHaninKeyboardSymbolMode) { return revolveTypingMethod()
case (false, false): return handleCodePointInputToggle()
case (true, false), (false, true):
return handleHaninKeyboardSymbolModeToggle()
default: break
}
return true
default: break default: break
} }
case .kSpace: case .kSpace:
@ -85,7 +79,7 @@ public extension InputHandler {
if input.isShiftHold, !input.isControlHold, !input.isOptionHold { if input.isShiftHold, !input.isControlHold, !input.isOptionHold {
return revolveCandidate(reverseOrder: input.isCommandHold) return revolveCandidate(reverseOrder: input.isCommandHold)
} }
if isCodePointInputMode { if currentTypingMethod == .codePoint {
delegate.callError("FDD88EDB") delegate.callError("FDD88EDB")
delegate.switchState(IMEState.ofAbortion()) delegate.switchState(IMEState.ofAbortion())
return true return true
@ -148,13 +142,11 @@ public extension InputHandler {
guard let x = input.inputTextIgnoringModifiers, guard let x = input.inputTextIgnoringModifiers,
"¥\\".contains(x), input.keyModifierFlags.isEmpty "¥\\".contains(x), input.keyModifierFlags.isEmpty
else { break haninSymbolInput } else { break haninSymbolInput }
return handleHaninKeyboardSymbolModeToggle() return revolveTypingMethod(to: .haninKeyboardSymbol)
} }
// // /
if isHaninKeyboardSymbolMode, [[], .shift].contains(input.keyModifierFlags) { if let compositionHandled = handleComposition(input: input) {
return handleHaninKeyboardSymbolModeInput(input: input)
} else if let compositionHandled = handleComposition(input: input) {
return compositionHandled return compositionHandled
} }

View File

@ -0,0 +1,80 @@
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
// ... with NTL restriction stating that:
// 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 defined in MIT License.
import Foundation
import SwiftExtension
// MARK: - Typing Method
public extension InputHandler {
enum TypingMethod: Int, CaseIterable {
case vChewingFactory // : 0
case codePoint // : 1
case haninKeyboardSymbol // : 2
mutating func revolveNext() {
var theInt = rawValue
theInt.revolveAsIndex(with: Self.allCases)
guard let nextMethod = TypingMethod(rawValue: theInt) else { return }
self = nextMethod
}
func getTooltip(vertical: Bool = false) -> String {
switch self {
case .vChewingFactory: return ""
case .codePoint:
let commonTerm = NSMutableString()
commonTerm.insert("Code Point Input.".localized, at: 0)
if !vertical {
switch IMEApp.currentInputMode {
case .imeModeCHS: commonTerm.insert("[GB] ", at: 0)
case .imeModeCHT: commonTerm.insert("[Big5] ", at: 0)
default: break
}
}
return commonTerm.description
case .haninKeyboardSymbol:
return "\("Hanin Keyboard Symbol Input.".localized)"
}
}
}
}
// MARK: - Handle Rotation Toggles
public extension InputHandler {
@discardableResult func revolveTypingMethod(to specifiedMethod: TypingMethod? = nil) -> Bool {
guard let delegate = delegate else { return false }
var newMethod = currentTypingMethod
if let specified = specifiedMethod {
newMethod = specified
} else {
newMethod.revolveNext()
}
/// defer
/// switch newMethod currentTypingMethod
defer {
currentTypingMethod = newMethod
}
switch newMethod {
case .vChewingFactory:
delegate.switchState(IMEState.ofAbortion())
return true
case .codePoint:
strCodePointBuffer.removeAll()
case .haninKeyboardSymbol: break
}
var updatedState = generateStateOfInputting(sansReading: true)
delegate.switchState(IMEState.ofCommitting(textToCommit: updatedState.displayedText))
updatedState = generateStateOfInputting(guarded: true)
updatedState.tooltipDuration = 0
updatedState.tooltip = newMethod.getTooltip(vertical: delegate.isVerticalTyping)
delegate.switchState(updatedState)
return true
}
}