IMEState // Make certain data components directly accessible.
This commit is contained in:
parent
abec924d16
commit
cab7eb28f7
|
@ -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<Int> { get }
|
||||
var cursor: Int { get }
|
||||
var u16MarkedRange: Range<Int> { 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<Int> { data.markedRange }
|
||||
public var u16MarkedRange: Range<Int> { 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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue