From 03d40998944e44ad1a797b371b87341f0d3dc2d6 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 21 Sep 2022 10:28:39 +0800 Subject: [PATCH] KeyHandler // Use PrefMgrProtocol delegate to handle UserDefaults. --- Packages/vChewing_Tekkon/README.md | 4 +- Source/Modules/AppDelegate.swift | 10 +-- Source/Modules/ChineseConverterBridge.swift | 6 +- Source/Modules/IMEState.swift | 2 +- Source/Modules/IMEStateData.swift | 10 +-- Source/Modules/KeyHandler_Core.swift | 34 +++++---- .../Modules/KeyHandler_HandleCandidate.swift | 10 +-- .../KeyHandler_HandleComposition.swift | 10 +-- Source/Modules/KeyHandler_HandleInput.swift | 8 +- Source/Modules/KeyHandler_States.swift | 14 ++-- Source/Modules/LMMgr.swift | 10 +-- Source/Modules/PrefMgr.swift | 4 +- .../CandidateUI/ctlCandidateIMK.swift | 16 ++-- .../CandidateUI/ctlCandidateUniversal.swift | 8 +- .../UIModules/PrefUI/suiPrefPaneDevZone.swift | 11 +-- .../PrefUI/suiPrefPaneDictionary.swift | 30 ++++---- .../PrefUI/suiPrefPaneExperience.swift | 40 +++++----- .../UIModules/PrefUI/suiPrefPaneGeneral.swift | 34 ++++----- .../PrefUI/suiPrefPaneKeyboard.swift | 74 +++++++++---------- .../WindowControllers/ctlClientListMgr.swift | 26 +++---- .../WindowControllers/ctlPrefWindow.swift | 32 ++++---- Source/Modules/ctlInputMethod_Core.swift | 38 +++++----- Source/Modules/ctlInputMethod_Delegates.swift | 8 +- .../ctlInputMethod_HandleDisplay.swift | 22 +++--- .../Modules/ctlInputMethod_HandleStates.swift | 2 +- Source/Modules/ctlInputMethod_Menu.swift | 59 ++++++++------- Source/Modules/main.swift | 4 +- 27 files changed, 266 insertions(+), 260 deletions(-) diff --git a/Packages/vChewing_Tekkon/README.md b/Packages/vChewing_Tekkon/README.md index 767e5d72..c5727822 100644 --- a/Packages/vChewing_Tekkon/README.md +++ b/Packages/vChewing_Tekkon/README.md @@ -55,7 +55,7 @@ class ctlInputMethod: IMKInputController { // MARK: - Extracted methods and functions (Tekkon). func ensureParser() { - switch mgrPrefs.mandarinParser { + switch PrefMgr.shared.mandarinParser { case MandarinParser.ofStandard.rawValue: _composer.ensureParser(arrange: .ofDachen) // 大千 case MandarinParser.ofETen.rawValue: @@ -82,7 +82,7 @@ class ctlInputMethod: IMKInputController { _composer.ensureParser(arrange: .ofUniversalPinyin) // 通用拼音 default: _composer.ensureParser(arrange: .ofDachen) // 預設情況下按照 PrefMgr 內定義預設值來處理 - mgrPrefs.mandarinParser = MandarinParser.ofStandard.rawValue + PrefMgr.shared.mandarinParser = MandarinParser.ofStandard.rawValue } _composer.clear() } diff --git a/Source/Modules/AppDelegate.swift b/Source/Modules/AppDelegate.swift index da334923..447ffd26 100644 --- a/Source/Modules/AppDelegate.swift +++ b/Source/Modules/AppDelegate.swift @@ -17,7 +17,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele private func reloadOnFolderChangeHappens() { // 拖 100ms 再重載,畢竟有些有特殊需求的使用者可能會想使用巨型自訂語彙檔案。 DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) { - if mgrPrefs.shouldAutoReloadUserDataFiles { + if PrefMgr.shared.shouldAutoReloadUserDataFiles { LMMgr.initUserLangModels() } } @@ -39,10 +39,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele func applicationDidFinishLaunching(_: Notification) { NSUserNotificationCenter.default.delegate = self // 一旦發現與使用者半衰模組的觀察行為有關的崩潰標記被開啟,就清空既有的半衰記憶資料檔案。 - if mgrPrefs.failureFlagForUOMObservation { + if PrefMgr.shared.failureFlagForUOMObservation { LMMgr.clearUserOverrideModelData(.imeModeCHS) LMMgr.clearUserOverrideModelData(.imeModeCHT) - mgrPrefs.failureFlagForUOMObservation = false + PrefMgr.shared.failureFlagForUOMObservation = false let userNotification = NSUserNotification() userNotification.title = NSLocalizedString("vChewing", comment: "") userNotification.informativeText = @@ -61,7 +61,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele } } - mgrPrefs.fixOddPreferences() + PrefMgr.shared.fixOddPreferences() // 配置更新小助手 updateSputnik.varkUpdateInfoPageURLKey = "UpdateInfoSite" @@ -71,7 +71,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele updateSputnik.varCheckUpdateAutomatically = "ChecvarkUpdateAutomatically" // 只要使用者沒有勾選檢查更新、沒有主動做出要檢查更新的操作,就不要檢查更新。 - if mgrPrefs.checkUpdateAutomatically { + if PrefMgr.shared.checkUpdateAutomatically { updateSputnik.checkForUpdate(forced: false, url: kUpdateInfoSourceURL) } } diff --git a/Source/Modules/ChineseConverterBridge.swift b/Source/Modules/ChineseConverterBridge.swift index 8255f6a7..751dc93d 100644 --- a/Source/Modules/ChineseConverterBridge.swift +++ b/Source/Modules/ChineseConverterBridge.swift @@ -54,14 +54,14 @@ public enum ChineseConverter { /// 將指定字串內的小寫漢字數字轉換為大寫,會對轉換對象進行直接修改操作。 /// - Parameter target: 轉換對象。 public static func ensureCurrencyNumerals(target: inout String) { - if !mgrPrefs.currencyNumeralsEnabled { return } + if !PrefMgr.shared.currencyNumeralsEnabled { return } for key in currencyNumeralDictTable.keys { guard let result = currencyNumeralDictTable[key] else { continue } if IMEApp.currentInputMode == InputMode.imeModeCHS { target = target.replacingOccurrences(of: key, with: result.3) // Simplified Chinese continue } - switch (mgrPrefs.chineseConversionEnabled, mgrPrefs.shiftJISShinjitaiOutputEnabled) { + switch (PrefMgr.shared.chineseConversionEnabled, PrefMgr.shared.shiftJISShinjitaiOutputEnabled) { case (false, true), (true, true): target = target.replacingOccurrences(of: key, with: result.2) // JIS case (true, false): target = target.replacingOccurrences(of: key, with: result.0) // KangXi default: target = target.replacingOccurrences(of: key, with: result.1) // Contemporary @@ -98,7 +98,7 @@ public enum ChineseConverter { static func kanjiConversionIfRequired(_ text: String) -> String { guard IMEApp.currentInputMode == InputMode.imeModeCHT else { return text } - switch (mgrPrefs.chineseConversionEnabled, mgrPrefs.shiftJISShinjitaiOutputEnabled) { + switch (PrefMgr.shared.chineseConversionEnabled, PrefMgr.shared.shiftJISShinjitaiOutputEnabled) { case (false, true): return ChineseConverter.cnvTradToJIS(text) case (true, false): return ChineseConverter.cnvTradToKangXi(text) // 本來這兩個開關不該同時開啟的,但萬一被同時開啟了的話就這樣處理: diff --git a/Source/Modules/IMEState.swift b/Source/Modules/IMEState.swift index f77784eb..aee24f70 100644 --- a/Source/Modules/IMEState.swift +++ b/Source/Modules/IMEState.swift @@ -121,7 +121,7 @@ extension IMEState { // 注意資料的設定順序,一定得先設定 displayTextSegments。 result.data.displayTextSegments = displayTextSegments.map { if !ctlInputMethod.isVerticalTyping { return $0 } - guard mgrPrefs.hardenVerticalPunctuations else { return $0 } + guard PrefMgr.shared.hardenVerticalPunctuations else { return $0 } var neta = $0 ChineseConverter.hardenVerticalPunctuations(target: &neta, convert: ctlInputMethod.isVerticalTyping) return neta diff --git a/Source/Modules/IMEStateData.swift b/Source/Modules/IMEStateData.swift index 33000465..08abfbbf 100644 --- a/Source/Modules/IMEStateData.swift +++ b/Source/Modules/IMEStateData.swift @@ -10,11 +10,11 @@ import Tekkon public struct StateData { private static var minCandidateLength: Int { - mgrPrefs.allowBoostingSingleKanjiAsUserPhrase ? 1 : 2 + PrefMgr.shared.allowBoostingSingleKanjiAsUserPhrase ? 1 : 2 } static var allowedMarkLengthRange: ClosedRange { - Self.minCandidateLength...mgrPrefs.maxCandidateLength + Self.minCandidateLength...PrefMgr.shared.maxCandidateLength } var displayedText: String = "" @@ -177,8 +177,8 @@ extension StateData { arrOutput.append("??") continue } - if mgrPrefs.showHanyuPinyinInCompositionBuffer, - mgrPrefs.alwaysShowTooltipTextsHorizontally || !isVerticalTyping + if PrefMgr.shared.showHanyuPinyinInCompositionBuffer, + PrefMgr.shared.alwaysShowTooltipTextsHorizontally || !isVerticalTyping { // 恢復陰平標記->注音轉拼音->轉教科書式標調 neta = Tekkon.restoreToneOneInZhuyinKey(target: neta) @@ -215,7 +215,7 @@ extension StateData { mutating func updateTooltipForMarking() { var tooltipForMarking: String { let pair = userPhraseKVPair - if mgrPrefs.phraseReplacementEnabled { + if PrefMgr.shared.phraseReplacementEnabled { tooltipColorState = .warning return NSLocalizedString( "⚠︎ Phrase replacement mode enabled, interfering user phrase entry.", comment: "" diff --git a/Source/Modules/KeyHandler_Core.swift b/Source/Modules/KeyHandler_Core.swift index c0e3c709..a0c44473 100644 --- a/Source/Modules/KeyHandler_Core.swift +++ b/Source/Modules/KeyHandler_Core.swift @@ -32,6 +32,7 @@ public protocol KeyHandlerDelegate { public class KeyHandler { /// 委任物件 (ctlInputMethod),以便呼叫其中的函式。 public var delegate: KeyHandlerDelegate? + public var prefs: PrefMgrProtocol /// 半衰模組的衰減指數 let kEpsilon: Double = 0.000_001 @@ -47,11 +48,12 @@ public class KeyHandler { } /// 初期化。 - public init(lm: vChewingLM.LMInstantiator, uom: vChewingLM.LMUserOverride) { + public init(lm: vChewingLM.LMInstantiator, uom: vChewingLM.LMUserOverride, pref: PrefMgrProtocol) { + prefs = pref currentLM = lm currentUOM = uom /// 同步組字器單個詞的幅位長度上限。 - Megrez.Compositor.maxSpanLength = mgrPrefs.maxCandidateLength + Megrez.Compositor.maxSpanLength = prefs.maxCandidateLength /// 組字器初期化。因為是首次初期化變數,所以這裡不能用 ensureCompositor() 代勞。 compositor = Megrez.Compositor(with: currentLM, separator: "-") /// 注拼槽初期化。 @@ -85,7 +87,7 @@ public class KeyHandler { /// 威注音對游標前置與游標後置模式採取的候選字節點陣列抓取方法是分離的,且不使用 Node Crossing。 var actualCandidateCursor: Int { compositor.cursor - - ((compositor.cursor == compositor.width || !mgrPrefs.useRearCursorMode) && compositor.cursor > 0 ? 1 : 0) + - ((compositor.cursor == compositor.width || !prefs.useRearCursorMode) && compositor.cursor > 0 ? 1 : 0) } /// 利用給定的讀音鏈來試圖爬取最接近的組字結果(最大相似度估算)。 @@ -97,7 +99,7 @@ public class KeyHandler { compositor.walk() // 在偵錯模式開啟時,將 GraphViz 資料寫入至指定位置。 - if mgrPrefs.isDebugModeEnabled { + if prefs.isDebugModeEnabled { let result = compositor.dumpDOT let thePath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0].path.appending( "/vChewing-visualization.dot") @@ -222,12 +224,12 @@ public class KeyHandler { let currentNode = currentWalk.findNode(at: actualCandidateCursor, target: &accumulatedCursor) guard let currentNode = currentNode else { return } - if currentNode.currentUnigram.score > -12, mgrPrefs.fetchSuggestionsFromUserOverrideModel { + if currentNode.currentUnigram.score > -12, prefs.fetchSuggestionsFromUserOverrideModel { vCLog("UOM: Start Observation.") // 這個過程可能會因為使用者半衰記憶模組內部資料錯亂、而導致輸入法在選字時崩潰。 // 於是在這裡引入災後狀況察覺專用變數,且先開啟該開關。順利執行完觀察後會關閉。 // 一旦輸入法崩潰,會在重啟時發現這個開關是開著的,屆時 AppDelegate 會做出應對。 - mgrPrefs.failureFlagForUOMObservation = true + prefs.failureFlagForUOMObservation = true // 令半衰記憶模組觀測給定的三元圖。 // 這個過程會讓半衰引擎根據當前上下文生成三元圖索引鍵。 currentUOM.performObservation( @@ -235,11 +237,11 @@ public class KeyHandler { timestamp: Date().timeIntervalSince1970, saveCallback: { self.currentUOM.saveData() } ) // 如果沒有出現崩框的話,那就將這個開關復位。 - mgrPrefs.failureFlagForUOMObservation = false + prefs.failureFlagForUOMObservation = false } /// 若偏好設定內啟用了相關選項,則會在選字之後始終將游標推送至選字後的節錨的前方。 - if mgrPrefs.moveCursorAfterSelectingCandidate, respectCursorPushing { + if prefs.moveCursorAfterSelectingCandidate, respectCursorPushing { // compositor.cursor = accumulatedCursor compositor.jumpCursorBySpan(to: .front) } @@ -250,7 +252,7 @@ public class KeyHandler { /// 警告:不要對游標前置風格使用 nodesCrossing,否則會導致游標行為與 macOS 內建注音輸入法不一致。 /// 微軟新注音輸入法的游標後置風格也是不允許 nodeCrossing 的。 var arrCandidates: [Megrez.Compositor.KeyValuePaired] = { - switch mgrPrefs.useRearCursorMode { + switch prefs.useRearCursorMode { case false: return compositor.fetchCandidates(at: actualCandidateCursor, filter: .endAt) case true: @@ -264,7 +266,7 @@ public class KeyHandler { if arrCandidates.isEmpty { return .init() } // 決定是否根據半衰記憶模組的建議來調整候選字詞的順序。 - if !mgrPrefs.fetchSuggestionsFromUserOverrideModel || mgrPrefs.useSCPCTypingMode || fixOrder { + if !prefs.fetchSuggestionsFromUserOverrideModel || prefs.useSCPCTypingMode || fixOrder { return arrCandidates.map { ($0.key, $0.value) } } @@ -282,9 +284,9 @@ public class KeyHandler { @discardableResult func fetchSuggestionsFromUOM(apply: Bool) -> [(String, Megrez.Unigram)] { var arrResult = [(String, Megrez.Unigram)]() /// 如果逐字選字模式有啟用的話,直接放棄執行這個函式。 - if mgrPrefs.useSCPCTypingMode { return arrResult } + if prefs.useSCPCTypingMode { return arrResult } /// 如果這個開關沒打開的話,直接放棄執行這個函式。 - if !mgrPrefs.fetchSuggestionsFromUserOverrideModel { return arrResult } + if !prefs.fetchSuggestionsFromUserOverrideModel { return arrResult } /// 獲取來自半衰記憶模組的建議結果 let suggestion = currentUOM.fetchSuggestion( currentWalk: compositor.walkedNodes, cursor: actualCandidateCursor, timestamp: Date().timeIntervalSince1970 @@ -320,7 +322,7 @@ public class KeyHandler { } var currentKeyboardParserType: KeyboardParser { - .init(rawValue: mgrPrefs.keyboardParser) ?? .ofStandard + .init(rawValue: prefs.keyboardParser) ?? .ofStandard } /// 給注拼槽指定注音排列或拼音輸入種類之後,將注拼槽內容清空。 @@ -358,7 +360,7 @@ public class KeyHandler { composer.ensureParser(arrange: .ofUniversalPinyin) } composer.clear() - composer.phonabetCombinationCorrectionEnabled = mgrPrefs.autoCorrectReadingCombination + composer.phonabetCombinationCorrectionEnabled = prefs.autoCorrectReadingCombination } /// 返回前一個游標位置的可解析的漢字讀音。 @@ -394,7 +396,7 @@ public class KeyHandler { /// - Parameter input: 輸入的按鍵訊號。 /// - Returns: 生成的標點符號索引鍵。 func generatePunctuationNamePrefix(withKeyCondition input: InputSignalProtocol) -> String { - if mgrPrefs.halfWidthPunctuationEnabled { + if prefs.halfWidthPunctuationEnabled { return "_half_punctuation_" } switch (input.isControlHold, input.isOptionHold) { @@ -423,7 +425,7 @@ extension KeyHandler { guard !compositor.walkedNodes.isEmpty, compositor.width > compositorWidthLimit, let identifier = delegate?.clientBundleIdentifier, - mgrPrefs.clientsIMKTextInputIncapable.contains(identifier) + prefs.clientsIMKTextInputIncapable.contains(identifier) else { return "" } diff --git a/Source/Modules/KeyHandler_HandleCandidate.swift b/Source/Modules/KeyHandler_HandleCandidate.swift index 05907489..86671c68 100644 --- a/Source/Modules/KeyHandler_HandleCandidate.swift +++ b/Source/Modules/KeyHandler_HandleCandidate.swift @@ -39,7 +39,7 @@ extension KeyHandler { if cancelCandidateKey { if state.type == .ofAssociates - || mgrPrefs.useSCPCTypingMode + || prefs.useSCPCTypingMode || compositor.isEmpty { // 如果此時發現當前組字緩衝區為真空的情況的話, @@ -59,7 +59,7 @@ extension KeyHandler { // MARK: Enter if input.isEnter { - if state.type == .ofAssociates, !mgrPrefs.alsoConfirmAssociatedCandidatesByEnter { + if state.type == .ofAssociates, !prefs.alsoConfirmAssociatedCandidatesByEnter { stateCallback(IMEState.ofAbortion()) return true } @@ -71,7 +71,7 @@ extension KeyHandler { if input.isTab { let updated: Bool = - mgrPrefs.specifyShiftTabKeyBehavior + prefs.specifyShiftTabKeyBehavior ? (input.isShiftHold ? ctlCandidate.showPreviousPage() : ctlCandidate.showNextPage()) @@ -88,7 +88,7 @@ extension KeyHandler { if input.isSpace { let updated: Bool = - mgrPrefs.specifyShiftSpaceKeyBehavior + prefs.specifyShiftSpaceKeyBehavior ? (input.isShiftHold ? ctlCandidate.highlightNextCandidate() : ctlCandidate.showNextPage()) @@ -242,7 +242,7 @@ extension KeyHandler { // MARK: 逐字選字模式的處理 (SCPC Mode Processing) - if mgrPrefs.useSCPCTypingMode { + if prefs.useSCPCTypingMode { /// 檢查: /// - 是否是針對當前注音排列/拼音輸入種類專門提供的標點符號。 /// - 是否是需要摁修飾鍵才可以輸入的那種標點符號。 diff --git a/Source/Modules/KeyHandler_HandleComposition.swift b/Source/Modules/KeyHandler_HandleComposition.swift index ddf29097..c48af66a 100644 --- a/Source/Modules/KeyHandler_HandleComposition.swift +++ b/Source/Modules/KeyHandler_HandleComposition.swift @@ -36,7 +36,7 @@ extension KeyHandler { if !skipPhoneticHandling && composer.inputValidityCheck(key: input.charCode) { // 引入 macOS 內建注音輸入法的行為,允許用除了陰平以外的聲調鍵覆寫前一個漢字的讀音。 // 但如果要覆寫的內容會導致游標身後的字音沒有對應的辭典記錄的話,那就只蜂鳴警告一下。 - proc: if [0, 1].contains(mgrPrefs.specifyIntonationKeyBehavior), composer.isEmpty, !input.isSpace { + proc: if [0, 1].contains(prefs.specifyIntonationKeyBehavior), composer.isEmpty, !input.isSpace { // prevReading 的內容分別是:「完整讀音」「去掉聲調的讀音」「是否有聲調」。 guard let prevReading = previousParsableReading, isIntonationKey(input) else { break proc } var theComposer = composer @@ -44,7 +44,7 @@ extension KeyHandler { // 發現要覆寫的聲調與覆寫對象的聲調雷同的情況的話,直接跳過處理。 let oldIntonation: Tekkon.Phonabet = theComposer.intonation theComposer.receiveKey(fromString: input.text) - if theComposer.intonation == oldIntonation, mgrPrefs.specifyIntonationKeyBehavior == 1 { break proc } + if theComposer.intonation == oldIntonation, prefs.specifyIntonationKeyBehavior == 1 { break proc } theComposer.intonation.clear() // 檢查新的漢字字音是否在庫。 let temporaryReadingKey = theComposer.getComposition() @@ -88,7 +88,7 @@ extension KeyHandler { if !currentLM.hasUnigramsFor(key: readingKey) { errorCallback("B49C0979:語彙庫內無「\(readingKey)」的匹配記錄。") - if mgrPrefs.keepReadingUponCompositionError { + if prefs.keepReadingUponCompositionError { composer.intonation.clear() // 砍掉聲調。 stateCallback(buildInputtingState) return true @@ -125,14 +125,14 @@ extension KeyHandler { stateCallback(inputting) /// 逐字選字模式的處理。 - if mgrPrefs.useSCPCTypingMode { + if prefs.useSCPCTypingMode { let candidateState: IMEState = buildCandidate(state: inputting) if candidateState.candidates.count == 1, let firstCandidate = candidateState.candidates.first { let reading: String = firstCandidate.0 let text: String = firstCandidate.1 stateCallback(IMEState.ofCommitting(textToCommit: text)) - if !mgrPrefs.associatedPhrasesEnabled { + if !prefs.associatedPhrasesEnabled { stateCallback(IMEState.ofEmpty()) } else { let associatedPhrases = diff --git a/Source/Modules/KeyHandler_HandleInput.swift b/Source/Modules/KeyHandler_HandleInput.swift index e7020395..e49406de 100644 --- a/Source/Modules/KeyHandler_HandleInput.swift +++ b/Source/Modules/KeyHandler_HandleInput.swift @@ -149,11 +149,11 @@ extension KeyHandler { if state.hasComposition, composer.isEmpty, !input.isOptionHold, input.isCursorClockLeft || input.isCursorClockRight || input.isSpace - || input.isPageDown || input.isPageUp || (input.isTab && mgrPrefs.specifyShiftTabKeyBehavior) + || input.isPageDown || input.isPageUp || (input.isTab && prefs.specifyShiftTabKeyBehavior) { if input.isSpace { /// 倘若沒有在偏好設定內將 Space 空格鍵設為選字窗呼叫用鍵的話……… - if !mgrPrefs.chooseCandidateUsingSpace { + if !prefs.chooseCandidateUsingSpace { if compositor.cursor >= compositor.length { let displayedText = state.displayedText if !displayedText.isEmpty { @@ -317,7 +317,7 @@ extension KeyHandler { let string = NSMutableString(string: stringRAW) CFStringTransform(string, nil, kCFStringTransformFullwidthHalfwidth, true) stateCallback( - IMEState.ofCommitting(textToCommit: mgrPrefs.halfWidthPunctuationEnabled ? stringRAW : string as String) + IMEState.ofCommitting(textToCommit: prefs.halfWidthPunctuationEnabled ? stringRAW : string as String) ) stateCallback(IMEState.ofEmpty()) return true @@ -372,7 +372,7 @@ extension KeyHandler { if input.isUpperCaseASCIILetterKey, !input.isCommandHold, !input.isControlHold { if input.isShiftHold { // 這裡先不要判斷 isOptionHold。 - switch mgrPrefs.upperCaseLetterKeyBehavior { + switch prefs.upperCaseLetterKeyBehavior { case 1: stateCallback(IMEState.ofEmpty()) stateCallback(IMEState.ofCommitting(textToCommit: inputText.lowercased())) diff --git a/Source/Modules/KeyHandler_States.swift b/Source/Modules/KeyHandler_States.swift index f0936742..dc93a5af 100644 --- a/Source/Modules/KeyHandler_States.swift +++ b/Source/Modules/KeyHandler_States.swift @@ -23,7 +23,7 @@ extension KeyHandler { /// 換成由此處重新生成的組字字串(NSAttributeString,否則會不顯示)。 var displayTextSegments: [String] = compositor.walkedNodes.values var cursor = convertCursorForDisplay(compositor.cursor) - let reading = composer.getInlineCompositionForDisplay(isHanyuPinyin: mgrPrefs.showHanyuPinyinInCompositionBuffer) + let reading = composer.getInlineCompositionForDisplay(isHanyuPinyin: prefs.showHanyuPinyinInCompositionBuffer) if !reading.isEmpty { var newDisplayTextSegments = [String]() var temporaryNode = "" @@ -91,7 +91,7 @@ extension KeyHandler { state currentState: IMEStateProtocol ) -> IMEState { IMEState.ofCandidates( - candidates: getCandidatesArray(fixOrder: mgrPrefs.useFixecCandidateOrderOnSelection), + candidates: getCandidatesArray(fixOrder: prefs.useFixecCandidateOrderOnSelection), displayTextSegments: compositor.walkedNodes.values, cursor: currentState.cursor ) @@ -263,7 +263,7 @@ extension KeyHandler { stateCallback(inputting) // 從這一行之後開始,就是針對逐字選字模式的單獨處理。 - guard mgrPrefs.useSCPCTypingMode, composer.isEmpty else { return true } + guard prefs.useSCPCTypingMode, composer.isEmpty else { return true } let candidateState = buildCandidate(state: inputting) if candidateState.candidates.count == 1 { @@ -312,7 +312,7 @@ extension KeyHandler { guard state.type == .ofInputting else { return false } var displayedText = compositor.keys.joined(separator: "-") - if mgrPrefs.inlineDumpPinyinInLieuOfZhuyin { + if prefs.inlineDumpPinyinInLieuOfZhuyin { displayedText = Tekkon.restoreToneOneInZhuyinKey(target: displayedText) // 恢復陰平標記 displayedText = Tekkon.cnvPhonaToHanyuPinyin(target: displayedText) // 注音轉拼音 } @@ -343,7 +343,7 @@ extension KeyHandler { for node in compositor.walkedNodes { var key = node.key - if mgrPrefs.inlineDumpPinyinInLieuOfZhuyin { + if prefs.inlineDumpPinyinInLieuOfZhuyin { key = Tekkon.restoreToneOneInZhuyinKey(target: key) // 恢復陰平標記 key = Tekkon.cnvPhonaToHanyuPinyin(target: key) // 注音轉拼音 key = Tekkon.cnvHanyuPinyinToTextbookStyle(target: key) // 轉教科書式標調 @@ -380,7 +380,7 @@ extension KeyHandler { guard state.type == .ofInputting else { return false } // 引入 macOS 內建注音輸入法的行為,允許用 Shift+BackSpace 解構前一個漢字的讀音。 - switch mgrPrefs.specifyShiftBackSpaceKeyBehavior { + switch prefs.specifyShiftBackSpaceKeyBehavior { case 0: guard input.isShiftHold, composer.isEmpty else { break } guard let prevReading = previousParsableReading else { break } @@ -567,7 +567,7 @@ extension KeyHandler { ) -> Bool { guard state.type == .ofInputting else { return false } - if mgrPrefs.escToCleanInputBuffer { + if prefs.escToCleanInputBuffer { /// 若啟用了該選項,則清空組字器的內容與注拼槽的內容。 /// 此乃 macOS 內建注音輸入法預設之行為,但不太受 Windows 使用者群體之待見。 stateCallback(IMEState.ofAbortion()) diff --git a/Source/Modules/LMMgr.swift b/Source/Modules/LMMgr.swift index 3707ca6b..26a2c292 100644 --- a/Source/Modules/LMMgr.swift +++ b/Source/Modules/LMMgr.swift @@ -57,9 +57,9 @@ public enum LMMgr { // LMMgr 的 loadUserPhrases 等函式在自動讀取 dataFolderPath 時, // 如果發現自訂目錄不可用,則會自動抹去自訂目錄設定、改採預設目錄。 // 所以這裡不需要特別處理。 - if mgrPrefs.associatedPhrasesEnabled { Self.loadUserAssociatesData() } - if mgrPrefs.phraseReplacementEnabled { Self.loadUserPhraseReplacement() } - if mgrPrefs.useSCPCTypingMode { Self.loadUserSCPCSequencesData() } + if PrefMgr.shared.associatedPhrasesEnabled { Self.loadUserAssociatesData() } + if PrefMgr.shared.phraseReplacementEnabled { Self.loadUserPhraseReplacement() } + if PrefMgr.shared.useSCPCTypingMode { Self.loadUserSCPCSequencesData() } Self.loadUserPhrasesData() } @@ -445,7 +445,7 @@ public enum LMMgr { public static let appSupportURL = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0] public static func dataFolderPath(isDefaultFolder: Bool) -> String { - var userDictPathSpecified = mgrPrefs.userDataFolderSpecified.expandingTildeInPath + var userDictPathSpecified = PrefMgr.shared.userDataFolderSpecified.expandingTildeInPath var userDictPathDefault = Self.appSupportURL.appendingPathComponent("vChewing").path.expandingTildeInPath @@ -516,7 +516,7 @@ public enum LMMgr { // The new FolderMonitor module does NOT monitor cases that files are modified // by the current application itself, requiring additional manual loading process here. - // if !mgrPrefs.shouldAutoReloadUserDataFiles {} + // if !PrefMgr.shared.shouldAutoReloadUserDataFiles {} loadUserPhrasesData() return true } diff --git a/Source/Modules/PrefMgr.swift b/Source/Modules/PrefMgr.swift index b0eafdd9..922612c7 100644 --- a/Source/Modules/PrefMgr.swift +++ b/Source/Modules/PrefMgr.swift @@ -15,11 +15,11 @@ private let kDefaultKeys = "123456789" private let kDefaultBasicKeyboardLayout = "com.apple.keylayout.ZhuyinBopomofo" private let kDefaultAlphanumericalKeyboardLayout = "com.apple.keylayout.ABC" -public let mgrPrefs = PrefMgr() - // MARK: - public class PrefMgr: PrefMgrProtocol { + public static let shared = PrefMgr() + // MARK: - Settings (Tier 1) @AppProperty(key: UserDef.kIsDebugModeEnabled.rawValue, defaultValue: false) diff --git a/Source/Modules/UIModules/CandidateUI/ctlCandidateIMK.swift b/Source/Modules/UIModules/CandidateUI/ctlCandidateIMK.swift index b789e780..21b5dc6e 100644 --- a/Source/Modules/UIModules/CandidateUI/ctlCandidateIMK.swift +++ b/Source/Modules/UIModules/CandidateUI/ctlCandidateIMK.swift @@ -40,13 +40,13 @@ public class ctlCandidateIMK: IMKCandidates, ctlCandidateProtocol { ofSize: 14, weight: .medium ) - public var candidateFont = NSFont.systemFont(ofSize: mgrPrefs.candidateListTextSize) { + public var candidateFont = NSFont.systemFont(ofSize: PrefMgr.shared.candidateListTextSize) { didSet { if #available(macOS 10.14, *) { setFontSize(candidateFont.pointSize) } var attributes = attributes() // FB11300759: Set "NSAttributedString.Key.font" doesn't work. attributes?[NSAttributedString.Key.font] = candidateFont - if mgrPrefs.handleDefaultCandidateFontsByLangIdentifier { + if PrefMgr.shared.handleDefaultCandidateFontsByLangIdentifier { switch IMEApp.currentInputMode { case InputMode.imeModeCHS: if #available(macOS 12.0, *) { @@ -55,7 +55,7 @@ public class ctlCandidateIMK: IMKCandidates, ctlCandidateProtocol { case InputMode.imeModeCHT: if #available(macOS 12.0, *) { attributes?[NSAttributedString.Key.languageIdentifier] = - (mgrPrefs.shiftJISShinjitaiOutputEnabled || mgrPrefs.chineseConversionEnabled) + (PrefMgr.shared.shiftJISShinjitaiOutputEnabled || PrefMgr.shared.chineseConversionEnabled) ? "ja" as AnyObject : "zh-Hant" as AnyObject } default: @@ -201,12 +201,12 @@ public class ctlCandidateIMK: IMKCandidates, ctlCandidateProtocol { case .vertical: event.isShiftHold ? moveLeft(self) : moveRight(self) } } else if event.isSpace { - switch mgrPrefs.specifyShiftSpaceKeyBehavior { + switch PrefMgr.shared.specifyShiftSpaceKeyBehavior { case true: _ = event.isShiftHold ? highlightNextCandidate() : showNextPage() case false: _ = event.isShiftHold ? showNextPage() : highlightNextCandidate() } } else if event.isTab { - switch mgrPrefs.specifyShiftTabKeyBehavior { + switch PrefMgr.shared.specifyShiftTabKeyBehavior { case true: _ = event.isShiftHold ? showPreviousPage() : showNextPage() case false: _ = event.isShiftHold ? highlightPreviousCandidate() : highlightNextCandidate() } @@ -216,7 +216,7 @@ public class ctlCandidateIMK: IMKCandidates, ctlCandidateProtocol { /// 反正 IMK 選字窗目前也沒辦法修改選字鍵。 let newEvent = event.reinitiate(characters: newChar) if let newEvent = newEvent { - if mgrPrefs.useSCPCTypingMode, delegate.isAssociatedPhrasesState { + if PrefMgr.shared.useSCPCTypingMode, delegate.isAssociatedPhrasesState { // 註:input.isShiftHold 已經在 ctlInputMethod.handle() 內處理,因為在那邊處理才有效。 if !event.isShiftHold { _ = delegate.sharedEventHandler(event) @@ -233,7 +233,7 @@ public class ctlCandidateIMK: IMKCandidates, ctlCandidateProtocol { } } - if mgrPrefs.useSCPCTypingMode, !event.isReservedKey { + if PrefMgr.shared.useSCPCTypingMode, !event.isReservedKey { _ = delegate.sharedEventHandler(event) return } @@ -241,7 +241,7 @@ public class ctlCandidateIMK: IMKCandidates, ctlCandidateProtocol { if delegate.isAssociatedPhrasesState, !event.isPageUp, !event.isPageDown, !event.isCursorForward, !event.isCursorBackward, !event.isCursorClockLeft, !event.isCursorClockRight, !event.isSpace, - !event.isEnter || !mgrPrefs.alsoConfirmAssociatedCandidatesByEnter + !event.isEnter || !PrefMgr.shared.alsoConfirmAssociatedCandidatesByEnter { _ = delegate.sharedEventHandler(event) return diff --git a/Source/Modules/UIModules/CandidateUI/ctlCandidateUniversal.swift b/Source/Modules/UIModules/CandidateUI/ctlCandidateUniversal.swift index 97017164..1c02fa8c 100644 --- a/Source/Modules/UIModules/CandidateUI/ctlCandidateUniversal.swift +++ b/Source/Modules/UIModules/CandidateUI/ctlCandidateUniversal.swift @@ -134,7 +134,7 @@ private class vwrCandidateUniversal: NSView { } func ensureLangIdentifier(for attr: inout [NSAttributedString.Key: AnyObject]) { - if mgrPrefs.handleDefaultCandidateFontsByLangIdentifier { + if PrefMgr.shared.handleDefaultCandidateFontsByLangIdentifier { switch IMEApp.currentInputMode { case InputMode.imeModeCHS: if #available(macOS 12.0, *) { @@ -143,7 +143,7 @@ private class vwrCandidateUniversal: NSView { case InputMode.imeModeCHT: if #available(macOS 12.0, *) { attr[.languageIdentifier] = - (mgrPrefs.shiftJISShinjitaiOutputEnabled || mgrPrefs.chineseConversionEnabled) + (PrefMgr.shared.shiftJISShinjitaiOutputEnabled || PrefMgr.shared.chineseConversionEnabled) ? "ja" as AnyObject : "zh-Hant" as AnyObject } default: @@ -542,7 +542,7 @@ extension ctlCandidateUniversal { candidateView.frame = frameRect let counterHeight: CGFloat = newSize.height - 24 - if pageCount > 1, mgrPrefs.showPageButtonsInCandidateWindow { + if pageCount > 1, PrefMgr.shared.showPageButtonsInCandidateWindow { var buttonRect = nextPageButton.frame let spacing: CGFloat = 0.0 @@ -587,7 +587,7 @@ extension ctlCandidateUniversal { ? (newSize.height - rect.height) / 2 : counterHeight let rectOriginX: CGFloat = - mgrPrefs.showPageButtonsInCandidateWindow + PrefMgr.shared.showPageButtonsInCandidateWindow ? newSize.width : newSize.width + 4 rect.origin = NSPoint(x: rectOriginX, y: rectOriginY) diff --git a/Source/Modules/UIModules/PrefUI/suiPrefPaneDevZone.swift b/Source/Modules/UIModules/PrefUI/suiPrefPaneDevZone.swift index 4e682a4c..371554ca 100644 --- a/Source/Modules/UIModules/PrefUI/suiPrefPaneDevZone.swift +++ b/Source/Modules/UIModules/PrefUI/suiPrefPaneDevZone.swift @@ -21,11 +21,11 @@ struct suiPrefPaneDevZone: View { private let contentMaxHeight: Double = 432 private let contentWidth: Double = { - switch mgrPrefs.appleLanguages[0] { + switch PrefMgr.shared.appleLanguages[0] { case "ja": return 520 default: - if mgrPrefs.appleLanguages[0].contains("zh-Han") { + if PrefMgr.shared.appleLanguages[0].contains("zh-Han") { return 480 } else { return 580 @@ -53,7 +53,7 @@ struct suiPrefPaneDevZone: View { Toggle( LocalizedStringKey("Use IMK Candidate Window instead (will reboot the IME)"), isOn: $selUseIMKCandidateWindow.onChange { - mgrPrefs.useIMKCandidateWindow = selUseIMKCandidateWindow + PrefMgr.shared.useIMKCandidateWindow = selUseIMKCandidateWindow NSLog("vChewing App self-terminated due to enabling / disabling IMK candidate window.") NSApplication.shared.terminate(nil) } @@ -67,7 +67,8 @@ struct suiPrefPaneDevZone: View { Toggle( LocalizedStringKey("Use .langIdentifier to handle UI fonts in candidate window"), isOn: $selHandleDefaultCandidateFontsByLangIdentifier.onChange { - mgrPrefs.handleDefaultCandidateFontsByLangIdentifier = selHandleDefaultCandidateFontsByLangIdentifier + PrefMgr.shared.handleDefaultCandidateFontsByLangIdentifier = + selHandleDefaultCandidateFontsByLangIdentifier } ) .disabled(!isMontereyOrAbove) @@ -80,7 +81,7 @@ struct suiPrefPaneDevZone: View { Picker( "", selection: $selShiftKeyAccommodationBehavior.onChange { - mgrPrefs.shiftKeyAccommodationBehavior = selShiftKeyAccommodationBehavior + PrefMgr.shared.shiftKeyAccommodationBehavior = selShiftKeyAccommodationBehavior } ) { Text(LocalizedStringKey("Disable Shift key accomodation in all cases")).tag(0) diff --git a/Source/Modules/UIModules/PrefUI/suiPrefPaneDictionary.swift b/Source/Modules/UIModules/PrefUI/suiPrefPaneDictionary.swift index 1c02f49d..75a228da 100644 --- a/Source/Modules/UIModules/PrefUI/suiPrefPaneDictionary.swift +++ b/Source/Modules/UIModules/PrefUI/suiPrefPaneDictionary.swift @@ -37,11 +37,11 @@ struct suiPrefPaneDictionary: View { private let contentMaxHeight: Double = 432 private let contentWidth: Double = { - switch mgrPrefs.appleLanguages[0] { + switch PrefMgr.shared.appleLanguages[0] { case "ja": return 520 default: - if mgrPrefs.appleLanguages[0].contains("zh-Han") { + if PrefMgr.shared.appleLanguages[0].contains("zh-Han") { return 480 } else { return 580 @@ -72,7 +72,7 @@ struct suiPrefPaneDictionary: View { Self.dlgOpenPath.canChooseDirectories = true let bolPreviousFolderValidity = LMMgr.checkIfSpecifiedUserDataFolderValid( - mgrPrefs.userDataFolderSpecified.expandingTildeInPath) + PrefMgr.shared.userDataFolderSpecified.expandingTildeInPath) if let window = ctlPrefUI.shared.controller.window { Self.dlgOpenPath.beginSheetModal(for: window) { result in @@ -83,8 +83,8 @@ struct suiPrefPaneDictionary: View { var newPath = url.path newPath.ensureTrailingSlash() if LMMgr.checkIfSpecifiedUserDataFolderValid(newPath) { - mgrPrefs.userDataFolderSpecified = newPath - tbxUserDataPathSpecified = mgrPrefs.userDataFolderSpecified + PrefMgr.shared.userDataFolderSpecified = newPath + tbxUserDataPathSpecified = PrefMgr.shared.userDataFolderSpecified BookmarkManager.shared.saveBookmark(for: url) (NSApplication.shared.delegate as! AppDelegate).updateDirectoryMonitorPath() } else { @@ -115,7 +115,7 @@ struct suiPrefPaneDictionary: View { Toggle( LocalizedStringKey("Automatically reload user data files if changes detected"), isOn: $selAutoReloadUserData.onChange { - mgrPrefs.shouldAutoReloadUserDataFiles = selAutoReloadUserData + PrefMgr.shared.shouldAutoReloadUserDataFiles = selAutoReloadUserData } ).controlSize(.small) } @@ -123,39 +123,39 @@ struct suiPrefPaneDictionary: View { Toggle( LocalizedStringKey("Enable CNS11643 Support (2022-08-02)"), isOn: $selEnableCNS11643.onChange { - mgrPrefs.cns11643Enabled = selEnableCNS11643 - LMMgr.setCNSEnabled(mgrPrefs.cns11643Enabled) + PrefMgr.shared.cns11643Enabled = selEnableCNS11643 + LMMgr.setCNSEnabled(PrefMgr.shared.cns11643Enabled) } ) Toggle( LocalizedStringKey("Enable symbol input support (incl. certain emoji symbols)"), isOn: $selEnableSymbolInputSupport.onChange { - mgrPrefs.symbolInputEnabled = selEnableSymbolInputSupport - LMMgr.setSymbolEnabled(mgrPrefs.symbolInputEnabled) + PrefMgr.shared.symbolInputEnabled = selEnableSymbolInputSupport + LMMgr.setSymbolEnabled(PrefMgr.shared.symbolInputEnabled) } ) Toggle( LocalizedStringKey("Allow boosting / excluding a candidate of single kanji"), isOn: $selAllowBoostingSingleKanjiAsUserPhrase.onChange { - mgrPrefs.allowBoostingSingleKanjiAsUserPhrase = selAllowBoostingSingleKanjiAsUserPhrase + PrefMgr.shared.allowBoostingSingleKanjiAsUserPhrase = selAllowBoostingSingleKanjiAsUserPhrase } ) Toggle( LocalizedStringKey("Applying typing suggestions from half-life user override model"), isOn: $selFetchSuggestionsFromUserOverrideModel.onChange { - mgrPrefs.fetchSuggestionsFromUserOverrideModel = selFetchSuggestionsFromUserOverrideModel + PrefMgr.shared.fetchSuggestionsFromUserOverrideModel = selFetchSuggestionsFromUserOverrideModel } ) Toggle( LocalizedStringKey("Always use fixed listing order in candidate window"), isOn: $selUseFixecCandidateOrderOnSelection.onChange { - mgrPrefs.useFixecCandidateOrderOnSelection = selUseFixecCandidateOrderOnSelection + PrefMgr.shared.useFixecCandidateOrderOnSelection = selUseFixecCandidateOrderOnSelection } ) Toggle( LocalizedStringKey("Consolidate the context on confirming candidate selection"), isOn: $selConsolidateContextOnCandidateSelection.onChange { - mgrPrefs.consolidateContextOnCandidateSelection = selConsolidateContextOnCandidateSelection + PrefMgr.shared.consolidateContextOnCandidateSelection = selConsolidateContextOnCandidateSelection } ) Text( @@ -167,7 +167,7 @@ struct suiPrefPaneDictionary: View { Toggle( LocalizedStringKey("Harden vertical punctuations during vertical typing (not recommended)"), isOn: $selHardenVerticalPunctuations.onChange { - mgrPrefs.hardenVerticalPunctuations = selHardenVerticalPunctuations + PrefMgr.shared.hardenVerticalPunctuations = selHardenVerticalPunctuations } ) Text( diff --git a/Source/Modules/UIModules/PrefUI/suiPrefPaneExperience.swift b/Source/Modules/UIModules/PrefUI/suiPrefPaneExperience.swift index 62c68e34..f1399b73 100644 --- a/Source/Modules/UIModules/PrefUI/suiPrefPaneExperience.swift +++ b/Source/Modules/UIModules/PrefUI/suiPrefPaneExperience.swift @@ -50,11 +50,11 @@ struct suiPrefPaneExperience: View { private let contentMaxHeight: Double = 432 private let contentWidth: Double = { - switch mgrPrefs.appleLanguages[0] { + switch PrefMgr.shared.appleLanguages[0] { case "ja": return 520 default: - if mgrPrefs.appleLanguages[0].contains("zh-Han") { + if PrefMgr.shared.appleLanguages[0].contains("zh-Han") { return 480 } else { return 580 @@ -85,7 +85,7 @@ struct suiPrefPaneExperience: View { Picker( "", selection: $selCursorPosition.onChange { - mgrPrefs.useRearCursorMode = (selCursorPosition == 1) ? true : false + PrefMgr.shared.useRearCursorMode = (selCursorPosition == 1) ? true : false } ) { Text(LocalizedStringKey("in front of the phrase (like macOS built-in Zhuyin IME)")).tag(0) @@ -98,7 +98,7 @@ struct suiPrefPaneExperience: View { Toggle( LocalizedStringKey("Push the cursor in front of the phrase after selection"), isOn: $selPushCursorAfterSelection.onChange { - mgrPrefs.moveCursorAfterSelectingCandidate = selPushCursorAfterSelection + PrefMgr.shared.moveCursorAfterSelectingCandidate = selPushCursorAfterSelection } ).controlSize(.small) } @@ -106,7 +106,7 @@ struct suiPrefPaneExperience: View { Picker( "", selection: $selSpecifyShiftBackSpaceKeyBehavior.onChange { - mgrPrefs.specifyShiftBackSpaceKeyBehavior = selSpecifyShiftBackSpaceKeyBehavior + PrefMgr.shared.specifyShiftBackSpaceKeyBehavior = selSpecifyShiftBackSpaceKeyBehavior } ) { Text(LocalizedStringKey("Disassemble the previous reading, dropping its intonation")).tag(0) @@ -122,7 +122,7 @@ struct suiPrefPaneExperience: View { Picker( "", selection: $selKeyBehaviorShiftTab.onChange { - mgrPrefs.specifyShiftTabKeyBehavior = (selKeyBehaviorShiftTab == 1) ? true : false + PrefMgr.shared.specifyShiftTabKeyBehavior = (selKeyBehaviorShiftTab == 1) ? true : false } ) { Text(LocalizedStringKey("for cycling candidates")).tag(0) @@ -138,7 +138,7 @@ struct suiPrefPaneExperience: View { Picker( "", selection: $selKeyBehaviorShiftSpace.onChange { - mgrPrefs.specifyShiftSpaceKeyBehavior = (selKeyBehaviorShiftSpace == 1) ? true : false + PrefMgr.shared.specifyShiftSpaceKeyBehavior = (selKeyBehaviorShiftSpace == 1) ? true : false } ) { Text(LocalizedStringKey("Space to +cycle candidates, Shift+Space to +cycle pages")).tag(0) @@ -153,7 +153,7 @@ struct suiPrefPaneExperience: View { Picker( "", selection: $selUpperCaseLetterKeyBehavior.onChange { - mgrPrefs.upperCaseLetterKeyBehavior = selUpperCaseLetterKeyBehavior + PrefMgr.shared.upperCaseLetterKeyBehavior = selUpperCaseLetterKeyBehavior } ) { Text(LocalizedStringKey("Type them into inline composition buffer")).tag(0) @@ -169,7 +169,7 @@ struct suiPrefPaneExperience: View { Picker( "", selection: $selSpecifyIntonationKeyBehavior.onChange { - mgrPrefs.specifyIntonationKeyBehavior = selSpecifyIntonationKeyBehavior + PrefMgr.shared.specifyIntonationKeyBehavior = selSpecifyIntonationKeyBehavior } ) { Text(LocalizedStringKey("Override the previous reading's intonation with candidate-reset")).tag(0) @@ -185,57 +185,57 @@ struct suiPrefPaneExperience: View { Toggle( LocalizedStringKey("Completely disable using Shift key to toggle alphanumerical mode"), isOn: $selDisableShiftTogglingAlphanumericalMode.onChange { - mgrPrefs.disableShiftTogglingAlphanumericalMode = selDisableShiftTogglingAlphanumericalMode + PrefMgr.shared.disableShiftTogglingAlphanumericalMode = selDisableShiftTogglingAlphanumericalMode } ) Toggle( LocalizedStringKey("Also toggle alphanumerical mode with Left-Shift"), isOn: $selTogglingAlphanumericalModeWithLShift.onChange { - mgrPrefs.togglingAlphanumericalModeWithLShift = selTogglingAlphanumericalModeWithLShift + PrefMgr.shared.togglingAlphanumericalModeWithLShift = selTogglingAlphanumericalModeWithLShift } - ).disabled(mgrPrefs.disableShiftTogglingAlphanumericalMode == true) + ).disabled(PrefMgr.shared.disableShiftTogglingAlphanumericalMode == true) } Preferences.Section(label: { Text(LocalizedStringKey("Misc Settings:")) }) { Toggle( LocalizedStringKey("Enable Space key for calling candidate window"), isOn: $selKeyBehaviorSpaceForCallingCandidate.onChange { - mgrPrefs.chooseCandidateUsingSpace = selKeyBehaviorSpaceForCallingCandidate + PrefMgr.shared.chooseCandidateUsingSpace = selKeyBehaviorSpaceForCallingCandidate } ) Toggle( LocalizedStringKey("Use ESC key to clear the entire input buffer"), isOn: $selKeyBehaviorESCForClearingTheBuffer.onChange { - mgrPrefs.escToCleanInputBuffer = selKeyBehaviorESCForClearingTheBuffer + PrefMgr.shared.escToCleanInputBuffer = selKeyBehaviorESCForClearingTheBuffer } ) Toggle( LocalizedStringKey("Automatically correct reading combinations when typing"), isOn: $selAutoCorrectReadingCombination.onChange { - mgrPrefs.autoCorrectReadingCombination = selAutoCorrectReadingCombination + PrefMgr.shared.autoCorrectReadingCombination = selAutoCorrectReadingCombination } ) Toggle( LocalizedStringKey("Allow using Enter key to confirm associated candidate selection"), isOn: $selAlsoConfirmAssociatedCandidatesByEnter.onChange { - mgrPrefs.alsoConfirmAssociatedCandidatesByEnter = selAlsoConfirmAssociatedCandidatesByEnter + PrefMgr.shared.alsoConfirmAssociatedCandidatesByEnter = selAlsoConfirmAssociatedCandidatesByEnter } ) Toggle( LocalizedStringKey("Allow backspace-editing miscomposed readings"), isOn: $selKeepReadingUponCompositionError.onChange { - mgrPrefs.keepReadingUponCompositionError = selKeepReadingUponCompositionError + PrefMgr.shared.keepReadingUponCompositionError = selKeepReadingUponCompositionError } ) Toggle( LocalizedStringKey("Trim unfinished readings on commit"), isOn: $selTrimUnfinishedReadingsOnCommit.onChange { - mgrPrefs.trimUnfinishedReadingsOnCommit = selTrimUnfinishedReadingsOnCommit + PrefMgr.shared.trimUnfinishedReadingsOnCommit = selTrimUnfinishedReadingsOnCommit } ) Toggle( LocalizedStringKey("Emulating select-candidate-per-character mode"), isOn: $selEnableSCPCTypingMode.onChange { - mgrPrefs.useSCPCTypingMode = selEnableSCPCTypingMode + PrefMgr.shared.useSCPCTypingMode = selEnableSCPCTypingMode } ) Text(LocalizedStringKey("An accommodation for elder computer users.")) @@ -243,7 +243,7 @@ struct suiPrefPaneExperience: View { Toggle( LocalizedStringKey("Always show tooltip texts horizontally"), isOn: $selAlwaysShowTooltipTextsHorizontally.onChange { - mgrPrefs.alwaysShowTooltipTextsHorizontally = selAlwaysShowTooltipTextsHorizontally + PrefMgr.shared.alwaysShowTooltipTextsHorizontally = selAlwaysShowTooltipTextsHorizontally } ).disabled(Bundle.main.preferredLocalizations[0] == "en") Text( diff --git a/Source/Modules/UIModules/PrefUI/suiPrefPaneGeneral.swift b/Source/Modules/UIModules/PrefUI/suiPrefPaneGeneral.swift index 3982cdfd..14acbd93 100644 --- a/Source/Modules/UIModules/PrefUI/suiPrefPaneGeneral.swift +++ b/Source/Modules/UIModules/PrefUI/suiPrefPaneGeneral.swift @@ -41,11 +41,11 @@ struct suiPrefPaneGeneral: View { private let contentMaxHeight: Double = 432 private let contentWidth: Double = { - switch mgrPrefs.appleLanguages[0] { + switch PrefMgr.shared.appleLanguages[0] { case "ja": return 520 default: - if mgrPrefs.appleLanguages[0].contains("zh-Han") { + if PrefMgr.shared.appleLanguages[0].contains("zh-Han") { return 480 } else { return 580 @@ -60,7 +60,7 @@ struct suiPrefPaneGeneral: View { Picker( "", selection: $selCandidateUIFontSize.onChange { - mgrPrefs.candidateListTextSize = CGFloat(selCandidateUIFontSize) + PrefMgr.shared.candidateListTextSize = CGFloat(selCandidateUIFontSize) } ) { Group { @@ -89,14 +89,14 @@ struct suiPrefPaneGeneral: View { LocalizedStringKey("Follow OS settings"), selection: $selUILanguage.onChange { vCLog(selUILanguage[0]) - if selUILanguage == mgrPrefs.appleLanguages + if selUILanguage == PrefMgr.shared.appleLanguages || (selUILanguage[0] == "auto" && UserDefaults.standard.object(forKey: UserDef.kAppleLanguages.rawValue) == nil) { return } if selUILanguage[0] != "auto" { - mgrPrefs.appleLanguages = selUILanguage + PrefMgr.shared.appleLanguages = selUILanguage } else { UserDefaults.standard.removeObject(forKey: UserDef.kAppleLanguages.rawValue) } @@ -120,7 +120,7 @@ struct suiPrefPaneGeneral: View { Picker( "", selection: $selEnableHorizontalCandidateLayout.onChange { - mgrPrefs.useHorizontalCandidateList = selEnableHorizontalCandidateLayout + PrefMgr.shared.useHorizontalCandidateList = selEnableHorizontalCandidateLayout } ) { Text(LocalizedStringKey("Vertical")).tag(false) @@ -134,43 +134,43 @@ struct suiPrefPaneGeneral: View { Toggle( LocalizedStringKey("Show page buttons in candidate window"), isOn: $selShowPageButtonsInCandidateUI.onChange { - mgrPrefs.showPageButtonsInCandidateWindow = selShowPageButtonsInCandidateUI + PrefMgr.shared.showPageButtonsInCandidateWindow = selShowPageButtonsInCandidateUI } ) .controlSize(.small) - .disabled(mgrPrefs.useIMKCandidateWindow) + .disabled(PrefMgr.shared.useIMKCandidateWindow) } Preferences.Section(label: { Text(LocalizedStringKey("Output Settings:")) }) { Toggle( LocalizedStringKey("Auto-convert traditional Chinese glyphs to KangXi characters"), isOn: $selEnableKanjiConvToKangXi.onChange { - mgrPrefs.chineseConversionEnabled = selEnableKanjiConvToKangXi - selEnableKanjiConvToJIS = mgrPrefs.shiftJISShinjitaiOutputEnabled + PrefMgr.shared.chineseConversionEnabled = selEnableKanjiConvToKangXi + selEnableKanjiConvToJIS = PrefMgr.shared.shiftJISShinjitaiOutputEnabled } ) Toggle( LocalizedStringKey("Auto-convert traditional Chinese glyphs to JIS Shinjitai characters"), isOn: $selEnableKanjiConvToJIS.onChange { - mgrPrefs.shiftJISShinjitaiOutputEnabled = selEnableKanjiConvToJIS - selEnableKanjiConvToKangXi = mgrPrefs.chineseConversionEnabled + PrefMgr.shared.shiftJISShinjitaiOutputEnabled = selEnableKanjiConvToJIS + selEnableKanjiConvToKangXi = PrefMgr.shared.chineseConversionEnabled } ) Toggle( LocalizedStringKey("Show Hanyu-Pinyin in the inline composition buffer"), isOn: $selShowHanyuPinyinInCompositionBuffer.onChange { - mgrPrefs.showHanyuPinyinInCompositionBuffer = selShowHanyuPinyinInCompositionBuffer + PrefMgr.shared.showHanyuPinyinInCompositionBuffer = selShowHanyuPinyinInCompositionBuffer } ) Toggle( LocalizedStringKey("Commit Hanyu-Pinyin instead on Ctrl(+Option)+Command+Enter"), isOn: $selInlineDumpPinyinInLieuOfZhuyin.onChange { - mgrPrefs.inlineDumpPinyinInLieuOfZhuyin = selInlineDumpPinyinInLieuOfZhuyin + PrefMgr.shared.inlineDumpPinyinInLieuOfZhuyin = selInlineDumpPinyinInLieuOfZhuyin } ) Toggle( LocalizedStringKey("Stop farting (when typed phonetic combination is invalid, etc.)"), isOn: $selEnableFartSuppressor.onChange { - mgrPrefs.shouldNotFartInLieuOfBeep = selEnableFartSuppressor + PrefMgr.shared.shouldNotFartInLieuOfBeep = selEnableFartSuppressor IMEApp.buzz() } ) @@ -179,14 +179,14 @@ struct suiPrefPaneGeneral: View { Toggle( LocalizedStringKey("Check for updates automatically"), isOn: $selEnableAutoUpdateCheck.onChange { - mgrPrefs.checkUpdateAutomatically = selEnableAutoUpdateCheck + PrefMgr.shared.checkUpdateAutomatically = selEnableAutoUpdateCheck } ) .controlSize(.small) Toggle( LocalizedStringKey("Debug Mode"), isOn: $selEnableDebugMode.onChange { - mgrPrefs.isDebugModeEnabled = selEnableDebugMode + PrefMgr.shared.isDebugModeEnabled = selEnableDebugMode } ) .controlSize(.small) diff --git a/Source/Modules/UIModules/PrefUI/suiPrefPaneKeyboard.swift b/Source/Modules/UIModules/PrefUI/suiPrefPaneKeyboard.swift index a36a5dee..be2ef9f9 100644 --- a/Source/Modules/UIModules/PrefUI/suiPrefPaneKeyboard.swift +++ b/Source/Modules/UIModules/PrefUI/suiPrefPaneKeyboard.swift @@ -18,10 +18,10 @@ struct suiPrefPaneKeyboard: View { UserDefaults.standard.string(forKey: UserDef.kCandidateKeys.rawValue) ?? CandidateKey.defaultKeys @State private var selKeyboardParser = UserDefaults.standard.integer(forKey: UserDef.kKeyboardParser.rawValue) @State private var selBasicKeyboardLayout: String = - UserDefaults.standard.string(forKey: UserDef.kBasicKeyboardLayout.rawValue) ?? mgrPrefs.basicKeyboardLayout + UserDefaults.standard.string(forKey: UserDef.kBasicKeyboardLayout.rawValue) ?? PrefMgr.shared.basicKeyboardLayout @State private var selAlphanumericalKeyboardLayout: String = UserDefaults.standard.string(forKey: UserDef.kAlphanumericalKeyboardLayout.rawValue) - ?? mgrPrefs.alphanumericalKeyboardLayout + ?? PrefMgr.shared.alphanumericalKeyboardLayout @State private var selUsingHotKeySCPC = UserDefaults.standard.bool(forKey: UserDef.kUsingHotKeySCPC.rawValue) @State private var selUsingHotKeyAssociates = UserDefaults.standard.bool( @@ -36,11 +36,11 @@ struct suiPrefPaneKeyboard: View { private let contentMaxHeight: Double = 432 private let contentWidth: Double = { - switch mgrPrefs.appleLanguages[0] { + switch PrefMgr.shared.appleLanguages[0] { case "ja": return 520 default: - if mgrPrefs.appleLanguages[0].contains("zh-Han") { + if PrefMgr.shared.appleLanguages[0].contains("zh-Han") { return 480 } else { return 580 @@ -59,22 +59,22 @@ struct suiPrefPaneKeyboard: View { let keys: String = value.trimmingCharacters(in: .whitespacesAndNewlines).deduplicate do { try CandidateKey.validate(keys: keys) - mgrPrefs.candidateKeys = keys - selSelectionKeys = mgrPrefs.candidateKeys + PrefMgr.shared.candidateKeys = keys + selSelectionKeys = PrefMgr.shared.candidateKeys } catch CandidateKey.ErrorType.empty { - selSelectionKeys = mgrPrefs.candidateKeys + selSelectionKeys = PrefMgr.shared.candidateKeys } catch { if let window = ctlPrefUI.shared.controller.window { let alert = NSAlert(error: error) alert.beginSheetModal(for: window) { _ in - selSelectionKeys = mgrPrefs.candidateKeys + selSelectionKeys = PrefMgr.shared.candidateKeys } IMEApp.buzz() } } } - ).frame(width: 180).disabled(mgrPrefs.useIMKCandidateWindow) - if mgrPrefs.useIMKCandidateWindow { + ).frame(width: 180).disabled(PrefMgr.shared.useIMKCandidateWindow) + if PrefMgr.shared.useIMKCandidateWindow { Text( LocalizedStringKey( "⚠︎ This feature in IMK Candidate Window defects. Please consult Apple Developer Relations\nand tell them the related Radar ID: #FB11300759." @@ -96,17 +96,17 @@ struct suiPrefPaneKeyboard: View { "", selection: $selKeyboardParser.onChange { let value = selKeyboardParser - mgrPrefs.keyboardParser = value + PrefMgr.shared.keyboardParser = value switch value { case 0: - if !IMKHelper.arrDynamicBasicKeyLayouts.contains(mgrPrefs.basicKeyboardLayout) { - mgrPrefs.basicKeyboardLayout = "com.apple.keylayout.ZhuyinBopomofo" - selBasicKeyboardLayout = mgrPrefs.basicKeyboardLayout + if !IMKHelper.arrDynamicBasicKeyLayouts.contains(PrefMgr.shared.basicKeyboardLayout) { + PrefMgr.shared.basicKeyboardLayout = "com.apple.keylayout.ZhuyinBopomofo" + selBasicKeyboardLayout = PrefMgr.shared.basicKeyboardLayout } default: - if IMKHelper.arrDynamicBasicKeyLayouts.contains(mgrPrefs.basicKeyboardLayout) { - mgrPrefs.basicKeyboardLayout = "com.apple.keylayout.ABC" - selBasicKeyboardLayout = mgrPrefs.basicKeyboardLayout + if IMKHelper.arrDynamicBasicKeyLayouts.contains(PrefMgr.shared.basicKeyboardLayout) { + PrefMgr.shared.basicKeyboardLayout = "com.apple.keylayout.ABC" + selBasicKeyboardLayout = PrefMgr.shared.basicKeyboardLayout } } } @@ -137,18 +137,18 @@ struct suiPrefPaneKeyboard: View { } .labelsHidden() Button { - mgrPrefs.keyboardParser = 0 - selKeyboardParser = mgrPrefs.keyboardParser - mgrPrefs.basicKeyboardLayout = "com.apple.keylayout.ZhuyinBopomofo" - selBasicKeyboardLayout = mgrPrefs.basicKeyboardLayout + PrefMgr.shared.keyboardParser = 0 + selKeyboardParser = PrefMgr.shared.keyboardParser + PrefMgr.shared.basicKeyboardLayout = "com.apple.keylayout.ZhuyinBopomofo" + selBasicKeyboardLayout = PrefMgr.shared.basicKeyboardLayout } label: { Text("↻ㄅ") } Button { - mgrPrefs.keyboardParser = 10 - selKeyboardParser = mgrPrefs.keyboardParser - mgrPrefs.basicKeyboardLayout = "com.apple.keylayout.ABC" - selBasicKeyboardLayout = mgrPrefs.basicKeyboardLayout + PrefMgr.shared.keyboardParser = 10 + selKeyboardParser = PrefMgr.shared.keyboardParser + PrefMgr.shared.basicKeyboardLayout = "com.apple.keylayout.ABC" + selBasicKeyboardLayout = PrefMgr.shared.basicKeyboardLayout } label: { Text("↻A") } @@ -159,7 +159,7 @@ struct suiPrefPaneKeyboard: View { NSLocalizedString( "Choose the phonetic layout for Mandarin parser.", comment: "" - ) + (mgrPrefs.appleLanguages[0].contains("en") ? " " : "") + ) + (PrefMgr.shared.appleLanguages[0].contains("en") ? " " : "") + NSLocalizedString( "Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional.", comment: "" @@ -175,10 +175,10 @@ struct suiPrefPaneKeyboard: View { "", selection: $selBasicKeyboardLayout.onChange { let value = selBasicKeyboardLayout - mgrPrefs.basicKeyboardLayout = value + PrefMgr.shared.basicKeyboardLayout = value if IMKHelper.arrDynamicBasicKeyLayouts.contains(value) { - mgrPrefs.keyboardParser = 0 - selKeyboardParser = mgrPrefs.keyboardParser + PrefMgr.shared.keyboardParser = 0 + selKeyboardParser = PrefMgr.shared.keyboardParser } } ) { @@ -210,7 +210,7 @@ struct suiPrefPaneKeyboard: View { Picker( "", selection: $selAlphanumericalKeyboardLayout.onChange { - mgrPrefs.alphanumericalKeyboardLayout = selAlphanumericalKeyboardLayout + PrefMgr.shared.alphanumericalKeyboardLayout = selAlphanumericalKeyboardLayout } ) { ForEach(0...(IMKHelper.allowedAlphanumericalTISInputSources.count - 1), id: \.self) { id in @@ -239,25 +239,25 @@ struct suiPrefPaneKeyboard: View { Toggle( LocalizedStringKey("Per-Char Select Mode"), isOn: $selUsingHotKeySCPC.onChange { - mgrPrefs.usingHotKeySCPC = selUsingHotKeySCPC + PrefMgr.shared.usingHotKeySCPC = selUsingHotKeySCPC } ) Toggle( LocalizedStringKey("Per-Char Associated Phrases"), isOn: $selUsingHotKeyAssociates.onChange { - mgrPrefs.usingHotKeyAssociates = selUsingHotKeyAssociates + PrefMgr.shared.usingHotKeyAssociates = selUsingHotKeyAssociates } ) Toggle( LocalizedStringKey("CNS11643 Mode"), isOn: $selUsingHotKeyCNS.onChange { - mgrPrefs.usingHotKeyCNS = selUsingHotKeyCNS + PrefMgr.shared.usingHotKeyCNS = selUsingHotKeyCNS } ) Toggle( LocalizedStringKey("Force KangXi Writing"), isOn: $selUsingHotKeyKangXi.onChange { - mgrPrefs.usingHotKeyKangXi = selUsingHotKeyKangXi + PrefMgr.shared.usingHotKeyKangXi = selUsingHotKeyKangXi } ) } @@ -265,19 +265,19 @@ struct suiPrefPaneKeyboard: View { Toggle( LocalizedStringKey("JIS Shinjitai Output"), isOn: $selUsingHotKeyJIS.onChange { - mgrPrefs.usingHotKeyJIS = selUsingHotKeyJIS + PrefMgr.shared.usingHotKeyJIS = selUsingHotKeyJIS } ) Toggle( LocalizedStringKey("Half-Width Punctuation Mode"), isOn: $selUsingHotKeyHalfWidthASCII.onChange { - mgrPrefs.usingHotKeyHalfWidthASCII = selUsingHotKeyHalfWidthASCII + PrefMgr.shared.usingHotKeyHalfWidthASCII = selUsingHotKeyHalfWidthASCII } ) Toggle( LocalizedStringKey("Currency Numeral Output"), isOn: $selUsingHotKeyCurrencyNumerals.onChange { - mgrPrefs.usingHotKeyCurrencyNumerals = selUsingHotKeyCurrencyNumerals + PrefMgr.shared.usingHotKeyCurrencyNumerals = selUsingHotKeyCurrencyNumerals } ) } diff --git a/Source/Modules/WindowControllers/ctlClientListMgr.swift b/Source/Modules/WindowControllers/ctlClientListMgr.swift index 425a1e28..787bec77 100644 --- a/Source/Modules/WindowControllers/ctlClientListMgr.swift +++ b/Source/Modules/WindowControllers/ctlClientListMgr.swift @@ -27,7 +27,7 @@ class ctlClientListMgr: NSWindowController, NSTableViewDelegate, NSTableViewData extension ctlClientListMgr { func numberOfRows(in _: NSTableView) -> Int { - mgrPrefs.clientsIMKTextInputIncapable.count + PrefMgr.shared.clientsIMKTextInputIncapable.count } func callAlert(_ window: NSWindow, title: String, text: String? = nil) { @@ -107,7 +107,7 @@ extension ctlClientListMgr { self.callAlert(window, title: title, text: text) return } - if mgrPrefs.clientsIMKTextInputIncapable.contains(identifier) { + if PrefMgr.shared.clientsIMKTextInputIncapable.contains(identifier) { title = NSLocalizedString( "The selected item's identifier is already in the list.", comment: "" ) @@ -125,41 +125,41 @@ extension ctlClientListMgr { private func applyNewValue(_ newValue: String) { guard !newValue.isEmpty else { return } - var arrResult = mgrPrefs.clientsIMKTextInputIncapable + var arrResult = PrefMgr.shared.clientsIMKTextInputIncapable arrResult.append(newValue) - mgrPrefs.clientsIMKTextInputIncapable = arrResult.sorted() + PrefMgr.shared.clientsIMKTextInputIncapable = arrResult.sorted() tblClients.reloadData() - btnRemoveClient.isEnabled = (0..= mgrPrefs.clientsIMKTextInputIncapable.count { return } + if minIndexSelected >= PrefMgr.shared.clientsIMKTextInputIncapable.count { return } if minIndexSelected < 0 { return } var isLastRow = false tblClients.selectedRowIndexes.sorted().reversed().forEach { index in isLastRow = { - if mgrPrefs.clientsIMKTextInputIncapable.count < 2 { return false } - return minIndexSelected == mgrPrefs.clientsIMKTextInputIncapable.count - 1 + if PrefMgr.shared.clientsIMKTextInputIncapable.count < 2 { return false } + return minIndexSelected == PrefMgr.shared.clientsIMKTextInputIncapable.count - 1 }() - if index < mgrPrefs.clientsIMKTextInputIncapable.count { - mgrPrefs.clientsIMKTextInputIncapable.remove(at: index) + if index < PrefMgr.shared.clientsIMKTextInputIncapable.count { + PrefMgr.shared.clientsIMKTextInputIncapable.remove(at: index) } } if isLastRow { tblClients.selectRowIndexes(.init(arrayLiteral: minIndexSelected - 1), byExtendingSelection: false) } tblClients.reloadData() - btnRemoveClient.isEnabled = (0.. Any? { defer { - self.btnRemoveClient.isEnabled = (0.. Bool { @@ -82,20 +82,20 @@ class ctlInputMethod: IMKInputController { func setKeyLayout() { guard let client = client() else { return } if isASCIIMode, IMKHelper.isDynamicBasicKeyboardLayoutEnabled { - client.overrideKeyboard(withKeyboardNamed: mgrPrefs.alphanumericalKeyboardLayout) + client.overrideKeyboard(withKeyboardNamed: PrefMgr.shared.alphanumericalKeyboardLayout) return } - client.overrideKeyboard(withKeyboardNamed: mgrPrefs.basicKeyboardLayout) + client.overrideKeyboard(withKeyboardNamed: PrefMgr.shared.basicKeyboardLayout) } /// 重設按鍵調度模組,會將當前尚未遞交的內容遞交出去。 func resetKeyHandler() { // 過濾掉尚未完成拼寫的注音。 - if state.type == .ofInputting, mgrPrefs.trimUnfinishedReadingsOnCommit { + if state.type == .ofInputting, PrefMgr.shared.trimUnfinishedReadingsOnCommit { keyHandler.composer.clear() handle(state: keyHandler.buildInputtingState) } - let isSecureMode = mgrPrefs.clientsIMKTextInputIncapable.contains(clientBundleIdentifier) + let isSecureMode = PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier) if state.hasComposition, !isSecureMode { /// 將傳回的新狀態交給調度函式。 handle(state: IMEState.ofCommitting(textToCommit: state.displayedText)) @@ -137,7 +137,7 @@ class ctlInputMethod: IMKInputController { keyHandler.clear() // 這句不要砍,因為後面 handle State.Empty() 不一定執行。 keyHandler.ensureKeyboardParser() - if isASCIIMode, mgrPrefs.disableShiftTogglingAlphanumericalMode { isASCIIMode = false } + if isASCIIMode, PrefMgr.shared.disableShiftTogglingAlphanumericalMode { isASCIIMode = false } /// 必須加上下述條件,否則會在每次切換至輸入法本體的視窗(比如偏好設定視窗)時會卡死。 /// 這是很多 macOS 副廠輸入法的常見失誤之處。 @@ -199,7 +199,7 @@ class ctlInputMethod: IMKInputController { willSet { /// 將新的簡繁輸入模式提報給 Prefs 與 IME 模組。 IMEApp.currentInputMode = newValue - mgrPrefs.mostRecentInputMode = IMEApp.currentInputMode.rawValue + PrefMgr.shared.mostRecentInputMode = IMEApp.currentInputMode.rawValue } didSet { /// 重設所有語言模組。這裡不需要做按需重設,因為對運算量沒有影響。 @@ -214,11 +214,11 @@ class ctlInputMethod: IMKInputController { /// 將輸入法偏好設定同步至語言模組內。 func syncBaseLMPrefs() { - LMMgr.currentLM().isPhraseReplacementEnabled = mgrPrefs.phraseReplacementEnabled - LMMgr.currentLM().isCNSEnabled = mgrPrefs.cns11643Enabled - LMMgr.currentLM().isSymbolEnabled = mgrPrefs.symbolInputEnabled - LMMgr.currentLM().isSCPCEnabled = mgrPrefs.useSCPCTypingMode - LMMgr.currentLM().deltaOfCalendarYears = mgrPrefs.deltaOfCalendarYears + LMMgr.currentLM().isPhraseReplacementEnabled = PrefMgr.shared.phraseReplacementEnabled + LMMgr.currentLM().isCNSEnabled = PrefMgr.shared.cns11643Enabled + LMMgr.currentLM().isSymbolEnabled = PrefMgr.shared.symbolInputEnabled + LMMgr.currentLM().isSCPCEnabled = PrefMgr.shared.useSCPCTypingMode + LMMgr.currentLM().deltaOfCalendarYears = PrefMgr.shared.deltaOfCalendarYears } // MARK: - IMKServerInput 協定規定的方法 @@ -261,7 +261,7 @@ class ctlInputMethod: IMKInputController { // 用 Shift 開關半形英數模式,僅對 macOS 10.15 及之後的 macOS 有效。 let shouldUseShiftToggleHandle: Bool = { - switch mgrPrefs.shiftKeyAccommodationBehavior { + switch PrefMgr.shared.shiftKeyAccommodationBehavior { case 0: return false case 1: return Shared.arrClientShiftHandlingExceptionList.contains(clientBundleIdentifier) case 2: return true @@ -271,7 +271,7 @@ class ctlInputMethod: IMKInputController { /// 警告:這裡的 event 必須是原始 event 且不能被 var,否則會影響 Shift 中英模式判定。 if #available(macOS 10.15, *) { - if Self.theShiftKeyDetector.check(event), !mgrPrefs.disableShiftTogglingAlphanumericalMode { + if Self.theShiftKeyDetector.check(event), !PrefMgr.shared.disableShiftTogglingAlphanumericalMode { if !shouldUseShiftToggleHandle || (!rencentKeyHandledByKeyHandlerEtc && shouldUseShiftToggleHandle) { NotifierController.notify( message: toggleASCIIMode() @@ -375,7 +375,7 @@ class ctlInputMethod: IMKInputController { var result = (theCandidate.1 == theConverted) ? theCandidate.1 : "\(theConverted)\u{1A}(\(theCandidate.1))" if arrResult.contains(result) { let reading: String = - mgrPrefs.showHanyuPinyinInCompositionBuffer + PrefMgr.shared.showHanyuPinyinInCompositionBuffer ? Tekkon.cnvPhonaToHanyuPinyin(target: Tekkon.restoreToneOneInZhuyinKey(target: theCandidate.0)) : theCandidate.0 result = "\(result)\u{17}(\(reading))" @@ -423,7 +423,7 @@ class ctlInputMethod: IMKInputController { override open func candidateSelected(_ candidateString: NSAttributedString!) { let candidateString: String = candidateString?.string ?? "" if state.type == .ofAssociates { - if !mgrPrefs.alsoConfirmAssociatedCandidatesByEnter { + if !PrefMgr.shared.alsoConfirmAssociatedCandidatesByEnter { handle(state: IMEState.ofAbortion()) return } @@ -437,7 +437,7 @@ class ctlInputMethod: IMKInputController { let theConverted = ChineseConverter.kanjiConversionIfRequired(neta.1) let netaShown = (neta.1 == theConverted) ? neta.1 : "\(theConverted)\u{1A}(\(neta.1))" let reading: String = - mgrPrefs.showHanyuPinyinInCompositionBuffer + PrefMgr.shared.showHanyuPinyinInCompositionBuffer ? Tekkon.cnvPhonaToHanyuPinyin(target: Tekkon.restoreToneOneInZhuyinKey(target: neta.0)) : neta.0 let netaShownWithPronunciation = "\(netaShown)\u{17}(\(reading))" if candidateString == prefix + netaShownWithPronunciation { diff --git a/Source/Modules/ctlInputMethod_Delegates.swift b/Source/Modules/ctlInputMethod_Delegates.swift index 55a8ec54..b1432375 100644 --- a/Source/Modules/ctlInputMethod_Delegates.swift +++ b/Source/Modules/ctlInputMethod_Delegates.swift @@ -106,15 +106,15 @@ extension ctlInputMethod: ctlCandidateDelegate { let selectedValue = state.candidates[index] keyHandler.fixNode( candidate: selectedValue, respectCursorPushing: true, - preConsolidate: mgrPrefs.consolidateContextOnCandidateSelection + preConsolidate: PrefMgr.shared.consolidateContextOnCandidateSelection ) let inputting = keyHandler.buildInputtingState - if mgrPrefs.useSCPCTypingMode { + if PrefMgr.shared.useSCPCTypingMode { handle(state: IMEState.ofCommitting(textToCommit: inputting.displayedText)) // 此時是逐字選字模式,所以「selectedValue.1」是單個字、不用追加處理。 - if mgrPrefs.associatedPhrasesEnabled { + if PrefMgr.shared.associatedPhrasesEnabled { let associates = keyHandler.buildAssociatePhraseState( withPair: .init(key: selectedValue.0, value: selectedValue.1) ) @@ -137,7 +137,7 @@ extension ctlInputMethod: ctlCandidateDelegate { handle(state: IMEState.ofEmpty()) return } - if mgrPrefs.associatedPhrasesEnabled { + if PrefMgr.shared.associatedPhrasesEnabled { let associates = keyHandler.buildAssociatePhraseState( withPair: .init(key: selectedValue.0, value: String(valueKept)) ) diff --git a/Source/Modules/ctlInputMethod_HandleDisplay.swift b/Source/Modules/ctlInputMethod_HandleDisplay.swift index 7937d911..748c1aa5 100644 --- a/Source/Modules/ctlInputMethod_HandleDisplay.swift +++ b/Source/Modules/ctlInputMethod_HandleDisplay.swift @@ -18,7 +18,7 @@ extension ctlInputMethod { // 對此類 App 有疑慮者,可以將這類 App 登記到客體管理員當中。 // 這樣,不但強制使用(限制讀音 20 個的)浮動組字窗,而且內文組字區只會顯示一個空格。 var attributedStringSecured: (NSAttributedString, NSRange) { - mgrPrefs.clientsIMKTextInputIncapable.contains(clientBundleIdentifier) + PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier) ? (state.data.attributedStringPlaceholder, NSRange(location: 0, length: 0)) : (state.attributedString, NSRange(state.data.u16MarkedRange)) } @@ -56,7 +56,7 @@ extension ctlInputMethod { ) } let tooltipContentDirection: NSAttributedTextView.writingDirection = { - if mgrPrefs.alwaysShowTooltipTextsHorizontally { return .horizontal } + if PrefMgr.shared.alwaysShowTooltipTextsHorizontally { return .horizontal } return isVerticalTyping ? .vertical : .horizontal }() // 強制重新初期化,因為 NSAttributedTextView 有顯示滯後性。 @@ -88,13 +88,13 @@ extension ctlInputMethod { // 因為在拿候選字陣列時已經排序過了,所以這裡不用再多排序。 // 測量每頁顯示候選字的累計總長度。如果太長的話就強制使用縱排候選字窗。 // 範例:「屬實牛逼」(會有一大串各種各樣的「鼠食牛Beer」的 emoji)。 - let maxCandidatesPerPage = mgrPrefs.candidateKeys.count + let maxCandidatesPerPage = PrefMgr.shared.candidateKeys.count let firstPageCandidates = candidates[0.. Int(round(Double(maxCandidatesPerPage) * 1.8)) // 上面這句如果是 true 的話,就會是縱排;反之則為橫排。 } - state.isVerticalCandidateWindow = (isCandidateWindowVertical || !mgrPrefs.useHorizontalCandidateList) + state.isVerticalCandidateWindow = (isCandidateWindowVertical || !PrefMgr.shared.useHorizontalCandidateList) ctlInputMethod.ctlCandidateCurrent.delegate = nil @@ -105,16 +105,16 @@ extension ctlInputMethod { /// 該問題徹底解決的價值並不大,直接等到 macOS 10.x 全線淘汰之後用 SwiftUI 重寫選字窗吧。 let candidateLayout: CandidateLayout = - ((isCandidateWindowVertical || !mgrPrefs.useHorizontalCandidateList) + ((isCandidateWindowVertical || !PrefMgr.shared.useHorizontalCandidateList) ? CandidateLayout.vertical : CandidateLayout.horizontal) ctlInputMethod.ctlCandidateCurrent = - mgrPrefs.useIMKCandidateWindow + PrefMgr.shared.useIMKCandidateWindow ? ctlCandidateIMK.init(candidateLayout) : ctlCandidateUniversal.init(candidateLayout) // set the attributes for the candidate panel (which uses NSAttributedString) - let textSize = mgrPrefs.candidateListTextSize + let textSize = PrefMgr.shared.candidateListTextSize let minimumKeyLabelSize: Double = 10 let keyLabelSize = max(textSize / 2, minimumKeyLabelSize) @@ -126,13 +126,13 @@ extension ctlInputMethod { } ctlInputMethod.ctlCandidateCurrent.keyLabelFont = labelFont( - name: mgrPrefs.candidateKeyLabelFontName, size: keyLabelSize + name: PrefMgr.shared.candidateKeyLabelFontName, size: keyLabelSize ) ctlInputMethod.ctlCandidateCurrent.candidateFont = ctlInputMethod.candidateFont( - name: mgrPrefs.candidateTextFontName, size: textSize + name: PrefMgr.shared.candidateTextFontName, size: textSize ) - let candidateKeys = mgrPrefs.candidateKeys + let candidateKeys = PrefMgr.shared.candidateKeys let keyLabels = candidateKeys.count > 4 ? Array(candidateKeys) : Array(CandidateKey.defaultKeys) let keyLabelSuffix = state.type == .ofAssociates ? "^" : "" @@ -195,7 +195,7 @@ extension ctlInputMethod { case InputMode.imeModeCHS: return CTFontCreateUIFontForLanguage(.system, size, "zh-Hans" as CFString) case InputMode.imeModeCHT: - return (mgrPrefs.shiftJISShinjitaiOutputEnabled || mgrPrefs.chineseConversionEnabled) + return (PrefMgr.shared.shiftJISShinjitaiOutputEnabled || PrefMgr.shared.chineseConversionEnabled) ? CTFontCreateUIFontForLanguage(.system, size, "ja" as CFString) : CTFontCreateUIFontForLanguage(.system, size, "zh-Hant" as CFString) default: diff --git a/Source/Modules/ctlInputMethod_HandleStates.swift b/Source/Modules/ctlInputMethod_HandleStates.swift index 4d670c44..2540d20e 100644 --- a/Source/Modules/ctlInputMethod_HandleStates.swift +++ b/Source/Modules/ctlInputMethod_HandleStates.swift @@ -80,7 +80,7 @@ extension ctlInputMethod { default: break } // 浮動組字窗的顯示判定 - if state.hasComposition, mgrPrefs.clientsIMKTextInputIncapable.contains(clientBundleIdentifier) { + if state.hasComposition, PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier) { ctlInputMethod.popupCompositionBuffer.isTypingDirectionVertical = isVerticalTyping ctlInputMethod.popupCompositionBuffer.show( state: state, at: lineHeightRect(zeroCursor: true).origin diff --git a/Source/Modules/ctlInputMethod_Menu.swift b/Source/Modules/ctlInputMethod_Menu.swift index bb753b5b..5d424e90 100644 --- a/Source/Modules/ctlInputMethod_Menu.swift +++ b/Source/Modules/ctlInputMethod_Menu.swift @@ -28,61 +28,64 @@ extension ctlInputMethod { let useSCPCTypingModeItem = menu.addItem( withTitle: NSLocalizedString("Per-Char Select Mode", comment: ""), - action: #selector(toggleSCPCTypingMode(_:)), keyEquivalent: mgrPrefs.usingHotKeySCPC ? "P" : "" + action: #selector(toggleSCPCTypingMode(_:)), keyEquivalent: PrefMgr.shared.usingHotKeySCPC ? "P" : "" ) useSCPCTypingModeItem.keyEquivalentModifierMask = [.command, .control] - useSCPCTypingModeItem.state = mgrPrefs.useSCPCTypingMode.state + useSCPCTypingModeItem.state = PrefMgr.shared.useSCPCTypingMode.state let userAssociatedPhrasesItem = menu.addItem( withTitle: NSLocalizedString("Per-Char Associated Phrases", comment: ""), - action: #selector(toggleAssociatedPhrasesEnabled(_:)), keyEquivalent: mgrPrefs.usingHotKeyAssociates ? "O" : "" + action: #selector(toggleAssociatedPhrasesEnabled(_:)), + keyEquivalent: PrefMgr.shared.usingHotKeyAssociates ? "O" : "" ) userAssociatedPhrasesItem.keyEquivalentModifierMask = [.command, .control] - userAssociatedPhrasesItem.state = mgrPrefs.associatedPhrasesEnabled.state + userAssociatedPhrasesItem.state = PrefMgr.shared.associatedPhrasesEnabled.state let useCNS11643SupportItem = menu.addItem( withTitle: NSLocalizedString("CNS11643 Mode", comment: ""), - action: #selector(toggleCNS11643Enabled(_:)), keyEquivalent: mgrPrefs.usingHotKeyCNS ? "L" : "" + action: #selector(toggleCNS11643Enabled(_:)), keyEquivalent: PrefMgr.shared.usingHotKeyCNS ? "L" : "" ) useCNS11643SupportItem.keyEquivalentModifierMask = [.command, .control] - useCNS11643SupportItem.state = mgrPrefs.cns11643Enabled.state + useCNS11643SupportItem.state = PrefMgr.shared.cns11643Enabled.state if IMEApp.currentInputMode == InputMode.imeModeCHT { let chineseConversionItem = menu.addItem( withTitle: NSLocalizedString("Force KangXi Writing", comment: ""), - action: #selector(toggleChineseConverter(_:)), keyEquivalent: mgrPrefs.usingHotKeyKangXi ? "K" : "" + action: #selector(toggleChineseConverter(_:)), keyEquivalent: PrefMgr.shared.usingHotKeyKangXi ? "K" : "" ) chineseConversionItem.keyEquivalentModifierMask = [.command, .control] - chineseConversionItem.state = mgrPrefs.chineseConversionEnabled.state + chineseConversionItem.state = PrefMgr.shared.chineseConversionEnabled.state let shiftJISConversionItem = menu.addItem( withTitle: NSLocalizedString("JIS Shinjitai Output", comment: ""), - action: #selector(toggleShiftJISShinjitaiOutput(_:)), keyEquivalent: mgrPrefs.usingHotKeyJIS ? "J" : "" + action: #selector(toggleShiftJISShinjitaiOutput(_:)), keyEquivalent: PrefMgr.shared.usingHotKeyJIS ? "J" : "" ) shiftJISConversionItem.keyEquivalentModifierMask = [.command, .control] - shiftJISConversionItem.state = mgrPrefs.shiftJISShinjitaiOutputEnabled.state + shiftJISConversionItem.state = PrefMgr.shared.shiftJISShinjitaiOutputEnabled.state } let currencyNumeralsItem = menu.addItem( withTitle: NSLocalizedString("Currency Numeral Output", comment: ""), - action: #selector(toggleCurrencyNumerals(_:)), keyEquivalent: mgrPrefs.usingHotKeyCurrencyNumerals ? "M" : "" + action: #selector(toggleCurrencyNumerals(_:)), + keyEquivalent: PrefMgr.shared.usingHotKeyCurrencyNumerals ? "M" : "" ) currencyNumeralsItem.keyEquivalentModifierMask = [.command, .control] - currencyNumeralsItem.state = mgrPrefs.currencyNumeralsEnabled.state + currencyNumeralsItem.state = PrefMgr.shared.currencyNumeralsEnabled.state let halfWidthPunctuationItem = menu.addItem( withTitle: NSLocalizedString("Half-Width Punctuation Mode", comment: ""), - action: #selector(toggleHalfWidthPunctuation(_:)), keyEquivalent: mgrPrefs.usingHotKeyHalfWidthASCII ? "H" : "" + action: #selector(toggleHalfWidthPunctuation(_:)), + keyEquivalent: PrefMgr.shared.usingHotKeyHalfWidthASCII ? "H" : "" ) halfWidthPunctuationItem.keyEquivalentModifierMask = [.command, .control] - halfWidthPunctuationItem.state = mgrPrefs.halfWidthPunctuationEnabled.state + halfWidthPunctuationItem.state = PrefMgr.shared.halfWidthPunctuationEnabled.state - if optionKeyPressed || mgrPrefs.phraseReplacementEnabled { + if optionKeyPressed || PrefMgr.shared.phraseReplacementEnabled { let phaseReplacementItem = menu.addItem( withTitle: NSLocalizedString("Use Phrase Replacement", comment: ""), action: #selector(togglePhraseReplacement(_:)), keyEquivalent: "" ) - phaseReplacementItem.state = mgrPrefs.phraseReplacementEnabled.state + phaseReplacementItem.state = PrefMgr.shared.phraseReplacementEnabled.state } if optionKeyPressed { @@ -90,7 +93,7 @@ extension ctlInputMethod { withTitle: NSLocalizedString("Symbol & Emoji Input", comment: ""), action: #selector(toggleSymbolEnabled(_:)), keyEquivalent: "" ) - toggleSymbolInputItem.state = mgrPrefs.symbolInputEnabled.state + toggleSymbolInputItem.state = PrefMgr.shared.symbolInputEnabled.state } menu.addItem(NSMenuItem.separator()) // --------------------- @@ -108,7 +111,7 @@ extension ctlInputMethod { action: #selector(openExcludedPhrases(_:)), keyEquivalent: "" ) - if optionKeyPressed || mgrPrefs.associatedPhrasesEnabled { + if optionKeyPressed || PrefMgr.shared.associatedPhrasesEnabled { menu.addItem( withTitle: NSLocalizedString("Edit Associated Phrases…", comment: ""), action: #selector(openAssociatedPhrases(_:)), keyEquivalent: "" @@ -126,7 +129,7 @@ extension ctlInputMethod { ) } - if optionKeyPressed || !mgrPrefs.shouldAutoReloadUserDataFiles { + if optionKeyPressed || !PrefMgr.shared.shouldAutoReloadUserDataFiles { menu.addItem( withTitle: NSLocalizedString("Reload User Phrases", comment: ""), action: #selector(reloadUserPhrasesData(_:)), keyEquivalent: "" @@ -222,7 +225,7 @@ extension ctlInputMethod { resetKeyHandler() NotifierController.notify( message: NSLocalizedString("Per-Char Select Mode", comment: "") + "\n" - + (mgrPrefs.useSCPCTypingMode.toggled() + + (PrefMgr.shared.useSCPCTypingMode.toggled() ? NSLocalizedString("NotificationSwitchON", comment: "") : NSLocalizedString("NotificationSwitchOFF", comment: "")) ) @@ -232,7 +235,7 @@ extension ctlInputMethod { resetKeyHandler() NotifierController.notify( message: NSLocalizedString("Force KangXi Writing", comment: "") + "\n" - + (mgrPrefs.chineseConversionEnabled.toggled() + + (PrefMgr.shared.chineseConversionEnabled.toggled() ? NSLocalizedString("NotificationSwitchON", comment: "") : NSLocalizedString("NotificationSwitchOFF", comment: "")) ) @@ -242,7 +245,7 @@ extension ctlInputMethod { resetKeyHandler() NotifierController.notify( message: NSLocalizedString("JIS Shinjitai Output", comment: "") + "\n" - + (mgrPrefs.shiftJISShinjitaiOutputEnabled.toggled() + + (PrefMgr.shared.shiftJISShinjitaiOutputEnabled.toggled() ? NSLocalizedString("NotificationSwitchON", comment: "") : NSLocalizedString("NotificationSwitchOFF", comment: "")) ) @@ -252,7 +255,7 @@ extension ctlInputMethod { resetKeyHandler() NotifierController.notify( message: NSLocalizedString("Currency Numeral Output", comment: "") + "\n" - + (mgrPrefs.currencyNumeralsEnabled.toggled() + + (PrefMgr.shared.currencyNumeralsEnabled.toggled() ? NSLocalizedString("NotificationSwitchON", comment: "") : NSLocalizedString("NotificationSwitchOFF", comment: "")) ) @@ -262,7 +265,7 @@ extension ctlInputMethod { resetKeyHandler() NotifierController.notify( message: NSLocalizedString("Half-Width Punctuation Mode", comment: "") + "\n" - + (mgrPrefs.halfWidthPunctuationEnabled.toggled() + + (PrefMgr.shared.halfWidthPunctuationEnabled.toggled() ? NSLocalizedString("NotificationSwitchON", comment: "") : NSLocalizedString("NotificationSwitchOFF", comment: "")) ) @@ -272,7 +275,7 @@ extension ctlInputMethod { resetKeyHandler() NotifierController.notify( message: NSLocalizedString("CNS11643 Mode", comment: "") + "\n" - + (mgrPrefs.cns11643Enabled.toggled() + + (PrefMgr.shared.cns11643Enabled.toggled() ? NSLocalizedString("NotificationSwitchON", comment: "") : NSLocalizedString("NotificationSwitchOFF", comment: "")) ) @@ -282,7 +285,7 @@ extension ctlInputMethod { resetKeyHandler() NotifierController.notify( message: NSLocalizedString("Symbol & Emoji Input", comment: "") + "\n" - + (mgrPrefs.symbolInputEnabled.toggled() + + (PrefMgr.shared.symbolInputEnabled.toggled() ? NSLocalizedString("NotificationSwitchON", comment: "") : NSLocalizedString("NotificationSwitchOFF", comment: "")) ) @@ -292,7 +295,7 @@ extension ctlInputMethod { resetKeyHandler() NotifierController.notify( message: NSLocalizedString("Per-Char Associated Phrases", comment: "") + "\n" - + (mgrPrefs.associatedPhrasesEnabled.toggled() + + (PrefMgr.shared.associatedPhrasesEnabled.toggled() ? NSLocalizedString("NotificationSwitchON", comment: "") : NSLocalizedString("NotificationSwitchOFF", comment: "")) ) @@ -302,7 +305,7 @@ extension ctlInputMethod { resetKeyHandler() NotifierController.notify( message: NSLocalizedString("Use Phrase Replacement", comment: "") + "\n" - + (mgrPrefs.phraseReplacementEnabled.toggled() + + (PrefMgr.shared.phraseReplacementEnabled.toggled() ? NSLocalizedString("NotificationSwitchON", comment: "") : NSLocalizedString("NotificationSwitchOFF", comment: "")) ) diff --git a/Source/Modules/main.swift b/Source/Modules/main.swift index 177c206e..c62aa851 100644 --- a/Source/Modules/main.swift +++ b/Source/Modules/main.swift @@ -94,10 +94,10 @@ public enum InputMode: String, CaseIterable { public enum IMEApp { // MARK: - 輸入法的當前的簡繁體中文模式 - public static var currentInputMode: InputMode = .init(rawValue: mgrPrefs.mostRecentInputMode) ?? .imeModeNULL + public static var currentInputMode: InputMode = .init(rawValue: PrefMgr.shared.mostRecentInputMode) ?? .imeModeNULL /// Fart or Beep? static func buzz() { - NSSound.buzz(fart: !mgrPrefs.shouldNotFartInLieuOfBeep) + NSSound.buzz(fart: !PrefMgr.shared.shouldNotFartInLieuOfBeep) } }