1.8.7 // Rescue. Merge Gitee PR!73 from dev/bleed

This commit is contained in:
ShikiSuen 2022-08-02 13:49:01 +00:00 committed by Gitee
commit d5f0ed4b6f
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
43 changed files with 781 additions and 411 deletions

View File

@ -97,7 +97,7 @@
- 天權星語彙處理引擎Shiki Suen (MIT-NTL License)。 - 天權星語彙處理引擎Shiki Suen (MIT-NTL License)。
- 威注音詞庫由 Shiki Suen 維護,以 3-Clause BSD License 授權釋出。其中的詞頻數據[由 NAER 授權用於非商業用途](https://twitter.com/ShikiSuen/status/1479329302713831424)。 - 威注音詞庫由 Shiki Suen 維護,以 3-Clause BSD License 授權釋出。其中的詞頻數據[由 NAER 授權用於非商業用途](https://twitter.com/ShikiSuen/status/1479329302713831424)。
使用者可自由使用、散播本軟體,惟散播時必須完整保留版權聲明及軟體授權、且一旦經過修改便不可以再繼續使用威注音的產品名稱。 使用者可自由使用、散播本軟體,惟散播時必須完整保留版權聲明及軟體授權、且一旦經過修改便不可以再繼續使用威注音的產品名稱」。換言之,這條相對上游 MIT 而言新增的規定就是:你 Fork 可以,但 Fork 成單獨發行的產品名稱時就必須修改產品名稱。這條新增規定對 OpenVanilla 與威注音雙方都有益,免得各自的旗號被盜版下載販子等挪用做意外用途
## 資料來源 ## 資料來源

View File

@ -97,7 +97,7 @@
- 天权星语汇处理引擎Shiki Suen (MIT-NTL License)。 - 天权星语汇处理引擎Shiki Suen (MIT-NTL License)。
- 威注音词库由 Shiki Suen 维护,以 3-Clause BSD License 授权释出。其中的词频数据[由 NAER 授权用于非商业用途](https://twitter.com/ShikiSuen/status/1479329302713831424)。 - 威注音词库由 Shiki Suen 维护,以 3-Clause BSD License 授权释出。其中的词频数据[由 NAER 授权用于非商业用途](https://twitter.com/ShikiSuen/status/1479329302713831424)。
使用者可自由使用、散播本软件,惟散播时必须完整保留版权声明及软件授权、且一旦经过修改便不可以再继续使用威注音的产品名称。 使用者可自由使用、散播本软件,惟散播时必须完整保留版权声明及软件授权、且一旦经过修改便不可以再继续使用威注音的产品名称」。换言之,这条相对上游 MIT 而言新增的规定就是:你 Fork 可以,但 Fork 成单独发行的产品名称时就必须修改产品名称。这条新增规定对 OpenVanilla 与威注音双方都有益,免得各自的旗号被盗版下载贩子等挪用做意外用途
## 资料来源 ## 资料来源

@ -1 +1 @@
Subproject commit 30a5bc773a21d67c3f117eef5346d3b35433bbaa Subproject commit 144db528de84caff0fa20802b144421bcc58419f

View File

@ -29,7 +29,7 @@ import InputMethodKit
@objc(AppDelegate) @objc(AppDelegate)
class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelegate, class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelegate,
FSEventStreamHelperDelegate FSEventStreamHelperDelegate, NSUserNotificationCenterDelegate
{ {
func helper(_: FSEventStreamHelper, didReceive _: [FSEventStreamHelper.Event]) { func helper(_: FSEventStreamHelper, didReceive _: [FSEventStreamHelper.Event]) {
// 100ms 使使 // 100ms 使使
@ -63,7 +63,25 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega
fsStreamHelper.delegate = nil fsStreamHelper.delegate = nil
} }
func userNotificationCenter(_: NSUserNotificationCenter, shouldPresent _: NSUserNotification) -> Bool {
return true
}
func applicationDidFinishLaunching(_: Notification) { func applicationDidFinishLaunching(_: Notification) {
NSUserNotificationCenter.default.delegate = self
// 使
if mgrPrefs.failureFlagForUOMObservation {
mgrLangModel.clearUserOverrideModelData(.imeModeCHS)
mgrLangModel.clearUserOverrideModelData(.imeModeCHT)
mgrPrefs.failureFlagForUOMObservation = false
let userNotification = NSUserNotification()
userNotification.title = NSLocalizedString("vChewing", comment: "")
userNotification.informativeText =
"\(NSLocalizedString("vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability.", comment: ""))"
userNotification.soundName = NSUserNotificationDefaultSoundName
NSUserNotificationCenter.default.deliver(userNotification)
}
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) {
IME.initLangModels(userOnly: false) IME.initLangModels(userOnly: false)
} }

View File

@ -29,7 +29,7 @@ import Cocoa
// InputState 使 Struct Struct // InputState 使 Struct Struct
// enum // enum
enum StateType { public enum StateType {
case ofDeactivated case ofDeactivated
case ofAssociatedPhrases case ofAssociatedPhrases
case ofEmpty case ofEmpty
@ -38,12 +38,12 @@ enum StateType {
case ofNotEmpty case ofNotEmpty
case ofInputting case ofInputting
case ofMarking case ofMarking
case ofChooseCandidate case ofChoosingCandidate
case ofSymbolTable case ofSymbolTable
} }
// InputState // InputState
protocol InputStateProtocol { public protocol InputStateProtocol {
var type: StateType { get } var type: StateType { get }
} }
@ -79,7 +79,7 @@ protocol InputStateProtocol {
/// ///
/// - .ChoosingCandidate: 使 /// - .ChoosingCandidate: 使
/// - .SymbolTable: /// - .SymbolTable:
enum InputState { public enum InputState {
/// .Deactivated: 使使 /// .Deactivated: 使使
class Deactivated: InputStateProtocol { class Deactivated: InputStateProtocol {
public var type: StateType { .ofDeactivated } public var type: StateType { .ofDeactivated }
@ -175,6 +175,8 @@ enum InputState {
public var type: StateType { .ofNotEmpty } public var type: StateType { .ofNotEmpty }
private(set) var composingBuffer: String private(set) var composingBuffer: String
private(set) var cursorIndex: Int = 0 { didSet { cursorIndex = max(cursorIndex, 0) } } private(set) var cursorIndex: Int = 0 { didSet { cursorIndex = max(cursorIndex, 0) } }
private(set) var reading: String = ""
private(set) var nodeValuesArray = [String]()
public var composingBufferConverted: String { public var composingBufferConverted: String {
let converted = IME.kanjiConversionIfRequired(composingBuffer) let converted = IME.kanjiConversionIfRequired(composingBuffer)
if converted.utf16.count != composingBuffer.utf16.count if converted.utf16.count != composingBuffer.utf16.count
@ -185,21 +187,39 @@ enum InputState {
return converted return converted
} }
init(composingBuffer: String, cursorIndex: Int) { init(composingBuffer: String, cursorIndex: Int, reading: String = "", nodeValuesArray: [String] = []) {
self.composingBuffer = composingBuffer self.composingBuffer = composingBuffer
self.reading = reading
self.nodeValuesArray = nodeValuesArray
defer { self.cursorIndex = cursorIndex } defer { self.cursorIndex = cursorIndex }
} }
var attributedString: NSMutableAttributedString { var attributedString: NSMutableAttributedString {
/// ///
/// JIS /// JIS
let attributedString = NSMutableAttributedString( guard reading.isEmpty else {
string: composingBufferConverted, let attributedString = NSMutableAttributedString(
attributes: [ string: composingBufferConverted,
.underlineStyle: NSUnderlineStyle.single.rawValue, attributes: [
.markedClauseSegment: 0, /// .thick
] .underlineStyle: NSUnderlineStyle.single.rawValue,
) .markedClauseSegment: 0,
]
)
return attributedString
}
let attributedString = NSMutableAttributedString(string: composingBufferConverted)
var newBegin = 0
for (i, neta) in nodeValuesArray.enumerated() {
attributedString.setAttributes(
[
/// .thick
.underlineStyle: NSUnderlineStyle.single.rawValue,
.markedClauseSegment: i,
], range: NSRange(location: newBegin, length: neta.utf16.count)
)
newBegin += neta.utf16.count
}
return attributedString return attributedString
} }
@ -216,8 +236,9 @@ enum InputState {
var textToCommit: String = "" var textToCommit: String = ""
var tooltip: String = "" var tooltip: String = ""
override init(composingBuffer: String, cursorIndex: Int) { override init(composingBuffer: String, cursorIndex: Int, reading: String = "", nodeValuesArray: [String] = []) {
super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex) super.init(
composingBuffer: composingBuffer, cursorIndex: cursorIndex, reading: reading, nodeValuesArray: nodeValuesArray)
} }
override var description: String { override var description: String {
@ -264,9 +285,9 @@ enum InputState {
private var deleteTargetExists = false private var deleteTargetExists = false
var tooltip: String { var tooltip: String {
if composingBuffer.count != readings.count { if composingBuffer.count != readings.count {
ctlInputMethod.tooltipController.setColor(state: .redAlert) ctlInputMethod.tooltipController.setColor(state: .denialOverflow)
return NSLocalizedString( return NSLocalizedString(
"⚠︎ Unhandlable: Chars and Readings in buffer doesn't match.", comment: "" "⚠︎ Beware: Chars and Readings in buffer doesn't match.", comment: ""
) )
} }
if mgrPrefs.phraseReplacementEnabled { if mgrPrefs.phraseReplacementEnabled {
@ -376,14 +397,9 @@ enum InputState {
} }
var validToWrite: Bool { var validToWrite: Bool {
/// The input method allows users to input a string whose length differs ///
/// from the amount of Bopomofo readings. In this case, the range /// deleteTargetExists 使
/// in the composing buffer and the readings could not match, so (ctlInputMethod.areWeDeleting && !deleteTargetExists)
/// we disable the function to write user phrases in this case.
/// deleteTargetExists 使
/// 使
((composingBuffer.count != readings.count)
|| (ctlInputMethod.areWeDeleting && !deleteTargetExists))
? false ? false
: allowedMarkRange.contains(literalMarkedRange.count) : allowedMarkRange.contains(literalMarkedRange.count)
} }
@ -418,7 +434,7 @@ enum InputState {
/// .ChoosingCandidate: 使 /// .ChoosingCandidate: 使
class ChoosingCandidate: NotEmpty { class ChoosingCandidate: NotEmpty {
override public var type: StateType { .ofChooseCandidate } override public var type: StateType { .ofChoosingCandidate }
private(set) var candidates: [(String, String)] private(set) var candidates: [(String, String)]
private(set) var isTypingVertical: Bool private(set) var isTypingVertical: Bool

View File

@ -34,10 +34,10 @@ import Cocoa
/// KeyHandler /// KeyHandler
protocol KeyHandlerDelegate { protocol KeyHandlerDelegate {
func ctlCandidate() -> ctlCandidate func ctlCandidate() -> ctlCandidateProtocol
func keyHandler( func keyHandler(
_: KeyHandler, didSelectCandidateAt index: Int, _: KeyHandler, didSelectCandidateAt index: Int,
ctlCandidate controller: ctlCandidate ctlCandidate controller: ctlCandidateProtocol
) )
func keyHandler(_ keyHandler: KeyHandler, didRequestWriteUserPhraseWith state: InputStateProtocol) func keyHandler(_ keyHandler: KeyHandler, didRequestWriteUserPhraseWith state: InputStateProtocol)
-> Bool -> Bool
@ -46,9 +46,11 @@ protocol KeyHandlerDelegate {
// MARK: - (Kernel). // MARK: - (Kernel).
/// KeyHandler 調 /// KeyHandler 調
class KeyHandler { public class KeyHandler {
/// ///
let kEpsilon: Double = 0.000001 let kEpsilon: Double = 0.000001
///
var isCursorCuttingChar = false
/// ///
let kMaxComposingBufferNeedsToWalkSize = Int(max(12, ceil(Double(mgrPrefs.composingBufferSize) / 2))) let kMaxComposingBufferNeedsToWalkSize = Int(max(12, ceil(Double(mgrPrefs.composingBufferSize) / 2)))
@ -182,14 +184,20 @@ class KeyHandler {
addToUserOverrideModel = false addToUserOverrideModel = false
} }
} }
if addToUserOverrideModel { if addToUserOverrideModel, mgrPrefs.fetchSuggestionsFromUserOverrideModel {
IME.prtDebugIntel("UOM: Start Observation.") IME.prtDebugIntel("UOM: Start Observation.")
// 使
//
// AppDelegate
mgrPrefs.failureFlagForUOMObservation = true
// //
// //
currentUOM.observe( currentUOM.observe(
walkedAnchors: walkedAnchors, cursorIndex: adjustedCursor, candidate: theCandidate.value, walkedAnchors: walkedAnchors, cursorIndex: adjustedCursor, candidate: theCandidate.value,
timestamp: NSDate().timeIntervalSince1970, saveCallback: { mgrLangModel.saveUserOverrideModelData() } timestamp: NSDate().timeIntervalSince1970, saveCallback: { mgrLangModel.saveUserOverrideModelData() }
) )
//
mgrPrefs.failureFlagForUOMObservation = false
} }
} }

View File

@ -46,7 +46,7 @@ extension KeyHandler {
) -> Bool { ) -> Bool {
let inputText = input.inputText let inputText = input.inputText
let charCode: UniChar = input.charCode let charCode: UniChar = input.charCode
guard let ctlCandidateCurrent = delegate?.ctlCandidate() else { guard var ctlCandidateCurrent = delegate?.ctlCandidate() else {
IME.prtDebugIntel("06661F6E") IME.prtDebugIntel("06661F6E")
errorCallback() errorCallback()
return true return true
@ -69,6 +69,7 @@ extension KeyHandler {
// compositor.isEmpty // compositor.isEmpty
clear() clear()
stateCallback(InputState.EmptyIgnoringPreviousState()) stateCallback(InputState.EmptyIgnoringPreviousState())
stateCallback(InputState.Empty())
} else { } else {
stateCallback(buildInputtingState) stateCallback(buildInputtingState)
} }
@ -84,6 +85,7 @@ extension KeyHandler {
if state is InputState.AssociatedPhrases, !mgrPrefs.alsoConfirmAssociatedCandidatesByEnter { if state is InputState.AssociatedPhrases, !mgrPrefs.alsoConfirmAssociatedCandidatesByEnter {
clear() clear()
stateCallback(InputState.EmptyIgnoringPreviousState()) stateCallback(InputState.EmptyIgnoringPreviousState())
stateCallback(InputState.Empty())
return true return true
} }
delegate?.keyHandler( delegate?.keyHandler(
@ -293,14 +295,12 @@ extension KeyHandler {
let match: String = let match: String =
(state is InputState.AssociatedPhrases) ? input.inputTextIgnoringModifiers ?? "" : inputText (state is InputState.AssociatedPhrases) ? input.inputTextIgnoringModifiers ?? "" : inputText
var j = 0 for j in 0..<ctlCandidateCurrent.keyLabels.count {
while j < ctlCandidateCurrent.keyLabels.count {
let label: CandidateKeyLabel = ctlCandidateCurrent.keyLabels[j] let label: CandidateKeyLabel = ctlCandidateCurrent.keyLabels[j]
if match.compare(label.key, options: .caseInsensitive, range: nil, locale: .current) == .orderedSame { if match.compare(label.key, options: .caseInsensitive, range: nil, locale: .current) == .orderedSame {
index = j index = j
break break
} }
j += 1
} }
if index != NSNotFound { if index != NSNotFound {
@ -352,10 +352,10 @@ extension KeyHandler {
ctlCandidate: ctlCandidateCurrent ctlCandidate: ctlCandidateCurrent
) )
clear() clear()
let empty = InputState.EmptyIgnoringPreviousState() stateCallback(InputState.EmptyIgnoringPreviousState())
stateCallback(empty) stateCallback(InputState.Empty())
return handle( return handle(
input: input, state: empty, stateCallback: stateCallback, errorCallback: errorCallback input: input, state: InputState.Empty(), stateCallback: stateCallback, errorCallback: errorCallback
) )
} }
return true return true

View File

@ -30,17 +30,14 @@ extension KeyHandler {
/// KeyHandler.HandleInput() /// KeyHandler.HandleInput()
/// - Parameters: /// - Parameters:
/// - input: /// - input:
/// - state:
/// - stateCallback: /// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: IMK /// - Returns: IMK
func handleComposition( func handleComposition(
input: InputSignal, input: InputSignal,
state: InputStateProtocol,
stateCallback: @escaping (InputStateProtocol) -> Void, stateCallback: @escaping (InputStateProtocol) -> Void,
errorCallback: @escaping () -> Void errorCallback: @escaping () -> Void
) -> Bool? { ) -> Bool? {
// MARK: (Handle BPMF Keys) // MARK: (Handle BPMF Keys)
var keyConsumedByReading = false var keyConsumedByReading = false
@ -63,7 +60,7 @@ extension KeyHandler {
} }
} }
var composeReading = composer.hasToneMarker() // var composeReading = composer.hasToneMarker() && composer.inputValidityCheck(key: input.charCode) //
// Enter Space _composer // Enter Space _composer
// |= // |=
@ -81,9 +78,21 @@ extension KeyHandler {
if !currentLM.hasUnigramsFor(key: readingKey) { if !currentLM.hasUnigramsFor(key: readingKey) {
IME.prtDebugIntel("B49C0979語彙庫內無「\(readingKey)」的匹配記錄。") IME.prtDebugIntel("B49C0979語彙庫內無「\(readingKey)」的匹配記錄。")
errorCallback() errorCallback()
if mgrPrefs.keepReadingUponCompositionError {
composer.intonation.clear() // 調
stateCallback(buildInputtingState)
return true
}
composer.clear() composer.clear()
// //
stateCallback((compositor.isEmpty) ? InputState.EmptyIgnoringPreviousState() : buildInputtingState) switch compositor.isEmpty {
case false: stateCallback(buildInputtingState)
case true:
stateCallback(InputState.EmptyIgnoringPreviousState())
stateCallback(InputState.Empty())
}
return true // IMK return true // IMK
} }
@ -141,9 +150,7 @@ extension KeyHandler {
return true return true
} }
/// true 調調 /// 調
/// 6jˊˊ調
/// 調ˊˊˊˊˇˊ
if keyConsumedByReading { if keyConsumedByReading {
// updateClientComposingBuffer() // updateClientComposingBuffer()
stateCallback(buildInputtingState) stateCallback(buildInputtingState)

View File

@ -159,8 +159,8 @@ extension KeyHandler {
// MARK: (Handle BPMF Keys) // MARK: (Handle BPMF Keys)
if let compositionHandled = handleComposition( if let compositionHandled = handleComposition(
input: input, state: state, stateCallback: stateCallback, errorCallback: errorCallback) input: input, stateCallback: stateCallback, errorCallback: errorCallback
{ ) {
return compositionHandled return compositionHandled
} }

View File

@ -38,7 +38,7 @@ extension KeyHandler {
/// (Update the composing buffer) /// (Update the composing buffer)
/// NSAttributeString /// NSAttributeString
var tooltipParameterRef: [String] = ["", ""] var tooltipParameterRef: [String] = ["", ""]
var composingBuffer = "" let nodeValuesArray: [String] = walkedAnchors.map(\.node.currentPair.value)
var composedStringCursorIndex = 0 var composedStringCursorIndex = 0
var readingCursorIndex = 0 var readingCursorIndex = 0
/// IMK UTF8 emoji /// IMK UTF8 emoji
@ -47,7 +47,6 @@ extension KeyHandler {
for theAnchor in walkedAnchors { for theAnchor in walkedAnchors {
let theNode = theAnchor.node let theNode = theAnchor.node
let strNodeValue = theNode.currentPair.value let strNodeValue = theNode.currentPair.value
composingBuffer += strNodeValue
let arrSplit: [String] = Array(strNodeValue).map { String($0) } let arrSplit: [String] = Array(strNodeValue).map { String($0) }
let codepointCount = arrSplit.count let codepointCount = arrSplit.count
/// ///
@ -57,57 +56,45 @@ extension KeyHandler {
if readingCursorIndex + spanningLength <= compositor.cursor { if readingCursorIndex + spanningLength <= compositor.cursor {
composedStringCursorIndex += strNodeValue.utf16.count composedStringCursorIndex += strNodeValue.utf16.count
readingCursorIndex += spanningLength readingCursorIndex += spanningLength
} else { continue
if codepointCount == spanningLength { }
var i = 0 if codepointCount == spanningLength {
while i < codepointCount, readingCursorIndex < compositor.cursor { for i in 0..<codepointCount {
composedStringCursorIndex += arrSplit[i].utf16.count guard readingCursorIndex < compositor.cursor else { continue }
readingCursorIndex += 1 composedStringCursorIndex += arrSplit[i].utf16.count
i += 1 readingCursorIndex += 1
}
} else {
if readingCursorIndex < compositor.cursor {
composedStringCursorIndex += strNodeValue.utf16.count
readingCursorIndex += spanningLength
readingCursorIndex = min(readingCursorIndex, compositor.cursor)
///
///
///
///
///
switch compositor.cursor {
case compositor.readings.count...:
// compositor.cursor readings.count Megrez
tooltipParameterRef[0] = compositor.readings[compositor.cursor - 1]
case 0:
tooltipParameterRef[1] = compositor.readings[compositor.cursor]
default:
tooltipParameterRef[0] = compositor.readings[compositor.cursor - 1]
tooltipParameterRef[1] = compositor.readings[compositor.cursor]
}
///
for (i, _) in tooltipParameterRef.enumerated() {
if tooltipParameterRef[i].isEmpty { continue }
if tooltipParameterRef[i].contains("_") { continue }
if mgrPrefs.showHanyuPinyinInCompositionBuffer { // ->->調
tooltipParameterRef[i] = Tekkon.restoreToneOneInZhuyinKey(target: tooltipParameterRef[i])
tooltipParameterRef[i] = Tekkon.cnvPhonaToHanyuPinyin(target: tooltipParameterRef[i])
tooltipParameterRef[i] = Tekkon.cnvHanyuPinyinToTextbookStyle(target: tooltipParameterRef[i])
} else {
tooltipParameterRef[i] = Tekkon.cnvZhuyinChainToTextbookReading(target: tooltipParameterRef[i])
}
}
}
} }
continue
}
guard readingCursorIndex < compositor.cursor else { continue }
composedStringCursorIndex += strNodeValue.utf16.count
readingCursorIndex += spanningLength
readingCursorIndex = min(readingCursorIndex, compositor.cursor)
///
///
///
///
///
switch compositor.cursor {
case compositor.readings.count...:
// compositor.cursor readings.count Megrez
tooltipParameterRef[0] = compositor.readings[compositor.cursor - 1]
case 0:
tooltipParameterRef[1] = compositor.readings[compositor.cursor]
default:
tooltipParameterRef[0] = compositor.readings[compositor.cursor - 1]
tooltipParameterRef[1] = compositor.readings[compositor.cursor]
} }
} }
isCursorCuttingChar = !tooltipParameterRef[0].isEmpty || !tooltipParameterRef[1].isEmpty
/// ///
/// 便 composer /// 便 composer
var arrHead = [String.UTF16View.Element]() var arrHead = [String.UTF16View.Element]()
var arrTail = [String.UTF16View.Element]() var arrTail = [String.UTF16View.Element]()
for (i, n) in composingBuffer.utf16.enumerated() { for (i, n) in nodeValuesArray.joined().utf16.enumerated() {
if i < composedStringCursorIndex { if i < composedStringCursorIndex {
arrHead.append(n) arrHead.append(n)
} else { } else {
@ -126,42 +113,16 @@ extension KeyHandler {
// //
var cleanedComposition = "" var cleanedComposition = ""
for theChar in composedText { for theChar in composedText {
if let charCode = theChar.utf16.first { guard let charCode = theChar.utf16.first else { continue }
if !(theChar.isASCII && !(charCode.isPrintable)) { if !(theChar.isASCII && !(charCode.isPrintable)) {
cleanedComposition += String(theChar) cleanedComposition += String(theChar)
}
} }
} }
/// 使 /// 使
let stateResult = InputState.Inputting(composingBuffer: cleanedComposition, cursorIndex: cursorIndex) return InputState.Inputting(
composingBuffer: cleanedComposition, cursorIndex: cursorIndex, reading: reading, nodeValuesArray: nodeValuesArray
/// )
switch (tooltipParameterRef[0].isEmpty, tooltipParameterRef[1].isEmpty) {
case (true, true): stateResult.tooltip.removeAll()
case (true, false):
stateResult.tooltip = String(
format: NSLocalizedString("Cursor is to the rear of \"%@\".", comment: ""),
tooltipParameterRef[1]
)
case (false, true):
stateResult.tooltip = String(
format: NSLocalizedString("Cursor is in front of \"%@\".", comment: ""),
tooltipParameterRef[0]
)
case (false, false):
stateResult.tooltip = String(
format: NSLocalizedString("Cursor is between \"%@\" and \"%@\".", comment: ""),
tooltipParameterRef[0], tooltipParameterRef[1]
)
}
///
if !stateResult.tooltip.isEmpty {
ctlInputMethod.tooltipController.setColor(state: .denialOverflow)
}
return stateResult
} }
// MARK: - // MARK: -
@ -459,8 +420,12 @@ extension KeyHandler {
composer.doBackSpace() composer.doBackSpace()
} }
stateCallback( switch composer.isEmpty && compositor.isEmpty {
composer.isEmpty && compositor.isEmpty ? InputState.EmptyIgnoringPreviousState() : buildInputtingState) case false: stateCallback(buildInputtingState)
case true:
stateCallback(InputState.EmptyIgnoringPreviousState())
stateCallback(InputState.Empty())
}
return true return true
} }
@ -497,7 +462,12 @@ extension KeyHandler {
walk() walk()
let inputting = buildInputtingState let inputting = buildInputtingState
// count > 0!isEmpty滿 // count > 0!isEmpty滿
stateCallback(inputting.composingBuffer.isEmpty ? InputState.EmptyIgnoringPreviousState() : inputting) switch inputting.composingBuffer.isEmpty {
case false: stateCallback(inputting)
case true:
stateCallback(InputState.EmptyIgnoringPreviousState())
stateCallback(InputState.Empty())
}
return true return true
} }
@ -609,11 +579,17 @@ extension KeyHandler {
/// macOS Windows 使 /// macOS Windows 使
clear() clear()
stateCallback(InputState.EmptyIgnoringPreviousState()) stateCallback(InputState.EmptyIgnoringPreviousState())
stateCallback(InputState.Empty())
} else { } else {
if composer.isEmpty { return true } if composer.isEmpty { return true }
/// ///
composer.clear() composer.clear()
stateCallback(compositor.isEmpty ? InputState.EmptyIgnoringPreviousState() : buildInputtingState) switch compositor.isEmpty {
case false: stateCallback(buildInputtingState)
case true:
stateCallback(InputState.EmptyIgnoringPreviousState())
stateCallback(InputState.Empty())
}
} }
return true return true
} }
@ -661,6 +637,7 @@ extension KeyHandler {
stateCallback(state) stateCallback(state)
} }
} else if input.isOptionHold { } else if input.isOptionHold {
isCursorCuttingChar = false
if input.isControlHold { if input.isControlHold {
return handleEnd(state: state, stateCallback: stateCallback, errorCallback: errorCallback) return handleEnd(state: state, stateCallback: stateCallback, errorCallback: errorCallback)
} }
@ -675,7 +652,12 @@ extension KeyHandler {
} else { } else {
if compositor.cursor < compositor.length { if compositor.cursor < compositor.length {
compositor.cursor += 1 compositor.cursor += 1
stateCallback(buildInputtingState) var inputtingState = buildInputtingState
if isCursorCuttingChar == true {
compositor.jumpCursorBySpan(to: .front)
inputtingState = buildInputtingState
}
stateCallback(inputtingState)
} else { } else {
IME.prtDebugIntel("A96AAD58") IME.prtDebugIntel("A96AAD58")
errorCallback() errorCallback()
@ -729,6 +711,7 @@ extension KeyHandler {
stateCallback(state) stateCallback(state)
} }
} else if input.isOptionHold { } else if input.isOptionHold {
isCursorCuttingChar = false
if input.isControlHold { if input.isControlHold {
return handleHome(state: state, stateCallback: stateCallback, errorCallback: errorCallback) return handleHome(state: state, stateCallback: stateCallback, errorCallback: errorCallback)
} }
@ -743,7 +726,12 @@ extension KeyHandler {
} else { } else {
if compositor.cursor > 0 { if compositor.cursor > 0 {
compositor.cursor -= 1 compositor.cursor -= 1
stateCallback(buildInputtingState) var inputtingState = buildInputtingState
if isCursorCuttingChar == true {
compositor.jumpCursorBySpan(to: .rear)
inputtingState = buildInputtingState
}
stateCallback(inputtingState)
} else { } else {
IME.prtDebugIntel("7045E6F3") IME.prtDebugIntel("7045E6F3")
errorCallback() errorCallback()

View File

@ -41,7 +41,7 @@ class ctlInputMethod: IMKInputController {
static var areWeDeleting = false static var areWeDeleting = false
/// ///
static var ctlCandidateCurrent = ctlCandidateUniversal.init(.horizontal) static var ctlCandidateCurrent: ctlCandidateProtocol = ctlCandidateUniversal.init(.horizontal)
/// ///
static let tooltipController = TooltipController() static let tooltipController = TooltipController()
@ -85,6 +85,7 @@ class ctlInputMethod: IMKInputController {
keyHandler.delegate = self keyHandler.delegate = self
// //
activateServer(inputClient) activateServer(inputClient)
keyHandler.ensureParser()
resetKeyHandler() resetKeyHandler()
} }
@ -99,7 +100,7 @@ class ctlInputMethod: IMKInputController {
// activateServer nil // activateServer nil
// //
if keyHandler.delegate == nil { keyHandler.delegate = self } if keyHandler.delegate == nil { keyHandler.delegate = self }
setValue(IME.currentInputMode.rawValue, forTag: 114514, client: client())
keyHandler.clear() keyHandler.clear()
keyHandler.ensureParser() keyHandler.ensureParser()
@ -236,4 +237,30 @@ class ctlInputMethod: IMKInputController {
_ = sender // _ = sender //
resetKeyHandler() resetKeyHandler()
} }
/// IMK
/// - Parameter sender: 使
/// - Returns: IMK
override func candidates(_ sender: Any!) -> [Any]! {
_ = sender //
if let state = state as? InputState.AssociatedPhrases {
return state.candidates.map { theCandidate -> String in
let theConverted = IME.kanjiConversionIfRequired(theCandidate.1)
return (theCandidate.1 == theConverted) ? theCandidate.1 : "\(theConverted)(\(theCandidate.1))"
}
}
if let state = state as? InputState.ChoosingCandidate {
return state.candidates.map { theCandidate -> String in
let theConverted = IME.kanjiConversionIfRequired(theCandidate.1)
return (theCandidate.1 == theConverted) ? theCandidate.1 : "\(theConverted)(\(theCandidate.1))"
}
}
if let state = state as? InputState.SymbolTable {
return state.candidates.map { theCandidate -> String in
let theConverted = IME.kanjiConversionIfRequired(theCandidate.1)
return (theCandidate.1 == theConverted) ? theCandidate.1 : "\(theConverted)(\(theCandidate.1))"
}
}
return .init()
}
} }

View File

@ -24,16 +24,16 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
import Foundation import Cocoa
// MARK: - KeyHandler Delegate // MARK: - KeyHandler Delegate
extension ctlInputMethod: KeyHandlerDelegate { extension ctlInputMethod: KeyHandlerDelegate {
func ctlCandidate() -> ctlCandidate { ctlInputMethod.ctlCandidateCurrent } func ctlCandidate() -> ctlCandidateProtocol { ctlInputMethod.ctlCandidateCurrent }
func keyHandler( func keyHandler(
_: KeyHandler, didSelectCandidateAt index: Int, _: KeyHandler, didSelectCandidateAt index: Int,
ctlCandidate controller: ctlCandidate ctlCandidate controller: ctlCandidateProtocol
) { ) {
ctlCandidate(controller, didSelectCandidateAtIndex: index) ctlCandidate(controller, didSelectCandidateAtIndex: index)
} }
@ -70,7 +70,54 @@ extension ctlInputMethod: KeyHandlerDelegate {
// MARK: - Candidate Controller Delegate // MARK: - Candidate Controller Delegate
extension ctlInputMethod: ctlCandidateDelegate { extension ctlInputMethod: ctlCandidateDelegate {
func candidateCountForController(_ controller: ctlCandidate) -> Int { func handleDelegateEvent(_ event: NSEvent!) -> Bool {
/// flags使 KeyHandler
/// flags
/// event.type == .flagsChanged return false
/// NSInternalInconsistencyException
if event.type == .flagsChanged {
return false
}
// Enter
ctlInputMethod.areWeDeleting = event.modifierFlags.contains([.shift, .command])
var textFrame = NSRect.zero
let attributes: [AnyHashable: Any]? = client().attributes(
forCharacterIndex: 0, lineHeightRectangle: &textFrame
)
let isTypingVertical =
(attributes?["IMKTextOrientation"] as? NSNumber)?.intValue == 0 || false
if client().bundleIdentifier()
== "org.atelierInmu.vChewing.vChewingPhraseEditor"
{
IME.areWeUsingOurOwnPhraseEditor = true
} else {
IME.areWeUsingOurOwnPhraseEditor = false
}
let input = InputSignal(event: event, isVerticalTyping: isTypingVertical)
//
// KeyHandler
if !input.charCode.isPrintable {
return false
}
/// 調
/// result bool IMK
let result = keyHandler.handleCandidate(state: state, input: input) { newState in
self.handle(state: newState)
} errorCallback: {
clsSFX.beep()
}
return result
}
func candidateCountForController(_ controller: ctlCandidateProtocol) -> Int {
_ = controller // _ = controller //
if let state = state as? InputState.ChoosingCandidate { if let state = state as? InputState.ChoosingCandidate {
return state.candidates.count return state.candidates.count
@ -80,7 +127,20 @@ extension ctlInputMethod: ctlCandidateDelegate {
return 0 return 0
} }
func ctlCandidate(_ controller: ctlCandidate, candidateAtIndex index: Int) ///
/// - Parameter controller:
/// - Returns:
func candidatesForController(_ controller: ctlCandidateProtocol) -> [(String, String)] {
_ = controller //
if let state = state as? InputState.ChoosingCandidate {
return state.candidates
} else if let state = state as? InputState.AssociatedPhrases {
return state.candidates
}
return .init()
}
func ctlCandidate(_ controller: ctlCandidateProtocol, candidateAtIndex index: Int)
-> (String, String) -> (String, String)
{ {
_ = controller // _ = controller //
@ -92,7 +152,7 @@ extension ctlInputMethod: ctlCandidateDelegate {
return ("", "") return ("", "")
} }
func ctlCandidate(_ controller: ctlCandidate, didSelectCandidateAtIndex index: Int) { func ctlCandidate(_ controller: ctlCandidateProtocol, didSelectCandidateAtIndex index: Int) {
_ = controller // _ = controller //
if let state = state as? InputState.SymbolTable, if let state = state as? InputState.SymbolTable,

View File

@ -81,11 +81,11 @@ extension ctlInputMethod {
/// macOS 10.x SwiftUI /// macOS 10.x SwiftUI
if isCandidateWindowVertical { // 使 if isCandidateWindowVertical { // 使
ctlInputMethod.ctlCandidateCurrent = .init(.vertical) ctlInputMethod.ctlCandidateCurrent = ctlCandidateUniversal.init(.vertical)
} else if mgrPrefs.useHorizontalCandidateList { } else if mgrPrefs.useHorizontalCandidateList {
ctlInputMethod.ctlCandidateCurrent = .init(.horizontal) ctlInputMethod.ctlCandidateCurrent = ctlCandidateUniversal.init(.horizontal)
} else { } else {
ctlInputMethod.ctlCandidateCurrent = .init(.vertical) ctlInputMethod.ctlCandidateCurrent = ctlCandidateUniversal.init(.vertical)
} }
// set the attributes for the candidate panel (which uses NSAttributedString) // set the attributes for the candidate panel (which uses NSAttributedString)
@ -100,12 +100,22 @@ extension ctlInputMethod {
} }
func candidateFont(name: String?, size: CGFloat) -> NSFont { func candidateFont(name: String?, size: CGFloat) -> NSFont {
let currentMUIFont = var finalReturnFont: NSFont =
(keyHandler.inputMode == InputMode.imeModeCHS) {
? "Sarasa Term Slab SC" : "Sarasa Term Slab TC" switch IME.currentInputMode {
var finalReturnFont = case InputMode.imeModeCHS:
NSFont(name: currentMUIFont, size: size) ?? NSFont.systemFont(ofSize: size) return CTFontCreateUIFontForLanguage(.system, size, "zh-Hans" as CFString)
// macOS 11 Big Sur macOS 12 Monterey 使 case InputMode.imeModeCHT:
return (mgrPrefs.shiftJISShinjitaiOutputEnabled || mgrPrefs.chineseConversionEnabled)
? CTFontCreateUIFontForLanguage(.system, size, "ja" as CFString)
: CTFontCreateUIFontForLanguage(.system, size, "zh-Hant" as CFString)
default:
return CTFontCreateUIFontForLanguage(.system, size, nil)
}
}()
?? NSFont.systemFont(ofSize: size)
// macOS 10.11-10.15 macOS 12 Monterey Bug
// macOS 12 Monterey ctlCandidateUniversal
if #available(macOS 12.0, *) { finalReturnFont = NSFont.systemFont(ofSize: size) } if #available(macOS 12.0, *) { finalReturnFont = NSFont.systemFont(ofSize: size) }
if let name = name { if let name = name {
return NSFont(name: name, size: size) ?? finalReturnFont return NSFont(name: name, size: size) ?? finalReturnFont

View File

@ -26,56 +26,58 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import Cocoa import Cocoa
struct UserDef { public enum UserDef: String, CaseIterable {
static let kIsDebugModeEnabled = "_DebugMode" case kIsDebugModeEnabled = "_DebugMode"
static let kMostRecentInputMode = "MostRecentInputMode" case kFailureFlagForUOMObservation = "_FailureFlag_UOMObservation"
static let kUserDataFolderSpecified = "UserDataFolderSpecified" case kMostRecentInputMode = "MostRecentInputMode"
static let kCheckUpdateAutomatically = "CheckUpdateAutomatically" case kUserDataFolderSpecified = "UserDataFolderSpecified"
static let kMandarinParser = "MandarinParser" case kCheckUpdateAutomatically = "CheckUpdateAutomatically"
static let kBasicKeyboardLayout = "BasicKeyboardLayout" case kMandarinParser = "MandarinParser"
static let kShowPageButtonsInCandidateWindow = "ShowPageButtonsInCandidateWindow" case kBasicKeyboardLayout = "BasicKeyboardLayout"
static let kCandidateListTextSize = "CandidateListTextSize" case kShowPageButtonsInCandidateWindow = "ShowPageButtonsInCandidateWindow"
static let kAppleLanguages = "AppleLanguages" case kCandidateListTextSize = "CandidateListTextSize"
static let kShouldAutoReloadUserDataFiles = "ShouldAutoReloadUserDataFiles" case kAppleLanguages = "AppleLanguages"
static let kuseRearCursorMode = "useRearCursorMode" case kShouldAutoReloadUserDataFiles = "ShouldAutoReloadUserDataFiles"
static let kUseHorizontalCandidateList = "UseHorizontalCandidateList" case kUseRearCursorMode = "useRearCursorMode"
static let kComposingBufferSize = "ComposingBufferSize" case kUseHorizontalCandidateList = "UseHorizontalCandidateList"
static let kChooseCandidateUsingSpace = "ChooseCandidateUsingSpace" case kComposingBufferSize = "ComposingBufferSize"
static let kCNS11643Enabled = "CNS11643Enabled" case kChooseCandidateUsingSpace = "ChooseCandidateUsingSpace"
static let kSymbolInputEnabled = "SymbolInputEnabled" case kCNS11643Enabled = "CNS11643Enabled"
static let kChineseConversionEnabled = "ChineseConversionEnabled" case kSymbolInputEnabled = "SymbolInputEnabled"
static let kShiftJISShinjitaiOutputEnabled = "ShiftJISShinjitaiOutputEnabled" case kChineseConversionEnabled = "ChineseConversionEnabled"
static let kCurrencyNumeralsEnabled = "CurrencyNumeralsEnabled" case kShiftJISShinjitaiOutputEnabled = "ShiftJISShinjitaiOutputEnabled"
static let kHalfWidthPunctuationEnabled = "HalfWidthPunctuationEnable" case kCurrencyNumeralsEnabled = "CurrencyNumeralsEnabled"
static let kMoveCursorAfterSelectingCandidate = "MoveCursorAfterSelectingCandidate" case kHalfWidthPunctuationEnabled = "HalfWidthPunctuationEnable"
static let kEscToCleanInputBuffer = "EscToCleanInputBuffer" case kMoveCursorAfterSelectingCandidate = "MoveCursorAfterSelectingCandidate"
static let kSpecifyShiftTabKeyBehavior = "SpecifyShiftTabKeyBehavior" case kEscToCleanInputBuffer = "EscToCleanInputBuffer"
static let kSpecifyShiftSpaceKeyBehavior = "SpecifyShiftSpaceKeyBehavior" case kSpecifyShiftTabKeyBehavior = "SpecifyShiftTabKeyBehavior"
static let kAllowBoostingSingleKanjiAsUserPhrase = "AllowBoostingSingleKanjiAsUserPhrase" case kSpecifyShiftSpaceKeyBehavior = "SpecifyShiftSpaceKeyBehavior"
static let kUseSCPCTypingMode = "UseSCPCTypingMode" case kAllowBoostingSingleKanjiAsUserPhrase = "AllowBoostingSingleKanjiAsUserPhrase"
static let kMaxCandidateLength = "MaxCandidateLength" case kUseSCPCTypingMode = "UseSCPCTypingMode"
static let kShouldNotFartInLieuOfBeep = "ShouldNotFartInLieuOfBeep" case kMaxCandidateLength = "MaxCandidateLength"
static let kShowHanyuPinyinInCompositionBuffer = "ShowHanyuPinyinInCompositionBuffer" case kShouldNotFartInLieuOfBeep = "ShouldNotFartInLieuOfBeep"
static let kInlineDumpPinyinInLieuOfZhuyin = "InlineDumpPinyinInLieuOfZhuyin" case kShowHanyuPinyinInCompositionBuffer = "ShowHanyuPinyinInCompositionBuffer"
static let kFetchSuggestionsFromUserOverrideModel = "FetchSuggestionsFromUserOverrideModel" case kInlineDumpPinyinInLieuOfZhuyin = "InlineDumpPinyinInLieuOfZhuyin"
static let kUseFixecCandidateOrderOnSelection = "UseFixecCandidateOrderOnSelection" case kFetchSuggestionsFromUserOverrideModel = "FetchSuggestionsFromUserOverrideModel"
static let kAutoCorrectReadingCombination = "AutoCorrectReadingCombination" case kUseFixecCandidateOrderOnSelection = "UseFixecCandidateOrderOnSelection"
static let kAlsoConfirmAssociatedCandidatesByEnter = "AlsoConfirmAssociatedCandidatesByEnter" case kAutoCorrectReadingCombination = "AutoCorrectReadingCombination"
case kAlsoConfirmAssociatedCandidatesByEnter = "AlsoConfirmAssociatedCandidatesByEnter"
case kKeepReadingUponCompositionError = "KeepReadingUponCompositionError"
static let kCandidateTextFontName = "CandidateTextFontName" case kCandidateTextFontName = "CandidateTextFontName"
static let kCandidateKeyLabelFontName = "CandidateKeyLabelFontName" case kCandidateKeyLabelFontName = "CandidateKeyLabelFontName"
static let kCandidateKeys = "CandidateKeys" case kCandidateKeys = "CandidateKeys"
static let kAssociatedPhrasesEnabled = "AssociatedPhrasesEnabled" case kAssociatedPhrasesEnabled = "AssociatedPhrasesEnabled"
static let kPhraseReplacementEnabled = "PhraseReplacementEnabled" case kPhraseReplacementEnabled = "PhraseReplacementEnabled"
static let kUsingHotKeySCPC = "UsingHotKeySCPC" case kUsingHotKeySCPC = "UsingHotKeySCPC"
static let kUsingHotKeyAssociates = "UsingHotKeyAssociates" case kUsingHotKeyAssociates = "UsingHotKeyAssociates"
static let kUsingHotKeyCNS = "UsingHotKeyCNS" case kUsingHotKeyCNS = "UsingHotKeyCNS"
static let kUsingHotKeyKangXi = "UsingHotKeyKangXi" case kUsingHotKeyKangXi = "UsingHotKeyKangXi"
static let kUsingHotKeyJIS = "UsingHotKeyJIS" case kUsingHotKeyJIS = "UsingHotKeyJIS"
static let kUsingHotKeyHalfWidthASCII = "UsingHotKeyHalfWidthASCII" case kUsingHotKeyHalfWidthASCII = "UsingHotKeyHalfWidthASCII"
static let kUsingHotKeyCurrencyNumerals = "UsingHotKeyCurrencyNumerals" case kUsingHotKeyCurrencyNumerals = "UsingHotKeyCurrencyNumerals"
} }
private let kDefaultCandidateListTextSize: CGFloat = 18 private let kDefaultCandidateListTextSize: CGFloat = 18
@ -237,92 +239,117 @@ enum MandarinParser: Int {
public enum mgrPrefs { public enum mgrPrefs {
public static func setMissingDefaults() { public static func setMissingDefaults() {
UserDefaults.standard.setDefault(mgrPrefs.isDebugModeEnabled, forKey: UserDef.kIsDebugModeEnabled) UserDefaults.standard.setDefault(mgrPrefs.isDebugModeEnabled, forKey: UserDef.kIsDebugModeEnabled.rawValue)
UserDefaults.standard.setDefault(mgrPrefs.mostRecentInputMode, forKey: UserDef.kMostRecentInputMode)
UserDefaults.standard.setDefault(mgrPrefs.checkUpdateAutomatically, forKey: UserDef.kCheckUpdateAutomatically)
UserDefaults.standard.setDefault( UserDefaults.standard.setDefault(
mgrPrefs.showPageButtonsInCandidateWindow, forKey: UserDef.kShowPageButtonsInCandidateWindow mgrPrefs.failureFlagForUOMObservation, forKey: UserDef.kFailureFlagForUOMObservation.rawValue
) )
UserDefaults.standard.setDefault(mgrPrefs.symbolInputEnabled, forKey: UserDef.kSymbolInputEnabled) UserDefaults.standard.setDefault(mgrPrefs.mostRecentInputMode, forKey: UserDef.kMostRecentInputMode.rawValue)
UserDefaults.standard.setDefault(mgrPrefs.candidateListTextSize, forKey: UserDef.kCandidateListTextSize)
UserDefaults.standard.setDefault(mgrPrefs.chooseCandidateUsingSpace, forKey: UserDef.kChooseCandidateUsingSpace)
UserDefaults.standard.setDefault( UserDefaults.standard.setDefault(
mgrPrefs.shouldAutoReloadUserDataFiles, forKey: UserDef.kShouldAutoReloadUserDataFiles mgrPrefs.checkUpdateAutomatically, forKey: UserDef.kCheckUpdateAutomatically.rawValue
) )
UserDefaults.standard.setDefault( UserDefaults.standard.setDefault(
mgrPrefs.specifyShiftTabKeyBehavior, forKey: UserDef.kSpecifyShiftTabKeyBehavior mgrPrefs.showPageButtonsInCandidateWindow, forKey: UserDef.kShowPageButtonsInCandidateWindow.rawValue
)
UserDefaults.standard.setDefault(mgrPrefs.symbolInputEnabled, forKey: UserDef.kSymbolInputEnabled.rawValue)
UserDefaults.standard.setDefault(mgrPrefs.candidateListTextSize, forKey: UserDef.kCandidateListTextSize.rawValue)
UserDefaults.standard.setDefault(
mgrPrefs.chooseCandidateUsingSpace, forKey: UserDef.kChooseCandidateUsingSpace.rawValue
) )
UserDefaults.standard.setDefault( UserDefaults.standard.setDefault(
mgrPrefs.specifyShiftSpaceKeyBehavior, forKey: UserDef.kSpecifyShiftSpaceKeyBehavior mgrPrefs.shouldAutoReloadUserDataFiles, forKey: UserDef.kShouldAutoReloadUserDataFiles.rawValue
)
UserDefaults.standard.setDefault(mgrPrefs.useSCPCTypingMode, forKey: UserDef.kUseSCPCTypingMode)
UserDefaults.standard.setDefault(mgrPrefs.associatedPhrasesEnabled, forKey: UserDef.kAssociatedPhrasesEnabled)
UserDefaults.standard.setDefault(
mgrPrefs.useRearCursorMode, forKey: UserDef.kuseRearCursorMode
) )
UserDefaults.standard.setDefault( UserDefaults.standard.setDefault(
mgrPrefs.moveCursorAfterSelectingCandidate, forKey: UserDef.kMoveCursorAfterSelectingCandidate mgrPrefs.specifyShiftTabKeyBehavior, forKey: UserDef.kSpecifyShiftTabKeyBehavior.rawValue
) )
UserDefaults.standard.setDefault( UserDefaults.standard.setDefault(
mgrPrefs.useHorizontalCandidateList, forKey: UserDef.kUseHorizontalCandidateList mgrPrefs.specifyShiftSpaceKeyBehavior, forKey: UserDef.kSpecifyShiftSpaceKeyBehavior.rawValue
) )
UserDefaults.standard.setDefault(mgrPrefs.cns11643Enabled, forKey: UserDef.kCNS11643Enabled) UserDefaults.standard.setDefault(mgrPrefs.useSCPCTypingMode, forKey: UserDef.kUseSCPCTypingMode.rawValue)
UserDefaults.standard.setDefault(mgrPrefs.chineseConversionEnabled, forKey: UserDef.kChineseConversionEnabled)
UserDefaults.standard.setDefault( UserDefaults.standard.setDefault(
mgrPrefs.shiftJISShinjitaiOutputEnabled, forKey: UserDef.kShiftJISShinjitaiOutputEnabled mgrPrefs.associatedPhrasesEnabled, forKey: UserDef.kAssociatedPhrasesEnabled.rawValue
)
UserDefaults.standard.setDefault(mgrPrefs.phraseReplacementEnabled, forKey: UserDef.kPhraseReplacementEnabled)
UserDefaults.standard.setDefault(mgrPrefs.shouldNotFartInLieuOfBeep, forKey: UserDef.kShouldNotFartInLieuOfBeep)
UserDefaults.standard.setDefault(
mgrPrefs.showHanyuPinyinInCompositionBuffer, forKey: UserDef.kShowHanyuPinyinInCompositionBuffer
) )
UserDefaults.standard.setDefault( UserDefaults.standard.setDefault(
mgrPrefs.inlineDumpPinyinInLieuOfZhuyin, forKey: UserDef.kInlineDumpPinyinInLieuOfZhuyin mgrPrefs.useRearCursorMode, forKey: UserDef.kUseRearCursorMode.rawValue
) )
UserDefaults.standard.setDefault( UserDefaults.standard.setDefault(
mgrPrefs.allowBoostingSingleKanjiAsUserPhrase, forKey: UserDef.kAllowBoostingSingleKanjiAsUserPhrase mgrPrefs.moveCursorAfterSelectingCandidate, forKey: UserDef.kMoveCursorAfterSelectingCandidate.rawValue
) )
UserDefaults.standard.setDefault( UserDefaults.standard.setDefault(
mgrPrefs.fetchSuggestionsFromUserOverrideModel, forKey: UserDef.kFetchSuggestionsFromUserOverrideModel mgrPrefs.useHorizontalCandidateList, forKey: UserDef.kUseHorizontalCandidateList.rawValue
)
UserDefaults.standard.setDefault(mgrPrefs.cns11643Enabled, forKey: UserDef.kCNS11643Enabled.rawValue)
UserDefaults.standard.setDefault(
mgrPrefs.chineseConversionEnabled, forKey: UserDef.kChineseConversionEnabled.rawValue
) )
UserDefaults.standard.setDefault( UserDefaults.standard.setDefault(
mgrPrefs.useFixecCandidateOrderOnSelection, forKey: UserDef.kUseFixecCandidateOrderOnSelection mgrPrefs.shiftJISShinjitaiOutputEnabled, forKey: UserDef.kShiftJISShinjitaiOutputEnabled.rawValue
) )
UserDefaults.standard.setDefault( UserDefaults.standard.setDefault(
mgrPrefs.autoCorrectReadingCombination, forKey: UserDef.kAutoCorrectReadingCombination mgrPrefs.phraseReplacementEnabled, forKey: UserDef.kPhraseReplacementEnabled.rawValue
) )
UserDefaults.standard.setDefault( UserDefaults.standard.setDefault(
mgrPrefs.alsoConfirmAssociatedCandidatesByEnter, forKey: UserDef.kAlsoConfirmAssociatedCandidatesByEnter mgrPrefs.shouldNotFartInLieuOfBeep, forKey: UserDef.kShouldNotFartInLieuOfBeep.rawValue
) )
UserDefaults.standard.setDefault( UserDefaults.standard.setDefault(
mgrPrefs.currencyNumeralsEnabled, forKey: UserDef.kCurrencyNumeralsEnabled mgrPrefs.showHanyuPinyinInCompositionBuffer, forKey: UserDef.kShowHanyuPinyinInCompositionBuffer.rawValue
)
UserDefaults.standard.setDefault(
mgrPrefs.inlineDumpPinyinInLieuOfZhuyin, forKey: UserDef.kInlineDumpPinyinInLieuOfZhuyin.rawValue
)
UserDefaults.standard.setDefault(
mgrPrefs.allowBoostingSingleKanjiAsUserPhrase, forKey: UserDef.kAllowBoostingSingleKanjiAsUserPhrase.rawValue
)
UserDefaults.standard.setDefault(
mgrPrefs.fetchSuggestionsFromUserOverrideModel, forKey: UserDef.kFetchSuggestionsFromUserOverrideModel.rawValue
)
UserDefaults.standard.setDefault(
mgrPrefs.useFixecCandidateOrderOnSelection, forKey: UserDef.kUseFixecCandidateOrderOnSelection.rawValue
)
UserDefaults.standard.setDefault(
mgrPrefs.autoCorrectReadingCombination, forKey: UserDef.kAutoCorrectReadingCombination.rawValue
)
UserDefaults.standard.setDefault(
mgrPrefs.alsoConfirmAssociatedCandidatesByEnter, forKey: UserDef.kAlsoConfirmAssociatedCandidatesByEnter.rawValue
)
UserDefaults.standard.setDefault(
mgrPrefs.currencyNumeralsEnabled, forKey: UserDef.kCurrencyNumeralsEnabled.rawValue
)
UserDefaults.standard.setDefault(
mgrPrefs.keepReadingUponCompositionError, forKey: UserDef.kKeepReadingUponCompositionError.rawValue
) )
UserDefaults.standard.setDefault(mgrPrefs.usingHotKeySCPC, forKey: UserDef.kUsingHotKeySCPC) UserDefaults.standard.setDefault(mgrPrefs.usingHotKeySCPC, forKey: UserDef.kUsingHotKeySCPC.rawValue)
UserDefaults.standard.setDefault(mgrPrefs.usingHotKeyAssociates, forKey: UserDef.kUsingHotKeyAssociates) UserDefaults.standard.setDefault(mgrPrefs.usingHotKeyAssociates, forKey: UserDef.kUsingHotKeyAssociates.rawValue)
UserDefaults.standard.setDefault(mgrPrefs.usingHotKeyCNS, forKey: UserDef.kUsingHotKeyCNS) UserDefaults.standard.setDefault(mgrPrefs.usingHotKeyCNS, forKey: UserDef.kUsingHotKeyCNS.rawValue)
UserDefaults.standard.setDefault(mgrPrefs.usingHotKeyKangXi, forKey: UserDef.kUsingHotKeyKangXi) UserDefaults.standard.setDefault(mgrPrefs.usingHotKeyKangXi, forKey: UserDef.kUsingHotKeyKangXi.rawValue)
UserDefaults.standard.setDefault(mgrPrefs.usingHotKeyJIS, forKey: UserDef.kUsingHotKeyJIS) UserDefaults.standard.setDefault(mgrPrefs.usingHotKeyJIS, forKey: UserDef.kUsingHotKeyJIS.rawValue)
UserDefaults.standard.setDefault(mgrPrefs.usingHotKeyHalfWidthASCII, forKey: UserDef.kUsingHotKeyHalfWidthASCII) UserDefaults.standard.setDefault(
UserDefaults.standard.setDefault(mgrPrefs.usingHotKeyCurrencyNumerals, forKey: UserDef.kUsingHotKeyCurrencyNumerals) mgrPrefs.usingHotKeyHalfWidthASCII, forKey: UserDef.kUsingHotKeyHalfWidthASCII.rawValue
)
UserDefaults.standard.setDefault(
mgrPrefs.usingHotKeyCurrencyNumerals, forKey: UserDef.kUsingHotKeyCurrencyNumerals.rawValue
)
UserDefaults.standard.synchronize() UserDefaults.standard.synchronize()
} }
@UserDefault(key: UserDef.kIsDebugModeEnabled, defaultValue: false) @UserDefault(key: UserDef.kIsDebugModeEnabled.rawValue, defaultValue: false)
static var isDebugModeEnabled: Bool static var isDebugModeEnabled: Bool
@UserDefault(key: UserDef.kMostRecentInputMode, defaultValue: "") @UserDefault(key: UserDef.kFailureFlagForUOMObservation.rawValue, defaultValue: false)
static var failureFlagForUOMObservation: Bool
@UserDefault(key: UserDef.kMostRecentInputMode.rawValue, defaultValue: "")
static var mostRecentInputMode: String static var mostRecentInputMode: String
@UserDefault(key: UserDef.kCheckUpdateAutomatically, defaultValue: false) @UserDefault(key: UserDef.kCheckUpdateAutomatically.rawValue, defaultValue: false)
static var checkUpdateAutomatically: Bool static var checkUpdateAutomatically: Bool
@UserDefault(key: UserDef.kUserDataFolderSpecified, defaultValue: "") @UserDefault(key: UserDef.kUserDataFolderSpecified.rawValue, defaultValue: "")
static var userDataFolderSpecified: String static var userDataFolderSpecified: String
static func ifSpecifiedUserDataPathExistsInPlist() -> Bool { static func ifSpecifiedUserDataPathExistsInPlist() -> Bool {
UserDefaults.standard.object(forKey: UserDef.kUserDataFolderSpecified) != nil UserDefaults.standard.object(forKey: UserDef.kUserDataFolderSpecified.rawValue) != nil
} }
static func resetSpecifiedUserDataFolder() { static func resetSpecifiedUserDataFolder() {
@ -330,10 +357,10 @@ public enum mgrPrefs {
IME.initLangModels(userOnly: true) IME.initLangModels(userOnly: true)
} }
@UserDefault(key: UserDef.kAppleLanguages, defaultValue: []) @UserDefault(key: UserDef.kAppleLanguages.rawValue, defaultValue: [])
static var appleLanguages: [String] static var appleLanguages: [String]
@UserDefault(key: UserDef.kMandarinParser, defaultValue: 0) @UserDefault(key: UserDef.kMandarinParser.rawValue, defaultValue: 0)
static var mandarinParser: Int static var mandarinParser: Int
static var mandarinParserName: String { static var mandarinParserName: String {
@ -341,103 +368,106 @@ public enum mgrPrefs {
} }
@UserDefault( @UserDefault(
key: UserDef.kBasicKeyboardLayout, defaultValue: "com.apple.keylayout.ZhuyinBopomofo" key: UserDef.kBasicKeyboardLayout.rawValue, defaultValue: "com.apple.keylayout.ZhuyinBopomofo"
) )
static var basicKeyboardLayout: String static var basicKeyboardLayout: String
@UserDefault(key: UserDef.kShowPageButtonsInCandidateWindow, defaultValue: true) @UserDefault(key: UserDef.kShowPageButtonsInCandidateWindow.rawValue, defaultValue: true)
static var showPageButtonsInCandidateWindow: Bool static var showPageButtonsInCandidateWindow: Bool
@CandidateListTextSize(key: UserDef.kCandidateListTextSize) @CandidateListTextSize(key: UserDef.kCandidateListTextSize.rawValue)
static var candidateListTextSize: CGFloat static var candidateListTextSize: CGFloat
static var minKeyLabelSize: CGFloat { kDefaultMinKeyLabelSize } static var minKeyLabelSize: CGFloat { kDefaultMinKeyLabelSize }
@UserDefault(key: UserDef.kShouldAutoReloadUserDataFiles, defaultValue: true) @UserDefault(key: UserDef.kShouldAutoReloadUserDataFiles.rawValue, defaultValue: true)
static var shouldAutoReloadUserDataFiles: Bool static var shouldAutoReloadUserDataFiles: Bool
@UserDefault(key: UserDef.kuseRearCursorMode, defaultValue: false) @UserDefault(key: UserDef.kUseRearCursorMode.rawValue, defaultValue: false)
static var useRearCursorMode: Bool static var useRearCursorMode: Bool
@UserDefault(key: UserDef.kMoveCursorAfterSelectingCandidate, defaultValue: true) @UserDefault(key: UserDef.kMoveCursorAfterSelectingCandidate.rawValue, defaultValue: true)
static var moveCursorAfterSelectingCandidate: Bool static var moveCursorAfterSelectingCandidate: Bool
@UserDefault(key: UserDef.kUseHorizontalCandidateList, defaultValue: true) @UserDefault(key: UserDef.kUseHorizontalCandidateList.rawValue, defaultValue: true)
static var useHorizontalCandidateList: Bool static var useHorizontalCandidateList: Bool
@ComposingBufferSize(key: UserDef.kComposingBufferSize) @ComposingBufferSize(key: UserDef.kComposingBufferSize.rawValue)
static var composingBufferSize: Int static var composingBufferSize: Int
@UserDefault(key: UserDef.kChooseCandidateUsingSpace, defaultValue: true) @UserDefault(key: UserDef.kChooseCandidateUsingSpace.rawValue, defaultValue: true)
static var chooseCandidateUsingSpace: Bool static var chooseCandidateUsingSpace: Bool
@UserDefault(key: UserDef.kAllowBoostingSingleKanjiAsUserPhrase, defaultValue: false) @UserDefault(key: UserDef.kAllowBoostingSingleKanjiAsUserPhrase.rawValue, defaultValue: false)
static var allowBoostingSingleKanjiAsUserPhrase: Bool static var allowBoostingSingleKanjiAsUserPhrase: Bool
@UserDefault(key: UserDef.kFetchSuggestionsFromUserOverrideModel, defaultValue: true) @UserDefault(key: UserDef.kFetchSuggestionsFromUserOverrideModel.rawValue, defaultValue: true)
static var fetchSuggestionsFromUserOverrideModel: Bool static var fetchSuggestionsFromUserOverrideModel: Bool
@UserDefault(key: UserDef.kUseFixecCandidateOrderOnSelection, defaultValue: false) @UserDefault(key: UserDef.kUseFixecCandidateOrderOnSelection.rawValue, defaultValue: false)
static var useFixecCandidateOrderOnSelection: Bool static var useFixecCandidateOrderOnSelection: Bool
@UserDefault(key: UserDef.kAutoCorrectReadingCombination, defaultValue: true) @UserDefault(key: UserDef.kAutoCorrectReadingCombination.rawValue, defaultValue: true)
static var autoCorrectReadingCombination: Bool static var autoCorrectReadingCombination: Bool
@UserDefault(key: UserDef.kAlsoConfirmAssociatedCandidatesByEnter, defaultValue: true) @UserDefault(key: UserDef.kAlsoConfirmAssociatedCandidatesByEnter.rawValue, defaultValue: true)
static var alsoConfirmAssociatedCandidatesByEnter: Bool static var alsoConfirmAssociatedCandidatesByEnter: Bool
@UserDefault(key: UserDef.kAlsoConfirmAssociatedCandidatesByEnter.rawValue, defaultValue: false)
static var keepReadingUponCompositionError: Bool
static var minCandidateLength: Int { static var minCandidateLength: Int {
mgrPrefs.allowBoostingSingleKanjiAsUserPhrase ? 1 : 2 mgrPrefs.allowBoostingSingleKanjiAsUserPhrase ? 1 : 2
} }
@UserDefault(key: UserDef.kUseSCPCTypingMode, defaultValue: false) @UserDefault(key: UserDef.kUseSCPCTypingMode.rawValue, defaultValue: false)
static var useSCPCTypingMode: Bool static var useSCPCTypingMode: Bool
static func toggleSCPCTypingModeEnabled() -> Bool { static func toggleSCPCTypingModeEnabled() -> Bool {
useSCPCTypingMode = !useSCPCTypingMode useSCPCTypingMode = !useSCPCTypingMode
UserDefaults.standard.set(useSCPCTypingMode, forKey: UserDef.kUseSCPCTypingMode) UserDefaults.standard.set(useSCPCTypingMode, forKey: UserDef.kUseSCPCTypingMode.rawValue)
return useSCPCTypingMode return useSCPCTypingMode
} }
@UserDefault(key: UserDef.kMaxCandidateLength, defaultValue: 10) @UserDefault(key: UserDef.kMaxCandidateLength.rawValue, defaultValue: 10)
static var maxCandidateLength: Int static var maxCandidateLength: Int
@UserDefault(key: UserDef.kShouldNotFartInLieuOfBeep, defaultValue: true) @UserDefault(key: UserDef.kShouldNotFartInLieuOfBeep.rawValue, defaultValue: true)
static var shouldNotFartInLieuOfBeep: Bool static var shouldNotFartInLieuOfBeep: Bool
@UserDefault(key: UserDef.kShowHanyuPinyinInCompositionBuffer, defaultValue: false) @UserDefault(key: UserDef.kShowHanyuPinyinInCompositionBuffer.rawValue, defaultValue: false)
static var showHanyuPinyinInCompositionBuffer: Bool static var showHanyuPinyinInCompositionBuffer: Bool
@UserDefault(key: UserDef.kInlineDumpPinyinInLieuOfZhuyin, defaultValue: false) @UserDefault(key: UserDef.kInlineDumpPinyinInLieuOfZhuyin.rawValue, defaultValue: false)
static var inlineDumpPinyinInLieuOfZhuyin: Bool static var inlineDumpPinyinInLieuOfZhuyin: Bool
static func toggleShouldNotFartInLieuOfBeep() -> Bool { static func toggleShouldNotFartInLieuOfBeep() -> Bool {
shouldNotFartInLieuOfBeep = !shouldNotFartInLieuOfBeep shouldNotFartInLieuOfBeep = !shouldNotFartInLieuOfBeep
UserDefaults.standard.set(shouldNotFartInLieuOfBeep, forKey: UserDef.kShouldNotFartInLieuOfBeep) UserDefaults.standard.set(shouldNotFartInLieuOfBeep, forKey: UserDef.kShouldNotFartInLieuOfBeep.rawValue)
return shouldNotFartInLieuOfBeep return shouldNotFartInLieuOfBeep
} }
@UserDefault(key: UserDef.kCNS11643Enabled, defaultValue: false) @UserDefault(key: UserDef.kCNS11643Enabled.rawValue, defaultValue: false)
static var cns11643Enabled: Bool static var cns11643Enabled: Bool
static func toggleCNS11643Enabled() -> Bool { static func toggleCNS11643Enabled() -> Bool {
cns11643Enabled = !cns11643Enabled cns11643Enabled = !cns11643Enabled
mgrLangModel.setCNSEnabled(cns11643Enabled) // mgrLangModel.setCNSEnabled(cns11643Enabled) //
UserDefaults.standard.set(cns11643Enabled, forKey: UserDef.kCNS11643Enabled) UserDefaults.standard.set(cns11643Enabled, forKey: UserDef.kCNS11643Enabled.rawValue)
return cns11643Enabled return cns11643Enabled
} }
@UserDefault(key: UserDef.kSymbolInputEnabled, defaultValue: true) @UserDefault(key: UserDef.kSymbolInputEnabled.rawValue, defaultValue: true)
static var symbolInputEnabled: Bool static var symbolInputEnabled: Bool
static func toggleSymbolInputEnabled() -> Bool { static func toggleSymbolInputEnabled() -> Bool {
symbolInputEnabled = !symbolInputEnabled symbolInputEnabled = !symbolInputEnabled
mgrLangModel.setSymbolEnabled(symbolInputEnabled) // mgrLangModel.setSymbolEnabled(symbolInputEnabled) //
UserDefaults.standard.set(symbolInputEnabled, forKey: UserDef.kSymbolInputEnabled) UserDefaults.standard.set(symbolInputEnabled, forKey: UserDef.kSymbolInputEnabled.rawValue)
return symbolInputEnabled return symbolInputEnabled
} }
@UserDefault(key: UserDef.kChineseConversionEnabled, defaultValue: false) @UserDefault(key: UserDef.kChineseConversionEnabled.rawValue, defaultValue: false)
static var chineseConversionEnabled: Bool static var chineseConversionEnabled: Bool
@discardableResult static func toggleChineseConversionEnabled() -> Bool { @discardableResult static func toggleChineseConversionEnabled() -> Bool {
@ -446,14 +476,14 @@ public enum mgrPrefs {
if chineseConversionEnabled, shiftJISShinjitaiOutputEnabled { if chineseConversionEnabled, shiftJISShinjitaiOutputEnabled {
toggleShiftJISShinjitaiOutputEnabled() toggleShiftJISShinjitaiOutputEnabled()
UserDefaults.standard.set( UserDefaults.standard.set(
shiftJISShinjitaiOutputEnabled, forKey: UserDef.kShiftJISShinjitaiOutputEnabled shiftJISShinjitaiOutputEnabled, forKey: UserDef.kShiftJISShinjitaiOutputEnabled.rawValue
) )
} }
UserDefaults.standard.set(chineseConversionEnabled, forKey: UserDef.kChineseConversionEnabled) UserDefaults.standard.set(chineseConversionEnabled, forKey: UserDef.kChineseConversionEnabled.rawValue)
return chineseConversionEnabled return chineseConversionEnabled
} }
@UserDefault(key: UserDef.kShiftJISShinjitaiOutputEnabled, defaultValue: false) @UserDefault(key: UserDef.kShiftJISShinjitaiOutputEnabled.rawValue, defaultValue: false)
static var shiftJISShinjitaiOutputEnabled: Bool static var shiftJISShinjitaiOutputEnabled: Bool
@discardableResult static func toggleShiftJISShinjitaiOutputEnabled() -> Bool { @discardableResult static func toggleShiftJISShinjitaiOutputEnabled() -> Bool {
@ -463,12 +493,12 @@ public enum mgrPrefs {
toggleChineseConversionEnabled() toggleChineseConversionEnabled()
} }
UserDefaults.standard.set( UserDefaults.standard.set(
shiftJISShinjitaiOutputEnabled, forKey: UserDef.kShiftJISShinjitaiOutputEnabled shiftJISShinjitaiOutputEnabled, forKey: UserDef.kShiftJISShinjitaiOutputEnabled.rawValue
) )
return shiftJISShinjitaiOutputEnabled return shiftJISShinjitaiOutputEnabled
} }
@UserDefault(key: UserDef.kCurrencyNumeralsEnabled, defaultValue: false) @UserDefault(key: UserDef.kCurrencyNumeralsEnabled.rawValue, defaultValue: false)
static var currencyNumeralsEnabled: Bool static var currencyNumeralsEnabled: Bool
static func toggleCurrencyNumeralsEnabled() -> Bool { static func toggleCurrencyNumeralsEnabled() -> Bool {
@ -476,7 +506,7 @@ public enum mgrPrefs {
return currencyNumeralsEnabled return currencyNumeralsEnabled
} }
@UserDefault(key: UserDef.kHalfWidthPunctuationEnabled, defaultValue: false) @UserDefault(key: UserDef.kHalfWidthPunctuationEnabled.rawValue, defaultValue: false)
static var halfWidthPunctuationEnabled: Bool static var halfWidthPunctuationEnabled: Bool
static func toggleHalfWidthPunctuationEnabled() -> Bool { static func toggleHalfWidthPunctuationEnabled() -> Bool {
@ -484,24 +514,24 @@ public enum mgrPrefs {
return halfWidthPunctuationEnabled return halfWidthPunctuationEnabled
} }
@UserDefault(key: UserDef.kEscToCleanInputBuffer, defaultValue: true) @UserDefault(key: UserDef.kEscToCleanInputBuffer.rawValue, defaultValue: true)
static var escToCleanInputBuffer: Bool static var escToCleanInputBuffer: Bool
@UserDefault(key: UserDef.kSpecifyShiftTabKeyBehavior, defaultValue: false) @UserDefault(key: UserDef.kSpecifyShiftTabKeyBehavior.rawValue, defaultValue: false)
static var specifyShiftTabKeyBehavior: Bool static var specifyShiftTabKeyBehavior: Bool
@UserDefault(key: UserDef.kSpecifyShiftSpaceKeyBehavior, defaultValue: false) @UserDefault(key: UserDef.kSpecifyShiftSpaceKeyBehavior.rawValue, defaultValue: false)
static var specifyShiftSpaceKeyBehavior: Bool static var specifyShiftSpaceKeyBehavior: Bool
// MARK: - Optional settings // MARK: - Optional settings
@UserDefault(key: UserDef.kCandidateTextFontName, defaultValue: nil) @UserDefault(key: UserDef.kCandidateTextFontName.rawValue, defaultValue: nil)
static var candidateTextFontName: String? static var candidateTextFontName: String?
@UserDefault(key: UserDef.kCandidateKeyLabelFontName, defaultValue: nil) @UserDefault(key: UserDef.kCandidateKeyLabelFontName.rawValue, defaultValue: nil)
static var candidateKeyLabelFontName: String? static var candidateKeyLabelFontName: String?
@UserDefault(key: UserDef.kCandidateKeys, defaultValue: kDefaultKeys) @UserDefault(key: UserDef.kCandidateKeys.rawValue, defaultValue: kDefaultKeys)
static var candidateKeys: String static var candidateKeys: String
static var defaultCandidateKeys: String { static var defaultCandidateKeys: String {
@ -566,46 +596,46 @@ public enum mgrPrefs {
} }
} }
@UserDefault(key: UserDef.kPhraseReplacementEnabled, defaultValue: false) @UserDefault(key: UserDef.kPhraseReplacementEnabled.rawValue, defaultValue: false)
static var phraseReplacementEnabled: Bool static var phraseReplacementEnabled: Bool
static func togglePhraseReplacementEnabled() -> Bool { static func togglePhraseReplacementEnabled() -> Bool {
phraseReplacementEnabled = !phraseReplacementEnabled phraseReplacementEnabled = !phraseReplacementEnabled
mgrLangModel.setPhraseReplacementEnabled(phraseReplacementEnabled) mgrLangModel.setPhraseReplacementEnabled(phraseReplacementEnabled)
UserDefaults.standard.set(phraseReplacementEnabled, forKey: UserDef.kPhraseReplacementEnabled) UserDefaults.standard.set(phraseReplacementEnabled, forKey: UserDef.kPhraseReplacementEnabled.rawValue)
return phraseReplacementEnabled return phraseReplacementEnabled
} }
@UserDefault(key: UserDef.kAssociatedPhrasesEnabled, defaultValue: false) @UserDefault(key: UserDef.kAssociatedPhrasesEnabled.rawValue, defaultValue: false)
static var associatedPhrasesEnabled: Bool static var associatedPhrasesEnabled: Bool
static func toggleAssociatedPhrasesEnabled() -> Bool { static func toggleAssociatedPhrasesEnabled() -> Bool {
associatedPhrasesEnabled = !associatedPhrasesEnabled associatedPhrasesEnabled = !associatedPhrasesEnabled
UserDefaults.standard.set(associatedPhrasesEnabled, forKey: UserDef.kAssociatedPhrasesEnabled) UserDefaults.standard.set(associatedPhrasesEnabled, forKey: UserDef.kAssociatedPhrasesEnabled.rawValue)
return associatedPhrasesEnabled return associatedPhrasesEnabled
} }
// MARK: - Keyboard HotKey Enable / Disable // MARK: - Keyboard HotKey Enable / Disable
@UserDefault(key: UserDef.kUsingHotKeySCPC, defaultValue: true) @UserDefault(key: UserDef.kUsingHotKeySCPC.rawValue, defaultValue: true)
static var usingHotKeySCPC: Bool static var usingHotKeySCPC: Bool
@UserDefault(key: UserDef.kUsingHotKeyAssociates, defaultValue: true) @UserDefault(key: UserDef.kUsingHotKeyAssociates.rawValue, defaultValue: true)
static var usingHotKeyAssociates: Bool static var usingHotKeyAssociates: Bool
@UserDefault(key: UserDef.kUsingHotKeyCNS, defaultValue: true) @UserDefault(key: UserDef.kUsingHotKeyCNS.rawValue, defaultValue: true)
static var usingHotKeyCNS: Bool static var usingHotKeyCNS: Bool
@UserDefault(key: UserDef.kUsingHotKeyKangXi, defaultValue: true) @UserDefault(key: UserDef.kUsingHotKeyKangXi.rawValue, defaultValue: true)
static var usingHotKeyKangXi: Bool static var usingHotKeyKangXi: Bool
@UserDefault(key: UserDef.kUsingHotKeyJIS, defaultValue: true) @UserDefault(key: UserDef.kUsingHotKeyJIS.rawValue, defaultValue: true)
static var usingHotKeyJIS: Bool static var usingHotKeyJIS: Bool
@UserDefault(key: UserDef.kUsingHotKeyHalfWidthASCII, defaultValue: true) @UserDefault(key: UserDef.kUsingHotKeyHalfWidthASCII.rawValue, defaultValue: true)
static var usingHotKeyHalfWidthASCII: Bool static var usingHotKeyHalfWidthASCII: Bool
@UserDefault(key: UserDef.kUsingHotKeyCurrencyNumerals, defaultValue: true) @UserDefault(key: UserDef.kUsingHotKeyCurrencyNumerals.rawValue, defaultValue: true)
static var usingHotKeyCurrencyNumerals: Bool static var usingHotKeyCurrencyNumerals: Bool
} }
@ -614,45 +644,23 @@ public enum mgrPrefs {
var snapshot: [String: Any]? var snapshot: [String: Any]?
extension mgrPrefs { extension mgrPrefs {
static var allKeys: [String] {
[
UserDef.kIsDebugModeEnabled, UserDef.kMostRecentInputMode, UserDef.kUserDataFolderSpecified,
UserDef.kCheckUpdateAutomatically, UserDef.kMandarinParser, UserDef.kBasicKeyboardLayout,
UserDef.kShowPageButtonsInCandidateWindow, UserDef.kCandidateListTextSize, UserDef.kAppleLanguages,
UserDef.kShouldAutoReloadUserDataFiles, UserDef.kuseRearCursorMode, UserDef.kUseHorizontalCandidateList,
UserDef.kComposingBufferSize, UserDef.kChooseCandidateUsingSpace, UserDef.kCNS11643Enabled,
UserDef.kSymbolInputEnabled, UserDef.kChineseConversionEnabled, UserDef.kShiftJISShinjitaiOutputEnabled,
UserDef.kHalfWidthPunctuationEnabled, UserDef.kMoveCursorAfterSelectingCandidate, UserDef.kEscToCleanInputBuffer,
UserDef.kSpecifyShiftTabKeyBehavior, UserDef.kSpecifyShiftSpaceKeyBehavior,
UserDef.kAllowBoostingSingleKanjiAsUserPhrase, UserDef.kUseSCPCTypingMode, UserDef.kMaxCandidateLength,
UserDef.kShouldNotFartInLieuOfBeep, UserDef.kShowHanyuPinyinInCompositionBuffer,
UserDef.kInlineDumpPinyinInLieuOfZhuyin, UserDef.kFetchSuggestionsFromUserOverrideModel,
UserDef.kCandidateTextFontName, UserDef.kCandidateKeyLabelFontName, UserDef.kCandidateKeys,
UserDef.kAssociatedPhrasesEnabled, UserDef.kPhraseReplacementEnabled, UserDef.kUsingHotKeySCPC,
UserDef.kUsingHotKeyAssociates, UserDef.kUsingHotKeyCNS, UserDef.kUsingHotKeyKangXi, UserDef.kUsingHotKeyJIS,
UserDef.kUsingHotKeyHalfWidthASCII, UserDef.kUseFixecCandidateOrderOnSelection,
UserDef.kAutoCorrectReadingCombination, UserDef.kAlsoConfirmAssociatedCandidatesByEnter,
UserDef.kCurrencyNumeralsEnabled, UserDef.kUsingHotKeyCurrencyNumerals,
]
}
func reset() { func reset() {
mgrPrefs.allKeys.forEach { UserDef.allCases.forEach {
UserDefaults.standard.removeObject(forKey: $0) UserDefaults.standard.removeObject(forKey: $0.rawValue)
} }
} }
func makeSnapshot() -> [String: Any] { func makeSnapshot() -> [String: Any] {
var dict = [String: Any]() var dict = [String: Any]()
mgrPrefs.allKeys.forEach { UserDef.allCases.forEach {
dict[$0] = UserDefaults.standard.object(forKey: $0) dict[$0.rawValue] = UserDefaults.standard.object(forKey: $0.rawValue)
} }
return dict return dict
} }
func restore(from snapshot: [String: Any]) { func restore(from snapshot: [String: Any]) {
mgrPrefs.allKeys.forEach { UserDef.allCases.forEach {
UserDefaults.standard.set(snapshot[$0], forKey: $0) UserDefaults.standard.set(snapshot[$0.rawValue], forKey: $0.rawValue)
} }
} }
} }

View File

@ -62,7 +62,7 @@ extension vChewing {
do { do {
strData = try String(contentsOfFile: path, encoding: .utf8).replacingOccurrences(of: "\t", with: " ") strData = try String(contentsOfFile: path, encoding: .utf8).replacingOccurrences(of: "\t", with: " ")
strData = strData.replacingOccurrences(of: "\r", with: "\n") strData = strData.replacingOccurrences(of: "\r", with: "\n")
strData.ranges(splitBy: "\n").filter({ !$0.isEmpty }).forEach { strData.ranges(splitBy: "\n").filter { !$0.isEmpty }.forEach {
let neta = strData[$0].split(separator: " ") let neta = strData[$0].split(separator: " ")
if neta.count >= 2 { if neta.count >= 2 {
let theKey = String(neta[0]) let theKey = String(neta[0])

View File

@ -87,7 +87,7 @@ extension vChewing {
do { do {
strData = try String(contentsOfFile: path, encoding: .utf8).replacingOccurrences(of: "\t", with: " ") strData = try String(contentsOfFile: path, encoding: .utf8).replacingOccurrences(of: "\t", with: " ")
strData = strData.replacingOccurrences(of: "\r", with: "\n") strData = strData.replacingOccurrences(of: "\r", with: "\n")
strData.ranges(splitBy: "\n").filter({ !$0.isEmpty }).forEach { strData.ranges(splitBy: "\n").filter { !$0.isEmpty }.forEach {
let neta = strData[$0].split(separator: " ") let neta = strData[$0].split(separator: " ")
if neta.count >= 2, String(neta[0]).first != "#" { if neta.count >= 2, String(neta[0]).first != "#" {
if !neta[0].isEmpty, !neta[1].isEmpty { if !neta[0].isEmpty, !neta[1].isEmpty {

View File

@ -53,7 +53,7 @@ extension vChewing {
do { do {
strData = try String(contentsOfFile: path, encoding: .utf8).replacingOccurrences(of: "\t", with: " ") strData = try String(contentsOfFile: path, encoding: .utf8).replacingOccurrences(of: "\t", with: " ")
strData = strData.replacingOccurrences(of: "\r", with: "\n") strData = strData.replacingOccurrences(of: "\r", with: "\n")
strData.ranges(splitBy: "\n").filter({ !$0.isEmpty }).forEach { strData.ranges(splitBy: "\n").filter { !$0.isEmpty }.forEach {
let neta = strData[$0].split(separator: " ") let neta = strData[$0].split(separator: " ")
if neta.count >= 2 { if neta.count >= 2 {
let theKey = String(neta[0]) let theKey = String(neta[0])

View File

@ -326,9 +326,8 @@ extension vChewing.LMUserOverride {
public func saveData(toURL fileURL: URL) { public func saveData(toURL fileURL: URL) {
let encoder = JSONEncoder() let encoder = JSONEncoder()
do { do {
if let jsonData = try? encoder.encode(mutLRUMap) { guard let jsonData = try? encoder.encode(mutLRUMap) else { return }
try jsonData.write(to: fileURL, options: .atomic) try jsonData.write(to: fileURL, options: .atomic)
}
} catch { } catch {
IME.prtDebugIntel("UOM Error: Unable to save data, abort saving. Details: \(error)") IME.prtDebugIntel("UOM Error: Unable to save data, abort saving. Details: \(error)")
return return

View File

@ -67,4 +67,6 @@ else {
exit(-1) exit(-1)
} }
public let theServer = server
NSApp.run() NSApp.run()

View File

@ -1,3 +1,5 @@
"vChewing" = "vChewing";
"vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability." = "vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability.";
"About vChewing…" = "About vChewing…"; "About vChewing…" = "About vChewing…";
"vChewing Preferences…" = "vChewing Preferences…"; "vChewing Preferences…" = "vChewing Preferences…";
"Uninstallation" = "Uninstallation"; "Uninstallation" = "Uninstallation";
@ -37,7 +39,7 @@
"Please specify at least 4 candidate keys." = "Please specify at least 4 candidate keys."; "Please specify at least 4 candidate keys." = "Please specify at least 4 candidate keys.";
"Maximum 15 candidate keys allowed." = "Maximum 15 candidate keys allowed."; "Maximum 15 candidate keys allowed." = "Maximum 15 candidate keys allowed.";
"⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ Phrase replacement mode enabled, interfering user phrase entry."; "⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ Phrase replacement mode enabled, interfering user phrase entry.";
"⚠︎ Unhandlable: Chars and Readings in buffer doesn't match." = "⚠︎ Unhandlable: Chars and Readings in buffer doesn't match."; "⚠︎ Beware: Chars and Readings in buffer doesn't match." = "⚠︎ Beware: Chars and Readings in buffer doesn't match.";
"Per-Char Select Mode" = "Per-Char Select Mode"; "Per-Char Select Mode" = "Per-Char Select Mode";
"CNS11643 Mode" = "CNS11643 Mode"; "CNS11643 Mode" = "CNS11643 Mode";
"JIS Shinjitai Output" = "JIS Shinjitai Output"; "JIS Shinjitai Output" = "JIS Shinjitai Output";
@ -85,6 +87,7 @@
// SwiftUI Preferences // SwiftUI Preferences
"(Shift+)Space:" = "(Shift+)Space:"; "(Shift+)Space:" = "(Shift+)Space:";
"Allow backspace-editing miscomposed readings" = "Allow backspace-editing miscomposed readings";
"Allow boosting / excluding a candidate of single kanji" = "Allow boosting / excluding a candidate of single kanji"; "Allow boosting / excluding a candidate of single kanji" = "Allow boosting / excluding a candidate of single kanji";
"Allow using Enter key to confirm associated candidate selection" = "Allow using Enter key to confirm associated candidate selection"; "Allow using Enter key to confirm associated candidate selection" = "Allow using Enter key to confirm associated candidate selection";
"Always use fixed listing order in candidate window" = "Always use fixed listing order in candidate window"; "Always use fixed listing order in candidate window" = "Always use fixed listing order in candidate window";

View File

@ -1,3 +1,5 @@
"vChewing" = "vChewing";
"vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability." = "vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability.";
"About vChewing…" = "About vChewing…"; "About vChewing…" = "About vChewing…";
"vChewing Preferences…" = "vChewing Preferences…"; "vChewing Preferences…" = "vChewing Preferences…";
"Uninstallation" = "Uninstallation"; "Uninstallation" = "Uninstallation";
@ -37,7 +39,7 @@
"Please specify at least 4 candidate keys." = "Please specify at least 4 candidate keys."; "Please specify at least 4 candidate keys." = "Please specify at least 4 candidate keys.";
"Maximum 15 candidate keys allowed." = "Maximum 15 candidate keys allowed."; "Maximum 15 candidate keys allowed." = "Maximum 15 candidate keys allowed.";
"⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ Phrase replacement mode enabled, interfering user phrase entry."; "⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ Phrase replacement mode enabled, interfering user phrase entry.";
"⚠︎ Unhandlable: Chars and Readings in buffer doesn't match." = "⚠︎ Unhandlable: Chars and Readings in buffer doesn't match."; "⚠︎ Beware: Chars and Readings in buffer doesn't match." = "⚠︎ Beware: Chars and Readings in buffer doesn't match.";
"Per-Char Select Mode" = "Per-Char Select Mode"; "Per-Char Select Mode" = "Per-Char Select Mode";
"CNS11643 Mode" = "CNS11643 Mode"; "CNS11643 Mode" = "CNS11643 Mode";
"JIS Shinjitai Output" = "JIS Shinjitai Output"; "JIS Shinjitai Output" = "JIS Shinjitai Output";
@ -85,6 +87,7 @@
// SwiftUI Preferences // SwiftUI Preferences
"(Shift+)Space:" = "(Shift+)Space:"; "(Shift+)Space:" = "(Shift+)Space:";
"Allow backspace-editing miscomposed readings" = "Allow backspace-editing miscomposed readings";
"Allow boosting / excluding a candidate of single kanji" = "Allow boosting / excluding a candidate of single kanji"; "Allow boosting / excluding a candidate of single kanji" = "Allow boosting / excluding a candidate of single kanji";
"Allow using Enter key to confirm associated candidate selection" = "Allow using Enter key to confirm associated candidate selection"; "Allow using Enter key to confirm associated candidate selection" = "Allow using Enter key to confirm associated candidate selection";
"Always use fixed listing order in candidate window" = "Always use fixed listing order in candidate window"; "Always use fixed listing order in candidate window" = "Always use fixed listing order in candidate window";

View File

@ -1,3 +1,5 @@
"vChewing" = "威注音入力アプリ";
"vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability." = "臨時記憶モジュールの観測行為による威注音入力アプリの意外中止は発生した。威注音入力アプリの無事利用のために、既存臨時記憶データは全てお消しした。";
"About vChewing…" = "威注音について…"; "About vChewing…" = "威注音について…";
"vChewing Preferences…" = "入力機能設定…"; "vChewing Preferences…" = "入力機能設定…";
"Uninstallation" = "入力アプリの卸除(おろしのぞき)"; "Uninstallation" = "入力アプリの卸除(おろしのぞき)";
@ -37,7 +39,7 @@
"Please specify at least 4 candidate keys." = "言選り用キー陣列に少なくとも4つのキーをご登録ください。"; "Please specify at least 4 candidate keys." = "言選り用キー陣列に少なくとも4つのキーをご登録ください。";
"Maximum 15 candidate keys allowed." = "言選り用キー陣列には最多15つキー登録できます。"; "Maximum 15 candidate keys allowed." = "言選り用キー陣列には最多15つキー登録できます。";
"⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 言葉置換機能稼働中、新添付言葉にも影響。"; "⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 言葉置換機能稼働中、新添付言葉にも影響。";
"⚠︎ Unhandlable: Chars and Readings in buffer doesn't match." = "⚠︎ 緩衝列の字数は読みの数と不同等のため、対処不可。"; "⚠︎ Beware: Chars and Readings in buffer doesn't match." = "⚠︎ 注意:緩衝列の字数は読みの数と不同等。";
"Per-Char Select Mode" = "全候補入力モード"; "Per-Char Select Mode" = "全候補入力モード";
"CNS11643 Mode" = "全字庫モード"; "CNS11643 Mode" = "全字庫モード";
"JIS Shinjitai Output" = "JIS 新字体モード"; "JIS Shinjitai Output" = "JIS 新字体モード";
@ -85,6 +87,7 @@
// SwiftUI Preferences // SwiftUI Preferences
"(Shift+)Space:" = "(Shift+)Space:"; "(Shift+)Space:" = "(Shift+)Space:";
"Allow backspace-editing miscomposed readings" = "効かぬ音読みを BackSpace で再編集";
"Allow boosting / excluding a candidate of single kanji" = "即排除/即最優先にできる候補の文字数の最低限は1字とする"; "Allow boosting / excluding a candidate of single kanji" = "即排除/即最優先にできる候補の文字数の最低限は1字とする";
"Allow using Enter key to confirm associated candidate selection" = "Enter キーを連想語彙候補の確認のために使う"; "Allow using Enter key to confirm associated candidate selection" = "Enter キーを連想語彙候補の確認のために使う";
"Always use fixed listing order in candidate window" = "候補文字を固定順番で陳列する"; "Always use fixed listing order in candidate window" = "候補文字を固定順番で陳列する";

View File

@ -1,3 +1,5 @@
"vChewing" = "威注音输入法";
"vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability." = "威注音输入法的使用者半衰记忆模组在观测时崩溃,相关半衰记忆资料档案内容已全部清空。";
"About vChewing…" = "关于威注音…"; "About vChewing…" = "关于威注音…";
"vChewing Preferences…" = "威注音偏好设定…"; "vChewing Preferences…" = "威注音偏好设定…";
"Uninstallation" = "卸除输入法"; "Uninstallation" = "卸除输入法";
@ -37,7 +39,7 @@
"Please specify at least 4 candidate keys." = "请至少指定四个选字键。"; "Please specify at least 4 candidate keys." = "请至少指定四个选字键。";
"Maximum 15 candidate keys allowed." = "选字键最多只能指定十五个。"; "Maximum 15 candidate keys allowed." = "选字键最多只能指定十五个。";
"⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 语汇置换功能已启用,会波及语汇自订。"; "⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 语汇置换功能已启用,会波及语汇自订。";
"⚠︎ Unhandlable: Chars and Readings in buffer doesn't match." = "⚠︎ 无法处理组字区字数与读音数不对应的情形。"; "⚠︎ Beware: Chars and Readings in buffer doesn't match." = "⚠︎ 注意:组字区字数与读音数不对应。";
"Per-Char Select Mode" = "仿真逐字选字输入"; "Per-Char Select Mode" = "仿真逐字选字输入";
"CNS11643 Mode" = "全字库模式"; "CNS11643 Mode" = "全字库模式";
"JIS Shinjitai Output" = "JIS 新字体模式"; "JIS Shinjitai Output" = "JIS 新字体模式";
@ -85,6 +87,7 @@
// SwiftUI Preferences // SwiftUI Preferences
"(Shift+)Space:" = "(Shift+)空格键:"; "(Shift+)Space:" = "(Shift+)空格键:";
"Allow backspace-editing miscomposed readings" = "允许对无效的读音使用 BackSpace 编辑";
"Allow boosting / excluding a candidate of single kanji" = "将可以就地升权/排除的候选字词的最短词长设为单个汉字"; "Allow boosting / excluding a candidate of single kanji" = "将可以就地升权/排除的候选字词的最短词长设为单个汉字";
"Allow using Enter key to confirm associated candidate selection" = "允许使用 Enter 确认当前选中的联想词"; "Allow using Enter key to confirm associated candidate selection" = "允许使用 Enter 确认当前选中的联想词";
"Always use fixed listing order in candidate window" = "以固定顺序来陈列选字窗内的候选字"; "Always use fixed listing order in candidate window" = "以固定顺序来陈列选字窗内的候选字";

View File

@ -1,3 +1,5 @@
"vChewing" = "威注音輸入法";
"vChewing crashed while handling previously loaded UOM observation data. These data files are cleaned now to ensure the usability." = "威注音輸入法的使用者半衰記憶模組在觀測時崩潰,相關半衰記憶資料檔案內容已全部清空。";
"About vChewing…" = "關於威注音…"; "About vChewing…" = "關於威注音…";
"vChewing Preferences…" = "威注音偏好設定…"; "vChewing Preferences…" = "威注音偏好設定…";
"Uninstallation" = "卸除輸入法"; "Uninstallation" = "卸除輸入法";
@ -37,7 +39,7 @@
"Please specify at least 4 candidate keys." = "請至少指定四個選字鍵。"; "Please specify at least 4 candidate keys." = "請至少指定四個選字鍵。";
"Maximum 15 candidate keys allowed." = "選字鍵最多只能指定十五個。"; "Maximum 15 candidate keys allowed." = "選字鍵最多只能指定十五個。";
"⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 語彙置換功能已啟用,會波及語彙自訂。"; "⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 語彙置換功能已啟用,會波及語彙自訂。";
"⚠︎ Unhandlable: Chars and Readings in buffer doesn't match." = "⚠︎ 無法處理組字區字數與讀音數不對應的情形。"; "⚠︎ Beware: Chars and Readings in buffer doesn't match." = "⚠︎ 注意:組字區字數與讀音數不對應。";
"Per-Char Select Mode" = "模擬逐字選字輸入"; "Per-Char Select Mode" = "模擬逐字選字輸入";
"CNS11643 Mode" = "全字庫模式"; "CNS11643 Mode" = "全字庫模式";
"JIS Shinjitai Output" = "JIS 新字體模式"; "JIS Shinjitai Output" = "JIS 新字體模式";
@ -85,6 +87,7 @@
// SwiftUI Preferences // SwiftUI Preferences
"(Shift+)Space:" = "(Shift+)空格鍵:"; "(Shift+)Space:" = "(Shift+)空格鍵:";
"Allow backspace-editing miscomposed readings" = "允許對無效的讀音使用 BackSpace 編輯";
"Allow boosting / excluding a candidate of single kanji" = "將可以就地升權/排除的候選字詞的最短詞長設為單個漢字"; "Allow boosting / excluding a candidate of single kanji" = "將可以就地升權/排除的候選字詞的最短詞長設為單個漢字";
"Allow using Enter key to confirm associated candidate selection" = "允許使用 Enter 確認當前選中的聯想詞"; "Allow using Enter key to confirm associated candidate selection" = "允許使用 Enter 確認當前選中的聯想詞";
"Always use fixed listing order in candidate window" = "以固定順序來陳列選字窗內的候選字"; "Always use fixed listing order in candidate window" = "以固定順序來陳列選字窗內的候選字";

View File

@ -26,6 +26,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import Cocoa import Cocoa
public enum CandidateLayout {
case horizontal
case vertical
}
public class CandidateKeyLabel: NSObject { public class CandidateKeyLabel: NSObject {
public private(set) var key: String public private(set) var key: String
public private(set) var displayedText: String public private(set) var displayedText: String
@ -38,21 +43,39 @@ public class CandidateKeyLabel: NSObject {
} }
public protocol ctlCandidateDelegate: AnyObject { public protocol ctlCandidateDelegate: AnyObject {
func candidateCountForController(_ controller: ctlCandidate) -> Int func handleDelegateEvent(_ event: NSEvent!) -> Bool
func ctlCandidate(_ controller: ctlCandidate, candidateAtIndex index: Int) func candidateCountForController(_ controller: ctlCandidateProtocol) -> Int
func candidatesForController(_ controller: ctlCandidateProtocol) -> [(String, String)]
func ctlCandidate(_ controller: ctlCandidateProtocol, candidateAtIndex index: Int)
-> (String, String) -> (String, String)
func ctlCandidate( func ctlCandidate(
_ controller: ctlCandidate, didSelectCandidateAtIndex index: Int _ controller: ctlCandidateProtocol, didSelectCandidateAtIndex index: Int
) )
} }
public class ctlCandidate: NSWindowController { public protocol ctlCandidateProtocol {
public enum Layout { var currentLayout: CandidateLayout { get set }
case horizontal var delegate: ctlCandidateDelegate? { get set }
case vertical var selectedCandidateIndex: Int { get set }
} var visible: Bool { get set }
var windowTopLeftPoint: NSPoint { get set }
var keyLabels: [CandidateKeyLabel] { get set }
var keyLabelFont: NSFont { get set }
var candidateFont: NSFont { get set }
var tooltip: String { get set }
public var currentLayout: Layout = .horizontal init(_ layout: CandidateLayout)
func reloadData()
func showNextPage() -> Bool
func showPreviousPage() -> Bool
func highlightNextCandidate() -> Bool
func highlightPreviousCandidate() -> Bool
func candidateIndexAtKeyLabelIndex(_: Int) -> Int
func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight height: CGFloat)
}
public class ctlCandidate: NSWindowController, ctlCandidateProtocol {
public var currentLayout: CandidateLayout = .horizontal
public weak var delegate: ctlCandidateDelegate? { public weak var delegate: ctlCandidateDelegate? {
didSet { didSet {
reloadData() reloadData()
@ -85,6 +108,16 @@ public class ctlCandidate: NSWindowController {
} }
} }
public required init(_: CandidateLayout = .horizontal) {
super.init(window: .init())
visible = false
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public var keyLabels: [CandidateKeyLabel] = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] public var keyLabels: [CandidateKeyLabel] = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
.map { .map {
CandidateKeyLabel(key: $0, displayedText: $0) CandidateKeyLabel(key: $0, displayedText: $0)

View File

@ -0,0 +1,141 @@
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
/*
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
1. The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
2. No trademark license is granted to use the trade names, trademarks, service
marks, or product names of Contributor, except as required to fulfill notice
requirements above.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import Foundation
import InputMethodKit
public class ctlCandidateIMK: IMKCandidates, ctlCandidateProtocol {
public var currentLayout: CandidateLayout = .horizontal
public weak var delegate: ctlCandidateDelegate? {
didSet {
reloadData()
}
}
public var selectedCandidateIndex: Int = .max
public var visible: Bool = false {
didSet {
if visible {
show()
} else {
hide()
}
}
}
public var windowTopLeftPoint: NSPoint = .init(x: 0, y: 0) {
didSet {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) {
self.set(windowTopLeftPoint: self.windowTopLeftPoint, bottomOutOfScreenAdjustmentHeight: 0)
}
}
}
public var keyLabels: [CandidateKeyLabel] = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
.map {
CandidateKeyLabel(key: $0, displayedText: $0)
}
public var keyLabelFont: NSFont = NSFont.monospacedDigitSystemFont(
ofSize: 14, weight: .medium
)
public var candidateFont: NSFont = NSFont.systemFont(ofSize: 18)
public var tooltip: String = ""
var keyCount = 0
var displayedCandidates = [String]()
public func specifyLayout(_ layout: CandidateLayout = .horizontal) {
currentLayout = layout
switch currentLayout {
case .horizontal:
setPanelType(kIMKScrollingGridCandidatePanel)
case .vertical:
setPanelType(kIMKSingleColumnScrollingCandidatePanel)
}
setAttributes([IMKCandidatesSendServerKeyEventFirst: false])
}
public required init(_ layout: CandidateLayout = .horizontal) {
super.init(server: theServer, panelType: kIMKScrollingGridCandidatePanel)
specifyLayout(layout)
visible = false
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public func reloadData() {
guard let delegate = delegate else { return }
let candidates = delegate.candidatesForController(self).map { theCandidate -> String in
let theConverted = IME.kanjiConversionIfRequired(theCandidate.1)
return (theCandidate.1 == theConverted) ? theCandidate.1 : "\(theConverted)(\(theCandidate.1))"
}
setCandidateData(candidates)
keyCount = selectionKeys().count
selectedCandidateIndex = 0
update()
}
public func showNextPage() -> Bool {
if selectedCandidateIndex == candidates(self).count - 1 { return false }
selectedCandidateIndex = min(selectedCandidateIndex + keyCount, candidates(self).count - 1)
return selectCandidate(withIdentifier: selectedCandidateIndex)
}
public func showPreviousPage() -> Bool {
if selectedCandidateIndex == 0 { return true }
selectedCandidateIndex = max(selectedCandidateIndex - keyCount, 0)
return selectCandidate(withIdentifier: selectedCandidateIndex)
}
public func highlightNextCandidate() -> Bool {
if selectedCandidateIndex == candidates(self).count - 1 { return false }
selectedCandidateIndex = min(selectedCandidateIndex + 1, candidates(self).count - 1)
return selectCandidate(withIdentifier: selectedCandidateIndex)
}
public func highlightPreviousCandidate() -> Bool {
if selectedCandidateIndex == 0 { return true }
selectedCandidateIndex = max(selectedCandidateIndex - 1, 0)
return selectCandidate(withIdentifier: selectedCandidateIndex)
}
public func candidateIndexAtKeyLabelIndex(_: Int) -> Int {
selectedCandidateIndex
}
public func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight _: CGFloat = 0) {
setCandidateFrameTopLeft(windowTopLeftPoint)
}
override public func handle(_ event: NSEvent!, client _: Any!) -> Bool {
guard let delegate = delegate else { return false }
return delegate.handleDelegateEvent(event)
}
}

View File

@ -370,7 +370,7 @@ public class ctlCandidateUniversal: ctlCandidate {
private var nextPageButton: NSButton private var nextPageButton: NSButton
private var pageCounterLabel: NSTextField private var pageCounterLabel: NSTextField
private var currentPageIndex: Int = 0 private var currentPageIndex: Int = 0
override public var currentLayout: Layout { override public var currentLayout: CandidateLayout {
get { candidateView.isVerticalLayout ? .vertical : .horizontal } get { candidateView.isVerticalLayout ? .vertical : .horizontal }
set { set {
switch newValue { switch newValue {
@ -380,7 +380,7 @@ public class ctlCandidateUniversal: ctlCandidate {
} }
} }
public init(_ layout: Layout = .horizontal) { public required init(_ layout: CandidateLayout = .horizontal) {
var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0) var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0)
let styleMask: NSWindow.StyleMask = [.nonactivatingPanel] let styleMask: NSWindow.StyleMask = [.nonactivatingPanel]
let panel = NSPanel( let panel = NSPanel(
@ -448,7 +448,8 @@ public class ctlCandidateUniversal: ctlCandidate {
// MARK: Post-Init() // MARK: Post-Init()
super.init(window: panel) super.init(layout)
window = panel
currentLayout = layout currentLayout = layout
candidateView.target = self candidateView.target = self

View File

@ -28,19 +28,19 @@ import SwiftUI
struct suiPrefPaneDictionary: View { struct suiPrefPaneDictionary: View {
private var fdrDefault = mgrLangModel.dataFolderPath(isDefaultFolder: true) private var fdrDefault = mgrLangModel.dataFolderPath(isDefaultFolder: true)
@State private var tbxUserDataPathSpecified: String = @State private var tbxUserDataPathSpecified: String =
UserDefaults.standard.string(forKey: UserDef.kUserDataFolderSpecified) UserDefaults.standard.string(forKey: UserDef.kUserDataFolderSpecified.rawValue)
?? mgrLangModel.dataFolderPath(isDefaultFolder: true) ?? mgrLangModel.dataFolderPath(isDefaultFolder: true)
@State private var selAutoReloadUserData: Bool = UserDefaults.standard.bool( @State private var selAutoReloadUserData: Bool = UserDefaults.standard.bool(
forKey: UserDef.kShouldAutoReloadUserDataFiles) forKey: UserDef.kShouldAutoReloadUserDataFiles.rawValue)
@State private var selEnableCNS11643: Bool = UserDefaults.standard.bool(forKey: UserDef.kCNS11643Enabled) @State private var selEnableCNS11643: Bool = UserDefaults.standard.bool(forKey: UserDef.kCNS11643Enabled.rawValue)
@State private var selEnableSymbolInputSupport: Bool = UserDefaults.standard.bool( @State private var selEnableSymbolInputSupport: Bool = UserDefaults.standard.bool(
forKey: UserDef.kSymbolInputEnabled) forKey: UserDef.kSymbolInputEnabled.rawValue)
@State private var selAllowBoostingSingleKanjiAsUserPhrase: Bool = UserDefaults.standard.bool( @State private var selAllowBoostingSingleKanjiAsUserPhrase: Bool = UserDefaults.standard.bool(
forKey: UserDef.kAllowBoostingSingleKanjiAsUserPhrase) forKey: UserDef.kAllowBoostingSingleKanjiAsUserPhrase.rawValue)
@State private var selFetchSuggestionsFromUserOverrideModel: Bool = UserDefaults.standard.bool( @State private var selFetchSuggestionsFromUserOverrideModel: Bool = UserDefaults.standard.bool(
forKey: UserDef.kFetchSuggestionsFromUserOverrideModel) forKey: UserDef.kFetchSuggestionsFromUserOverrideModel.rawValue)
@State private var selUseFixecCandidateOrderOnSelection: Bool = UserDefaults.standard.bool( @State private var selUseFixecCandidateOrderOnSelection: Bool = UserDefaults.standard.bool(
forKey: UserDef.kUseFixecCandidateOrderOnSelection) forKey: UserDef.kUseFixecCandidateOrderOnSelection.rawValue)
private let contentWidth: Double = { private let contentWidth: Double = {
switch mgrPrefs.appleLanguages[0] { switch mgrPrefs.appleLanguages[0] {
case "ja": case "ja":

View File

@ -29,27 +29,30 @@ import SwiftUI
struct suiPrefPaneExperience: View { struct suiPrefPaneExperience: View {
@State private var selSelectionKeysList = mgrPrefs.suggestedCandidateKeys @State private var selSelectionKeysList = mgrPrefs.suggestedCandidateKeys
@State private var selSelectionKeys = @State private var selSelectionKeys =
(UserDefaults.standard.string(forKey: UserDef.kCandidateKeys) ?? mgrPrefs.defaultCandidateKeys) as String (UserDefaults.standard.string(forKey: UserDef.kCandidateKeys.rawValue) ?? mgrPrefs.defaultCandidateKeys) as String
@State private var selCursorPosition = @State private var selCursorPosition =
UserDefaults.standard.bool( UserDefaults.standard.bool(
forKey: UserDef.kuseRearCursorMode) ? 1 : 0 forKey: UserDef.kUseRearCursorMode.rawValue) ? 1 : 0
@State private var selPushCursorAfterSelection = UserDefaults.standard.bool( @State private var selPushCursorAfterSelection = UserDefaults.standard.bool(
forKey: UserDef.kMoveCursorAfterSelectingCandidate) forKey: UserDef.kMoveCursorAfterSelectingCandidate.rawValue)
@State private var selKeyBehaviorShiftTab = @State private var selKeyBehaviorShiftTab =
UserDefaults.standard.bool(forKey: UserDef.kSpecifyShiftTabKeyBehavior) ? 1 : 0 UserDefaults.standard.bool(forKey: UserDef.kSpecifyShiftTabKeyBehavior.rawValue) ? 1 : 0
@State private var selKeyBehaviorShiftSpace = @State private var selKeyBehaviorShiftSpace =
UserDefaults.standard.bool( UserDefaults.standard.bool(
forKey: UserDef.kSpecifyShiftSpaceKeyBehavior) ? 1 : 0 forKey: UserDef.kSpecifyShiftSpaceKeyBehavior.rawValue) ? 1 : 0
@State private var selKeyBehaviorSpaceForCallingCandidate = UserDefaults.standard.bool( @State private var selKeyBehaviorSpaceForCallingCandidate = UserDefaults.standard.bool(
forKey: UserDef.kChooseCandidateUsingSpace) forKey: UserDef.kChooseCandidateUsingSpace.rawValue)
@State private var selKeyBehaviorESCForClearingTheBuffer = UserDefaults.standard.bool( @State private var selKeyBehaviorESCForClearingTheBuffer = UserDefaults.standard.bool(
forKey: UserDef.kEscToCleanInputBuffer) forKey: UserDef.kEscToCleanInputBuffer.rawValue)
@State private var selEnableSCPCTypingMode = UserDefaults.standard.bool(forKey: UserDef.kUseSCPCTypingMode) @State private var selEnableSCPCTypingMode = UserDefaults.standard.bool(forKey: UserDef.kUseSCPCTypingMode.rawValue)
@State private var selComposingBufferSize = UserDefaults.standard.integer(forKey: UserDef.kComposingBufferSize) @State private var selComposingBufferSize = UserDefaults.standard.integer(
forKey: UserDef.kComposingBufferSize.rawValue)
@State private var selAutoCorrectReadingCombination = UserDefaults.standard.bool( @State private var selAutoCorrectReadingCombination = UserDefaults.standard.bool(
forKey: UserDef.kAutoCorrectReadingCombination) forKey: UserDef.kAutoCorrectReadingCombination.rawValue)
@State private var selAlsoConfirmAssociatedCandidatesByEnter = UserDefaults.standard.bool( @State private var selAlsoConfirmAssociatedCandidatesByEnter = UserDefaults.standard.bool(
forKey: UserDef.kAlsoConfirmAssociatedCandidatesByEnter) forKey: UserDef.kAlsoConfirmAssociatedCandidatesByEnter.rawValue)
@State private var selKeepReadingUponCompositionError = UserDefaults.standard.bool(
forKey: UserDef.kKeepReadingUponCompositionError.rawValue)
private let contentWidth: Double = { private let contentWidth: Double = {
switch mgrPrefs.appleLanguages[0] { switch mgrPrefs.appleLanguages[0] {
case "ja": case "ja":
@ -188,6 +191,12 @@ struct suiPrefPaneExperience: View {
).onChange(of: selAlsoConfirmAssociatedCandidatesByEnter) { value in ).onChange(of: selAlsoConfirmAssociatedCandidatesByEnter) { value in
mgrPrefs.alsoConfirmAssociatedCandidatesByEnter = value mgrPrefs.alsoConfirmAssociatedCandidatesByEnter = value
} }
Toggle(
LocalizedStringKey("Allow backspace-editing miscomposed readings"),
isOn: $selKeepReadingUponCompositionError
).onChange(of: selKeepReadingUponCompositionError) { value in
mgrPrefs.keepReadingUponCompositionError = value
}
} }
} }
} }

View File

@ -27,29 +27,32 @@ import SwiftUI
@available(macOS 11.0, *) @available(macOS 11.0, *)
struct suiPrefPaneGeneral: View { struct suiPrefPaneGeneral: View {
@State private var selCandidateUIFontSize = UserDefaults.standard.integer(forKey: UserDef.kCandidateListTextSize) @State private var selCandidateUIFontSize = UserDefaults.standard.integer(
forKey: UserDef.kCandidateListTextSize.rawValue)
@State private var selUILanguage: [String] = @State private var selUILanguage: [String] =
IME.arrSupportedLocales.contains( IME.arrSupportedLocales.contains(
((UserDefaults.standard.object(forKey: UserDef.kAppleLanguages) == nil) ((UserDefaults.standard.object(forKey: UserDef.kAppleLanguages.rawValue) == nil)
? ["auto"] : UserDefaults.standard.array(forKey: UserDef.kAppleLanguages) as? [String] ?? ["auto"])[0]) ? ["auto"] : UserDefaults.standard.array(forKey: UserDef.kAppleLanguages.rawValue) as? [String] ?? ["auto"])[0])
? ((UserDefaults.standard.object(forKey: UserDef.kAppleLanguages) == nil) ? ((UserDefaults.standard.object(forKey: UserDef.kAppleLanguages.rawValue) == nil)
? ["auto"] : UserDefaults.standard.array(forKey: UserDef.kAppleLanguages) as? [String] ?? ["auto"]) ? ["auto"] : UserDefaults.standard.array(forKey: UserDef.kAppleLanguages.rawValue) as? [String] ?? ["auto"])
: ["auto"] : ["auto"]
@State private var selEnableHorizontalCandidateLayout = UserDefaults.standard.bool( @State private var selEnableHorizontalCandidateLayout = UserDefaults.standard.bool(
forKey: UserDef.kUseHorizontalCandidateList) forKey: UserDef.kUseHorizontalCandidateList.rawValue)
@State private var selShowPageButtonsInCandidateUI = UserDefaults.standard.bool( @State private var selShowPageButtonsInCandidateUI = UserDefaults.standard.bool(
forKey: UserDef.kShowPageButtonsInCandidateWindow) forKey: UserDef.kShowPageButtonsInCandidateWindow.rawValue)
@State private var selEnableKanjiConvToKangXi = UserDefaults.standard.bool( @State private var selEnableKanjiConvToKangXi = UserDefaults.standard.bool(
forKey: UserDef.kChineseConversionEnabled) forKey: UserDef.kChineseConversionEnabled.rawValue)
@State private var selEnableKanjiConvToJIS = UserDefaults.standard.bool( @State private var selEnableKanjiConvToJIS = UserDefaults.standard.bool(
forKey: UserDef.kShiftJISShinjitaiOutputEnabled) forKey: UserDef.kShiftJISShinjitaiOutputEnabled.rawValue)
@State private var selShowHanyuPinyinInCompositionBuffer = UserDefaults.standard.bool( @State private var selShowHanyuPinyinInCompositionBuffer = UserDefaults.standard.bool(
forKey: UserDef.kShowHanyuPinyinInCompositionBuffer) forKey: UserDef.kShowHanyuPinyinInCompositionBuffer.rawValue)
@State private var selInlineDumpPinyinInLieuOfZhuyin = UserDefaults.standard.bool( @State private var selInlineDumpPinyinInLieuOfZhuyin = UserDefaults.standard.bool(
forKey: UserDef.kInlineDumpPinyinInLieuOfZhuyin) forKey: UserDef.kInlineDumpPinyinInLieuOfZhuyin.rawValue)
@State private var selEnableFartSuppressor = UserDefaults.standard.bool(forKey: UserDef.kShouldNotFartInLieuOfBeep) @State private var selEnableFartSuppressor = UserDefaults.standard.bool(
@State private var selEnableAutoUpdateCheck = UserDefaults.standard.bool(forKey: UserDef.kCheckUpdateAutomatically) forKey: UserDef.kShouldNotFartInLieuOfBeep.rawValue)
@State private var selEnableDebugMode = UserDefaults.standard.bool(forKey: UserDef.kIsDebugModeEnabled) @State private var selEnableAutoUpdateCheck = UserDefaults.standard.bool(
forKey: UserDef.kCheckUpdateAutomatically.rawValue)
@State private var selEnableDebugMode = UserDefaults.standard.bool(forKey: UserDef.kIsDebugModeEnabled.rawValue)
private let contentWidth: Double = { private let contentWidth: Double = {
switch mgrPrefs.appleLanguages[0] { switch mgrPrefs.appleLanguages[0] {
case "ja": case "ja":
@ -94,14 +97,14 @@ struct suiPrefPaneGeneral: View {
IME.prtDebugIntel(value[0]) IME.prtDebugIntel(value[0])
if selUILanguage == mgrPrefs.appleLanguages if selUILanguage == mgrPrefs.appleLanguages
|| (selUILanguage[0] == "auto" || (selUILanguage[0] == "auto"
&& UserDefaults.standard.object(forKey: UserDef.kAppleLanguages) == nil) && UserDefaults.standard.object(forKey: UserDef.kAppleLanguages.rawValue) == nil)
{ {
return return
} }
if selUILanguage[0] != "auto" { if selUILanguage[0] != "auto" {
mgrPrefs.appleLanguages = value mgrPrefs.appleLanguages = value
} else { } else {
UserDefaults.standard.removeObject(forKey: UserDef.kAppleLanguages) UserDefaults.standard.removeObject(forKey: UserDef.kAppleLanguages.rawValue)
} }
NSLog("vChewing App self-terminated due to UI language change.") NSLog("vChewing App self-terminated due to UI language change.")
NSApplication.shared.terminate(nil) NSApplication.shared.terminate(nil)

View File

@ -26,19 +26,20 @@ import SwiftUI
@available(macOS 11.0, *) @available(macOS 11.0, *)
struct suiPrefPaneKeyboard: View { struct suiPrefPaneKeyboard: View {
@State private var selMandarinParser = UserDefaults.standard.integer(forKey: UserDef.kMandarinParser) @State private var selMandarinParser = UserDefaults.standard.integer(forKey: UserDef.kMandarinParser.rawValue)
@State private var selBasicKeyboardLayout: String = @State private var selBasicKeyboardLayout: String =
UserDefaults.standard.string(forKey: UserDef.kBasicKeyboardLayout) ?? mgrPrefs.basicKeyboardLayout UserDefaults.standard.string(forKey: UserDef.kBasicKeyboardLayout.rawValue) ?? mgrPrefs.basicKeyboardLayout
@State private var selUsingHotKeySCPC = UserDefaults.standard.bool(forKey: UserDef.kUsingHotKeySCPC) @State private var selUsingHotKeySCPC = UserDefaults.standard.bool(forKey: UserDef.kUsingHotKeySCPC.rawValue)
@State private var selUsingHotKeyAssociates = UserDefaults.standard.bool(forKey: UserDef.kUsingHotKeyAssociates) @State private var selUsingHotKeyAssociates = UserDefaults.standard.bool(
@State private var selUsingHotKeyCNS = UserDefaults.standard.bool(forKey: UserDef.kUsingHotKeyCNS) forKey: UserDef.kUsingHotKeyAssociates.rawValue)
@State private var selUsingHotKeyKangXi = UserDefaults.standard.bool(forKey: UserDef.kUsingHotKeyKangXi) @State private var selUsingHotKeyCNS = UserDefaults.standard.bool(forKey: UserDef.kUsingHotKeyCNS.rawValue)
@State private var selUsingHotKeyJIS = UserDefaults.standard.bool(forKey: UserDef.kUsingHotKeyJIS) @State private var selUsingHotKeyKangXi = UserDefaults.standard.bool(forKey: UserDef.kUsingHotKeyKangXi.rawValue)
@State private var selUsingHotKeyJIS = UserDefaults.standard.bool(forKey: UserDef.kUsingHotKeyJIS.rawValue)
@State private var selUsingHotKeyHalfWidthASCII = UserDefaults.standard.bool( @State private var selUsingHotKeyHalfWidthASCII = UserDefaults.standard.bool(
forKey: UserDef.kUsingHotKeyHalfWidthASCII) forKey: UserDef.kUsingHotKeyHalfWidthASCII.rawValue)
@State private var selUsingHotKeyCurrencyNumerals = UserDefaults.standard.bool( @State private var selUsingHotKeyCurrencyNumerals = UserDefaults.standard.bool(
forKey: UserDef.kUsingHotKeyCurrencyNumerals) forKey: UserDef.kUsingHotKeyCurrencyNumerals.rawValue)
private let contentWidth: Double = { private let contentWidth: Double = {
switch mgrPrefs.appleLanguages[0] { switch mgrPrefs.appleLanguages[0] {

View File

@ -57,13 +57,13 @@ class ctlAboutWindow: NSWindowController {
) )
} }
@IBAction func btnBugReport(_ sender: NSButton) { @IBAction func btnBugReport(_: NSButton) {
if let url = URL(string: "https://vchewing.github.io/BUGREPORT.html") { if let url = URL(string: "https://vchewing.github.io/BUGREPORT.html") {
NSWorkspace.shared.open(url) NSWorkspace.shared.open(url)
} }
} }
@IBAction func btnWebsite(_ sender: NSButton) { @IBAction func btnWebsite(_: NSButton) {
if let url = URL(string: "https://vchewing.github.io/") { if let url = URL(string: "https://vchewing.github.io/") {
NSWorkspace.shared.open(url) NSWorkspace.shared.open(url)
} }

View File

@ -388,7 +388,8 @@ extension ctlPrefWindow: NSToolbarDelegate {
item.label = title item.label = title
if #available(macOS 11.0, *) { if #available(macOS 11.0, *) {
item.image = NSImage( item.image = NSImage(
systemSymbolName: "wrench.and.screwdriver.fill", accessibilityDescription: "General Preferences") systemSymbolName: "wrench.and.screwdriver.fill", accessibilityDescription: "General Preferences"
)
} else { } else {
item.image = NSImage(named: NSImage.homeTemplateName) item.image = NSImage(named: NSImage.homeTemplateName)
} }
@ -399,7 +400,8 @@ extension ctlPrefWindow: NSToolbarDelegate {
item.label = title item.label = title
if #available(macOS 11.0, *) { if #available(macOS 11.0, *) {
item.image = NSImage( item.image = NSImage(
systemSymbolName: "person.fill.questionmark", accessibilityDescription: "Experiences Preferences") systemSymbolName: "person.fill.questionmark", accessibilityDescription: "Experiences Preferences"
)
} else { } else {
item.image = NSImage(named: NSImage.flowViewTemplateName) item.image = NSImage(named: NSImage.flowViewTemplateName)
} }
@ -410,7 +412,8 @@ extension ctlPrefWindow: NSToolbarDelegate {
item.label = title item.label = title
if #available(macOS 11.0, *) { if #available(macOS 11.0, *) {
item.image = NSImage( item.image = NSImage(
systemSymbolName: "character.book.closed.fill", accessibilityDescription: "Dictionary Preferences") systemSymbolName: "character.book.closed.fill", accessibilityDescription: "Dictionary Preferences"
)
} else { } else {
item.image = NSImage(named: NSImage.bookmarksTemplateName) item.image = NSImage(named: NSImage.bookmarksTemplateName)
} }

View File

@ -591,12 +591,23 @@
<binding destination="32" name="value" keyPath="values.AlsoConfirmAssociatedCandidatesByEnter" id="P1C-j9-N88"/> <binding destination="32" name="value" keyPath="values.AlsoConfirmAssociatedCandidatesByEnter" id="P1C-j9-N88"/>
</connections> </connections>
</button> </button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="HaB-rc-AcW">
<rect key="frame" x="19" y="40.5" width="388" height="16"/>
<buttonCell key="cell" type="check" title="Allow backspace-editing miscomposed readings" bezelStyle="regularSquare" imagePosition="left" controlSize="small" inset="2" id="chkKeepReadingUponCompositionError">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>
<connections>
<binding destination="32" name="value" keyPath="values.KeepReadingUponCompositionError" id="ddF-qg-jes"/>
</connections>
</button>
</subviews> </subviews>
<constraints> <constraints>
<constraint firstItem="n7q-ew-DYu" firstAttribute="leading" secondItem="XWo-36-xGi" secondAttribute="leading" constant="33" id="2gT-9Z-6F4"/> <constraint firstItem="n7q-ew-DYu" firstAttribute="leading" secondItem="XWo-36-xGi" secondAttribute="leading" constant="33" id="2gT-9Z-6F4"/>
<constraint firstItem="109" firstAttribute="top" secondItem="YkJ-lr-EP6" secondAttribute="bottom" constant="9" id="3tl-Zc-C5n"/> <constraint firstItem="109" firstAttribute="top" secondItem="YkJ-lr-EP6" secondAttribute="bottom" constant="9" id="3tl-Zc-C5n"/>
<constraint firstItem="13" firstAttribute="top" secondItem="d5f-bq-dRQ" secondAttribute="bottom" constant="8" symbolic="YES" id="4pp-NX-pCc"/> <constraint firstItem="13" firstAttribute="top" secondItem="d5f-bq-dRQ" secondAttribute="bottom" constant="8" symbolic="YES" id="4pp-NX-pCc"/>
<constraint firstItem="YkJ-lr-EP6" firstAttribute="top" secondItem="J0f-Aw-dxC" secondAttribute="bottom" constant="7" id="5fd-qi-hJ6"/> <constraint firstItem="YkJ-lr-EP6" firstAttribute="top" secondItem="J0f-Aw-dxC" secondAttribute="bottom" constant="7" id="5fd-qi-hJ6"/>
<constraint firstItem="HaB-rc-AcW" firstAttribute="leading" secondItem="6MM-WC-Mpd" secondAttribute="leading" id="7Fs-9l-g66"/>
<constraint firstItem="d5f-bq-dRQ" firstAttribute="leading" secondItem="XWo-36-xGi" secondAttribute="leading" constant="20" id="9wo-7x-RKb"/> <constraint firstItem="d5f-bq-dRQ" firstAttribute="leading" secondItem="XWo-36-xGi" secondAttribute="leading" constant="20" id="9wo-7x-RKb"/>
<constraint firstItem="TMn-LX-3Ub" firstAttribute="top" secondItem="7z2-DD-c58" secondAttribute="bottom" constant="9" id="AXY-LV-HMX"/> <constraint firstItem="TMn-LX-3Ub" firstAttribute="top" secondItem="7z2-DD-c58" secondAttribute="bottom" constant="9" id="AXY-LV-HMX"/>
<constraint firstItem="7z2-DD-c58" firstAttribute="leading" secondItem="XWo-36-xGi" secondAttribute="leading" constant="34" id="BUo-Us-u2B"/> <constraint firstItem="7z2-DD-c58" firstAttribute="leading" secondItem="XWo-36-xGi" secondAttribute="leading" constant="34" id="BUo-Us-u2B"/>
@ -618,6 +629,7 @@
<constraint firstItem="IpX-f7-rTL" firstAttribute="top" secondItem="XWo-36-xGi" secondAttribute="top" constant="20" id="YaG-ab-LJH"/> <constraint firstItem="IpX-f7-rTL" firstAttribute="top" secondItem="XWo-36-xGi" secondAttribute="top" constant="20" id="YaG-ab-LJH"/>
<constraint firstItem="uHU-aL-du7" firstAttribute="top" secondItem="IpX-f7-rTL" secondAttribute="bottom" constant="8" symbolic="YES" id="aet-Zq-v6x"/> <constraint firstItem="uHU-aL-du7" firstAttribute="top" secondItem="IpX-f7-rTL" secondAttribute="bottom" constant="8" symbolic="YES" id="aet-Zq-v6x"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="TMn-LX-3Ub" secondAttribute="trailing" constant="20" symbolic="YES" id="atz-4L-U9s"/> <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="TMn-LX-3Ub" secondAttribute="trailing" constant="20" symbolic="YES" id="atz-4L-U9s"/>
<constraint firstItem="HaB-rc-AcW" firstAttribute="top" secondItem="6MM-WC-Mpd" secondAttribute="bottom" constant="6" symbolic="YES" id="cBa-57-gWH"/>
<constraint firstItem="ETa-09-qWI" firstAttribute="top" secondItem="IpX-f7-rTL" secondAttribute="bottom" constant="11" id="cx2-US-uOU"/> <constraint firstItem="ETa-09-qWI" firstAttribute="top" secondItem="IpX-f7-rTL" secondAttribute="bottom" constant="11" id="cx2-US-uOU"/>
<constraint firstItem="6MM-WC-Mpd" firstAttribute="top" secondItem="j8R-Hj-3dj" secondAttribute="bottom" constant="6" id="dmy-Au-peI"/> <constraint firstItem="6MM-WC-Mpd" firstAttribute="top" secondItem="j8R-Hj-3dj" secondAttribute="bottom" constant="6" id="dmy-Au-peI"/>
<constraint firstItem="YkJ-lr-EP6" firstAttribute="leading" secondItem="XWo-36-xGi" secondAttribute="leading" constant="33" id="e3v-m2-co7"/> <constraint firstItem="YkJ-lr-EP6" firstAttribute="leading" secondItem="XWo-36-xGi" secondAttribute="leading" constant="33" id="e3v-m2-co7"/>
@ -630,6 +642,7 @@
<constraint firstItem="6MM-WC-Mpd" firstAttribute="leading" secondItem="j8R-Hj-3dj" secondAttribute="leading" id="mbl-sV-kc8"/> <constraint firstItem="6MM-WC-Mpd" firstAttribute="leading" secondItem="j8R-Hj-3dj" secondAttribute="leading" id="mbl-sV-kc8"/>
<constraint firstItem="mzw-F2-aAQ" firstAttribute="leading" secondItem="XWo-36-xGi" secondAttribute="leading" constant="20" id="pHT-DE-qdx"/> <constraint firstItem="mzw-F2-aAQ" firstAttribute="leading" secondItem="XWo-36-xGi" secondAttribute="leading" constant="20" id="pHT-DE-qdx"/>
<constraint firstItem="ETa-09-qWI" firstAttribute="leading" secondItem="XWo-36-xGi" secondAttribute="leading" constant="33" id="qFL-i6-eUT"/> <constraint firstItem="ETa-09-qWI" firstAttribute="leading" secondItem="XWo-36-xGi" secondAttribute="leading" constant="33" id="qFL-i6-eUT"/>
<constraint firstItem="HaB-rc-AcW" firstAttribute="trailing" secondItem="6MM-WC-Mpd" secondAttribute="trailing" id="rA7-0f-akd"/>
<constraint firstItem="JG6-RM-ZdJ" firstAttribute="top" secondItem="uHU-aL-du7" secondAttribute="bottom" constant="8" id="shS-7h-z7u"/> <constraint firstItem="JG6-RM-ZdJ" firstAttribute="top" secondItem="uHU-aL-du7" secondAttribute="bottom" constant="8" id="shS-7h-z7u"/>
<constraint firstItem="TMn-LX-3Ub" firstAttribute="leading" secondItem="XWo-36-xGi" secondAttribute="leading" constant="20" id="tFX-Eg-X70"/> <constraint firstItem="TMn-LX-3Ub" firstAttribute="leading" secondItem="XWo-36-xGi" secondAttribute="leading" constant="20" id="tFX-Eg-X70"/>
<constraint firstItem="J0f-Aw-dxC" firstAttribute="leading" secondItem="XWo-36-xGi" secondAttribute="leading" constant="20" id="v75-cS-TsO"/> <constraint firstItem="J0f-Aw-dxC" firstAttribute="leading" secondItem="XWo-36-xGi" secondAttribute="leading" constant="20" id="v75-cS-TsO"/>

View File

@ -43,6 +43,7 @@
"chkAlsoConfirmAssociatedCandidatesByEnter.title" = "Allow using Enter key to confirm associated candidate selection"; "chkAlsoConfirmAssociatedCandidatesByEnter.title" = "Allow using Enter key to confirm associated candidate selection";
"chkAutoCorrectReadingCombination.title" = "Automatically correct reading combinations when typing"; "chkAutoCorrectReadingCombination.title" = "Automatically correct reading combinations when typing";
"chkFetchSuggestionsFromUserOverrideModel.title" = "Applying typing suggestions from half-life user override model"; "chkFetchSuggestionsFromUserOverrideModel.title" = "Applying typing suggestions from half-life user override model";
"chkKeepReadingUponCompositionError.title" = "Allow backspace-editing miscomposed readings";
"chkUseFixecCandidateOrderOnSelection.title" = "Always use fixed listing order in candidate window"; "chkUseFixecCandidateOrderOnSelection.title" = "Always use fixed listing order in candidate window";
"DbW-eq-ZdB.title" = "Starlight"; "DbW-eq-ZdB.title" = "Starlight";
"dIN-TZ-67g.title" = "Space to +cycle candidates, Shift+Space to +cycle pages"; "dIN-TZ-67g.title" = "Space to +cycle candidates, Shift+Space to +cycle pages";

View File

@ -43,6 +43,7 @@
"chkAlsoConfirmAssociatedCandidatesByEnter.title" = "Enter キーを連想語彙候補の確認のために使う"; "chkAlsoConfirmAssociatedCandidatesByEnter.title" = "Enter キーを連想語彙候補の確認のために使う";
"chkAutoCorrectReadingCombination.title" = "入力中で打ち間違った発音組み合わせを自動的に訂正する"; "chkAutoCorrectReadingCombination.title" = "入力中で打ち間違った発音組み合わせを自動的に訂正する";
"chkFetchSuggestionsFromUserOverrideModel.title" = "入力中で臨時記憶モジュールからお薦めの候補を自動的に選ぶ"; "chkFetchSuggestionsFromUserOverrideModel.title" = "入力中で臨時記憶モジュールからお薦めの候補を自動的に選ぶ";
"chkKeepReadingUponCompositionError.title" = "効かぬ音読みを BackSpace で再編集";
"chkUseFixecCandidateOrderOnSelection.title" = "候補文字を固定順番で陳列する"; "chkUseFixecCandidateOrderOnSelection.title" = "候補文字を固定順番で陳列する";
"DbW-eq-ZdB.title" = "星光"; "DbW-eq-ZdB.title" = "星光";
"dIN-TZ-67g.title" = "Shift+Space で次のページ、Space で次の候補文字を"; "dIN-TZ-67g.title" = "Shift+Space で次のページ、Space で次の候補文字を";

View File

@ -43,6 +43,7 @@
"chkAlsoConfirmAssociatedCandidatesByEnter.title" = "允许使用 Enter 确认当前选中的联想词"; "chkAlsoConfirmAssociatedCandidatesByEnter.title" = "允许使用 Enter 确认当前选中的联想词";
"chkAutoCorrectReadingCombination.title" = "敲字时自动纠正读音组合"; "chkAutoCorrectReadingCombination.title" = "敲字时自动纠正读音组合";
"chkFetchSuggestionsFromUserOverrideModel.title" = "在敲字时自动套用来自半衰记忆模组的建议"; "chkFetchSuggestionsFromUserOverrideModel.title" = "在敲字时自动套用来自半衰记忆模组的建议";
"chkKeepReadingUponCompositionError.title" = "允许对无效的读音使用 BackSpace 编辑";
"chkUseFixecCandidateOrderOnSelection.title" = "以固定顺序来陈列选字窗内的候选字"; "chkUseFixecCandidateOrderOnSelection.title" = "以固定顺序来陈列选字窗内的候选字";
"DbW-eq-ZdB.title" = "星光"; "DbW-eq-ZdB.title" = "星光";
"dIN-TZ-67g.title" = "Shift+Space 换下一页Space 换选下一个候选字。"; "dIN-TZ-67g.title" = "Shift+Space 换下一页Space 换选下一个候选字。";

View File

@ -43,6 +43,7 @@
"chkAlsoConfirmAssociatedCandidatesByEnter.title" = "允許使用 Enter 確認當前選中的聯想詞"; "chkAlsoConfirmAssociatedCandidatesByEnter.title" = "允許使用 Enter 確認當前選中的聯想詞";
"chkAutoCorrectReadingCombination.title" = "敲字時自動糾正讀音組合"; "chkAutoCorrectReadingCombination.title" = "敲字時自動糾正讀音組合";
"chkFetchSuggestionsFromUserOverrideModel.title" = "在敲字時自動套用來自半衰記憶模組的建議"; "chkFetchSuggestionsFromUserOverrideModel.title" = "在敲字時自動套用來自半衰記憶模組的建議";
"chkKeepReadingUponCompositionError.title" = "允許對無效的讀音使用 BackSpace 編輯";
"chkUseFixecCandidateOrderOnSelection.title" = "以固定順序來陳列選字窗內的候選字"; "chkUseFixecCandidateOrderOnSelection.title" = "以固定順序來陳列選字窗內的候選字";
"DbW-eq-ZdB.title" = "星光"; "DbW-eq-ZdB.title" = "星光";
"dIN-TZ-67g.title" = "Shift+Space 換下一頁Space 換選下一個候選字"; "dIN-TZ-67g.title" = "Shift+Space 換下一頁Space 換選下一個候選字";

View File

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

View File

@ -57,7 +57,7 @@ import Cocoa
) )
} }
@IBAction func btnWebsite(_ sender: NSButton) { @IBAction func btnWebsite(_: NSButton) {
if let url = URL(string: "https://vchewing.github.io/") { if let url = URL(string: "https://vchewing.github.io/") {
NSWorkspace.shared.open(url) NSWorkspace.shared.open(url)
} }

View File

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

View File

@ -116,6 +116,7 @@
5BF9DA2A28840E6200DBD48E /* template-replacements.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2528840E6200DBD48E /* template-replacements.txt */; }; 5BF9DA2A28840E6200DBD48E /* template-replacements.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2528840E6200DBD48E /* template-replacements.txt */; };
5BF9DA2B28840E6200DBD48E /* template-userphrases.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2628840E6200DBD48E /* template-userphrases.txt */; }; 5BF9DA2B28840E6200DBD48E /* template-userphrases.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2628840E6200DBD48E /* template-userphrases.txt */; };
5BF9DA2D288427E000DBD48E /* template-associatedPhrases-cht.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2C2884247800DBD48E /* template-associatedPhrases-cht.txt */; }; 5BF9DA2D288427E000DBD48E /* template-associatedPhrases-cht.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2C2884247800DBD48E /* template-associatedPhrases-cht.txt */; };
5BFDF011289635C100417BBC /* ctlCandidateIMK.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BFDF010289635C100417BBC /* ctlCandidateIMK.swift */; };
6A187E2616004C5900466B2E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6A187E2816004C5900466B2E /* MainMenu.xib */; }; 6A187E2616004C5900466B2E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6A187E2816004C5900466B2E /* MainMenu.xib */; };
6A225A1F23679F2600F685C6 /* NotarizedArchives in Resources */ = {isa = PBXBuildFile; fileRef = 6A225A1E23679F2600F685C6 /* NotarizedArchives */; }; 6A225A1F23679F2600F685C6 /* NotarizedArchives in Resources */ = {isa = PBXBuildFile; fileRef = 6A225A1E23679F2600F685C6 /* NotarizedArchives */; };
6A2E40F6253A69DA00D1AE1D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6A2E40F5253A69DA00D1AE1D /* Images.xcassets */; }; 6A2E40F6253A69DA00D1AE1D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6A2E40F5253A69DA00D1AE1D /* Images.xcassets */; };
@ -320,6 +321,7 @@
5BF9DA2528840E6200DBD48E /* template-replacements.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = "template-replacements.txt"; sourceTree = "<group>"; usesTabs = 0; }; 5BF9DA2528840E6200DBD48E /* template-replacements.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = "template-replacements.txt"; sourceTree = "<group>"; usesTabs = 0; };
5BF9DA2628840E6200DBD48E /* template-userphrases.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = "template-userphrases.txt"; sourceTree = "<group>"; usesTabs = 0; }; 5BF9DA2628840E6200DBD48E /* template-userphrases.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = "template-userphrases.txt"; sourceTree = "<group>"; usesTabs = 0; };
5BF9DA2C2884247800DBD48E /* template-associatedPhrases-cht.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; name = "template-associatedPhrases-cht.txt"; path = "../Data/components/cht/template-associatedPhrases-cht.txt"; sourceTree = "<group>"; }; 5BF9DA2C2884247800DBD48E /* template-associatedPhrases-cht.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; name = "template-associatedPhrases-cht.txt"; path = "../Data/components/cht/template-associatedPhrases-cht.txt"; sourceTree = "<group>"; };
5BFDF010289635C100417BBC /* ctlCandidateIMK.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlCandidateIMK.swift; sourceTree = "<group>"; };
5BFDF48C27B51867009523B6 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Main.strings"; sourceTree = "<group>"; }; 5BFDF48C27B51867009523B6 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Main.strings"; sourceTree = "<group>"; };
6A0D4EA215FC0D2D00ABF4B3 /* vChewing.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = vChewing.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6A0D4EA215FC0D2D00ABF4B3 /* vChewing.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = vChewing.app; sourceTree = BUILT_PRODUCTS_DIR; };
6A0D4EF515FC0DA600ABF4B3 /* IME-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "IME-Info.plist"; sourceTree = "<group>"; }; 6A0D4EF515FC0DA600ABF4B3 /* IME-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "IME-Info.plist"; sourceTree = "<group>"; };
@ -570,6 +572,7 @@
children = ( children = (
5B62A34027AE7CD900A19448 /* ctlCandidate.swift */, 5B62A34027AE7CD900A19448 /* ctlCandidate.swift */,
5B242402284B0D6500520FE4 /* ctlCandidateUniversal.swift */, 5B242402284B0D6500520FE4 /* ctlCandidateUniversal.swift */,
5BFDF010289635C100417BBC /* ctlCandidateIMK.swift */,
); );
path = CandidateUI; path = CandidateUI;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1203,6 +1206,7 @@
5BA9FD4727FEF3C9002DE248 /* PreferencesStyleController.swift in Sources */, 5BA9FD4727FEF3C9002DE248 /* PreferencesStyleController.swift in Sources */,
5B949BDB2816DDBC00D87B5D /* LMConsolidator.swift in Sources */, 5B949BDB2816DDBC00D87B5D /* LMConsolidator.swift in Sources */,
5B38F59F281E2E49007D5F5D /* 3_NodeAnchor.swift in Sources */, 5B38F59F281E2E49007D5F5D /* 3_NodeAnchor.swift in Sources */,
5BFDF011289635C100417BBC /* ctlCandidateIMK.swift in Sources */,
5B62A34727AE7CD900A19448 /* ctlCandidate.swift in Sources */, 5B62A34727AE7CD900A19448 /* ctlCandidate.swift in Sources */,
5BA9FD3F27FEF3C8002DE248 /* Pane.swift in Sources */, 5BA9FD3F27FEF3C8002DE248 /* Pane.swift in Sources */,
5BB802DA27FABA8300CF1C19 /* ctlInputMethod_Menu.swift in Sources */, 5BB802DA27FABA8300CF1C19 /* ctlInputMethod_Menu.swift in Sources */,
@ -1393,7 +1397,7 @@
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1986; CURRENT_PROJECT_VERSION = 1987;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO; GCC_DYNAMIC_NO_PIC = NO;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
@ -1403,7 +1407,7 @@
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.8.6; MARKETING_VERSION = 1.8.7;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewingTests; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewingTests;
@ -1432,13 +1436,13 @@
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1986; CURRENT_PROJECT_VERSION = 1987;
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.8.6; MARKETING_VERSION = 1.8.7;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewingTests; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewingTests;
@ -1469,7 +1473,7 @@
CODE_SIGN_IDENTITY = "-"; CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1986; CURRENT_PROJECT_VERSION = 1987;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO; GCC_DYNAMIC_NO_PIC = NO;
@ -1490,7 +1494,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MARKETING_VERSION = 1.8.6; MARKETING_VERSION = 1.8.7;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
@ -1519,7 +1523,7 @@
CODE_SIGN_IDENTITY = "-"; CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1986; CURRENT_PROJECT_VERSION = 1987;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
@ -1536,7 +1540,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MARKETING_VERSION = 1.8.6; MARKETING_VERSION = 1.8.7;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
@ -1650,7 +1654,7 @@
CODE_SIGN_IDENTITY = "-"; CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1986; CURRENT_PROJECT_VERSION = 1987;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
@ -1678,7 +1682,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MARKETING_VERSION = 1.8.6; MARKETING_VERSION = 1.8.7;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@ -1705,7 +1709,7 @@
CODE_SIGN_IDENTITY = "-"; CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1986; CURRENT_PROJECT_VERSION = 1987;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
@ -1727,7 +1731,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MARKETING_VERSION = 1.8.6; MARKETING_VERSION = 1.8.7;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
@ -1749,7 +1753,7 @@
CODE_SIGN_IDENTITY = "-"; CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1986; CURRENT_PROJECT_VERSION = 1987;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
@ -1769,7 +1773,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MARKETING_VERSION = 1.8.6; MARKETING_VERSION = 1.8.7;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@ -1791,7 +1795,7 @@
CODE_SIGN_IDENTITY = "-"; CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1986; CURRENT_PROJECT_VERSION = 1987;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
@ -1805,7 +1809,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MARKETING_VERSION = 1.8.6; MARKETING_VERSION = 1.8.7;
PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";

View File

@ -357,7 +357,7 @@ extension String {
extension vChewing.LMAssociates { extension vChewing.LMAssociates {
public mutating func forceOpenStringInstead(_ strData: String) { public mutating func forceOpenStringInstead(_ strData: String) {
strData.ranges(splitBy: "\n").filter({ !$0.isEmpty }).forEach { strData.ranges(splitBy: "\n").filter { !$0.isEmpty }.forEach {
let neta = strData[$0].split(separator: " ") let neta = strData[$0].split(separator: " ")
if neta.count >= 2 { if neta.count >= 2 {
let theKey = String(neta[0]) let theKey = String(neta[0])