From 5475a05241b728070cdc0009770d7f7c0f64a4b2 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Thu, 14 Apr 2022 21:43:04 +0800 Subject: [PATCH] KeyHandler // Swiftify: day 1. --- Source/Modules/ControllerModules/KeyHandler.h | 3 + .../Modules/ControllerModules/KeyHandler.mm | 5 + .../ControllerModules/KeyHandler.swift | 120 ++++++++++++++++++ vChewing.xcodeproj/project.pbxproj | 4 + 4 files changed, 132 insertions(+) create mode 100644 Source/Modules/ControllerModules/KeyHandler.swift diff --git a/Source/Modules/ControllerModules/KeyHandler.h b/Source/Modules/ControllerModules/KeyHandler.h index 5854f7ad..48edd962 100644 --- a/Source/Modules/ControllerModules/KeyHandler.h +++ b/Source/Modules/ControllerModules/KeyHandler.h @@ -63,6 +63,9 @@ extern InputMode imeModeNULL; @property(strong, nonatomic) InputMode inputMode; @property(weak, nonatomic) id delegate; +- (BOOL)isPhoneticReadingBufferEmpty; +- (BOOL)isPrintable:(UniChar)charCode; + @end NS_ASSUME_NONNULL_END diff --git a/Source/Modules/ControllerModules/KeyHandler.mm b/Source/Modules/ControllerModules/KeyHandler.mm index 36202c28..56ad7b67 100644 --- a/Source/Modules/ControllerModules/KeyHandler.mm +++ b/Source/Modules/ControllerModules/KeyHandler.mm @@ -1789,4 +1789,9 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; #pragma mark - 威注音認為有必要單獨拿出來處理的部分。 +- (BOOL)isPrintable:(UniChar)charCode +{ + return isprint(charCode); +} + @end diff --git a/Source/Modules/ControllerModules/KeyHandler.swift b/Source/Modules/ControllerModules/KeyHandler.swift new file mode 100644 index 00000000..5d80b77d --- /dev/null +++ b/Source/Modules/ControllerModules/KeyHandler.swift @@ -0,0 +1,120 @@ +// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License). +// All possible vChewing-specific modifications are of: +// (c) 2021 and onwards The vChewing Project (MIT-NTL License). +/* +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +1. The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +2. No trademark license is granted to use the trade names, trademarks, service +marks, or product names of Contributor, except as required to fulfill notice +requirements above. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +import Cocoa + +@objc extension KeyHandler { + func handleInputSwift( + input: keyParser, + state: InputState, + stateCallback: @escaping (InputState) -> Void, + errorCallback: @escaping () -> Void + ) -> Bool { + let charCode: UniChar = input.charCode + // let emacsKey: vChewingEmacsKey = input.emacsKey + let inputText: String = input.inputText ?? "" + + // Ignore the input if its inputText is empty. + // Reason: such inputs may be functional key combinations. + + if (inputText).isEmpty { + return false + } + + // Ignore the input if the composing buffer is empty with no reading + // and there is some function key combination. + let isFunctionKey: Bool = + input.isControlHotKey || (input.isCommandHold || input.isOptionHotKey || input.isNumericPad) + if !(state is InputState.NotEmpty) && !(state is InputState.AssociatedPhrases) && isFunctionKey { + return false + } + + // MARK: - Caps Lock processing. + // If Caps Lock is ON, temporarily disable bopomofo. + // Note: Alphanumerical mode processing. + if input.isBackSpace || input.isEnter || input.isAbsorbedArrowKey || input.isExtraChooseCandidateKey + || input.isExtraChooseCandidateKeyReverse || input.isCursorForward || input.isCursorBackward + { + // Do nothing if backspace is pressed -- we ignore the key + } else if input.isCapsLockOn { + // Process all possible combination, we hope. + clear() + let emptyState = InputState.Empty() + stateCallback(emptyState) + + // When shift is pressed, don't do further processing... + // ...since it outputs capital letter anyway. + if input.isShiftHold { + return false + } + + // If ASCII but not printable, don't use insertText:replacementRange: + // Certain apps don't handle non-ASCII char insertions. + if charCode < 0x80 && !isPrintable(charCode) { + return false + } + + // Commit the entire input buffer. + let committingState = InputState.Committing(poppedText: inputText.lowercased()) + stateCallback(committingState) + stateCallback(emptyState) + + return true + } + + // MARK: - Numeric Pad Processing. + if input.isNumericPad { + if !input.isLeft && !input.isRight && !input.isDown + && !input.isUp && !input.isSpace && isPrintable(charCode) + { + clear() + let emptyState = InputState.Empty() + stateCallback(emptyState) + let committing = InputState.Committing(poppedText: inputText.lowercased()) + stateCallback(committing) + stateCallback(emptyState) + return true + } + } + + // MARK: - Still Nothing. + // Still nothing? Then we update the composing buffer. + // Note that some app has strange behavior if we don't do this, + // "thinking" that the key is not actually consumed). + // 砍掉這一段會導致「F1-F12 按鍵干擾組字區」的問題。 + // 暫時只能先恢復這段,且補上偵錯彙報機制,方便今後排查故障。 + if (state is InputState.NotEmpty) || !isPhoneticReadingBufferEmpty() { + IME.prtDebugIntel( + "Blocked data: charCode: \(charCode), keyCode: \(input.keyCode)") + IME.prtDebugIntel("A9BFF20E") + errorCallback() + stateCallback(state) + return true + } + + return false + } +} diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index b12b3090..c6b2e3f9 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -30,6 +30,7 @@ 5B707CEC27D9F4870099EF99 /* OpenCC in Frameworks */ = {isa = PBXBuildFile; productRef = 5B707CEB27D9F4870099EF99 /* OpenCC */; }; 5B73FB5E27B2BE1300E9BF49 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5B73FB6027B2BE1300E9BF49 /* InfoPlist.strings */; }; 5B7BC4B027AFFBE800F66C24 /* frmPrefWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B7BC4AE27AFFBE800F66C24 /* frmPrefWindow.xib */; }; + 5B7F225D2808501000DDD3CB /* KeyHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B7F225C2808501000DDD3CB /* KeyHandler.swift */; }; 5BA9FD0F27FEDB6B002DE248 /* suiPrefPaneGeneral.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0A27FEDB6B002DE248 /* suiPrefPaneGeneral.swift */; }; 5BA9FD1027FEDB6B002DE248 /* suiPrefPaneKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0B27FEDB6B002DE248 /* suiPrefPaneKeyboard.swift */; }; 5BA9FD1127FEDB6B002DE248 /* ctlPrefUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0C27FEDB6B002DE248 /* ctlPrefUI.swift */; }; @@ -208,6 +209,7 @@ 5B73FB5F27B2BE1300E9BF49 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 5B7BC4AF27AFFBE800F66C24 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/frmPrefWindow.xib; sourceTree = ""; }; 5B7BC4B227AFFC0B00F66C24 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/frmPrefWindow.strings; sourceTree = ""; }; + 5B7F225C2808501000DDD3CB /* KeyHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyHandler.swift; sourceTree = ""; }; 5B8F43ED27C9BC220069AC27 /* SymbolLM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SymbolLM.h; sourceTree = ""; }; 5BA9FD0A27FEDB6B002DE248 /* suiPrefPaneGeneral.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = suiPrefPaneGeneral.swift; sourceTree = ""; }; 5BA9FD0B27FEDB6B002DE248 /* suiPrefPaneKeyboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = suiPrefPaneKeyboard.swift; sourceTree = ""; }; @@ -423,6 +425,7 @@ D461B791279DAC010070E734 /* InputState.swift */, D4E569DA27A34CC100AC2CEF /* KeyHandler.h */, D4E569DB27A34CC100AC2CEF /* KeyHandler.mm */, + 5B7F225C2808501000DDD3CB /* KeyHandler.swift */, D456576D279E4F7B00DF6BC9 /* KeyParser.swift */, 6ACC3D3E27914F2400F1B140 /* KeyValueBlobReader.cpp */, 6ACC3D3C27914AAB00F1B140 /* KeyValueBlobReader.h */, @@ -1061,6 +1064,7 @@ D427F76C278CA2B0004A2160 /* AppDelegate.swift in Sources */, 5BA9FD4527FEF3C9002DE248 /* ToolbarItemStyleViewController.swift in Sources */, 5BA9FD4127FEF3C8002DE248 /* PreferencesStyle.swift in Sources */, + 5B7F225D2808501000DDD3CB /* KeyHandler.swift in Sources */, 5BA9FD1227FEDB6B002DE248 /* suiPrefPaneExperience.swift in Sources */, 6ACC3D442793701600F1B140 /* ParselessPhraseDB.cpp in Sources */, D461B792279DAC010070E734 /* InputState.swift in Sources */,