ctlIME // +isVerticalTyping() & guard-let the client().
This commit is contained in:
parent
318f27ad19
commit
eab6402e31
|
@ -39,6 +39,15 @@ class ctlInputMethod: IMKInputController {
|
||||||
var state: InputStateProtocol = InputState.Empty()
|
var state: InputStateProtocol = InputState.Empty()
|
||||||
/// 當前這個 ctlInputMethod 副本是否處於英數輸入模式。
|
/// 當前這個 ctlInputMethod 副本是否處於英數輸入模式。
|
||||||
var isASCIIMode: Bool = false
|
var isASCIIMode: Bool = false
|
||||||
|
/// 記錄當前輸入環境是縱排輸入還是橫排輸入。
|
||||||
|
public var isVerticalTyping: Bool {
|
||||||
|
guard let client = client() else { return false }
|
||||||
|
var textFrame = NSRect.zero
|
||||||
|
let attributes: [AnyHashable: Any]? = client.attributes(
|
||||||
|
forCharacterIndex: 0, lineHeightRectangle: &textFrame
|
||||||
|
)
|
||||||
|
return (attributes?["IMKTextOrientation"] as? NSNumber)?.intValue == 0 || false
|
||||||
|
}
|
||||||
|
|
||||||
/// 切換當前 ctlInputMethod 副本的英數輸入模式開關。
|
/// 切換當前 ctlInputMethod 副本的英數輸入模式開關。
|
||||||
func toggleASCIIMode() -> Bool {
|
func toggleASCIIMode() -> Bool {
|
||||||
|
@ -54,7 +63,9 @@ class ctlInputMethod: IMKInputController {
|
||||||
|
|
||||||
/// 指定鍵盤佈局。
|
/// 指定鍵盤佈局。
|
||||||
func setKeyLayout() {
|
func setKeyLayout() {
|
||||||
client().overrideKeyboard(withKeyboardNamed: mgrPrefs.basicKeyboardLayout)
|
if let client = client() {
|
||||||
|
client.overrideKeyboard(withKeyboardNamed: mgrPrefs.basicKeyboardLayout)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 重設按鍵調度模組,會將當前尚未遞交的內容遞交出去。
|
/// 重設按鍵調度模組,會將當前尚未遞交的內容遞交出去。
|
||||||
|
@ -95,7 +106,8 @@ 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: 114_514, client: client())
|
guard let client = client() else { return }
|
||||||
|
setValue(IME.currentInputMode.rawValue, forTag: 114_514, client: client)
|
||||||
keyHandler.clear() // 這句不要砍,因為後面 handle State.Empty() 不一定執行。
|
keyHandler.clear() // 這句不要砍,因為後面 handle State.Empty() 不一定執行。
|
||||||
keyHandler.ensureParser()
|
keyHandler.ensureParser()
|
||||||
|
|
||||||
|
@ -111,7 +123,7 @@ class ctlInputMethod: IMKInputController {
|
||||||
|
|
||||||
/// 必須加上下述條件,否則會在每次切換至輸入法本體的視窗(比如偏好設定視窗)時會卡死。
|
/// 必須加上下述條件,否則會在每次切換至輸入法本體的視窗(比如偏好設定視窗)時會卡死。
|
||||||
/// 這是很多 macOS 副廠輸入法的常見失誤之處。
|
/// 這是很多 macOS 副廠輸入法的常見失誤之處。
|
||||||
if client().bundleIdentifier() != Bundle.main.bundleIdentifier {
|
if client.bundleIdentifier() != Bundle.main.bundleIdentifier {
|
||||||
// 強制重設當前鍵盤佈局、使其與偏好設定同步。
|
// 強制重設當前鍵盤佈局、使其與偏好設定同步。
|
||||||
setKeyLayout()
|
setKeyLayout()
|
||||||
handle(state: InputState.Empty())
|
handle(state: InputState.Empty())
|
||||||
|
@ -152,7 +164,7 @@ class ctlInputMethod: IMKInputController {
|
||||||
keyHandler.inputMode = newInputMode
|
keyHandler.inputMode = newInputMode
|
||||||
/// 必須加上下述條件,否則會在每次切換至輸入法本體的視窗(比如偏好設定視窗)時會卡死。
|
/// 必須加上下述條件,否則會在每次切換至輸入法本體的視窗(比如偏好設定視窗)時會卡死。
|
||||||
/// 這是很多 macOS 副廠輸入法的常見失誤之處。
|
/// 這是很多 macOS 副廠輸入法的常見失誤之處。
|
||||||
if client().bundleIdentifier() != Bundle.main.bundleIdentifier {
|
if let client = client(), client.bundleIdentifier() != Bundle.main.bundleIdentifier {
|
||||||
// 強制重設當前鍵盤佈局、使其與偏好設定同步。這裡的這一步也不能省略。
|
// 強制重設當前鍵盤佈局、使其與偏好設定同步。這裡的這一步也不能省略。
|
||||||
setKeyLayout()
|
setKeyLayout()
|
||||||
handle(state: InputState.Empty())
|
handle(state: InputState.Empty())
|
||||||
|
@ -221,16 +233,8 @@ class ctlInputMethod: IMKInputController {
|
||||||
// 準備修飾鍵,用來判定要新增的詞彙是否需要賦以非常低的權重。
|
// 準備修飾鍵,用來判定要新增的詞彙是否需要賦以非常低的權重。
|
||||||
ctlInputMethod.areWeNerfing = event.modifierFlags.contains([.shift, .command])
|
ctlInputMethod.areWeNerfing = event.modifierFlags.contains([.shift, .command])
|
||||||
|
|
||||||
var textFrame = NSRect.zero
|
if let client = client(),
|
||||||
|
client.bundleIdentifier()
|
||||||
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"
|
== "org.atelierInmu.vChewing.vChewingPhraseEditor"
|
||||||
{
|
{
|
||||||
IME.areWeUsingOurOwnPhraseEditor = true
|
IME.areWeUsingOurOwnPhraseEditor = true
|
||||||
|
@ -238,7 +242,7 @@ class ctlInputMethod: IMKInputController {
|
||||||
IME.areWeUsingOurOwnPhraseEditor = false
|
IME.areWeUsingOurOwnPhraseEditor = false
|
||||||
}
|
}
|
||||||
|
|
||||||
var input = InputSignal(event: event, isVerticalTyping: isTypingVertical)
|
var input = InputSignal(event: event, isVerticalTyping: isVerticalTyping)
|
||||||
input.isASCIIModeInput = isASCIIMode
|
input.isASCIIModeInput = isASCIIMode
|
||||||
|
|
||||||
// 無法列印的訊號輸入,一概不作處理。
|
// 無法列印的訊號輸入,一概不作處理。
|
||||||
|
|
|
@ -78,16 +78,8 @@ extension ctlInputMethod: ctlCandidateDelegate {
|
||||||
// 準備修飾鍵,用來判定要新增的詞彙是否需要賦以非常低的權重。
|
// 準備修飾鍵,用來判定要新增的詞彙是否需要賦以非常低的權重。
|
||||||
ctlInputMethod.areWeNerfing = event.modifierFlags.contains([.shift, .command])
|
ctlInputMethod.areWeNerfing = event.modifierFlags.contains([.shift, .command])
|
||||||
|
|
||||||
var textFrame = NSRect.zero
|
if let client = client(),
|
||||||
|
client.bundleIdentifier()
|
||||||
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"
|
== "org.atelierInmu.vChewing.vChewingPhraseEditor"
|
||||||
{
|
{
|
||||||
IME.areWeUsingOurOwnPhraseEditor = true
|
IME.areWeUsingOurOwnPhraseEditor = true
|
||||||
|
@ -95,7 +87,7 @@ extension ctlInputMethod: ctlCandidateDelegate {
|
||||||
IME.areWeUsingOurOwnPhraseEditor = false
|
IME.areWeUsingOurOwnPhraseEditor = false
|
||||||
}
|
}
|
||||||
|
|
||||||
var input = InputSignal(event: event, isVerticalTyping: isTypingVertical)
|
var input = InputSignal(event: event, isVerticalTyping: isVerticalTyping)
|
||||||
input.isASCIIModeInput = isASCIIMode
|
input.isASCIIModeInput = isASCIIMode
|
||||||
|
|
||||||
// 無法列印的訊號輸入,一概不作處理。
|
// 無法列印的訊號輸入,一概不作處理。
|
||||||
|
|
|
@ -15,13 +15,14 @@ import Foundation
|
||||||
|
|
||||||
extension ctlInputMethod {
|
extension ctlInputMethod {
|
||||||
func show(tooltip: String, composingBuffer: String, cursorIndex: Int) {
|
func show(tooltip: String, composingBuffer: String, cursorIndex: Int) {
|
||||||
|
guard let client = client() else { return }
|
||||||
var lineHeightRect = NSRect(x: 0.0, y: 0.0, width: 16.0, height: 16.0)
|
var lineHeightRect = NSRect(x: 0.0, y: 0.0, width: 16.0, height: 16.0)
|
||||||
var cursor = cursorIndex
|
var cursor = cursorIndex
|
||||||
if cursor == composingBuffer.count, cursor != 0 {
|
if cursor == composingBuffer.count, cursor != 0 {
|
||||||
cursor -= 1
|
cursor -= 1
|
||||||
}
|
}
|
||||||
while lineHeightRect.origin.x == 0, lineHeightRect.origin.y == 0, cursor >= 0 {
|
while lineHeightRect.origin.x == 0, lineHeightRect.origin.y == 0, cursor >= 0 {
|
||||||
client().attributes(
|
client.attributes(
|
||||||
forCharacterIndex: cursor, lineHeightRectangle: &lineHeightRect
|
forCharacterIndex: cursor, lineHeightRectangle: &lineHeightRect
|
||||||
)
|
)
|
||||||
cursor -= 1
|
cursor -= 1
|
||||||
|
@ -30,6 +31,7 @@ extension ctlInputMethod {
|
||||||
}
|
}
|
||||||
|
|
||||||
func show(candidateWindowWith state: InputStateProtocol) {
|
func show(candidateWindowWith state: InputStateProtocol) {
|
||||||
|
guard let client = client() else { return }
|
||||||
var isTypingVertical: Bool {
|
var isTypingVertical: Bool {
|
||||||
if let state = state as? InputState.ChoosingCandidate {
|
if let state = state as? InputState.ChoosingCandidate {
|
||||||
return state.isTypingVertical
|
return state.isTypingVertical
|
||||||
|
@ -153,7 +155,7 @@ extension ctlInputMethod {
|
||||||
}
|
}
|
||||||
|
|
||||||
while lineHeightRect.origin.x == 0, lineHeightRect.origin.y == 0, cursor >= 0 {
|
while lineHeightRect.origin.x == 0, lineHeightRect.origin.y == 0, cursor >= 0 {
|
||||||
client().attributes(
|
client.attributes(
|
||||||
forCharacterIndex: cursor, lineHeightRectangle: &lineHeightRect
|
forCharacterIndex: cursor, lineHeightRectangle: &lineHeightRect
|
||||||
)
|
)
|
||||||
cursor -= 1
|
cursor -= 1
|
||||||
|
|
|
@ -47,8 +47,9 @@ extension ctlInputMethod {
|
||||||
|
|
||||||
/// 針對受 .NotEmpty() 管轄的非空狀態,在組字區內顯示游標。
|
/// 針對受 .NotEmpty() 管轄的非空狀態,在組字區內顯示游標。
|
||||||
private func setInlineDisplayWithCursor() {
|
private func setInlineDisplayWithCursor() {
|
||||||
|
guard let client = client() else { return }
|
||||||
if let state = state as? InputState.AssociatedPhrases {
|
if let state = state as? InputState.AssociatedPhrases {
|
||||||
client().setMarkedText(
|
client.setMarkedText(
|
||||||
state.attributedString, selectionRange: NSRange(location: 0, length: 0),
|
state.attributedString, selectionRange: NSRange(location: 0, length: 0),
|
||||||
replacementRange: NSRange(location: NSNotFound, length: NSNotFound)
|
replacementRange: NSRange(location: NSNotFound, length: NSNotFound)
|
||||||
)
|
)
|
||||||
|
@ -94,7 +95,7 @@ extension ctlInputMethod {
|
||||||
/// 所謂選區「selectionRange」,就是「可見游標位置」的位置,只不過長度
|
/// 所謂選區「selectionRange」,就是「可見游標位置」的位置,只不過長度
|
||||||
/// 是 0 且取代範圍(replacementRange)為「NSNotFound」罷了。
|
/// 是 0 且取代範圍(replacementRange)為「NSNotFound」罷了。
|
||||||
/// 也就是說,內文組字區該在哪裡出現,得由客體軟體來作主。
|
/// 也就是說,內文組字區該在哪裡出現,得由客體軟體來作主。
|
||||||
client().setMarkedText(
|
client.setMarkedText(
|
||||||
state.attributedString, selectionRange: NSRange(location: state.cursorIndex, length: 0),
|
state.attributedString, selectionRange: NSRange(location: state.cursorIndex, length: 0),
|
||||||
replacementRange: NSRange(location: NSNotFound, length: NSNotFound)
|
replacementRange: NSRange(location: NSNotFound, length: NSNotFound)
|
||||||
)
|
)
|
||||||
|
@ -113,12 +114,12 @@ extension ctlInputMethod {
|
||||||
/// 遞交組字區內容。
|
/// 遞交組字區內容。
|
||||||
/// 注意:必須在 IMK 的 commitComposition 函式當中也間接或者直接執行這個處理。
|
/// 注意:必須在 IMK 的 commitComposition 函式當中也間接或者直接執行這個處理。
|
||||||
private func commit(text: String) {
|
private func commit(text: String) {
|
||||||
|
guard let client = client() else { return }
|
||||||
let buffer = IME.kanjiConversionIfRequired(text)
|
let buffer = IME.kanjiConversionIfRequired(text)
|
||||||
if buffer.isEmpty {
|
if buffer.isEmpty {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
client.insertText(
|
||||||
client().insertText(
|
|
||||||
buffer, replacementRange: NSRange(location: NSNotFound, length: NSNotFound)
|
buffer, replacementRange: NSRange(location: NSNotFound, length: NSNotFound)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue