Repo // Remove the useless .ofNotEmpty() state.
This commit is contained in:
parent
71aafba1c5
commit
47ab4867b1
|
@ -123,17 +123,33 @@ public enum TooltipColorState {
|
||||||
|
|
||||||
// MARK: - IMEState types.
|
// MARK: - IMEState types.
|
||||||
|
|
||||||
// 用以讓每個狀態自描述的 enum。
|
/// 用以讓每個狀態自描述的 enum。
|
||||||
public enum StateType: String {
|
public enum StateType: String {
|
||||||
|
/// **失活狀態 .ofDeactivated**: 使用者沒在使用輸入法、或者使用者已經切換到另一個客體應用來敲字。
|
||||||
case ofDeactivated = "Deactivated"
|
case ofDeactivated = "Deactivated"
|
||||||
|
/// **空狀態 .ofEmpty**: 使用者剛剛切換至該輸入法、卻還沒有任何輸入行為。
|
||||||
|
/// 抑或是剛剛敲字遞交給客體應用、準備新的輸入行為。
|
||||||
|
/// 威注音輸入法在「組字區與組音區/組筆區同時為空」、
|
||||||
|
/// 且客體軟體正在準備接收使用者文字輸入行為的時候,會處於空狀態。
|
||||||
|
/// 有時,威注音會利用呼叫空狀態的方式,讓組字區內已經顯示出來的內容遞交出去。
|
||||||
case ofEmpty = "Empty"
|
case ofEmpty = "Empty"
|
||||||
case ofAbortion = "Abortion" // 該狀態會自動轉為 Empty
|
/// **中絕狀態 .ofAbortion**: 與 .ofEmpty() 類似,但會扔掉上一個狀態的內容、
|
||||||
|
/// 不將這些內容遞交給客體應用。該狀態在處理完畢之後會被立刻切換至 .ofEmpty()。
|
||||||
|
case ofAbortion = "Abortion"
|
||||||
|
/// **遞交狀態 .ofCommitting**: 該狀態會承載要遞交出去的內容,讓輸入法控制器處理時代為遞交。
|
||||||
|
/// 該狀態在處理完畢之後會被立刻切換至 .ofEmpty()。如果直接呼叫處理該狀態的話,
|
||||||
|
/// 在呼叫處理之前的組字區的內容會消失,除非你事先呼叫處理過 .ofEmpty()。
|
||||||
case ofCommitting = "Committing"
|
case ofCommitting = "Committing"
|
||||||
|
/// **聯想詞狀態 .ofAssociates**: 逐字選字模式內的聯想詞輸入狀態。
|
||||||
case ofAssociates = "Associates"
|
case ofAssociates = "Associates"
|
||||||
case ofNotEmpty = "NotEmpty"
|
/// **輸入狀態 .ofInputting**: 使用者輸入了內容。此時會出現組字區(Compositor)。
|
||||||
case ofInputting = "Inputting"
|
case ofInputting = "Inputting"
|
||||||
|
/// **標記狀態 .ofMarking**: 使用者在組字區內標記某段範圍,
|
||||||
|
/// 可以決定是添入新詞、還是將這個範圍的詞音組合放入語彙濾除清單。
|
||||||
case ofMarking = "Marking"
|
case ofMarking = "Marking"
|
||||||
|
/// **選字狀態 .ofCandidates**: 叫出選字窗、允許使用者選字。
|
||||||
case ofCandidates = "Candidates"
|
case ofCandidates = "Candidates"
|
||||||
|
/// **分類分層符號表狀態 .ofSymbolTable**: 分類分層符號表選單專用的狀態,有自身的特殊處理。
|
||||||
case ofSymbolTable = "SymbolTable"
|
case ofSymbolTable = "SymbolTable"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,20 +26,23 @@ import Shared
|
||||||
///
|
///
|
||||||
/// 輸入法控制器持下述狀態:
|
/// 輸入法控制器持下述狀態:
|
||||||
///
|
///
|
||||||
/// - .Deactivated: 使用者沒在使用輸入法。
|
/// - **失活狀態 .ofDeactivated**: 使用者沒在使用輸入法、或者使用者已經切換到另一個客體應用來敲字。
|
||||||
/// - .AssociatedPhrases: 逐字選字模式內的聯想詞輸入狀態。因為逐字選字模式不需要在
|
/// - **空狀態 .ofEmpty**: 使用者剛剛切換至該輸入法、卻還沒有任何輸入行為。
|
||||||
/// 組字區內存入任何東西,所以該狀態不受 .NotEmpty 的管轄。
|
/// 抑或是剛剛敲字遞交給客體應用、準備新的輸入行為。
|
||||||
/// - .Empty: 使用者剛剛切換至該輸入法、卻還沒有任何輸入行為。抑或是剛剛敲字遞交給
|
/// 威注音輸入法在「組字區與組音區/組筆區同時為空」、
|
||||||
/// 客體應用、準備新的輸入行為。
|
/// 且客體軟體正在準備接收使用者文字輸入行為的時候,會處於空狀態。
|
||||||
/// - .Abortion: 與 Empty 類似,但會扔掉上一個狀態的內容、不將這些
|
/// 有時,威注音會利用呼叫空狀態的方式,讓組字區內已經顯示出來的內容遞交出去。
|
||||||
/// 內容遞交給客體應用。該狀態在處理完畢之後會被立刻切換至 .Empty()。
|
/// - **聯想詞狀態 .ofAssociates**: 逐字選字模式內的聯想詞輸入狀態。
|
||||||
/// - .Committing: 該狀態會承載要遞交出去的內容,讓輸入法控制器處理時代為遞交。
|
/// - **中絕狀態 .ofAbortion**: 與 .ofEmpty() 類似,但會扔掉上一個狀態的內容、
|
||||||
/// - .NotEmpty: 非空狀態,是一種狀態大類、用以派生且代表下述諸狀態。
|
/// 不將這些內容遞交給客體應用。該狀態在處理完畢之後會被立刻切換至 .ofEmpty()。
|
||||||
/// - .Inputting: 使用者輸入了內容。此時會出現組字區(Compositor)。
|
/// - **遞交狀態 .ofCommitting**: 該狀態會承載要遞交出去的內容,讓輸入法控制器處理時代為遞交。
|
||||||
/// - .Marking: 使用者在組字區內標記某段範圍,可以決定是添入新詞、還是將這個範圍的
|
/// 該狀態在處理完畢之後會被立刻切換至 .ofEmpty()。如果直接呼叫處理該狀態的話,
|
||||||
/// 詞音組合放入語彙濾除清單。
|
/// 在呼叫處理之前的組字區的內容會消失,除非你事先呼叫處理過 .ofEmpty()。
|
||||||
/// - .ChoosingCandidate: 叫出選字窗、允許使用者選字。
|
/// - **輸入狀態 .ofInputting**: 使用者輸入了內容。此時會出現組字區(Compositor)。
|
||||||
/// - .SymbolTable: 波浪鍵符號選單專用的狀態,有自身的特殊處理。
|
/// - **標記狀態 .ofMarking**: 使用者在組字區內標記某段範圍,
|
||||||
|
/// 可以決定是添入新詞、還是將這個範圍的詞音組合放入語彙濾除清單。
|
||||||
|
/// - **選字狀態 .ofCandidates**: 叫出選字窗、允許使用者選字。
|
||||||
|
/// - **分類分層符號表狀態 .ofSymbolTable**: 分類分層符號表選單專用的狀態,有自身的特殊處理。
|
||||||
public struct IMEState: IMEStateProtocol {
|
public struct IMEState: IMEStateProtocol {
|
||||||
public var type: StateType = .ofEmpty
|
public var type: StateType = .ofEmpty
|
||||||
public var data: IMEStateDataProtocol = IMEStateData() as IMEStateDataProtocol
|
public var data: IMEStateDataProtocol = IMEStateData() as IMEStateDataProtocol
|
||||||
|
@ -52,6 +55,28 @@ public struct IMEState: IMEStateProtocol {
|
||||||
isVerticalTyping = SessionCtl.isVerticalTyping
|
isVerticalTyping = SessionCtl.isVerticalTyping
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 內部專用初期化函式,僅用於生成「有輸入內容」的狀態。
|
||||||
|
/// - Parameters:
|
||||||
|
/// - displayTextSegments: 用以顯示的文本的字詞字串陣列,其中包含正在輸入的讀音或字根。
|
||||||
|
/// - cursor: 要顯示的游標(UTF8)。
|
||||||
|
fileprivate init(displayTextSegments: [String], cursor: Int) {
|
||||||
|
// 注意資料的設定順序,一定得先設定 displayTextSegments。
|
||||||
|
data.displayTextSegments = displayTextSegments.map {
|
||||||
|
if !SessionCtl.isVerticalTyping { return $0 }
|
||||||
|
guard PrefMgr.shared.hardenVerticalPunctuations else { return $0 }
|
||||||
|
var neta = $0
|
||||||
|
ChineseConverter.hardenVerticalPunctuations(target: &neta, convert: SessionCtl.isVerticalTyping)
|
||||||
|
return neta
|
||||||
|
}
|
||||||
|
data.cursor = cursor
|
||||||
|
data.marker = cursor
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 泛用初期化函式。
|
||||||
|
/// - Parameters:
|
||||||
|
/// - data: 資料載體。
|
||||||
|
/// - type: 狀態類型。
|
||||||
|
/// - node: 節點。
|
||||||
init(
|
init(
|
||||||
_ data: IMEStateDataProtocol = IMEStateData() as IMEStateDataProtocol, type: StateType = .ofEmpty,
|
_ data: IMEStateDataProtocol = IMEStateData() as IMEStateDataProtocol, type: StateType = .ofEmpty,
|
||||||
node: CandidateNode
|
node: CandidateNode
|
||||||
|
@ -88,24 +113,8 @@ extension IMEState {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ofNotEmpty(displayTextSegments: [String], cursor: Int) -> IMEState {
|
|
||||||
var result = IMEState(type: .ofNotEmpty)
|
|
||||||
// 注意資料的設定順序,一定得先設定 displayTextSegments。
|
|
||||||
result.data.displayTextSegments = displayTextSegments.map {
|
|
||||||
if !SessionCtl.isVerticalTyping { return $0 }
|
|
||||||
guard PrefMgr.shared.hardenVerticalPunctuations else { return $0 }
|
|
||||||
var neta = $0
|
|
||||||
ChineseConverter.hardenVerticalPunctuations(target: &neta, convert: SessionCtl.isVerticalTyping)
|
|
||||||
return neta
|
|
||||||
}
|
|
||||||
|
|
||||||
result.data.cursor = cursor
|
|
||||||
result.data.marker = cursor
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func ofInputting(displayTextSegments: [String], cursor: Int) -> IMEState {
|
public static func ofInputting(displayTextSegments: [String], cursor: Int) -> IMEState {
|
||||||
var result = Self.ofNotEmpty(displayTextSegments: displayTextSegments, cursor: cursor)
|
var result = IMEState(displayTextSegments: displayTextSegments, cursor: cursor)
|
||||||
result.type = .ofInputting
|
result.type = .ofInputting
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -115,7 +124,7 @@ extension IMEState {
|
||||||
)
|
)
|
||||||
-> IMEState
|
-> IMEState
|
||||||
{
|
{
|
||||||
var result = Self.ofNotEmpty(displayTextSegments: displayTextSegments, cursor: cursor)
|
var result = IMEState(displayTextSegments: displayTextSegments, cursor: cursor)
|
||||||
result.type = .ofMarking
|
result.type = .ofMarking
|
||||||
result.data.marker = marker
|
result.data.marker = marker
|
||||||
result.data.markedReadings = markedReadings
|
result.data.markedReadings = markedReadings
|
||||||
|
@ -126,14 +135,14 @@ extension IMEState {
|
||||||
public static func ofCandidates(candidates: [(String, String)], displayTextSegments: [String], cursor: Int)
|
public static func ofCandidates(candidates: [(String, String)], displayTextSegments: [String], cursor: Int)
|
||||||
-> IMEState
|
-> IMEState
|
||||||
{
|
{
|
||||||
var result = Self.ofNotEmpty(displayTextSegments: displayTextSegments, cursor: cursor)
|
var result = IMEState(displayTextSegments: displayTextSegments, cursor: cursor)
|
||||||
result.type = .ofCandidates
|
result.type = .ofCandidates
|
||||||
result.data.candidates = candidates
|
result.data.candidates = candidates
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ofSymbolTable(node: CandidateNode) -> IMEState {
|
public static func ofSymbolTable(node: CandidateNode) -> IMEState {
|
||||||
var result = IMEState(type: .ofNotEmpty, node: node)
|
var result = IMEState(node: node)
|
||||||
result.type = .ofSymbolTable
|
result.type = .ofSymbolTable
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -195,7 +204,7 @@ extension IMEState {
|
||||||
/// 該參數僅用作輔助判斷。在 InputHandler 內使用的話,必須再檢查 !compositor.isEmpty。
|
/// 該參數僅用作輔助判斷。在 InputHandler 內使用的話,必須再檢查 !compositor.isEmpty。
|
||||||
public var hasComposition: Bool {
|
public var hasComposition: Bool {
|
||||||
switch type {
|
switch type {
|
||||||
case .ofNotEmpty, .ofInputting, .ofMarking, .ofCandidates: return true
|
case .ofInputting, .ofMarking, .ofCandidates: return true
|
||||||
default: return false
|
default: return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,6 @@ extension SessionCtl {
|
||||||
tooltipInstance.hide()
|
tooltipInstance.hide()
|
||||||
setInlineDisplayWithCursor()
|
setInlineDisplayWithCursor()
|
||||||
showCandidates()
|
showCandidates()
|
||||||
default: break
|
|
||||||
}
|
}
|
||||||
// 浮動組字窗的顯示判定
|
// 浮動組字窗的顯示判定
|
||||||
if newState.hasComposition, PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier) {
|
if newState.hasComposition, PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier) {
|
||||||
|
@ -108,17 +107,8 @@ extension SessionCtl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 針對受 .NotEmpty() 管轄的非空狀態,在組字區內顯示游標。
|
/// 如果當前狀態含有「組字結果內容」、或者有選字窗內容、或者存在正在輸入的字根/讀音,則在組字區內顯示游標。
|
||||||
public func setInlineDisplayWithCursor() {
|
public func setInlineDisplayWithCursor() {
|
||||||
if state.type == .ofAssociates {
|
|
||||||
doSetMarkedText(
|
|
||||||
state.data.attributedStringPlaceholder, selectionRange: NSRange(location: 0, length: 0),
|
|
||||||
replacementRange: NSRange(location: NSNotFound, length: NSNotFound)
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if state.hasComposition || state.isCandidateContainer {
|
|
||||||
/// 所謂選區「selectionRange」,就是「可見游標位置」的位置,只不過長度
|
/// 所謂選區「selectionRange」,就是「可見游標位置」的位置,只不過長度
|
||||||
/// 是 0 且取代範圍(replacementRange)為「NSNotFound」罷了。
|
/// 是 0 且取代範圍(replacementRange)為「NSNotFound」罷了。
|
||||||
/// 也就是說,內文組字區該在哪裡出現,得由客體軟體來作主。
|
/// 也就是說,內文組字區該在哪裡出現,得由客體軟體來作主。
|
||||||
|
@ -126,15 +116,9 @@ extension SessionCtl {
|
||||||
attributedStringSecured.0, selectionRange: attributedStringSecured.1,
|
attributedStringSecured.0, selectionRange: attributedStringSecured.1,
|
||||||
replacementRange: NSRange(location: NSNotFound, length: NSNotFound)
|
replacementRange: NSRange(location: NSNotFound, length: NSNotFound)
|
||||||
)
|
)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 其它情形。
|
/// 在處理某些「沒有組字區內容顯示」且「不需要攔截某些按鍵處理」的狀態時使用的函式,會清空螢幕上顯示的組字區。
|
||||||
clearInlineDisplay()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 在處理不受 .NotEmpty() 管轄的狀態時可能要用到的函式,會清空螢幕上顯示的內文組字區。
|
|
||||||
/// 當 setInlineDisplayWithCursor() 在錯誤的狀態下被呼叫時,也會觸發這個函式。
|
|
||||||
private func clearInlineDisplay() {
|
private func clearInlineDisplay() {
|
||||||
doSetMarkedText(
|
doSetMarkedText(
|
||||||
"", selectionRange: NSRange(location: 0, length: 0),
|
"", selectionRange: NSRange(location: 0, length: 0),
|
||||||
|
|
Loading…
Reference in New Issue