From 2d444d174c329059b3ad3918658270fcda72a5c8 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Tue, 1 Feb 2022 15:05:32 +0800 Subject: [PATCH] Zonble: UserPhrases // UTF8 Surrogate Pair Fix - phase 2 - Add a feature to block users from adding user phrases when an unhandlable char appeared in the selection. --- .../Engine/ControllerModules/InputState.swift | 59 +++++++++---------- Source/Engine/ControllerModules/KeyHandler.mm | 12 ++-- Source/en.lproj/Localizable.strings | 1 + Source/ja.lproj/Localizable.strings | 1 + Source/zh-Hans.lproj/Localizable.strings | 1 + Source/zh-Hant.lproj/Localizable.strings | 1 + 6 files changed, 38 insertions(+), 37 deletions(-) diff --git a/Source/Engine/ControllerModules/InputState.swift b/Source/Engine/ControllerModules/InputState.swift index 835c4a4c..23e91434 100644 --- a/Source/Engine/ControllerModules/InputState.swift +++ b/Source/Engine/ControllerModules/InputState.swift @@ -91,16 +91,14 @@ class InputState: NSObject { class NotEmpty: InputState { @objc private(set) var composingBuffer: String @objc private(set) var cursorIndex: UInt - @objc private(set) var phrases: [InputPhrase] - @objc init(composingBuffer: String, cursorIndex: UInt, phrases: [InputPhrase]) { + @objc init(composingBuffer: String, cursorIndex: UInt) { self.composingBuffer = composingBuffer self.cursorIndex = cursorIndex - self.phrases = phrases } override var description: String { - "" + "" } } @@ -109,8 +107,8 @@ class InputState: NSObject { class Inputting: NotEmpty { @objc var poppedText: String = "" - @objc override init(composingBuffer: String, cursorIndex: UInt, phrases: [InputPhrase]) { - super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex, phrases: phrases) + @objc override init(composingBuffer: String, cursorIndex: UInt) { + super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex) } @objc var attributedString: NSAttributedString { @@ -122,7 +120,7 @@ class InputState: NSObject { } override var description: String { - ", poppedText:\(poppedText)>" + ", poppedText:\(poppedText)>" } } @@ -136,7 +134,11 @@ class InputState: NSObject { @objc private(set) var markerIndex: UInt @objc private(set) var markedRange: NSRange @objc var tooltip: String { - + + if composingBuffer.count != readings.count { + return NSLocalizedString("⚠︎ Unhandlable char selected for user phrases.", comment: "") + } + if Preferences.phraseReplacementEnabled { return NSLocalizedString("⚠︎ Phrase replacement mode enabled, interfering user phrase entry.", comment: "") } @@ -144,7 +146,7 @@ class InputState: NSObject { if markedRange.length == 0 { return "" } - + let text = (composingBuffer as NSString).substring(with: markedRange) if markedRange.length < kMinMarkRangeLength { return String(format: NSLocalizedString("\"%@\" length must ≥ 2 for a user phrase.", comment: ""), text) @@ -154,12 +156,15 @@ class InputState: NSObject { return String(format: NSLocalizedString("\"%@\" selected. ENTER to add user phrase.", comment: ""), text) } - @objc init(composingBuffer: String, cursorIndex: UInt, markerIndex: UInt, phrases: [InputPhrase]) { + @objc private(set) var readings: [String] + + @objc init(composingBuffer: String, cursorIndex: UInt, markerIndex: UInt, readings: [String]) { self.markerIndex = markerIndex let begin = min(cursorIndex, markerIndex) let end = max(cursorIndex, markerIndex) markedRange = NSMakeRange(Int(begin), Int(end - begin)) - super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex, phrases: phrases) + self.readings = readings + super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex) } @objc var attributedString: NSAttributedString { @@ -183,34 +188,26 @@ class InputState: NSObject { } override var description: String { - "" + "" } @objc func convertToInputting() -> Inputting { - let state = Inputting(composingBuffer: composingBuffer, cursorIndex: cursorIndex, phrases: phrases) + let state = Inputting(composingBuffer: composingBuffer, cursorIndex: cursorIndex) return state } @objc var validToWrite: Bool { - markedRange.length >= kMinMarkRangeLength && markedRange.length <= kMaxMarkRangeLength + if composingBuffer.count != readings.count { + return false + } + return markedRange.length >= kMinMarkRangeLength && markedRange.length <= kMaxMarkRangeLength } @objc var userPhrase: String { let text = (composingBuffer as NSString).substring(with: markedRange) - let end = markedRange.location + markedRange.length - var selectedPhrases = [InputPhrase]() - var length = 0 - for component in self.phrases { - if length >= end { - break - } - if length >= markedRange.location { - selectedPhrases.append(component) - } - length += (component.text as NSString).length - } - - let readings = selectedPhrases.map { $0.reading } + let exactBegin = StringUtils.convertToCharIndex(from: markedRange.location, in: composingBuffer) + let exactEnd = StringUtils.convertToCharIndex(from: markedRange.location + markedRange.length, in: composingBuffer) + let readings = readings[exactBegin.." + "" } } diff --git a/Source/Engine/ControllerModules/KeyHandler.mm b/Source/Engine/ControllerModules/KeyHandler.mm index ee51842a..fc3ba67e 100644 --- a/Source/Engine/ControllerModules/KeyHandler.mm +++ b/Source/Engine/ControllerModules/KeyHandler.mm @@ -545,7 +545,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; // Shift + left if (currentState.cursorIndex > 0) { NSInteger previousPosition = [StringUtils previousUtf16PositionForIndex:currentState.cursorIndex in:currentState.composingBuffer]; - InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex markerIndex:previousPosition phrases:currentState.phrases]; + InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex markerIndex:previousPosition readings:[self _currentReadings]]; stateCallback(marking); } else { errorCallback(); @@ -582,7 +582,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; // Shift + Right if (currentState.cursorIndex < currentState.composingBuffer.length) { NSInteger nextPosition = [StringUtils nextUtf16PositionForIndex:currentState.cursorIndex in:currentState.composingBuffer]; - InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex markerIndex:nextPosition phrases:currentState.phrases]; + InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex markerIndex:nextPosition readings:[self _currentReadings]]; stateCallback(marking); } else { errorCallback(); @@ -809,7 +809,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; NSUInteger index = state.markerIndex; if (index > 0) { index = [StringUtils previousUtf16PositionForIndex:index in:state.composingBuffer]; - InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:state.composingBuffer cursorIndex:state.cursorIndex markerIndex:index phrases:state.phrases]; + InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:state.composingBuffer cursorIndex:state.cursorIndex markerIndex:index readings:state.readings]; stateCallback(marking); } else { errorCallback(); @@ -824,7 +824,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; NSUInteger index = state.markerIndex; if (index < state.composingBuffer.length) { index = [StringUtils nextUtf16PositionForIndex:index in:state.composingBuffer]; - InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:state.composingBuffer cursorIndex:state.cursorIndex markerIndex:index phrases:state.phrases]; + InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:state.composingBuffer cursorIndex:state.cursorIndex markerIndex:index readings:state.readings]; stateCallback(marking); } else { errorCallback(); @@ -1104,7 +1104,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; NSString *composedText = [head stringByAppendingString:[reading stringByAppendingString:tail]]; NSInteger cursorIndex = composedStringCursorIndex + [reading length]; - InputStateInputting *newState = [[InputStateInputting alloc] initWithComposingBuffer:composedText cursorIndex:cursorIndex phrases:phrases]; + InputStateInputting *newState = [[InputStateInputting alloc] initWithComposingBuffer:composedText cursorIndex:cursorIndex]; return newState; } @@ -1174,7 +1174,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; } } - InputStateChoosingCandidate *state = [[InputStateChoosingCandidate alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex candidates:candidatesArray phrases:currentState.phrases useVerticalMode:useVerticalMode]; + InputStateChoosingCandidate *state = [[InputStateChoosingCandidate alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex candidates:candidatesArray useVerticalMode:useVerticalMode]; return state; } diff --git a/Source/en.lproj/Localizable.strings b/Source/en.lproj/Localizable.strings index 26ba4bb1..8b897e3b 100644 --- a/Source/en.lproj/Localizable.strings +++ b/Source/en.lproj/Localizable.strings @@ -34,6 +34,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 char selected for user phrases." = "⚠︎ Unhandlable char selected for user phrases."; "NT351 BPMF EMU" = "NT351 Per-Char Select Mode"; "CNS11643 Mode" = "CNS11643 Mode"; "Reboot vChewing…" = "Reboot vChewing…"; diff --git a/Source/ja.lproj/Localizable.strings b/Source/ja.lproj/Localizable.strings index 73d5cbee..0224e802 100644 --- a/Source/ja.lproj/Localizable.strings +++ b/Source/ja.lproj/Localizable.strings @@ -34,6 +34,7 @@ "Please specify at least 4 candidate keys." = "言選り用キー陣列に少なくとも4つのキーをご登録ください。"; "Maximum 15 candidate keys allowed." = "言選り用キー陣列には最多15つキー登録できます。"; "⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 言葉置換機能稼働中、新添付言葉にも影響。"; +"⚠︎ Unhandlable char selected for user phrases." = "⚠︎ ユーザー辞書の対処できない文字は選択されています。"; "NT351 BPMF EMU" = "全候補入力モード"; "CNS11643 Mode" = "全字庫モード"; "Reboot vChewing…" = "入力アプリ再起動…"; diff --git a/Source/zh-Hans.lproj/Localizable.strings b/Source/zh-Hans.lproj/Localizable.strings index 7a3e14c1..5d6fb069 100644 --- a/Source/zh-Hans.lproj/Localizable.strings +++ b/Source/zh-Hans.lproj/Localizable.strings @@ -34,6 +34,7 @@ "Please specify at least 4 candidate keys." = "请至少指定四个选字键。"; "Maximum 15 candidate keys allowed." = "选字键最多只能指定十五个。"; "⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 语汇置换功能已启用,会波及语汇自订。"; +"⚠︎ Unhandlable char selected for user phrases." = "⚠︎ 已选中无法处理的字元,无法加入自订语汇。"; "NT351 BPMF EMU" = "模拟逐字选字输入"; "CNS11643 Mode" = "全字库模式"; "Reboot vChewing…" = "重新启动输入法…"; diff --git a/Source/zh-Hant.lproj/Localizable.strings b/Source/zh-Hant.lproj/Localizable.strings index 1066c72f..b0bc929f 100644 --- a/Source/zh-Hant.lproj/Localizable.strings +++ b/Source/zh-Hant.lproj/Localizable.strings @@ -34,6 +34,7 @@ "Please specify at least 4 candidate keys." = "請至少指定四個選字鍵。"; "Maximum 15 candidate keys allowed." = "選字鍵最多只能指定十五個。"; "⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 語彙置換功能已啟用,會波及語彙自訂。"; +"⚠︎ Unhandlable char selected for user phrases." = "⚠︎ 已選中無法處理的字元,無法加入自訂語彙。"; "NT351 BPMF EMU" = "模擬逐字選字輸入"; "CNS11643 Mode" = "全字庫模式"; "Reboot vChewing…" = "重新啟動輸入法…";