SessionCtl // Make PCB, tooltip, and candidate window instances dynamic.
This commit is contained in:
parent
940e9b6d85
commit
a144e20304
|
@ -28,7 +28,7 @@ class SessionCtl: IMKInputController {
|
|||
static var areWeNerfing = false
|
||||
|
||||
/// 目前在用的的選字窗副本。
|
||||
static var ctlCandidateCurrent: CtlCandidateProtocol = {
|
||||
var ctlCandidateCurrent: CtlCandidateProtocol = {
|
||||
let direction: NSUserInterfaceLayoutOrientation =
|
||||
PrefMgr.shared.useHorizontalCandidateList ? .horizontal : .vertical
|
||||
if #available(macOS 10.15, *) {
|
||||
|
@ -39,11 +39,11 @@ class SessionCtl: IMKInputController {
|
|||
}
|
||||
}()
|
||||
|
||||
/// 工具提示視窗的共用副本。
|
||||
static var tooltipInstance = TooltipUI()
|
||||
/// 工具提示視窗的副本。
|
||||
var tooltipInstance = TooltipUI()
|
||||
|
||||
/// 浮動組字窗的共用副本。
|
||||
static var popupCompositionBuffer = PopupCompositionBuffer()
|
||||
/// 浮動組字窗的副本。
|
||||
var popupCompositionBuffer = PopupCompositionBuffer()
|
||||
|
||||
// MARK: -
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ extension SessionCtl: KeyHandlerDelegate {
|
|||
return client.bundleIdentifier() ?? ""
|
||||
}
|
||||
|
||||
func candidateController() -> CtlCandidateProtocol { Self.ctlCandidateCurrent }
|
||||
func candidateController() -> CtlCandidateProtocol { ctlCandidateCurrent }
|
||||
|
||||
func candidateSelectionCalledByKeyHandler(at index: Int) {
|
||||
candidatePairSelected(at: index)
|
||||
|
|
|
@ -56,14 +56,14 @@ extension SessionCtl {
|
|||
}()
|
||||
// 強制重新初期化,因為 NSAttributedTextView 有顯示滯後性。
|
||||
do {
|
||||
Self.tooltipInstance.hide()
|
||||
Self.tooltipInstance = .init()
|
||||
tooltipInstance.hide()
|
||||
tooltipInstance = .init()
|
||||
if state.type == .ofMarking {
|
||||
Self.tooltipInstance.setColor(state: state.data.tooltipColorState)
|
||||
tooltipInstance.setColor(state: state.data.tooltipColorState)
|
||||
}
|
||||
}
|
||||
// 再設定其文字顯示內容並顯示。
|
||||
Self.tooltipInstance.show(
|
||||
tooltipInstance.show(
|
||||
tooltip: tooltip, at: finalOrigin,
|
||||
bottomOutOfScreenAdjustmentHeight: delta, direction: tooltipContentDirection
|
||||
)
|
||||
|
@ -74,34 +74,34 @@ extension SessionCtl {
|
|||
state.isVerticalCandidateWindow = (isVerticalTyping || !PrefMgr.shared.useHorizontalCandidateList)
|
||||
|
||||
/// 無論是田所選字窗還是 IMK 選字窗,在這裡都有必要重新初期化。
|
||||
Self.ctlCandidateCurrent.delegate = nil
|
||||
ctlCandidateCurrent.delegate = nil
|
||||
let candidateLayout: NSUserInterfaceLayoutOrientation =
|
||||
((isVerticalTyping || !PrefMgr.shared.useHorizontalCandidateList)
|
||||
? .vertical
|
||||
: .horizontal)
|
||||
|
||||
if #available(macOS 10.15, *) {
|
||||
Self.ctlCandidateCurrent =
|
||||
ctlCandidateCurrent =
|
||||
PrefMgr.shared.useIMKCandidateWindow
|
||||
? CtlCandidateIMK(candidateLayout) : CtlCandidateTDK(candidateLayout)
|
||||
if let candidateTDK = Self.ctlCandidateCurrent as? CtlCandidateTDK {
|
||||
if let candidateTDK = ctlCandidateCurrent as? CtlCandidateTDK {
|
||||
candidateTDK.maxLinesPerPage = isVerticalTyping ? 1 : 3
|
||||
}
|
||||
} else {
|
||||
Self.ctlCandidateCurrent = CtlCandidateIMK(candidateLayout)
|
||||
ctlCandidateCurrent = CtlCandidateIMK(candidateLayout)
|
||||
}
|
||||
|
||||
Self.ctlCandidateCurrent.candidateFont = Self.candidateFont(
|
||||
ctlCandidateCurrent.candidateFont = Self.candidateFont(
|
||||
name: PrefMgr.shared.candidateTextFontName, size: PrefMgr.shared.candidateListTextSize
|
||||
)
|
||||
|
||||
if state.type == .ofAssociates {
|
||||
Self.ctlCandidateCurrent.tooltip =
|
||||
ctlCandidateCurrent.tooltip =
|
||||
isVerticalTyping ? "⇧" : NSLocalizedString("Hold ⇧ to choose associates.", comment: "")
|
||||
}
|
||||
|
||||
Self.ctlCandidateCurrent.useLangIdentifier = PrefMgr.shared.handleDefaultCandidateFontsByLangIdentifier
|
||||
Self.ctlCandidateCurrent.locale = {
|
||||
ctlCandidateCurrent.useLangIdentifier = PrefMgr.shared.handleDefaultCandidateFontsByLangIdentifier
|
||||
ctlCandidateCurrent.locale = {
|
||||
switch inputMode {
|
||||
case .imeModeCHS: return "zh-Hans"
|
||||
case .imeModeCHT:
|
||||
|
@ -115,25 +115,25 @@ extension SessionCtl {
|
|||
|
||||
if #available(macOS 10.14, *) {
|
||||
// Spotlight 視窗會擋住 IMK 選字窗,所以需要特殊處理。
|
||||
if let ctlCandidateCurrent = Self.ctlCandidateCurrent as? CtlCandidateIMK {
|
||||
if let ctlCandidateCurrent = ctlCandidateCurrent as? CtlCandidateIMK {
|
||||
while ctlCandidateCurrent.windowLevel() <= client.windowLevel() {
|
||||
ctlCandidateCurrent.setWindowLevel(UInt64(max(0, client.windowLevel() + 1000)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Self.ctlCandidateCurrent.delegate = self // 會自動觸發田所選字窗的資料重載。
|
||||
Self.ctlCandidateCurrent.visible = true
|
||||
ctlCandidateCurrent.delegate = self // 會自動觸發田所選字窗的資料重載。
|
||||
ctlCandidateCurrent.visible = true
|
||||
|
||||
if isVerticalTyping {
|
||||
Self.ctlCandidateCurrent.set(
|
||||
ctlCandidateCurrent.set(
|
||||
windowTopLeftPoint: NSPoint(
|
||||
x: lineHeightRect().origin.x + lineHeightRect().size.width + 4.0, y: lineHeightRect().origin.y - 4.0
|
||||
),
|
||||
bottomOutOfScreenAdjustmentHeight: lineHeightRect().size.height + 4.0
|
||||
)
|
||||
} else {
|
||||
Self.ctlCandidateCurrent.set(
|
||||
ctlCandidateCurrent.set(
|
||||
windowTopLeftPoint: NSPoint(x: lineHeightRect().origin.x, y: lineHeightRect().origin.y - 4.0),
|
||||
bottomOutOfScreenAdjustmentHeight: lineHeightRect().size.height + 4.0
|
||||
)
|
||||
|
|
|
@ -173,7 +173,7 @@ extension SessionCtl {
|
|||
// 這樣可以讓 interpretKeyEvents() 函式自行判斷:
|
||||
// - 是就地交給 imkCandidates.interpretKeyEvents() 處理?
|
||||
// - 還是藉由 delegate 扔回 SessionCtl 給 KeyHandler 處理?
|
||||
if let imkCandidates = Self.ctlCandidateCurrent as? CtlCandidateIMK, imkCandidates.visible {
|
||||
if let imkCandidates = ctlCandidateCurrent as? CtlCandidateIMK, imkCandidates.visible {
|
||||
let event: NSEvent = CtlCandidateIMK.replaceNumPadKeyCodes(target: eventToDeal) ?? eventToDeal
|
||||
|
||||
// Shift+Enter 是個特殊情形,不提前攔截處理的話、會有垃圾參數傳給 delegate 的 keyHandler 從而崩潰。
|
||||
|
@ -207,7 +207,7 @@ extension SessionCtl {
|
|||
|
||||
private func imkCandidatesEventSubHandler(event: NSEvent) -> Bool {
|
||||
let eventArray = [event]
|
||||
guard let imkC = Self.ctlCandidateCurrent as? CtlCandidateIMK else { return false }
|
||||
guard let imkC = ctlCandidateCurrent as? CtlCandidateIMK else { return false }
|
||||
if event.isEsc || event.isBackSpace || event.isDelete || (event.isShiftHold && !event.isSpace) {
|
||||
return commonEventHandler(event)
|
||||
} else if event.isSymbolMenuPhysicalKey {
|
||||
|
|
|
@ -22,9 +22,10 @@ extension SessionCtl {
|
|||
state = newState
|
||||
switch state.type {
|
||||
case .ofDeactivated:
|
||||
Self.ctlCandidateCurrent.delegate = nil
|
||||
Self.ctlCandidateCurrent.visible = false
|
||||
Self.tooltipInstance.hide()
|
||||
ctlCandidateCurrent.delegate = nil
|
||||
ctlCandidateCurrent.visible = false
|
||||
popupCompositionBuffer.hide()
|
||||
tooltipInstance.hide()
|
||||
if previous.hasComposition {
|
||||
commit(text: previous.displayedText)
|
||||
}
|
||||
|
@ -37,29 +38,29 @@ extension SessionCtl {
|
|||
state = IMEState.ofEmpty()
|
||||
previous = state
|
||||
}
|
||||
Self.ctlCandidateCurrent.visible = false
|
||||
Self.tooltipInstance.hide()
|
||||
ctlCandidateCurrent.visible = false
|
||||
tooltipInstance.hide()
|
||||
// 全專案用以判斷「.Abortion」的地方僅此一處。
|
||||
if previous.hasComposition, state.type != .ofAbortion {
|
||||
commit(text: previous.displayedText)
|
||||
}
|
||||
// 在這裡手動再取消一次選字窗與工具提示的顯示,可謂雙重保險。
|
||||
Self.ctlCandidateCurrent.visible = false
|
||||
Self.tooltipInstance.hide()
|
||||
ctlCandidateCurrent.visible = false
|
||||
tooltipInstance.hide()
|
||||
clearInlineDisplay()
|
||||
// 最後一道保險
|
||||
keyHandler.clear()
|
||||
case .ofCommitting:
|
||||
Self.ctlCandidateCurrent.visible = false
|
||||
Self.tooltipInstance.hide()
|
||||
ctlCandidateCurrent.visible = false
|
||||
tooltipInstance.hide()
|
||||
let textToCommit = state.textToCommit
|
||||
if !textToCommit.isEmpty { commit(text: textToCommit) }
|
||||
clearInlineDisplay()
|
||||
// 最後一道保險
|
||||
keyHandler.clear()
|
||||
case .ofInputting:
|
||||
Self.ctlCandidateCurrent.visible = false
|
||||
Self.tooltipInstance.hide()
|
||||
ctlCandidateCurrent.visible = false
|
||||
tooltipInstance.hide()
|
||||
let textToCommit = state.textToCommit
|
||||
if !textToCommit.isEmpty { commit(text: textToCommit) }
|
||||
setInlineDisplayWithCursor()
|
||||
|
@ -67,27 +68,27 @@ extension SessionCtl {
|
|||
show(tooltip: state.tooltip)
|
||||
}
|
||||
case .ofMarking:
|
||||
Self.ctlCandidateCurrent.visible = false
|
||||
ctlCandidateCurrent.visible = false
|
||||
setInlineDisplayWithCursor()
|
||||
if state.tooltip.isEmpty {
|
||||
Self.tooltipInstance.hide()
|
||||
tooltipInstance.hide()
|
||||
} else {
|
||||
show(tooltip: state.tooltip)
|
||||
}
|
||||
case .ofCandidates, .ofAssociates, .ofSymbolTable:
|
||||
Self.tooltipInstance.hide()
|
||||
tooltipInstance.hide()
|
||||
setInlineDisplayWithCursor()
|
||||
showCandidates()
|
||||
default: break
|
||||
}
|
||||
// 浮動組字窗的顯示判定
|
||||
if state.hasComposition, PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier) {
|
||||
Self.popupCompositionBuffer.isTypingDirectionVertical = isVerticalTyping
|
||||
Self.popupCompositionBuffer.show(
|
||||
popupCompositionBuffer.isTypingDirectionVertical = isVerticalTyping
|
||||
popupCompositionBuffer.show(
|
||||
state: state, at: lineHeightRect(zeroCursor: true).origin
|
||||
)
|
||||
} else {
|
||||
Self.popupCompositionBuffer.hide()
|
||||
popupCompositionBuffer.hide()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue