InputHandler // Remove stateCallback().

This commit is contained in:
ShikiSuen 2022-10-14 12:03:14 +08:00
parent 4522921a0f
commit 36a83f25a2
12 changed files with 223 additions and 233 deletions

View File

@ -174,7 +174,6 @@ extension InputHandler {
func handle( func handle(
input: InputHandler, input: InputHandler,
state: InputState, state: InputState,
stateCallback: @escaping (InputState) -> Void,
errorCallback: @escaping (String) -> Void errorCallback: @escaping (String) -> Void
) -> Bool { ) -> Bool {
let charCode: UniChar = input.charCode let charCode: UniChar = input.charCode
@ -217,7 +216,7 @@ if !skipPhoneticHandling && _composer.inputValidityCheck(key: charCode) {
// 有調號的話,則不需要這樣處理,轉而繼續在此之後的處理。 // 有調號的話,則不需要這樣處理,轉而繼續在此之後的處理。
let composeReading = _composer.hasToneMarker() let composeReading = _composer.hasToneMarker()
if !composeReading { if !composeReading {
stateCallback(generateStateOfInputting()) delegate.switchState(generateStateOfInputting())
return true return true
} }
} }
@ -246,7 +245,7 @@ if composeReading { // 符合按鍵組合條件
errorCallback("114514") // 向狀態管理引擎回呼一個錯誤狀態 errorCallback("114514") // 向狀態管理引擎回呼一個錯誤狀態
_composer.clear() // 清空注拼槽的內容 _composer.clear() // 清空注拼槽的內容
// 根據「天權星引擎 (威注音) 或 Gramambular (小麥) 的組字器是否為空」來判定回呼哪一種狀態 // 根據「天權星引擎 (威注音) 或 Gramambular (小麥) 的組字器是否為空」來判定回呼哪一種狀態
stateCallback( delegate.switchState(
(getCompositorLength() == 0) ? InputState.EmptyIgnoringPreviousState() : generateStateOfInputting()) (getCompositorLength() == 0) ? InputState.EmptyIgnoringPreviousState() : generateStateOfInputting())
return true // 向 IMK 報告說這個按鍵訊號已經被輸入法攔截處理了 return true // 向 IMK 報告說這個按鍵訊號已經被輸入法攔截處理了
} }
@ -269,7 +268,7 @@ if composeReading { // 符合按鍵組合條件
// 再以回呼組字狀態的方式來執行updateClientComposingBuffer() // 再以回呼組字狀態的方式來執行updateClientComposingBuffer()
let inputting = generateStateOfInputting() let inputting = generateStateOfInputting()
inputting.poppedText = poppedText inputting.poppedText = poppedText
stateCallback(inputting) delegate.switchState(inputting)
return true // 向 IMK 報告說這個按鍵訊號已經被輸入法攔截處理了 return true // 向 IMK 報告說這個按鍵訊號已經被輸入法攔截處理了
} }

View File

@ -37,7 +37,7 @@ public protocol InputHandlerDelegate {
var selectionKeys: String { get } var selectionKeys: String { get }
var state: IMEStateProtocol { get set } var state: IMEStateProtocol { get set }
var clientBundleIdentifier: String { get } var clientBundleIdentifier: String { get }
func handle(state newState: IMEStateProtocol, replaceCurrent: Bool) func switchState(_ newState: IMEStateProtocol)
func candidateController() -> CtlCandidateProtocol func candidateController() -> CtlCandidateProtocol
func candidateSelectionCalledByInputHandler(at index: Int) func candidateSelectionCalledByInputHandler(at index: Int)
func performUserPhraseOperation(with state: IMEStateProtocol, addToFilter: Bool) func performUserPhraseOperation(with state: IMEStateProtocol, addToFilter: Bool)

View File

@ -18,20 +18,20 @@ extension InputHandler {
/// - Parameters: /// - Parameters:
/// - input: /// - input:
/// - state: /// - state:
/// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: IMK /// - Returns: IMK
func handleCandidate( func handleCandidate(
state: IMEStateProtocol, state: IMEStateProtocol,
input: InputSignalProtocol, input: InputSignalProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void,
errorCallback: @escaping (String) -> Void errorCallback: @escaping (String) -> Void
) -> Bool { ) -> Bool {
guard var ctlCandidate = delegate?.candidateController() else { guard let delegate = delegate else {
errorCallback("06661F6E") errorCallback("06661F6E")
return true return true
} }
var ctlCandidate = delegate.candidateController()
// MARK: (Cancel Candidate) // MARK: (Cancel Candidate)
let cancelCandidateKey = let cancelCandidateKey =
@ -47,12 +47,12 @@ extension InputHandler {
// //
// 使 BackSpace // 使 BackSpace
// compositor.isEmpty // compositor.isEmpty
stateCallback(IMEState.ofAbortion()) delegate.switchState(IMEState.ofAbortion())
} else { } else {
stateCallback(generateStateOfInputting()) delegate.switchState(generateStateOfInputting())
} }
if state.type == .ofSymbolTable, let nodePrevious = state.node.previous, !nodePrevious.members.isEmpty { if state.type == .ofSymbolTable, let nodePrevious = state.node.previous, !nodePrevious.members.isEmpty {
stateCallback(IMEState.ofSymbolTable(node: nodePrevious)) delegate.switchState(IMEState.ofSymbolTable(node: nodePrevious))
} }
return true return true
} }
@ -61,10 +61,10 @@ extension InputHandler {
if input.isEnter { if input.isEnter {
if state.type == .ofAssociates, !prefs.alsoConfirmAssociatedCandidatesByEnter { if state.type == .ofAssociates, !prefs.alsoConfirmAssociatedCandidatesByEnter {
stateCallback(IMEState.ofAbortion()) delegate.switchState(IMEState.ofAbortion())
return true return true
} }
delegate?.candidateSelectionCalledByInputHandler(at: ctlCandidate.selectedCandidateIndex) delegate.candidateSelectionCalledByInputHandler(at: ctlCandidate.selectedCandidateIndex)
return true return true
} }
@ -232,7 +232,7 @@ extension InputHandler {
let match: String = let match: String =
(state.type == .ofAssociates) ? input.inputTextIgnoringModifiers ?? "" : input.text (state.type == .ofAssociates) ? input.inputTextIgnoringModifiers ?? "" : input.text
let selectionKeys = delegate?.selectionKeys ?? PrefMgr.shared.candidateKeys let selectionKeys = delegate.selectionKeys
for j in 0..<selectionKeys.count { for j in 0..<selectionKeys.count {
let label = selectionKeys.charComponents[j] let label = selectionKeys.charComponents[j]
@ -245,7 +245,7 @@ extension InputHandler {
if index != NSNotFound { if index != NSNotFound {
let candidateIndex = ctlCandidate.candidateIndexAtKeyLabelIndex(index) let candidateIndex = ctlCandidate.candidateIndexAtKeyLabelIndex(index)
if candidateIndex != -114_514 { if candidateIndex != -114_514 {
delegate?.candidateSelectionCalledByInputHandler(at: candidateIndex) delegate.candidateSelectionCalledByInputHandler(at: candidateIndex)
return true return true
} }
} }
@ -285,10 +285,10 @@ extension InputHandler {
if shouldAutoSelectCandidate { if shouldAutoSelectCandidate {
let candidateIndex = ctlCandidate.candidateIndexAtKeyLabelIndex(0) let candidateIndex = ctlCandidate.candidateIndexAtKeyLabelIndex(0)
if candidateIndex != -114_514 { if candidateIndex != -114_514 {
delegate?.candidateSelectionCalledByInputHandler(at: candidateIndex) delegate.candidateSelectionCalledByInputHandler(at: candidateIndex)
stateCallback(IMEState.ofAbortion()) delegate.switchState(IMEState.ofAbortion())
return handleInput( return handleInput(
event: input, state: IMEState.ofEmpty(), stateCallback: stateCallback, errorCallback: errorCallback event: input, state: IMEState.ofEmpty(), errorCallback: errorCallback
) )
} }
return true return true

View File

@ -15,14 +15,14 @@ extension InputHandler {
/// InputHandler.HandleInput() /// InputHandler.HandleInput()
/// - Parameters: /// - Parameters:
/// - input: /// - input:
/// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: IMK /// - Returns: IMK
func handleComposition( func handleComposition(
input: InputSignalProtocol, input: InputSignalProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void,
errorCallback: @escaping (String) -> Void errorCallback: @escaping (String) -> Void
) -> Bool? { ) -> Bool? {
guard let delegate = delegate else { return nil }
// MARK: (Handle BPMF Keys) // MARK: (Handle BPMF Keys)
var keyConsumedByReading = false var keyConsumedByReading = false
@ -65,7 +65,7 @@ extension InputHandler {
// 調 setInlineDisplayWithCursor() return true // 調 setInlineDisplayWithCursor() return true
// 調 // 調
if !composer.hasToneMarker() { if !composer.hasToneMarker() {
stateCallback(generateStateOfInputting()) delegate.switchState(generateStateOfInputting())
return true return true
} }
} }
@ -90,16 +90,16 @@ extension InputHandler {
if prefs.keepReadingUponCompositionError { if prefs.keepReadingUponCompositionError {
composer.intonation.clear() // 調 composer.intonation.clear() // 調
stateCallback(generateStateOfInputting()) delegate.switchState(generateStateOfInputting())
return true return true
} }
composer.clear() composer.clear()
// //
switch compositor.isEmpty { switch compositor.isEmpty {
case false: stateCallback(generateStateOfInputting()) case false: delegate.switchState(generateStateOfInputting())
case true: case true:
stateCallback(IMEState.ofAbortion()) delegate.switchState(IMEState.ofAbortion())
} }
return true // IMK return true // IMK
} }
@ -122,27 +122,27 @@ extension InputHandler {
// setInlineDisplayWithCursor() // setInlineDisplayWithCursor()
var inputting = generateStateOfInputting() var inputting = generateStateOfInputting()
inputting.textToCommit = textToCommit inputting.textToCommit = textToCommit
stateCallback(inputting) delegate.switchState(inputting)
/// ///
if prefs.useSCPCTypingMode { if prefs.useSCPCTypingMode {
let candidateState: IMEStateProtocol = generateStateOfCandidates(state: inputting) let candidateState: IMEStateProtocol = generateStateOfCandidates(state: inputting)
switch candidateState.candidates.count { switch candidateState.candidates.count {
case 2...: stateCallback(candidateState) case 2...: delegate.switchState(candidateState)
case 1: case 1:
let firstCandidate = candidateState.candidates.first! // let firstCandidate = candidateState.candidates.first! //
let reading: String = firstCandidate.0 let reading: String = firstCandidate.0
let text: String = firstCandidate.1 let text: String = firstCandidate.1
stateCallback(IMEState.ofCommitting(textToCommit: text)) delegate.switchState(IMEState.ofCommitting(textToCommit: text))
if !prefs.associatedPhrasesEnabled { if !prefs.associatedPhrasesEnabled {
stateCallback(IMEState.ofEmpty()) delegate.switchState(IMEState.ofEmpty())
} else { } else {
let associatedPhrases = let associatedPhrases =
generateStateOfAssociates( generateStateOfAssociates(
withPair: .init(key: reading, value: text) withPair: .init(key: reading, value: text)
) )
stateCallback(associatedPhrases.candidates.isEmpty ? IMEState.ofEmpty() : associatedPhrases) delegate.switchState(associatedPhrases.candidates.isEmpty ? IMEState.ofEmpty() : associatedPhrases)
} }
default: break default: break
} }
@ -154,7 +154,7 @@ extension InputHandler {
/// 調 /// 調
if keyConsumedByReading { if keyConsumedByReading {
// setInlineDisplayWithCursor() // setInlineDisplayWithCursor()
stateCallback(generateStateOfInputting()) delegate.switchState(generateStateOfInputting())
return true return true
} }
return nil return nil

View File

@ -18,22 +18,18 @@ extension InputHandler {
/// - Parameter event: IMK /// - Parameter event: IMK
/// - Returns: `true` IMK`false` /// - Returns: `true` IMK`false`
public func handleEvent(_ event: NSEvent) -> Bool { public func handleEvent(_ event: NSEvent) -> Bool {
imkCandidatesEventPreHandler(event: event) ?? commonEventHandler(event) imkCandidatesEventPreHandler(event: event) ?? doHandleInput(event)
} }
/// 調 /// 調
/// result bool IMK /// result bool IMK
/// handleCandidate() /// handleCandidate()
private func commonEventHandler(_ event: NSEvent) -> Bool { private func doHandleInput(_ event: NSEvent) -> Bool {
guard let delegate = delegate else { return false } guard let delegate = delegate else { return false }
return handleInput(event: event, state: delegate.state) { errorString in
let result = handleInput(event: event, state: delegate.state) { newState in
delegate.handle(state: newState, replaceCurrent: true)
} errorCallback: { errorString in
vCLog(errorString) vCLog(errorString)
IMEApp.buzz() IMEApp.buzz()
} }
return result
} }
/// IMK /// IMK
@ -84,7 +80,7 @@ extension InputHandler {
let eventArray = [event] let eventArray = [event]
guard let imkC = delegate.candidateController() as? CtlCandidateIMK else { return false } guard let imkC = delegate.candidateController() as? CtlCandidateIMK else { return false }
if event.isEsc || event.isBackSpace || event.isDelete || (event.isShiftHold && !event.isSpace) { if event.isEsc || event.isBackSpace || event.isDelete || (event.isShiftHold && !event.isSpace) {
return commonEventHandler(event) return doHandleInput(event)
} else if event.isSymbolMenuPhysicalKey { } else if event.isSymbolMenuPhysicalKey {
// //
switch imkC.currentLayout { switch imkC.currentLayout {
@ -113,7 +109,7 @@ extension InputHandler {
if let newEvent = newEvent { if let newEvent = newEvent {
if prefs.useSCPCTypingMode, delegate.state.type == .ofAssociates { if prefs.useSCPCTypingMode, delegate.state.type == .ofAssociates {
// input.isShiftHold Self.handle() // input.isShiftHold Self.handle()
return event.isShiftHold ? true : commonEventHandler(event) return event.isShiftHold ? true : doHandleInput(event)
} else { } else {
if #available(macOS 10.14, *) { if #available(macOS 10.14, *) {
imkC.handleKeyboardEvent(newEvent) imkC.handleKeyboardEvent(newEvent)
@ -126,7 +122,7 @@ extension InputHandler {
} }
if prefs.useSCPCTypingMode, !event.isReservedKey { if prefs.useSCPCTypingMode, !event.isReservedKey {
return commonEventHandler(event) return doHandleInput(event)
} }
if delegate.state.type == .ofAssociates, if delegate.state.type == .ofAssociates,
@ -134,7 +130,7 @@ extension InputHandler {
!event.isCursorClockLeft, !event.isCursorClockRight, !event.isSpace, !event.isCursorClockLeft, !event.isCursorClockRight, !event.isSpace,
!event.isEnter || !prefs.alsoConfirmAssociatedCandidatesByEnter !event.isEnter || !prefs.alsoConfirmAssociatedCandidatesByEnter
{ {
return commonEventHandler(event) return doHandleInput(event)
} }
imkC.interpretKeyEvents(eventArray) imkC.interpretKeyEvents(eventArray)
return true return true

View File

@ -21,17 +21,17 @@ extension InputHandler {
/// - Parameters: /// - Parameters:
/// - input: /// - input:
/// - state: /// - state:
/// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: IMK /// - Returns: IMK
func handleInput( func handleInput(
event input: InputSignalProtocol, event input: InputSignalProtocol,
state: IMEStateProtocol, state: IMEStateProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void,
errorCallback: @escaping (String) -> Void errorCallback: @escaping (String) -> Void
) -> Bool { ) -> Bool {
// inputTest // inputTest
guard !input.text.isEmpty, input.charCode.isPrintable else { return false } //
// delegate
guard !input.text.isEmpty, input.charCode.isPrintable, let delegate = delegate else { return false }
let inputText: String = input.text let inputText: String = input.text
var state = state // var state = state //
@ -44,7 +44,7 @@ extension InputHandler {
return false return false
} }
errorCallback("550BCF7B: InputHandler just refused an invalid input.") errorCallback("550BCF7B: InputHandler just refused an invalid input.")
stateCallback(state) delegate.switchState(state)
return true return true
} }
@ -66,7 +66,7 @@ extension InputHandler {
// BackSpace // BackSpace
} else if input.isCapsLockOn || state.isASCIIMode { } else if input.isCapsLockOn || state.isASCIIMode {
// //
stateCallback(IMEState.ofEmpty()) delegate.switchState(IMEState.ofEmpty())
// Shift // Shift
if (input.isUpperCaseASCIILetterKey && state.isASCIIMode) if (input.isUpperCaseASCIILetterKey && state.isASCIIMode)
@ -82,8 +82,8 @@ extension InputHandler {
} }
// //
stateCallback(IMEState.ofCommitting(textToCommit: inputText.lowercased())) delegate.switchState(IMEState.ofCommitting(textToCommit: inputText.lowercased()))
stateCallback(IMEState.ofEmpty()) delegate.switchState(IMEState.ofEmpty())
return true return true
} }
@ -97,9 +97,9 @@ extension InputHandler {
if !(state.type == .ofCandidates || state.type == .ofAssociates if !(state.type == .ofCandidates || state.type == .ofAssociates
|| state.type == .ofSymbolTable) || state.type == .ofSymbolTable)
{ {
stateCallback(IMEState.ofEmpty()) delegate.switchState(IMEState.ofEmpty())
stateCallback(IMEState.ofCommitting(textToCommit: inputText.lowercased())) delegate.switchState(IMEState.ofCommitting(textToCommit: inputText.lowercased()))
stateCallback(IMEState.ofEmpty()) delegate.switchState(IMEState.ofEmpty())
return true return true
} }
} }
@ -108,7 +108,7 @@ extension InputHandler {
if [.ofCandidates, .ofSymbolTable].contains(state.type) { if [.ofCandidates, .ofSymbolTable].contains(state.type) {
return handleCandidate( return handleCandidate(
state: state, input: input, stateCallback: stateCallback, errorCallback: errorCallback state: state, input: input, errorCallback: errorCallback
) )
} }
@ -116,11 +116,11 @@ extension InputHandler {
if state.type == .ofAssociates { if state.type == .ofAssociates {
if handleCandidate( if handleCandidate(
state: state, input: input, stateCallback: stateCallback, errorCallback: errorCallback state: state, input: input, errorCallback: errorCallback
) { ) {
return true return true
} else { } else {
stateCallback(IMEState.ofEmpty()) delegate.switchState(IMEState.ofEmpty())
} }
} }
@ -128,19 +128,19 @@ extension InputHandler {
if state.type == .ofMarking { if state.type == .ofMarking {
if handleMarkingState( if handleMarkingState(
state, input: input, stateCallback: stateCallback, state, input: input,
errorCallback: errorCallback errorCallback: errorCallback
) { ) {
return true return true
} }
state = state.convertedToInputting state = state.convertedToInputting
stateCallback(state) delegate.switchState(state)
} }
// MARK: (Handle BPMF Keys) // MARK: (Handle BPMF Keys)
if let compositionHandled = handleComposition( if let compositionHandled = handleComposition(
input: input, stateCallback: stateCallback, errorCallback: errorCallback input: input, errorCallback: errorCallback
) { ) {
return compositionHandled return compositionHandled
} }
@ -157,10 +157,10 @@ extension InputHandler {
if compositor.cursor >= compositor.length { if compositor.cursor >= compositor.length {
let displayedText = state.displayedText let displayedText = state.displayedText
if !displayedText.isEmpty { if !displayedText.isEmpty {
stateCallback(IMEState.ofCommitting(textToCommit: displayedText)) delegate.switchState(IMEState.ofCommitting(textToCommit: displayedText))
} }
stateCallback(IMEState.ofCommitting(textToCommit: " ")) delegate.switchState(IMEState.ofCommitting(textToCommit: " "))
stateCallback(IMEState.ofEmpty()) delegate.switchState(IMEState.ofEmpty())
} else if currentLM.hasUnigramsFor(key: " ") { } else if currentLM.hasUnigramsFor(key: " ") {
compositor.insertKey(" ") compositor.insertKey(" ")
walk() walk()
@ -168,12 +168,12 @@ extension InputHandler {
let textToCommit = commitOverflownComposition let textToCommit = commitOverflownComposition
var inputting = generateStateOfInputting() var inputting = generateStateOfInputting()
inputting.textToCommit = textToCommit inputting.textToCommit = textToCommit
stateCallback(inputting) delegate.switchState(inputting)
} }
return true return true
} else if input.isShiftHold { // Tab Shift+Command+Space / } else if input.isShiftHold { // Tab Shift+Command+Space /
return handleInlineCandidateRotation( return handleInlineCandidateRotation(
state: state, reverseModifier: input.isCommandHold, stateCallback: stateCallback, state: state, reverseModifier: input.isCommandHold,
errorCallback: errorCallback errorCallback: errorCallback
) )
} }
@ -182,7 +182,7 @@ extension InputHandler {
if candidateState.candidates.isEmpty { if candidateState.candidates.isEmpty {
errorCallback("3572F238") errorCallback("3572F238")
} else { } else {
stateCallback(candidateState) delegate.switchState(candidateState)
} }
return true return true
} }
@ -191,56 +191,56 @@ extension InputHandler {
if let keyCodeType = KeyCode(rawValue: input.keyCode) { if let keyCodeType = KeyCode(rawValue: input.keyCode) {
switch keyCodeType { switch keyCodeType {
case .kEscape: return handleEsc(state: state, stateCallback: stateCallback) case .kEscape: return handleEsc(state: state)
case .kTab: case .kTab:
return handleInlineCandidateRotation( return handleInlineCandidateRotation(
state: state, reverseModifier: input.isShiftHold, stateCallback: stateCallback, errorCallback: errorCallback state: state, reverseModifier: input.isShiftHold, errorCallback: errorCallback
) )
case .kUpArrow, .kDownArrow, .kLeftArrow, .kRightArrow: case .kUpArrow, .kDownArrow, .kLeftArrow, .kRightArrow:
if (input.isControlHold || input.isShiftHold) && (input.isOptionHold) { if (input.isControlHold || input.isShiftHold) && (input.isOptionHold) {
if input.isLeft { // Ctrl+PgLf / Shift+PgLf if input.isLeft { // Ctrl+PgLf / Shift+PgLf
return handleHome(state: state, stateCallback: stateCallback, errorCallback: errorCallback) return handleHome(state: state, errorCallback: errorCallback)
} else if input.isRight { // Ctrl+PgRt or Shift+PgRt } else if input.isRight { // Ctrl+PgRt or Shift+PgRt
return handleEnd(state: state, stateCallback: stateCallback, errorCallback: errorCallback) return handleEnd(state: state, errorCallback: errorCallback)
} }
} }
if input.isCursorBackward { // Forward if input.isCursorBackward { // Forward
return handleBackward( return handleBackward(
state: state, input: input, stateCallback: stateCallback, errorCallback: errorCallback state: state, input: input, errorCallback: errorCallback
) )
} }
if input.isCursorForward { // Backward if input.isCursorForward { // Backward
return handleForward( return handleForward(
state: state, input: input, stateCallback: stateCallback, errorCallback: errorCallback state: state, input: input, errorCallback: errorCallback
) )
} }
if input.isCursorClockLeft || input.isCursorClockRight { // Clock keys if input.isCursorClockLeft || input.isCursorClockRight { // Clock keys
if input.isOptionHold, state.type == .ofInputting { if input.isOptionHold, state.type == .ofInputting {
if input.isCursorClockRight { if input.isCursorClockRight {
return handleInlineCandidateRotation( return handleInlineCandidateRotation(
state: state, reverseModifier: false, stateCallback: stateCallback, errorCallback: errorCallback state: state, reverseModifier: false, errorCallback: errorCallback
) )
} }
if input.isCursorClockLeft { if input.isCursorClockLeft {
return handleInlineCandidateRotation( return handleInlineCandidateRotation(
state: state, reverseModifier: true, stateCallback: stateCallback, errorCallback: errorCallback state: state, reverseModifier: true, errorCallback: errorCallback
) )
} }
} }
return handleClockKey(state: state, stateCallback: stateCallback, errorCallback: errorCallback) return handleClockKey(state: state, errorCallback: errorCallback)
} }
case .kHome: return handleHome(state: state, stateCallback: stateCallback, errorCallback: errorCallback) case .kHome: return handleHome(state: state, errorCallback: errorCallback)
case .kEnd: return handleEnd(state: state, stateCallback: stateCallback, errorCallback: errorCallback) case .kEnd: return handleEnd(state: state, errorCallback: errorCallback)
case .kBackSpace: case .kBackSpace:
return handleBackSpace(state: state, input: input, stateCallback: stateCallback, errorCallback: errorCallback) return handleBackSpace(state: state, input: input, errorCallback: errorCallback)
case .kWindowsDelete: case .kWindowsDelete:
return handleDelete(state: state, input: input, stateCallback: stateCallback, errorCallback: errorCallback) return handleDelete(state: state, input: input, errorCallback: errorCallback)
case .kCarriageReturn, .kLineFeed: case .kCarriageReturn, .kLineFeed:
return (input.isCommandHold && input.isControlHold) return (input.isCommandHold && input.isControlHold)
? (input.isOptionHold ? (input.isOptionHold
? handleCtrlOptionCommandEnter(state: state, stateCallback: stateCallback) ? handleCtrlOptionCommandEnter(state: state)
: handleCtrlCommandEnter(state: state, stateCallback: stateCallback)) : handleCtrlCommandEnter(state: state))
: handleEnter(state: state, stateCallback: stateCallback) : handleEnter(state: state)
default: break default: break
} }
} }
@ -257,12 +257,12 @@ extension InputHandler {
let textToCommit = commitOverflownComposition let textToCommit = commitOverflownComposition
var inputting = generateStateOfInputting() var inputting = generateStateOfInputting()
inputting.textToCommit = textToCommit inputting.textToCommit = textToCommit
stateCallback(inputting) delegate.switchState(inputting)
let candidateState = generateStateOfCandidates(state: inputting) let candidateState = generateStateOfCandidates(state: inputting)
if candidateState.candidates.isEmpty { if candidateState.candidates.isEmpty {
errorCallback("B5127D8A") errorCallback("B5127D8A")
} else { } else {
stateCallback(candidateState) delegate.switchState(candidateState)
} }
} else { // } else { //
errorCallback("17446655") errorCallback("17446655")
@ -273,8 +273,8 @@ extension InputHandler {
// commit buffer ESC // commit buffer ESC
// Enter 使 commit buffer // Enter 使 commit buffer
// bool _ = // bool _ =
_ = handleEnter(state: state, stateCallback: stateCallback) _ = handleEnter(state: state)
stateCallback(IMEState.ofSymbolTable(node: CandidateNode.root)) delegate.switchState(IMEState.ofSymbolTable(node: CandidateNode.root))
return true return true
} }
} }
@ -286,10 +286,10 @@ extension InputHandler {
guard let stringRAW = input.mainAreaNumKeyChar else { return false } guard let stringRAW = input.mainAreaNumKeyChar else { return false }
let newStringFW = stringRAW.applyingTransform(.fullwidthToHalfwidth, reverse: true) ?? stringRAW let newStringFW = stringRAW.applyingTransform(.fullwidthToHalfwidth, reverse: true) ?? stringRAW
let newStringHW = stringRAW.applyingTransform(.fullwidthToHalfwidth, reverse: false) ?? stringRAW let newStringHW = stringRAW.applyingTransform(.fullwidthToHalfwidth, reverse: false) ?? stringRAW
stateCallback( delegate.switchState(
IMEState.ofCommitting(textToCommit: prefs.halfWidthPunctuationEnabled ? newStringHW : newStringFW) IMEState.ofCommitting(textToCommit: prefs.halfWidthPunctuationEnabled ? newStringHW : newStringFW)
) )
stateCallback(IMEState.ofEmpty()) delegate.switchState(IMEState.ofEmpty())
return true return true
} }
} }
@ -307,7 +307,6 @@ extension InputHandler {
if handlePunctuation( if handlePunctuation(
customPunctuation, customPunctuation,
state: state, state: state,
stateCallback: stateCallback,
errorCallback: errorCallback errorCallback: errorCallback
) { ) {
return true return true
@ -321,7 +320,6 @@ extension InputHandler {
if handlePunctuation( if handlePunctuation(
punctuation, punctuation,
state: state, state: state,
stateCallback: stateCallback,
errorCallback: errorCallback errorCallback: errorCallback
) { ) {
return true return true
@ -332,8 +330,8 @@ extension InputHandler {
/// 使 /// 使
if state.type == .ofEmpty { if state.type == .ofEmpty {
if input.isSpace, !input.isOptionHold, !input.isControlHold, !input.isCommandHold { if input.isSpace, !input.isOptionHold, !input.isControlHold, !input.isCommandHold {
stateCallback(IMEState.ofCommitting(textToCommit: input.isShiftHold ? " " : " ")) delegate.switchState(IMEState.ofCommitting(textToCommit: input.isShiftHold ? " " : " "))
stateCallback(IMEState.ofEmpty()) delegate.switchState(IMEState.ofEmpty())
return true return true
} }
} }
@ -344,22 +342,21 @@ extension InputHandler {
if input.isShiftHold { // isOptionHold if input.isShiftHold { // isOptionHold
switch prefs.upperCaseLetterKeyBehavior { switch prefs.upperCaseLetterKeyBehavior {
case 1: case 1:
stateCallback(IMEState.ofEmpty()) delegate.switchState(IMEState.ofEmpty())
stateCallback(IMEState.ofCommitting(textToCommit: inputText.lowercased())) delegate.switchState(IMEState.ofCommitting(textToCommit: inputText.lowercased()))
stateCallback(IMEState.ofEmpty()) delegate.switchState(IMEState.ofEmpty())
return true return true
case 2: case 2:
stateCallback(IMEState.ofEmpty()) delegate.switchState(IMEState.ofEmpty())
stateCallback(IMEState.ofCommitting(textToCommit: inputText.uppercased())) delegate.switchState(IMEState.ofCommitting(textToCommit: inputText.uppercased()))
stateCallback(IMEState.ofEmpty()) delegate.switchState(IMEState.ofEmpty())
return true return true
default: // case 0 default: // case 0
let letter = "_letter_\(inputText)" let letter = "_letter_\(inputText)"
if handlePunctuation( if handlePunctuation(
letter, letter,
state: state, state: state,
stateCallback: stateCallback,
errorCallback: errorCallback errorCallback: errorCallback
) { ) {
return true return true
@ -378,7 +375,7 @@ extension InputHandler {
errorCallback( errorCallback(
"Blocked data: charCode: \(input.charCode), keyCode: \(input.keyCode)") "Blocked data: charCode: \(input.charCode), keyCode: \(input.keyCode)")
errorCallback("A9BFF20E") errorCallback("A9BFF20E")
stateCallback(state) delegate.switchState(state)
return true return true
} }

View File

@ -123,17 +123,17 @@ extension InputHandler {
/// - Parameters: /// - Parameters:
/// - state: /// - state:
/// - input: /// - input:
/// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: SessionCtl IMK /// - Returns: SessionCtl IMK
func handleMarkingState( func handleMarkingState(
_ state: IMEStateProtocol, _ state: IMEStateProtocol,
input: InputSignalProtocol, input: InputSignalProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void,
errorCallback: @escaping (String) -> Void errorCallback: @escaping (String) -> Void
) -> Bool { ) -> Bool {
guard let delegate = delegate else { return false }
if input.isEsc { if input.isEsc {
stateCallback(generateStateOfInputting()) delegate.switchState(generateStateOfInputting())
return true return true
} }
@ -145,38 +145,34 @@ extension InputHandler {
// Enter // Enter
if input.isEnter { if input.isEnter {
if let sessionCtl = delegate { //
// if input.isShiftHold, input.isCommandHold, !state.isFilterable {
if input.isShiftHold, input.isCommandHold, !state.isFilterable { errorCallback("2EAC1F7A")
errorCallback("2EAC1F7A") return true
return true
}
if !state.isMarkedLengthValid {
errorCallback("9AAFAC00")
return true
}
if !sessionCtl.performUserPhraseOperation(with: state, addToFilter: false) {
errorCallback("5B69CC8D")
return true
}
} }
stateCallback(generateStateOfInputting()) if !state.isMarkedLengthValid {
errorCallback("9AAFAC00")
return true
}
if !delegate.performUserPhraseOperation(with: state, addToFilter: false) {
errorCallback("5B69CC8D")
return true
}
delegate.switchState(generateStateOfInputting())
return true return true
} }
// BackSpace & Delete // BackSpace & Delete
if input.isBackSpace || input.isDelete { if input.isBackSpace || input.isDelete {
if let inputHandlerDelegate = delegate { if !state.isFilterable {
if !state.isFilterable { errorCallback("1F88B191")
errorCallback("1F88B191") return true
return true
}
if !inputHandlerDelegate.performUserPhraseOperation(with: state, addToFilter: true) {
errorCallback("68D3C6C8")
return true
}
} }
stateCallback(generateStateOfInputting()) if !delegate.performUserPhraseOperation(with: state, addToFilter: true) {
errorCallback("68D3C6C8")
return true
}
delegate.switchState(generateStateOfInputting())
return true return true
} }
@ -194,10 +190,10 @@ extension InputHandler {
marker: convertCursorForDisplay(compositor.marker) marker: convertCursorForDisplay(compositor.marker)
) )
marking.tooltipBackupForInputting = state.tooltipBackupForInputting marking.tooltipBackupForInputting = state.tooltipBackupForInputting
stateCallback(marking.markedRange.isEmpty ? marking.convertedToInputting : marking) delegate.switchState(marking.markedRange.isEmpty ? marking.convertedToInputting : marking)
} else { } else {
errorCallback("1149908D") errorCallback("1149908D")
stateCallback(state) delegate.switchState(state)
} }
return true return true
} }
@ -216,10 +212,10 @@ extension InputHandler {
marker: convertCursorForDisplay(compositor.marker) marker: convertCursorForDisplay(compositor.marker)
) )
marking.tooltipBackupForInputting = state.tooltipBackupForInputting marking.tooltipBackupForInputting = state.tooltipBackupForInputting
stateCallback(marking.markedRange.isEmpty ? marking.convertedToInputting : marking) delegate.switchState(marking.markedRange.isEmpty ? marking.convertedToInputting : marking)
} else { } else {
errorCallback("9B51408D") errorCallback("9B51408D")
stateCallback(state) delegate.switchState(state)
} }
return true return true
} }
@ -231,15 +227,15 @@ extension InputHandler {
/// ///
/// - Parameters: /// - Parameters:
/// - customPunctuation: /// - customPunctuation:
/// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: SessionCtl IMK /// - Returns: SessionCtl IMK
func handlePunctuation( func handlePunctuation(
_ customPunctuation: String, _ customPunctuation: String,
state: IMEStateProtocol, state: IMEStateProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void,
errorCallback: @escaping (String) -> Void errorCallback: @escaping (String) -> Void
) -> Bool { ) -> Bool {
guard let delegate = delegate else { return false }
if !currentLM.hasUnigramsFor(key: customPunctuation) { if !currentLM.hasUnigramsFor(key: customPunctuation) {
return false return false
} }
@ -247,7 +243,7 @@ extension InputHandler {
guard composer.isEmpty else { guard composer.isEmpty else {
// //
errorCallback("A9B69908D") errorCallback("A9B69908D")
stateCallback(state) delegate.switchState(state)
return true return true
} }
@ -257,21 +253,21 @@ extension InputHandler {
let textToCommit = commitOverflownComposition let textToCommit = commitOverflownComposition
var inputting = generateStateOfInputting() var inputting = generateStateOfInputting()
inputting.textToCommit = textToCommit inputting.textToCommit = textToCommit
stateCallback(inputting) delegate.switchState(inputting)
// //
guard prefs.useSCPCTypingMode, composer.isEmpty else { return true } guard prefs.useSCPCTypingMode, composer.isEmpty else { return true }
let candidateState = generateStateOfCandidates(state: inputting) let candidateState = generateStateOfCandidates(state: inputting)
switch candidateState.candidates.count { switch candidateState.candidates.count {
case 2...: stateCallback(candidateState) case 2...: delegate.switchState(candidateState)
case 1: case 1:
clear() // candidateState clear() // candidateState
if let candidateToCommit: (String, String) = candidateState.candidates.first, !candidateToCommit.1.isEmpty { if let candidateToCommit: (String, String) = candidateState.candidates.first, !candidateToCommit.1.isEmpty {
stateCallback(IMEState.ofCommitting(textToCommit: candidateToCommit.1)) delegate.switchState(IMEState.ofCommitting(textToCommit: candidateToCommit.1))
stateCallback(IMEState.ofEmpty()) delegate.switchState(IMEState.ofEmpty())
} else { } else {
stateCallback(candidateState) delegate.switchState(candidateState)
} }
default: errorCallback("8DA4096E") default: errorCallback("8DA4096E")
} }
@ -283,16 +279,15 @@ extension InputHandler {
/// Enter /// Enter
/// - Parameters: /// - Parameters:
/// - state: /// - state:
/// - stateCallback:
/// - Returns: SessionCtl IMK /// - Returns: SessionCtl IMK
func handleEnter( func handleEnter(
state: IMEStateProtocol, state: IMEStateProtocol
stateCallback: @escaping (IMEStateProtocol) -> Void
) -> Bool { ) -> Bool {
guard let delegate = delegate else { return false }
guard state.type == .ofInputting else { return false } guard state.type == .ofInputting else { return false }
stateCallback(IMEState.ofCommitting(textToCommit: state.displayedText)) delegate.switchState(IMEState.ofCommitting(textToCommit: state.displayedText))
stateCallback(IMEState.ofEmpty()) delegate.switchState(IMEState.ofEmpty())
return true return true
} }
@ -301,12 +296,11 @@ extension InputHandler {
/// Command+Enter /// Command+Enter
/// - Parameters: /// - Parameters:
/// - state: /// - state:
/// - stateCallback:
/// - Returns: SessionCtl IMK /// - Returns: SessionCtl IMK
func handleCtrlCommandEnter( func handleCtrlCommandEnter(
state: IMEStateProtocol, state: IMEStateProtocol
stateCallback: @escaping (IMEStateProtocol) -> Void
) -> Bool { ) -> Bool {
guard let delegate = delegate else { return false }
guard state.type == .ofInputting else { return false } guard state.type == .ofInputting else { return false }
var displayedText = compositor.keys.joined(separator: "-") var displayedText = compositor.keys.joined(separator: "-")
@ -315,12 +309,12 @@ extension InputHandler {
displayedText = Tekkon.cnvPhonaToHanyuPinyin(target: displayedText) // displayedText = Tekkon.cnvPhonaToHanyuPinyin(target: displayedText) //
} }
if let delegate = delegate, !delegate.clientBundleIdentifier.contains("vChewingPhraseEditor") { if !delegate.clientBundleIdentifier.contains("vChewingPhraseEditor") {
displayedText = displayedText.replacingOccurrences(of: "-", with: " ") displayedText = displayedText.replacingOccurrences(of: "-", with: " ")
} }
stateCallback(IMEState.ofCommitting(textToCommit: displayedText)) delegate.switchState(IMEState.ofCommitting(textToCommit: displayedText))
stateCallback(IMEState.ofEmpty()) delegate.switchState(IMEState.ofEmpty())
return true return true
} }
@ -329,12 +323,11 @@ extension InputHandler {
/// Command+Option+Enter Ruby /// Command+Option+Enter Ruby
/// - Parameters: /// - Parameters:
/// - state: /// - state:
/// - stateCallback:
/// - Returns: SessionCtl IMK /// - Returns: SessionCtl IMK
func handleCtrlOptionCommandEnter( func handleCtrlOptionCommandEnter(
state: IMEStateProtocol, state: IMEStateProtocol
stateCallback: @escaping (IMEStateProtocol) -> Void
) -> Bool { ) -> Bool {
guard let delegate = delegate else { return false }
guard state.type == .ofInputting else { return false } guard state.type == .ofInputting else { return false }
var composed = "" var composed = ""
@ -355,8 +348,8 @@ extension InputHandler {
composed += key.contains("_") ? value : "<ruby>\(value)<rp>(</rp><rt>\(key)</rt><rp>)</rp></ruby>" composed += key.contains("_") ? value : "<ruby>\(value)<rp>(</rp><rt>\(key)</rt><rp>)</rp></ruby>"
} }
stateCallback(IMEState.ofCommitting(textToCommit: composed)) delegate.switchState(IMEState.ofCommitting(textToCommit: composed))
stateCallback(IMEState.ofEmpty()) delegate.switchState(IMEState.ofEmpty())
return true return true
} }
@ -366,15 +359,14 @@ extension InputHandler {
/// - Parameters: /// - Parameters:
/// - state: /// - state:
/// - input: /// - input:
/// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: SessionCtl IMK /// - Returns: SessionCtl IMK
func handleBackSpace( func handleBackSpace(
state: IMEStateProtocol, state: IMEStateProtocol,
input: InputSignalProtocol, input: InputSignalProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void,
errorCallback: @escaping (String) -> Void errorCallback: @escaping (String) -> Void
) -> Bool { ) -> Bool {
guard let delegate = delegate else { return false }
guard state.type == .ofInputting else { return false } guard state.type == .ofInputting else { return false }
// macOS Shift+BackSpace // macOS Shift+BackSpace
@ -386,16 +378,16 @@ extension InputHandler {
compositor.dropKey(direction: .rear) compositor.dropKey(direction: .rear)
walk() // Walk walk walk() // Walk walk
prevReading.1.charComponents.forEach { composer.receiveKey(fromPhonabet: $0) } prevReading.1.charComponents.forEach { composer.receiveKey(fromPhonabet: $0) }
stateCallback(generateStateOfInputting()) delegate.switchState(generateStateOfInputting())
return true return true
case 1: case 1:
stateCallback(IMEState.ofAbortion()) delegate.switchState(IMEState.ofAbortion())
return true return true
default: break default: break
} }
if input.isShiftHold, input.isOptionHold { if input.isShiftHold, input.isOptionHold {
stateCallback(IMEState.ofAbortion()) delegate.switchState(IMEState.ofAbortion())
return true return true
} }
@ -407,7 +399,7 @@ extension InputHandler {
walk() walk()
} else { } else {
errorCallback("9D69908D") errorCallback("9D69908D")
stateCallback(state) delegate.switchState(state)
return true return true
} }
} else { } else {
@ -415,9 +407,9 @@ extension InputHandler {
} }
switch composer.isEmpty && compositor.isEmpty { switch composer.isEmpty && compositor.isEmpty {
case false: stateCallback(generateStateOfInputting()) case false: delegate.switchState(generateStateOfInputting())
case true: case true:
stateCallback(IMEState.ofAbortion()) delegate.switchState(IMEState.ofAbortion())
} }
return true return true
} }
@ -428,25 +420,24 @@ extension InputHandler {
/// - Parameters: /// - Parameters:
/// - state: /// - state:
/// - input: /// - input:
/// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: SessionCtl IMK /// - Returns: SessionCtl IMK
func handleDelete( func handleDelete(
state: IMEStateProtocol, state: IMEStateProtocol,
input: InputSignalProtocol, input: InputSignalProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void,
errorCallback: @escaping (String) -> Void errorCallback: @escaping (String) -> Void
) -> Bool { ) -> Bool {
guard let delegate = delegate else { return false }
guard state.type == .ofInputting else { return false } guard state.type == .ofInputting else { return false }
if input.isShiftHold { if input.isShiftHold {
stateCallback(IMEState.ofAbortion()) delegate.switchState(IMEState.ofAbortion())
return true return true
} }
if compositor.cursor == compositor.length, composer.isEmpty { if compositor.cursor == compositor.length, composer.isEmpty {
errorCallback("9B69938D") errorCallback("9B69938D")
stateCallback(state) delegate.switchState(state)
return true return true
} }
@ -460,9 +451,9 @@ extension InputHandler {
let inputting = generateStateOfInputting() let inputting = generateStateOfInputting()
// count > 0!isEmpty滿 // count > 0!isEmpty滿
switch inputting.displayedText.isEmpty { switch inputting.displayedText.isEmpty {
case false: stateCallback(inputting) case false: delegate.switchState(inputting)
case true: case true:
stateCallback(IMEState.ofAbortion()) delegate.switchState(IMEState.ofAbortion())
} }
return true return true
} }
@ -472,19 +463,18 @@ extension InputHandler {
/// 90 /// 90
/// - Parameters: /// - Parameters:
/// - state: /// - state:
/// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: SessionCtl IMK /// - Returns: SessionCtl IMK
func handleClockKey( func handleClockKey(
state: IMEStateProtocol, state: IMEStateProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void,
errorCallback: @escaping (String) -> Void errorCallback: @escaping (String) -> Void
) -> Bool { ) -> Bool {
guard let delegate = delegate else { return false }
guard state.type == .ofInputting else { return false } guard state.type == .ofInputting else { return false }
if !composer.isEmpty { if !composer.isEmpty {
errorCallback("9B6F908D") errorCallback("9B6F908D")
} }
stateCallback(state) delegate.switchState(state)
return true return true
} }
@ -493,28 +483,27 @@ extension InputHandler {
/// Home /// Home
/// - Parameters: /// - Parameters:
/// - state: /// - state:
/// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: SessionCtl IMK /// - Returns: SessionCtl IMK
func handleHome( func handleHome(
state: IMEStateProtocol, state: IMEStateProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void,
errorCallback: @escaping (String) -> Void errorCallback: @escaping (String) -> Void
) -> Bool { ) -> Bool {
guard let delegate = delegate else { return false }
guard state.type == .ofInputting else { return false } guard state.type == .ofInputting else { return false }
if !composer.isEmpty { if !composer.isEmpty {
errorCallback("ABC44080") errorCallback("ABC44080")
stateCallback(state) delegate.switchState(state)
return true return true
} }
if compositor.cursor != 0 { if compositor.cursor != 0 {
compositor.cursor = 0 compositor.cursor = 0
stateCallback(generateStateOfInputting()) delegate.switchState(generateStateOfInputting())
} else { } else {
errorCallback("66D97F90") errorCallback("66D97F90")
stateCallback(state) delegate.switchState(state)
} }
return true return true
@ -525,28 +514,27 @@ extension InputHandler {
/// End /// End
/// - Parameters: /// - Parameters:
/// - state: /// - state:
/// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: SessionCtl IMK /// - Returns: SessionCtl IMK
func handleEnd( func handleEnd(
state: IMEStateProtocol, state: IMEStateProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void,
errorCallback: @escaping (String) -> Void errorCallback: @escaping (String) -> Void
) -> Bool { ) -> Bool {
guard let delegate = delegate else { return false }
guard state.type == .ofInputting else { return false } guard state.type == .ofInputting else { return false }
if !composer.isEmpty { if !composer.isEmpty {
errorCallback("9B69908D") errorCallback("9B69908D")
stateCallback(state) delegate.switchState(state)
return true return true
} }
if compositor.cursor != compositor.length { if compositor.cursor != compositor.length {
compositor.cursor = compositor.length compositor.cursor = compositor.length
stateCallback(generateStateOfInputting()) delegate.switchState(generateStateOfInputting())
} else { } else {
errorCallback("9B69908E") errorCallback("9B69908E")
stateCallback(state) delegate.switchState(state)
} }
return true return true
@ -557,26 +545,25 @@ extension InputHandler {
/// Esc /// Esc
/// - Parameters: /// - Parameters:
/// - state: /// - state:
/// - stateCallback:
/// - Returns: SessionCtl IMK /// - Returns: SessionCtl IMK
func handleEsc( func handleEsc(
state: IMEStateProtocol, state: IMEStateProtocol
stateCallback: @escaping (IMEStateProtocol) -> Void
) -> Bool { ) -> Bool {
guard let delegate = delegate else { return false }
guard state.type == .ofInputting else { return false } guard state.type == .ofInputting else { return false }
if prefs.escToCleanInputBuffer { if prefs.escToCleanInputBuffer {
/// ///
/// macOS Windows 使 /// macOS Windows 使
stateCallback(IMEState.ofAbortion()) delegate.switchState(IMEState.ofAbortion())
} else { } else {
if composer.isEmpty { return true } if composer.isEmpty { return true }
/// ///
composer.clear() composer.clear()
switch compositor.isEmpty { switch compositor.isEmpty {
case false: stateCallback(generateStateOfInputting()) case false: delegate.switchState(generateStateOfInputting())
case true: case true:
stateCallback(IMEState.ofAbortion()) delegate.switchState(IMEState.ofAbortion())
} }
} }
return true return true
@ -588,20 +575,19 @@ extension InputHandler {
/// - Parameters: /// - Parameters:
/// - state: /// - state:
/// - input: /// - input:
/// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: SessionCtl IMK /// - Returns: SessionCtl IMK
func handleForward( func handleForward(
state: IMEStateProtocol, state: IMEStateProtocol,
input: InputSignalProtocol, input: InputSignalProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void,
errorCallback: @escaping (String) -> Void errorCallback: @escaping (String) -> Void
) -> Bool { ) -> Bool {
guard let delegate = delegate else { return false }
guard state.type == .ofInputting else { return false } guard state.type == .ofInputting else { return false }
if !composer.isEmpty { if !composer.isEmpty {
errorCallback("B3BA5257") errorCallback("B3BA5257")
stateCallback(state) delegate.switchState(state)
return true return true
} }
@ -619,32 +605,32 @@ extension InputHandler {
marker: convertCursorForDisplay(compositor.marker) marker: convertCursorForDisplay(compositor.marker)
) )
marking.tooltipBackupForInputting = state.tooltip marking.tooltipBackupForInputting = state.tooltip
stateCallback(marking) delegate.switchState(marking)
} else { } else {
errorCallback("BB7F6DB9") errorCallback("BB7F6DB9")
stateCallback(state) delegate.switchState(state)
} }
} else if input.isOptionHold { } else if input.isOptionHold {
if input.isControlHold { if input.isControlHold {
return handleEnd(state: state, stateCallback: stateCallback, errorCallback: errorCallback) return handleEnd(state: state, errorCallback: errorCallback)
} }
// //
if !compositor.jumpCursorBySpan(to: .front) { if !compositor.jumpCursorBySpan(to: .front) {
errorCallback("33C3B580") errorCallback("33C3B580")
stateCallback(state) delegate.switchState(state)
return true return true
} }
stateCallback(generateStateOfInputting()) delegate.switchState(generateStateOfInputting())
} else { } else {
if compositor.cursor < compositor.length { if compositor.cursor < compositor.length {
compositor.cursor += 1 compositor.cursor += 1
if isCursorCuttingChar() { if isCursorCuttingChar() {
compositor.jumpCursorBySpan(to: .front) compositor.jumpCursorBySpan(to: .front)
} }
stateCallback(generateStateOfInputting()) delegate.switchState(generateStateOfInputting())
} else { } else {
errorCallback("A96AAD58") errorCallback("A96AAD58")
stateCallback(state) delegate.switchState(state)
} }
} }
@ -657,20 +643,19 @@ extension InputHandler {
/// - Parameters: /// - Parameters:
/// - state: /// - state:
/// - input: /// - input:
/// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: SessionCtl IMK /// - Returns: SessionCtl IMK
func handleBackward( func handleBackward(
state: IMEStateProtocol, state: IMEStateProtocol,
input: InputSignalProtocol, input: InputSignalProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void,
errorCallback: @escaping (String) -> Void errorCallback: @escaping (String) -> Void
) -> Bool { ) -> Bool {
guard let delegate = delegate else { return false }
guard state.type == .ofInputting else { return false } guard state.type == .ofInputting else { return false }
if !composer.isEmpty { if !composer.isEmpty {
errorCallback("6ED95318") errorCallback("6ED95318")
stateCallback(state) delegate.switchState(state)
return true return true
} }
@ -688,32 +673,32 @@ extension InputHandler {
marker: convertCursorForDisplay(compositor.marker) marker: convertCursorForDisplay(compositor.marker)
) )
marking.tooltipBackupForInputting = state.tooltip marking.tooltipBackupForInputting = state.tooltip
stateCallback(marking) delegate.switchState(marking)
} else { } else {
errorCallback("D326DEA3") errorCallback("D326DEA3")
stateCallback(state) delegate.switchState(state)
} }
} else if input.isOptionHold { } else if input.isOptionHold {
if input.isControlHold { if input.isControlHold {
return handleHome(state: state, stateCallback: stateCallback, errorCallback: errorCallback) return handleHome(state: state, errorCallback: errorCallback)
} }
// //
if !compositor.jumpCursorBySpan(to: .rear) { if !compositor.jumpCursorBySpan(to: .rear) {
errorCallback("8D50DD9E") errorCallback("8D50DD9E")
stateCallback(state) delegate.switchState(state)
return true return true
} }
stateCallback(generateStateOfInputting()) delegate.switchState(generateStateOfInputting())
} else { } else {
if compositor.cursor > 0 { if compositor.cursor > 0 {
compositor.cursor -= 1 compositor.cursor -= 1
if isCursorCuttingChar() { if isCursorCuttingChar() {
compositor.jumpCursorBySpan(to: .rear) compositor.jumpCursorBySpan(to: .rear)
} }
stateCallback(generateStateOfInputting()) delegate.switchState(generateStateOfInputting())
} else { } else {
errorCallback("7045E6F3") errorCallback("7045E6F3")
stateCallback(state) delegate.switchState(state)
} }
} }
@ -726,15 +711,14 @@ extension InputHandler {
/// - Parameters: /// - Parameters:
/// - state: /// - state:
/// - reverseModifier: /// - reverseModifier:
/// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: SessionCtl IMK /// - Returns: SessionCtl IMK
func handleInlineCandidateRotation( func handleInlineCandidateRotation(
state: IMEStateProtocol, state: IMEStateProtocol,
reverseModifier: Bool, reverseModifier: Bool,
stateCallback: @escaping (IMEStateProtocol) -> Void,
errorCallback: @escaping (String) -> Void errorCallback: @escaping (String) -> Void
) -> Bool { ) -> Bool {
guard let delegate = delegate else { return false }
if composer.isEmpty, compositor.isEmpty || compositor.walkedNodes.isEmpty { return false } if composer.isEmpty, compositor.isEmpty || compositor.walkedNodes.isEmpty { return false }
guard state.type == .ofInputting else { guard state.type == .ofInputting else {
guard state.type == .ofEmpty else { guard state.type == .ofEmpty else {
@ -814,7 +798,7 @@ extension InputHandler {
consolidateNode(candidate: candidates[currentIndex], respectCursorPushing: false, preConsolidate: false) consolidateNode(candidate: candidates[currentIndex], respectCursorPushing: false, preConsolidate: false)
stateCallback(generateStateOfInputting()) delegate.switchState(generateStateOfInputting())
return true return true
} }
} }

View File

@ -119,7 +119,7 @@ public class SessionCtl: IMKInputController {
// ---------------------------- // ----------------------------
Self.isVerticalTyping = isVerticalTyping Self.isVerticalTyping = isVerticalTyping
// 使 // 使
handle(state: IMEState.ofEmpty()) switchState(IMEState.ofEmpty())
} }
} }
} }
@ -170,14 +170,14 @@ extension SessionCtl {
// //
if state.type == .ofInputting, PrefMgr.shared.trimUnfinishedReadingsOnCommit { if state.type == .ofInputting, PrefMgr.shared.trimUnfinishedReadingsOnCommit {
inputHandler.composer.clear() inputHandler.composer.clear()
handle(state: inputHandler.generateStateOfInputting()) switchState(inputHandler.generateStateOfInputting())
} }
let isSecureMode = PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier) let isSecureMode = PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier)
if state.hasComposition, !isSecureMode { if state.hasComposition, !isSecureMode {
/// 調 /// 調
handle(state: IMEState.ofCommitting(textToCommit: state.displayedText)) switchState(IMEState.ofCommitting(textToCommit: state.displayedText))
} }
handle(state: isSecureMode ? IMEState.ofAbortion() : IMEState.ofEmpty()) switchState(isSecureMode ? IMEState.ofAbortion() : IMEState.ofEmpty())
} }
} }
@ -208,7 +208,7 @@ extension SessionCtl {
UpdateSputnik.shared.checkForUpdate(forced: false, url: kUpdateInfoSourceURL) UpdateSputnik.shared.checkForUpdate(forced: false, url: kUpdateInfoSourceURL)
} }
handle(state: IMEState.ofEmpty()) switchState(IMEState.ofEmpty())
Self.allInstances.insert(self) Self.allInstances.insert(self)
} }
@ -217,7 +217,7 @@ extension SessionCtl {
public override func deactivateServer(_ sender: Any!) { public override func deactivateServer(_ sender: Any!) {
_ = sender // _ = sender //
resetInputHandler() // Empty resetInputHandler() // Empty
handle(state: IMEState.ofDeactivated()) switchState(IMEState.ofDeactivated())
Self.allInstances.remove(self) Self.allInstances.remove(self)
} }

View File

@ -75,11 +75,11 @@ extension SessionCtl: CtlCandidateDelegate {
if state.type == .ofSymbolTable, (0..<state.node.members.count).contains(index) { if state.type == .ofSymbolTable, (0..<state.node.members.count).contains(index) {
let node = state.node.members[index] let node = state.node.members[index]
if !node.members.isEmpty { if !node.members.isEmpty {
handle(state: IMEState.ofEmpty()) // switchState(IMEState.ofEmpty()) //
handle(state: IMEState.ofSymbolTable(node: node)) switchState(IMEState.ofSymbolTable(node: node))
} else { } else {
handle(state: IMEState.ofCommitting(textToCommit: node.name)) switchState(IMEState.ofCommitting(textToCommit: node.name))
handle(state: IMEState.ofEmpty()) switchState(IMEState.ofEmpty())
} }
return return
} }
@ -94,29 +94,29 @@ extension SessionCtl: CtlCandidateDelegate {
let inputting = inputHandler.generateStateOfInputting() let inputting = inputHandler.generateStateOfInputting()
if PrefMgr.shared.useSCPCTypingMode { if PrefMgr.shared.useSCPCTypingMode {
handle(state: IMEState.ofCommitting(textToCommit: inputting.displayedText)) switchState(IMEState.ofCommitting(textToCommit: inputting.displayedText))
// selectedValue.1 // selectedValue.1
if PrefMgr.shared.associatedPhrasesEnabled { if PrefMgr.shared.associatedPhrasesEnabled {
let associates = inputHandler.generateStateOfAssociates( let associates = inputHandler.generateStateOfAssociates(
withPair: .init(key: selectedValue.0, value: selectedValue.1) withPair: .init(key: selectedValue.0, value: selectedValue.1)
) )
handle(state: associates.candidates.isEmpty ? IMEState.ofEmpty() : associates) switchState(associates.candidates.isEmpty ? IMEState.ofEmpty() : associates)
} else { } else {
handle(state: IMEState.ofEmpty()) switchState(IMEState.ofEmpty())
} }
} else { } else {
handle(state: inputting) switchState(inputting)
} }
return return
} }
if state.type == .ofAssociates { if state.type == .ofAssociates {
let selectedValue = state.candidates[index] let selectedValue = state.candidates[index]
handle(state: IMEState.ofCommitting(textToCommit: selectedValue.1)) switchState(IMEState.ofCommitting(textToCommit: selectedValue.1))
// selectedValue.1 // selectedValue.1
// //
guard let valueKept = selectedValue.1.last else { guard let valueKept = selectedValue.1.last else {
handle(state: IMEState.ofEmpty()) switchState(IMEState.ofEmpty())
return return
} }
if PrefMgr.shared.associatedPhrasesEnabled { if PrefMgr.shared.associatedPhrasesEnabled {
@ -124,11 +124,11 @@ extension SessionCtl: CtlCandidateDelegate {
withPair: .init(key: selectedValue.0, value: String(valueKept)) withPair: .init(key: selectedValue.0, value: String(valueKept))
) )
if !associates.candidates.isEmpty { if !associates.candidates.isEmpty {
handle(state: associates) switchState(associates)
return return
} }
} }
handle(state: IMEState.ofEmpty()) switchState(IMEState.ofEmpty())
} }
} }
} }

View File

@ -27,7 +27,7 @@ extension SessionCtl {
// deactivated empty() // deactivated empty()
if let client = client(), state.type == .ofDeactivated { if let client = client(), state.type == .ofDeactivated {
handle(state: IMEState.ofEmpty()) switchState(IMEState.ofEmpty())
return handle(event, client: client) return handle(event, client: client)
} }

View File

@ -12,6 +12,20 @@ import Shared
// MARK: - 調 (State Handling) // MARK: - 調 (State Handling)
extension SessionCtl { extension SessionCtl {
/// 調
///
///
///
/// - Remark: (Static)
/// deactivateServer() 使
/// 使 SessionCtl
///
/// - Note: Swift Protocol
/// - Parameter newState:
public func switchState(_ newState: IMEStateProtocol) {
handle(state: newState, replace: true)
}
/// 調 /// 調
/// ///
/// ///
@ -21,9 +35,9 @@ extension SessionCtl {
/// 使 SessionCtl /// 使 SessionCtl
/// ///
/// - Parameter newState: /// - Parameter newState:
public func handle(state newState: IMEStateProtocol, replaceCurrent: Bool = true) { public func handle(state newState: IMEStateProtocol, replace: Bool) {
var previous = state var previous = state
if replaceCurrent { state = newState } if replace { state = newState }
switch newState.type { switch newState.type {
case .ofDeactivated: case .ofDeactivated:
ctlCandidateCurrent.visible = false ctlCandidateCurrent.visible = false
@ -43,14 +57,14 @@ extension SessionCtl {
for instance in Self.allInstances { for instance in Self.allInstances {
guard let imkC = instance.ctlCandidateCurrent as? CtlCandidateIMK else { continue } guard let imkC = instance.ctlCandidateCurrent as? CtlCandidateIMK else { continue }
if instance.state.isCandidateContainer, !imkC.visible { if instance.state.isCandidateContainer, !imkC.visible {
instance.handle(state: instance.state, replaceCurrent: false) instance.handle(state: instance.state, replace: false)
} }
} }
} }
case .ofEmpty, .ofAbortion: case .ofEmpty, .ofAbortion:
if newState.type == .ofAbortion { if newState.type == .ofAbortion {
previous = IMEState.ofEmpty() previous = IMEState.ofEmpty()
if replaceCurrent { state = previous } if replace { state = previous }
} }
ctlCandidateCurrent.visible = false ctlCandidateCurrent.visible = false
tooltipInstance.hide() tooltipInstance.hide()

View File

@ -75,7 +75,7 @@ extension SessionCtl {
let candidateString: String = candidateString?.string ?? "" let candidateString: String = candidateString?.string ?? ""
if state.type == .ofAssociates { if state.type == .ofAssociates {
if !PrefMgr.shared.alsoConfirmAssociatedCandidatesByEnter { if !PrefMgr.shared.alsoConfirmAssociatedCandidatesByEnter {
handle(state: IMEState.ofAbortion()) switchState(IMEState.ofAbortion())
return return
} }
} }