2.3.1 // Shift key. Merge PR#119 from upd/2.3.1
This commit is contained in:
commit
cd1cffd22e
1
AUTHORS
1
AUTHORS
|
@ -17,7 +17,6 @@ $ Contributors and volunteers of the upstream repo, having no responsibility in
|
|||
- Zonble Yang:
|
||||
- McBopomofo for macOS 2.x architect, especially state-based IME behavior management.
|
||||
- Voltaire candidate window MK2 (massively modified as MK3 in vChewing by Shiki Suen).
|
||||
- InputSignal (previously "KeyHandlerInput").
|
||||
- Notifier window and Tooltip UI.
|
||||
- NSStringUtils and FSEventStreamHelper.
|
||||
- App-style installer (only preserved for developer purposes).
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env swift
|
||||
|
||||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
@ -60,6 +60,7 @@ class AppDelegate: NSWindowController, NSApplicationDelegate {
|
|||
guard
|
||||
let installingVersion = Bundle.main.infoDictionary?[kCFBundleVersionKey as String]
|
||||
as? String,
|
||||
let window = window,
|
||||
let versionString = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
|
||||
else {
|
||||
return
|
||||
|
@ -71,7 +72,7 @@ class AppDelegate: NSWindowController, NSApplicationDelegate {
|
|||
cancelButton.nextKeyView = installButton
|
||||
installButton.nextKeyView = cancelButton
|
||||
if let cell = installButton.cell as? NSButtonCell {
|
||||
window?.defaultButtonCell = cell
|
||||
window.defaultButtonCell = cell
|
||||
}
|
||||
|
||||
if let copyrightLabel = Bundle.main.localizedInfoDictionary?["NSHumanReadableCopyright"]
|
||||
|
@ -82,17 +83,12 @@ class AppDelegate: NSWindowController, NSApplicationDelegate {
|
|||
if let eulaContent = Bundle.main.localizedInfoDictionary?["CFEULAContent"] as? String {
|
||||
appEULAContent.string = eulaContent
|
||||
}
|
||||
appVersionLabel.stringValue = String(
|
||||
format: "%@ Build %@", versionString, installingVersion
|
||||
)
|
||||
appVersionLabel.stringValue = "\(versionString) Build \(installingVersion)"
|
||||
|
||||
window?.title = String(
|
||||
format: NSLocalizedString("%@ (for version %@, r%@)", comment: ""), window?.title ?? "",
|
||||
versionString, installingVersion
|
||||
)
|
||||
window?.standardWindowButton(.closeButton)?.isHidden = true
|
||||
window?.standardWindowButton(.miniaturizeButton)?.isHidden = true
|
||||
window?.standardWindowButton(.zoomButton)?.isHidden = true
|
||||
window.title = "\(window.title) (v\(versionString), Build \(installingVersion))"
|
||||
window.standardWindowButton(.closeButton)?.isHidden = true
|
||||
window.standardWindowButton(.miniaturizeButton)?.isHidden = true
|
||||
window.standardWindowButton(.zoomButton)?.isHidden = true
|
||||
|
||||
if FileManager.default.fileExists(
|
||||
atPath: kTargetPartialPath)
|
||||
|
@ -114,8 +110,8 @@ class AppDelegate: NSWindowController, NSApplicationDelegate {
|
|||
installButton.title = NSLocalizedString("Upgrade", comment: "")
|
||||
}
|
||||
|
||||
window?.center()
|
||||
window?.orderFront(self)
|
||||
window.center()
|
||||
window.orderFront(self)
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
}
|
||||
|
||||
|
@ -126,14 +122,15 @@ class AppDelegate: NSWindowController, NSApplicationDelegate {
|
|||
}
|
||||
|
||||
@objc func timerTick(_ timer: Timer) {
|
||||
guard let window = window else { return }
|
||||
let elapsed = Date().timeIntervalSince(translocationRemovalStartTime ?? Date())
|
||||
if elapsed >= kTranslocationRemovalDeadline {
|
||||
timer.invalidate()
|
||||
window?.endSheet(progressSheet, returnCode: .cancel)
|
||||
window.endSheet(progressSheet, returnCode: .cancel)
|
||||
} else if isAppBundleTranslocated(atPath: kTargetPartialPath) == false {
|
||||
progressIndicator.doubleValue = 1.0
|
||||
timer.invalidate()
|
||||
window?.endSheet(progressSheet, returnCode: .continue)
|
||||
window.endSheet(progressSheet, returnCode: .continue)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -145,15 +142,17 @@ class AppDelegate: NSWindowController, NSApplicationDelegate {
|
|||
// return
|
||||
// }
|
||||
|
||||
guard let window = window else { return }
|
||||
|
||||
let shouldWaitForTranslocationRemoval =
|
||||
isAppBundleTranslocated(atPath: kTargetPartialPath)
|
||||
&& (window?.responds(to: #selector(NSWindow.beginSheet(_:completionHandler:))) ?? false)
|
||||
&& window.responds(to: #selector(NSWindow.beginSheet(_:completionHandler:)))
|
||||
|
||||
// 將既存輸入法扔到垃圾桶內
|
||||
do {
|
||||
let sourceDir = kDestinationPartial
|
||||
let fileManager = FileManager.default
|
||||
let fileURLString = String(format: "%@/%@", sourceDir, kTargetBundle)
|
||||
let fileURLString = sourceDir + "/" + kTargetBundle
|
||||
let fileURL = URL(fileURLWithPath: fileURLString)
|
||||
|
||||
// 檢查檔案是否存在
|
||||
|
@ -176,7 +175,7 @@ class AppDelegate: NSWindowController, NSApplicationDelegate {
|
|||
|
||||
if shouldWaitForTranslocationRemoval {
|
||||
progressIndicator.startAnimation(self)
|
||||
window?.beginSheet(progressSheet) { returnCode in
|
||||
window.beginSheet(progressSheet) { returnCode in
|
||||
DispatchQueue.main.async {
|
||||
if returnCode == .continue {
|
||||
self.installInputMethod(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
|
|
@ -17,5 +17,3 @@
|
|||
"Warning" = "Warning";
|
||||
"Input method may not be fully enabled. Please enable it through System Preferences > Keyboard > Input Sources." = "Input method may not be fully enabled. Please enable it through System Preferences > Keyboard > Input Sources.";
|
||||
"Continue" = "Continue";
|
||||
|
||||
"%@ (for version %@, r%@)" = "%@ (for version %@, r%@)";
|
|
@ -17,5 +17,3 @@
|
|||
"Warning" = "お知らせ";
|
||||
"Input method may not be fully enabled. Please enable it through System Preferences > Keyboard > Input Sources." = "入力アプリの自動起動はうまく出来なかったかもしれません。ご自分で「システム環境設定→キーボード→入力ソース」で起動してください。";
|
||||
"Continue" = "続行";
|
||||
|
||||
"%@ (for version %@, r%@)" = "%@ (for version %@, r%@)";
|
||||
|
|
|
@ -17,5 +17,3 @@
|
|||
"Warning" = "安装不完整";
|
||||
"Input method may not be fully enabled. Please enable it through System Preferences > Keyboard > Input Sources." = "输入法已经安装好,但可能没有完全启用。请从「系统偏好设定」 > 「键盘」 > 「输入方式」分页加入输入法。";
|
||||
"Continue" = "继续";
|
||||
|
||||
"%@ (for version %@, r%@)" = "%@ (for version %@, r%@)";
|
|
@ -17,5 +17,3 @@
|
|||
"Warning" = "安裝不完整";
|
||||
"Input method may not be fully enabled. Please enable it through System Preferences > Keyboard > Input Sources." = "輸入法已經安裝好,但可能沒有完全啟用。請從「系統偏好設定」 > 「鍵盤」 > 「輸入方式」分頁加入輸入法。";
|
||||
"Continue" = "繼續";
|
||||
|
||||
"%@ (for version %@, r%@)" = "%@ (for version %@, r%@)";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2019 and onwards Robert Muckle-Jones (Apache 2.0 License).
|
||||
// (c) 2019 and onwards Robert Muckle-Jones (Apache 2.0 License).
|
||||
|
||||
import Foundation
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// (c) 2018 and onwards Sindre Sorhus (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 6bf8cdb5bfaf9a884b4317b2fa330e37fd9e1cf6
|
||||
Subproject commit 4d6ed238c037c4d4f5464f6914198a503fd1f21a
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
@ -26,112 +26,6 @@ enum AppleKeyboardConverter {
|
|||
AppleKeyboardConverter.arrDynamicBasicKeyLayout.contains(mgrPrefs.basicKeyboardLayout)
|
||||
}
|
||||
|
||||
// 處理 Apple 注音鍵盤佈局類型。
|
||||
static func cnvApple2ABC(_ charCode: UniChar) -> UniChar {
|
||||
var charCode = charCode
|
||||
// 在按鍵資訊被送往注拼引擎之前,先轉換為可以被注拼引擎正常處理的資訊。
|
||||
if isDynamicBasicKeyboardLayoutEnabled {
|
||||
// 針對不同的 Apple 動態鍵盤佈局糾正大寫英文輸入。
|
||||
switch mgrPrefs.basicKeyboardLayout {
|
||||
case "com.apple.keylayout.ZhuyinBopomofo":
|
||||
switch charCode {
|
||||
case 97...122: charCode -= 32
|
||||
default: break
|
||||
}
|
||||
case "com.apple.keylayout.ZhuyinEten":
|
||||
switch charCode {
|
||||
case 65345...65370: charCode -= 65280
|
||||
default: break
|
||||
}
|
||||
default: break
|
||||
}
|
||||
// 注音鍵群。
|
||||
switch charCode {
|
||||
case 12573: charCode = UniChar(44)
|
||||
case 12582: charCode = UniChar(45)
|
||||
case 12577: charCode = UniChar(46)
|
||||
case 12581: charCode = UniChar(47)
|
||||
case 12578: charCode = UniChar(48)
|
||||
case 12549: charCode = UniChar(49)
|
||||
case 12553: charCode = UniChar(50)
|
||||
case 711: charCode = UniChar(51)
|
||||
case 715: charCode = UniChar(52)
|
||||
case 12563: charCode = UniChar(53)
|
||||
case 714: charCode = UniChar(54)
|
||||
case 729: charCode = UniChar(55)
|
||||
case 12570: charCode = UniChar(56)
|
||||
case 12574: charCode = UniChar(57)
|
||||
case 12580: charCode = UniChar(59)
|
||||
case 12551: charCode = UniChar(97)
|
||||
case 12566: charCode = UniChar(98)
|
||||
case 12559: charCode = UniChar(99)
|
||||
case 12558: charCode = UniChar(100)
|
||||
case 12557: charCode = UniChar(101)
|
||||
case 12561: charCode = UniChar(102)
|
||||
case 12565: charCode = UniChar(103)
|
||||
case 12568: charCode = UniChar(104)
|
||||
case 12571: charCode = UniChar(105)
|
||||
case 12584: charCode = UniChar(106)
|
||||
case 12572: charCode = UniChar(107)
|
||||
case 12576: charCode = UniChar(108)
|
||||
case 12585: charCode = UniChar(109)
|
||||
case 12569: charCode = UniChar(110)
|
||||
case 12575: charCode = UniChar(111)
|
||||
case 12579: charCode = UniChar(112)
|
||||
case 12550: charCode = UniChar(113)
|
||||
case 12560: charCode = UniChar(114)
|
||||
case 12555: charCode = UniChar(115)
|
||||
case 12564: charCode = UniChar(116)
|
||||
case 12583: charCode = UniChar(117)
|
||||
case 12562: charCode = UniChar(118)
|
||||
case 12554: charCode = UniChar(119)
|
||||
case 12556: charCode = UniChar(120)
|
||||
case 12567: charCode = UniChar(121)
|
||||
case 12552: charCode = UniChar(122)
|
||||
default: break
|
||||
}
|
||||
// 除了數字鍵區以外的標點符號。
|
||||
switch charCode {
|
||||
case 12289: charCode = UniChar(92)
|
||||
case 12300: charCode = UniChar(91)
|
||||
case 12301: charCode = UniChar(93)
|
||||
case 12302: charCode = UniChar(123)
|
||||
case 12303: charCode = UniChar(125)
|
||||
case 65292: charCode = UniChar(60)
|
||||
case 12290: charCode = UniChar(62)
|
||||
default: break
|
||||
}
|
||||
// 摁了 SHIFT 之後的數字區的符號。
|
||||
switch charCode {
|
||||
case 65281: charCode = UniChar(33)
|
||||
case 65312: charCode = UniChar(64)
|
||||
case 65283: charCode = UniChar(35)
|
||||
case 65284: charCode = UniChar(36)
|
||||
case 65285: charCode = UniChar(37)
|
||||
case 65087: charCode = UniChar(94)
|
||||
case 65286: charCode = UniChar(38)
|
||||
case 65290: charCode = UniChar(42)
|
||||
case 65288: charCode = UniChar(40)
|
||||
case 65289: charCode = UniChar(41)
|
||||
default: break
|
||||
}
|
||||
// 摁了 Alt 的符號。
|
||||
if charCode == 8212 { charCode = UniChar(45) }
|
||||
// Apple 倚天注音佈局追加符號糾正項目。
|
||||
if mgrPrefs.basicKeyboardLayout == "com.apple.keylayout.ZhuyinEten" {
|
||||
switch charCode {
|
||||
case 65343: charCode = UniChar(95)
|
||||
case 65306: charCode = UniChar(58)
|
||||
case 65311: charCode = UniChar(63)
|
||||
case 65291: charCode = UniChar(43)
|
||||
case 65372: charCode = UniChar(124)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
return charCode
|
||||
}
|
||||
|
||||
static func cnvStringApple2ABC(_ strProcessed: String) -> String {
|
||||
var strProcessed = strProcessed
|
||||
if isDynamicBasicKeyboardLayoutEnabled {
|
||||
|
|
|
@ -1,281 +0,0 @@
|
|||
// 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).
|
||||
// ====================
|
||||
// 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 Cocoa
|
||||
|
||||
// Use KeyCodes as much as possible since its recognition won't be affected by macOS Base Keyboard Layouts.
|
||||
// KeyCodes: https://eastmanreference.com/complete-list-of-applescript-key-codes
|
||||
// Also: HIToolbox.framework/Versions/A/Headers/Events.h
|
||||
enum KeyCode: UInt16 {
|
||||
case kNone = 0
|
||||
case kCarriageReturn = 36 // Renamed from "kReturn" to avoid nomenclatural confusions.
|
||||
case kTab = 48
|
||||
case kSpace = 49
|
||||
case kSymbolMenuPhysicalKeyIntl = 50 // vChewing Specific (Non-JIS)
|
||||
case kBackSpace = 51 // Renamed from "kDelete" to avoid nomenclatural confusions.
|
||||
case kEscape = 53
|
||||
case kCommand = 55
|
||||
case kShift = 56
|
||||
case kCapsLock = 57
|
||||
case kOption = 58
|
||||
case kControl = 59
|
||||
case kRightShift = 60
|
||||
case kRightOption = 61
|
||||
case kRightControl = 62
|
||||
case kFunction = 63
|
||||
case kF17 = 64
|
||||
case kVolumeUp = 72
|
||||
case kVolumeDown = 73
|
||||
case kMute = 74
|
||||
case kLineFeed = 76 // Another keyCode to identify the Enter Key, typable by Fn+Enter.
|
||||
case kF18 = 79
|
||||
case kF19 = 80
|
||||
case kF20 = 90
|
||||
case kSymbolMenuPhysicalKeyJIS = 94 // vChewing Specific (JIS)
|
||||
case kF5 = 96
|
||||
case kF6 = 97
|
||||
case kF7 = 98
|
||||
case kF3 = 99
|
||||
case kF8 = 100
|
||||
case kF9 = 101
|
||||
case kF11 = 103
|
||||
case kF13 = 105 // PrtSc
|
||||
case kF16 = 106
|
||||
case kF14 = 107
|
||||
case kF10 = 109
|
||||
case kF12 = 111
|
||||
case kF15 = 113
|
||||
case kHelp = 114 // Insert
|
||||
case kHome = 115
|
||||
case kPageUp = 116
|
||||
case kWindowsDelete = 117 // Renamed from "kForwardDelete" to avoid nomenclatural confusions.
|
||||
case kF4 = 118
|
||||
case kEnd = 119
|
||||
case kF2 = 120
|
||||
case kPageDown = 121
|
||||
case kF1 = 122
|
||||
case kLeftArrow = 123
|
||||
case kRightArrow = 124
|
||||
case kDownArrow = 125
|
||||
case kUpArrow = 126
|
||||
}
|
||||
|
||||
enum KeyCodeBlackListed: UInt16 {
|
||||
case kF17 = 64
|
||||
case kVolumeUp = 72
|
||||
case kVolumeDown = 73
|
||||
case kMute = 74
|
||||
case kF18 = 79
|
||||
case kF19 = 80
|
||||
case kF20 = 90
|
||||
case kF5 = 96
|
||||
case kF6 = 97
|
||||
case kF7 = 98
|
||||
case kF3 = 99
|
||||
case kF8 = 100
|
||||
case kF9 = 101
|
||||
case kF11 = 103
|
||||
case kF13 = 105 // PrtSc
|
||||
case kF16 = 106
|
||||
case kF14 = 107
|
||||
case kF10 = 109
|
||||
case kF12 = 111
|
||||
case kF15 = 113
|
||||
case kHelp = 114 // Insert
|
||||
case kF4 = 118
|
||||
case kF2 = 120
|
||||
case kF1 = 122
|
||||
}
|
||||
|
||||
/// 數字小鍵盤區域的按鍵的 KeyCode。
|
||||
///
|
||||
/// 注意:第 95 號 Key Code(逗號)為 JIS 佈局特有的數字小鍵盤按鍵。
|
||||
let arrNumpadKeyCodes: [UInt16] = [65, 67, 69, 71, 75, 78, 81, 82, 83, 84, 85, 86, 87, 88, 89, 91, 92, 95]
|
||||
|
||||
/// 主鍵盤區域的數字鍵的 KeyCode。
|
||||
let arrMainAreaNumKey: [UInt16] = [18, 19, 20, 21, 22, 23, 25, 26, 28, 29]
|
||||
|
||||
// CharCodes: https://theasciicode.com.ar/ascii-control-characters/horizontal-tab-ascii-code-9.html
|
||||
enum CharCode: UInt16 {
|
||||
case yajuusenpaiA = 114
|
||||
case yajuusenpaiB = 514
|
||||
case yajuusenpaiC = 1919
|
||||
case yajuusenpaiD = 810
|
||||
// CharCode is not reliable at all. KeyCode is the most appropriate choice due to its accuracy.
|
||||
// KeyCode doesn't give a phuque about the character sent through macOS keyboard layouts ...
|
||||
// ... but only focuses on which physical key is pressed.
|
||||
}
|
||||
|
||||
struct InputSignal: CustomStringConvertible {
|
||||
private(set) var isTypingVertical: Bool
|
||||
private(set) var inputText: String
|
||||
private(set) var inputTextIgnoringModifiers: String?
|
||||
private(set) var charCode: UInt16
|
||||
private(set) var keyCode: UInt16
|
||||
private var isFlagChanged: Bool
|
||||
private var flags: NSEvent.ModifierFlags
|
||||
private var cursorForwardKey: KeyCode = .kNone // 12 o'clock
|
||||
private var cursorBackwardKey: KeyCode = .kNone // 6 o'clock
|
||||
private var cursorKeyClockRight: KeyCode = .kNone // 3 o'clock
|
||||
private var cursorKeyClockLeft: KeyCode = .kNone // 9 o'clock
|
||||
private(set) var emacsKey: EmacsKey
|
||||
public var isASCIIModeInput: Bool = false
|
||||
|
||||
public init(
|
||||
inputText: String = "", keyCode: UInt16, charCode: UInt16, flags: NSEvent.ModifierFlags,
|
||||
isVerticalTyping: Bool = false, inputTextIgnoringModifiers: String? = nil
|
||||
) {
|
||||
self.inputText = AppleKeyboardConverter.cnvStringApple2ABC(inputText)
|
||||
self.inputTextIgnoringModifiers = AppleKeyboardConverter.cnvStringApple2ABC(
|
||||
inputTextIgnoringModifiers ?? inputText)
|
||||
self.flags = flags
|
||||
isFlagChanged = false
|
||||
isTypingVertical = isVerticalTyping
|
||||
self.keyCode = keyCode
|
||||
self.charCode = AppleKeyboardConverter.cnvApple2ABC(charCode)
|
||||
emacsKey = EmacsKeyHelper.detect(
|
||||
charCode: AppleKeyboardConverter.cnvApple2ABC(charCode), flags: flags
|
||||
)
|
||||
// Define Arrow Keys in the same way above.
|
||||
defineArrowKeys()
|
||||
}
|
||||
|
||||
public init(event: NSEvent, isVerticalTyping: Bool = false) {
|
||||
inputText = AppleKeyboardConverter.cnvStringApple2ABC(event.characters ?? "")
|
||||
inputTextIgnoringModifiers = AppleKeyboardConverter.cnvStringApple2ABC(
|
||||
event.charactersIgnoringModifiers ?? inputText)
|
||||
keyCode = event.keyCode
|
||||
flags = event.modifierFlags
|
||||
isFlagChanged = (event.type == .flagsChanged)
|
||||
isTypingVertical = isVerticalTyping
|
||||
let charCode: UInt16 = {
|
||||
// 這裡不用「count > 0」,因為該整數變數只要「!isEmpty」那就必定滿足這個條件。
|
||||
guard let inputText = event.characters, !inputText.isEmpty else {
|
||||
return 0
|
||||
}
|
||||
let first = inputText[inputText.startIndex].utf16.first!
|
||||
return first
|
||||
}()
|
||||
self.charCode = AppleKeyboardConverter.cnvApple2ABC(charCode)
|
||||
emacsKey = EmacsKeyHelper.detect(
|
||||
charCode: AppleKeyboardConverter.cnvApple2ABC(charCode), flags: flags
|
||||
)
|
||||
// Define Arrow Keys in the same way above.
|
||||
defineArrowKeys()
|
||||
}
|
||||
|
||||
mutating func defineArrowKeys() {
|
||||
cursorForwardKey = isTypingVertical ? .kDownArrow : .kRightArrow
|
||||
cursorBackwardKey = isTypingVertical ? .kUpArrow : .kLeftArrow
|
||||
cursorKeyClockLeft = isTypingVertical ? .kRightArrow : .kUpArrow
|
||||
cursorKeyClockRight = isTypingVertical ? .kLeftArrow : .kDownArrow
|
||||
}
|
||||
|
||||
var description: String {
|
||||
var result = "<[InputSignal] "
|
||||
result += "inputText:\(String(describing: inputText)), "
|
||||
result += "inputTextIgnoringModifiers:\(String(describing: inputTextIgnoringModifiers)), "
|
||||
result += "charCode:\(charCode), "
|
||||
result += "keyCode:\(keyCode), "
|
||||
result += "flags:\(flags), "
|
||||
result += "cursorForwardKey:\(cursorForwardKey), "
|
||||
result += "cursorBackwardKey:\(cursorBackwardKey), "
|
||||
result += "cursorKeyClockRight:\(cursorKeyClockRight), "
|
||||
result += "cursorKeyClockLeft:\(cursorKeyClockLeft), "
|
||||
result += "emacsKey:\(emacsKey), "
|
||||
result += "isTypingVertical:\(isTypingVertical)"
|
||||
result += ">"
|
||||
return result
|
||||
}
|
||||
|
||||
// 除了 ANSI charCode 以外,其餘一律過濾掉,免得純 Swift 版 KeyHandler 被餵屎。
|
||||
var isInvalid: Bool { (0x20...0xFF).contains(charCode) ? false : !(isReservedKey && !isKeyCodeBlacklisted) }
|
||||
|
||||
var isKeyCodeBlacklisted: Bool {
|
||||
guard let code = KeyCodeBlackListed(rawValue: keyCode) else { return false }
|
||||
return code.rawValue != KeyCode.kNone.rawValue
|
||||
}
|
||||
|
||||
var isReservedKey: Bool {
|
||||
guard let code = KeyCode(rawValue: keyCode) else { return false }
|
||||
return code.rawValue != KeyCode.kNone.rawValue
|
||||
}
|
||||
|
||||
// 摁 Alt+Shift+主鍵盤區域數字鍵 的話,根據不同的 macOS 鍵盤佈局種類,會出現不同的符號結果。
|
||||
// 然而呢,KeyCode 卻是一致的。於是這裡直接準備一個換算表來用。
|
||||
let mapMainAreaNumKey: [UInt16: String] = [
|
||||
18: "1", 19: "2", 20: "3", 21: "4", 23: "5", 22: "6", 26: "7", 28: "8", 25: "9", 29: "0",
|
||||
]
|
||||
|
||||
var isCandidateKey: Bool {
|
||||
mgrPrefs.candidateKeys.contains(inputText)
|
||||
|| mgrPrefs.candidateKeys.contains(inputTextIgnoringModifiers ?? "114514")
|
||||
}
|
||||
|
||||
/// 單獨用 flags 來判定數字小鍵盤輸入的方法已經失效了,所以必須再增補用 KeyCode 判定的方法。
|
||||
var isNumericPadKey: Bool { arrNumpadKeyCodes.contains(keyCode) }
|
||||
var isMainAreaNumKey: Bool { arrMainAreaNumKey.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 isCursorClockRight: Bool { KeyCode(rawValue: keyCode) == cursorKeyClockRight }
|
||||
var isCursorClockLeft: Bool { KeyCode(rawValue: keyCode) == cursorKeyClockLeft }
|
||||
|
||||
// 這裡必須加上「flags == .shift」,否則會出現某些情況下輸入法「誤判當前鍵入的非 Shift 字符為大寫」的問題。
|
||||
var isUpperCaseASCIILetterKey: Bool { (65...90).contains(charCode) && flags == .shift }
|
||||
|
||||
// 這裡必須用 KeyCode,這樣才不會受隨 macOS 版本更動的 Apple 動態注音鍵盤排列內容的影響。
|
||||
// 只是必須得與 ![input isShiftHold] 搭配使用才可以(也就是僅判定 Shift 沒被摁下的情形)。
|
||||
var isSymbolMenuPhysicalKey: Bool {
|
||||
[KeyCode.kSymbolMenuPhysicalKeyIntl, KeyCode.kSymbolMenuPhysicalKeyJIS].contains(KeyCode(rawValue: keyCode))
|
||||
}
|
||||
}
|
||||
|
||||
enum EmacsKey: UInt16 {
|
||||
case none = 0
|
||||
case forward = 6 // F
|
||||
case backward = 2 // B
|
||||
case home = 1 // A
|
||||
case end = 5 // E
|
||||
case delete = 4 // D
|
||||
case nextPage = 22 // V
|
||||
}
|
||||
|
||||
enum EmacsKeyHelper {
|
||||
static func detect(charCode: UniChar, flags: NSEvent.ModifierFlags) -> EmacsKey {
|
||||
let charCode = AppleKeyboardConverter.cnvApple2ABC(charCode)
|
||||
if flags.contains(.control) {
|
||||
return EmacsKey(rawValue: charCode) ?? .none
|
||||
}
|
||||
return .none
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// Refactored from the ObjCpp-version of this class by:
|
||||
// (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// ====================
|
||||
|
@ -392,10 +392,10 @@ public class KeyHandler {
|
|||
/// 檢測某個傳入的按鍵訊號是否為聲調鍵。
|
||||
/// - Parameter input: 傳入的按鍵訊號。
|
||||
/// - Returns: 判斷結果:是否為聲調鍵。
|
||||
func isIntonationKey(_ input: InputSignal) -> Bool {
|
||||
func isIntonationKey(_ input: InputSignalProtocol) -> Bool {
|
||||
var theComposer = composer // 複製一份用來做實驗。
|
||||
theComposer.clear() // 清空各種槽的內容。
|
||||
theComposer.receiveKey(fromCharCode: input.charCode)
|
||||
theComposer.receiveKey(fromString: input.text)
|
||||
return theComposer.hasToneMarker(withNothingElse: true)
|
||||
}
|
||||
|
||||
|
@ -417,7 +417,7 @@ public class KeyHandler {
|
|||
/// 生成標點符號索引鍵。
|
||||
/// - Parameter input: 輸入的按鍵訊號。
|
||||
/// - Returns: 生成的標點符號索引鍵。
|
||||
func generatePunctuationNamePrefix(withKeyCondition input: InputSignal) -> String {
|
||||
func generatePunctuationNamePrefix(withKeyCondition input: InputSignalProtocol) -> String {
|
||||
if mgrPrefs.halfWidthPunctuationEnabled {
|
||||
return "_half_punctuation_"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// Refactored from the ObjCpp-version of this class by:
|
||||
// (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// ====================
|
||||
|
@ -24,12 +24,10 @@ extension KeyHandler {
|
|||
/// - Returns: 告知 IMK「該按鍵是否已經被輸入法攔截處理」。
|
||||
func handleCandidate(
|
||||
state: InputStateProtocol,
|
||||
input: InputSignal,
|
||||
input: InputSignalProtocol,
|
||||
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||
errorCallback: @escaping () -> Void
|
||||
) -> Bool {
|
||||
let inputText = input.inputText
|
||||
let charCode: UniChar = input.charCode
|
||||
guard var ctlCandidateCurrent = delegate?.ctlCandidate() else {
|
||||
IME.prtDebugIntel("06661F6E")
|
||||
errorCallback()
|
||||
|
@ -275,7 +273,7 @@ extension KeyHandler {
|
|||
|
||||
var index: Int = NSNotFound
|
||||
let match: String =
|
||||
(state is InputState.AssociatedPhrases) ? input.inputTextIgnoringModifiers ?? "" : inputText
|
||||
(state is InputState.AssociatedPhrases) ? input.inputTextIgnoringModifiers ?? "" : input.text
|
||||
|
||||
for j in 0..<ctlCandidateCurrent.keyLabels.count {
|
||||
let label: CandidateKeyLabel = ctlCandidateCurrent.keyLabels[j]
|
||||
|
@ -307,25 +305,23 @@ extension KeyHandler {
|
|||
let punctuationNamePrefix: String = generatePunctuationNamePrefix(withKeyCondition: input)
|
||||
let parser = currentMandarinParser
|
||||
let arrCustomPunctuations: [String] = [
|
||||
punctuationNamePrefix, parser, String(format: "%c", charCode.isPrintableASCII ? CChar(charCode) : inputText),
|
||||
punctuationNamePrefix, parser, input.text,
|
||||
]
|
||||
let customPunctuation: String = arrCustomPunctuations.joined(separator: "")
|
||||
|
||||
/// 看看這個輸入是否是不需要修飾鍵的那種標點鍵輸入。
|
||||
|
||||
let arrPunctuations: [String] = [
|
||||
punctuationNamePrefix, String(format: "%c", charCode.isPrintableASCII ? CChar(charCode) : inputText),
|
||||
punctuationNamePrefix, input.text,
|
||||
]
|
||||
let punctuation: String = arrPunctuations.joined(separator: "")
|
||||
|
||||
var shouldAutoSelectCandidate: Bool =
|
||||
composer.inputValidityCheck(key: charCode) || currentLM.hasUnigramsFor(key: customPunctuation)
|
||||
composer.inputValidityCheck(key: input.charCode) || currentLM.hasUnigramsFor(key: customPunctuation)
|
||||
|| currentLM.hasUnigramsFor(key: punctuation)
|
||||
|
||||
if !shouldAutoSelectCandidate, input.isUpperCaseASCIILetterKey {
|
||||
let letter: String! = String(
|
||||
format: "%@%c", "_letter_", charCode.isPrintableASCII ? CChar(charCode) : inputText
|
||||
)
|
||||
let letter = "_letter_\(input.text)"
|
||||
if currentLM.hasUnigramsFor(key: letter) { shouldAutoSelectCandidate = true }
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// Refactored from the ObjCpp-version of this class by:
|
||||
// (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// ====================
|
||||
|
@ -18,7 +18,7 @@ extension KeyHandler {
|
|||
/// - errorCallback: 錯誤回呼。
|
||||
/// - Returns: 告知 IMK「該按鍵是否已經被輸入法攔截處理」。
|
||||
func handleComposition(
|
||||
input: InputSignal,
|
||||
input: InputSignalProtocol,
|
||||
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||
errorCallback: @escaping () -> Void
|
||||
) -> Bool? {
|
||||
|
@ -42,7 +42,7 @@ extension KeyHandler {
|
|||
prevReading.0.charComponents.forEach { theComposer.receiveKey(fromPhonabet: $0) }
|
||||
// 發現要覆寫的聲調與覆寫對象的聲調雷同的情況的話,直接跳過處理。
|
||||
let oldIntonation: Tekkon.Phonabet = theComposer.intonation
|
||||
theComposer.receiveKey(fromCharCode: input.charCode)
|
||||
theComposer.receiveKey(fromString: input.text)
|
||||
if theComposer.intonation == oldIntonation, mgrPrefs.specifyIntonationKeyBehavior == 1 { break proc }
|
||||
theComposer.intonation.clear()
|
||||
// 檢查新的漢字字音是否在庫。
|
||||
|
@ -59,7 +59,7 @@ extension KeyHandler {
|
|||
}
|
||||
}
|
||||
|
||||
composer.receiveKey(fromCharCode: input.charCode)
|
||||
composer.receiveKey(fromString: input.text)
|
||||
keyConsumedByReading = true
|
||||
|
||||
// 沒有調號的話,只需要 updateClientComposingBuffer() 且終止處理(return true)即可。
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// Refactored from the ObjCpp-version of this class by:
|
||||
// (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// ====================
|
||||
|
@ -24,16 +24,15 @@ extension KeyHandler {
|
|||
/// - errorCallback: 錯誤回呼。
|
||||
/// - Returns: 告知 IMK「該按鍵是否已經被輸入法攔截處理」。
|
||||
func handle(
|
||||
input: InputSignal,
|
||||
input: InputSignalProtocol,
|
||||
state: InputStateProtocol,
|
||||
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||
errorCallback: @escaping () -> Void
|
||||
) -> Bool {
|
||||
// 如果按鍵訊號內的 inputTest 是空的話,則忽略該按鍵輸入,因為很可能是功能修飾鍵。
|
||||
guard !input.inputText.isEmpty else { return false }
|
||||
guard !input.text.isEmpty else { return false }
|
||||
|
||||
let charCode: UniChar = input.charCode
|
||||
let inputText: String = input.inputText
|
||||
let inputText: String = input.text
|
||||
var state = state // 常數轉變數。
|
||||
|
||||
// 提前過濾掉一些不合規的按鍵訊號輸入,免得相關按鍵訊號被送給 Megrez 引發輸入法崩潰。
|
||||
|
@ -78,7 +77,7 @@ extension KeyHandler {
|
|||
|
||||
/// 如果是 ASCII 當中的不可列印的字元的話,不使用「insertText:replacementRange:」。
|
||||
/// 某些應用無法正常處理非 ASCII 字符的輸入。
|
||||
if charCode < 0x80, !charCode.isPrintableASCII {
|
||||
if input.isASCII, !input.charCode.isPrintableASCII {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -309,7 +308,7 @@ extension KeyHandler {
|
|||
if input.isMainAreaNumKey, input.isShiftHold, input.isOptionHold, !input.isControlHold, !input.isCommandHold {
|
||||
// NOTE: 將來棄用 macOS 10.11 El Capitan 支援的時候,把這裡由 CFStringTransform 改為 StringTransform:
|
||||
// https://developer.apple.com/documentation/foundation/stringtransform
|
||||
guard let stringRAW = input.mapMainAreaNumKey[input.keyCode] else { return false }
|
||||
guard let stringRAW = input.mainAreaNumKeyChar else { return false }
|
||||
let string = NSMutableString(string: stringRAW)
|
||||
CFStringTransform(string, nil, kCFStringTransformFullwidthHalfwidth, true)
|
||||
stateCallback(
|
||||
|
@ -328,9 +327,7 @@ extension KeyHandler {
|
|||
|
||||
let punctuationNamePrefix: String = generatePunctuationNamePrefix(withKeyCondition: input)
|
||||
let parser = currentMandarinParser
|
||||
let arrCustomPunctuations: [String] = [
|
||||
punctuationNamePrefix, parser, String(format: "%c", charCode.isPrintableASCII ? CChar(charCode) : inputText),
|
||||
]
|
||||
let arrCustomPunctuations: [String] = [punctuationNamePrefix, parser, input.text]
|
||||
let customPunctuation: String = arrCustomPunctuations.joined(separator: "")
|
||||
if handlePunctuation(
|
||||
customPunctuation,
|
||||
|
@ -344,9 +341,7 @@ extension KeyHandler {
|
|||
|
||||
/// 如果仍無匹配結果的話,看看這個輸入是否是不需要修飾鍵的那種標點鍵輸入。
|
||||
|
||||
let arrPunctuations: [String] = [
|
||||
punctuationNamePrefix, String(format: "%c", charCode.isPrintableASCII ? CChar(charCode) : inputText),
|
||||
]
|
||||
let arrPunctuations: [String] = [punctuationNamePrefix, input.text]
|
||||
let punctuation: String = arrPunctuations.joined(separator: "")
|
||||
|
||||
if handlePunctuation(
|
||||
|
@ -386,9 +381,7 @@ extension KeyHandler {
|
|||
stateCallback(InputState.Empty())
|
||||
return true
|
||||
default: // 包括 case 0,直接塞給組字區。
|
||||
let letter: String! = String(
|
||||
format: "%@%c", "_letter_", charCode.isPrintableASCII ? CChar(charCode) : inputText
|
||||
)
|
||||
let letter = "_letter_\(inputText)"
|
||||
if handlePunctuation(
|
||||
letter,
|
||||
state: state,
|
||||
|
@ -410,7 +403,7 @@ extension KeyHandler {
|
|||
/// 暫時只能先恢復這段,且補上偵錯彙報機制,方便今後排查故障。
|
||||
if (state is InputState.NotEmpty) || !composer.isEmpty {
|
||||
IME.prtDebugIntel(
|
||||
"Blocked data: charCode: \(charCode), keyCode: \(input.keyCode)")
|
||||
"Blocked data: charCode: \(input.charCode), keyCode: \(input.keyCode)")
|
||||
IME.prtDebugIntel("A9BFF20E")
|
||||
errorCallback()
|
||||
stateCallback(state)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// Refactored from the ObjCpp-version of this class by:
|
||||
// (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// ====================
|
||||
|
@ -170,7 +170,7 @@ extension KeyHandler {
|
|||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||
func handleMarkingState(
|
||||
_ state: InputState.Marking,
|
||||
input: InputSignal,
|
||||
input: InputSignalProtocol,
|
||||
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||
errorCallback: @escaping () -> Void
|
||||
) -> Bool {
|
||||
|
@ -416,7 +416,7 @@ extension KeyHandler {
|
|||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||
func handleBackSpace(
|
||||
state: InputStateProtocol,
|
||||
input: InputSignal,
|
||||
input: InputSignalProtocol,
|
||||
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||
errorCallback: @escaping () -> Void
|
||||
) -> Bool {
|
||||
|
@ -482,7 +482,7 @@ extension KeyHandler {
|
|||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||
func handleDelete(
|
||||
state: InputStateProtocol,
|
||||
input: InputSignal,
|
||||
input: InputSignalProtocol,
|
||||
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||
errorCallback: @escaping () -> Void
|
||||
) -> Bool {
|
||||
|
@ -652,7 +652,7 @@ extension KeyHandler {
|
|||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||
func handleForward(
|
||||
state: InputStateProtocol,
|
||||
input: InputSignal,
|
||||
input: InputSignalProtocol,
|
||||
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||
errorCallback: @escaping () -> Void
|
||||
) -> Bool {
|
||||
|
@ -726,7 +726,7 @@ extension KeyHandler {
|
|||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||
func handleBackward(
|
||||
state: InputStateProtocol,
|
||||
input: InputSignal,
|
||||
input: InputSignalProtocol,
|
||||
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||
errorCallback: @escaping () -> Void
|
||||
) -> Bool {
|
||||
|
|
|
@ -0,0 +1,302 @@
|
|||
// (c) 2022 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 Cocoa
|
||||
|
||||
// MARK: - NSEvent Extension
|
||||
|
||||
extension NSEvent: InputSignalProtocol {
|
||||
public var isASCIIModeInput: Bool { ctlInputMethod.isASCIIModeSituation }
|
||||
public var isTypingVertical: Bool { ctlInputMethod.isVerticalTypingSituation }
|
||||
public var text: String { AppleKeyboardConverter.cnvStringApple2ABC(characters ?? "") }
|
||||
public var inputTextIgnoringModifiers: String? {
|
||||
guard let charIgnoringModifiers = charactersIgnoringModifiers else { return nil }
|
||||
return AppleKeyboardConverter.cnvStringApple2ABC(charIgnoringModifiers)
|
||||
}
|
||||
|
||||
public var charCode: UInt16 {
|
||||
// 這裡不用「count > 0」,因為該整數變數只要「!isEmpty」那就必定滿足這個條件。
|
||||
guard !text.isEmpty else { return 0 }
|
||||
let scalars = text.unicodeScalars
|
||||
let result = scalars[scalars.startIndex].value
|
||||
return result <= UInt16.max ? UInt16(result) : UInt16.max
|
||||
}
|
||||
|
||||
public var isFlagChanged: Bool { type == .flagsChanged }
|
||||
|
||||
public var emacsKey: EmacsKey {
|
||||
NSEvent.detectEmacsKey(charCode: charCode, flags: modifierFlags)
|
||||
}
|
||||
|
||||
// 摁 Alt+Shift+主鍵盤區域數字鍵 的話,根據不同的 macOS 鍵盤佈局種類,會出現不同的符號結果。
|
||||
// 然而呢,KeyCode 卻是一致的。於是這裡直接準備一個換算表來用。
|
||||
// 這句用來返回換算結果。
|
||||
public var mainAreaNumKeyChar: String? { mapMainAreaNumKey[keyCode] }
|
||||
|
||||
// 除了 ANSI charCode 以外,其餘一律過濾掉,免得純 Swift 版 KeyHandler 被餵屎。
|
||||
public var isInvalid: Bool {
|
||||
(0x20...0xFF).contains(charCode) ? false : !(isReservedKey && !isKeyCodeBlacklisted)
|
||||
}
|
||||
|
||||
public var isKeyCodeBlacklisted: Bool {
|
||||
guard let code = KeyCodeBlackListed(rawValue: keyCode) else { return false }
|
||||
return code.rawValue != KeyCode.kNone.rawValue
|
||||
}
|
||||
|
||||
public var isReservedKey: Bool {
|
||||
guard let code = KeyCode(rawValue: keyCode) else { return false }
|
||||
return code.rawValue != KeyCode.kNone.rawValue
|
||||
}
|
||||
|
||||
public var isCandidateKey: Bool {
|
||||
mgrPrefs.candidateKeys.contains(text)
|
||||
|| mgrPrefs.candidateKeys.contains(inputTextIgnoringModifiers ?? "114514")
|
||||
}
|
||||
|
||||
/// 單獨用 flags 來判定數字小鍵盤輸入的方法已經失效了,所以必須再增補用 KeyCode 判定的方法。
|
||||
public var isNumericPadKey: Bool { arrNumpadKeyCodes.contains(keyCode) }
|
||||
public var isMainAreaNumKey: Bool { arrMainAreaNumKey.contains(keyCode) }
|
||||
public var isShiftHold: Bool { modifierFlags.contains([.shift]) }
|
||||
public var isCommandHold: Bool { modifierFlags.contains([.command]) }
|
||||
public var isControlHold: Bool { modifierFlags.contains([.control]) }
|
||||
public var isControlHotKey: Bool { modifierFlags.contains([.control]) && text.first?.isLetter ?? false }
|
||||
public var isOptionHold: Bool { modifierFlags.contains([.option]) }
|
||||
public var isOptionHotKey: Bool { modifierFlags.contains([.option]) && text.first?.isLetter ?? false }
|
||||
public var isCapsLockOn: Bool { modifierFlags.contains([.capsLock]) }
|
||||
public var isFunctionKeyHold: Bool { modifierFlags.contains([.function]) }
|
||||
public var isNonLaptopFunctionKey: Bool { modifierFlags.contains([.numericPad]) && !isNumericPadKey }
|
||||
public var isEnter: Bool { [KeyCode.kCarriageReturn, KeyCode.kLineFeed].contains(KeyCode(rawValue: keyCode)) }
|
||||
public var isTab: Bool { KeyCode(rawValue: keyCode) == KeyCode.kTab }
|
||||
public var isUp: Bool { KeyCode(rawValue: keyCode) == KeyCode.kUpArrow }
|
||||
public var isDown: Bool { KeyCode(rawValue: keyCode) == KeyCode.kDownArrow }
|
||||
public var isLeft: Bool { KeyCode(rawValue: keyCode) == KeyCode.kLeftArrow }
|
||||
public var isRight: Bool { KeyCode(rawValue: keyCode) == KeyCode.kRightArrow }
|
||||
public var isPageUp: Bool { KeyCode(rawValue: keyCode) == KeyCode.kPageUp }
|
||||
public var isPageDown: Bool { KeyCode(rawValue: keyCode) == KeyCode.kPageDown }
|
||||
public var isSpace: Bool { KeyCode(rawValue: keyCode) == KeyCode.kSpace }
|
||||
public var isBackSpace: Bool { KeyCode(rawValue: keyCode) == KeyCode.kBackSpace }
|
||||
public var isEsc: Bool { KeyCode(rawValue: keyCode) == KeyCode.kEscape }
|
||||
public var isHome: Bool { KeyCode(rawValue: keyCode) == KeyCode.kHome }
|
||||
public var isEnd: Bool { KeyCode(rawValue: keyCode) == KeyCode.kEnd }
|
||||
public var isDelete: Bool { KeyCode(rawValue: keyCode) == KeyCode.kWindowsDelete }
|
||||
|
||||
public var isCursorBackward: Bool {
|
||||
isTypingVertical
|
||||
? KeyCode(rawValue: keyCode) == .kUpArrow
|
||||
: KeyCode(rawValue: keyCode) == .kLeftArrow
|
||||
}
|
||||
|
||||
public var isCursorForward: Bool {
|
||||
isTypingVertical
|
||||
? KeyCode(rawValue: keyCode) == .kDownArrow
|
||||
: KeyCode(rawValue: keyCode) == .kRightArrow
|
||||
}
|
||||
|
||||
public var isCursorClockRight: Bool {
|
||||
isTypingVertical
|
||||
? KeyCode(rawValue: keyCode) == .kRightArrow
|
||||
: KeyCode(rawValue: keyCode) == .kUpArrow
|
||||
}
|
||||
|
||||
public var isCursorClockLeft: Bool {
|
||||
isTypingVertical
|
||||
? KeyCode(rawValue: keyCode) == .kLeftArrow
|
||||
: KeyCode(rawValue: keyCode) == .kDownArrow
|
||||
}
|
||||
|
||||
public var isASCII: Bool { charCode < 0x80 }
|
||||
|
||||
// 這裡必須加上「flags == .shift」,否則會出現某些情況下輸入法「誤判當前鍵入的非 Shift 字符為大寫」的問題
|
||||
public var isUpperCaseASCIILetterKey: Bool {
|
||||
(65...90).contains(charCode) && modifierFlags == .shift
|
||||
}
|
||||
|
||||
// 這裡必須用 KeyCode,這樣才不會受隨 macOS 版本更動的 Apple 動態注音鍵盤排列內容的影響。
|
||||
// 只是必須得與 ![input isShiftHold] 搭配使用才可以(也就是僅判定 Shift 沒被摁下的情形)。
|
||||
public var isSymbolMenuPhysicalKey: Bool {
|
||||
[KeyCode.kSymbolMenuPhysicalKeyIntl, KeyCode.kSymbolMenuPhysicalKeyJIS].contains(KeyCode(rawValue: keyCode))
|
||||
}
|
||||
|
||||
static func detectEmacsKey(charCode: UniChar, flags: NSEvent.ModifierFlags) -> EmacsKey {
|
||||
if flags.contains(.control) {
|
||||
return EmacsKey(rawValue: charCode) ?? .none
|
||||
}
|
||||
return .none
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - InputSignalProtocol
|
||||
|
||||
public protocol InputSignalProtocol {
|
||||
var isASCIIModeInput: Bool { get }
|
||||
var isTypingVertical: Bool { get }
|
||||
var text: String { get }
|
||||
var inputTextIgnoringModifiers: String? { get }
|
||||
var charCode: UInt16 { get }
|
||||
var keyCode: UInt16 { get }
|
||||
var isFlagChanged: Bool { get }
|
||||
var emacsKey: EmacsKey { get }
|
||||
var mainAreaNumKeyChar: String? { get }
|
||||
var isASCII: Bool { get }
|
||||
var isInvalid: Bool { get }
|
||||
var isKeyCodeBlacklisted: Bool { get }
|
||||
var isReservedKey: Bool { get }
|
||||
var isCandidateKey: Bool { get }
|
||||
var isNumericPadKey: Bool { get }
|
||||
var isMainAreaNumKey: Bool { get }
|
||||
var isShiftHold: Bool { get }
|
||||
var isCommandHold: Bool { get }
|
||||
var isControlHold: Bool { get }
|
||||
var isControlHotKey: Bool { get }
|
||||
var isOptionHold: Bool { get }
|
||||
var isOptionHotKey: Bool { get }
|
||||
var isCapsLockOn: Bool { get }
|
||||
var isFunctionKeyHold: Bool { get }
|
||||
var isNonLaptopFunctionKey: Bool { get }
|
||||
var isEnter: Bool { get }
|
||||
var isTab: Bool { get }
|
||||
var isUp: Bool { get }
|
||||
var isDown: Bool { get }
|
||||
var isLeft: Bool { get }
|
||||
var isRight: Bool { get }
|
||||
var isPageUp: Bool { get }
|
||||
var isPageDown: Bool { get }
|
||||
var isSpace: Bool { get }
|
||||
var isBackSpace: Bool { get }
|
||||
var isEsc: Bool { get }
|
||||
var isHome: Bool { get }
|
||||
var isEnd: Bool { get }
|
||||
var isDelete: Bool { get }
|
||||
var isCursorBackward: Bool { get }
|
||||
var isCursorForward: Bool { get }
|
||||
var isCursorClockRight: Bool { get }
|
||||
var isCursorClockLeft: Bool { get }
|
||||
var isUpperCaseASCIILetterKey: Bool { get }
|
||||
var isSymbolMenuPhysicalKey: Bool { get }
|
||||
}
|
||||
|
||||
// MARK: - Enums of Constants
|
||||
|
||||
// Use KeyCodes as much as possible since its recognition won't be affected by macOS Base Keyboard Layouts.
|
||||
// KeyCodes: https://eastmanreference.com/complete-list-of-applescript-key-codes
|
||||
// Also: HIToolbox.framework/Versions/A/Headers/Events.h
|
||||
public enum KeyCode: UInt16 {
|
||||
case kNone = 0
|
||||
case kCarriageReturn = 36 // Renamed from "kReturn" to avoid nomenclatural confusions.
|
||||
case kTab = 48
|
||||
case kSpace = 49
|
||||
case kSymbolMenuPhysicalKeyIntl = 50 // vChewing Specific (Non-JIS)
|
||||
case kBackSpace = 51 // Renamed from "kDelete" to avoid nomenclatural confusions.
|
||||
case kEscape = 53
|
||||
case kCommand = 55
|
||||
case kShift = 56
|
||||
case kCapsLock = 57
|
||||
case kOption = 58
|
||||
case kControl = 59
|
||||
case kRightShift = 60
|
||||
case kRightOption = 61
|
||||
case kRightControl = 62
|
||||
case kFunction = 63
|
||||
case kF17 = 64
|
||||
case kVolumeUp = 72
|
||||
case kVolumeDown = 73
|
||||
case kMute = 74
|
||||
case kLineFeed = 76 // Another keyCode to identify the Enter Key, typable by Fn+Enter.
|
||||
case kF18 = 79
|
||||
case kF19 = 80
|
||||
case kF20 = 90
|
||||
case kSymbolMenuPhysicalKeyJIS = 94 // vChewing Specific (JIS)
|
||||
case kF5 = 96
|
||||
case kF6 = 97
|
||||
case kF7 = 98
|
||||
case kF3 = 99
|
||||
case kF8 = 100
|
||||
case kF9 = 101
|
||||
case kF11 = 103
|
||||
case kF13 = 105 // PrtSc
|
||||
case kF16 = 106
|
||||
case kF14 = 107
|
||||
case kF10 = 109
|
||||
case kF12 = 111
|
||||
case kF15 = 113
|
||||
case kHelp = 114 // Insert
|
||||
case kHome = 115
|
||||
case kPageUp = 116
|
||||
case kWindowsDelete = 117 // Renamed from "kForwardDelete" to avoid nomenclatural confusions.
|
||||
case kF4 = 118
|
||||
case kEnd = 119
|
||||
case kF2 = 120
|
||||
case kPageDown = 121
|
||||
case kF1 = 122
|
||||
case kLeftArrow = 123
|
||||
case kRightArrow = 124
|
||||
case kDownArrow = 125
|
||||
case kUpArrow = 126
|
||||
}
|
||||
|
||||
enum KeyCodeBlackListed: UInt16 {
|
||||
case kF17 = 64
|
||||
case kVolumeUp = 72
|
||||
case kVolumeDown = 73
|
||||
case kMute = 74
|
||||
case kF18 = 79
|
||||
case kF19 = 80
|
||||
case kF20 = 90
|
||||
case kF5 = 96
|
||||
case kF6 = 97
|
||||
case kF7 = 98
|
||||
case kF3 = 99
|
||||
case kF8 = 100
|
||||
case kF9 = 101
|
||||
case kF11 = 103
|
||||
case kF13 = 105 // PrtSc
|
||||
case kF16 = 106
|
||||
case kF14 = 107
|
||||
case kF10 = 109
|
||||
case kF12 = 111
|
||||
case kF15 = 113
|
||||
case kHelp = 114 // Insert
|
||||
case kF4 = 118
|
||||
case kF2 = 120
|
||||
case kF1 = 122
|
||||
}
|
||||
|
||||
// 摁 Alt+Shift+主鍵盤區域數字鍵 的話,根據不同的 macOS 鍵盤佈局種類,會出現不同的符號結果。
|
||||
// 然而呢,KeyCode 卻是一致的。於是這裡直接準備一個換算表來用。
|
||||
let mapMainAreaNumKey: [UInt16: String] = [
|
||||
18: "1", 19: "2", 20: "3", 21: "4", 23: "5", 22: "6", 26: "7", 28: "8", 25: "9", 29: "0",
|
||||
]
|
||||
|
||||
/// 數字小鍵盤區域的按鍵的 KeyCode。
|
||||
///
|
||||
/// 注意:第 95 號 Key Code(逗號)為 JIS 佈局特有的數字小鍵盤按鍵。
|
||||
let arrNumpadKeyCodes: [UInt16] = [65, 67, 69, 71, 75, 78, 81, 82, 83, 84, 85, 86, 87, 88, 89, 91, 92, 95]
|
||||
|
||||
/// 主鍵盤區域的數字鍵的 KeyCode。
|
||||
let arrMainAreaNumKey: [UInt16] = [18, 19, 20, 21, 22, 23, 25, 26, 28, 29]
|
||||
|
||||
// CharCodes: https://theasciicode.com.ar/ascii-control-characters/horizontal-tab-ascii-code-9.html
|
||||
enum CharCode: UInt16 {
|
||||
case yajuusenpaiA = 114
|
||||
case yajuusenpaiB = 514
|
||||
case yajuusenpaiC = 1919
|
||||
case yajuusenpaiD = 810
|
||||
// CharCode is not reliable at all. KeyCode is the most appropriate choice due to its accuracy.
|
||||
// KeyCode doesn't give a phuque about the character sent through macOS keyboard layouts ...
|
||||
// ... but only focuses on which physical key is pressed.
|
||||
}
|
||||
|
||||
public enum EmacsKey: UInt16 {
|
||||
case none = 0
|
||||
case forward = 6 // F
|
||||
case backward = 2 // B
|
||||
case home = 1 // A
|
||||
case end = 5 // E
|
||||
case delete = 4 // D
|
||||
case nextPage = 22 // V
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
@ -17,19 +17,25 @@ extension ctlInputMethod {
|
|||
/// - Returns: 回「`true`」以將該案件已攔截處理的訊息傳遞給 IMK;回「`false`」則放行、不作處理。
|
||||
func commonEventHandler(_ event: NSEvent) -> Bool {
|
||||
// 用 Shift 開關半形英數模式,僅對 macOS 10.15 及之後的 macOS 有效。
|
||||
let shouldUseHandle =
|
||||
(IME.arrClientShiftHandlingExceptionList.contains(clientBundleIdentifier)
|
||||
|| mgrPrefs.shouldAlwaysUseShiftKeyAccommodation)
|
||||
let shouldUseHandle: Bool = {
|
||||
switch mgrPrefs.shiftKeyAccommodationBehavior {
|
||||
case 0: return false
|
||||
case 1: return IME.arrClientShiftHandlingExceptionList.contains(clientBundleIdentifier)
|
||||
case 2: return true
|
||||
default: return false
|
||||
}
|
||||
}()
|
||||
|
||||
if #available(macOS 10.15, *) {
|
||||
if ShiftKeyUpChecker.check(event), !mgrPrefs.disableShiftTogglingAlphanumericalMode {
|
||||
if !shouldUseHandle || (!rencentKeyHandledByKeyHandler && shouldUseHandle) {
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@%@%@", NSLocalizedString("Alphanumerical Mode", comment: ""), "\n",
|
||||
toggleASCIIMode()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
)
|
||||
message: NSLocalizedString("Alphanumerical Mode", comment: "") + "\n"
|
||||
+ {
|
||||
toggleASCIIMode()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
}()
|
||||
)
|
||||
}
|
||||
if shouldUseHandle {
|
||||
|
@ -51,19 +57,16 @@ extension ctlInputMethod {
|
|||
// 準備修飾鍵,用來判定要新增的詞彙是否需要賦以非常低的權重。
|
||||
ctlInputMethod.areWeNerfing = event.modifierFlags.contains([.shift, .command])
|
||||
|
||||
var input = InputSignal(event: event, isVerticalTyping: isVerticalTyping)
|
||||
input.isASCIIModeInput = isASCIIMode
|
||||
|
||||
// 無法列印的訊號輸入,一概不作處理。
|
||||
// 這個過程不能放在 KeyHandler 內,否則不會起作用。
|
||||
if !input.charCode.isPrintable {
|
||||
if !event.charCode.isPrintable {
|
||||
return false
|
||||
}
|
||||
|
||||
/// 將按鍵行為與當前輸入法狀態結合起來、交給按鍵調度模組來處理。
|
||||
/// 再根據返回的 result bool 數值來告知 IMK「這個按鍵事件是被處理了還是被放行了」。
|
||||
/// 這裡不用 keyHandler.handleCandidate() 是因為需要針對聯想詞輸入狀態做額外處理。
|
||||
let result = keyHandler.handle(input: input, state: state) { newState in
|
||||
let result = keyHandler.handle(input: event, state: state) { newState in
|
||||
self.handle(state: newState)
|
||||
} errorCallback: {
|
||||
clsSFX.beep()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
@ -38,6 +38,10 @@ class ctlInputMethod: IMKInputController {
|
|||
var state: InputStateProtocol = InputState.Empty()
|
||||
/// 當前這個 ctlInputMethod 副本是否處於英數輸入模式。
|
||||
var isASCIIMode: Bool = false
|
||||
/// 當前這個 ctlInputMethod 副本是否處於英數輸入模式(滯後項)。
|
||||
static var isASCIIModeSituation: Bool = false
|
||||
/// 當前這個 ctlInputMethod 副本是否處於縱排輸入模式(滯後項)。
|
||||
static var isVerticalTypingSituation: Bool = false
|
||||
|
||||
/// 切換當前 ctlInputMethod 副本的英數輸入模式開關。
|
||||
func toggleASCIIMode() -> Bool {
|
||||
|
@ -110,12 +114,13 @@ class ctlInputMethod: IMKInputController {
|
|||
isASCIIMode = false
|
||||
} else {
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@%@%@", NSLocalizedString("Alphanumerical Mode", comment: ""), "\n",
|
||||
isASCIIMode
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
))
|
||||
message: NSLocalizedString("Alphanumerical Mode", comment: "") + "\n"
|
||||
+ {
|
||||
isASCIIMode
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
}()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,6 +206,10 @@ class ctlInputMethod: IMKInputController {
|
|||
// 只針對特定類型的 client() 進行處理。
|
||||
if !(sender is IMKTextInput) { return false }
|
||||
|
||||
// 更新此時的靜態狀態標記。
|
||||
ctlInputMethod.isASCIIModeSituation = isASCIIMode
|
||||
ctlInputMethod.isVerticalTypingSituation = isVerticalTyping
|
||||
|
||||
// 就這傳入的 NSEvent 都還有可能是 nil,Apple InputMethodKit 團隊到底在搞三小。
|
||||
guard let event = event else { return false }
|
||||
|
||||
|
@ -211,11 +220,10 @@ class ctlInputMethod: IMKInputController {
|
|||
proc: if let ctlCandidateCurrent = ctlInputMethod.ctlCandidateCurrent as? ctlCandidateIMK {
|
||||
guard ctlCandidateCurrent.visible else { break proc }
|
||||
let event: NSEvent = ctlCandidateIMK.replaceNumPadKeyCodes(target: event) ?? event
|
||||
let input = InputSignal(event: event)
|
||||
|
||||
// Shift+Enter 是個特殊情形,不提前攔截處理的話、會有垃圾參數傳給 delegate 的 keyHandler 從而崩潰。
|
||||
// 所以這裡直接將 Shift Flags 清空。
|
||||
if input.isShiftHold, input.isEnter {
|
||||
if event.isShiftHold, event.isEnter {
|
||||
guard
|
||||
let newEvent = NSEvent.keyEvent(
|
||||
with: event.type,
|
||||
|
@ -238,7 +246,7 @@ class ctlInputMethod: IMKInputController {
|
|||
}
|
||||
|
||||
// 聯想詞選字。
|
||||
if let newChar = ctlCandidateIMK.defaultIMKSelectionKey[event.keyCode], input.isShiftHold,
|
||||
if let newChar = ctlCandidateIMK.defaultIMKSelectionKey[event.keyCode], event.isShiftHold,
|
||||
isAssociatedPhrasesState
|
||||
{
|
||||
let newEvent = NSEvent.keyEvent(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
@ -211,102 +211,109 @@ extension ctlInputMethod {
|
|||
@objc func toggleSCPCTypingMode(_: Any? = nil) {
|
||||
resetKeyHandler()
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@%@%@", NSLocalizedString("Per-Char Select Mode", comment: ""), "\n",
|
||||
mgrPrefs.toggleSCPCTypingModeEnabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
))
|
||||
message: NSLocalizedString("Per-Char Select Mode", comment: "") + "\n"
|
||||
+ {
|
||||
mgrPrefs.toggleSCPCTypingModeEnabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
}()
|
||||
)
|
||||
}
|
||||
|
||||
@objc func toggleChineseConverter(_: Any?) {
|
||||
resetKeyHandler()
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@%@%@", NSLocalizedString("Force KangXi Writing", comment: ""), "\n",
|
||||
mgrPrefs.toggleChineseConversionEnabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
))
|
||||
message: NSLocalizedString("Force KangXi Writing", comment: "") + "\n"
|
||||
+ {
|
||||
mgrPrefs.toggleChineseConversionEnabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
}()
|
||||
)
|
||||
}
|
||||
|
||||
@objc func toggleShiftJISShinjitaiOutput(_: Any?) {
|
||||
resetKeyHandler()
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@%@%@", NSLocalizedString("JIS Shinjitai Output", comment: ""), "\n",
|
||||
mgrPrefs.toggleShiftJISShinjitaiOutputEnabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
))
|
||||
message: NSLocalizedString("JIS Shinjitai Output", comment: "") + "\n"
|
||||
+ {
|
||||
mgrPrefs.toggleShiftJISShinjitaiOutputEnabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
}()
|
||||
)
|
||||
}
|
||||
|
||||
@objc func toggleCurrencyNumerals(_: Any?) {
|
||||
resetKeyHandler()
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@%@%@", NSLocalizedString("Currency Numeral Output", comment: ""), "\n",
|
||||
mgrPrefs.toggleCurrencyNumeralsEnabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
))
|
||||
message: NSLocalizedString("Currency Numeral Output", comment: "") + "\n"
|
||||
+ {
|
||||
mgrPrefs.toggleCurrencyNumeralsEnabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
}()
|
||||
)
|
||||
}
|
||||
|
||||
@objc func toggleHalfWidthPunctuation(_: Any?) {
|
||||
resetKeyHandler()
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@%@%@", NSLocalizedString("Half-Width Punctuation Mode", comment: ""),
|
||||
"\n",
|
||||
mgrPrefs.toggleHalfWidthPunctuationEnabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
))
|
||||
message: NSLocalizedString("Half-Width Punctuation Mode", comment: "") + "\n"
|
||||
+ {
|
||||
mgrPrefs.toggleHalfWidthPunctuationEnabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
}()
|
||||
)
|
||||
}
|
||||
|
||||
@objc func toggleCNS11643Enabled(_: Any?) {
|
||||
resetKeyHandler()
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@%@%@", NSLocalizedString("CNS11643 Mode", comment: ""), "\n",
|
||||
mgrPrefs.toggleCNS11643Enabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
))
|
||||
message: NSLocalizedString("CNS11643 Mode", comment: "") + "\n"
|
||||
+ {
|
||||
mgrPrefs.toggleCNS11643Enabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
}()
|
||||
)
|
||||
}
|
||||
|
||||
@objc func toggleSymbolEnabled(_: Any?) {
|
||||
resetKeyHandler()
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@%@%@", NSLocalizedString("Symbol & Emoji Input", comment: ""), "\n",
|
||||
mgrPrefs.toggleSymbolInputEnabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
))
|
||||
message: NSLocalizedString("Symbol & Emoji Input", comment: "") + "\n"
|
||||
+ {
|
||||
mgrPrefs.toggleSymbolInputEnabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
}()
|
||||
)
|
||||
}
|
||||
|
||||
@objc func toggleAssociatedPhrasesEnabled(_: Any?) {
|
||||
resetKeyHandler()
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@%@%@", NSLocalizedString("Per-Char Associated Phrases", comment: ""),
|
||||
"\n",
|
||||
mgrPrefs.toggleAssociatedPhrasesEnabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
))
|
||||
message: NSLocalizedString("Per-Char Associated Phrases", comment: "") + "\n"
|
||||
+ {
|
||||
mgrPrefs.toggleAssociatedPhrasesEnabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
}()
|
||||
)
|
||||
}
|
||||
|
||||
@objc func togglePhraseReplacement(_: Any?) {
|
||||
resetKeyHandler()
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@%@%@", NSLocalizedString("Use Phrase Replacement", comment: ""), "\n",
|
||||
mgrPrefs.togglePhraseReplacementEnabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
))
|
||||
message: NSLocalizedString("Use Phrase Replacement", comment: "") + "\n"
|
||||
+ {
|
||||
mgrPrefs.togglePhraseReplacementEnabled()
|
||||
? NSLocalizedString("NotificationSwitchON", comment: "")
|
||||
: NSLocalizedString("NotificationSwitchOFF", comment: "")
|
||||
}()
|
||||
)
|
||||
}
|
||||
|
||||
@objc func selfUninstall(_: Any?) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
@ -58,7 +58,7 @@ public enum UserDef: String, CaseIterable {
|
|||
|
||||
case kUseIMKCandidateWindow = "UseIMKCandidateWindow"
|
||||
case kHandleDefaultCandidateFontsByLangIdentifier = "HandleDefaultCandidateFontsByLangIdentifier"
|
||||
case kShouldAlwaysUseShiftKeyAccommodation = "ShouldAlwaysUseShiftKeyAccommodation"
|
||||
case kShiftKeyAccommodationBehavior = "ShiftKeyAccommodationBehavior"
|
||||
|
||||
case kCandidateTextFontName = "CandidateTextFontName"
|
||||
case kCandidateKeyLabelFontName = "CandidateKeyLabelFontName"
|
||||
|
@ -316,7 +316,7 @@ public enum mgrPrefs {
|
|||
forKey: UserDef.kHandleDefaultCandidateFontsByLangIdentifier.rawValue
|
||||
)
|
||||
UserDefaults.standard.setDefault(
|
||||
mgrPrefs.shouldAlwaysUseShiftKeyAccommodation, forKey: UserDef.kShouldAlwaysUseShiftKeyAccommodation.rawValue
|
||||
mgrPrefs.shiftKeyAccommodationBehavior, forKey: UserDef.kShiftKeyAccommodationBehavior.rawValue
|
||||
)
|
||||
|
||||
// -----
|
||||
|
@ -438,7 +438,6 @@ public enum mgrPrefs {
|
|||
|
||||
@UserDefault(key: UserDef.kTrimUnfinishedReadingsOnCommit.rawValue, defaultValue: true)
|
||||
static var trimUnfinishedReadingsOnCommit: Bool
|
||||
|
||||
// MARK: - Settings (Tier 2)
|
||||
|
||||
@UserDefault(key: UserDef.kUseIMKCandidateWindow.rawValue, defaultValue: false)
|
||||
|
@ -447,8 +446,8 @@ public enum mgrPrefs {
|
|||
@UserDefault(key: UserDef.kHandleDefaultCandidateFontsByLangIdentifier.rawValue, defaultValue: false)
|
||||
static var handleDefaultCandidateFontsByLangIdentifier: Bool
|
||||
|
||||
@UserDefault(key: UserDef.kShouldAlwaysUseShiftKeyAccommodation.rawValue, defaultValue: false)
|
||||
static var shouldAlwaysUseShiftKeyAccommodation: Bool
|
||||
@UserDefault(key: UserDef.kShiftKeyAccommodationBehavior.rawValue, defaultValue: 0)
|
||||
static var shiftKeyAccommodationBehavior: Int
|
||||
|
||||
// MARK: - Settings (Tier 3)
|
||||
|
||||
|
@ -728,7 +727,7 @@ extension mgrPrefs {
|
|||
}
|
||||
if #unavailable(macOS 10.15) {
|
||||
mgrPrefs.handleDefaultCandidateFontsByLangIdentifier = false
|
||||
mgrPrefs.shouldAlwaysUseShiftKeyAccommodation = false
|
||||
mgrPrefs.shiftKeyAccommodationBehavior = 0
|
||||
mgrPrefs.disableShiftTogglingAlphanumericalMode = false
|
||||
mgrPrefs.togglingAlphanumericalModeWithLShift = false
|
||||
}
|
||||
|
@ -768,6 +767,9 @@ extension mgrPrefs {
|
|||
if ![0, 1, 2].contains(upperCaseLetterKeyBehavior) {
|
||||
upperCaseLetterKeyBehavior = 0
|
||||
}
|
||||
if ![0, 1, 2].contains(shiftKeyAccommodationBehavior) {
|
||||
shiftKeyAccommodationBehavior = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// Refactored from the ObjCpp-version of this class by:
|
||||
// (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// ====================
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
@ -54,54 +54,30 @@ class SymbolNode {
|
|||
|
||||
// MARK: - Static data.
|
||||
|
||||
static let catCommonSymbols = String(
|
||||
format: NSLocalizedString("catCommonSymbols", comment: ""))
|
||||
static let catHoriBrackets = String(
|
||||
format: NSLocalizedString("catHoriBrackets", comment: ""))
|
||||
static let catVertBrackets = String(
|
||||
format: NSLocalizedString("catVertBrackets", comment: ""))
|
||||
static let catAlphabets = String(
|
||||
format: NSLocalizedString("catAlphabets", comment: ""))
|
||||
static let catSpecialNumbers = String(
|
||||
format: NSLocalizedString("catSpecialNumbers", comment: ""))
|
||||
static let catMathSymbols = String(
|
||||
format: NSLocalizedString("catMathSymbols", comment: ""))
|
||||
static let catCurrencyUnits = String(
|
||||
format: NSLocalizedString("catCurrencyUnits", comment: ""))
|
||||
static let catSpecialSymbols = String(
|
||||
format: NSLocalizedString("catSpecialSymbols", comment: ""))
|
||||
static let catUnicodeSymbols = String(
|
||||
format: NSLocalizedString("catUnicodeSymbols", comment: ""))
|
||||
static let catCircledKanjis = String(
|
||||
format: NSLocalizedString("catCircledKanjis", comment: ""))
|
||||
static let catCircledKataKana = String(
|
||||
format: NSLocalizedString("catCircledKataKana", comment: ""))
|
||||
static let catBracketKanjis = String(
|
||||
format: NSLocalizedString("catBracketKanjis", comment: ""))
|
||||
static let catSingleTableLines = String(
|
||||
format: NSLocalizedString("catSingleTableLines", comment: ""))
|
||||
static let catDoubleTableLines = String(
|
||||
format: NSLocalizedString("catDoubleTableLines", comment: ""))
|
||||
static let catFillingBlocks = String(
|
||||
format: NSLocalizedString("catFillingBlocks", comment: ""))
|
||||
static let catLineSegments = String(
|
||||
format: NSLocalizedString("catLineSegments", comment: ""))
|
||||
static let catKana = String(
|
||||
format: NSLocalizedString("catKana", comment: ""))
|
||||
static let catCombinations = String(
|
||||
format: NSLocalizedString("catCombinations", comment: ""))
|
||||
static let catPhonabets = String(
|
||||
format: NSLocalizedString("catPhonabets", comment: ""))
|
||||
static let catCircledASCII = String(
|
||||
format: NSLocalizedString("catCircledASCII", comment: ""))
|
||||
static let catBracketedASCII = String(
|
||||
format: NSLocalizedString("catBracketedASCII", comment: ""))
|
||||
static let catMusicSymbols = String(
|
||||
format: NSLocalizedString("catMusicSymbols", comment: ""))
|
||||
static let catThai = String(
|
||||
format: NSLocalizedString("catThai", comment: ""))
|
||||
static let catYi = String(
|
||||
format: NSLocalizedString("catYi", comment: ""))
|
||||
static let catCommonSymbols = NSLocalizedString("catCommonSymbols", comment: "")
|
||||
static let catHoriBrackets = NSLocalizedString("catHoriBrackets", comment: "")
|
||||
static let catVertBrackets = NSLocalizedString("catVertBrackets", comment: "")
|
||||
static let catAlphabets = NSLocalizedString("catAlphabets", comment: "")
|
||||
static let catSpecialNumbers = NSLocalizedString("catSpecialNumbers", comment: "")
|
||||
static let catMathSymbols = NSLocalizedString("catMathSymbols", comment: "")
|
||||
static let catCurrencyUnits = NSLocalizedString("catCurrencyUnits", comment: "")
|
||||
static let catSpecialSymbols = NSLocalizedString("catSpecialSymbols", comment: "")
|
||||
static let catUnicodeSymbols = NSLocalizedString("catUnicodeSymbols", comment: "")
|
||||
static let catCircledKanjis = NSLocalizedString("catCircledKanjis", comment: "")
|
||||
static let catCircledKataKana = NSLocalizedString("catCircledKataKana", comment: "")
|
||||
static let catBracketKanjis = NSLocalizedString("catBracketKanjis", comment: "")
|
||||
static let catSingleTableLines = NSLocalizedString("catSingleTableLines", comment: "")
|
||||
static let catDoubleTableLines = NSLocalizedString("catDoubleTableLines", comment: "")
|
||||
static let catFillingBlocks = NSLocalizedString("catFillingBlocks", comment: "")
|
||||
static let catLineSegments = NSLocalizedString("catLineSegments", comment: "")
|
||||
static let catKana = NSLocalizedString("catKana", comment: "")
|
||||
static let catCombinations = NSLocalizedString("catCombinations", comment: "")
|
||||
static let catPhonabets = NSLocalizedString("catPhonabets", comment: "")
|
||||
static let catCircledASCII = NSLocalizedString("catCircledASCII", comment: "")
|
||||
static let catBracketedASCII = NSLocalizedString("catBracketedASCII", comment: "")
|
||||
static let catMusicSymbols = NSLocalizedString("catMusicSymbols", comment: "")
|
||||
static let catThai = NSLocalizedString("catThai", comment: "")
|
||||
static let catYi = NSLocalizedString("catYi", comment: "")
|
||||
|
||||
private(set) static var root: SymbolNode = .init("/")
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// StringView Ranges extension by (c) 2022 and onwards Isaac Xen (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// StringView Ranges extension by (c) 2022 and onwards Isaac Xen (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// StringView Ranges extension by (c) 2022 and onwards Isaac Xen (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// StringView Ranges extension by (c) 2022 and onwards Isaac Xen (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// Refactored from the Cpp version of this class by Mengjuei Hsieh (MIT License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// Refactored from the ObjCpp-version of this class by:
|
||||
// (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// ====================
|
||||
|
@ -63,28 +63,20 @@ enum mgrLangModel {
|
|||
}
|
||||
if !gLangModelCHT.isLanguageModelLoaded {
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@", NSLocalizedString("Loading CHT Core Dict...", comment: "")
|
||||
)
|
||||
message: NSLocalizedString("Loading CHT Core Dict...", comment: "")
|
||||
)
|
||||
loadCoreLanguageModelFile(filenameSansExtension: "data-cht", langModel: &gLangModelCHT)
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@", NSLocalizedString("Core Dict loading complete.", comment: "")
|
||||
)
|
||||
message: NSLocalizedString("Core Dict loading complete.", comment: "")
|
||||
)
|
||||
}
|
||||
if !gLangModelCHS.isLanguageModelLoaded {
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@", NSLocalizedString("Loading CHS Core Dict...", comment: "")
|
||||
)
|
||||
message: NSLocalizedString("Loading CHS Core Dict...", comment: "")
|
||||
)
|
||||
loadCoreLanguageModelFile(filenameSansExtension: "data-chs", langModel: &gLangModelCHS)
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@", NSLocalizedString("Core Dict loading complete.", comment: "")
|
||||
)
|
||||
message: NSLocalizedString("Core Dict loading complete.", comment: "")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -102,15 +94,11 @@ enum mgrLangModel {
|
|||
}
|
||||
if !gLangModelCHS.isLanguageModelLoaded {
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@", NSLocalizedString("Loading CHS Core Dict...", comment: "")
|
||||
)
|
||||
message: NSLocalizedString("Loading CHS Core Dict...", comment: "")
|
||||
)
|
||||
loadCoreLanguageModelFile(filenameSansExtension: "data-chs", langModel: &gLangModelCHS)
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@", NSLocalizedString("Core Dict loading complete.", comment: "")
|
||||
)
|
||||
message: NSLocalizedString("Core Dict loading complete.", comment: "")
|
||||
)
|
||||
}
|
||||
} else if mode == InputMode.imeModeCHT {
|
||||
|
@ -125,15 +113,11 @@ enum mgrLangModel {
|
|||
}
|
||||
if !gLangModelCHT.isLanguageModelLoaded {
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@", NSLocalizedString("Loading CHT Core Dict...", comment: "")
|
||||
)
|
||||
message: NSLocalizedString("Loading CHT Core Dict...", comment: "")
|
||||
)
|
||||
loadCoreLanguageModelFile(filenameSansExtension: "data-cht", langModel: &gLangModelCHT)
|
||||
NotifierController.notify(
|
||||
message: String(
|
||||
format: "%@", NSLocalizedString("Core Dict loading complete.", comment: "")
|
||||
)
|
||||
message: NSLocalizedString("Core Dict loading complete.", comment: "")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
@ -206,25 +206,24 @@ public class ctlCandidateIMK: IMKCandidates, ctlCandidateProtocol {
|
|||
// 這也可能是 Objective-C 當中允許接收內容為 nil 的一種方式。
|
||||
guard !eventArray.isEmpty else { return }
|
||||
let event = eventArray[0]
|
||||
let input = InputSignal(event: event)
|
||||
guard let delegate = delegate else { return }
|
||||
if input.isEsc || input.isBackSpace || input.isDelete || (input.isShiftHold && !input.isSpace) {
|
||||
if event.isEsc || event.isBackSpace || event.isDelete || (event.isShiftHold && !event.isSpace) {
|
||||
_ = delegate.sharedEventHandler(event)
|
||||
} else if input.isSymbolMenuPhysicalKey {
|
||||
} else if event.isSymbolMenuPhysicalKey {
|
||||
// 符號鍵的行為是固定的,不受偏好設定影響。
|
||||
switch currentLayout {
|
||||
case .horizontal: input.isShiftHold ? moveUp(self) : moveDown(self)
|
||||
case .vertical: input.isShiftHold ? moveLeft(self) : moveRight(self)
|
||||
case .horizontal: event.isShiftHold ? moveUp(self) : moveDown(self)
|
||||
case .vertical: event.isShiftHold ? moveLeft(self) : moveRight(self)
|
||||
}
|
||||
} else if input.isSpace {
|
||||
} else if event.isSpace {
|
||||
switch mgrPrefs.specifyShiftSpaceKeyBehavior {
|
||||
case true: _ = input.isShiftHold ? highlightNextCandidate() : showNextPage()
|
||||
case false: _ = input.isShiftHold ? showNextPage() : highlightNextCandidate()
|
||||
case true: _ = event.isShiftHold ? highlightNextCandidate() : showNextPage()
|
||||
case false: _ = event.isShiftHold ? showNextPage() : highlightNextCandidate()
|
||||
}
|
||||
} else if input.isTab {
|
||||
} else if event.isTab {
|
||||
switch mgrPrefs.specifyShiftTabKeyBehavior {
|
||||
case true: _ = input.isShiftHold ? showPreviousPage() : showNextPage()
|
||||
case false: _ = input.isShiftHold ? highlightPreviousCandidate() : highlightNextCandidate()
|
||||
case true: _ = event.isShiftHold ? showPreviousPage() : showNextPage()
|
||||
case false: _ = event.isShiftHold ? highlightPreviousCandidate() : highlightNextCandidate()
|
||||
}
|
||||
} else {
|
||||
if let newChar = ctlCandidateIMK.defaultIMKSelectionKey[event.keyCode] {
|
||||
|
@ -245,7 +244,7 @@ public class ctlCandidateIMK: IMKCandidates, ctlCandidateProtocol {
|
|||
if let newEvent = newEvent {
|
||||
if mgrPrefs.useSCPCTypingMode, delegate.isAssociatedPhrasesState {
|
||||
// 註:input.isShiftHold 已經在 ctlInputMethod.handle() 內處理,因為在那邊處理才有效。
|
||||
if !input.isShiftHold {
|
||||
if !event.isShiftHold {
|
||||
_ = delegate.sharedEventHandler(event)
|
||||
return
|
||||
}
|
||||
|
@ -256,15 +255,15 @@ public class ctlCandidateIMK: IMKCandidates, ctlCandidateProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
if mgrPrefs.useSCPCTypingMode, !input.isReservedKey {
|
||||
if mgrPrefs.useSCPCTypingMode, !event.isReservedKey {
|
||||
_ = delegate.sharedEventHandler(event)
|
||||
return
|
||||
}
|
||||
|
||||
if delegate.isAssociatedPhrasesState,
|
||||
!input.isPageUp, !input.isPageDown, !input.isCursorForward, !input.isCursorBackward,
|
||||
!input.isCursorClockLeft, !input.isCursorClockRight, !input.isSpace,
|
||||
!input.isEnter || !mgrPrefs.alsoConfirmAssociatedCandidatesByEnter
|
||||
!event.isPageUp, !event.isPageDown, !event.isCursorForward, !event.isCursorBackward,
|
||||
!event.isCursorClockLeft, !event.isCursorClockRight, !event.isSpace,
|
||||
!event.isEnter || !mgrPrefs.alsoConfirmAssociatedCandidatesByEnter
|
||||
{
|
||||
_ = delegate.sharedEventHandler(event)
|
||||
return
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards Weizhong Yang (MIT License).
|
||||
// (c) 2021 and onwards Weizhong Yang (MIT License).
|
||||
// All possible vChewing-specific modifications are of:
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// ====================
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
@ -14,8 +14,8 @@ struct suiPrefPaneDevZone: View {
|
|||
forKey: UserDef.kUseIMKCandidateWindow.rawValue)
|
||||
@State private var selHandleDefaultCandidateFontsByLangIdentifier: Bool = UserDefaults.standard.bool(
|
||||
forKey: UserDef.kHandleDefaultCandidateFontsByLangIdentifier.rawValue)
|
||||
@State private var selShouldAlwaysUseShiftKeyAccommodation: Bool = UserDefaults.standard.bool(
|
||||
forKey: UserDef.kShouldAlwaysUseShiftKeyAccommodation.rawValue)
|
||||
@State private var selShiftKeyAccommodationBehavior: Int = UserDefaults.standard.integer(
|
||||
forKey: UserDef.kShiftKeyAccommodationBehavior.rawValue)
|
||||
|
||||
private let contentMaxHeight: Double = 432
|
||||
private let contentWidth: Double = {
|
||||
|
@ -68,23 +68,28 @@ struct suiPrefPaneDevZone: View {
|
|||
mgrPrefs.handleDefaultCandidateFontsByLangIdentifier = selHandleDefaultCandidateFontsByLangIdentifier
|
||||
}
|
||||
)
|
||||
.disabled(!isMontereyOrAbove)
|
||||
Text(
|
||||
LocalizedStringKey(
|
||||
"This only works since macOS 12 with non-IMK candidate window as an alternative wordaround of Apple Bug Report #FB10978412. Apple should patch that for macOS 11 and later."
|
||||
)
|
||||
)
|
||||
.preferenceDescription().fixedSize(horizontal: false, vertical: true)
|
||||
.disabled(!isMontereyOrAbove)
|
||||
Toggle(
|
||||
LocalizedStringKey("Use Shift Key Accommodation in all cases"),
|
||||
isOn: $selShouldAlwaysUseShiftKeyAccommodation.onChange {
|
||||
mgrPrefs.shouldAlwaysUseShiftKeyAccommodation = selShouldAlwaysUseShiftKeyAccommodation
|
||||
Picker(
|
||||
"",
|
||||
selection: $selShiftKeyAccommodationBehavior.onChange {
|
||||
mgrPrefs.shiftKeyAccommodationBehavior = selShiftKeyAccommodationBehavior
|
||||
}
|
||||
)
|
||||
.disabled(mgrPrefs.disableShiftTogglingAlphanumericalMode)
|
||||
) {
|
||||
Text(LocalizedStringKey("Disable Shift key accomodation in all cases")).tag(0)
|
||||
Text(LocalizedStringKey("Only use this with known Chromium-based browsers")).tag(1)
|
||||
Text(LocalizedStringKey("Use Shift key accommodation in all cases")).tag(2)
|
||||
}
|
||||
.labelsHidden()
|
||||
.pickerStyle(RadioGroupPickerStyle())
|
||||
Text(
|
||||
LocalizedStringKey(
|
||||
"Some client apps (like Chromium-cored browsers: MS Edge, Google Chrome, etc.) may duplicate Shift-key inputs due to their internal bugs, and their devs are less likely to fix their bugs of such. vChewing has its accommodation procedures enabled by default for known Chromium-cored browsers. If you want the same accommodation for other client apps, please tick this checkbox on."
|
||||
"Some client apps (like Chromium-cored browsers: MS Edge, Google Chrome, etc.) may duplicate Shift-key inputs due to their internal bugs, and their devs are less likely to fix their bugs of such. vChewing has its accommodation procedures enabled by default for known Chromium-cored browsers. Here you can customize how the accommodation should work."
|
||||
)
|
||||
)
|
||||
.preferenceDescription().fixedSize(horizontal: false, vertical: true)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards Weizhong Yang (MIT License).
|
||||
// (c) 2021 and onwards Weizhong Yang (MIT License).
|
||||
// All possible vChewing-specific modifications are of:
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// ====================
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
|
|
@ -187,7 +187,7 @@
|
|||
"Show Hanyu-Pinyin in the inline composition buffer & tooltip" = "Show Hanyu-Pinyin in the inline composition buffer & tooltip";
|
||||
"Show page buttons in candidate window" = "Show page buttons in candidate window";
|
||||
"Simplified Chinese" = "Simplified Chinese";
|
||||
"Some client apps (like Chromium-cored browsers: MS Edge, Google Chrome, etc.) may duplicate Shift-key inputs due to their internal bugs, and their devs are less likely to fix their bugs of such. vChewing has its accommodation procedures enabled by default for known Chromium-cored browsers. If you want the same accommodation for other client apps, please tick this checkbox on." = "Some client apps (like Chromium-cored browsers: MS Edge, Google Chrome, etc.) may duplicate Shift-key inputs due to their internal bugs, and their devs are less likely to fix their bugs of such. vChewing has its accommodation procedures enabled by default for known Chromium-cored browsers. If you want the same accommodation for other client apps, please tick this checkbox on.";
|
||||
"Some client apps (like Chromium-cored browsers: MS Edge, Google Chrome, etc.) may duplicate Shift-key inputs due to their internal bugs, and their devs are less likely to fix their bugs of such. vChewing has its accommodation procedures enabled by default for known Chromium-cored browsers. Here you can customize how the accommodation should work." = "Some client apps (like Chromium-cored browsers: MS Edge, Google Chrome, etc.) may duplicate Shift-key inputs due to their internal bugs, and their devs are less likely to fix their bugs of such. vChewing has its accommodation procedures enabled by default for known Chromium-cored browsers. Here you can customize how the accommodation should work.";
|
||||
"Space to +cycle candidates, Shift+Space to +cycle pages" = "Space to +cycle candidates, Shift+Space to +cycle pages";
|
||||
"Space to +cycle pages, Shift+Space to +cycle candidates" = "Space to +cycle pages, Shift+Space to +cycle candidates";
|
||||
"Specify the behavior of intonation key when syllable composer is empty." = "Specify the behavior of intonation key when syllable composer is empty.";
|
||||
|
@ -203,8 +203,10 @@
|
|||
"Use .langIdentifier to handle UI fonts in candidate window" = "Use .langIdentifier to handle UI fonts in candidate window";
|
||||
"Use ESC key to clear the entire input buffer" = "Use ESC key to clear the entire input buffer";
|
||||
"Use IMK Candidate Window instead (will reboot the IME)" = "Use IMK Candidate Window instead (will reboot the IME)";
|
||||
"Use Shift Key Accommodation in all cases" = "Use Shift Key Accommodation in all cases";
|
||||
"Use Shift key accommodation in all cases" = "Use Shift key accommodation in all cases";
|
||||
"Vertical" = "Vertical";
|
||||
"Warning: This page is for testing future features. \nFeatures listed here may not work as expected." = "Warning: This page is for testing future features. \nFeatures listed here may not work as expected.";
|
||||
"For example: When typing “章太炎” and you want to override the “太” with “泰”, and the raw operation index range [1,2) which bounds are cutting the current node “章太炎” in range [0,3). If having lack of the pre-consolidation process, this word will become something like “張泰言” after the candidate selection. Only if we enable this consolidation, this word will become “章泰炎” which is the expected result that the context is kept as-is." = "For example: When typing “章太炎” and you want to override the “太” with “泰”, and the raw operation index range [1,2) which bounds are cutting the current node “章太炎” in range [0,3). If having lack of the pre-consolidation process, this word will become something like “張泰言” after the candidate selection. Only if we enable this consolidation, this word will become “章泰炎” which is the expected result that the context is kept as-is.";
|
||||
"Yale Pinyin with Numeral Intonation" = "Yale Pinyin with Numeral Intonation";
|
||||
"Only use this with known Chromium-based browsers" = "Only use this with known Chromium-based browsers";
|
||||
"Disable Shift key accomodation in all cases" = "Disable Shift key accomodation in all cases";
|
||||
|
|
|
@ -187,7 +187,7 @@
|
|||
"Show Hanyu-Pinyin in the inline composition buffer & tooltip" = "Show Hanyu-Pinyin in the inline composition buffer & tooltip";
|
||||
"Show page buttons in candidate window" = "Show page buttons in candidate window";
|
||||
"Simplified Chinese" = "Simplified Chinese";
|
||||
"Some client apps (like Chromium-cored browsers: MS Edge, Google Chrome, etc.) may duplicate Shift-key inputs due to their internal bugs, and their devs are less likely to fix their bugs of such. vChewing has its accommodation procedures enabled by default for known Chromium-cored browsers. If you want the same accommodation for other client apps, please tick this checkbox on." = "Some client apps (like Chromium-cored browsers: MS Edge, Google Chrome, etc.) may duplicate Shift-key inputs due to their internal bugs, and their devs are less likely to fix their bugs of such. vChewing has its accommodation procedures enabled by default for known Chromium-cored browsers. If you want the same accommodation for other client apps, please tick this checkbox on.";
|
||||
"Some client apps (like Chromium-cored browsers: MS Edge, Google Chrome, etc.) may duplicate Shift-key inputs due to their internal bugs, and their devs are less likely to fix their bugs of such. vChewing has its accommodation procedures enabled by default for known Chromium-cored browsers. Here you can customize how the accommodation should work." = "Some client apps (like Chromium-cored browsers: MS Edge, Google Chrome, etc.) may duplicate Shift-key inputs due to their internal bugs, and their devs are less likely to fix their bugs of such. vChewing has its accommodation procedures enabled by default for known Chromium-cored browsers. Here you can customize how the accommodation should work.";
|
||||
"Space to +cycle candidates, Shift+Space to +cycle pages" = "Space to +cycle candidates, Shift+Space to +cycle pages";
|
||||
"Space to +cycle pages, Shift+Space to +cycle candidates" = "Space to +cycle pages, Shift+Space to +cycle candidates";
|
||||
"Specify the behavior of intonation key when syllable composer is empty." = "Specify the behavior of intonation key when syllable composer is empty.";
|
||||
|
@ -203,8 +203,10 @@
|
|||
"Use .langIdentifier to handle UI fonts in candidate window" = "Use .langIdentifier to handle UI fonts in candidate window";
|
||||
"Use ESC key to clear the entire input buffer" = "Use ESC key to clear the entire input buffer";
|
||||
"Use IMK Candidate Window instead (will reboot the IME)" = "Use IMK Candidate Window instead (will reboot the IME)";
|
||||
"Use Shift Key Accommodation in all cases" = "Use Shift Key Accommodation in all cases";
|
||||
"Use Shift key accommodation in all cases" = "Use Shift key accommodation in all cases";
|
||||
"Vertical" = "Vertical";
|
||||
"Warning: This page is for testing future features. \nFeatures listed here may not work as expected." = "Warning: This page is for testing future features. \nFeatures listed here may not work as expected.";
|
||||
"For example: When typing “章太炎” and you want to override the “太” with “泰”, and the raw operation index range [1,2) which bounds are cutting the current node “章太炎” in range [0,3). If having lack of the pre-consolidation process, this word will become something like “張泰言” after the candidate selection. Only if we enable this consolidation, this word will become “章泰炎” which is the expected result that the context is kept as-is." = "For example: When typing “章太炎” and you want to override the “太” with “泰”, and the raw operation index range [1,2) which bounds are cutting the current node “章太炎” in range [0,3). If having lack of the pre-consolidation process, this word will become something like “張泰言” after the candidate selection. Only if we enable this consolidation, this word will become “章泰炎” which is the expected result that the context is kept as-is.";
|
||||
"Yale Pinyin with Numeral Intonation" = "Yale Pinyin with Numeral Intonation";
|
||||
"Only use this with known Chromium-based browsers" = "Only use this with known Chromium-based browsers";
|
||||
"Disable Shift key accomodation in all cases" = "Disable Shift key accomodation in all cases";
|
||||
|
|
|
@ -187,7 +187,7 @@
|
|||
"Show Hanyu-Pinyin in the inline composition buffer & tooltip" = "弁音合併入力(入力緩衝列とヒントで音読みを漢語弁音に)";
|
||||
"Show page buttons in candidate window" = "入力候補陳列の側にページボタンを表示";
|
||||
"Simplified Chinese" = "簡体中国語";
|
||||
"Some client apps (like Chromium-cored browsers: MS Edge, Google Chrome, etc.) may duplicate Shift-key inputs due to their internal bugs, and their devs are less likely to fix their bugs of such. vChewing has its accommodation procedures enabled by default for known Chromium-cored browsers. If you want the same accommodation for other client apps, please tick this checkbox on." = "いくつかのアプリ(例えば MS Edge や Google Chrome などのような Chromium 系ブラウザー)には「Shift キーの入力イベントを複数化してしまう」という支障があり、そしてアプリそれぞれの開発元に修復される可能性はほぼゼロだと言える。威注音入力アプリは対策用の特殊措置を普段に起用している。別のアプリにも同じ特殊措置が欲しければ、これをチェックしてください。";
|
||||
"Some client apps (like Chromium-cored browsers: MS Edge, Google Chrome, etc.) may duplicate Shift-key inputs due to their internal bugs, and their devs are less likely to fix their bugs of such. vChewing has its accommodation procedures enabled by default for known Chromium-cored browsers. Here you can customize how the accommodation should work." = "いくつかのアプリ(例えば MS Edge や Google Chrome などのような Chromium 系ブラウザー)には「Shift キーの入力イベントを複数化してしまう」という支障があり、そしてアプリそれぞれの開発元に修復される可能性はほぼゼロだと言える。威注音入力アプリは対策用の特殊措置を普段に起用している。ご自分の必要によって設定してください。";
|
||||
"Space to +cycle candidates, Shift+Space to +cycle pages" = "Shift+Space で次のページ、Space で次の候補文字を";
|
||||
"Space to +cycle pages, Shift+Space to +cycle candidates" = "Space で次のページ、Shift+Space で次の候補文字を";
|
||||
"Specify the behavior of intonation key when syllable composer is empty." = "音読組立緩衝列が空かされた時の音調キーの行為をご指定ください。";
|
||||
|
@ -203,8 +203,10 @@
|
|||
"Use .langIdentifier to handle UI fonts in candidate window" = "「.langIdentifier」を使って候補陳列ウィンドウのフォントを取り扱う";
|
||||
"Use ESC key to clear the entire input buffer" = "ESC キーで入力緩衝列を消す";
|
||||
"Use IMK Candidate Window instead (will reboot the IME)" = "IMK 候補陳列ウィンドウを起用(入力アプリは自動的に再起動)";
|
||||
"Use Shift Key Accommodation in all cases" = "いずれの客体アプリにも Shift キーの互換性措置を起用";
|
||||
"Use Shift key accommodation in all cases" = "いずれの客体アプリにも Shift キーの互換性措置を起用";
|
||||
"Vertical" = "縦型陳列";
|
||||
"Warning: This page is for testing future features. \nFeatures listed here may not work as expected." = "警告:これからの新機能テストのために作ったページですから、\nここで陳列されている諸機能は予想通り動けるだと思わないでください。";
|
||||
"For example: When typing “章太炎” and you want to override the “太” with “泰”, and the raw operation index range [1,2) which bounds are cutting the current node “章太炎” in range [0,3). If having lack of the pre-consolidation process, this word will become something like “張泰言” after the candidate selection. Only if we enable this consolidation, this word will become “章泰炎” which is the expected result that the context is kept as-is." = "例えば、入力緩衝列には「章太炎」という節点があり、その範囲は [0,3) である。もし、「太」を「泰」にしたいのなら、今回の作業範囲は [1,2) で、「章太炎」の範囲と重ねてしまう。この場合、もし、事前強固措置がなければ、今回の作業でこの単語は「張泰言」のような望ましくない変換結果になってしまう。事前強固措置があるからこそ、「章泰炎」のような正確な作業結果の保証である。";
|
||||
"Yale Pinyin with Numeral Intonation" = "イェール弁音 (ローマ字+数字音調)";
|
||||
"Only use this with known Chromium-based browsers" = "有名なる Chromium 系ブラウザーだけに、この装置を起用";
|
||||
"Disable Shift key accomodation in all cases" = "いずれの客体アプリにも Shift キーの互換性措置を禁ず";
|
||||
|
|
|
@ -187,7 +187,7 @@
|
|||
"Show Hanyu-Pinyin in the inline composition buffer & tooltip" = "拼音并击(组字区与工具提示内显示汉语拼音)";
|
||||
"Show page buttons in candidate window" = "在选字窗内显示翻页按钮";
|
||||
"Simplified Chinese" = "简体中文";
|
||||
"Some client apps (like Chromium-cored browsers: MS Edge, Google Chrome, etc.) may duplicate Shift-key inputs due to their internal bugs, and their devs are less likely to fix their bugs of such. vChewing has its accommodation procedures enabled by default for known Chromium-cored browsers. If you want the same accommodation for other client apps, please tick this checkbox on." = "某些应用(比如像是 MS Edge 或者 Chrome 这样的 Chromium 核心的浏览器)可能会使输入的 Shift 按键讯号被重复输入,且其有关研发方很可能不打算修复这些产品缺陷。威注音针对这些应用预设启用了相容措施。如果您希望在任何应用当中都启用该措施的话,请勾选之。";
|
||||
"Some client apps (like Chromium-cored browsers: MS Edge, Google Chrome, etc.) may duplicate Shift-key inputs due to their internal bugs, and their devs are less likely to fix their bugs of such. vChewing has its accommodation procedures enabled by default for known Chromium-cored browsers. Here you can customize how the accommodation should work." = "某些应用(比如像是 MS Edge 或者 Chrome 这样的 Chromium 核心的浏览器)可能会使输入的 Shift 按键讯号被重复输入,且其有关研发方很可能不打算修复这些产品缺陷。威注音针对这些应用预设启用了相容措施。请在此根据您的需求自订。";
|
||||
"Space to +cycle candidates, Shift+Space to +cycle pages" = "Shift+空格键 换下一页,空格键 换选下一个候选字";
|
||||
"Space to +cycle pages, Shift+Space to +cycle candidates" = "空格键 换下一页,Shift+空格键 换选下一个候选字";
|
||||
"Specify the behavior of intonation key when syllable composer is empty." = "指定声调键(在注拼槽为「空」状态时)的行为。";
|
||||
|
@ -203,8 +203,10 @@
|
|||
"Use .langIdentifier to handle UI fonts in candidate window" = "使用 .langIdentifier 来管理选字窗的预设介面字型";
|
||||
"Use ESC key to clear the entire input buffer" = "敲 ESC 键以清空整个组字缓冲区";
|
||||
"Use IMK Candidate Window instead (will reboot the IME)" = "启用与 macOS 内建输入法相同的 IMK 选字窗(会自动重启输入法)";
|
||||
"Use Shift Key Accommodation in all cases" = "对任何客体应用均启用 Shift 键相容性措施";
|
||||
"Use Shift key accommodation in all cases" = "对任何客体应用均启用 Shift 键相容性措施";
|
||||
"Vertical" = "纵向布局";
|
||||
"Warning: This page is for testing future features. \nFeatures listed here may not work as expected." = "警告:该页面仅作未来功能测试所用。\n在此列出的功能并非处于完全可用之状态。";
|
||||
"For example: When typing “章太炎” and you want to override the “太” with “泰”, and the raw operation index range [1,2) which bounds are cutting the current node “章太炎” in range [0,3). If having lack of the pre-consolidation process, this word will become something like “張泰言” after the candidate selection. Only if we enable this consolidation, this word will become “章泰炎” which is the expected result that the context is kept as-is." = "打比方说,你敲了「章太炎」,你想将「太」改成「泰」。这个操作的作业索引范围是开闭区间 [1,2),会切到「章太炎」这个节点的所在索引范围 [0,3)。如果没有事前巩固处理的话,这个词会在你选字之后变成诸如「张泰言」这种你不想要的自动选字结果。当且仅当你启用了这个巩固功能的前提下,你选字之后的结果才会是「章泰炎」这种你想要的结果。";
|
||||
"Yale Pinyin with Numeral Intonation" = "耶鲁拼音+数字标调";
|
||||
"Only use this with known Chromium-based browsers" = "仅针对知名的 Chromium 核心的浏览器启用该措施";
|
||||
"Disable Shift key accomodation in all cases" = "对任何客体应用均停用 Shift 键相容性措施";
|
||||
|
|
|
@ -187,7 +187,7 @@
|
|||
"Show Hanyu-Pinyin in the inline composition buffer & tooltip" = "拼音並擊(組字區與工具提示內顯示漢語拼音)";
|
||||
"Show page buttons in candidate window" = "在選字窗內顯示翻頁按鈕";
|
||||
"Simplified Chinese" = "簡體中文";
|
||||
"Some client apps (like Chromium-cored browsers: MS Edge, Google Chrome, etc.) may duplicate Shift-key inputs due to their internal bugs, and their devs are less likely to fix their bugs of such. vChewing has its accommodation procedures enabled by default for known Chromium-cored browsers. If you want the same accommodation for other client apps, please tick this checkbox on." = "某些應用(比如像是 MS Edge 或者 Chrome 這樣的 Chromium 核心的瀏覽器)可能會使輸入的 Shift 按鍵訊號被重複輸入,且其有關研發方很可能不打算修復這些產品缺陷。威注音針對這些應用預設啟用了相容措施。如果您希望在任何應用當中都啟用該措施的話,請勾選之。";
|
||||
"Some client apps (like Chromium-cored browsers: MS Edge, Google Chrome, etc.) may duplicate Shift-key inputs due to their internal bugs, and their devs are less likely to fix their bugs of such. vChewing has its accommodation procedures enabled by default for known Chromium-cored browsers. Here you can customize how the accommodation should work." = "某些應用(比如像是 MS Edge 或者 Chrome 這樣的 Chromium 核心的瀏覽器)可能會使輸入的 Shift 按鍵訊號被重複輸入,且其有關研發方很可能不打算修復這些產品缺陷。威注音針對這些應用預設啟用了相容措施。請在此根據您的需求自訂。";
|
||||
"Space to +cycle candidates, Shift+Space to +cycle pages" = "Shift+空格鍵 換下一頁,空格鍵 換選下一個候選字";
|
||||
"Space to +cycle pages, Shift+Space to +cycle candidates" = "空格鍵 換下一頁,Shift+空格鍵 換選下一個候選字";
|
||||
"Specify the behavior of intonation key when syllable composer is empty." = "指定聲調鍵(在注拼槽為「空」狀態時)的行為。";
|
||||
|
@ -203,8 +203,10 @@
|
|||
"Use .langIdentifier to handle UI fonts in candidate window" = "使用 .langIdentifier 來管理選字窗的預設介面字型";
|
||||
"Use ESC key to clear the entire input buffer" = "敲 ESC 鍵以清空整個組字緩衝區";
|
||||
"Use IMK Candidate Window instead (will reboot the IME)" = "啟用與 macOS 內建輸入法相同的 IMK 選字窗(會自動重啟輸入法)";
|
||||
"Use Shift Key Accommodation in all cases" = "對任何客體應用均啟用 Shift 鍵相容性措施";
|
||||
"Use Shift key accommodation in all cases" = "對任何客體應用均啟用 Shift 鍵相容性措施";
|
||||
"Vertical" = "縱向佈局";
|
||||
"Warning: This page is for testing future features. \nFeatures listed here may not work as expected." = "警告:該頁面僅作未來功能測試所用。\n在此列出的功能並非處於完全可用之狀態。";
|
||||
"For example: When typing “章太炎” and you want to override the “太” with “泰”, and the raw operation index range [1,2) which bounds are cutting the current node “章太炎” in range [0,3). If having lack of the pre-consolidation process, this word will become something like “張泰言” after the candidate selection. Only if we enable this consolidation, this word will become “章泰炎” which is the expected result that the context is kept as-is." = "打比方說,你敲了「章太炎」,你想將「太」改成「泰」。這個操作的作業索引範圍是開閉區間 [1,2),會切到「章太炎」這個節點的所在索引範圍 [0,3)。如果沒有事前鞏固處理的話,這個詞會在你選字之後變成諸如「張泰言」這種你不想要的自動選字結果。當且僅當你啟用了這個鞏固功能的前提下,你選字之後的結果才會是「章泰炎」這種你想要的結果。";
|
||||
"Yale Pinyin with Numeral Intonation" = "耶魯拼音+數字標調";
|
||||
"Only use this with known Chromium-based browsers" = "僅針對知名的 Chromium 核心的瀏覽器啟用該措施";
|
||||
"Disable Shift key accomodation in all cases" = "對任何客體應用均停用 Shift 鍵相容性措施";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
@ -36,9 +36,7 @@ class ctlAboutWindow: NSWindowController {
|
|||
if let eulaContent = Bundle.main.localizedInfoDictionary?["CFEULAContent"] as? String {
|
||||
appEULAContent.string = eulaContent
|
||||
}
|
||||
appVersionLabel.stringValue = String(
|
||||
format: "%@ Build %@", versionString, installingVersion
|
||||
)
|
||||
appVersionLabel.stringValue = "\(versionString) Build \(installingVersion)"
|
||||
}
|
||||
|
||||
@IBAction func btnBugReport(_: NSButton) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
@ -100,15 +100,13 @@ class ctlPrefWindow: NSWindowController {
|
|||
basicKeyboardLayoutButton.menu?.removeAllItems()
|
||||
|
||||
let itmAppleZhuyinBopomofo = NSMenuItem()
|
||||
itmAppleZhuyinBopomofo.title = String(
|
||||
format: NSLocalizedString("Apple Zhuyin Bopomofo (Dachen)", comment: ""))
|
||||
itmAppleZhuyinBopomofo.title = NSLocalizedString("Apple Zhuyin Bopomofo (Dachen)", comment: "")
|
||||
itmAppleZhuyinBopomofo.representedObject = String(
|
||||
"com.apple.keylayout.ZhuyinBopomofo")
|
||||
basicKeyboardLayoutButton.menu?.addItem(itmAppleZhuyinBopomofo)
|
||||
|
||||
let itmAppleZhuyinEten = NSMenuItem()
|
||||
itmAppleZhuyinEten.title = String(
|
||||
format: NSLocalizedString("Apple Zhuyin Eten (Traditional)", comment: ""))
|
||||
itmAppleZhuyinEten.title = NSLocalizedString("Apple Zhuyin Eten (Traditional)", comment: "")
|
||||
itmAppleZhuyinEten.representedObject = String("com.apple.keylayout.ZhuyinEten")
|
||||
basicKeyboardLayoutButton.menu?.addItem(itmAppleZhuyinEten)
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.3.0</string>
|
||||
<string>2.3.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2300</string>
|
||||
<string>2310</string>
|
||||
<key>UpdateInfoEndpoint</key>
|
||||
<string>https://gitee.com/vchewing/vChewing-macOS/raw/main/Update-Info.plist</string>
|
||||
<key>UpdateInfoSite</key>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// (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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// (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).
|
||||
// ====================
|
||||
|
@ -36,9 +36,7 @@ import Cocoa
|
|||
if let eulaContent = Bundle.main.localizedInfoDictionary?["CFEULAContent"] as? String {
|
||||
appEULAContent.string = eulaContent
|
||||
}
|
||||
appVersionLabel.stringValue = String(
|
||||
format: "%@ Build %@", versionString, installingVersion
|
||||
)
|
||||
appVersionLabel.stringValue = "\(versionString) Build \(installingVersion)"
|
||||
}
|
||||
|
||||
@IBAction func btnWebsite(_: NSButton) {
|
||||
|
|
|
@ -726,7 +726,7 @@
|
|||
<key>USE_HFS+_COMPRESSION</key>
|
||||
<false/>
|
||||
<key>VERSION</key>
|
||||
<string>2.3.0</string>
|
||||
<string>2.3.1</string>
|
||||
</dict>
|
||||
<key>TYPE</key>
|
||||
<integer>0</integer>
|
||||
|
|
|
@ -116,6 +116,7 @@
|
|||
5BEDB723283B4C250078EB25 /* data-cht.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5BEDB720283B4AEA0078EB25 /* data-cht.plist */; };
|
||||
5BEDB724283B4C250078EB25 /* data-symbols.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5BEDB71E283B4AEA0078EB25 /* data-symbols.plist */; };
|
||||
5BEDB725283B4C250078EB25 /* data-chs.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5BEDB71C283B4AEA0078EB25 /* data-chs.plist */; };
|
||||
5BF0B84C28C070B000795FC6 /* NSEventExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BF0B84B28C070B000795FC6 /* NSEventExtension.swift */; };
|
||||
5BF9DA2728840E6200DBD48E /* template-usersymbolphrases.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2228840E6200DBD48E /* template-usersymbolphrases.txt */; };
|
||||
5BF9DA2828840E6200DBD48E /* template-exclusions.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2328840E6200DBD48E /* template-exclusions.txt */; };
|
||||
5BF9DA2928840E6200DBD48E /* template-associatedPhrases-chs.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2428840E6200DBD48E /* template-associatedPhrases-chs.txt */; };
|
||||
|
@ -133,7 +134,6 @@
|
|||
6ACA41FD15FC1D9000935EF6 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6ACA41F015FC1D9000935EF6 /* MainMenu.xib */; };
|
||||
6ACA420215FC1E5200935EF6 /* vChewing.app in Resources */ = {isa = PBXBuildFile; fileRef = 6A0D4EA215FC0D2D00ABF4B3 /* vChewing.app */; };
|
||||
D427F76C278CA2B0004A2160 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D427F76B278CA1BA004A2160 /* AppDelegate.swift */; };
|
||||
D456576E279E4F7B00DF6BC9 /* InputSignal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D456576D279E4F7B00DF6BC9 /* InputSignal.swift */; };
|
||||
D461B792279DAC010070E734 /* InputState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D461B791279DAC010070E734 /* InputState.swift */; };
|
||||
D47B92C027972AD100458394 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47B92BF27972AC800458394 /* main.swift */; };
|
||||
D47F7DCE278BFB57002F9DD7 /* ctlPrefWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DCD278BFB57002F9DD7 /* ctlPrefWindow.swift */; };
|
||||
|
@ -344,6 +344,7 @@
|
|||
5BEDB71E283B4AEA0078EB25 /* data-symbols.plist */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; name = "data-symbols.plist"; path = "Data/data-symbols.plist"; sourceTree = "<group>"; };
|
||||
5BEDB71F283B4AEA0078EB25 /* data-zhuyinwen.plist */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; name = "data-zhuyinwen.plist"; path = "Data/data-zhuyinwen.plist"; sourceTree = "<group>"; };
|
||||
5BEDB720283B4AEA0078EB25 /* data-cht.plist */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; name = "data-cht.plist"; path = "Data/data-cht.plist"; sourceTree = "<group>"; };
|
||||
5BF0B84B28C070B000795FC6 /* NSEventExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSEventExtension.swift; sourceTree = "<group>"; };
|
||||
5BF255CD28B2694E003ECB60 /* vChewing-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "vChewing-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
5BF9DA2228840E6200DBD48E /* template-usersymbolphrases.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = "template-usersymbolphrases.txt"; sourceTree = "<group>"; usesTabs = 0; };
|
||||
5BF9DA2328840E6200DBD48E /* template-exclusions.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = "template-exclusions.txt"; sourceTree = "<group>"; usesTabs = 0; };
|
||||
|
@ -365,7 +366,6 @@
|
|||
6ACA41EF15FC1D9000935EF6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
6ACA41F215FC1D9000935EF6 /* Installer-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "Installer-Info.plist"; path = "Installer/Installer-Info.plist"; sourceTree = SOURCE_ROOT; };
|
||||
D427F76B278CA1BA004A2160 /* AppDelegate.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = AppDelegate.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
D456576D279E4F7B00DF6BC9 /* InputSignal.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = InputSignal.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
D461B791279DAC010070E734 /* InputState.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = InputState.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
D47B92BF27972AC800458394 /* main.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = main.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
D47F7DCD278BFB57002F9DD7 /* ctlPrefWindow.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlPrefWindow.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
|
@ -498,13 +498,13 @@
|
|||
5B21176D28753B35000443A9 /* ctlInputMethod_HandleDisplay.swift */,
|
||||
5B21176B287539BB000443A9 /* ctlInputMethod_HandleStates.swift */,
|
||||
5BB802D927FABA8300CF1C19 /* ctlInputMethod_Menu.swift */,
|
||||
D456576D279E4F7B00DF6BC9 /* InputSignal.swift */,
|
||||
D461B791279DAC010070E734 /* InputState.swift */,
|
||||
5BD0113C2818543900609769 /* KeyHandler_Core.swift */,
|
||||
5B782EC3280C243C007276DE /* KeyHandler_HandleCandidate.swift */,
|
||||
5BE3779F288FED8D0037365B /* KeyHandler_HandleComposition.swift */,
|
||||
5B7F225C2808501000DDD3CB /* KeyHandler_HandleInput.swift */,
|
||||
5B3133BE280B229700A4A505 /* KeyHandler_States.swift */,
|
||||
5BF0B84B28C070B000795FC6 /* NSEventExtension.swift */,
|
||||
5B62A33727AE79CD00A19448 /* StringUtils.swift */,
|
||||
5BAA8FBD282CAF380066C406 /* SyllableComposer.swift */,
|
||||
);
|
||||
|
@ -1220,7 +1220,6 @@
|
|||
D47F7DD0278C0897002F9DD7 /* ctlNonModalAlertWindow.swift in Sources */,
|
||||
5B2170E5289FACAD00BE7304 /* 6_Node.swift in Sources */,
|
||||
5B949BD92816DC5400D87B5D /* LineReader.swift in Sources */,
|
||||
D456576E279E4F7B00DF6BC9 /* InputSignal.swift in Sources */,
|
||||
5BA9FD1027FEDB6B002DE248 /* suiPrefPaneKeyboard.swift in Sources */,
|
||||
5B3133BF280B229700A4A505 /* KeyHandler_States.swift in Sources */,
|
||||
5B2170E1289FACAD00BE7304 /* 0_Megrez.swift in Sources */,
|
||||
|
@ -1262,6 +1261,7 @@
|
|||
5B2170E0289FACAD00BE7304 /* 7_LangModel.swift in Sources */,
|
||||
5B62A34927AE7CD900A19448 /* TooltipController.swift in Sources */,
|
||||
5BA9FD4027FEF3C8002DE248 /* Localization.swift in Sources */,
|
||||
5BF0B84C28C070B000795FC6 /* NSEventExtension.swift in Sources */,
|
||||
5BAA8FBE282CAF380066C406 /* SyllableComposer.swift in Sources */,
|
||||
5B20430728BEE30900BFC6FD /* BookmarkManager.swift in Sources */,
|
||||
5BA9FD1327FEDB6B002DE248 /* suiPrefPaneDictionary.swift in Sources */,
|
||||
|
@ -1471,7 +1471,7 @@
|
|||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2300;
|
||||
CURRENT_PROJECT_VERSION = 2310;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
|
@ -1481,7 +1481,7 @@
|
|||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 2.3.0;
|
||||
MARKETING_VERSION = 2.3.1;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewingTests;
|
||||
|
@ -1510,13 +1510,13 @@
|
|||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2300;
|
||||
CURRENT_PROJECT_VERSION = 2310;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 2.3.0;
|
||||
MARKETING_VERSION = 2.3.1;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewingTests;
|
||||
|
@ -1548,7 +1548,7 @@
|
|||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2300;
|
||||
CURRENT_PROJECT_VERSION = 2310;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
|
@ -1570,7 +1570,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.3.0;
|
||||
MARKETING_VERSION = 2.3.1;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
|
||||
|
@ -1600,7 +1600,7 @@
|
|||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2300;
|
||||
CURRENT_PROJECT_VERSION = 2310;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
|
@ -1618,7 +1618,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.3.0;
|
||||
MARKETING_VERSION = 2.3.1;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
|
||||
|
@ -1734,7 +1734,7 @@
|
|||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2300;
|
||||
CURRENT_PROJECT_VERSION = 2310;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
|
@ -1763,7 +1763,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.3.0;
|
||||
MARKETING_VERSION = 2.3.1;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@ -1793,7 +1793,7 @@
|
|||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2300;
|
||||
CURRENT_PROJECT_VERSION = 2310;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
|
@ -1816,7 +1816,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.3.0;
|
||||
MARKETING_VERSION = 2.3.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -1840,7 +1840,7 @@
|
|||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2300;
|
||||
CURRENT_PROJECT_VERSION = 2310;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
|
@ -1861,7 +1861,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.3.0;
|
||||
MARKETING_VERSION = 2.3.1;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingInstaller;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@ -1884,7 +1884,7 @@
|
|||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2300;
|
||||
CURRENT_PROJECT_VERSION = 2310;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
|
@ -1899,7 +1899,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.3.0;
|
||||
MARKETING_VERSION = 2.3.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingInstaller;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,357 +1 @@
|
|||
// Copyright (c) 2021 and onwards Zonble Yang (MIT-NTL License).
|
||||
// All possible vChewing-specific modifications are of:
|
||||
// (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 XCTest
|
||||
|
||||
@testable import vChewing
|
||||
|
||||
class KeyHandlerTestsSCPCCHT: XCTestCase {
|
||||
func reset() {
|
||||
UserDef.allCases.forEach {
|
||||
UserDefaults.standard.removeObject(forKey: $0.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
func makeSnapshot() -> [String: Any] {
|
||||
var dict = [String: Any]()
|
||||
UserDef.allCases.forEach {
|
||||
dict[$0.rawValue] = UserDefaults.standard.object(forKey: $0.rawValue)
|
||||
}
|
||||
return dict
|
||||
}
|
||||
|
||||
func restore(from snapshot: [String: Any]) {
|
||||
UserDef.allCases.forEach {
|
||||
UserDefaults.standard.set(snapshot[$0.rawValue], forKey: $0.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
var snapshot: [String: Any]?
|
||||
|
||||
var handler = KeyHandler()
|
||||
|
||||
override func setUpWithError() throws {
|
||||
snapshot = makeSnapshot()
|
||||
reset()
|
||||
mgrPrefs.basicKeyboardLayout = "com.apple.keylayout.ABC"
|
||||
mgrPrefs.mandarinParser = 0
|
||||
mgrPrefs.useSCPCTypingMode = false
|
||||
mgrPrefs.associatedPhrasesEnabled = false
|
||||
mgrLangModel.loadDataModel(.imeModeCHT)
|
||||
handler = KeyHandler()
|
||||
handler.inputMode = .imeModeCHT
|
||||
_ = mgrPrefs.toggleSCPCTypingModeEnabled()
|
||||
_ = mgrPrefs.toggleAssociatedPhrasesEnabled()
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
if let snapshot = snapshot {
|
||||
restore(from: snapshot)
|
||||
}
|
||||
}
|
||||
|
||||
func testPunctuationTable() {
|
||||
let input = InputSignal(
|
||||
inputText: "`", keyCode: KeyCode.kSymbolMenuPhysicalKeyIntl.rawValue, charCode: 0, flags: .option
|
||||
)
|
||||
var state: InputStateProtocol = InputState.Empty()
|
||||
_ = handler.handle(input: input, state: state) { newState in
|
||||
state = newState
|
||||
} errorCallback: {
|
||||
}
|
||||
|
||||
XCTAssertTrue(state is InputState.ChoosingCandidate, "\(state)")
|
||||
if let state = state as? InputState.ChoosingCandidate {
|
||||
XCTAssertTrue(state.candidates.map(\.1).contains(","))
|
||||
}
|
||||
}
|
||||
|
||||
func testPunctuationComma() {
|
||||
let enabled = mgrPrefs.halfWidthPunctuationEnabled
|
||||
mgrPrefs.halfWidthPunctuationEnabled = false
|
||||
let input = InputSignal(inputText: "<", keyCode: 0, charCode: charCode("<"), flags: .shift)
|
||||
var state: InputStateProtocol = InputState.Empty()
|
||||
_ = handler.handle(input: input, state: state) { newState in
|
||||
state = newState
|
||||
} errorCallback: {
|
||||
}
|
||||
|
||||
XCTAssertTrue(state is InputState.ChoosingCandidate, "\(state)")
|
||||
if let state = state as? InputState.ChoosingCandidate {
|
||||
XCTAssertEqual(state.composingBuffer, ",")
|
||||
}
|
||||
mgrPrefs.halfWidthPunctuationEnabled = enabled
|
||||
}
|
||||
|
||||
func testPunctuationPeriod() {
|
||||
let enabled = mgrPrefs.halfWidthPunctuationEnabled
|
||||
mgrPrefs.halfWidthPunctuationEnabled = false
|
||||
let input = InputSignal(inputText: ">", keyCode: 0, charCode: charCode(">"), flags: .shift)
|
||||
var state: InputStateProtocol = InputState.Empty()
|
||||
_ = handler.handle(input: input, state: state) { newState in
|
||||
state = newState
|
||||
} errorCallback: {
|
||||
}
|
||||
|
||||
XCTAssertTrue(state is InputState.ChoosingCandidate, "\(state)")
|
||||
if let state = state as? InputState.ChoosingCandidate {
|
||||
XCTAssertEqual(state.composingBuffer, "。")
|
||||
}
|
||||
mgrPrefs.halfWidthPunctuationEnabled = enabled
|
||||
}
|
||||
|
||||
func testHalfPunctuationPeriod() {
|
||||
let enabled = mgrPrefs.halfWidthPunctuationEnabled
|
||||
mgrPrefs.halfWidthPunctuationEnabled = true
|
||||
let input = InputSignal(inputText: ">", keyCode: 0, charCode: charCode(">"), flags: .shift)
|
||||
var state: InputStateProtocol = InputState.Empty()
|
||||
_ = handler.handle(input: input, state: state) { newState in
|
||||
state = newState
|
||||
} errorCallback: {
|
||||
}
|
||||
|
||||
XCTAssertTrue(state is InputState.ChoosingCandidate, "\(state)")
|
||||
if let state = state as? InputState.ChoosingCandidate {
|
||||
XCTAssertEqual(state.composingBuffer, ".")
|
||||
}
|
||||
mgrPrefs.halfWidthPunctuationEnabled = enabled
|
||||
}
|
||||
|
||||
func testControlPunctuationPeriod() {
|
||||
let input = InputSignal(
|
||||
inputText: ".", keyCode: 0, charCode: charCode("."), flags: [.shift, .control]
|
||||
)
|
||||
var state: InputStateProtocol = InputState.Empty()
|
||||
var count = 0
|
||||
_ = handler.handle(input: input, state: state) { newState in
|
||||
if count == 0 {
|
||||
state = newState
|
||||
}
|
||||
count += 1
|
||||
} errorCallback: {
|
||||
}
|
||||
|
||||
XCTAssertTrue(state is InputState.Inputting, "\(state)")
|
||||
if let state = state as? InputState.Inputting {
|
||||
XCTAssertEqual(state.composingBuffer, "。")
|
||||
}
|
||||
}
|
||||
|
||||
func testEnterWithReading() {
|
||||
let input = InputSignal(inputText: "s", keyCode: 0, charCode: charCode("s"), flags: .shift)
|
||||
var state: InputStateProtocol = InputState.Empty()
|
||||
_ = handler.handle(input: input, state: state) { newState in
|
||||
state = newState
|
||||
} errorCallback: {
|
||||
}
|
||||
|
||||
XCTAssertTrue(state is InputState.Inputting, "\(state)")
|
||||
if let state = state as? InputState.Inputting {
|
||||
XCTAssertEqual(state.composingBuffer, "ㄋ")
|
||||
}
|
||||
|
||||
let enter = InputSignal(inputText: " ", keyCode: 0, charCode: 13, flags: [])
|
||||
var count = 0
|
||||
|
||||
_ = handler.handle(input: enter, state: state) { newState in
|
||||
if count == 0 {
|
||||
state = newState
|
||||
}
|
||||
count += 1
|
||||
} errorCallback: {
|
||||
}
|
||||
|
||||
XCTAssertTrue(state is InputState.Inputting, "\(state)")
|
||||
if let state = state as? InputState.Inputting {
|
||||
XCTAssertEqual(state.composingBuffer, "ㄋ")
|
||||
}
|
||||
}
|
||||
|
||||
func testInputNe() {
|
||||
let input = InputSignal(inputText: "s", keyCode: 0, charCode: charCode("s"), flags: .shift)
|
||||
var state: InputStateProtocol = InputState.Empty()
|
||||
_ = handler.handle(input: input, state: state) { newState in
|
||||
state = newState
|
||||
} errorCallback: {
|
||||
}
|
||||
|
||||
XCTAssertTrue(state is InputState.Inputting, "\(state)")
|
||||
if let state = state as? InputState.Inputting {
|
||||
XCTAssertEqual(state.composingBuffer, "ㄋ")
|
||||
}
|
||||
}
|
||||
|
||||
func testInputNi() {
|
||||
var state: InputStateProtocol = InputState.Empty()
|
||||
let keys = Array("su").charComponents
|
||||
for key in keys {
|
||||
let input = InputSignal(inputText: key, keyCode: 0, charCode: charCode(key), flags: [])
|
||||
_ = handler.handle(input: input, state: state) { newState in
|
||||
state = newState
|
||||
} errorCallback: {
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertTrue(state is InputState.Inputting, "\(state)")
|
||||
if let state = state as? InputState.Inputting {
|
||||
XCTAssertEqual(state.composingBuffer, "ㄋㄧ")
|
||||
}
|
||||
}
|
||||
|
||||
func testInputNi3() {
|
||||
var state: InputStateProtocol = InputState.Empty()
|
||||
let keys = Array("su3").charComponents
|
||||
for key in keys {
|
||||
let input = InputSignal(inputText: key, keyCode: 0, charCode: charCode(key), flags: [])
|
||||
_ = handler.handle(input: input, state: state) { newState in
|
||||
state = newState
|
||||
} errorCallback: {
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertTrue(state is InputState.ChoosingCandidate, "\(state)")
|
||||
if let state = state as? InputState.ChoosingCandidate {
|
||||
XCTAssertTrue(state.candidates.map(\.1).contains("你"))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Further bug-hunting needed.
|
||||
func testCancelCandidateUsingDelete() {
|
||||
mgrPrefs.useSCPCTypingMode = true
|
||||
var state: InputStateProtocol = InputState.Empty()
|
||||
let keys = Array("su3").charComponents
|
||||
for key in keys {
|
||||
let input = InputSignal(inputText: key, keyCode: 0, charCode: charCode(key), flags: [])
|
||||
_ = handler.handle(input: input, state: state) { newState in
|
||||
state = newState
|
||||
} errorCallback: {
|
||||
}
|
||||
}
|
||||
|
||||
let input = InputSignal(
|
||||
inputText: " ", keyCode: KeyCode.kWindowsDelete.rawValue, charCode: charCode(" "), flags: []
|
||||
)
|
||||
_ = handler.handle(input: input, state: state) { newState in
|
||||
state = newState
|
||||
} errorCallback: {
|
||||
}
|
||||
print("Expecting EmptyIgnoringPreviousState.")
|
||||
print("\(state)")
|
||||
// XCTAssertTrue(state is InputState.Empty, "\(state)")
|
||||
}
|
||||
|
||||
// TODO: Further bug-hunting needed.
|
||||
func testCancelCandidateUsingEsc() {
|
||||
mgrPrefs.useSCPCTypingMode = true
|
||||
var state: InputStateProtocol = InputState.Empty()
|
||||
let keys = Array("su3").charComponents
|
||||
for key in keys {
|
||||
let input = InputSignal(inputText: key, keyCode: 0, charCode: charCode(key), flags: [])
|
||||
_ = handler.handle(input: input, state: state) { newState in
|
||||
state = newState
|
||||
} errorCallback: {
|
||||
}
|
||||
}
|
||||
|
||||
let input = InputSignal(inputText: " ", keyCode: KeyCode.kEscape.rawValue, charCode: charCode(" "), flags: [])
|
||||
_ = handler.handle(input: input, state: state) { newState in
|
||||
state = newState
|
||||
} errorCallback: {
|
||||
}
|
||||
print("Expecting EmptyIgnoringPreviousState.")
|
||||
print("\(state)")
|
||||
// XCTAssertTrue(state is InputState.Empty, "\(state)")
|
||||
}
|
||||
|
||||
// TODO: Further bug-hunting needed.
|
||||
func testAssociatedPhrases() {
|
||||
let enabled = mgrPrefs.associatedPhrasesEnabled
|
||||
mgrPrefs.associatedPhrasesEnabled = true
|
||||
mgrPrefs.useSCPCTypingMode = true
|
||||
handler.forceOpenStringInsteadForAssociatePhrases("二 百五")
|
||||
var state: InputStateProtocol = InputState.Empty()
|
||||
let keys = Array("-41").charComponents
|
||||
for key in keys {
|
||||
let input = InputSignal(inputText: key, keyCode: 0, charCode: charCode(key), flags: [])
|
||||
_ = handler.handle(input: input, state: state) { newState in
|
||||
state = newState
|
||||
} errorCallback: {
|
||||
}
|
||||
}
|
||||
print("Expecting AssociatedPhrases.")
|
||||
print("\(state)")
|
||||
// XCTAssertTrue(state is InputState.AssociatedPhrases, "\(state)")
|
||||
// if let state = state as? InputState.AssociatedPhrases {
|
||||
// XCTAssertTrue(state.candidates.map(\.1).contains("百五"))
|
||||
// }
|
||||
mgrPrefs.associatedPhrasesEnabled = enabled
|
||||
}
|
||||
|
||||
func testNoAssociatedPhrases() {
|
||||
let enabled = mgrPrefs.associatedPhrasesEnabled
|
||||
mgrPrefs.associatedPhrasesEnabled = false
|
||||
var state: InputStateProtocol = InputState.Empty()
|
||||
let keys = Array("aul ").charComponents
|
||||
for key in keys {
|
||||
let input = InputSignal(inputText: key, keyCode: 0, charCode: charCode(key), flags: [])
|
||||
_ = handler.handle(input: input, state: state) { newState in
|
||||
state = newState
|
||||
|
||||
} errorCallback: {
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertTrue(state is InputState.Empty, "\(state)")
|
||||
mgrPrefs.associatedPhrasesEnabled = enabled
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - StringView Ranges Extension (by Isaac Xen)
|
||||
|
||||
extension String {
|
||||
fileprivate func ranges(splitBy separator: Element) -> [Range<String.Index>] {
|
||||
var startIndex = startIndex
|
||||
return split(separator: separator).reduce(into: []) { ranges, substring in
|
||||
_ = range(of: substring, range: startIndex..<endIndex).map { range in
|
||||
ranges.append(range)
|
||||
startIndex = range.upperBound
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension vChewing.LMAssociates {
|
||||
public mutating func forceOpenStringInstead(_ strData: String) {
|
||||
strData.ranges(splitBy: "\n").filter { !$0.isEmpty }.forEach {
|
||||
let neta = strData[$0].split(separator: " ")
|
||||
if neta.count >= 2 {
|
||||
let theKey = String(neta[0])
|
||||
if !theKey.isEmpty, theKey.first != "#" {
|
||||
for (i, _) in neta.filter({ $0.first != "#" && !$0.isEmpty }).enumerated() {
|
||||
if i == 0 { continue }
|
||||
rangeMap[theKey, default: []].append(($0, i))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension vChewing.LMInstantiator {
|
||||
public func forceOpenStringInsteadForAssociatePhrases(_ strData: String) {
|
||||
lmAssociates.forceOpenStringInstead(strData)
|
||||
}
|
||||
}
|
||||
|
||||
extension KeyHandler {
|
||||
public func forceOpenStringInsteadForAssociatePhrases(_ strData: String) {
|
||||
currentLM.forceOpenStringInsteadForAssociatePhrases(strData + "\n")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards Zonble Yang (MIT-NTL License).
|
||||
// (c) 2021 and onwards Zonble Yang (MIT-NTL License).
|
||||
// All possible vChewing-specific modifications are of:
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// ====================
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2021 and onwards Zonble Yang (MIT-NTL License).
|
||||
// (c) 2021 and onwards Zonble Yang (MIT-NTL License).
|
||||
// All possible vChewing-specific modifications are of:
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// ====================
|
||||
|
|
Loading…
Reference in New Issue