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 hasComposition: Bool { get }
|
||||||
var isCandidateContainer: Bool { get }
|
var isCandidateContainer: Bool { get }
|
||||||
var displayedText: String { get }
|
var displayedText: String { get }
|
||||||
|
var displayedTextConverted: String { get }
|
||||||
var textToCommit: String { get set }
|
var textToCommit: String { get set }
|
||||||
var tooltip: String { get set }
|
var tooltip: String { get set }
|
||||||
var attributedString: NSAttributedString { get }
|
var attributedString: NSAttributedString { get }
|
||||||
|
@ -40,10 +41,12 @@ public protocol IMEStateProtocol {
|
||||||
var isFilterable: Bool { get }
|
var isFilterable: Bool { get }
|
||||||
var isMarkedLengthValid: Bool { get }
|
var isMarkedLengthValid: Bool { get }
|
||||||
var node: CandidateNode { get set }
|
var node: CandidateNode { get set }
|
||||||
var cursor: Int { get }
|
|
||||||
var displayTextSegments: [String] { get }
|
var displayTextSegments: [String] { get }
|
||||||
var tooltipBackupForInputting: String { get set }
|
var tooltipBackupForInputting: String { get set }
|
||||||
var markedRange: Range<Int> { get }
|
var markedRange: Range<Int> { get }
|
||||||
|
var cursor: Int { get }
|
||||||
|
var u16MarkedRange: Range<Int> { get }
|
||||||
|
var u16Cursor: Int { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 用以呈現輸入法控制器(ctlInputMethod)的各種狀態。
|
/// 用以呈現輸入法控制器(ctlInputMethod)的各種狀態。
|
||||||
|
@ -174,9 +177,12 @@ extension IMEState {
|
||||||
public var isMarkedLengthValid: Bool { data.isMarkedLengthValid }
|
public var isMarkedLengthValid: Bool { data.isMarkedLengthValid }
|
||||||
public var candidates: [(String, String)] { data.candidates }
|
public var candidates: [(String, String)] { data.candidates }
|
||||||
public var displayedText: String { data.displayedText }
|
public var displayedText: String { data.displayedText }
|
||||||
|
public var displayedTextConverted: String { data.displayedTextConverted }
|
||||||
public var cursor: Int { data.cursor }
|
public var cursor: Int { data.cursor }
|
||||||
public var displayTextSegments: [String] { data.displayTextSegments }
|
public var displayTextSegments: [String] { data.displayTextSegments }
|
||||||
public var markedRange: Range<Int> { data.markedRange }
|
public var markedRange: Range<Int> { data.markedRange }
|
||||||
|
public var u16MarkedRange: Range<Int> { data.u16MarkedRange }
|
||||||
|
public var u16Cursor: Int { data.u16Cursor }
|
||||||
public var convertedToInputting: IMEState {
|
public var convertedToInputting: IMEState {
|
||||||
if type == .ofInputting { return self }
|
if type == .ofInputting { return self }
|
||||||
var result = IMEState.ofInputting(displayTextSegments: data.displayTextSegments, cursor: data.cursor)
|
var result = IMEState.ofInputting(displayTextSegments: data.displayTextSegments, cursor: data.cursor)
|
||||||
|
|
|
@ -58,7 +58,7 @@ public class ctlPopupCompositionBuffer: NSWindowController {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let attrString: NSMutableAttributedString = .init(string: state.data.displayedTextConverted)
|
let attrString: NSMutableAttributedString = .init(string: state.displayedTextConverted)
|
||||||
let verticalAttributes: [NSAttributedString.Key: Any] = [
|
let verticalAttributes: [NSAttributedString.Key: Any] = [
|
||||||
.verticalGlyphForm: true,
|
.verticalGlyphForm: true,
|
||||||
.paragraphStyle: {
|
.paragraphStyle: {
|
||||||
|
@ -95,8 +95,8 @@ public class ctlPopupCompositionBuffer: NSWindowController {
|
||||||
attrString.setAttributes(
|
attrString.setAttributes(
|
||||||
markerAttributes,
|
markerAttributes,
|
||||||
range: NSRange(
|
range: NSRange(
|
||||||
location: state.data.u16MarkedRange.lowerBound,
|
location: state.u16MarkedRange.lowerBound,
|
||||||
length: state.data.u16MarkedRange.upperBound - state.data.u16MarkedRange.lowerBound
|
length: state.u16MarkedRange.upperBound - state.u16MarkedRange.lowerBound
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -123,12 +123,12 @@ public class ctlPopupCompositionBuffer: NSWindowController {
|
||||||
isTypingDirectionVertical
|
isTypingDirectionVertical
|
||||||
? NSMutableAttributedString(string: "▔", attributes: cursorAttributes)
|
? NSMutableAttributedString(string: "▔", attributes: cursorAttributes)
|
||||||
: NSMutableAttributedString(string: "_", attributes: cursorAttributes)
|
: NSMutableAttributedString(string: "_", attributes: cursorAttributes)
|
||||||
attrString.insert(attrCursor, at: state.data.u16Cursor)
|
attrString.insert(attrCursor, at: state.u16Cursor)
|
||||||
|
|
||||||
textShown = attrString
|
textShown = attrString
|
||||||
messageTextField.maximumNumberOfLines = 1
|
messageTextField.maximumNumberOfLines = 1
|
||||||
if let editor = messageTextField.currentEditor() {
|
if let editor = messageTextField.currentEditor() {
|
||||||
editor.selectedRange = NSRange(state.data.u16MarkedRange)
|
editor.selectedRange = NSRange(state.u16MarkedRange)
|
||||||
}
|
}
|
||||||
window?.orderFront(nil)
|
window?.orderFront(nil)
|
||||||
set(windowOrigin: point)
|
set(windowOrigin: point)
|
||||||
|
|
|
@ -20,7 +20,7 @@ extension ctlInputMethod {
|
||||||
var attributedStringSecured: (NSAttributedString, NSRange) {
|
var attributedStringSecured: (NSAttributedString, NSRange) {
|
||||||
PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier)
|
PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier)
|
||||||
? (state.data.attributedStringPlaceholder, NSRange(location: 0, length: 0))
|
? (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 {
|
func lineHeightRect(zeroCursor: Bool = false) -> NSRect {
|
||||||
|
@ -28,14 +28,10 @@ extension ctlInputMethod {
|
||||||
guard let client = client() else {
|
guard let client = client() else {
|
||||||
return lineHeightRect
|
return lineHeightRect
|
||||||
}
|
}
|
||||||
var u16Cursor: Int = {
|
var u16Cursor: Int = state.u16MarkedRange.lowerBound
|
||||||
// iMessage 在 cursor == 0 時的計算會有一些偏差,所以例外處理。
|
u16Cursor = max(min(state.displayedTextConverted.utf16.count, u16Cursor), 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)
|
|
||||||
if zeroCursor { u16Cursor = 0 }
|
if zeroCursor { u16Cursor = 0 }
|
||||||
|
// iMessage 的話,據此算出來的 lineHeightRect 結果的橫向座標起始點不準確。目前無解。
|
||||||
while lineHeightRect.origin.x == 0, lineHeightRect.origin.y == 0, u16Cursor >= 0 {
|
while lineHeightRect.origin.x == 0, lineHeightRect.origin.y == 0, u16Cursor >= 0 {
|
||||||
client.attributes(
|
client.attributes(
|
||||||
forCharacterIndex: u16Cursor, lineHeightRectangle: &lineHeightRect
|
forCharacterIndex: u16Cursor, lineHeightRectangle: &lineHeightRect
|
||||||
|
|
Loading…
Reference in New Issue