1.9.1 SP2 // Maintenance. Merge Gitee PR!81 from upd/1.9.1sp2

This commit is contained in:
ShikiSuen 2022-08-11 05:31:13 +00:00 committed by Gitee
commit a227fa8459
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
39 changed files with 567 additions and 344 deletions

View File

@ -8,7 +8,7 @@ import SwiftUI
// MARK: - NSComboBox
// Ref: https://stackoverflow.com/a/71058587/4162914
@available(macOS 11.0, *)
@available(macOS 10.15, *)
struct ComboBox: NSViewRepresentable {
// The items that will show up in the pop-up menu:
var items: [String]

@ -1 +1 @@
Subproject commit 1d1224ee392d757526dc8aab6550e9d41dd3d784
Subproject commit 1daf4d576a248373889889213bea4bd3cbb4b5d4

View File

@ -372,7 +372,6 @@ extension KeyHandler {
// MARK: Shift+ (Shift+Letter Processing)
// 使 2.2
if input.isUpperCaseASCIILetterKey, !input.isCommandHold, !input.isControlHold {
if input.isShiftHold { // isOptionHold
switch mgrPrefs.upperCaseLetterKeyBehavior {
@ -388,7 +387,8 @@ extension KeyHandler {
return true
default: // case 0
let letter: String! = String(
format: "%@%c", "_letter_", charCode.isPrintableASCII ? CChar(charCode) : inputText)
format: "%@%c", "_letter_", charCode.isPrintableASCII ? CChar(charCode) : inputText
)
if handlePunctuation(
letter,
state: state,

View File

@ -922,7 +922,8 @@ public struct Tekkon {
/// - newToneOne:
/// - Returns:
static func cnvHanyuPinyinToPhona(target: String, newToneOne: String = "") -> String {
if target.contains("_") { return target }
///
if target.contains("_") || !target.isNotPureAlphanumerical { return target }
var result = target
for key in Tekkon.mapHanyuPinyin.keys.sorted(by: { $0.count > $1.count }) {
guard let value = Tekkon.mapHanyuPinyin[key] else { continue }
@ -1446,3 +1447,12 @@ public struct Tekkon {
"s": "", "t": "", "u": "", "v": "", "w": "", "x": "", "y": "", "z": "", " ": " ",
]
}
///
extension String {
fileprivate var isNotPureAlphanumerical: Bool {
let regex = ".*[^A-Za-z0-9].*"
let testString = NSPredicate(format: "SELF MATCHES %@", regex)
return testString.evaluate(with: self)
}
}

View File

@ -187,7 +187,8 @@ class ctlInputMethod: IMKInputController {
@objc(handleEvent:client:) override func handle(_ event: NSEvent!, client sender: Any!) -> Bool {
_ = sender //
// Shift
// Shift macOS 10.15 macOS
if #available(macOS 10.15, *) {
if ShiftKeyUpChecker.check(event) {
if !rencentKeyHandledByKeyHandler {
NotifierController.notify(
@ -202,6 +203,7 @@ class ctlInputMethod: IMKInputController {
rencentKeyHandledByKeyHandler = false
return false
}
}
/// flags使 KeyHandler
/// flags

View File

@ -83,8 +83,23 @@ extension ctlInputMethod {
return NSFont.systemFont(ofSize: size)
}
/// FB10978412: Since macOS 11 Big Sur, CTFontCreateUIFontForLanguage cannot
/// distinguish zh-Hans and zh-Hant with correct adoptation of proper PingFang SC/TC variants.
///
/// Instructions for Apple Developer relations to reveal this bug:
///
/// 1) Remove the usage of ".languageIdentifier" from ctlCandidateUniversal.swift (already done).
/// 2) Run "make update" in the project folder to download the latest git-submodule of dictionary file.
/// 3) Compile the target "vChewingInstaller", run it. It will install the input method into
/// "~/Library/Input Methods/" folder. Remember to ENABLE BOTH "vChewing-CHS"
/// and "vChewing-CHT" input sources in System Preferences / Settings.
/// 4) Type Zhuyin "ej3" (ˇ) (or "gu3" in Pinyin if you enabled Pinyin typing in vChewing preferences.)
/// using both "vChewing-CHS" and "vChewing-CHT", and check the candidate window by pressing SPACE key.
/// 5) Do NOT enable either KangXi conversion mode nor JIS conversion mode. They are disabled by default.
/// 6) Expecting the glyph differences of the candidate "" between PingFang SC and PingFang TC when rendering
/// the candidate window in different "vChewing-CHS" and "vChewing-CHT" input modes.
func candidateFont(name: String?, size: CGFloat) -> NSFont {
var finalReturnFont: NSFont =
let finalReturnFont: NSFont =
{
switch IME.currentInputMode {
case InputMode.imeModeCHS:
@ -98,9 +113,6 @@ extension ctlInputMethod {
}
}()
?? NSFont.systemFont(ofSize: size)
// macOS 10.11-10.15 macOS 12 Monterey Bug
// macOS 12 Monterey ctlCandidateUniversal
if #available(macOS 12.0, *) { finalReturnFont = NSFont.systemFont(ofSize: size) }
if let name = name {
return NSFont(name: name, size: size) ?? finalReturnFont
}

View File

@ -185,7 +185,7 @@ extension ctlInputMethod {
// MARK: - IME Menu Items
@objc override func showPreferences(_: Any?) {
if #available(macOS 11.0, *) {
if #available(macOS 10.15, *) {
NSApp.setActivationPolicy(.accessory)
ctlPrefUI.shared.controller.show(preferencePane: Preferences.PaneIdentifier(rawValue: "General"))
ctlPrefUI.shared.controller.window?.level = .floating

View File

@ -77,8 +77,15 @@ public enum IME {
// mgrLangModel loadUserPhrases dataFolderPath
//
//
if mgrPrefs.associatedPhrasesEnabled {
mgrLangModel.loadUserAssociatesData()
}
if mgrPrefs.phraseReplacementEnabled {
mgrLangModel.loadUserPhraseReplacement()
}
if mgrPrefs.useSCPCTypingMode {
mgrLangModel.loadUserSCPCSequencesData()
}
mgrLangModel.loadUserPhrasesData()
if !userOnly {
// mgrLangModel.loadDataModels()

View File

@ -23,7 +23,7 @@ public enum UserDef: String, CaseIterable {
case kCandidateListTextSize = "CandidateListTextSize"
case kAppleLanguages = "AppleLanguages"
case kShouldAutoReloadUserDataFiles = "ShouldAutoReloadUserDataFiles"
case kUseRearCursorMode = "useRearCursorMode"
case kUseRearCursorMode = "UseRearCursorMode"
case kUseHorizontalCandidateList = "UseHorizontalCandidateList"
case kChooseCandidateUsingSpace = "ChooseCandidateUsingSpace"
case kCNS11643Enabled = "CNS11643Enabled"
@ -388,15 +388,6 @@ public enum mgrPrefs {
mgrPrefs.allowBoostingSingleKanjiAsUserPhrase ? 1 : 2
}
@UserDefault(key: UserDef.kUseSCPCTypingMode.rawValue, defaultValue: false)
static var useSCPCTypingMode: Bool
static func toggleSCPCTypingModeEnabled() -> Bool {
useSCPCTypingMode = !useSCPCTypingMode
UserDefaults.standard.set(useSCPCTypingMode, forKey: UserDef.kUseSCPCTypingMode.rawValue)
return useSCPCTypingMode
}
@UserDefault(key: UserDef.kMaxCandidateLength.rawValue, defaultValue: 10)
static var maxCandidateLength: Int
@ -564,8 +555,29 @@ public enum mgrPrefs {
}
}
@UserDefault(key: UserDef.kUseSCPCTypingMode.rawValue, defaultValue: false)
static var useSCPCTypingMode: Bool {
willSet {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) {
mgrLangModel.loadUserSCPCSequencesData()
}
}
}
static func toggleSCPCTypingModeEnabled() -> Bool {
useSCPCTypingMode = !useSCPCTypingMode
UserDefaults.standard.set(useSCPCTypingMode, forKey: UserDef.kUseSCPCTypingMode.rawValue)
return useSCPCTypingMode
}
@UserDefault(key: UserDef.kPhraseReplacementEnabled.rawValue, defaultValue: false)
static var phraseReplacementEnabled: Bool
static var phraseReplacementEnabled: Bool {
willSet {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) {
mgrLangModel.loadUserPhraseReplacement()
}
}
}
static func togglePhraseReplacementEnabled() -> Bool {
phraseReplacementEnabled = !phraseReplacementEnabled
@ -575,7 +587,13 @@ public enum mgrPrefs {
}
@UserDefault(key: UserDef.kAssociatedPhrasesEnabled.rawValue, defaultValue: false)
static var associatedPhrasesEnabled: Bool
static var associatedPhrasesEnabled: Bool {
willSet {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) {
mgrLangModel.loadUserAssociatesData()
}
}
}
static func toggleAssociatedPhrasesEnabled() -> Bool {
associatedPhrasesEnabled = !associatedPhrasesEnabled

View File

@ -76,6 +76,7 @@ extension vChewing {
)
var lmReplacements = LMReplacments()
var lmAssociates = LMAssociates()
var lmPlainBopomofo = LMPlainBopomofo()
// MARK: -
@ -166,6 +167,16 @@ extension vChewing {
}
}
public func loadUserSCPCSequencesData(path: String) {
if FileManager.default.isReadableFile(atPath: path) {
lmPlainBopomofo.close()
lmPlainBopomofo.open(path)
IME.prtDebugIntel("lmPlainBopomofo: \(lmPlainBopomofo.count) entries of data loaded from: \(path)")
} else {
IME.prtDebugIntel("lmPlainBopomofo: File access failure: \(path)")
}
}
// MARK: -
///
@ -181,6 +192,11 @@ extension vChewing {
///
var rawAllUnigrams: [Megrez.Unigram] = []
// 使
if mgrPrefs.useSCPCTypingMode {
rawAllUnigrams += lmPlainBopomofo.valuesFor(key: key).map { Megrez.Unigram(value: $0, score: 0) }
}
// reversed 使
//
// rawUserUnigrams

View File

@ -32,7 +32,7 @@ extension vChewing {
}
let arrTarget = target.dropLast().dropFirst().split(separator: ",")
guard arrTarget.count == 2 else { return target }
return "(\(Tekkon.cnvHanyuPinyinToPhona(target: String(arrTarget[0]))),\(arrTarget[1]))"
return "(\(Tekkon.cnvHanyuPinyinToPhona(target: String(arrTarget[0]).lowercased())),\(arrTarget[1]))"
}
@discardableResult public mutating func open(_ path: String) -> Bool {

View File

@ -77,7 +77,7 @@ extension vChewing {
if !neta[0].isEmpty, !neta[1].isEmpty {
let theKey = shouldReverse ? String(neta[1]) : String(neta[0])
let theValue = $0
rangeMap[Tekkon.cnvHanyuPinyinToPhona(target: theKey), default: []].append(theValue)
rangeMap[Tekkon.cnvHanyuPinyinToPhona(target: theKey.lowercased()), default: []].append(theValue)
}
}
}

View File

@ -0,0 +1,83 @@
// Copyright (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)
// ... with NTL restriction stating that:
// No trademark license is granted to use the trade names, trademarks, service
// marks, or product names of Contributor, except as required to fulfill notice
// requirements defined in MIT License.
import Foundation
extension vChewing {
@frozen public struct LMPlainBopomofo {
var rangeMap: [String: String] = [:]
public var count: Int {
rangeMap.count
}
public init() {
rangeMap = [:]
}
public func isLoaded() -> Bool {
!rangeMap.isEmpty
}
@discardableResult public mutating func open(_ path: String) -> Bool {
if isLoaded() {
return false
}
do {
let rawData = try Data(contentsOf: URL(fileURLWithPath: path))
let rawPlist: [String: String] =
try PropertyListSerialization.propertyList(from: rawData, format: nil) as? [String: String] ?? .init()
rangeMap = rawPlist
} catch {
IME.prtDebugIntel("\(error)")
IME.prtDebugIntel("↑ Exception happened when reading data at: \(path).")
return false
}
return true
}
public mutating func close() {
if isLoaded() {
rangeMap.removeAll()
}
}
public func dump() {
// We remove this function in order to reduce out maintenance workload.
// This function will be implemented only if further hard-necessity comes.
}
public func valuesFor(key: String) -> [String] {
var pairs: [String] = []
if let arrRangeRecords: String = rangeMap[key] {
pairs.append(contentsOf: arrRangeRecords.map { String($0) })
}
var set = Set<String>()
return pairs.filter { set.insert($0).inserted }
}
public func hasValuesFor(key: String) -> Bool { rangeMap.keys.contains(key) }
}
}
// 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
}
}
}
}

View File

@ -175,6 +175,15 @@ enum mgrLangModel {
)
}
public static func loadUserSCPCSequencesData() {
gLangModelCHT.loadUserSCPCSequencesData(
path: mgrLangModel.userSCPCSequencesURL(InputMode.imeModeCHT).path
)
gLangModelCHS.loadUserSCPCSequencesData(
path: mgrLangModel.userSCPCSequencesURL(InputMode.imeModeCHS).path
)
}
public static func checkIfUserPhraseExist(
userPhrase: String,
mode: InputMode,
@ -256,6 +265,14 @@ enum mgrLangModel {
return URL(fileURLWithPath: dataFolderPath(isDefaultFolder: false)).appendingPathComponent(fileName)
}
/// 使
/// - Parameter mode:
/// - Returns: URL
static func userSCPCSequencesURL(_ mode: InputMode) -> URL {
let fileName = (mode == InputMode.imeModeCHT) ? "data-plain-bpmf-cht.plist" : "data-plain-bpmf-chs.plist"
return URL(fileURLWithPath: dataFolderPath(isDefaultFolder: false)).appendingPathComponent(fileName)
}
/// 使
/// - Returns: URL
static func userSymbolNodeDataURL() -> URL {
@ -311,6 +328,7 @@ enum mgrLangModel {
userAssociatesDataURL(mode),
populateWithTemplate: mode == .imeModeCHS ? kTemplateNameUserAssociatesCHS : kTemplateNameUserAssociatesCHT
)
|| !ensureFileExists(userSCPCSequencesURL(mode))
|| !ensureFileExists(userFilteredDataURL(mode), populateWithTemplate: kTemplateNameUserExclusions)
|| !ensureFileExists(userReplacementsDataURL(mode), populateWithTemplate: kTemplateNameUserReplacements)
|| !ensureFileExists(userSymbolDataURL(mode), populateWithTemplate: kTemplateNameUserSymbolPhrases)

View File

@ -79,12 +79,8 @@ extension Megrez.Compositor {
//
let begin: Int = location - min(location, Megrez.Compositor.maxSpanLength - 1)
for theLocation in begin..<location {
let (A, B): (Int, Int) = {
(
min(location - theLocation + 1, spans[theLocation].maxLength),
max(location - theLocation + 1, spans[theLocation].maxLength)
)
}()
let (A, B): (Int, Int) = (location - theLocation + 1, spans[theLocation].maxLength)
guard A <= B else { continue }
for theLength in A...B {
guard let node = spans[theLocation].nodeOf(length: theLength) else { continue }
results.append(.init(node: node, spanIndex: theLocation))

View File

@ -150,7 +150,7 @@
"Keyboard" = "Keyboard";
"Misc Settings:" = "Misc Settings:";
"MiTAC" = "MiTAC";
"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only.";
"Non-QWERTY alphanumerical keyboard layouts are for Hanyu Pinyin parser only." = "Non-QWERTY alphanumerical keyboard layouts are for Hanyu Pinyin parser only.";
"Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter" = "Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter";
"Output Settings:" = "Output Settings:";
"Phonetic Parser:" = "Phonetic Parser:";

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 749 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 942 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -150,7 +150,7 @@
"Keyboard" = "Keyboard";
"Misc Settings:" = "Misc Settings:";
"MiTAC" = "MiTAC";
"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only.";
"Non-QWERTY alphanumerical keyboard layouts are for Hanyu Pinyin parser only." = "Non-QWERTY alphanumerical keyboard layouts are for Hanyu Pinyin parser only.";
"Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter" = "Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter";
"Output Settings:" = "Output Settings:";
"Phonetic Parser:" = "Phonetic Parser:";

View File

@ -150,7 +150,7 @@
"Keyboard" = "配列設定";
"Misc Settings:" = "他の設定:";
"MiTAC" = "神通配列";
"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "QWERTY 以外の英数キーボードは漢語弁音以外の配列に不適用。";
"Non-QWERTY alphanumerical keyboard layouts are for Hanyu Pinyin parser only." = "QWERTY 以外の英数キーボードは漢語弁音以外の配列に不適用。";
"Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter" = "Ctrl(+Alt)+CMD+Enter で出すのを漢語弁音と変換";
"Output Settings:" = "出力設定:";
"Phonetic Parser:" = "注音配列:";

View File

@ -151,7 +151,7 @@
"Keyboard" = "键盘";
"Misc Settings:" = "杂项:";
"MiTAC" = "神通排列";
"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "QWERTY 以外的英数布局是为了汉语拼音排列使用者而准备的。";
"Non-QWERTY alphanumerical keyboard layouts are for Hanyu Pinyin parser only." = "QWERTY 以外的英数布局是为了汉语拼音排列使用者而准备的。";
"Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter" = "Ctrl(+Alt)+CMD+Enter 输出汉语拼音而非注音";
"Output Settings:" = "输出设定:";
"Phonetic Parser:" = "注音排列:";

View File

@ -150,7 +150,7 @@
"Keyboard" = "鍵盤";
"Misc Settings:" = "雜項:";
"MiTAC" = "神通排列";
"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "QWERTY 以外的英數佈局是為了漢語拼音排列使用者而準備的。";
"Non-QWERTY alphanumerical keyboard layouts are for Hanyu Pinyin parser only." = "QWERTY 以外的英數佈局是為了漢語拼音排列使用者而準備的。";
"Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter" = "Ctrl(+Alt)+CMD+Enter 輸出漢語拼音而非注音";
"Output Settings:" = "輸出設定:";
"Phonetic Parser:" = "注音排列:";

View File

@ -190,20 +190,6 @@ private class vwrCandidateUniversal: NSView {
} else {
NSColor.controlBackgroundColor.setFill()
}
switch IME.currentInputMode {
case InputMode.imeModeCHS:
if #available(macOS 12.0, *) {
activeCandidateAttr[.languageIdentifier] = "zh-Hans" as AnyObject
}
case InputMode.imeModeCHT:
if #available(macOS 12.0, *) {
activeCandidateAttr[.languageIdentifier] =
(mgrPrefs.shiftJISShinjitaiOutputEnabled || mgrPrefs.chineseConversionEnabled)
? "ja" as AnyObject : "zh-Hant" as AnyObject
}
default:
break
}
NSBezierPath.fill(rctCandidateArea)
(keyLabels[index] as NSString).draw(
in: rctLabel, withAttributes: activeCandidateIndexAttr
@ -260,20 +246,6 @@ private class vwrCandidateUniversal: NSView {
} else {
NSColor.controlBackgroundColor.setFill()
}
switch IME.currentInputMode {
case InputMode.imeModeCHS:
if #available(macOS 12.0, *) {
activeCandidateAttr[.languageIdentifier] = "zh-Hans" as AnyObject
}
case InputMode.imeModeCHT:
if #available(macOS 12.0, *) {
activeCandidateAttr[.languageIdentifier] =
(mgrPrefs.shiftJISShinjitaiOutputEnabled || mgrPrefs.chineseConversionEnabled)
? "ja" as AnyObject : "zh-Hant" as AnyObject
}
default:
break
}
NSBezierPath.fill(rctCandidateArea)
(keyLabels[index] as NSString).draw(
in: rctLabel, withAttributes: activeCandidateIndexAttr

View File

@ -7,48 +7,59 @@
// requirements defined in MIT License.
import Cocoa
import SwiftUI
@available(macOS 11.0, *)
@available(macOS 10.15, *)
class ctlPrefUI {
private(set) var tabImageGeneral: NSImage! = NSImage(named: "PrefToolbar-General")
private(set) var tabImageExperiences: NSImage! = NSImage(named: "PrefToolbar-Experiences")
private(set) var tabImageDictionary: NSImage! = NSImage(named: "PrefToolbar-Dictionary")
private(set) var tabImageKeyboard: NSImage! = NSImage(named: "PrefToolbar-Keyboard")
init() {
if #available(macOS 11.0, *) {
tabImageGeneral = NSImage(
systemSymbolName: "wrench.and.screwdriver.fill", accessibilityDescription: "General Preferences"
)
tabImageExperiences = NSImage(
systemSymbolName: "person.fill.questionmark", accessibilityDescription: "Experiences Preferences"
)
tabImageDictionary = NSImage(
systemSymbolName: "character.book.closed.fill", accessibilityDescription: "Dictionary Preferences"
)
tabImageKeyboard = NSImage(
systemSymbolName: "keyboard.macwindow", accessibilityDescription: "Keyboard Preferences"
)
}
}
lazy var controller = PreferencesWindowController(
panes: [
Preferences.Pane(
identifier: Preferences.PaneIdentifier(rawValue: "General"),
title: NSLocalizedString("General", comment: ""),
toolbarIcon: NSImage(
systemSymbolName: "wrench.and.screwdriver.fill", accessibilityDescription: "General Preferences"
)
?? NSImage(named: NSImage.homeTemplateName)!
toolbarIcon: tabImageGeneral
) {
suiPrefPaneGeneral()
},
Preferences.Pane(
identifier: Preferences.PaneIdentifier(rawValue: "Experiences"),
title: NSLocalizedString("Experience", comment: ""),
toolbarIcon: NSImage(
systemSymbolName: "person.fill.questionmark", accessibilityDescription: "Experiences Preferences"
)
?? NSImage(named: NSImage.listViewTemplateName)!
toolbarIcon: tabImageExperiences
) {
suiPrefPaneExperience()
},
Preferences.Pane(
identifier: Preferences.PaneIdentifier(rawValue: "Dictionary"),
title: NSLocalizedString("Dictionary", comment: ""),
toolbarIcon: NSImage(
systemSymbolName: "character.book.closed.fill", accessibilityDescription: "Dictionary Preferences"
)
?? NSImage(named: NSImage.bookmarksTemplateName)!
toolbarIcon: tabImageDictionary
) {
suiPrefPaneDictionary()
},
Preferences.Pane(
identifier: Preferences.PaneIdentifier(rawValue: "Keyboard"),
title: NSLocalizedString("Keyboard", comment: ""),
toolbarIcon: NSImage(
systemSymbolName: "keyboard.macwindow", accessibilityDescription: "Keyboard Preferences"
)
?? NSImage(named: NSImage.actionTemplateName)!
toolbarIcon: tabImageKeyboard
) {
suiPrefPaneKeyboard()
},
@ -57,3 +68,47 @@ class ctlPrefUI {
)
static let shared = ctlPrefUI()
}
// MARK: - Add "onChange" support.
// Ref: https://mjeld.com/swiftui-macos-10-15-toggle-onchange/
@available(macOS 10.15, *)
extension Binding {
public func onChange(_ action: @escaping () -> Void) -> Binding {
Binding(
get: {
wrappedValue
},
set: { newValue in
wrappedValue = newValue
action()
}
)
}
}
// MARK: - Add ".tooltip" support.
// Ref: https://stackoverflow.com/a/63217861
@available(macOS 10.15, *)
struct Tooltip: NSViewRepresentable {
let tooltip: String
func makeNSView(context _: NSViewRepresentableContext<Tooltip>) -> NSView {
let view = NSView()
view.toolTip = tooltip
return view
}
func updateNSView(_: NSView, context _: NSViewRepresentableContext<Tooltip>) {}
}
@available(macOS 10.15, *)
extension View {
public func toolTip(_ tooltip: String) -> some View {
overlay(Tooltip(tooltip: tooltip))
}
}

View File

@ -8,7 +8,7 @@
import SwiftUI
@available(macOS 11.0, *)
@available(macOS 10.15, *)
struct suiPrefPaneDictionary: View {
private var fdrDefault = mgrLangModel.dataFolderPath(isDefaultFolder: true)
@State private var tbxUserDataPathSpecified: String =
@ -43,8 +43,13 @@ struct suiPrefPaneDictionary: View {
Preferences.Section(title: "", bottomDivider: true) {
Text(LocalizedStringKey("Choose your desired user data folder path. Will be omitted if invalid."))
HStack {
if #available(macOS 11.0, *) {
TextField(fdrDefault, text: $tbxUserDataPathSpecified).disabled(true)
.help(tbxUserDataPathSpecified)
} else {
TextField(fdrDefault, text: $tbxUserDataPathSpecified).disabled(true)
.toolTip(tbxUserDataPathSpecified)
}
Button {
IME.dlgOpenPath.title = NSLocalizedString(
"Choose your desired user data folder.", comment: ""
@ -98,48 +103,43 @@ struct suiPrefPaneDictionary: View {
}
Toggle(
LocalizedStringKey("Automatically reload user data files if changes detected"),
isOn: $selAutoReloadUserData
).controlSize(.small).onChange(of: selAutoReloadUserData) { value in
mgrPrefs.shouldAutoReloadUserDataFiles = value
isOn: $selAutoReloadUserData.onChange {
mgrPrefs.shouldAutoReloadUserDataFiles = selAutoReloadUserData
}
).controlSize(.small)
Divider()
Toggle(
LocalizedStringKey("Enable CNS11643 Support (2022-07-20)"),
isOn: $selEnableCNS11643
)
.onChange(of: selEnableCNS11643) { value in
mgrPrefs.cns11643Enabled = value
mgrLangModel.setCNSEnabled(value)
isOn: $selEnableCNS11643.onChange {
mgrPrefs.cns11643Enabled = selEnableCNS11643
mgrLangModel.setCNSEnabled(mgrPrefs.cns11643Enabled)
}
)
Toggle(
LocalizedStringKey("Enable symbol input support (incl. certain emoji symbols)"),
isOn: $selEnableSymbolInputSupport
)
.onChange(of: selEnableSymbolInputSupport) { value in
mgrPrefs.symbolInputEnabled = value
mgrLangModel.setSymbolEnabled(value)
isOn: $selEnableSymbolInputSupport.onChange {
mgrPrefs.symbolInputEnabled = selEnableSymbolInputSupport
mgrLangModel.setSymbolEnabled(mgrPrefs.symbolInputEnabled)
}
)
Toggle(
LocalizedStringKey("Allow boosting / excluding a candidate of single kanji"),
isOn: $selAllowBoostingSingleKanjiAsUserPhrase
)
.onChange(of: selAllowBoostingSingleKanjiAsUserPhrase) { value in
mgrPrefs.allowBoostingSingleKanjiAsUserPhrase = value
isOn: $selAllowBoostingSingleKanjiAsUserPhrase.onChange {
mgrPrefs.allowBoostingSingleKanjiAsUserPhrase = selAllowBoostingSingleKanjiAsUserPhrase
}
)
Toggle(
LocalizedStringKey("Applying typing suggestions from half-life user override model"),
isOn: $selFetchSuggestionsFromUserOverrideModel
)
.onChange(of: selFetchSuggestionsFromUserOverrideModel) { value in
mgrPrefs.fetchSuggestionsFromUserOverrideModel = value
isOn: $selFetchSuggestionsFromUserOverrideModel.onChange {
mgrPrefs.fetchSuggestionsFromUserOverrideModel = selFetchSuggestionsFromUserOverrideModel
}
)
Toggle(
LocalizedStringKey("Always use fixed listing order in candidate window"),
isOn: $selUseFixecCandidateOrderOnSelection
)
.onChange(of: selUseFixecCandidateOrderOnSelection) { value in
mgrPrefs.useFixecCandidateOrderOnSelection = value
isOn: $selUseFixecCandidateOrderOnSelection.onChange {
mgrPrefs.useFixecCandidateOrderOnSelection = selUseFixecCandidateOrderOnSelection
}
)
}
}
}

View File

@ -9,11 +9,8 @@
import Cocoa
import SwiftUI
@available(macOS 11.0, *)
@available(macOS 10.15, *)
struct suiPrefPaneExperience: View {
@State private var selSelectionKeysList = mgrPrefs.suggestedCandidateKeys
@State private var selSelectionKeys =
(UserDefaults.standard.string(forKey: UserDef.kCandidateKeys.rawValue) ?? mgrPrefs.defaultCandidateKeys) as String
@State private var selCursorPosition =
UserDefaults.standard.bool(
forKey: UserDef.kUseRearCursorMode.rawValue) ? 1 : 0
@ -54,40 +51,15 @@ struct suiPrefPaneExperience: View {
var body: some View {
Preferences.Container(contentWidth: contentWidth) {
Preferences.Section(label: { Text(LocalizedStringKey("Selection Keys:")) }) {
ComboBox(items: mgrPrefs.suggestedCandidateKeys, text: $selSelectionKeys).frame(width: 180).onChange(
of: selSelectionKeys
) { value in
let keys: String = value.trimmingCharacters(in: .whitespacesAndNewlines).deduplicate
do {
try mgrPrefs.validate(candidateKeys: keys)
mgrPrefs.candidateKeys = keys
selSelectionKeys = mgrPrefs.candidateKeys
} catch mgrPrefs.CandidateKeyError.empty {
selSelectionKeys = mgrPrefs.candidateKeys
} catch {
if let window = ctlPrefUI.shared.controller.window {
let alert = NSAlert(error: error)
alert.beginSheetModal(for: window) { _ in
selSelectionKeys = mgrPrefs.candidateKeys
}
clsSFX.beep()
}
}
}
Text(
LocalizedStringKey(
"Choose or hit Enter to confim your prefered keys for selecting candidates."
)
)
.preferenceDescription()
}
Preferences.Section(label: { Text(LocalizedStringKey("Cursor Selection:")) }) {
Picker("", selection: $selCursorPosition) {
Picker(
"",
selection: $selCursorPosition.onChange {
mgrPrefs.useRearCursorMode = (selCursorPosition == 1) ? true : false
}
) {
Text(LocalizedStringKey("in front of the phrase (like macOS built-in Zhuyin IME)")).tag(0)
Text(LocalizedStringKey("at the rear of the phrase (like Microsoft New Phonetic)")).tag(1)
}.onChange(of: selCursorPosition) { value in
mgrPrefs.useRearCursorMode = (value == 1) ? true : false
}
.labelsHidden()
.pickerStyle(RadioGroupPickerStyle())
@ -95,17 +67,20 @@ struct suiPrefPaneExperience: View {
.preferenceDescription()
Toggle(
LocalizedStringKey("Push the cursor in front of the phrase after selection"),
isOn: $selPushCursorAfterSelection
).onChange(of: selPushCursorAfterSelection) { value in
mgrPrefs.moveCursorAfterSelectingCandidate = value
}.controlSize(.small)
isOn: $selPushCursorAfterSelection.onChange {
mgrPrefs.moveCursorAfterSelectingCandidate = selPushCursorAfterSelection
}
).controlSize(.small)
}
Preferences.Section(title: "(Shift+)Tab:") {
Picker("", selection: $selKeyBehaviorShiftTab) {
Picker(
"",
selection: $selKeyBehaviorShiftTab.onChange {
mgrPrefs.specifyShiftTabKeyBehavior = (selKeyBehaviorShiftTab == 1) ? true : false
}
) {
Text(LocalizedStringKey("for cycling candidates")).tag(0)
Text(LocalizedStringKey("for cycling pages")).tag(1)
}.onChange(of: selKeyBehaviorShiftTab) { value in
mgrPrefs.specifyShiftTabKeyBehavior = (value == 1) ? true : false
}
.labelsHidden()
.horizontalRadioGroupLayout()
@ -114,11 +89,14 @@ struct suiPrefPaneExperience: View {
.preferenceDescription()
}
Preferences.Section(label: { Text(LocalizedStringKey("(Shift+)Space:")) }) {
Picker("", selection: $selKeyBehaviorShiftSpace) {
Picker(
"",
selection: $selKeyBehaviorShiftSpace.onChange {
mgrPrefs.specifyShiftSpaceKeyBehavior = (selKeyBehaviorShiftSpace == 1) ? true : false
}
) {
Text(LocalizedStringKey("Space to +cycle candidates, Shift+Space to +cycle pages")).tag(0)
Text(LocalizedStringKey("Space to +cycle pages, Shift+Space to +cycle candidates")).tag(1)
}.onChange(of: selKeyBehaviorShiftSpace) { value in
mgrPrefs.specifyShiftSpaceKeyBehavior = (value == 1) ? true : false
}
.labelsHidden()
.pickerStyle(RadioGroupPickerStyle())
@ -126,12 +104,15 @@ struct suiPrefPaneExperience: View {
.preferenceDescription()
}
Preferences.Section(label: { Text(LocalizedStringKey("Shift+Letter:")) }) {
Picker("", selection: $selUpperCaseLetterKeyBehavior) {
Picker(
"",
selection: $selUpperCaseLetterKeyBehavior.onChange {
mgrPrefs.upperCaseLetterKeyBehavior = selUpperCaseLetterKeyBehavior
}
) {
Text(LocalizedStringKey("Type them into inline composition buffer")).tag(0)
Text(LocalizedStringKey("Directly commit lowercased letters")).tag(1)
Text(LocalizedStringKey("Directly commit uppercased letters")).tag(2)
}.onChange(of: selUpperCaseLetterKeyBehavior) { value in
mgrPrefs.upperCaseLetterKeyBehavior = value
}
.labelsHidden()
.pickerStyle(RadioGroupPickerStyle())
@ -141,39 +122,46 @@ struct suiPrefPaneExperience: View {
Preferences.Section(label: { Text(LocalizedStringKey("Misc Settings:")) }) {
Toggle(
LocalizedStringKey("Enable Space key for calling candidate window"),
isOn: $selKeyBehaviorSpaceForCallingCandidate
).onChange(of: selKeyBehaviorSpaceForCallingCandidate) { value in
mgrPrefs.chooseCandidateUsingSpace = value
isOn: $selKeyBehaviorSpaceForCallingCandidate.onChange {
mgrPrefs.chooseCandidateUsingSpace = selKeyBehaviorSpaceForCallingCandidate
}
)
Toggle(
LocalizedStringKey("Use ESC key to clear the entire input buffer"),
isOn: $selKeyBehaviorESCForClearingTheBuffer
).onChange(of: selKeyBehaviorESCForClearingTheBuffer) { value in
mgrPrefs.escToCleanInputBuffer = value
isOn: $selKeyBehaviorESCForClearingTheBuffer.onChange {
mgrPrefs.escToCleanInputBuffer = selKeyBehaviorESCForClearingTheBuffer
}
)
Toggle(
LocalizedStringKey("Automatically correct reading combinations when typing"),
isOn: $selAutoCorrectReadingCombination
).onChange(of: selAutoCorrectReadingCombination) { value in
mgrPrefs.autoCorrectReadingCombination = value
isOn: $selAutoCorrectReadingCombination.onChange {
mgrPrefs.autoCorrectReadingCombination = selAutoCorrectReadingCombination
}
)
Toggle(
LocalizedStringKey("Allow using Enter key to confirm associated candidate selection"),
isOn: $selAlsoConfirmAssociatedCandidatesByEnter
).onChange(of: selAlsoConfirmAssociatedCandidatesByEnter) { value in
mgrPrefs.alsoConfirmAssociatedCandidatesByEnter = value
isOn: $selAlsoConfirmAssociatedCandidatesByEnter.onChange {
mgrPrefs.alsoConfirmAssociatedCandidatesByEnter = selAlsoConfirmAssociatedCandidatesByEnter
}
)
Toggle(
LocalizedStringKey("Also toggle alphanumerical mode with Left-Shift"),
isOn: $selTogglingAlphanumericalModeWithLShift
).onChange(of: selTogglingAlphanumericalModeWithLShift) { value in
mgrPrefs.togglingAlphanumericalModeWithLShift = value
isOn: $selTogglingAlphanumericalModeWithLShift.onChange {
mgrPrefs.togglingAlphanumericalModeWithLShift = selTogglingAlphanumericalModeWithLShift
}
)
Toggle(
LocalizedStringKey("Emulating select-candidate-per-character mode"), isOn: $selEnableSCPCTypingMode
).onChange(of: selEnableSCPCTypingMode) { value in
mgrPrefs.useSCPCTypingMode = value
LocalizedStringKey("Allow backspace-editing miscomposed readings"),
isOn: $selKeepReadingUponCompositionError.onChange {
mgrPrefs.keepReadingUponCompositionError = selKeepReadingUponCompositionError
}
)
Toggle(
LocalizedStringKey("Emulating select-candidate-per-character mode"),
isOn: $selEnableSCPCTypingMode.onChange {
mgrPrefs.useSCPCTypingMode = selEnableSCPCTypingMode
}
)
Text(LocalizedStringKey("An accomodation for elder computer users."))
.preferenceDescription()
}

View File

@ -9,7 +9,7 @@
import Cocoa
import SwiftUI
@available(macOS 11.0, *)
@available(macOS 10.15, *)
struct suiPrefPaneGeneral: View {
@State private var selCandidateUIFontSize = UserDefaults.standard.integer(
forKey: UserDef.kCandidateListTextSize.rawValue)
@ -53,7 +53,12 @@ struct suiPrefPaneGeneral: View {
var body: some View {
Preferences.Container(contentWidth: contentWidth) {
Preferences.Section(bottomDivider: false, label: { Text(LocalizedStringKey("Candidate Size:")) }) {
Picker("", selection: $selCandidateUIFontSize) {
Picker(
"",
selection: $selCandidateUIFontSize.onChange {
mgrPrefs.candidateListTextSize = CGFloat(selCandidateUIFontSize)
}
) {
Text("12").tag(12)
Text("14").tag(14)
Text("16").tag(16)
@ -62,8 +67,6 @@ struct suiPrefPaneGeneral: View {
Text("32").tag(32)
Text("64").tag(64)
Text("96").tag(96)
}.onChange(of: selCandidateUIFontSize) { value in
mgrPrefs.candidateListTextSize = CGFloat(value)
}
.labelsHidden()
.frame(width: 120.0)
@ -71,14 +74,10 @@ struct suiPrefPaneGeneral: View {
.preferenceDescription()
}
Preferences.Section(bottomDivider: false, label: { Text(LocalizedStringKey("UI Language:")) }) {
Picker(LocalizedStringKey("Follow OS settings"), selection: $selUILanguage) {
Text(LocalizedStringKey("Follow OS settings")).tag(["auto"])
Text(LocalizedStringKey("Simplified Chinese")).tag(["zh-Hans"])
Text(LocalizedStringKey("Traditional Chinese")).tag(["zh-Hant"])
Text(LocalizedStringKey("Japanese")).tag(["ja"])
Text(LocalizedStringKey("English")).tag(["en"])
}.onChange(of: selUILanguage) { value in
IME.prtDebugIntel(value[0])
Picker(
LocalizedStringKey("Follow OS settings"),
selection: $selUILanguage.onChange {
IME.prtDebugIntel(selUILanguage[0])
if selUILanguage == mgrPrefs.appleLanguages
|| (selUILanguage[0] == "auto"
&& UserDefaults.standard.object(forKey: UserDef.kAppleLanguages.rawValue) == nil)
@ -86,13 +85,20 @@ struct suiPrefPaneGeneral: View {
return
}
if selUILanguage[0] != "auto" {
mgrPrefs.appleLanguages = value
mgrPrefs.appleLanguages = selUILanguage
} else {
UserDefaults.standard.removeObject(forKey: UserDef.kAppleLanguages.rawValue)
}
NSLog("vChewing App self-terminated due to UI language change.")
NSApplication.shared.terminate(nil)
}
) {
Text(LocalizedStringKey("Follow OS settings")).tag(["auto"])
Text(LocalizedStringKey("Simplified Chinese")).tag(["zh-Hans"])
Text(LocalizedStringKey("Traditional Chinese")).tag(["zh-Hant"])
Text(LocalizedStringKey("Japanese")).tag(["ja"])
Text(LocalizedStringKey("English")).tag(["en"])
}
.labelsHidden()
.frame(width: 180.0)
@ -100,11 +106,14 @@ struct suiPrefPaneGeneral: View {
.preferenceDescription()
}
Preferences.Section(bottomDivider: true, label: { Text(LocalizedStringKey("Candidate Layout:")) }) {
Picker("", selection: $selEnableHorizontalCandidateLayout) {
Picker(
"",
selection: $selEnableHorizontalCandidateLayout.onChange {
mgrPrefs.useHorizontalCandidateList = selEnableHorizontalCandidateLayout
}
) {
Text(LocalizedStringKey("Vertical")).tag(false)
Text(LocalizedStringKey("Horizontal")).tag(true)
}.onChange(of: selEnableHorizontalCandidateLayout) { value in
mgrPrefs.useHorizontalCandidateList = value
}
.labelsHidden()
.horizontalRadioGroupLayout()
@ -112,11 +121,9 @@ struct suiPrefPaneGeneral: View {
Text(LocalizedStringKey("Choose your preferred layout of the candidate window."))
.preferenceDescription()
Toggle(
LocalizedStringKey("Show page buttons in candidate window"), isOn: $selShowPageButtonsInCandidateUI
).onChange(
of: selShowPageButtonsInCandidateUI,
perform: { value in
mgrPrefs.showPageButtonsInCandidateWindow = value
LocalizedStringKey("Show page buttons in candidate window"),
isOn: $selShowPageButtonsInCandidateUI.onChange {
mgrPrefs.showPageButtonsInCandidateWindow = selShowPageButtonsInCandidateUI
}
)
.controlSize(.small)
@ -124,58 +131,59 @@ struct suiPrefPaneGeneral: View {
Preferences.Section(bottomDivider: true, label: { Text(LocalizedStringKey("Output Settings:")) }) {
Toggle(
LocalizedStringKey("Auto-convert traditional Chinese glyphs to KangXi characters"),
isOn: $selEnableKanjiConvToKangXi
).onChange(of: selEnableKanjiConvToKangXi) { value in
mgrPrefs.chineseConversionEnabled = value
selEnableKanjiConvToKangXi = value
if value {
mgrPrefs.shiftJISShinjitaiOutputEnabled = !value
selEnableKanjiConvToJIS = !value
isOn: $selEnableKanjiConvToKangXi.onChange {
mgrPrefs.chineseConversionEnabled = selEnableKanjiConvToKangXi
if selEnableKanjiConvToKangXi {
mgrPrefs.shiftJISShinjitaiOutputEnabled = !selEnableKanjiConvToKangXi
selEnableKanjiConvToJIS = !selEnableKanjiConvToKangXi
}
}
)
Toggle(
LocalizedStringKey("Auto-convert traditional Chinese glyphs to JIS Shinjitai characters"),
isOn: $selEnableKanjiConvToJIS
).onChange(of: selEnableKanjiConvToJIS) { value in
mgrPrefs.shiftJISShinjitaiOutputEnabled = value
selEnableKanjiConvToJIS = value
if value {
mgrPrefs.chineseConversionEnabled = !value
selEnableKanjiConvToKangXi = !value
isOn: $selEnableKanjiConvToJIS.onChange {
mgrPrefs.shiftJISShinjitaiOutputEnabled = selEnableKanjiConvToJIS
if selEnableKanjiConvToJIS {
mgrPrefs.chineseConversionEnabled = !selEnableKanjiConvToJIS
selEnableKanjiConvToKangXi = !selEnableKanjiConvToJIS
}
}
)
Toggle(
LocalizedStringKey("Show Hanyu-Pinyin in the inline composition buffer & tooltip"),
isOn: $selShowHanyuPinyinInCompositionBuffer
).onChange(of: selShowHanyuPinyinInCompositionBuffer) { value in
mgrPrefs.showHanyuPinyinInCompositionBuffer = value
selShowHanyuPinyinInCompositionBuffer = value
isOn: $selShowHanyuPinyinInCompositionBuffer.onChange {
mgrPrefs.showHanyuPinyinInCompositionBuffer = selShowHanyuPinyinInCompositionBuffer
}
)
Toggle(
LocalizedStringKey("Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter"),
isOn: $selInlineDumpPinyinInLieuOfZhuyin
).onChange(of: selInlineDumpPinyinInLieuOfZhuyin) { value in
mgrPrefs.inlineDumpPinyinInLieuOfZhuyin = value
selInlineDumpPinyinInLieuOfZhuyin = value
isOn: $selInlineDumpPinyinInLieuOfZhuyin.onChange {
mgrPrefs.inlineDumpPinyinInLieuOfZhuyin = selInlineDumpPinyinInLieuOfZhuyin
}
)
Toggle(
LocalizedStringKey("Stop farting (when typed phonetic combination is invalid, etc.)"),
isOn: $selEnableFartSuppressor
).onChange(of: selEnableFartSuppressor) { value in
mgrPrefs.shouldNotFartInLieuOfBeep = value
isOn: $selEnableFartSuppressor.onChange {
mgrPrefs.shouldNotFartInLieuOfBeep = selEnableFartSuppressor
clsSFX.beep()
}
)
}
Preferences.Section(label: { Text(LocalizedStringKey("Misc Settings:")).controlSize(.small) }) {
Toggle(LocalizedStringKey("Check for updates automatically"), isOn: $selEnableAutoUpdateCheck)
.onChange(of: selEnableAutoUpdateCheck) { value in
mgrPrefs.checkUpdateAutomatically = value
Toggle(
LocalizedStringKey("Check for updates automatically"),
isOn: $selEnableAutoUpdateCheck.onChange {
mgrPrefs.checkUpdateAutomatically = selEnableAutoUpdateCheck
}
)
.controlSize(.small)
Toggle(LocalizedStringKey("Debug Mode"), isOn: $selEnableDebugMode).controlSize(.small)
.onChange(of: selEnableDebugMode) { value in
mgrPrefs.isDebugModeEnabled = value
Toggle(
LocalizedStringKey("Debug Mode"),
isOn: $selEnableDebugMode.onChange {
mgrPrefs.isDebugModeEnabled = selEnableDebugMode
}
)
.controlSize(.small)
}
}
}

View File

@ -8,8 +8,11 @@
import SwiftUI
@available(macOS 11.0, *)
@available(macOS 10.15, *)
struct suiPrefPaneKeyboard: View {
@State private var selSelectionKeysList = mgrPrefs.suggestedCandidateKeys
@State private var selSelectionKeys =
UserDefaults.standard.string(forKey: UserDef.kCandidateKeys.rawValue) ?? mgrPrefs.defaultCandidateKeys
@State private var selMandarinParser = UserDefaults.standard.integer(forKey: UserDef.kMandarinParser.rawValue)
@State private var selBasicKeyboardLayout: String =
UserDefaults.standard.string(forKey: UserDef.kBasicKeyboardLayout.rawValue) ?? mgrPrefs.basicKeyboardLayout
@ -40,9 +43,57 @@ struct suiPrefPaneKeyboard: View {
var body: some View {
Preferences.Container(contentWidth: contentWidth) {
Preferences.Section(label: { Text(LocalizedStringKey("Selection Keys:")) }) {
ComboBox(
items: mgrPrefs.suggestedCandidateKeys,
text: $selSelectionKeys.onChange {
let value = selSelectionKeys
let keys: String = value.trimmingCharacters(in: .whitespacesAndNewlines).deduplicate
do {
try mgrPrefs.validate(candidateKeys: keys)
mgrPrefs.candidateKeys = keys
selSelectionKeys = mgrPrefs.candidateKeys
} catch mgrPrefs.CandidateKeyError.empty {
selSelectionKeys = mgrPrefs.candidateKeys
} catch {
if let window = ctlPrefUI.shared.controller.window {
let alert = NSAlert(error: error)
alert.beginSheetModal(for: window) { _ in
selSelectionKeys = mgrPrefs.candidateKeys
}
clsSFX.beep()
}
}
}
).frame(width: 180)
Text(
LocalizedStringKey(
"Choose or hit Enter to confim your prefered keys for selecting candidates."
)
)
.preferenceDescription()
}
Preferences.Section(label: { Text(LocalizedStringKey("Phonetic Parser:")) }) {
HStack {
Picker("", selection: $selMandarinParser) {
Picker(
"",
selection: $selMandarinParser.onChange {
let value = selMandarinParser
mgrPrefs.mandarinParser = value
switch value {
case 0:
if !AppleKeyboardConverter.arrDynamicBasicKeyLayout.contains(mgrPrefs.basicKeyboardLayout) {
mgrPrefs.basicKeyboardLayout = "com.apple.keylayout.ZhuyinBopomofo"
selBasicKeyboardLayout = mgrPrefs.basicKeyboardLayout
}
default:
if AppleKeyboardConverter.arrDynamicBasicKeyLayout.contains(mgrPrefs.basicKeyboardLayout) {
mgrPrefs.basicKeyboardLayout = "com.apple.keylayout.ABC"
selBasicKeyboardLayout = mgrPrefs.basicKeyboardLayout
}
}
}
) {
Group {
Text(LocalizedStringKey("Dachen (Microsoft Standard / Wang / 01, etc.)")).tag(0)
Text(LocalizedStringKey("Eten Traditional")).tag(1)
@ -66,20 +117,6 @@ struct suiPrefPaneKeyboard: View {
Text(LocalizedStringKey("Hualuo Pinyin with Numeral Intonation")).tag(13)
Text(LocalizedStringKey("Universal Pinyin with Numeral Intonation")).tag(14)
}
}.onChange(of: selMandarinParser) { value in
mgrPrefs.mandarinParser = value
switch value {
case 0:
if !AppleKeyboardConverter.arrDynamicBasicKeyLayout.contains(mgrPrefs.basicKeyboardLayout) {
mgrPrefs.basicKeyboardLayout = "com.apple.keylayout.ZhuyinBopomofo"
selBasicKeyboardLayout = mgrPrefs.basicKeyboardLayout
}
default:
if AppleKeyboardConverter.arrDynamicBasicKeyLayout.contains(mgrPrefs.basicKeyboardLayout) {
mgrPrefs.basicKeyboardLayout = "com.apple.keylayout.ABC"
selBasicKeyboardLayout = mgrPrefs.basicKeyboardLayout
}
}
}
.labelsHidden()
Button {
@ -105,18 +142,22 @@ struct suiPrefPaneKeyboard: View {
}
Preferences.Section(bottomDivider: true, label: { Text(LocalizedStringKey("Basic Keyboard Layout:")) }) {
HStack {
Picker("", selection: $selBasicKeyboardLayout) {
ForEach(0...(IME.arrEnumerateSystemKeyboardLayouts.count - 1), id: \.self) { id in
Text(IME.arrEnumerateSystemKeyboardLayouts[id].strName).tag(
IME.arrEnumerateSystemKeyboardLayouts[id].strValue)
}.id(UUID())
}.onChange(of: selBasicKeyboardLayout) { value in
Picker(
"",
selection: $selBasicKeyboardLayout.onChange {
let value = selBasicKeyboardLayout
mgrPrefs.basicKeyboardLayout = value
if AppleKeyboardConverter.arrDynamicBasicKeyLayout.contains(value) {
mgrPrefs.mandarinParser = 0
selMandarinParser = mgrPrefs.mandarinParser
}
}
) {
ForEach(0...(IME.arrEnumerateSystemKeyboardLayouts.count - 1), id: \.self) { id in
Text(IME.arrEnumerateSystemKeyboardLayouts[id].strName).tag(
IME.arrEnumerateSystemKeyboardLayouts[id].strValue)
}.id(UUID())
}
.labelsHidden()
.frame(width: 240.0)
}
@ -126,53 +167,46 @@ struct suiPrefPaneKeyboard: View {
Preferences.Section(bottomDivider: true, label: { Text(LocalizedStringKey("Keyboard Shortcuts:")) }) {
Toggle(
LocalizedStringKey("Per-Char Select Mode"),
isOn: $selUsingHotKeySCPC
).onChange(of: selUsingHotKeySCPC) { value in
mgrPrefs.usingHotKeySCPC = value
selUsingHotKeySCPC = value
isOn: $selUsingHotKeySCPC.onChange {
mgrPrefs.usingHotKeySCPC = selUsingHotKeySCPC
}
)
Toggle(
LocalizedStringKey("Per-Char Associated Phrases"),
isOn: $selUsingHotKeyAssociates
).onChange(of: selUsingHotKeyAssociates) { value in
mgrPrefs.usingHotKeyAssociates = value
selUsingHotKeyAssociates = value
isOn: $selUsingHotKeyAssociates.onChange {
mgrPrefs.usingHotKeyAssociates = selUsingHotKeyAssociates
}
)
Toggle(
LocalizedStringKey("CNS11643 Mode"),
isOn: $selUsingHotKeyCNS
).onChange(of: selUsingHotKeyCNS) { value in
mgrPrefs.usingHotKeyCNS = value
selUsingHotKeyCNS = value
isOn: $selUsingHotKeyCNS.onChange {
mgrPrefs.usingHotKeyCNS = selUsingHotKeyCNS
}
)
Toggle(
LocalizedStringKey("Force KangXi Writing"),
isOn: $selUsingHotKeyKangXi
).onChange(of: selUsingHotKeyKangXi) { value in
mgrPrefs.usingHotKeyKangXi = value
selUsingHotKeyKangXi = value
isOn: $selUsingHotKeyKangXi.onChange {
mgrPrefs.usingHotKeyKangXi = selUsingHotKeyKangXi
}
)
Toggle(
LocalizedStringKey("JIS Shinjitai Output"),
isOn: $selUsingHotKeyJIS
).onChange(of: selUsingHotKeyJIS) { value in
mgrPrefs.usingHotKeyJIS = value
selUsingHotKeyJIS = value
isOn: $selUsingHotKeyJIS.onChange {
mgrPrefs.usingHotKeyJIS = selUsingHotKeyJIS
}
)
Toggle(
LocalizedStringKey("Half-Width Punctuation Mode"),
isOn: $selUsingHotKeyHalfWidthASCII
).onChange(of: selUsingHotKeyHalfWidthASCII) { value in
mgrPrefs.usingHotKeyHalfWidthASCII = value
selUsingHotKeyHalfWidthASCII = value
isOn: $selUsingHotKeyHalfWidthASCII.onChange {
mgrPrefs.usingHotKeyHalfWidthASCII = selUsingHotKeyHalfWidthASCII
}
)
Toggle(
LocalizedStringKey("Currency Numeral Output"),
isOn: $selUsingHotKeyCurrencyNumerals
).onChange(of: selUsingHotKeyCurrencyNumerals) { value in
mgrPrefs.usingHotKeyCurrencyNumerals = value
selUsingHotKeyCurrencyNumerals = value
isOn: $selUsingHotKeyCurrencyNumerals.onChange {
mgrPrefs.usingHotKeyCurrencyNumerals = selUsingHotKeyCurrencyNumerals
}
)
}
}
Divider()
@ -181,7 +215,7 @@ struct suiPrefPaneKeyboard: View {
VStack(alignment: .leading, spacing: 10) {
Text(
LocalizedStringKey(
"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only."
"Non-QWERTY alphanumerical keyboard layouts are for Hanyu Pinyin parser only."
)
)
.preferenceDescription()

View File

@ -375,7 +375,7 @@ extension ctlPrefWindow: NSToolbarDelegate {
systemSymbolName: "wrench.and.screwdriver.fill", accessibilityDescription: "General Preferences"
)
} else {
item.image = NSImage(named: NSImage.homeTemplateName)
item.image = NSImage(named: "PrefToolbar-General")
}
item.action = #selector(showGeneralView(_:))
@ -387,7 +387,7 @@ extension ctlPrefWindow: NSToolbarDelegate {
systemSymbolName: "person.fill.questionmark", accessibilityDescription: "Experiences Preferences"
)
} else {
item.image = NSImage(named: NSImage.flowViewTemplateName)
item.image = NSImage(named: "PrefToolbar-Experiences")
}
item.action = #selector(showExperienceView(_:))
@ -399,7 +399,7 @@ extension ctlPrefWindow: NSToolbarDelegate {
systemSymbolName: "character.book.closed.fill", accessibilityDescription: "Dictionary Preferences"
)
} else {
item.image = NSImage(named: NSImage.bookmarksTemplateName)
item.image = NSImage(named: "PrefToolbar-Dictionary")
}
item.action = #selector(showDictionaryView(_:))
@ -409,7 +409,7 @@ extension ctlPrefWindow: NSToolbarDelegate {
if #available(macOS 11.0, *) {
item.image = NSImage(systemSymbolName: "keyboard.macwindow", accessibilityDescription: "Keyboard Preferences")
} else {
item.image = NSImage(named: NSImage.slideshowTemplateName)
item.image = NSImage(named: "PrefToolbar-Keyboard")
}
item.action = #selector(showKeyboardView(_:))

View File

@ -410,7 +410,7 @@
</column>
</cells>
<connections>
<binding destination="32" name="selectedTag" keyPath="values.SelectPhraseAfterCursorAsCandidate" id="104"/>
<binding destination="32" name="selectedTag" keyPath="values.UseRearCursorMode" id="8rm-vc-0Db"/>
</connections>
</matrix>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="7z2-DD-c58">

View File

@ -3,9 +3,9 @@
<plist version="1.0">
<dict>
<key>CFBundleShortVersionString</key>
<string>1.9.0</string>
<string>1.9.1</string>
<key>CFBundleVersion</key>
<string>1990</string>
<string>1991</string>
<key>UpdateInfoEndpoint</key>
<string>https://gitee.com/vchewing/vChewing-macOS/raw/main/Update-Info.plist</string>
<key>UpdateInfoSite</key>

View File

@ -726,7 +726,7 @@
<key>USE_HFS+_COMPRESSION</key>
<false/>
<key>VERSION</key>
<string>1.9.0</string>
<string>1.9.1</string>
</dict>
<key>TYPE</key>
<integer>0</integer>

View File

@ -117,6 +117,7 @@
5BF9DA2A28840E6200DBD48E /* template-replacements.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2528840E6200DBD48E /* template-replacements.txt */; };
5BF9DA2B28840E6200DBD48E /* template-userphrases.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2628840E6200DBD48E /* template-userphrases.txt */; };
5BF9DA2D288427E000DBD48E /* template-associatedPhrases-cht.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2C2884247800DBD48E /* template-associatedPhrases-cht.txt */; };
5BF9EC1628A2BFC600333639 /* lmPlainBopomofo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BF9EC1528A2BFC600333639 /* lmPlainBopomofo.swift */; };
5BFDF011289635C100417BBC /* ctlCandidateIMK.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BFDF010289635C100417BBC /* ctlCandidateIMK.swift */; };
6A187E2616004C5900466B2E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6A187E2816004C5900466B2E /* MainMenu.xib */; };
6A225A1F23679F2600F685C6 /* NotarizedArchives in Resources */ = {isa = PBXBuildFile; fileRef = 6A225A1E23679F2600F685C6 /* NotarizedArchives */; };
@ -333,6 +334,7 @@
5BF9DA2528840E6200DBD48E /* template-replacements.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = "template-replacements.txt"; sourceTree = "<group>"; usesTabs = 0; };
5BF9DA2628840E6200DBD48E /* template-userphrases.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = "template-userphrases.txt"; sourceTree = "<group>"; usesTabs = 0; };
5BF9DA2C2884247800DBD48E /* template-associatedPhrases-cht.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; name = "template-associatedPhrases-cht.txt"; path = "../Data/components/cht/template-associatedPhrases-cht.txt"; sourceTree = "<group>"; };
5BF9EC1528A2BFC600333639 /* lmPlainBopomofo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = lmPlainBopomofo.swift; sourceTree = "<group>"; };
5BFDF010289635C100417BBC /* ctlCandidateIMK.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlCandidateIMK.swift; sourceTree = "<group>"; };
5BFDF48C27B51867009523B6 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Main.strings"; sourceTree = "<group>"; };
6A0D4EA215FC0D2D00ABF4B3 /* vChewing.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = vChewing.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -432,6 +434,7 @@
5B407309281672610023DFFF /* lmAssociates.swift */,
5B887F2F2826AEA400B6651E /* lmCoreEX.swift */,
5B54E742283A7D89001ECBDC /* lmCoreNS.swift */,
5BF9EC1528A2BFC600333639 /* lmPlainBopomofo.swift */,
5B40730A281672610023DFFF /* lmReplacements.swift */,
5BA0DF2E2817857D009E73BB /* lmUserOverride.swift */,
);
@ -1177,6 +1180,7 @@
5BA9FD1027FEDB6B002DE248 /* suiPrefPaneKeyboard.swift in Sources */,
5B3133BF280B229700A4A505 /* KeyHandler_States.swift in Sources */,
5B2170E1289FACAD00BE7304 /* 0_Megrez.swift in Sources */,
5BF9EC1628A2BFC600333639 /* lmPlainBopomofo.swift in Sources */,
5B3A87BC28597CDB0090E163 /* LMSymbolNode.swift in Sources */,
5BA9FD4327FEF3C8002DE248 /* Preferences.swift in Sources */,
5BA9FD4427FEF3C8002DE248 /* SegmentedControlStyleViewController.swift in Sources */,
@ -1409,7 +1413,7 @@
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1990;
CURRENT_PROJECT_VERSION = 1991;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
@ -1419,7 +1423,7 @@
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.9.0;
MARKETING_VERSION = 1.9.1;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewingTests;
@ -1448,13 +1452,13 @@
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1990;
CURRENT_PROJECT_VERSION = 1991;
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 = 1.9.0;
MARKETING_VERSION = 1.9.1;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewingTests;
@ -1485,7 +1489,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1990;
CURRENT_PROJECT_VERSION = 1991;
DEAD_CODE_STRIPPING = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
@ -1506,7 +1510,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 1.9.0;
MARKETING_VERSION = 1.9.1;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
@ -1535,7 +1539,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1990;
CURRENT_PROJECT_VERSION = 1991;
DEAD_CODE_STRIPPING = YES;
ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
@ -1552,7 +1556,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 1.9.0;
MARKETING_VERSION = 1.9.1;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
@ -1666,7 +1670,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1990;
CURRENT_PROJECT_VERSION = 1991;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
@ -1694,7 +1698,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 1.9.0;
MARKETING_VERSION = 1.9.1;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -1721,7 +1725,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1990;
CURRENT_PROJECT_VERSION = 1991;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
@ -1743,7 +1747,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 1.9.0;
MARKETING_VERSION = 1.9.1;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -1765,7 +1769,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1990;
CURRENT_PROJECT_VERSION = 1991;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
@ -1785,7 +1789,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 1.9.0;
MARKETING_VERSION = 1.9.1;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
@ -1807,7 +1811,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1990;
CURRENT_PROJECT_VERSION = 1991;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
@ -1821,7 +1825,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 1.9.0;
MARKETING_VERSION = 1.9.1;
PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";