From 74785b0df2294ebdd3750eb316cdb441f137b744 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Tue, 26 Jul 2022 13:09:18 +0800 Subject: [PATCH] InputSignal // Reformat & refactor. --- .../ControllerModules/InputSignal.swift | 196 ++++-------------- .../KeyHandler_HandleCandidate.swift | 2 +- .../KeyHandler_HandleInput.swift | 27 ++- vChewingTests/KeyHandlerTestsNormalCHS.swift | 4 +- 4 files changed, 61 insertions(+), 168 deletions(-) diff --git a/Source/Modules/ControllerModules/InputSignal.swift b/Source/Modules/ControllerModules/InputSignal.swift index 621475d4..cba80639 100644 --- a/Source/Modules/ControllerModules/InputSignal.swift +++ b/Source/Modules/ControllerModules/InputSignal.swift @@ -128,7 +128,7 @@ enum CharCode: UInt16 { struct InputSignal: CustomStringConvertible { private(set) var isTypingVertical: Bool - private(set) var inputText: String? + private(set) var inputText: String private(set) var inputTextIgnoringModifiers: String? private(set) var charCode: UInt16 private(set) var keyCode: UInt16 @@ -139,16 +139,16 @@ struct InputSignal: CustomStringConvertible { private var extraChooseCandidateKey: KeyCode = .kNone private var extraChooseCandidateKeyReverse: KeyCode = .kNone private var absorbedArrowKey: KeyCode = .kNone - private var verticalTypingOnlyChooseCandidateKey: KeyCode = .kNone + private var verticalTypingCandidateKey: KeyCode = .kNone private(set) var emacsKey: EmacsKey public init( - inputText: String?, keyCode: UInt16, charCode: UInt16, flags: NSEvent.ModifierFlags, + inputText: String = "", keyCode: UInt16, charCode: UInt16, flags: NSEvent.ModifierFlags, isVerticalTyping: Bool = false, inputTextIgnoringModifiers: String? = nil ) { - self.inputText = AppleKeyboardConverter.cnvStringApple2ABC(inputText ?? "") + self.inputText = AppleKeyboardConverter.cnvStringApple2ABC(inputText) self.inputTextIgnoringModifiers = AppleKeyboardConverter.cnvStringApple2ABC( - inputTextIgnoringModifiers ?? inputText ?? "") + inputTextIgnoringModifiers ?? inputText) self.flags = flags isFlagChanged = false isTypingVertical = isVerticalTyping @@ -164,7 +164,7 @@ struct InputSignal: CustomStringConvertible { public init(event: NSEvent, isVerticalTyping: Bool = false) { inputText = AppleKeyboardConverter.cnvStringApple2ABC(event.characters ?? "") inputTextIgnoringModifiers = AppleKeyboardConverter.cnvStringApple2ABC( - event.charactersIgnoringModifiers ?? "") + event.charactersIgnoringModifiers ?? inputText) keyCode = event.keyCode flags = event.modifierFlags isFlagChanged = (event.type == .flagsChanged) @@ -191,170 +191,64 @@ struct InputSignal: CustomStringConvertible { extraChooseCandidateKey = isTypingVertical ? .kLeftArrow : .kDownArrow extraChooseCandidateKeyReverse = isTypingVertical ? .kRightArrow : .kUpArrow absorbedArrowKey = isTypingVertical ? .kRightArrow : .kUpArrow - verticalTypingOnlyChooseCandidateKey = isTypingVertical ? absorbedArrowKey : .kNone + verticalTypingCandidateKey = isTypingVertical ? absorbedArrowKey : .kNone } var description: String { - "" + "" } // 除了 ANSI charCode 以外,其餘一律過濾掉,免得純 Swift 版 KeyHandler 被餵屎。 - var isInvalidInput: Bool { - switch charCode { - case 0x20...0xFF: // ANSI charCode 範圍 - return false - default: - if isReservedKey, !isKeyCodeBlacklisted { - return false - } - return true - } - } + var isInvalid: Bool { (0x20...0xFF).contains(charCode) ? false : !(isReservedKey && !isKeyCodeBlacklisted) } var isKeyCodeBlacklisted: Bool { - guard let code = KeyCodeBlackListed(rawValue: keyCode) else { - return false - } + guard let code = KeyCodeBlackListed(rawValue: keyCode) else { return false } return code.rawValue != KeyCode.kNone.rawValue } - var isShiftHold: Bool { - flags.contains([.shift]) - } - - var isCommandHold: Bool { - flags.contains([.command]) - } - - var isControlHold: Bool { - flags.contains([.control]) - } - - var isControlHotKey: Bool { - flags.contains([.control]) && inputText?.first?.isLetter ?? false - } - - var isOptionHold: Bool { - flags.contains([.option]) - } - - var isOptionHotKey: Bool { - flags.contains([.option]) && inputText?.first?.isLetter ?? false - } - - var isCapsLockOn: Bool { - flags.contains([.capsLock]) - } - - var isNumericPad: Bool { - flags.contains([.numericPad]) - } - - var isFunctionKeyHold: Bool { - flags.contains([.function]) - } - var isReservedKey: Bool { - guard let code = KeyCode(rawValue: keyCode) else { - return false - } + guard let code = KeyCode(rawValue: keyCode) else { return false } return code.rawValue != KeyCode.kNone.rawValue } /// 單獨用 flags 來判定數字小鍵盤輸入的方法已經失效了,所以必須再增補用 KeyCode 判定的方法。 - var isNumericPadAreaKey: Bool { - arrNumpadKeyCodes.contains(keyCode) - } + var isNumericPadKey: Bool { arrNumpadKeyCodes.contains(keyCode) } + var isShiftHold: Bool { flags.contains([.shift]) } + var isCommandHold: Bool { flags.contains([.command]) } + var isControlHold: Bool { flags.contains([.control]) } + var isControlHotKey: Bool { flags.contains([.control]) && inputText.first?.isLetter ?? false } + var isOptionHold: Bool { flags.contains([.option]) } + var isOptionHotKey: Bool { flags.contains([.option]) && inputText.first?.isLetter ?? false } + var isCapsLockOn: Bool { flags.contains([.capsLock]) } + var isFunctionKeyHold: Bool { flags.contains([.function]) } + var isNonLaptopFunctionKey: Bool { flags.contains([.numericPad]) && !isNumericPadKey } + var isEnter: Bool { [KeyCode.kCarriageReturn, KeyCode.kLineFeed].contains(KeyCode(rawValue: keyCode)) } + var isTab: Bool { KeyCode(rawValue: keyCode) == KeyCode.kTab } + var isUp: Bool { KeyCode(rawValue: keyCode) == KeyCode.kUpArrow } + var isDown: Bool { KeyCode(rawValue: keyCode) == KeyCode.kDownArrow } + var isLeft: Bool { KeyCode(rawValue: keyCode) == KeyCode.kLeftArrow } + var isRight: Bool { KeyCode(rawValue: keyCode) == KeyCode.kRightArrow } + var isPageUp: Bool { KeyCode(rawValue: keyCode) == KeyCode.kPageUp } + var isPageDown: Bool { KeyCode(rawValue: keyCode) == KeyCode.kPageDown } + var isSpace: Bool { KeyCode(rawValue: keyCode) == KeyCode.kSpace } + var isBackSpace: Bool { KeyCode(rawValue: keyCode) == KeyCode.kBackSpace } + var isEsc: Bool { KeyCode(rawValue: keyCode) == KeyCode.kEscape } + var isHome: Bool { KeyCode(rawValue: keyCode) == KeyCode.kHome } + var isEnd: Bool { KeyCode(rawValue: keyCode) == KeyCode.kEnd } + var isDelete: Bool { KeyCode(rawValue: keyCode) == KeyCode.kWindowsDelete } + var isCursorBackward: Bool { KeyCode(rawValue: keyCode) == cursorBackwardKey } + var isCursorForward: Bool { KeyCode(rawValue: keyCode) == cursorForwardKey } + var isAbsorbedArrowKey: Bool { KeyCode(rawValue: keyCode) == absorbedArrowKey } + var isExtraChooseCandidateKey: Bool { KeyCode(rawValue: keyCode) == extraChooseCandidateKey } + var isExtraChooseCandidateKeyReverse: Bool { KeyCode(rawValue: keyCode) == extraChooseCandidateKeyReverse } + var isVerticalTypingCandidateKey: Bool { KeyCode(rawValue: keyCode) == verticalTypingCandidateKey } - var isTab: Bool { - KeyCode(rawValue: keyCode) == KeyCode.kTab - } - - var isEnter: Bool { - (KeyCode(rawValue: keyCode) == KeyCode.kCarriageReturn) - || (KeyCode(rawValue: keyCode) == KeyCode.kLineFeed) - } - - var isUp: Bool { - KeyCode(rawValue: keyCode) == KeyCode.kUpArrow - } - - var isDown: Bool { - KeyCode(rawValue: keyCode) == KeyCode.kDownArrow - } - - var isLeft: Bool { - KeyCode(rawValue: keyCode) == KeyCode.kLeftArrow - } - - var isRight: Bool { - KeyCode(rawValue: keyCode) == KeyCode.kRightArrow - } - - var isPageUp: Bool { - KeyCode(rawValue: keyCode) == KeyCode.kPageUp - } - - var isPageDown: Bool { - KeyCode(rawValue: keyCode) == KeyCode.kPageDown - } - - var isSpace: Bool { - KeyCode(rawValue: keyCode) == KeyCode.kSpace - } - - var isBackSpace: Bool { - KeyCode(rawValue: keyCode) == KeyCode.kBackSpace - } - - var isEsc: Bool { - KeyCode(rawValue: keyCode) == KeyCode.kEscape - } - - var isHome: Bool { - KeyCode(rawValue: keyCode) == KeyCode.kHome - } - - var isEnd: Bool { - KeyCode(rawValue: keyCode) == KeyCode.kEnd - } - - var isDelete: Bool { - KeyCode(rawValue: keyCode) == KeyCode.kWindowsDelete - } - - var isCursorBackward: Bool { - KeyCode(rawValue: keyCode) == cursorBackwardKey - } - - var isCursorForward: Bool { - KeyCode(rawValue: keyCode) == cursorForwardKey - } - - var isAbsorbedArrowKey: Bool { - KeyCode(rawValue: keyCode) == absorbedArrowKey - } - - var isExtraChooseCandidateKey: Bool { - KeyCode(rawValue: keyCode) == extraChooseCandidateKey - } - - var isExtraChooseCandidateKeyReverse: Bool { - KeyCode(rawValue: keyCode) == extraChooseCandidateKeyReverse - } - - var isVerticalTypingOnlyChooseCandidateKey: Bool { - KeyCode(rawValue: keyCode) == verticalTypingOnlyChooseCandidateKey - } - - var isUpperCaseASCIILetterKey: Bool { - // 這裡必須加上「flags == .shift」,否則會出現某些情況下輸入法「誤判當前鍵入的非 Shift 字符為大寫」的問題。 - (65...90).contains(charCode) && flags == .shift - } + // 這裡必須加上「flags == .shift」,否則會出現某些情況下輸入法「誤判當前鍵入的非 Shift 字符為大寫」的問題。 + var isUpperCaseASCIILetterKey: Bool { (65...90).contains(charCode) && flags == .shift } + // 這裡必須用 KeyCode,這樣才不會受隨 macOS 版本更動的 Apple 動態注音鍵盤排列內容的影響。 + // 只是必須得與 ![input isShift] 搭配使用才可以(也就是僅判定 Shift 沒被摁下的情形)。 var isSymbolMenuPhysicalKey: Bool { - // 這裡必須用 KeyCode,這樣才不會受隨 macOS 版本更動的 Apple 動態注音鍵盤排列內容的影響。 - // 只是必須得與 ![input isShift] 搭配使用才可以(也就是僅判定 Shift 沒被摁下的情形)。 [KeyCode.kSymbolMenuPhysicalKeyIntl, KeyCode.kSymbolMenuPhysicalKeyJIS].contains(KeyCode(rawValue: keyCode)) } } diff --git a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift index f8e6a067..2f8eba7b 100644 --- a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift +++ b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift @@ -288,7 +288,7 @@ extension KeyHandler { var index: Int = NSNotFound let match: String = - (state is InputState.AssociatedPhrases) ? input.inputTextIgnoringModifiers ?? "" : inputText ?? "" + (state is InputState.AssociatedPhrases) ? input.inputTextIgnoringModifiers ?? "" : inputText var j = 0 while j < ctlCandidateCurrent.keyLabels.count { diff --git a/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift b/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift index c801d32f..21e89e6d 100644 --- a/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift +++ b/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift @@ -45,16 +45,15 @@ extension KeyHandler { stateCallback: @escaping (InputStateProtocol) -> Void, errorCallback: @escaping () -> Void ) -> Bool { + // 如果按鍵訊號內的 inputTest 是空的話,則忽略該按鍵輸入,因為很可能是功能修飾鍵。 + guard !input.inputText.isEmpty else { return false } + let charCode: UniChar = input.charCode + let inputText: String = input.inputText var state = state // 常數轉變數。 - // 如果按鍵訊號內的 inputTest 是空的話,則忽略該按鍵輸入,因為很可能是功能修飾鍵。 - guard let inputText: String = input.inputText, !inputText.isEmpty else { - return false - } - // 提前過濾掉一些不合規的按鍵訊號輸入,免得相關按鍵訊號被送給 Megrez 引發輸入法崩潰。 - if input.isInvalidInput { + if input.isInvalid { // 在「.Empty(IgnoringPreviousState) 與 .Deactivated」狀態下的首次不合規按鍵輸入可以直接放行。 // 因為「.EmptyIgnorePreviousState」會在處理之後被自動轉為「.Empty」,所以不需要單獨判斷。 if state is InputState.Empty || state is InputState.Deactivated { @@ -68,7 +67,7 @@ extension KeyHandler { // 如果當前組字器為空的話,就不再攔截某些修飾鍵,畢竟這些鍵可能會會用來觸發某些功能。 let isFunctionKey: Bool = - input.isControlHotKey || (input.isCommandHold || input.isOptionHotKey || input.isNumericPad) + input.isControlHotKey || (input.isCommandHold || input.isOptionHotKey || input.isNonLaptopFunctionKey) if !(state is InputState.NotEmpty) && !(state is InputState.AssociatedPhrases) && isFunctionKey { return false } @@ -108,10 +107,10 @@ extension KeyHandler { // MARK: 處理數字小鍵盤 (Numeric Pad Processing) - // 這裡必須用「isNumericPadAreaKey」這個以 KeyCode 判定數字鍵區輸入的方法來鎖定按鍵範圍。 - // 不然的話,會誤傷到在主鍵盤區域的功能鍵。 + // 這裡的「isNumericPadKey」處理邏輯已經改成用 KeyCode 判定數字鍵區輸入、以鎖定按鍵範圍。 + // 不然、使用 Cocoa 內建的 flags 的話,會誤傷到在主鍵盤區域的功能鍵。 // 我們先規定允許小鍵盤區域操縱選字窗,其餘場合一律直接放行。 - if input.isNumericPadAreaKey { + if input.isNumericPadKey { if !(state is InputState.ChoosingCandidate || state is InputState.AssociatedPhrases || state is InputState.SymbolTable) { @@ -268,7 +267,7 @@ extension KeyHandler { if let currentState = state as? InputState.NotEmpty, composer.isEmpty, !input.isOptionHold, input.isExtraChooseCandidateKey || input.isExtraChooseCandidateKeyReverse || input.isSpace || input.isPageDown || input.isPageUp || (input.isTab && mgrPrefs.specifyShiftTabKeyBehavior) - || (input.isTypingVertical && (input.isVerticalTypingOnlyChooseCandidateKey)) + || (input.isTypingVertical && (input.isVerticalTypingCandidateKey)) { if input.isSpace { /// 倘若沒有在偏好設定內將 Space 空格鍵設為選字窗呼叫用鍵的話……… @@ -479,11 +478,11 @@ extension KeyHandler { /// 該功能僅可在當前組字區沒有任何內容的時候使用。 if state is InputState.Empty { - if input.isSpace, !input.isOptionHold, !input.isFunctionKeyHold, !input.isControlHold, !input.isCommandHold { + if input.isSpace, !input.isOptionHold, !input.isControlHold, !input.isCommandHold { stateCallback(InputState.Committing(textToCommit: input.isShiftHold ? " " : " ")) + stateCallback(InputState.Empty()) + return true } - stateCallback(InputState.Empty()) - return true } // MARK: - 終末處理 (Still Nothing) diff --git a/vChewingTests/KeyHandlerTestsNormalCHS.swift b/vChewingTests/KeyHandlerTestsNormalCHS.swift index c6e14668..8af4ccc5 100644 --- a/vChewingTests/KeyHandlerTestsNormalCHS.swift +++ b/vChewingTests/KeyHandlerTestsNormalCHS.swift @@ -296,7 +296,7 @@ class KeyHandlerTestsNormalCHS: XCTestCase { XCTAssertTrue(state is InputState.Empty, "\(state)") } - func testisNumericPad() { + func testisNumericPadKey() { var input = InputSignal(inputText: "b", keyCode: 0, charCode: charCode("b"), flags: [], isVerticalTyping: false) var state: InputStateProtocol = InputState.Empty() _ = handler.handle(input: input, state: state) { newState in @@ -304,7 +304,7 @@ class KeyHandlerTestsNormalCHS: XCTestCase { } errorCallback: { } input = InputSignal( - inputText: "1", keyCode: 0, charCode: charCode("1"), flags: .numericPad, isVerticalTyping: false + inputText: "1", keyCode: 83, charCode: charCode("1"), flags: [], isVerticalTyping: false ) var count = 0 var empty: InputStateProtocol = InputState.Empty()