diff --git a/Source/Modules/IMEState.swift b/Source/Modules/IMEState.swift index aee24f70..eec9530c 100644 --- a/Source/Modules/IMEState.swift +++ b/Source/Modules/IMEState.swift @@ -33,6 +33,7 @@ public protocol IMEStateProtocol { var hasComposition: Bool { get } var isCandidateContainer: Bool { get } var displayedText: String { get } + var displayedTextConverted: String { get } var textToCommit: String { get set } var tooltip: String { get set } var attributedString: NSAttributedString { get } @@ -40,10 +41,12 @@ public protocol IMEStateProtocol { var isFilterable: Bool { get } var isMarkedLengthValid: Bool { get } var node: CandidateNode { get set } - var cursor: Int { get } var displayTextSegments: [String] { get } var tooltipBackupForInputting: String { get set } var markedRange: Range { get } + var cursor: Int { get } + var u16MarkedRange: Range { get } + var u16Cursor: Int { get } } /// 用以呈現輸入法控制器(ctlInputMethod)的各種狀態。 @@ -174,9 +177,12 @@ extension IMEState { public var isMarkedLengthValid: Bool { data.isMarkedLengthValid } public var candidates: [(String, String)] { data.candidates } public var displayedText: String { data.displayedText } + public var displayedTextConverted: String { data.displayedTextConverted } public var cursor: Int { data.cursor } public var displayTextSegments: [String] { data.displayTextSegments } public var markedRange: Range { data.markedRange } + public var u16MarkedRange: Range { data.u16MarkedRange } + public var u16Cursor: Int { data.u16Cursor } public var convertedToInputting: IMEState { if type == .ofInputting { return self } var result = IMEState.ofInputting(displayTextSegments: data.displayTextSegments, cursor: data.cursor) diff --git a/Source/Modules/UIModules/PopupCompositionBufferUI/ctlPopupCompositionBuffer.swift b/Source/Modules/UIModules/PopupCompositionBufferUI/ctlPopupCompositionBuffer.swift index 6e2376cc..8b2a4526 100644 --- a/Source/Modules/UIModules/PopupCompositionBufferUI/ctlPopupCompositionBuffer.swift +++ b/Source/Modules/UIModules/PopupCompositionBufferUI/ctlPopupCompositionBuffer.swift @@ -58,7 +58,7 @@ public class ctlPopupCompositionBuffer: NSWindowController { return } - let attrString: NSMutableAttributedString = .init(string: state.data.displayedTextConverted) + let attrString: NSMutableAttributedString = .init(string: state.displayedTextConverted) let verticalAttributes: [NSAttributedString.Key: Any] = [ .verticalGlyphForm: true, .paragraphStyle: { @@ -95,8 +95,8 @@ public class ctlPopupCompositionBuffer: NSWindowController { attrString.setAttributes( markerAttributes, range: NSRange( - location: state.data.u16MarkedRange.lowerBound, - length: state.data.u16MarkedRange.upperBound - state.data.u16MarkedRange.lowerBound + location: state.u16MarkedRange.lowerBound, + length: state.u16MarkedRange.upperBound - state.u16MarkedRange.lowerBound ) ) @@ -123,12 +123,12 @@ public class ctlPopupCompositionBuffer: NSWindowController { isTypingDirectionVertical ? NSMutableAttributedString(string: "▔", attributes: cursorAttributes) : NSMutableAttributedString(string: "_", attributes: cursorAttributes) - attrString.insert(attrCursor, at: state.data.u16Cursor) + attrString.insert(attrCursor, at: state.u16Cursor) textShown = attrString messageTextField.maximumNumberOfLines = 1 if let editor = messageTextField.currentEditor() { - editor.selectedRange = NSRange(state.data.u16MarkedRange) + editor.selectedRange = NSRange(state.u16MarkedRange) } window?.orderFront(nil) set(windowOrigin: point) diff --git a/Source/Modules/ctlInputMethod_HandleDisplay.swift b/Source/Modules/ctlInputMethod_HandleDisplay.swift index 4be773bd..bd7246d9 100644 --- a/Source/Modules/ctlInputMethod_HandleDisplay.swift +++ b/Source/Modules/ctlInputMethod_HandleDisplay.swift @@ -20,7 +20,7 @@ extension ctlInputMethod { var attributedStringSecured: (NSAttributedString, NSRange) { PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier) ? (state.data.attributedStringPlaceholder, NSRange(location: 0, length: 0)) - : (state.attributedString, NSRange(state.data.u16MarkedRange)) + : (state.attributedString, NSRange(state.u16MarkedRange)) } func lineHeightRect(zeroCursor: Bool = false) -> NSRect { @@ -28,14 +28,10 @@ extension ctlInputMethod { guard let client = client() else { return lineHeightRect } - var u16Cursor: Int = { - // iMessage 在 cursor == 0 時的計算會有一些偏差,所以例外處理。 - if clientBundleIdentifier == "com.apple.MobileSMS" { return state.data.u16Cursor } - if state.data.marker >= state.data.cursor { return state.data.u16Cursor } - return state.data.u16Marker // 這樣可以讓工具提示視窗始終盡量往書寫方向的後方顯示。 - }() - u16Cursor = max(min(state.data.displayedTextConverted.utf16.count, u16Cursor), 0) + var u16Cursor: Int = state.u16MarkedRange.lowerBound + u16Cursor = max(min(state.displayedTextConverted.utf16.count, u16Cursor), 0) if zeroCursor { u16Cursor = 0 } + // iMessage 的話,據此算出來的 lineHeightRect 結果的橫向座標起始點不準確。目前無解。 while lineHeightRect.origin.x == 0, lineHeightRect.origin.y == 0, u16Cursor >= 0 { client.attributes( forCharacterIndex: u16Cursor, lineHeightRectangle: &lineHeightRect