Repo // InputState -> InputStateProtocol, plus clang-format.
This commit is contained in:
parent
dedc8770cf
commit
63659ee662
|
@ -28,6 +28,25 @@ import Cocoa
|
||||||
|
|
||||||
// 註:所有 InputState 型別均不適合使用 Struct,因為 Struct 無法相互繼承派生。
|
// 註:所有 InputState 型別均不適合使用 Struct,因為 Struct 無法相互繼承派生。
|
||||||
|
|
||||||
|
// 用以讓每個狀態自描述的 enum。
|
||||||
|
enum StateType {
|
||||||
|
case ofDeactivated
|
||||||
|
case ofAssociatedPhrases
|
||||||
|
case ofEmpty
|
||||||
|
case ofEmptyIgnorePreviousState
|
||||||
|
case ofCommitting
|
||||||
|
case ofNotEmpty
|
||||||
|
case ofInputting
|
||||||
|
case ofMarking
|
||||||
|
case ofChooseCandidate
|
||||||
|
case ofSymbolTable
|
||||||
|
}
|
||||||
|
|
||||||
|
// 所有 InputState 均遵守该协定:
|
||||||
|
protocol InputStateProtocol {
|
||||||
|
var type: StateType { get }
|
||||||
|
}
|
||||||
|
|
||||||
/// 此型別用以呈現輸入法控制器(ctlInputMethod)的各種狀態。
|
/// 此型別用以呈現輸入法控制器(ctlInputMethod)的各種狀態。
|
||||||
///
|
///
|
||||||
/// 從實際角度來看,輸入法屬於有限態械(Finite State Machine)。其藉由滑鼠/鍵盤
|
/// 從實際角度來看,輸入法屬於有限態械(Finite State Machine)。其藉由滑鼠/鍵盤
|
||||||
|
@ -60,9 +79,10 @@ import Cocoa
|
||||||
/// 詞音組合放入語彙濾除清單。
|
/// 詞音組合放入語彙濾除清單。
|
||||||
/// - .ChoosingCandidate: 叫出選字窗、允許使用者選字。
|
/// - .ChoosingCandidate: 叫出選字窗、允許使用者選字。
|
||||||
/// - .SymbolTable: 波浪鍵符號選單專用的狀態,有自身的特殊處理。
|
/// - .SymbolTable: 波浪鍵符號選單專用的狀態,有自身的特殊處理。
|
||||||
class InputState {
|
enum InputState {
|
||||||
/// .Deactivated: 使用者沒在使用輸入法。
|
/// .Deactivated: 使用者沒在使用輸入法。
|
||||||
class Deactivated: InputState {
|
class Deactivated: InputStateProtocol {
|
||||||
|
public var type: StateType { .ofDeactivated }
|
||||||
var description: String {
|
var description: String {
|
||||||
"<InputState.Deactivated>"
|
"<InputState.Deactivated>"
|
||||||
}
|
}
|
||||||
|
@ -72,7 +92,9 @@ class InputState {
|
||||||
|
|
||||||
/// .Empty: 使用者剛剛切換至該輸入法、卻還沒有任何輸入行為。
|
/// .Empty: 使用者剛剛切換至該輸入法、卻還沒有任何輸入行為。
|
||||||
/// 抑或是剛剛敲字遞交給客體應用、準備新的輸入行為。
|
/// 抑或是剛剛敲字遞交給客體應用、準備新的輸入行為。
|
||||||
class Empty: InputState {
|
class Empty: InputStateProtocol {
|
||||||
|
public var type: StateType { .ofEmpty }
|
||||||
|
|
||||||
var composingBuffer: String {
|
var composingBuffer: String {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
|
@ -87,6 +109,7 @@ class InputState {
|
||||||
/// .EmptyIgnorePreviousState: 與 Empty 類似,
|
/// .EmptyIgnorePreviousState: 與 Empty 類似,
|
||||||
/// 但會扔掉上一個狀態的內容、不將這些內容遞交給客體應用。
|
/// 但會扔掉上一個狀態的內容、不將這些內容遞交給客體應用。
|
||||||
class EmptyIgnoringPreviousState: Empty {
|
class EmptyIgnoringPreviousState: Empty {
|
||||||
|
override public var type: StateType { .ofEmptyIgnorePreviousState }
|
||||||
override var description: String {
|
override var description: String {
|
||||||
"<InputState.EmptyIgnoringPreviousState>"
|
"<InputState.EmptyIgnoringPreviousState>"
|
||||||
}
|
}
|
||||||
|
@ -95,7 +118,8 @@ class InputState {
|
||||||
// MARK: -
|
// MARK: -
|
||||||
|
|
||||||
/// .Committing: 該狀態會承載要遞交出去的內容,讓輸入法控制器處理時代為遞交。
|
/// .Committing: 該狀態會承載要遞交出去的內容,讓輸入法控制器處理時代為遞交。
|
||||||
class Committing: InputState {
|
class Committing: InputStateProtocol {
|
||||||
|
public var type: StateType { .ofCommitting }
|
||||||
private(set) var textToCommit: String = ""
|
private(set) var textToCommit: String = ""
|
||||||
|
|
||||||
convenience init(textToCommit: String) {
|
convenience init(textToCommit: String) {
|
||||||
|
@ -112,13 +136,13 @@ class InputState {
|
||||||
|
|
||||||
/// .AssociatedPhrases: 逐字選字模式內的聯想詞輸入狀態。
|
/// .AssociatedPhrases: 逐字選字模式內的聯想詞輸入狀態。
|
||||||
/// 因為逐字選字模式不需要在組字區內存入任何東西,所以該狀態不受 .NotEmpty 的管轄。
|
/// 因為逐字選字模式不需要在組字區內存入任何東西,所以該狀態不受 .NotEmpty 的管轄。
|
||||||
class AssociatedPhrases: InputState {
|
class AssociatedPhrases: InputStateProtocol {
|
||||||
|
public var type: StateType { .ofAssociatedPhrases }
|
||||||
private(set) var candidates: [String] = []
|
private(set) var candidates: [String] = []
|
||||||
private(set) var isTypingVertical: Bool = false
|
private(set) var isTypingVertical: Bool = false
|
||||||
init(candidates: [String], isTypingVertical: Bool) {
|
init(candidates: [String], isTypingVertical: Bool) {
|
||||||
self.candidates = candidates
|
self.candidates = candidates
|
||||||
self.isTypingVertical = isTypingVertical
|
self.isTypingVertical = isTypingVertical
|
||||||
super.init()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var description: String {
|
var description: String {
|
||||||
|
@ -134,7 +158,8 @@ class InputState {
|
||||||
/// 還是將這個範圍的詞音組合放入語彙濾除清單。
|
/// 還是將這個範圍的詞音組合放入語彙濾除清單。
|
||||||
/// - .ChoosingCandidate: 叫出選字窗、允許使用者選字。
|
/// - .ChoosingCandidate: 叫出選字窗、允許使用者選字。
|
||||||
/// - .SymbolTable: 波浪鍵符號選單專用的狀態,有自身的特殊處理。
|
/// - .SymbolTable: 波浪鍵符號選單專用的狀態,有自身的特殊處理。
|
||||||
class NotEmpty: InputState {
|
class NotEmpty: InputStateProtocol {
|
||||||
|
public var type: StateType { .ofNotEmpty }
|
||||||
private(set) var composingBuffer: String
|
private(set) var composingBuffer: String
|
||||||
private(set) var cursorIndex: Int = 0 { didSet { cursorIndex = max(cursorIndex, 0) } }
|
private(set) var cursorIndex: Int = 0 { didSet { cursorIndex = max(cursorIndex, 0) } }
|
||||||
public var composingBufferConverted: String {
|
public var composingBufferConverted: String {
|
||||||
|
@ -149,7 +174,6 @@ class InputState {
|
||||||
|
|
||||||
init(composingBuffer: String, cursorIndex: Int) {
|
init(composingBuffer: String, cursorIndex: Int) {
|
||||||
self.composingBuffer = composingBuffer
|
self.composingBuffer = composingBuffer
|
||||||
super.init()
|
|
||||||
defer { self.cursorIndex = cursorIndex }
|
defer { self.cursorIndex = cursorIndex }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,6 +199,7 @@ class InputState {
|
||||||
|
|
||||||
/// .Inputting: 使用者輸入了內容。此時會出現組字區(Compositor)。
|
/// .Inputting: 使用者輸入了內容。此時會出現組字區(Compositor)。
|
||||||
class Inputting: NotEmpty {
|
class Inputting: NotEmpty {
|
||||||
|
override public var type: StateType { .ofInputting }
|
||||||
var textToCommit: String = ""
|
var textToCommit: String = ""
|
||||||
var tooltip: String = ""
|
var tooltip: String = ""
|
||||||
|
|
||||||
|
@ -192,6 +217,7 @@ class InputState {
|
||||||
/// .Marking: 使用者在組字區內標記某段範圍,可以決定是添入新詞、
|
/// .Marking: 使用者在組字區內標記某段範圍,可以決定是添入新詞、
|
||||||
/// 還是將這個範圍的詞音組合放入語彙濾除清單。
|
/// 還是將這個範圍的詞音組合放入語彙濾除清單。
|
||||||
class Marking: NotEmpty {
|
class Marking: NotEmpty {
|
||||||
|
override public var type: StateType { .ofMarking }
|
||||||
private var allowedMarkRange: ClosedRange<Int> = mgrPrefs.minCandidateLength...mgrPrefs.maxCandidateLength
|
private var allowedMarkRange: ClosedRange<Int> = mgrPrefs.minCandidateLength...mgrPrefs.maxCandidateLength
|
||||||
private(set) var markerIndex: Int = 0 { didSet { markerIndex = max(markerIndex, 0) } }
|
private(set) var markerIndex: Int = 0 { didSet { markerIndex = max(markerIndex, 0) } }
|
||||||
private(set) var markedRange: Range<Int>
|
private(set) var markedRange: Range<Int>
|
||||||
|
@ -358,6 +384,7 @@ class InputState {
|
||||||
|
|
||||||
/// .ChoosingCandidate: 叫出選字窗、允許使用者選字。
|
/// .ChoosingCandidate: 叫出選字窗、允許使用者選字。
|
||||||
class ChoosingCandidate: NotEmpty {
|
class ChoosingCandidate: NotEmpty {
|
||||||
|
override public var type: StateType { .ofChooseCandidate }
|
||||||
private(set) var candidates: [String]
|
private(set) var candidates: [String]
|
||||||
private(set) var isTypingVertical: Bool
|
private(set) var isTypingVertical: Bool
|
||||||
|
|
||||||
|
@ -376,6 +403,7 @@ class InputState {
|
||||||
|
|
||||||
/// .SymbolTable: 波浪鍵符號選單專用的狀態,有自身的特殊處理。
|
/// .SymbolTable: 波浪鍵符號選單專用的狀態,有自身的特殊處理。
|
||||||
class SymbolTable: ChoosingCandidate {
|
class SymbolTable: ChoosingCandidate {
|
||||||
|
override public var type: StateType { .ofSymbolTable }
|
||||||
var node: SymbolNode
|
var node: SymbolNode
|
||||||
|
|
||||||
init(node: SymbolNode, isTypingVertical: Bool) {
|
init(node: SymbolNode, isTypingVertical: Bool) {
|
||||||
|
|
|
@ -39,7 +39,7 @@ protocol KeyHandlerDelegate {
|
||||||
_: KeyHandler, didSelectCandidateAt index: Int,
|
_: KeyHandler, didSelectCandidateAt index: Int,
|
||||||
ctlCandidate controller: ctlCandidate
|
ctlCandidate controller: ctlCandidate
|
||||||
)
|
)
|
||||||
func keyHandler(_ keyHandler: KeyHandler, didRequestWriteUserPhraseWith state: InputState)
|
func keyHandler(_ keyHandler: KeyHandler, didRequestWriteUserPhraseWith state: InputStateProtocol)
|
||||||
-> Bool
|
-> Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,7 +264,7 @@ class KeyHandler {
|
||||||
}
|
}
|
||||||
if mgrPrefs.fetchSuggestionsFromUserOverrideModel, !mgrPrefs.useSCPCTypingMode {
|
if mgrPrefs.fetchSuggestionsFromUserOverrideModel, !mgrPrefs.useSCPCTypingMode {
|
||||||
let arrSuggestedUnigrams: [Megrez.Unigram] = fetchSuggestedCandidates().stableSort { $0.score > $1.score }
|
let arrSuggestedUnigrams: [Megrez.Unigram] = fetchSuggestedCandidates().stableSort { $0.score > $1.score }
|
||||||
let arrSuggestedCandidates: [String] = arrSuggestedUnigrams.map { $0.keyValue.value }
|
let arrSuggestedCandidates: [String] = arrSuggestedUnigrams.map(\.keyValue.value)
|
||||||
arrCandidates = arrSuggestedCandidates.filter { arrCandidates.contains($0) } + arrCandidates
|
arrCandidates = arrSuggestedCandidates.filter { arrCandidates.contains($0) } + arrCandidates
|
||||||
arrCandidates = arrCandidates.deduplicate
|
arrCandidates = arrCandidates.deduplicate
|
||||||
arrCandidates = arrCandidates.stableSort { $0.count > $1.count }
|
arrCandidates = arrCandidates.stableSort { $0.count > $1.count }
|
||||||
|
@ -276,7 +276,8 @@ class KeyHandler {
|
||||||
func fetchSuggestedCandidates() -> [Megrez.Unigram] {
|
func fetchSuggestedCandidates() -> [Megrez.Unigram] {
|
||||||
currentUOM.suggest(
|
currentUOM.suggest(
|
||||||
walkedAnchors: walkedAnchors, cursorIndex: compositorCursorIndex,
|
walkedAnchors: walkedAnchors, cursorIndex: compositorCursorIndex,
|
||||||
timestamp: NSDate().timeIntervalSince1970)
|
timestamp: NSDate().timeIntervalSince1970
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 向半衰引擎詢問可能的選字建議、且套用給組字器內的當前游標位置。
|
/// 向半衰引擎詢問可能的選字建議、且套用給組字器內的當前游標位置。
|
||||||
|
|
|
@ -32,9 +32,9 @@ import Cocoa
|
||||||
|
|
||||||
extension KeyHandler {
|
extension KeyHandler {
|
||||||
func handleCandidate(
|
func handleCandidate(
|
||||||
state: InputState,
|
state: InputStateProtocol,
|
||||||
input: InputSignal,
|
input: InputSignal,
|
||||||
stateCallback: @escaping (InputState) -> Void,
|
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||||
errorCallback: @escaping () -> Void
|
errorCallback: @escaping () -> Void
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
let inputText = input.inputText
|
let inputText = input.inputText
|
||||||
|
|
|
@ -34,8 +34,8 @@ import Cocoa
|
||||||
extension KeyHandler {
|
extension KeyHandler {
|
||||||
func handle(
|
func handle(
|
||||||
input: InputSignal,
|
input: InputSignal,
|
||||||
state: InputState,
|
state: InputStateProtocol,
|
||||||
stateCallback: @escaping (InputState) -> Void,
|
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||||
errorCallback: @escaping () -> Void
|
errorCallback: @escaping () -> Void
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
let charCode: UniChar = input.charCode
|
let charCode: UniChar = input.charCode
|
||||||
|
|
|
@ -211,7 +211,7 @@ extension KeyHandler {
|
||||||
func handleMarkingState(
|
func handleMarkingState(
|
||||||
_ state: InputState.Marking,
|
_ state: InputState.Marking,
|
||||||
input: InputSignal,
|
input: InputSignal,
|
||||||
stateCallback: @escaping (InputState) -> Void,
|
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||||
errorCallback: @escaping () -> Void
|
errorCallback: @escaping () -> Void
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
if input.isESC {
|
if input.isESC {
|
||||||
|
@ -288,9 +288,9 @@ extension KeyHandler {
|
||||||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||||
func handlePunctuation(
|
func handlePunctuation(
|
||||||
_ customPunctuation: String,
|
_ customPunctuation: String,
|
||||||
state: InputState,
|
state: InputStateProtocol,
|
||||||
usingVerticalTyping isTypingVertical: Bool,
|
usingVerticalTyping isTypingVertical: Bool,
|
||||||
stateCallback: @escaping (InputState) -> Void,
|
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||||
errorCallback: @escaping () -> Void
|
errorCallback: @escaping () -> Void
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
if !ifLangModelHasUnigrams(forKey: customPunctuation) {
|
if !ifLangModelHasUnigrams(forKey: customPunctuation) {
|
||||||
|
@ -339,8 +339,8 @@ extension KeyHandler {
|
||||||
/// - stateCallback: 狀態回呼。
|
/// - stateCallback: 狀態回呼。
|
||||||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||||
func handleEnter(
|
func handleEnter(
|
||||||
state: InputState,
|
state: InputStateProtocol,
|
||||||
stateCallback: @escaping (InputState) -> Void,
|
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||||
errorCallback _: @escaping () -> Void
|
errorCallback _: @escaping () -> Void
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
guard let currentState = state as? InputState.Inputting else { return false }
|
guard let currentState = state as? InputState.Inputting else { return false }
|
||||||
|
@ -359,8 +359,8 @@ extension KeyHandler {
|
||||||
/// - stateCallback: 狀態回呼。
|
/// - stateCallback: 狀態回呼。
|
||||||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||||
func handleCtrlCommandEnter(
|
func handleCtrlCommandEnter(
|
||||||
state: InputState,
|
state: InputStateProtocol,
|
||||||
stateCallback: @escaping (InputState) -> Void,
|
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||||
errorCallback _: @escaping () -> Void
|
errorCallback _: @escaping () -> Void
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
guard state is InputState.Inputting else { return false }
|
guard state is InputState.Inputting else { return false }
|
||||||
|
@ -390,8 +390,8 @@ extension KeyHandler {
|
||||||
/// - stateCallback: 狀態回呼。
|
/// - stateCallback: 狀態回呼。
|
||||||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||||
func handleCtrlOptionCommandEnter(
|
func handleCtrlOptionCommandEnter(
|
||||||
state: InputState,
|
state: InputStateProtocol,
|
||||||
stateCallback: @escaping (InputState) -> Void,
|
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||||
errorCallback _: @escaping () -> Void
|
errorCallback _: @escaping () -> Void
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
guard state is InputState.Inputting else { return false }
|
guard state is InputState.Inputting else { return false }
|
||||||
|
@ -435,8 +435,8 @@ extension KeyHandler {
|
||||||
/// - errorCallback: 錯誤回呼。
|
/// - errorCallback: 錯誤回呼。
|
||||||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||||
func handleBackspace(
|
func handleBackspace(
|
||||||
state: InputState,
|
state: InputStateProtocol,
|
||||||
stateCallback: @escaping (InputState) -> Void,
|
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||||
errorCallback: @escaping () -> Void
|
errorCallback: @escaping () -> Void
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
guard state is InputState.Inputting else { return false }
|
guard state is InputState.Inputting else { return false }
|
||||||
|
@ -474,8 +474,8 @@ extension KeyHandler {
|
||||||
/// - errorCallback: 錯誤回呼。
|
/// - errorCallback: 錯誤回呼。
|
||||||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||||
func handleDelete(
|
func handleDelete(
|
||||||
state: InputState,
|
state: InputStateProtocol,
|
||||||
stateCallback: @escaping (InputState) -> Void,
|
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||||
errorCallback: @escaping () -> Void
|
errorCallback: @escaping () -> Void
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
guard state is InputState.Inputting else { return false }
|
guard state is InputState.Inputting else { return false }
|
||||||
|
@ -514,8 +514,8 @@ extension KeyHandler {
|
||||||
/// - errorCallback: 錯誤回呼。
|
/// - errorCallback: 錯誤回呼。
|
||||||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||||
func handleAbsorbedArrowKey(
|
func handleAbsorbedArrowKey(
|
||||||
state: InputState,
|
state: InputStateProtocol,
|
||||||
stateCallback: @escaping (InputState) -> Void,
|
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||||
errorCallback: @escaping () -> Void
|
errorCallback: @escaping () -> Void
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
guard state is InputState.Inputting else { return false }
|
guard state is InputState.Inputting else { return false }
|
||||||
|
@ -536,8 +536,8 @@ extension KeyHandler {
|
||||||
/// - errorCallback: 錯誤回呼。
|
/// - errorCallback: 錯誤回呼。
|
||||||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||||
func handleHome(
|
func handleHome(
|
||||||
state: InputState,
|
state: InputStateProtocol,
|
||||||
stateCallback: @escaping (InputState) -> Void,
|
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||||
errorCallback: @escaping () -> Void
|
errorCallback: @escaping () -> Void
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
guard state is InputState.Inputting else { return false }
|
guard state is InputState.Inputting else { return false }
|
||||||
|
@ -570,8 +570,8 @@ extension KeyHandler {
|
||||||
/// - errorCallback: 錯誤回呼。
|
/// - errorCallback: 錯誤回呼。
|
||||||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||||
func handleEnd(
|
func handleEnd(
|
||||||
state: InputState,
|
state: InputStateProtocol,
|
||||||
stateCallback: @escaping (InputState) -> Void,
|
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||||
errorCallback: @escaping () -> Void
|
errorCallback: @escaping () -> Void
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
guard state is InputState.Inputting else { return false }
|
guard state is InputState.Inputting else { return false }
|
||||||
|
@ -603,8 +603,8 @@ extension KeyHandler {
|
||||||
/// - stateCallback: 狀態回呼。
|
/// - stateCallback: 狀態回呼。
|
||||||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||||
func handleEsc(
|
func handleEsc(
|
||||||
state: InputState,
|
state: InputStateProtocol,
|
||||||
stateCallback: @escaping (InputState) -> Void,
|
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||||
errorCallback _: @escaping () -> Void
|
errorCallback _: @escaping () -> Void
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
guard state is InputState.Inputting else { return false }
|
guard state is InputState.Inputting else { return false }
|
||||||
|
@ -638,9 +638,9 @@ extension KeyHandler {
|
||||||
/// - errorCallback: 錯誤回呼。
|
/// - errorCallback: 錯誤回呼。
|
||||||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||||
func handleForward(
|
func handleForward(
|
||||||
state: InputState,
|
state: InputStateProtocol,
|
||||||
input: InputSignal,
|
input: InputSignal,
|
||||||
stateCallback: @escaping (InputState) -> Void,
|
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||||
errorCallback: @escaping () -> Void
|
errorCallback: @escaping () -> Void
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
guard let currentState = state as? InputState.Inputting else { return false }
|
guard let currentState = state as? InputState.Inputting else { return false }
|
||||||
|
@ -694,9 +694,9 @@ extension KeyHandler {
|
||||||
/// - errorCallback: 錯誤回呼。
|
/// - errorCallback: 錯誤回呼。
|
||||||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||||
func handleBackward(
|
func handleBackward(
|
||||||
state: InputState,
|
state: InputStateProtocol,
|
||||||
input: InputSignal,
|
input: InputSignal,
|
||||||
stateCallback: @escaping (InputState) -> Void,
|
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||||
errorCallback: @escaping () -> Void
|
errorCallback: @escaping () -> Void
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
guard let currentState = state as? InputState.Inputting else { return false }
|
guard let currentState = state as? InputState.Inputting else { return false }
|
||||||
|
@ -750,12 +750,12 @@ extension KeyHandler {
|
||||||
/// - errorCallback: 錯誤回呼。
|
/// - errorCallback: 錯誤回呼。
|
||||||
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
/// - Returns: 將按鍵行為「是否有處理掉」藉由 ctlInputMethod 回報給 IMK。
|
||||||
func handleInlineCandidateRotation(
|
func handleInlineCandidateRotation(
|
||||||
state: InputState,
|
state: InputStateProtocol,
|
||||||
reverseModifier: Bool,
|
reverseModifier: Bool,
|
||||||
stateCallback: @escaping (InputState) -> Void,
|
stateCallback: @escaping (InputStateProtocol) -> Void,
|
||||||
errorCallback: @escaping () -> Void
|
errorCallback: @escaping () -> Void
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
if composer.isEmpty && (compositor.isEmpty || walkedAnchors.isEmpty) { return false }
|
if composer.isEmpty, compositor.isEmpty || walkedAnchors.isEmpty { return false }
|
||||||
guard state is InputState.Inputting else {
|
guard state is InputState.Inputting else {
|
||||||
guard state is InputState.Empty else {
|
guard state is InputState.Empty else {
|
||||||
IME.prtDebugIntel("6044F081")
|
IME.prtDebugIntel("6044F081")
|
||||||
|
|
|
@ -46,7 +46,7 @@ extension String {
|
||||||
/// in an NSString (or .utf16).
|
/// in an NSString (or .utf16).
|
||||||
public func charIndexLiteral(from utf16Index: Int) -> Int {
|
public func charIndexLiteral(from utf16Index: Int) -> Int {
|
||||||
var length = 0
|
var length = 0
|
||||||
for (i, character) in self.enumerated() {
|
for (i, character) in enumerated() {
|
||||||
length += character.utf16.count
|
length += character.utf16.count
|
||||||
if length > utf16Index {
|
if length > utf16Index {
|
||||||
return (i)
|
return (i)
|
||||||
|
@ -65,8 +65,8 @@ extension String {
|
||||||
return self[..<self.index(startIndex, offsetBy: fixedIndex)].utf16.count
|
return self[..<self.index(startIndex, offsetBy: fixedIndex)].utf16.count
|
||||||
}
|
}
|
||||||
|
|
||||||
func utf16SubString(with r: Range<Int>) -> String {
|
internal func utf16SubString(with r: Range<Int>) -> String {
|
||||||
let arr = Array(self.utf16)[r].map { $0 }
|
let arr = Array(utf16)[r].map { $0 }
|
||||||
return String(utf16CodeUnits: arr, count: arr.count)
|
return String(utf16CodeUnits: arr, count: arr.count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ class ctlInputMethod: IMKInputController {
|
||||||
/// 按鍵調度模組的副本。
|
/// 按鍵調度模組的副本。
|
||||||
private var keyHandler: KeyHandler = .init()
|
private var keyHandler: KeyHandler = .init()
|
||||||
/// 用以記錄當前輸入法狀態的變數。
|
/// 用以記錄當前輸入法狀態的變數。
|
||||||
private var state: InputState = .Empty()
|
private var state: InputStateProtocol = InputState.Empty()
|
||||||
|
|
||||||
// MARK: - 工具函式
|
// MARK: - 工具函式
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ class ctlInputMethod: IMKInputController {
|
||||||
if client().bundleIdentifier() != Bundle.main.bundleIdentifier {
|
if client().bundleIdentifier() != Bundle.main.bundleIdentifier {
|
||||||
// 強制重設當前鍵盤佈局、使其與偏好設定同步。
|
// 強制重設當前鍵盤佈局、使其與偏好設定同步。
|
||||||
setKeyLayout()
|
setKeyLayout()
|
||||||
handle(state: .Empty())
|
handle(state: InputState.Empty())
|
||||||
} // 除此之外就不要動了,免得在點開輸入法自身的視窗時卡死。
|
} // 除此之外就不要動了,免得在點開輸入法自身的視窗時卡死。
|
||||||
(NSApp.delegate as? AppDelegate)?.checkForUpdate()
|
(NSApp.delegate as? AppDelegate)?.checkForUpdate()
|
||||||
}
|
}
|
||||||
|
@ -117,8 +117,8 @@ class ctlInputMethod: IMKInputController {
|
||||||
override func deactivateServer(_ sender: Any!) {
|
override func deactivateServer(_ sender: Any!) {
|
||||||
_ = sender // 防止格式整理工具毀掉與此對應的參數。
|
_ = sender // 防止格式整理工具毀掉與此對應的參數。
|
||||||
keyHandler.clear()
|
keyHandler.clear()
|
||||||
handle(state: .Empty())
|
handle(state: InputState.Empty())
|
||||||
handle(state: .Deactivated())
|
handle(state: InputState.Deactivated())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 切換至某一個輸入法的某個副本時(比如威注音的簡體輸入法副本與繁體輸入法副本),會觸發該函式。
|
/// 切換至某一個輸入法的某個副本時(比如威注音的簡體輸入法副本與繁體輸入法副本),會觸發該函式。
|
||||||
|
@ -149,7 +149,7 @@ class ctlInputMethod: IMKInputController {
|
||||||
if client().bundleIdentifier() != Bundle.main.bundleIdentifier {
|
if client().bundleIdentifier() != Bundle.main.bundleIdentifier {
|
||||||
// 強制重設當前鍵盤佈局、使其與偏好設定同步。這裡的這一步也不能省略。
|
// 強制重設當前鍵盤佈局、使其與偏好設定同步。這裡的這一步也不能省略。
|
||||||
setKeyLayout()
|
setKeyLayout()
|
||||||
handle(state: .Empty())
|
handle(state: InputState.Empty())
|
||||||
} // 除此之外就不要動了,免得在點開輸入法自身的視窗時卡死。
|
} // 除此之外就不要動了,免得在點開輸入法自身的視窗時卡死。
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ extension ctlInputMethod {
|
||||||
/// 先將舊狀態單獨記錄起來,再將新舊狀態作為參數,
|
/// 先將舊狀態單獨記錄起來,再將新舊狀態作為參數,
|
||||||
/// 根據新狀態本身的狀態種類來判斷交給哪一個專門的函式來處理。
|
/// 根據新狀態本身的狀態種類來判斷交給哪一個專門的函式來處理。
|
||||||
/// - Parameter newState: 新狀態。
|
/// - Parameter newState: 新狀態。
|
||||||
private func handle(state newState: InputState) {
|
private func handle(state newState: InputStateProtocol) {
|
||||||
let prevState = state
|
let prevState = state
|
||||||
state = newState
|
state = newState
|
||||||
|
|
||||||
|
@ -341,7 +341,7 @@ extension ctlInputMethod {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handle(state: InputState.Deactivated, previous: InputState) {
|
private func handle(state: InputState.Deactivated, previous: InputStateProtocol) {
|
||||||
_ = state // 防止格式整理工具毀掉與此對應的參數。
|
_ = state // 防止格式整理工具毀掉與此對應的參數。
|
||||||
ctlCandidateCurrent.delegate = nil
|
ctlCandidateCurrent.delegate = nil
|
||||||
ctlCandidateCurrent.visible = false
|
ctlCandidateCurrent.visible = false
|
||||||
|
@ -352,7 +352,7 @@ extension ctlInputMethod {
|
||||||
clearInlineDisplay()
|
clearInlineDisplay()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handle(state: InputState.Empty, previous: InputState) {
|
private func handle(state: InputState.Empty, previous: InputStateProtocol) {
|
||||||
_ = state // 防止格式整理工具毀掉與此對應的參數。
|
_ = state // 防止格式整理工具毀掉與此對應的參數。
|
||||||
ctlCandidateCurrent.visible = false
|
ctlCandidateCurrent.visible = false
|
||||||
hideTooltip()
|
hideTooltip()
|
||||||
|
@ -365,7 +365,7 @@ extension ctlInputMethod {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handle(
|
private func handle(
|
||||||
state: InputState.EmptyIgnoringPreviousState, previous: InputState
|
state: InputState.EmptyIgnoringPreviousState, previous: InputStateProtocol
|
||||||
) {
|
) {
|
||||||
_ = state // 防止格式整理工具毀掉與此對應的參數。
|
_ = state // 防止格式整理工具毀掉與此對應的參數。
|
||||||
_ = previous // 防止格式整理工具毀掉與此對應的參數。
|
_ = previous // 防止格式整理工具毀掉與此對應的參數。
|
||||||
|
@ -374,7 +374,7 @@ extension ctlInputMethod {
|
||||||
clearInlineDisplay()
|
clearInlineDisplay()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handle(state: InputState.Committing, previous: InputState) {
|
private func handle(state: InputState.Committing, previous: InputStateProtocol) {
|
||||||
_ = previous // 防止格式整理工具毀掉與此對應的參數。
|
_ = previous // 防止格式整理工具毀掉與此對應的參數。
|
||||||
ctlCandidateCurrent.visible = false
|
ctlCandidateCurrent.visible = false
|
||||||
hideTooltip()
|
hideTooltip()
|
||||||
|
@ -385,7 +385,7 @@ extension ctlInputMethod {
|
||||||
clearInlineDisplay()
|
clearInlineDisplay()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handle(state: InputState.Inputting, previous: InputState) {
|
private func handle(state: InputState.Inputting, previous: InputStateProtocol) {
|
||||||
_ = previous // 防止格式整理工具毀掉與此對應的參數。
|
_ = previous // 防止格式整理工具毀掉與此對應的參數。
|
||||||
ctlCandidateCurrent.visible = false
|
ctlCandidateCurrent.visible = false
|
||||||
hideTooltip()
|
hideTooltip()
|
||||||
|
@ -402,7 +402,7 @@ extension ctlInputMethod {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handle(state: InputState.Marking, previous: InputState) {
|
private func handle(state: InputState.Marking, previous: InputStateProtocol) {
|
||||||
_ = previous // 防止格式整理工具毀掉與此對應的參數。
|
_ = previous // 防止格式整理工具毀掉與此對應的參數。
|
||||||
ctlCandidateCurrent.visible = false
|
ctlCandidateCurrent.visible = false
|
||||||
setInlineDisplayWithCursor()
|
setInlineDisplayWithCursor()
|
||||||
|
@ -416,21 +416,21 @@ extension ctlInputMethod {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handle(state: InputState.ChoosingCandidate, previous: InputState) {
|
private func handle(state: InputState.ChoosingCandidate, previous: InputStateProtocol) {
|
||||||
_ = previous // 防止格式整理工具毀掉與此對應的參數。
|
_ = previous // 防止格式整理工具毀掉與此對應的參數。
|
||||||
hideTooltip()
|
hideTooltip()
|
||||||
setInlineDisplayWithCursor()
|
setInlineDisplayWithCursor()
|
||||||
show(candidateWindowWith: state)
|
show(candidateWindowWith: state)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handle(state: InputState.SymbolTable, previous: InputState) {
|
private func handle(state: InputState.SymbolTable, previous: InputStateProtocol) {
|
||||||
_ = previous // 防止格式整理工具毀掉與此對應的參數。
|
_ = previous // 防止格式整理工具毀掉與此對應的參數。
|
||||||
hideTooltip()
|
hideTooltip()
|
||||||
setInlineDisplayWithCursor()
|
setInlineDisplayWithCursor()
|
||||||
show(candidateWindowWith: state)
|
show(candidateWindowWith: state)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handle(state: InputState.AssociatedPhrases, previous: InputState) {
|
private func handle(state: InputState.AssociatedPhrases, previous: InputStateProtocol) {
|
||||||
_ = previous // 防止格式整理工具毀掉與此對應的參數。
|
_ = previous // 防止格式整理工具毀掉與此對應的參數。
|
||||||
hideTooltip()
|
hideTooltip()
|
||||||
clearInlineDisplay()
|
clearInlineDisplay()
|
||||||
|
@ -441,7 +441,7 @@ extension ctlInputMethod {
|
||||||
// MARK: -
|
// MARK: -
|
||||||
|
|
||||||
extension ctlInputMethod {
|
extension ctlInputMethod {
|
||||||
private func show(candidateWindowWith state: InputState) {
|
private func show(candidateWindowWith state: InputStateProtocol) {
|
||||||
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
|
||||||
|
@ -595,7 +595,7 @@ extension ctlInputMethod: KeyHandlerDelegate {
|
||||||
ctlCandidate(controller, didSelectCandidateAtIndex: index)
|
ctlCandidate(controller, didSelectCandidateAtIndex: index)
|
||||||
}
|
}
|
||||||
|
|
||||||
func keyHandler(_ keyHandler: KeyHandler, didRequestWriteUserPhraseWith state: InputState)
|
func keyHandler(_ keyHandler: KeyHandler, didRequestWriteUserPhraseWith state: InputStateProtocol)
|
||||||
-> Bool
|
-> Bool
|
||||||
{
|
{
|
||||||
guard let state = state as? InputState.Marking else {
|
guard let state = state as? InputState.Marking else {
|
||||||
|
@ -656,13 +656,13 @@ extension ctlInputMethod: ctlCandidateDelegate {
|
||||||
let node = state.node.children?[index]
|
let node = state.node.children?[index]
|
||||||
{
|
{
|
||||||
if let children = node.children, !children.isEmpty {
|
if let children = node.children, !children.isEmpty {
|
||||||
handle(state: .Empty()) // 防止縱橫排選字窗同時出現
|
handle(state: InputState.Empty()) // 防止縱橫排選字窗同時出現
|
||||||
handle(
|
handle(
|
||||||
state: .SymbolTable(node: node, isTypingVertical: state.isTypingVertical)
|
state: InputState.SymbolTable(node: node, isTypingVertical: state.isTypingVertical)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
handle(state: .Committing(textToCommit: node.title))
|
handle(state: InputState.Committing(textToCommit: node.title))
|
||||||
handle(state: .Empty())
|
handle(state: InputState.Empty())
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -676,7 +676,7 @@ extension ctlInputMethod: ctlCandidateDelegate {
|
||||||
if mgrPrefs.useSCPCTypingMode {
|
if mgrPrefs.useSCPCTypingMode {
|
||||||
keyHandler.clear()
|
keyHandler.clear()
|
||||||
let composingBuffer = inputting.composingBuffer
|
let composingBuffer = inputting.composingBuffer
|
||||||
handle(state: .Committing(textToCommit: composingBuffer))
|
handle(state: InputState.Committing(textToCommit: composingBuffer))
|
||||||
if mgrPrefs.associatedPhrasesEnabled,
|
if mgrPrefs.associatedPhrasesEnabled,
|
||||||
let associatePhrases = keyHandler.buildAssociatePhraseState(
|
let associatePhrases = keyHandler.buildAssociatePhraseState(
|
||||||
withKey: composingBuffer, isTypingVertical: state.isTypingVertical
|
withKey: composingBuffer, isTypingVertical: state.isTypingVertical
|
||||||
|
@ -684,7 +684,7 @@ extension ctlInputMethod: ctlCandidateDelegate {
|
||||||
{
|
{
|
||||||
handle(state: associatePhrases)
|
handle(state: associatePhrases)
|
||||||
} else {
|
} else {
|
||||||
handle(state: .Empty())
|
handle(state: InputState.Empty())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
handle(state: inputting)
|
handle(state: inputting)
|
||||||
|
@ -694,7 +694,7 @@ extension ctlInputMethod: ctlCandidateDelegate {
|
||||||
|
|
||||||
if let state = state as? InputState.AssociatedPhrases {
|
if let state = state as? InputState.AssociatedPhrases {
|
||||||
let selectedValue = state.candidates[index]
|
let selectedValue = state.candidates[index]
|
||||||
handle(state: .Committing(textToCommit: selectedValue))
|
handle(state: InputState.Committing(textToCommit: selectedValue))
|
||||||
if mgrPrefs.associatedPhrasesEnabled,
|
if mgrPrefs.associatedPhrasesEnabled,
|
||||||
let associatePhrases = keyHandler.buildAssociatePhraseState(
|
let associatePhrases = keyHandler.buildAssociatePhraseState(
|
||||||
withKey: selectedValue, isTypingVertical: state.isTypingVertical
|
withKey: selectedValue, isTypingVertical: state.isTypingVertical
|
||||||
|
@ -702,7 +702,7 @@ extension ctlInputMethod: ctlCandidateDelegate {
|
||||||
{
|
{
|
||||||
handle(state: associatePhrases)
|
handle(state: associatePhrases)
|
||||||
} else {
|
} else {
|
||||||
handle(state: .Empty())
|
handle(state: InputState.Empty())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ public class ctlCandidate: NSWindowController {
|
||||||
case horizontal
|
case horizontal
|
||||||
case vertical
|
case vertical
|
||||||
}
|
}
|
||||||
|
|
||||||
public var currentLayout: Layout = .horizontal
|
public var currentLayout: Layout = .horizontal
|
||||||
public weak var delegate: ctlCandidateDelegate? {
|
public weak var delegate: ctlCandidateDelegate? {
|
||||||
didSet {
|
didSet {
|
||||||
|
|
Loading…
Reference in New Issue