SessionCtl // Use an alternative way to keep IMKCandidates' visibility.
- We have no other way to solve the excessive-memory-usage problem without completely removing the instance container.
This commit is contained in:
parent
337cf84c8b
commit
1057a3fe82
|
@ -25,8 +25,6 @@ import UpdateSputnik
|
||||||
/// 輸入會話創建一個控制器型別。因此,對於每個輸入會話,都有一個對應的 IMKInputController。
|
/// 輸入會話創建一個控制器型別。因此,對於每個輸入會話,都有一個對應的 IMKInputController。
|
||||||
@objc(SessionCtl) // 必須加上 ObjC,因為 IMK 是用 ObjC 寫的。
|
@objc(SessionCtl) // 必須加上 ObjC,因為 IMK 是用 ObjC 寫的。
|
||||||
public class SessionCtl: IMKInputController {
|
public class SessionCtl: IMKInputController {
|
||||||
public static var allInstances: NSMutableOrderedSet = .init()
|
|
||||||
|
|
||||||
/// 標記狀態來聲明目前新增的詞彙是否需要賦以非常低的權重。
|
/// 標記狀態來聲明目前新增的詞彙是否需要賦以非常低的權重。
|
||||||
public static var areWeNerfing = false
|
public static var areWeNerfing = false
|
||||||
|
|
||||||
|
@ -121,6 +119,15 @@ public class SessionCtl: IMKInputController {
|
||||||
/// 重置輸入調度模組。
|
/// 重置輸入調度模組。
|
||||||
resetInputHandler(forceComposerCleanup: true)
|
resetInputHandler(forceComposerCleanup: true)
|
||||||
}
|
}
|
||||||
|
// 特殊處理:deactivateServer() 可能會遲於另一個客體會話的 activateServer() 執行。
|
||||||
|
// 雖然所有在這個函式內影響到的變數都改為動態變數了(不會出現跨副本波及的情況),
|
||||||
|
// 但 IMKCandidates 是有內部共用副本的、會被波及。所以在這裡糾偏一下。
|
||||||
|
if PrefMgr.shared.useIMKCandidateWindow {
|
||||||
|
guard let imkC = ctlCandidateCurrent as? CtlCandidateIMK else { return }
|
||||||
|
if state.isCandidateContainer, !imkC.visible {
|
||||||
|
handle(state: state, replace: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +191,7 @@ extension SessionCtl {
|
||||||
public override func activateServer(_ sender: Any!) {
|
public override func activateServer(_ sender: Any!) {
|
||||||
_ = sender // 防止格式整理工具毀掉與此對應的參數。
|
_ = sender // 防止格式整理工具毀掉與此對應的參數。
|
||||||
DispatchQueue.main.async { [self] in
|
DispatchQueue.main.async { [self] in
|
||||||
if Self.allInstances.contains(self) { return }
|
if isActivated { return }
|
||||||
|
|
||||||
// 因為偶爾會收到與 activateServer 有關的以「強制拆 nil」為理由的報錯,
|
// 因為偶爾會收到與 activateServer 有關的以「強制拆 nil」為理由的報錯,
|
||||||
// 所以這裡添加這句、來試圖應對這種情況。
|
// 所以這裡添加這句、來試圖應對這種情況。
|
||||||
|
@ -207,7 +214,6 @@ extension SessionCtl {
|
||||||
|
|
||||||
state = IMEState.ofEmpty()
|
state = IMEState.ofEmpty()
|
||||||
isActivated = true // 登記啟用狀態。
|
isActivated = true // 登記啟用狀態。
|
||||||
Self.allInstances.insert(self, at: 0)
|
|
||||||
setKeyLayout()
|
setKeyLayout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,7 +226,6 @@ extension SessionCtl {
|
||||||
isActivated = false
|
isActivated = false
|
||||||
resetInputHandler() // 這條會自動搞定 Empty 狀態。
|
resetInputHandler() // 這條會自動搞定 Empty 狀態。
|
||||||
switchState(IMEState.ofDeactivated())
|
switchState(IMEState.ofDeactivated())
|
||||||
Self.allInstances.remove(self)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,24 +42,12 @@ extension SessionCtl {
|
||||||
if replace { state = newState }
|
if replace { state = newState }
|
||||||
switch newState.type {
|
switch newState.type {
|
||||||
case .ofDeactivated:
|
case .ofDeactivated:
|
||||||
|
// 這裡移除一些處理,轉而交給 commitComposition() 代為執行。
|
||||||
|
// 這裡不需要 clearInlineDisplay() ,否則會觸發無限迴圈。
|
||||||
|
// 對於 IMK 選字窗的顯示狀態糾正的行為交給 inputMode.didSet() 來處理。
|
||||||
ctlCandidateCurrent.visible = false
|
ctlCandidateCurrent.visible = false
|
||||||
popupCompositionBuffer.hide()
|
popupCompositionBuffer.hide()
|
||||||
tooltipInstance.hide()
|
tooltipInstance.hide()
|
||||||
// 這裡移除一些處理,轉而交給 commitComposition() 代為執行。
|
|
||||||
// 這裡不需要 clearInlineDisplay() ,否則會觸發無限迴圈。
|
|
||||||
// 特殊處理:deactivateServer() 可能會遲於另一個客體會話的 activateServer() 執行。
|
|
||||||
// 雖然所有在這個函式內影響到的變數都改為動態變數了(不會出現跨副本波及的情況),
|
|
||||||
// 但 IMKCandidates 是有內部共用副本的、會被波及。
|
|
||||||
// 所以在這裡糾偏一下、讓所有開啟了選字窗的會話重新顯示選字窗。
|
|
||||||
if PrefMgr.shared.useIMKCandidateWindow {
|
|
||||||
for instance in Self.allInstances {
|
|
||||||
guard let instance = instance as? SessionCtl else { continue }
|
|
||||||
guard let imkC = instance.ctlCandidateCurrent as? CtlCandidateIMK else { continue }
|
|
||||||
if instance.state.isCandidateContainer, !imkC.visible {
|
|
||||||
instance.handle(state: instance.state, replace: false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case .ofEmpty, .ofAbortion, .ofCommitting:
|
case .ofEmpty, .ofAbortion, .ofCommitting:
|
||||||
innerCircle: switch newState.type {
|
innerCircle: switch newState.type {
|
||||||
case .ofAbortion:
|
case .ofAbortion:
|
||||||
|
|
Loading…
Reference in New Issue