From a8f8408302aedf031d38c9f42942d2d209bd6b63 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Tue, 30 Aug 2022 12:01:22 +0800 Subject: [PATCH 01/20] LMSymbolNode // Clang-format. --- Source/Modules/LangModelRelated/LMSymbolNode.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/Modules/LangModelRelated/LMSymbolNode.swift b/Source/Modules/LangModelRelated/LMSymbolNode.swift index fa3d413f..e897c988 100644 --- a/Source/Modules/LangModelRelated/LMSymbolNode.swift +++ b/Source/Modules/LangModelRelated/LMSymbolNode.swift @@ -173,7 +173,9 @@ class SymbolNode { symbols: "①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓂ︎ⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ⓪⓫⓬⓭⓮⓯⓰⓱⓲⓳⓴⓵⓶⓷⓸⓹⓺⓻⓼⓽⓾⓿❶❷❸❹❺❻❼❽❾❿➀➁➂➃➄➅➆➇➈➉➊➋➌➍➎➏➐➑➒➓🄰🄱🄲🄳🄴🄵🄶🄷🄸🄹🄺🄻🄼🄽🄾🄿🅀🅁🅂🅃🅄🅅🅆🅇🅈🅉🅐🅑🅒🅓🅔🅕🅖🅗🅘🅙🅚🅛🅜🅝🅞🅟🅠🅡🅢🅣🅤🅥🅦🅧🅨🅩🅰🅱🅲🅳🅴🅵🅶🅷🅸🅹🅺🅻🅼🅽🅾🅿︎🆀🆁🆂🆃🆄🆅🆆🆇🆈🆉" ), - SymbolNode(catBracketedASCII, symbols: "⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇⒜⒝⒞⒟⒠⒡⒢⒣⒤⒥⒦⒧⒨⒩⒪⒫⒬⒭⒮⒯⒰⒱⒲⒳⒴⒵🄐🄑🄒🄓🄔🄕🄖🄗🄘🄙🄚🄛🄜🄝🄞🄟🄠🄡🄢🄣🄤🄥🄦🄧🄨🄩"), + SymbolNode( + catBracketedASCII, symbols: "⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇⒜⒝⒞⒟⒠⒡⒢⒣⒤⒥⒦⒧⒨⒩⒪⒫⒬⒭⒮⒯⒰⒱⒲⒳⒴⒵🄐🄑🄒🄓🄔🄕🄖🄗🄘🄙🄚🄛🄜🄝🄞🄟🄠🄡🄢🄣🄤🄥🄦🄧🄨🄩" + ), SymbolNode( catThai, symbols: [ From e3c832011eef046fbaa71137134437ad259aa98c Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Mon, 29 Aug 2022 16:50:40 +0800 Subject: [PATCH 02/20] Repo // Unify the usage of Megrez.Compositor.Candidate. --- Source/Modules/ControllerModules/KeyHandler_Core.swift | 2 +- Source/Modules/ControllerModules/KeyHandler_States.swift | 2 +- Source/Modules/LangModelRelated/LMInstantiator.swift | 4 ++-- Source/Modules/LangModelRelated/SubLMs/lmAssociates.swift | 4 ++-- Source/Modules/LangModelRelated/SubLMs/lmUserOverride.swift | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Source/Modules/ControllerModules/KeyHandler_Core.swift b/Source/Modules/ControllerModules/KeyHandler_Core.swift index 09016f4c..d02d07a7 100644 --- a/Source/Modules/ControllerModules/KeyHandler_Core.swift +++ b/Source/Modules/ControllerModules/KeyHandler_Core.swift @@ -122,7 +122,7 @@ public class KeyHandler { /// - Parameter key: 給定的聯想詞的開頭字。 /// - Returns: 抓取到的聯想詞陣列。 /// 不會是 nil,但那些負責接收結果的函式會對空白陣列結果做出正確的處理。 - func buildAssociatePhraseArray(withPair pair: Megrez.KeyValuePaired) -> [(String, String)] { + func buildAssociatePhraseArray(withPair pair: Megrez.Compositor.Candidate) -> [(String, String)] { var arrResult: [(String, String)] = [] if currentLM.hasAssociatedPhrasesFor(pair: pair) { arrResult = currentLM.associatedPhrasesFor(pair: pair).map { ("", $0) } diff --git a/Source/Modules/ControllerModules/KeyHandler_States.swift b/Source/Modules/ControllerModules/KeyHandler_States.swift index c82bf2c2..85ec6488 100644 --- a/Source/Modules/ControllerModules/KeyHandler_States.swift +++ b/Source/Modules/ControllerModules/KeyHandler_States.swift @@ -150,7 +150,7 @@ extension KeyHandler { /// - isTypingVertical: 是否縱排輸入? /// - Returns: 回呼一個新的聯想詞狀態,來就給定的聯想詞陣列資料內容顯示選字窗。 func buildAssociatePhraseState( - withPair pair: Megrez.KeyValuePaired, + withPair pair: Megrez.Compositor.Candidate, isTypingVertical: Bool ) -> InputState.AssociatedPhrases! { // 上一行必須要用驚嘆號,否則 Xcode 會誤導你砍掉某些實際上必需的語句。 diff --git a/Source/Modules/LangModelRelated/LMInstantiator.swift b/Source/Modules/LangModelRelated/LMInstantiator.swift index 9237f4fc..31ef15df 100644 --- a/Source/Modules/LangModelRelated/LMInstantiator.swift +++ b/Source/Modules/LangModelRelated/LMInstantiator.swift @@ -245,11 +245,11 @@ extension vChewing { return !unigramsFor(key: key).isEmpty } - public func associatedPhrasesFor(pair: Megrez.KeyValuePaired) -> [String] { + public func associatedPhrasesFor(pair: Megrez.Compositor.Candidate) -> [String] { lmAssociates.valuesFor(pair: pair) } - public func hasAssociatedPhrasesFor(pair: Megrez.KeyValuePaired) -> Bool { + public func hasAssociatedPhrasesFor(pair: Megrez.Compositor.Candidate) -> Bool { lmAssociates.hasValuesFor(pair: pair) } diff --git a/Source/Modules/LangModelRelated/SubLMs/lmAssociates.swift b/Source/Modules/LangModelRelated/SubLMs/lmAssociates.swift index 8dfc1ce6..3b169dcf 100644 --- a/Source/Modules/LangModelRelated/SubLMs/lmAssociates.swift +++ b/Source/Modules/LangModelRelated/SubLMs/lmAssociates.swift @@ -78,7 +78,7 @@ extension vChewing { // This function will be implemented only if further hard-necessity comes. } - public func valuesFor(pair: Megrez.KeyValuePaired) -> [String] { + public func valuesFor(pair: Megrez.Compositor.Candidate) -> [String] { var pairs: [String] = [] if let arrRangeRecords: [(Range, Int)] = rangeMap[pair.toNGramKey] { for (netaRange, index) in arrRangeRecords { @@ -98,7 +98,7 @@ extension vChewing { return pairs.filter { set.insert($0).inserted } } - public func hasValuesFor(pair: Megrez.KeyValuePaired) -> Bool { + public func hasValuesFor(pair: Megrez.Compositor.Candidate) -> Bool { if rangeMap[pair.toNGramKey] != nil { return true } return rangeMap[pair.value] != nil } diff --git a/Source/Modules/LangModelRelated/SubLMs/lmUserOverride.swift b/Source/Modules/LangModelRelated/SubLMs/lmUserOverride.swift index ba8edbbd..247d969c 100644 --- a/Source/Modules/LangModelRelated/SubLMs/lmUserOverride.swift +++ b/Source/Modules/LangModelRelated/SubLMs/lmUserOverride.swift @@ -319,8 +319,8 @@ extension vChewing.LMUserOverride { // 前置單元只記錄讀音,在其後的單元則同時記錄讀音與字詞 let strCurrent = kvCurrent.key - var kvPrevious = Megrez.KeyValuePaired() - var kvAnterior = Megrez.KeyValuePaired() + var kvPrevious = Megrez.Compositor.Candidate() + var kvAnterior = Megrez.Compositor.Candidate() var readingStack = "" var trigramKey: String { "(\(kvAnterior.toNGramKey),\(kvPrevious.toNGramKey),\(strCurrent))" } var result: String { From 34fa183148c53cfd30384624e1812a4f13c4ffa6 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Tue, 30 Aug 2022 11:59:40 +0800 Subject: [PATCH 03/20] ctlIME // Tweak tooltip axis during vertical typing. --- .../ctlInputMethod_HandleDisplay.swift | 11 ++++++++++- .../UIModules/TooltipUI/TooltipController.swift | 8 ++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Source/Modules/ControllerModules/ctlInputMethod_HandleDisplay.swift b/Source/Modules/ControllerModules/ctlInputMethod_HandleDisplay.swift index a0c5e50f..017d4871 100644 --- a/Source/Modules/ControllerModules/ctlInputMethod_HandleDisplay.swift +++ b/Source/Modules/ControllerModules/ctlInputMethod_HandleDisplay.swift @@ -26,7 +26,16 @@ extension ctlInputMethod { ) cursor -= 1 } - ctlInputMethod.tooltipController.show(tooltip: tooltip, at: lineHeightRect.origin) + var finalOrigin: NSPoint = lineHeightRect.origin + if isVerticalTyping { + finalOrigin = NSPoint( + x: lineHeightRect.origin.x + lineHeightRect.size.width + 4.0, y: lineHeightRect.origin.y - 4.0 + ) + ctlInputMethod.tooltipController.direction = .vertical + } else { + ctlInputMethod.tooltipController.direction = .horizontal + } + ctlInputMethod.tooltipController.show(tooltip: tooltip, at: finalOrigin) } func show(candidateWindowWith state: InputStateProtocol) { diff --git a/Source/Modules/UIModules/TooltipUI/TooltipController.swift b/Source/Modules/UIModules/TooltipUI/TooltipController.swift index 16898b9b..cc8c300c 100644 --- a/Source/Modules/UIModules/TooltipUI/TooltipController.swift +++ b/Source/Modules/UIModules/TooltipUI/TooltipController.swift @@ -20,6 +20,11 @@ public class TooltipController: NSWindowController { case prompt } + public enum displayDirection { + case horizontal + case vertical + } + private var backgroundColor = NSColor.windowBackgroundColor private var textColor = NSColor.windowBackgroundColor private var messageTextField: NSTextField @@ -30,6 +35,8 @@ public class TooltipController: NSWindowController { } } + public var direction: displayDirection = .horizontal + public init() { let contentRect = NSRect(x: 128.0, y: 128.0, width: 300.0, height: 20.0) let styleMask: NSWindow.StyleMask = [.borderless, .nonactivatingPanel] @@ -157,6 +164,7 @@ public class TooltipController: NSWindowController { var rect = attrString.boundingRect( with: NSSize(width: 1600.0, height: 1600.0), options: .usesLineFragmentOrigin ) + rect.size.width += 10 messageTextField.frame = rect window?.setFrame(rect, display: true) From a05a92b9fbccb88e361ca3dfc8f26cf370fba73a Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Mon, 29 Aug 2022 17:56:31 +0800 Subject: [PATCH 04/20] ctlIME // Ensure committingBufferConverted. --- .../ControllerModules/ctlInputMethod_HandleStates.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Modules/ControllerModules/ctlInputMethod_HandleStates.swift b/Source/Modules/ControllerModules/ctlInputMethod_HandleStates.swift index 7829288c..255eb0f1 100644 --- a/Source/Modules/ControllerModules/ctlInputMethod_HandleStates.swift +++ b/Source/Modules/ControllerModules/ctlInputMethod_HandleStates.swift @@ -130,7 +130,7 @@ extension ctlInputMethod { ctlInputMethod.ctlCandidateCurrent.visible = false ctlInputMethod.tooltipController.hide() if let previous = previous as? InputState.NotEmpty { - commit(text: previous.composingBuffer) + commit(text: previous.committingBufferConverted) } clearInlineDisplay() // 最後一道保險 @@ -145,7 +145,7 @@ extension ctlInputMethod { if let previous = previous as? InputState.NotEmpty, !(state is InputState.EmptyIgnoringPreviousState) { - commit(text: previous.composingBuffer) + commit(text: previous.committingBufferConverted) } // 在這裡手動再取消一次選字窗與工具提示的顯示,可謂雙重保險。 ctlInputMethod.ctlCandidateCurrent.visible = false From 149484f98835a8d41fdfd8cf7708e15b1f9250b1 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Tue, 30 Aug 2022 13:35:35 +0800 Subject: [PATCH 05/20] ctlIME // Do not handle when client is not IMKTextInput. --- Source/Modules/ControllerModules/ctlInputMethod_Core.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/Modules/ControllerModules/ctlInputMethod_Core.swift b/Source/Modules/ControllerModules/ctlInputMethod_Core.swift index dab2ccf2..9551ae8e 100644 --- a/Source/Modules/ControllerModules/ctlInputMethod_Core.swift +++ b/Source/Modules/ControllerModules/ctlInputMethod_Core.swift @@ -193,6 +193,9 @@ class ctlInputMethod: IMKInputController { @objc(handleEvent:client:) override func handle(_ event: NSEvent!, client sender: Any!) -> Bool { _ = sender // 防止格式整理工具毀掉與此對應的參數。 + // 只針對特定類型的 client() 進行處理。 + if !(sender is IMKTextInput) { return false } + // 就這傳入的 NSEvent 都還有可能是 nil,Apple InputMethodKit 團隊到底在搞三小。 guard let event = event else { return false } From eba750048f9f22c9e7e107788e513190ee161b6d Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Tue, 30 Aug 2022 13:18:57 +0800 Subject: [PATCH 06/20] mgrPrefs // +trimUnfinishedReadingsOnCommit. --- Source/Modules/IMEModules/mgrPrefs.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Source/Modules/IMEModules/mgrPrefs.swift b/Source/Modules/IMEModules/mgrPrefs.swift index 14c4ce65..3ed8fa54 100644 --- a/Source/Modules/IMEModules/mgrPrefs.swift +++ b/Source/Modules/IMEModules/mgrPrefs.swift @@ -54,6 +54,7 @@ public enum UserDef: String, CaseIterable { case kDisableShiftTogglingAlphanumericalMode = "DisableShiftTogglingAlphanumericalMode" case kConsolidateContextOnCandidateSelection = "ConsolidateContextOnCandidateSelection" case kHardenVerticalPunctuations = "HardenVerticalPunctuations" + case kTrimUnfinishedReadingsOnCommit = "TrimUnfinishedReadingsOnCommit" case kUseIMKCandidateWindow = "UseIMKCandidateWindow" case kHandleDefaultCandidateFontsByLangIdentifier = "HandleDefaultCandidateFontsByLangIdentifier" @@ -301,6 +302,9 @@ public enum mgrPrefs { UserDefaults.standard.setDefault( mgrPrefs.hardenVerticalPunctuations, forKey: UserDef.kHardenVerticalPunctuations.rawValue ) + UserDefaults.standard.setDefault( + mgrPrefs.trimUnfinishedReadingsOnCommit, forKey: UserDef.kTrimUnfinishedReadingsOnCommit.rawValue + ) // ----- @@ -432,6 +436,9 @@ public enum mgrPrefs { @UserDefault(key: UserDef.kHardenVerticalPunctuations.rawValue, defaultValue: false) static var hardenVerticalPunctuations: Bool + @UserDefault(key: UserDef.kTrimUnfinishedReadingsOnCommit.rawValue, defaultValue: true) + static var trimUnfinishedReadingsOnCommit: Bool + // MARK: - Settings (Tier 2) @UserDefault(key: UserDef.kUseIMKCandidateWindow.rawValue, defaultValue: false) From d36d0b7aa1c1122971ea1f77c5fb662a43351549 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Mon, 29 Aug 2022 18:27:10 +0800 Subject: [PATCH 07/20] ctlIME // Clear composer when necessary. --- .../ControllerModules/ctlInputMethod_Core.swift | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Source/Modules/ControllerModules/ctlInputMethod_Core.swift b/Source/Modules/ControllerModules/ctlInputMethod_Core.swift index 9551ae8e..2bdbc75a 100644 --- a/Source/Modules/ControllerModules/ctlInputMethod_Core.swift +++ b/Source/Modules/ControllerModules/ctlInputMethod_Core.swift @@ -60,6 +60,11 @@ class ctlInputMethod: IMKInputController { /// 重設按鍵調度模組,會將當前尚未遞交的內容遞交出去。 func resetKeyHandler() { + // 過濾掉尚未完成拼寫的注音。 + if state is InputState.Inputting, mgrPrefs.trimUnfinishedReadingsOnCommit { + keyHandler.composer.clear() + handle(state: keyHandler.buildInputtingState) + } if let state = state as? InputState.NotEmpty { /// 將傳回的新狀態交給調度函式。 handle(state: InputState.Committing(textToCommit: state.composingBufferConverted)) @@ -128,7 +133,7 @@ class ctlInputMethod: IMKInputController { /// - Parameter sender: 呼叫了該函式的客體(無須使用)。 override func deactivateServer(_ sender: Any!) { _ = sender // 防止格式整理工具毀掉與此對應的參數。 - handle(state: InputState.Empty()) + resetKeyHandler() // 這條會自動搞定 Empty 狀態。 handle(state: InputState.Deactivated()) } @@ -267,6 +272,7 @@ class ctlInputMethod: IMKInputController { override func commitComposition(_ sender: Any!) { _ = sender // 防止格式整理工具毀掉與此對應的參數。 resetKeyHandler() + // super.commitComposition(sender) // 這句不要引入,否則每次切出輸入法時都會死當。 } /// 指定輸入法要遞交出去的內容(雖然威注音可能並未用到這個函式)。 @@ -278,6 +284,14 @@ class ctlInputMethod: IMKInputController { return state.committingBufferConverted } + /// 輸入法要被換掉或關掉的時候,要做的事情。 + /// 不過好像因為 IMK 的 Bug 而並不會被執行。 + override func inputControllerWillClose() { + // 下述兩行用來防止尚未完成拼寫的注音內容貝蒂交出去。 + resetKeyHandler() + super.inputControllerWillClose() + } + // MARK: - IMKCandidates 功能擴充 /// 生成 IMK 選字窗專用的候選字串陣列。 From f4e44c38a6fdceb52f097bdaa2845f5e7ec42656 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Tue, 30 Aug 2022 15:58:16 +0800 Subject: [PATCH 08/20] PrefUI // +trimUnfinishedReadingsOnCommit. --- .../Modules/UIModules/PrefUI/suiPrefPaneExperience.swift | 8 ++++++++ Source/Resources/Base.lproj/Localizable.strings | 1 + Source/Resources/en.lproj/Localizable.strings | 1 + Source/Resources/ja.lproj/Localizable.strings | 1 + Source/Resources/zh-Hans.lproj/Localizable.strings | 1 + Source/Resources/zh-Hant.lproj/Localizable.strings | 1 + 6 files changed, 13 insertions(+) diff --git a/Source/Modules/UIModules/PrefUI/suiPrefPaneExperience.swift b/Source/Modules/UIModules/PrefUI/suiPrefPaneExperience.swift index 3318fbd0..36e9cf05 100644 --- a/Source/Modules/UIModules/PrefUI/suiPrefPaneExperience.swift +++ b/Source/Modules/UIModules/PrefUI/suiPrefPaneExperience.swift @@ -41,6 +41,8 @@ struct suiPrefPaneExperience: View { forKey: UserDef.kSpecifyIntonationKeyBehavior.rawValue) @State private var selSpecifyShiftBackSpaceKeyBehavior = UserDefaults.standard.integer( forKey: UserDef.kSpecifyShiftBackSpaceKeyBehavior.rawValue) + @State private var selTrimUnfinishedReadingsOnCommit = UserDefaults.standard.bool( + forKey: UserDef.kTrimUnfinishedReadingsOnCommit.rawValue) private let contentMaxHeight: Double = 432 private let contentWidth: Double = { @@ -220,6 +222,12 @@ struct suiPrefPaneExperience: View { mgrPrefs.keepReadingUponCompositionError = selKeepReadingUponCompositionError } ) + Toggle( + LocalizedStringKey("Trim unfinished readings on commit"), + isOn: $selTrimUnfinishedReadingsOnCommit.onChange { + mgrPrefs.trimUnfinishedReadingsOnCommit = selTrimUnfinishedReadingsOnCommit + } + ) Toggle( LocalizedStringKey("Emulating select-candidate-per-character mode"), isOn: $selEnableSCPCTypingMode.onChange { diff --git a/Source/Resources/Base.lproj/Localizable.strings b/Source/Resources/Base.lproj/Localizable.strings index 517096d3..bce949a9 100644 --- a/Source/Resources/Base.lproj/Localizable.strings +++ b/Source/Resources/Base.lproj/Localizable.strings @@ -195,6 +195,7 @@ "Stop farting (when typed phonetic combination is invalid, etc.)" = "Stop farting (when typed phonetic combination is invalid, etc.)"; "This only works since macOS 12 with non-IMK candidate window as an alternative wordaround of Apple Bug Report #FB10978412. Apple should patch that for macOS 11 and later." = "This only works since macOS 12 with non-IMK candidate window as an alternative wordaround of Apple Bug Report #FB10978412. Apple should patch that for macOS 11 and later."; "Traditional Chinese" = "Traditional Chinese"; +"Trim unfinished readings on commit" = "Trim unfinished readings on commit"; "Type them into inline composition buffer" = "Type them into inline composition buffer"; "Typing Style:" = "Typing Style:"; "UI Language:" = "UI Language:"; diff --git a/Source/Resources/en.lproj/Localizable.strings b/Source/Resources/en.lproj/Localizable.strings index 517096d3..bce949a9 100644 --- a/Source/Resources/en.lproj/Localizable.strings +++ b/Source/Resources/en.lproj/Localizable.strings @@ -195,6 +195,7 @@ "Stop farting (when typed phonetic combination is invalid, etc.)" = "Stop farting (when typed phonetic combination is invalid, etc.)"; "This only works since macOS 12 with non-IMK candidate window as an alternative wordaround of Apple Bug Report #FB10978412. Apple should patch that for macOS 11 and later." = "This only works since macOS 12 with non-IMK candidate window as an alternative wordaround of Apple Bug Report #FB10978412. Apple should patch that for macOS 11 and later."; "Traditional Chinese" = "Traditional Chinese"; +"Trim unfinished readings on commit" = "Trim unfinished readings on commit"; "Type them into inline composition buffer" = "Type them into inline composition buffer"; "Typing Style:" = "Typing Style:"; "UI Language:" = "UI Language:"; diff --git a/Source/Resources/ja.lproj/Localizable.strings b/Source/Resources/ja.lproj/Localizable.strings index 36d9f6a1..4c00e769 100644 --- a/Source/Resources/ja.lproj/Localizable.strings +++ b/Source/Resources/ja.lproj/Localizable.strings @@ -195,6 +195,7 @@ "Stop farting (when typed phonetic combination is invalid, etc.)" = "マナーモード // 外すと入力間違った時に変な声が出る"; "This only works since macOS 12 with non-IMK candidate window as an alternative wordaround of Apple Bug Report #FB10978412. Apple should patch that for macOS 11 and later." = "これは Apple Bug Report #FB10978412 の臨時対策であり、macOS 12 からの macOS に効き、IMK 以外の候補陳列ウィンドウに作用する。Apple は macOS 11 からの macOS のために該当 Bug を修復すべきである。"; "Traditional Chinese" = "繁体中国語"; +"Trim unfinished readings on commit" = "送り出す緩衝列内容から未完成な音読みを除く"; "Type them into inline composition buffer" = "入力緩衝列にローマ字入力"; "Typing Style:" = "入力習慣:"; "UI Language:" = "表示用言語:"; diff --git a/Source/Resources/zh-Hans.lproj/Localizable.strings b/Source/Resources/zh-Hans.lproj/Localizable.strings index 47093c28..6d0894e8 100644 --- a/Source/Resources/zh-Hans.lproj/Localizable.strings +++ b/Source/Resources/zh-Hans.lproj/Localizable.strings @@ -195,6 +195,7 @@ "Stop farting (when typed phonetic combination is invalid, etc.)" = "廉耻模式 // 取消勾选的话,敲错字时会有异音"; "This only works since macOS 12 with non-IMK candidate window as an alternative wordaround of Apple Bug Report #FB10978412. Apple should patch that for macOS 11 and later." = "该方法是 Apple Bug Report #FB10978412 的保守治疗方案,用来仅针对 macOS 12 开始的系统,且仅对非 IMK 选字窗起作用。Apple 应该对 macOS 11 开始的系统修复这个 Bug。"; "Traditional Chinese" = "繁体中文"; +"Trim unfinished readings on commit" = "在递交时清理未完成拼写的读音"; "Type them into inline composition buffer" = "直接键入内文组字区"; "Typing Style:" = "输入风格:"; "UI Language:" = "介面语言:"; diff --git a/Source/Resources/zh-Hant.lproj/Localizable.strings b/Source/Resources/zh-Hant.lproj/Localizable.strings index 6c6a677a..ae7b2c06 100644 --- a/Source/Resources/zh-Hant.lproj/Localizable.strings +++ b/Source/Resources/zh-Hant.lproj/Localizable.strings @@ -195,6 +195,7 @@ "Stop farting (when typed phonetic combination is invalid, etc.)" = "廉恥模式 // 取消勾選的話,敲錯字時會有異音"; "This only works since macOS 12 with non-IMK candidate window as an alternative wordaround of Apple Bug Report #FB10978412. Apple should patch that for macOS 11 and later." = "該方法是 Apple Bug Report #FB10978412 的保守治療方案,用來僅針對 macOS 12 開始的系統,且僅對非 IMK 選字窗起作用。Apple 應該對 macOS 11 開始的系統修復這個 Bug。"; "Traditional Chinese" = "繁體中文"; +"Trim unfinished readings on commit" = "在遞交時清理未完成拼寫的讀音"; "Type them into inline composition buffer" = "直接鍵入內文組字區"; "Typing Style:" = "輸入風格:"; "UI Language:" = "介面語言:"; From 9b4d34cf31e28995ea559dc5d005650351526148 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Tue, 30 Aug 2022 16:27:58 +0800 Subject: [PATCH 09/20] PrefWindow // +trimUnfinishedReadingsOnCommit. --- .../WindowNIBs/Base.lproj/frmPrefWindow.xib | 38 ++++++++++++------- .../WindowNIBs/en.lproj/frmPrefWindow.strings | 1 + .../WindowNIBs/ja.lproj/frmPrefWindow.strings | 1 + .../zh-Hans.lproj/frmPrefWindow.strings | 1 + .../zh-Hant.lproj/frmPrefWindow.strings | 1 + 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/Source/WindowNIBs/Base.lproj/frmPrefWindow.xib b/Source/WindowNIBs/Base.lproj/frmPrefWindow.xib index e78789c7..ab3f6540 100644 --- a/Source/WindowNIBs/Base.lproj/frmPrefWindow.xib +++ b/Source/WindowNIBs/Base.lproj/frmPrefWindow.xib @@ -266,10 +266,10 @@ - + - + @@ -319,7 +319,7 @@ - + @@ -365,10 +365,10 @@ - + + @@ -435,6 +445,7 @@ + @@ -443,6 +454,7 @@ + @@ -810,7 +822,7 @@ - + diff --git a/Source/WindowNIBs/en.lproj/frmPrefWindow.strings b/Source/WindowNIBs/en.lproj/frmPrefWindow.strings index 71bf86e9..d6c01133 100644 --- a/Source/WindowNIBs/en.lproj/frmPrefWindow.strings +++ b/Source/WindowNIBs/en.lproj/frmPrefWindow.strings @@ -90,6 +90,7 @@ "s7u-Fm-dVg.title" = "Cycling Pages"; "shc-Nu-UsM.title" = "Show page buttons in candidate list"; "tglDevZoneIMKCandidate.title" = "Use IMK Candidate Window instead (will reboot the IME)"; +"tglTrimUnfinishedReadingsOnCommit.title" = "Trim unfinished readings on commit"; "TXr-FF-ehw.title" = "Traditional Chinese"; "ueU-Rz-a1C.title" = "Choose the behavior of (Shift+)Tab key in the candidate window."; "VdT-fw-7pQ.title" = "Debug Mode"; diff --git a/Source/WindowNIBs/ja.lproj/frmPrefWindow.strings b/Source/WindowNIBs/ja.lproj/frmPrefWindow.strings index 9393550b..101de50e 100644 --- a/Source/WindowNIBs/ja.lproj/frmPrefWindow.strings +++ b/Source/WindowNIBs/ja.lproj/frmPrefWindow.strings @@ -90,6 +90,7 @@ "s7u-Fm-dVg.title" = "ページ"; "shc-Nu-UsM.title" = "ページボタンを表示"; "tglDevZoneIMKCandidate.title" = "IMK 候補陳列ウィンドウを起用(入力アプリは自動的に再起動)"; +"tglTrimUnfinishedReadingsOnCommit.title" = "送り出す緩衝列内容から未完成な音読みを除く"; "TXr-FF-ehw.title" = "繁体中国語"; "ueU-Rz-a1C.title" = "入力候補陳列での (Shift+)Tab キーの輪番切替対象をご指定ください。"; "VdT-fw-7pQ.title" = "欠陥辿着モード"; diff --git a/Source/WindowNIBs/zh-Hans.lproj/frmPrefWindow.strings b/Source/WindowNIBs/zh-Hans.lproj/frmPrefWindow.strings index ac8fcefb..46f3ee03 100644 --- a/Source/WindowNIBs/zh-Hans.lproj/frmPrefWindow.strings +++ b/Source/WindowNIBs/zh-Hans.lproj/frmPrefWindow.strings @@ -90,6 +90,7 @@ "s7u-Fm-dVg.title" = "轮替页面"; "shc-Nu-UsM.title" = "在选字窗内显示翻页按钮"; "tglDevZoneIMKCandidate.title" = "启用与 macOS 内建输入法相同的 IMK 选字窗(会自动重启输入法)"; +"tglTrimUnfinishedReadingsOnCommit.title" = "在递交时清理未完成拼写的读音"; "TXr-FF-ehw.title" = "繁体中文"; "ueU-Rz-a1C.title" = "指定 (Shift+)Tab 热键在选字窗内的轮替操作对象。"; "VdT-fw-7pQ.title" = "侦错模式"; diff --git a/Source/WindowNIBs/zh-Hant.lproj/frmPrefWindow.strings b/Source/WindowNIBs/zh-Hant.lproj/frmPrefWindow.strings index 8a105a5e..cc55d922 100644 --- a/Source/WindowNIBs/zh-Hant.lproj/frmPrefWindow.strings +++ b/Source/WindowNIBs/zh-Hant.lproj/frmPrefWindow.strings @@ -90,6 +90,7 @@ "s7u-Fm-dVg.title" = "輪替頁面"; "shc-Nu-UsM.title" = "在選字窗內顯示翻頁按鈕"; "tglDevZoneIMKCandidate.title" = "啟用與 macOS 內建輸入法相同的 IMK 選字窗(會自動重啟輸入法)"; +"tglTrimUnfinishedReadingsOnCommit.title" = "在遞交時清理未完成拼寫的讀音"; "TXr-FF-ehw.title" = "繁體中文"; "ueU-Rz-a1C.title" = "指定 (Shift+)Tab 熱鍵在選字窗內的輪替操作對象。"; "VdT-fw-7pQ.title" = "偵錯模式"; From 3b14208c0e16c38b853d3c558b1c9f3e2d03ea0d Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Tue, 30 Aug 2022 16:51:45 +0800 Subject: [PATCH 10/20] KeyHandler // Fix an issue with alphanumerical mode. - This fix stops this mode from committing full-width punctuations. --- Source/Modules/ControllerModules/KeyHandler_HandleInput.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift b/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift index bf46972f..15df851e 100644 --- a/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift +++ b/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift @@ -71,8 +71,8 @@ extension KeyHandler { // 但願能夠處理這種情況下所有可能的按鍵組合。 stateCallback(InputState.Empty()) - // 摁 Shift 的話,無須額外處理,因為直接就會敲出大寫字母。 - if input.isShiftHold { + // 字母鍵摁 Shift 的話,無須額外處理,因為直接就會敲出大寫字母。 + if input.isUpperCaseASCIILetterKey { return false } From d3bca595c18f970bfc58229949a5c707dbd3676a Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 31 Aug 2022 09:59:12 +0800 Subject: [PATCH 11/20] Uninstall.sh // Also remove receipts generated by pkg installer. --- uninstall.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/uninstall.sh b/uninstall.sh index 4cb6cfd8..955bd14a 100644 --- a/uninstall.sh +++ b/uninstall.sh @@ -13,6 +13,8 @@ rm ~/Library/Keyboard\ Layouts/vChewing\ IBM.keylayout rm ~/Library/Keyboard\ Layouts/vChewing\ FakeSeigyou.keylayout rm ~/Library/Keyboard\ Layouts/vChewing\ ETen.keylayout rm ~/Library/Keyboard\ Layouts/vChewing\ Dachen.keylayout +rm ~/Library/Receipts/org.atelierInmu.vChewing.bom +rm ~/Library/Receipts/org.atelierInmu.vChewing.plist # Also user phrase folder: # 原廠預設的使用者辭典目錄: @@ -35,6 +37,8 @@ sudo rm -rf /Library/Keyboard\ Layouts/vChewing\ IBM.keylayout sudo rm -rf /Library/Keyboard\ Layouts/vChewing\ FakeSeigyou.keylayout sudo rm -rf /Library/Keyboard\ Layouts/vChewing\ ETen.keylayout sudo rm -rf /Library/Keyboard\ Layouts/vChewing\ Dachen.keylayout +sudo rm -rf /Library/Receipts/org.atelierInmu.vChewing.bom +sudo rm -rf /Library/Receipts/org.atelierInmu.vChewing.plist # P.S.: The "vChewingKeyLayout.bundle" and keylayout files are deployed by the pkg installer. They are not hard-requirements for running vChewing, but providing extended on-screen keyboard for MiTAC, IBM, FakeSeigyou phonetic layouts. # P.S.: 「vChewingKeyLayout.bundle」與 keylayout 檔案只會被 pkg 格式的安裝包安裝。這些檔案提供了除了大千傳統與倚天傳統以外的靜態注音排列的螢幕鍵盤支援。 From 7ca01eebca74f94dbc93a9b2ed4dae308eff72ea Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 31 Aug 2022 10:06:51 +0800 Subject: [PATCH 12/20] Uninstall.sh // Stop automatically removing dictionary data. --- uninstall.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/uninstall.sh b/uninstall.sh index 955bd14a..2108bb8d 100644 --- a/uninstall.sh +++ b/uninstall.sh @@ -17,8 +17,9 @@ rm ~/Library/Receipts/org.atelierInmu.vChewing.bom rm ~/Library/Receipts/org.atelierInmu.vChewing.plist # Also user phrase folder: -# 原廠預設的使用者辭典目錄: -rm -rf ~/Library/Application\ Support/vChewing/ +# 原廠預設的使用者辭典目錄不自動刪除了,讓使用者自己刪: +# rm -rf ~/Library/Application\ Support/vChewing/ +# rm -rf /Users/shikisuen/Library/Containers/org.atelierInmu.inputmethod.vChewing/Data/Library/Application\ Support/vChewing/ # Also the IME configuration file: # 輸入法偏好設定檔案: From 0c7e4f7a0f7277530ee9606c056890901adba326 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Tue, 30 Aug 2022 18:46:28 +0800 Subject: [PATCH 13/20] Repo // Standardize the IMK Server connection name. --- Source/Modules/main.swift | 2 +- Source/Resources/IME-Info.plist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Modules/main.swift b/Source/Modules/main.swift index bc35e346..6935662d 100644 --- a/Source/Modules/main.swift +++ b/Source/Modules/main.swift @@ -11,7 +11,7 @@ import Cocoa import InputMethodKit -let kConnectionName = "vChewing_1_Connection" +let kConnectionName = "org.atelierInmu.inputmethod.vChewing_Connection" switch max(CommandLine.arguments.count - 1, 0) { case 0: break diff --git a/Source/Resources/IME-Info.plist b/Source/Resources/IME-Info.plist index 4ea76f83..c3fa892b 100644 --- a/Source/Resources/IME-Info.plist +++ b/Source/Resources/IME-Info.plist @@ -90,7 +90,7 @@ InputMethodConnectionName - vChewing_1_Connection + org.atelierInmu.inputmethod.vChewing_Connection InputMethodServerControllerClass ctlInputMethod InputMethodServerDelegateClass From 18596d527562396ffb8c6cfd55d89298d0c025af Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 31 Aug 2022 08:40:19 +0800 Subject: [PATCH 14/20] Repo // Add BookmarkManager. --- Source/3rdParty/Sandbox/BookmarkManager.swift | 101 ++++++++++++++++++ vChewing.xcodeproj/project.pbxproj | 12 +++ 2 files changed, 113 insertions(+) create mode 100644 Source/3rdParty/Sandbox/BookmarkManager.swift diff --git a/Source/3rdParty/Sandbox/BookmarkManager.swift b/Source/3rdParty/Sandbox/BookmarkManager.swift new file mode 100644 index 00000000..ba1d03f0 --- /dev/null +++ b/Source/3rdParty/Sandbox/BookmarkManager.swift @@ -0,0 +1,101 @@ +// +// Ref: https://stackoverflow.com/a/61695824 +// License: https://creativecommons.org/licenses/by-sa/4.0/ +// + +import Cocoa + +class BookmarkManager { + static let shared = BookmarkManager() + // Save bookmark for URL. Use this inside the NSOpenPanel `begin` closure + func saveBookmark(for url: URL) { + guard let bookmarkDic = getBookmarkData(url: url), + let bookmarkURL = getBookmarkURL() + else { + IME.prtDebugIntel("Error getting data or bookmarkURL") + return + } + + if #available(macOS 10.13, *) { + do { + let data = try NSKeyedArchiver.archivedData(withRootObject: bookmarkDic, requiringSecureCoding: false) + try data.write(to: bookmarkURL) + IME.prtDebugIntel("Did save data to url") + } catch { + IME.prtDebugIntel("Couldn't save bookmarks") + } + } + } + + // Load bookmarks when your app launch for example + func loadBookmarks() { + guard let url = getBookmarkURL() else { + return + } + + if fileExists(url) { + do { + let fileData = try Data(contentsOf: url) + if let fileBookmarks = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(fileData) as! [URL: Data]? { + for bookmark in fileBookmarks { + restoreBookmark(key: bookmark.key, value: bookmark.value) + } + } + } catch { + IME.prtDebugIntel("Couldn't load bookmarks") + } + } + } + + private func restoreBookmark(key: URL, value: Data) { + let restoredUrl: URL? + var isStale = false + + IME.prtDebugIntel("Restoring \(key)") + do { + restoredUrl = try URL( + resolvingBookmarkData: value, options: NSURL.BookmarkResolutionOptions.withSecurityScope, relativeTo: nil, + bookmarkDataIsStale: &isStale + ) + } catch { + IME.prtDebugIntel("Error restoring bookmarks") + restoredUrl = nil + } + + if let url = restoredUrl { + if isStale { + IME.prtDebugIntel("URL is stale") + } else { + if !url.startAccessingSecurityScopedResource() { + IME.prtDebugIntel("Couldn't access: \(url.path)") + } + } + } + } + + private func getBookmarkData(url: URL) -> [URL: Data]? { + let data = try? url.bookmarkData( + options: NSURL.BookmarkCreationOptions.withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil + ) + if let data = data { + return [url: data] + } + return nil + } + + private func getBookmarkURL() -> URL? { + let urls = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask) + if let appSupportURL = urls.last { + let url = appSupportURL.appendingPathComponent("Bookmarks.dict") + return url + } + return nil + } + + private func fileExists(_ url: URL) -> Bool { + var isDir = ObjCBool(false) + let exists = FileManager.default.fileExists(atPath: url.path, isDirectory: &isDir) + + return exists + } +} diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index 42bd02d2..76583ce6 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 5B09307628B6FC3B0021F8C5 /* shortcuts.html in Resources */ = {isa = PBXBuildFile; fileRef = 5B09307828B6FC3B0021F8C5 /* shortcuts.html */; }; 5B0AF8B527B2C8290096FE54 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B0AF8B427B2C8290096FE54 /* StringExtension.swift */; }; 5B11328927B94CFB00E58451 /* AppleKeyboardConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B11328827B94CFB00E58451 /* AppleKeyboardConverter.swift */; }; + 5B20430728BEE30900BFC6FD /* BookmarkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B20430628BEE30900BFC6FD /* BookmarkManager.swift */; }; 5B21176C287539BB000443A9 /* ctlInputMethod_HandleStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B21176B287539BB000443A9 /* ctlInputMethod_HandleStates.swift */; }; 5B21176E28753B35000443A9 /* ctlInputMethod_HandleDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B21176D28753B35000443A9 /* ctlInputMethod_HandleDisplay.swift */; }; 5B21177028753B9D000443A9 /* ctlInputMethod_Delegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B21176F28753B9D000443A9 /* ctlInputMethod_Delegates.swift */; }; @@ -217,6 +218,7 @@ 5B18BA7227C7BD8B0056EB19 /* LICENSE.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; 5B18BA7327C7BD8C0056EB19 /* LICENSE-JPN.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "LICENSE-JPN.txt"; sourceTree = ""; }; 5B18BA7427C7BD8C0056EB19 /* LICENSE-CHT.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "LICENSE-CHT.txt"; sourceTree = ""; }; + 5B20430628BEE30900BFC6FD /* BookmarkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkManager.swift; sourceTree = ""; }; 5B21176B287539BB000443A9 /* ctlInputMethod_HandleStates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlInputMethod_HandleStates.swift; sourceTree = ""; }; 5B21176D28753B35000443A9 /* ctlInputMethod_HandleDisplay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlInputMethod_HandleDisplay.swift; sourceTree = ""; }; 5B21176F28753B9D000443A9 /* ctlInputMethod_Delegates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlInputMethod_Delegates.swift; sourceTree = ""; }; @@ -427,6 +429,14 @@ name = MiscRootFiles; sourceTree = ""; }; + 5B20430528BEE2F300BFC6FD /* Sandbox */ = { + isa = PBXGroup; + children = ( + 5B20430628BEE30900BFC6FD /* BookmarkManager.swift */, + ); + path = Sandbox; + sourceTree = ""; + }; 5B2F2BB4286216A500B8557B /* vChewingTests */ = { isa = PBXGroup; children = ( @@ -457,6 +467,7 @@ 5B84579B2871AD2200C93B01 /* HotenkaChineseConverter */, 5B949BD72816DC4400D87B5D /* LineReader */, 5BA58644289BCFAC0077D02F /* Qwertyyb */, + 5B20430528BEE2F300BFC6FD /* Sandbox */, 5BA9FCEA27FED652002DE248 /* SindreSorhus */, 5BA9FD8C28006BA7002DE248 /* VDKComboBox */, ); @@ -1242,6 +1253,7 @@ 5B62A34927AE7CD900A19448 /* TooltipController.swift in Sources */, 5BA9FD4027FEF3C8002DE248 /* Localization.swift in Sources */, 5BAA8FBE282CAF380066C406 /* SyllableComposer.swift in Sources */, + 5B20430728BEE30900BFC6FD /* BookmarkManager.swift in Sources */, 5BA9FD1327FEDB6B002DE248 /* suiPrefPaneDictionary.swift in Sources */, 5B2170E8289FACAD00BE7304 /* 5_Vertex.swift in Sources */, 5BBBB77A27AEDC690023B93A /* clsSFX.swift in Sources */, From f300305f856040168c77278d87ba8b7db1e3a9cc Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 31 Aug 2022 11:26:33 +0800 Subject: [PATCH 15/20] Repo // Ensure BookmarkMangager. --- .../LangModelRelated/mgrLangModel.swift | 3 +- .../PrefUI/suiPrefPaneDictionary.swift | 32 +++++++++---------- Source/WindowControllers/ctlPrefWindow.swift | 30 ++++++++--------- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/Source/Modules/LangModelRelated/mgrLangModel.swift b/Source/Modules/LangModelRelated/mgrLangModel.swift index 218c58e7..8697db08 100644 --- a/Source/Modules/LangModelRelated/mgrLangModel.swift +++ b/Source/Modules/LangModelRelated/mgrLangModel.swift @@ -354,7 +354,7 @@ enum mgrLangModel { folderPath?.ensureTrailingSlash() } let isFolderWritable = FileManager.default.isWritableFile(atPath: folderPath ?? "") - + // IME.prtDebugIntel("mgrLM: Exist: \(folderExist), IsFolder: \(isFolder.boolValue), isWritable: \(isFolderWritable)") if ((folderExist && !isFolder.boolValue) || !folderExist) || !isFolderWritable { return false } @@ -423,6 +423,7 @@ enum mgrLangModel { return userDictPathDefault } if mgrPrefs.ifSpecifiedUserDataPathExistsInPlist() { + BookmarkManager.shared.loadBookmarks() if mgrLangModel.checkIfSpecifiedUserDataFolderValid(userDictPathSpecified) { return userDictPathSpecified } else { diff --git a/Source/Modules/UIModules/PrefUI/suiPrefPaneDictionary.swift b/Source/Modules/UIModules/PrefUI/suiPrefPaneDictionary.swift index fe1855ec..612eadaa 100644 --- a/Source/Modules/UIModules/PrefUI/suiPrefPaneDictionary.swift +++ b/Source/Modules/UIModules/PrefUI/suiPrefPaneDictionary.swift @@ -72,23 +72,23 @@ struct suiPrefPaneDictionary: View { if let window = ctlPrefUI.shared.controller.window { IME.dlgOpenPath.beginSheetModal(for: window) { result in if result == NSApplication.ModalResponse.OK { - if IME.dlgOpenPath.url != nil { - // CommonDialog 讀入的路徑沒有結尾斜槓,這會導致檔案目錄合規性判定失準。 - // 所以要手動補回來。 - var newPath = IME.dlgOpenPath.url!.path - newPath.ensureTrailingSlash() - if mgrLangModel.checkIfSpecifiedUserDataFolderValid(newPath) { - mgrPrefs.userDataFolderSpecified = newPath - tbxUserDataPathSpecified = mgrPrefs.userDataFolderSpecified - IME.initLangModels(userOnly: true) - (NSApplication.shared.delegate as! AppDelegate).updateStreamHelperPath() - } else { - clsSFX.beep() - if !bolPreviousFolderValidity { - mgrPrefs.resetSpecifiedUserDataFolder() - } - return + guard let url = IME.dlgOpenPath.url else { return } + // CommonDialog 讀入的路徑沒有結尾斜槓,這會導致檔案目錄合規性判定失準。 + // 所以要手動補回來。 + var newPath = url.path + newPath.ensureTrailingSlash() + if mgrLangModel.checkIfSpecifiedUserDataFolderValid(newPath) { + mgrPrefs.userDataFolderSpecified = newPath + tbxUserDataPathSpecified = mgrPrefs.userDataFolderSpecified + BookmarkManager.shared.saveBookmark(for: url) + IME.initLangModels(userOnly: true) + (NSApplication.shared.delegate as! AppDelegate).updateStreamHelperPath() + } else { + clsSFX.beep() + if !bolPreviousFolderValidity { + mgrPrefs.resetSpecifiedUserDataFolder() } + return } } else { if !bolPreviousFolderValidity { diff --git a/Source/WindowControllers/ctlPrefWindow.swift b/Source/WindowControllers/ctlPrefWindow.swift index 161ed061..85c17d56 100644 --- a/Source/WindowControllers/ctlPrefWindow.swift +++ b/Source/WindowControllers/ctlPrefWindow.swift @@ -293,22 +293,22 @@ class ctlPrefWindow: NSWindowController { IME.dlgOpenPath.beginSheetModal(for: window) { result in if result == NSApplication.ModalResponse.OK { - if IME.dlgOpenPath.url != nil { - // CommonDialog 讀入的路徑沒有結尾斜槓,這會導致檔案目錄合規性判定失準。 - // 所以要手動補回來。 - var newPath = IME.dlgOpenPath.url!.path - newPath.ensureTrailingSlash() - if mgrLangModel.checkIfSpecifiedUserDataFolderValid(newPath) { - mgrPrefs.userDataFolderSpecified = newPath - IME.initLangModels(userOnly: true) - (NSApplication.shared.delegate as! AppDelegate).updateStreamHelperPath() - } else { - clsSFX.beep() - if !bolPreviousFolderValidity { - mgrPrefs.resetSpecifiedUserDataFolder() - } - return + guard let url = IME.dlgOpenPath.url else { return } + // CommonDialog 讀入的路徑沒有結尾斜槓,這會導致檔案目錄合規性判定失準。 + // 所以要手動補回來。 + var newPath = url.path + newPath.ensureTrailingSlash() + if mgrLangModel.checkIfSpecifiedUserDataFolderValid(newPath) { + mgrPrefs.userDataFolderSpecified = newPath + BookmarkManager.shared.saveBookmark(for: url) + IME.initLangModels(userOnly: true) + (NSApplication.shared.delegate as! AppDelegate).updateStreamHelperPath() + } else { + clsSFX.beep() + if !bolPreviousFolderValidity { + mgrPrefs.resetSpecifiedUserDataFolder() } + return } } else { if !bolPreviousFolderValidity { From bc0c26891a53445f21ebedfc826e5393202ed8bd Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 31 Aug 2022 16:16:38 +0800 Subject: [PATCH 16/20] Repo // Sandbox entitlements and hardened runtime. --- Installer/AppDelegate.swift | 68 ++++++++++++++++++++--------- Source/Modules/IMEModules/IME.swift | 24 ++++++---- vChewing.entitlements | 22 ++++++++++ vChewing.xcodeproj/project.pbxproj | 18 ++++++++ vChewingInstaller.entitlements | 14 ++++++ vChewingPhraseEditor.entitlements | 12 +++++ 6 files changed, 130 insertions(+), 28 deletions(-) create mode 100644 vChewing.entitlements create mode 100644 vChewingInstaller.entitlements create mode 100644 vChewingPhraseEditor.entitlements diff --git a/Installer/AppDelegate.swift b/Installer/AppDelegate.swift index 0eb095c8..f474cea3 100644 --- a/Installer/AppDelegate.swift +++ b/Installer/AppDelegate.swift @@ -13,12 +13,14 @@ import Cocoa private let kTargetBin = "vChewing" private let kTargetType = "app" private let kTargetBundle = "vChewing.app" +private let kTargetBundleWithComponents = "Library/Input%20Methods/vChewing.app" -private let urlDestinationPartial = FileManager.default.urls( - for: .inputMethodsDirectory, in: .userDomainMask -)[0] -private let urlTargetPartial = urlDestinationPartial.appendingPathComponent(kTargetBundle) -private let urlTargetFullBinPartial = urlTargetPartial.appendingPathComponent("Contents/MacOS/") +private let realHomeDir = URL( + fileURLWithFileSystemRepresentation: getpwuid(getuid()).pointee.pw_dir, isDirectory: true, relativeTo: nil +) +private let urlDestinationPartial = realHomeDir.appendingPathComponent("Library/Input Methods") +private let urlTargetPartial = realHomeDir.appendingPathComponent(kTargetBundleWithComponents) +private let urlTargetFullBinPartial = urlTargetPartial.appendingPathComponent("Contents/MacOS") .appendingPathComponent(kTargetBin) private let kDestinationPartial = urlDestinationPartial.path @@ -93,9 +95,9 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { window?.standardWindowButton(.zoomButton)?.isHidden = true if FileManager.default.fileExists( - atPath: (kTargetPartialPath as NSString).expandingTildeInPath) + atPath: kTargetPartialPath) { - let currentBundle = Bundle(path: (kTargetPartialPath as NSString).expandingTildeInPath) + let currentBundle = Bundle(path: kTargetPartialPath) let shortVersion = currentBundle?.infoDictionary?["CFBundleShortVersionString"] as? String let currentVersion = @@ -136,15 +138,12 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { } func removeThenInstallInputMethod() { - if FileManager.default.fileExists( - atPath: (kTargetPartialPath as NSString).expandingTildeInPath) - == false - { - installInputMethod( - previousExists: false, previousVersionNotFullyDeactivatedWarning: false - ) - return - } + // if !FileManager.default.fileExists(atPath: kTargetPartialPath) { + // installInputMethod( + // previousExists: false, previousVersionNotFullyDeactivatedWarning: false + // ) + // return + // } let shouldWaitForTranslocationRemoval = isAppBundleTranslocated(atPath: kTargetPartialPath) @@ -152,7 +151,7 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { // 將既存輸入法扔到垃圾桶內 do { - let sourceDir = (kDestinationPartial as NSString).expandingTildeInPath + let sourceDir = kDestinationPartial let fileManager = FileManager.default let fileURLString = String(format: "%@/%@", sourceDir, kTargetBundle) let fileURL = URL(fileURLWithPath: fileURLString) @@ -216,8 +215,9 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { } let cpTask = Process() cpTask.launchPath = "/bin/cp" + print(kDestinationPartial) cpTask.arguments = [ - "-R", targetBundle, (kDestinationPartial as NSString).expandingTildeInPath, + "-R", targetBundle, kDestinationPartial, ] cpTask.launch() cpTask.waitUntilExit() @@ -231,7 +231,11 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { endAppWithDelay() } - guard let imeBundle = Bundle(path: (kTargetPartialPath as NSString).expandingTildeInPath), + let imeURLInstalled = realHomeDir.appendingPathComponent("Library/Input Methods/vChewing.app") + + _ = try? shell("/usr/bin/xattr -drs com.apple.quarantine \(kTargetPartialPath)") + + guard let imeBundle = Bundle(url: imeURLInstalled), let imeIdentifier = imeBundle.bundleIdentifier else { endAppWithDelay() @@ -343,6 +347,30 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { NSApp.terminate(self) } + private func shell(_ command: String) throws -> String { + let task = Process() + let pipe = Pipe() + + task.standardOutput = pipe + task.standardError = pipe + task.arguments = ["-c", command] + if #available(macOS 10.13, *) { + task.executableURL = URL(fileURLWithPath: "/bin/zsh") + } else { + task.launchPath = "/bin/zsh" + } + task.standardInput = nil + + if #available(macOS 10.13, *) { + try task.run() + } + + let data = pipe.fileHandleForReading.readDataToEndOfFile() + let output = String(data: data, encoding: .utf8)! + + return output + } + // Determines if an app is translocated by Gatekeeper to a randomized path. // See https://weblog.rogueamoeba.com/2016/06/29/sierra-and-gatekeeper-path-randomization/ // Originally written by Zonble Yang in Objective-C (MIT License). @@ -350,7 +378,7 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { func isAppBundleTranslocated(atPath bundlePath: String) -> Bool { var entryCount = getfsstat(nil, 0, 0) var entries: [statfs] = .init(repeating: .init(), count: Int(entryCount)) - let absPath = (bundlePath as NSString).expandingTildeInPath.cString(using: .utf8) + let absPath = bundlePath.cString(using: .utf8) entryCount = getfsstat(&entries, entryCount * Int32(MemoryLayout.stride), MNT_NOWAIT) for entry in entries.prefix(Int(entryCount)) { let isMatch = withUnsafeBytes(of: entry.f_mntfromname) { mntFromName in diff --git a/Source/Modules/IMEModules/IME.swift b/Source/Modules/IMEModules/IME.swift index ecde1e14..e6e62313 100644 --- a/Source/Modules/IMEModules/IME.swift +++ b/Source/Modules/IMEModules/IME.swift @@ -22,6 +22,9 @@ public enum InputMode: String { public enum IME { static let arrSupportedLocales = ["en", "zh-Hant", "zh-Hans", "ja"] static let dlgOpenPath = NSOpenPanel() + public static let realHomeDir = URL( + fileURLWithFileSystemRepresentation: getpwuid(getuid()).pointee.pw_dir, isDirectory: true, relativeTo: nil + ) // MARK: - 瀏覽器 Bundle Identifier 關鍵詞匹配黑名單 @@ -173,16 +176,23 @@ public enum IME { return -1 } - let kTargetBin = "vChewing" + // 自威注音 v2.3.0 開始,沙箱限制了威注音的某些行為,所以該函式不再受理 sudo 模式下的操作。 + if isSudo { + print( + "vChewing binary does not support sudo-uninstall since v2.3.0. Please use the bundled uninstall.sh instead.\n\nIf you want to fix the installation (i.e. removing all incorrectly installed files outside of the current user folder), please use the bundled fixinstall.sh instead.\n\nIf you don't know how to proceed, please bring either the uninstall.sh / install.sh or the instruction article https://vchewing.github.io/UNINSTALL.html to Apple Support (support.apple.com) for help. Their senior advisors can understand these uninstall instructions." + ) + return -1 + } + let kTargetBundle = "/vChewing.app" let pathLibrary = isSudo ? "/Library" - : FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask)[0].path + : IME.realHomeDir.appendingPathComponent("Library/").path let pathIMELibrary = isSudo ? "/Library/Input Methods" - : FileManager.default.urls(for: .inputMethodsDirectory, in: .userDomainMask)[0].path + : IME.realHomeDir.appendingPathComponent("Library/Input Methods/").path let pathUnitKeyboardLayouts = "/Keyboard Layouts" let arrKeyLayoutFiles = [ "/vChewing ETen.keylayout", "/vChewingKeyLayout.bundle", "/vChewing MiTAC.keylayout", @@ -203,15 +213,13 @@ public enum IME { // 目前暫時無法應對 symbol link 的情況。 IME.trashTargetIfExists(mgrLangModel.dataFolderPath(isDefaultFolder: true)) IME.trashTargetIfExists(pathLibrary + "/Preferences/" + bundleID + ".plist") // 之後移除 App 偏好設定 + IME.trashTargetIfExists(pathLibrary + "/Receipts/org.atelierInmu.vChewing.bom") // pkg 垃圾 + IME.trashTargetIfExists(pathLibrary + "/Receipts/org.atelierInmu.vChewing.plist") // pkg 垃圾 } if !IME.trashTargetIfExists(pathIMELibrary + kTargetBundle) { return -1 } // 最後移除 App 自身 // 幹掉殘留在記憶體內的執行緒。 if selfKill { - let killTask = Process() - killTask.launchPath = "/usr/bin/killall" - killTask.arguments = ["-9", kTargetBin] - killTask.launch() - killTask.waitUntilExit() + NSApplication.shared.terminate(nil) } return 0 } diff --git a/vChewing.entitlements b/vChewing.entitlements new file mode 100644 index 00000000..ada9860e --- /dev/null +++ b/vChewing.entitlements @@ -0,0 +1,22 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.bookmarks.app-scope + + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client + + com.apple.security.temporary-exception.files.home-relative-path.read-write + + / + + com.apple.security.temporary-exception.mach-register.global-name + org.atelierInmu.inputmethod.vChewing_Connection + com.apple.security.temporary-exception.shared-preference.read-only + org.atelierInmu.inputmethod.vChewing + + diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index 76583ce6..5294da42 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -219,6 +219,9 @@ 5B18BA7327C7BD8C0056EB19 /* LICENSE-JPN.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "LICENSE-JPN.txt"; sourceTree = ""; }; 5B18BA7427C7BD8C0056EB19 /* LICENSE-CHT.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "LICENSE-CHT.txt"; sourceTree = ""; }; 5B20430628BEE30900BFC6FD /* BookmarkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkManager.swift; sourceTree = ""; }; + 5B20430B28BEFC0C00BFC6FD /* vChewing.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = vChewing.entitlements; sourceTree = ""; }; + 5B20430C28BEFC1200BFC6FD /* vChewingPhraseEditor.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = vChewingPhraseEditor.entitlements; sourceTree = ""; }; + 5B20430D28BF279900BFC6FD /* vChewingInstaller.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = vChewingInstaller.entitlements; sourceTree = ""; }; 5B21176B287539BB000443A9 /* ctlInputMethod_HandleStates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlInputMethod_HandleStates.swift; sourceTree = ""; }; 5B21176D28753B35000443A9 /* ctlInputMethod_HandleDisplay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlInputMethod_HandleDisplay.swift; sourceTree = ""; }; 5B21176F28753B9D000443A9 /* ctlInputMethod_Delegates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlInputMethod_Delegates.swift; sourceTree = ""; }; @@ -789,6 +792,9 @@ 6A0D4E9215FC0CFA00ABF4B3 = { isa = PBXGroup; children = ( + 5B20430D28BF279900BFC6FD /* vChewingInstaller.entitlements */, + 5B20430C28BEFC1200BFC6FD /* vChewingPhraseEditor.entitlements */, + 5B20430B28BEFC0C00BFC6FD /* vChewing.entitlements */, 5BBD627827B6C4D900271480 /* Update-Info.plist */, 5B18BA7027C7BD8B0056EB19 /* Makefile */, 5B0C5EDE27C7D94C0078037C /* DataCompiler */, @@ -1534,11 +1540,13 @@ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = vChewingPhraseEditor.entitlements; CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 2201; DEAD_CODE_STRIPPING = YES; + ENABLE_HARDENED_RUNTIME = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -1584,11 +1592,13 @@ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = vChewingPhraseEditor.entitlements; CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 2201; DEAD_CODE_STRIPPING = YES; + ENABLE_HARDENED_RUNTIME = YES; ENABLE_NS_ASSERTIONS = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; @@ -1716,6 +1726,7 @@ CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = vChewing.entitlements; CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; @@ -1723,6 +1734,7 @@ DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = ""; + ENABLE_HARDENED_RUNTIME = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; @@ -1773,6 +1785,7 @@ CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = vChewing.entitlements; CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; @@ -1780,6 +1793,7 @@ DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = ""; + ENABLE_HARDENED_RUNTIME = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_TREAT_WARNINGS_AS_ERRORS = YES; @@ -1818,12 +1832,14 @@ CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = vChewingInstaller.entitlements; CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 2201; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = ""; + ENABLE_HARDENED_RUNTIME = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; @@ -1860,12 +1876,14 @@ CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = vChewingInstaller.entitlements; CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 2201; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = ""; + ENABLE_HARDENED_RUNTIME = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_TREAT_WARNINGS_AS_ERRORS = YES; diff --git a/vChewingInstaller.entitlements b/vChewingInstaller.entitlements new file mode 100644 index 00000000..d0c50061 --- /dev/null +++ b/vChewingInstaller.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.files.bookmarks.app-scope + + com.apple.security.temporary-exception.files.home-relative-path.read-write + + /Library/Input Methods/ + + com.apple.security.temporary-exception.shared-preference.read-write + org.atelierInmu.vChewing.vChewingInstaller + + diff --git a/vChewingPhraseEditor.entitlements b/vChewingPhraseEditor.entitlements new file mode 100644 index 00000000..db28c6a8 --- /dev/null +++ b/vChewingPhraseEditor.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.bookmarks.app-scope + + com.apple.security.files.user-selected.read-write + + + From eaefed236c8874869460008c21c2586c70be7ded Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 31 Aug 2022 18:16:41 +0800 Subject: [PATCH 17/20] Repo // Add fixinstall.sh as an alternative fix. --- Installer/pkgTextWarning-CHS.txt | 4 ++-- Installer/pkgTextWarning-CHT.txt | 4 ++-- Installer/pkgTextWarning-ENU.txt | 4 ++-- Installer/pkgTextWarning-JPN.txt | 3 +-- fixinstall.sh | 13 +++++++++++++ vChewing.xcodeproj/project.pbxproj | 4 ++++ 6 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 fixinstall.sh diff --git a/Installer/pkgTextWarning-CHS.txt b/Installer/pkgTextWarning-CHS.txt index ffd3ee37..d7e993be 100644 --- a/Installer/pkgTextWarning-CHS.txt +++ b/Installer/pkgTextWarning-CHS.txt @@ -1,6 +1,6 @@ 注意事项: -一、macOS 10.x-11.x 系统有 Bug、令该安装程式无法自动将安装目标设为当前使用者资料夹。如果您在 macOS 12 Monterey 之前的系统安装该输入法的话,请务必「手动」将安装目的地设为当前使用者资料夹。否则,当您今后(在升级系统之后)升级输入法的时候,可能会出现各种混乱情况。下述 sudo 指令会将任何安装到错误位置的档案全部移除。如果不用 sudo 的话,反而会将安装到正确位置的输入法档案给移除掉,所以请认真使用: - sudo /Users/$(stat -f%Su /dev/console)/Library/Input\ Methods/vChewing.app/Contents/MacOS/vChewing uninstall +一、macOS 10.x-11.x 系统有 Bug、令该安装程式无法自动将安装目标设为当前使用者资料夹。如果您在 macOS 12 Monterey 之前的系统安装该输入法的话,请务必「手动」将安装目的地设为当前使用者资料夹。否则,当您今后(在升级系统之后)升级输入法的时候,可能会出现各种混乱情况。下述 sudo 指令会将任何安装到错误位置的档案全部移除: + sudo bash /Users/$(stat -f%Su /dev/console)/Library/Input\ Methods/vChewing.app/Contents/Resources/fixinstall.sh 二、安装完毕之后,如果输入法无法正常使用的话,请重新登入即可。 diff --git a/Installer/pkgTextWarning-CHT.txt b/Installer/pkgTextWarning-CHT.txt index 08236174..d6d26e0e 100644 --- a/Installer/pkgTextWarning-CHT.txt +++ b/Installer/pkgTextWarning-CHT.txt @@ -1,6 +1,6 @@ 注意事項: -一、macOS 10.x-11.x 系統有 Bug、令該安裝程式無法自動將安裝目標設為當前使用者資料夾。如果您在 macOS 12 Monterey 之前的系統安裝該輸入法的話,請務必「手動」將安裝目的地設為當前使用者資料夾。否則,當您今後(在升級系統之後)升級輸入法的時候,可能會出現各種混亂情況。下述 sudo 指令會將任何安裝到錯誤位置的檔案全部移除。如果不用 sudo 的話,反而會將安裝到正確位置的輸入法檔案給移除掉,所以請認真使用: - sudo /Users/$(stat -f%Su /dev/console)/Library/Input\ Methods/vChewing.app/Contents/MacOS/vChewing uninstall +一、macOS 10.x-11.x 系統有 Bug、令該安裝程式無法自動將安裝目標設為當前使用者資料夾。如果您在 macOS 12 Monterey 之前的系統安裝該輸入法的話,請務必「手動」將安裝目的地設為當前使用者資料夾。否則,當您今後(在升級系統之後)升級輸入法的時候,可能會出現各種混亂情況。下述 sudo 指令會將任何安裝到錯誤位置的檔案全部移除: + sudo bash /Users/$(stat -f%Su /dev/console)/Library/Input\ Methods/vChewing.app/Contents/Resources/fixinstall.sh 二、安裝完畢之後,如果輸入法無法正常使用的話,請重新登入即可。 diff --git a/Installer/pkgTextWarning-ENU.txt b/Installer/pkgTextWarning-ENU.txt index 42fc66ac..6244bc1e 100644 --- a/Installer/pkgTextWarning-ENU.txt +++ b/Installer/pkgTextWarning-ENU.txt @@ -1,6 +1,6 @@ Notice: -1. Due to a bug in macOS 10.x and 11.x, if you are trying to install this input method on macOS releases earlier than macOS 12 Monterey, PLEASE manually choose the install target to the user folder. Otherwise, there will be problems when you are trying to install this input method to later versions when your OS gets upgraded to macOS 12 Monterey or later. The following terminal command can solve such probelems by removing all incorrectly-installed files (must use sudo to avoid the removal of the correctly-installled files): - sudo /Users/$(stat -f%Su /dev/console)/Library/Input\ Methods/vChewing.app/Contents/MacOS/vChewing uninstall +1. Due to a bug in macOS 10.x and 11.x, if you are trying to install this input method on macOS releases earlier than macOS 12 Monterey, PLEASE manually choose the install target to the user folder. Otherwise, there will be problems when you are trying to install this input method to later versions when your OS gets upgraded to macOS 12 Monterey or later. The following terminal command can solve such probelems by removing all incorrectly-installed files (must use sudo): + sudo bash /Users/$(stat -f%Su /dev/console)/Library/Input\ Methods/vChewing.app/Contents/Resources/fixinstall.sh 2. Feel free to logout and re-login if the input method doesn't work after installation. diff --git a/Installer/pkgTextWarning-JPN.txt b/Installer/pkgTextWarning-JPN.txt index e771839b..6ccd740b 100644 --- a/Installer/pkgTextWarning-JPN.txt +++ b/Installer/pkgTextWarning-JPN.txt @@ -1,7 +1,6 @@ ご注意: ● macOS 12 Monterey 以前の OS(macOS 10.x-11.x)のバグのため、macOS 10.x-11.x でインストールする場合、この入力アプリ必ずご自分でユーザーフォルダをインストール先と設定してください。然もないと、いずれ macOS 12 にアップデートし、この入力アプリのもっと新しいバージョンをインストールする時に、予測できない支障が生ずる恐れがあります。下記のターミナル指令を(必ず下記のまま sudo で)実行すれば、この様な支障を解決することができます: - sudo /Users/$(stat -f%Su /dev/console)/Library/Input\ Methods/vChewing.app/Contents/MacOS/vChewing uninstall -⚠︎ 間違ったところへ実装したファイルだけは消されますが、もし sudo 使わずに実行すると、逆に正しく実装されたファイルは消されます。 + sudo bash /Users/$(stat -f%Su /dev/console)/Library/Input\ Methods/vChewing.app/Contents/Resources/fixinstall.sh ● そして、インストール直後、入力アプリがうまく使えない場合、再ログインすれば済ませることです。 diff --git a/fixinstall.sh b/fixinstall.sh new file mode 100644 index 00000000..c1811246 --- /dev/null +++ b/fixinstall.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +# Here's how to fix this input method, removing unnecessary files outside of the user directory: + +sudo rm -rf /Library/Input\ Methods/vChewing.app +sudo rm -rf /Library/Keyboard\ Layouts/vChewingKeyLayout.bundle +sudo rm -rf /Library/Keyboard\ Layouts/vChewing\ MiTAC.keylayout +sudo rm -rf /Library/Keyboard\ Layouts/vChewing\ IBM.keylayout +sudo rm -rf /Library/Keyboard\ Layouts/vChewing\ FakeSeigyou.keylayout +sudo rm -rf /Library/Keyboard\ Layouts/vChewing\ ETen.keylayout +sudo rm -rf /Library/Keyboard\ Layouts/vChewing\ Dachen.keylayout +sudo rm -rf /Library/Receipts/org.atelierInmu.vChewing.bom +sudo rm -rf /Library/Receipts/org.atelierInmu.vChewing.plist diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index 5294da42..962f1b08 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -45,6 +45,7 @@ 5B782EC4280C243C007276DE /* KeyHandler_HandleCandidate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B782EC3280C243C007276DE /* KeyHandler_HandleCandidate.swift */; }; 5B78EE0D28A562B4009456C1 /* suiPrefPaneDevZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B78EE0C28A562B4009456C1 /* suiPrefPaneDevZone.swift */; }; 5B7BC4B027AFFBE800F66C24 /* frmPrefWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B7BC4AE27AFFBE800F66C24 /* frmPrefWindow.xib */; }; + 5B7DA80328BF6BC600D7B2AD /* fixinstall.sh in Resources */ = {isa = PBXBuildFile; fileRef = 5B7DA80228BF6BBA00D7B2AD /* fixinstall.sh */; }; 5B7F225D2808501000DDD3CB /* KeyHandler_HandleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B7F225C2808501000DDD3CB /* KeyHandler_HandleInput.swift */; }; 5B84579E2871AD2200C93B01 /* convdict.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5B84579C2871AD2200C93B01 /* convdict.plist */; }; 5B84579F2871AD2200C93B01 /* HotenkaChineseConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B84579D2871AD2200C93B01 /* HotenkaChineseConverter.swift */; }; @@ -262,6 +263,7 @@ 5B78EE0C28A562B4009456C1 /* suiPrefPaneDevZone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = suiPrefPaneDevZone.swift; sourceTree = ""; }; 5B7BC4AF27AFFBE800F66C24 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/frmPrefWindow.xib; sourceTree = ""; }; 5B7BC4B227AFFC0B00F66C24 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/frmPrefWindow.strings; sourceTree = ""; }; + 5B7DA80228BF6BBA00D7B2AD /* fixinstall.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; lineEnding = 0; path = fixinstall.sh; sourceTree = ""; }; 5B7F225C2808501000DDD3CB /* KeyHandler_HandleInput.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = KeyHandler_HandleInput.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B84579C2871AD2200C93B01 /* convdict.plist */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = convdict.plist; sourceTree = ""; }; 5B84579D2871AD2200C93B01 /* HotenkaChineseConverter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HotenkaChineseConverter.swift; sourceTree = ""; }; @@ -418,6 +420,7 @@ 5B18BA7527C7BF6D0056EB19 /* MiscRootFiles */ = { isa = PBXGroup; children = ( + 5B7DA80228BF6BBA00D7B2AD /* fixinstall.sh */, 5BC2652127E04B7B00700291 /* uninstall.sh */, 5BC447AB2865BEF500EDC323 /* AUTHORS */, 5BE8A8C4281EE65300197741 /* CONTRIBUTING.md */, @@ -1062,6 +1065,7 @@ 5BBBB77427AED70B0023B93A /* MenuIcon-SCVIM@2x.png in Resources */, D4E33D8A27A838CF006DB1CF /* Localizable.strings in Resources */, 5BF9DA2828840E6200DBD48E /* template-exclusions.txt in Resources */, + 5B7DA80328BF6BC600D7B2AD /* fixinstall.sh in Resources */, 5BDCBB2E27B4E67A00D0CC59 /* vChewingPhraseEditor.app in Resources */, 5BBBB76027AED54C0023B93A /* Fart.m4a in Resources */, 6A2E40F6253A69DA00D1AE1D /* Images.xcassets in Resources */, From 582709fd9df72ab4de400270c3fa4a31f79cc9be Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 31 Aug 2022 21:49:25 +0800 Subject: [PATCH 18/20] mgrLM // Move UOM data out of FSEventStreamHelper's sight. --- Source/Modules/LangModelRelated/mgrLangModel.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/Modules/LangModelRelated/mgrLangModel.swift b/Source/Modules/LangModelRelated/mgrLangModel.swift index 8697db08..2886ce3b 100644 --- a/Source/Modules/LangModelRelated/mgrLangModel.swift +++ b/Source/Modules/LangModelRelated/mgrLangModel.swift @@ -285,7 +285,9 @@ enum mgrLangModel { /// - Parameter mode: 簡繁體輸入模式。 /// - Returns: 資料路徑(URL)。 static func userOverrideModelDataURL(_ mode: InputMode) -> URL { - let fileName = (mode == InputMode.imeModeCHT) ? "override-model-data-cht.dat" : "override-model-data-chs.dat" + let fileName = + (mode == InputMode.imeModeCHT) + ? "../vChewing_override-model-data-cht.dat" : "../vChewing_override-model-data-chs.dat" return URL(fileURLWithPath: dataFolderPath(isDefaultFolder: true)).appendingPathComponent(fileName) } From 758774cb0b7738a86be2a761c329a10968cf0e67 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 31 Aug 2022 22:33:31 +0800 Subject: [PATCH 19/20] Update Data - 20220831 --- Source/Data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Data b/Source/Data index 975d8b02..6bf8cdb5 160000 --- a/Source/Data +++ b/Source/Data @@ -1 +1 @@ -Subproject commit 975d8b02cc1c87e83ac71adf9f937dd1cafaa1bb +Subproject commit 6bf8cdb5bfaf9a884b4317b2fa330e37fd9e1cf6 From 1f0e58cf01eec733fcb6e252107b08cbaca68236 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 31 Aug 2022 22:34:01 +0800 Subject: [PATCH 20/20] Bump version to 2.3.0 Golden Master Build 2300. --- Update-Info.plist | 4 ++-- vChewing.pkgproj | 2 +- vChewing.xcodeproj/project.pbxproj | 32 +++++++++++++++--------------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Update-Info.plist b/Update-Info.plist index cfe72764..ecee0f62 100644 --- a/Update-Info.plist +++ b/Update-Info.plist @@ -3,9 +3,9 @@ CFBundleShortVersionString - 2.2.0 + 2.3.0 CFBundleVersion - 2201 + 2300 UpdateInfoEndpoint https://gitee.com/vchewing/vChewing-macOS/raw/main/Update-Info.plist UpdateInfoSite diff --git a/vChewing.pkgproj b/vChewing.pkgproj index b5ce7ea0..3f818c61 100644 --- a/vChewing.pkgproj +++ b/vChewing.pkgproj @@ -726,7 +726,7 @@ USE_HFS+_COMPRESSION VERSION - 2.2.0 + 2.3.0 TYPE 0 diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index 962f1b08..ff7e931f 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -1471,7 +1471,7 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2201; + CURRENT_PROJECT_VERSION = 2300; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -1481,7 +1481,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 2.2.0; + MARKETING_VERSION = 2.3.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewingTests; @@ -1510,13 +1510,13 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2201; + CURRENT_PROJECT_VERSION = 2300; ENABLE_NS_ASSERTIONS = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 2.2.0; + MARKETING_VERSION = 2.3.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewingTests; @@ -1548,7 +1548,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 2201; + CURRENT_PROJECT_VERSION = 2300; DEAD_CODE_STRIPPING = YES; ENABLE_HARDENED_RUNTIME = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -1570,7 +1570,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 2.2.0; + MARKETING_VERSION = 2.3.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor; @@ -1600,7 +1600,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 2201; + CURRENT_PROJECT_VERSION = 2300; DEAD_CODE_STRIPPING = YES; ENABLE_HARDENED_RUNTIME = YES; ENABLE_NS_ASSERTIONS = NO; @@ -1618,7 +1618,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 2.2.0; + MARKETING_VERSION = 2.3.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor; @@ -1734,7 +1734,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 2201; + CURRENT_PROJECT_VERSION = 2300; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = ""; @@ -1763,7 +1763,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 2.2.0; + MARKETING_VERSION = 2.3.0; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1793,7 +1793,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 2201; + CURRENT_PROJECT_VERSION = 2300; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = ""; @@ -1816,7 +1816,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 2.2.0; + MARKETING_VERSION = 2.3.0; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1840,7 +1840,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 2201; + CURRENT_PROJECT_VERSION = 2300; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; @@ -1861,7 +1861,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 2.2.0; + MARKETING_VERSION = 2.3.0; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingInstaller; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1884,7 +1884,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 2201; + CURRENT_PROJECT_VERSION = 2300; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; @@ -1899,7 +1899,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 2.2.0; + MARKETING_VERSION = 2.3.0; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingInstaller; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "";