SessionCtl // Nil the candidateUI for inactive sessions.
- We don't nil the IMKCandidates on deinit() in order to avoid EXC_BAD_ACCESS error.
This commit is contained in:
parent
6f25182af0
commit
65462f4ad0
|
@ -49,7 +49,7 @@ public protocol InputHandlerDelegate {
|
|||
var clientBundleIdentifier: String { get }
|
||||
func callError(_ logMessage: String)
|
||||
func switchState(_ newState: IMEStateProtocol)
|
||||
func candidateController() -> CtlCandidateProtocol
|
||||
func candidateController() -> CtlCandidateProtocol?
|
||||
func candidateSelectionCalledByInputHandler(at index: Int)
|
||||
func performUserPhraseOperation(addToFilter: Bool)
|
||||
-> Bool
|
||||
|
|
|
@ -21,7 +21,7 @@ extension InputHandler {
|
|||
/// - Returns: 告知 IMK「該按鍵是否已經被輸入法攔截處理」。
|
||||
func handleCandidate(input: InputSignalProtocol) -> Bool {
|
||||
guard let delegate = delegate else { return false }
|
||||
var ctlCandidate = delegate.candidateController()
|
||||
guard var ctlCandidate = delegate.candidateController() else { return false }
|
||||
let state = delegate.state
|
||||
guard !state.candidates.isEmpty else { return false }
|
||||
|
||||
|
|
|
@ -29,16 +29,7 @@ public class SessionCtl: IMKInputController {
|
|||
public static var areWeNerfing = false
|
||||
|
||||
/// 目前在用的的選字窗副本。
|
||||
public var candidateUI: CtlCandidateProtocol = {
|
||||
let direction: NSUserInterfaceLayoutOrientation =
|
||||
PrefMgr.shared.useHorizontalCandidateList ? .horizontal : .vertical
|
||||
if #available(macOS 10.15, *) {
|
||||
return PrefMgr.shared.useIMKCandidateWindow
|
||||
? CtlCandidateIMK(direction) : CtlCandidateTDK(direction)
|
||||
} else {
|
||||
return CtlCandidateIMK(direction)
|
||||
}
|
||||
}()
|
||||
public var candidateUI: CtlCandidateProtocol?
|
||||
|
||||
/// 工具提示視窗的副本。
|
||||
public var tooltipInstance = TooltipUI()
|
||||
|
@ -210,7 +201,6 @@ extension SessionCtl {
|
|||
// 因為偶爾會收到與 activateServer 有關的以「強制拆 nil」為理由的報錯,
|
||||
// 所以這裡添加這句、來試圖應對這種情況。
|
||||
inputHandler.delegate = self
|
||||
candidateUI.delegate = self
|
||||
// 這裡不需要 setValue(),因為 IMK 會在自動呼叫 activateServer() 之後自動執行 setValue()。
|
||||
inputHandler.clear() // 這句不要砍,因為後面 handle State.Empty() 不一定執行。
|
||||
inputHandler.ensureKeyboardParser()
|
||||
|
@ -241,6 +231,10 @@ extension SessionCtl {
|
|||
isActivated = false
|
||||
resetInputHandler() // 這條會自動搞定 Empty 狀態。
|
||||
switchState(IMEState.ofDeactivated())
|
||||
// IMK 選字窗可以不用 nil,不然反而會出問題。反正 IMK 選字窗記憶體開銷可以不計。
|
||||
if candidateUI is CtlCandidateTDK {
|
||||
candidateUI = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ extension SessionCtl: InputHandlerDelegate {
|
|||
return client.bundleIdentifier() ?? ""
|
||||
}
|
||||
|
||||
public func candidateController() -> CtlCandidateProtocol { candidateUI }
|
||||
public func candidateController() -> CtlCandidateProtocol? { candidateUI }
|
||||
|
||||
public func candidateSelectionCalledByInputHandler(at index: Int) {
|
||||
candidatePairSelected(at: index)
|
||||
|
|
|
@ -82,7 +82,7 @@ extension SessionCtl {
|
|||
: .horizontal)
|
||||
|
||||
/// 先取消既有的選字窗的內容顯示。否則可能會重複生成選字窗的 NSWindow()。
|
||||
candidateUI.visible = false
|
||||
candidateUI?.visible = false
|
||||
/// 然後再重新初期化。
|
||||
if #available(macOS 10.15, *) {
|
||||
candidateUI =
|
||||
|
@ -95,22 +95,22 @@ extension SessionCtl {
|
|||
candidateUI = CtlCandidateIMK(candidateLayout)
|
||||
}
|
||||
|
||||
candidateUI.candidateFont = Self.candidateFont(
|
||||
candidateUI?.candidateFont = Self.candidateFont(
|
||||
name: PrefMgr.shared.candidateTextFontName, size: PrefMgr.shared.candidateListTextSize
|
||||
)
|
||||
|
||||
if PrefMgr.shared.cassetteEnabled {
|
||||
candidateUI.tooltip =
|
||||
candidateUI?.tooltip =
|
||||
isVerticalTyping ? "📼" : "📼 " + NSLocalizedString("CIN Cassette Mode", comment: "")
|
||||
}
|
||||
|
||||
if state.type == .ofAssociates {
|
||||
candidateUI.tooltip =
|
||||
candidateUI?.tooltip =
|
||||
isVerticalTyping ? "⇧" : NSLocalizedString("Hold ⇧ to choose associates.", comment: "")
|
||||
}
|
||||
|
||||
candidateUI.useLangIdentifier = PrefMgr.shared.handleDefaultCandidateFontsByLangIdentifier
|
||||
candidateUI.locale = {
|
||||
candidateUI?.useLangIdentifier = PrefMgr.shared.handleDefaultCandidateFontsByLangIdentifier
|
||||
candidateUI?.locale = {
|
||||
switch inputMode {
|
||||
case .imeModeCHS: return "zh-Hans"
|
||||
case .imeModeCHT:
|
||||
|
@ -131,11 +131,11 @@ extension SessionCtl {
|
|||
}
|
||||
}
|
||||
|
||||
candidateUI.delegate = self // 會自動觸發田所選字窗的資料重載。
|
||||
candidateUI.visible = true
|
||||
candidateUI?.delegate = self // 會自動觸發田所選字窗的資料重載。
|
||||
candidateUI?.visible = true
|
||||
|
||||
if isVerticalTyping {
|
||||
candidateUI.set(
|
||||
candidateUI?.set(
|
||||
windowTopLeftPoint: NSPoint(
|
||||
x: lineHeightRect().origin.x + lineHeightRect().size.width + 4.0, y: lineHeightRect().origin.y - 4.0
|
||||
),
|
||||
|
@ -143,7 +143,7 @@ extension SessionCtl {
|
|||
useGCD: true
|
||||
)
|
||||
} else {
|
||||
candidateUI.set(
|
||||
candidateUI?.set(
|
||||
windowTopLeftPoint: NSPoint(x: lineHeightRect().origin.x, y: lineHeightRect().origin.y - 4.0),
|
||||
bottomOutOfScreenAdjustmentHeight: lineHeightRect().size.height + 4.0,
|
||||
useGCD: true
|
||||
|
|
|
@ -45,7 +45,7 @@ extension SessionCtl {
|
|||
// 這裡移除一些處理,轉而交給 commitComposition() 代為執行。
|
||||
// 這裡不需要 clearInlineDisplay() ,否則會觸發無限迴圈。
|
||||
// 對於 IMK 選字窗的顯示狀態糾正的行為交給 inputMode.didSet() 來處理。
|
||||
candidateUI.visible = false
|
||||
candidateUI?.visible = false
|
||||
popupCompositionBuffer.hide()
|
||||
tooltipInstance.hide()
|
||||
case .ofEmpty, .ofAbortion, .ofCommitting:
|
||||
|
@ -58,7 +58,7 @@ extension SessionCtl {
|
|||
if replace { state = IMEState.ofEmpty() }
|
||||
default: break innerCircle
|
||||
}
|
||||
candidateUI.visible = false
|
||||
candidateUI?.visible = false
|
||||
// 全專案用以判斷「.Abortion」的地方僅此一處。
|
||||
if previous.hasComposition, ![.ofAbortion, .ofCommitting].contains(newState.type) {
|
||||
commit(text: previous.displayedText)
|
||||
|
@ -67,12 +67,12 @@ extension SessionCtl {
|
|||
clearInlineDisplay()
|
||||
inputHandler.clear()
|
||||
case .ofInputting:
|
||||
candidateUI.visible = false
|
||||
candidateUI?.visible = false
|
||||
commit(text: newState.textToCommit)
|
||||
setInlineDisplayWithCursor()
|
||||
showTooltip(newState.tooltip, duration: 1) // 會在工具提示為空的時候自動消除顯示。
|
||||
case .ofMarking:
|
||||
candidateUI.visible = false
|
||||
candidateUI?.visible = false
|
||||
setInlineDisplayWithCursor()
|
||||
showTooltip(newState.tooltip)
|
||||
case .ofCandidates, .ofAssociates, .ofSymbolTable:
|
||||
|
|
Loading…
Reference in New Issue