fix: avoid input source work in event tap
This commit is contained in:
parent
240bd4fcf6
commit
f4606e44a4
3 changed files with 28 additions and 15 deletions
|
|
@ -25,6 +25,8 @@ final class InputSourceManager {
|
||||||
let id: String
|
let id: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var orderedSources: [Source] = []
|
||||||
|
|
||||||
var currentDisplayName: String {
|
var currentDisplayName: String {
|
||||||
guard let source = currentSource() else {
|
guard let source = currentSource() else {
|
||||||
return "—"
|
return "—"
|
||||||
|
|
@ -43,9 +45,13 @@ final class InputSourceManager {
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func refresh() {
|
||||||
|
orderedSources = enabledKeyboardSourcesInUserOrder()
|
||||||
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
func selectNextInputSource() -> Bool {
|
func selectNextInputSource() -> Bool {
|
||||||
let sources = enabledKeyboardSourcesInUserOrder()
|
let sources = orderedSources
|
||||||
guard sources.count > 1 else {
|
guard sources.count > 1 else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -163,6 +169,11 @@ final class MacOSInputController {
|
||||||
throw InputControllerError.accessibilityRequired
|
throw InputControllerError.accessibilityRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build the source order before the event tap starts. Enumerating TIS
|
||||||
|
// sources from inside a keyboard callback can block long enough for
|
||||||
|
// macOS to disable the tap while the user is typing quickly.
|
||||||
|
inputSources.refresh()
|
||||||
|
|
||||||
let eventMask = CGEventMask(1 << CGEventType.flagsChanged.rawValue)
|
let eventMask = CGEventMask(1 << CGEventType.flagsChanged.rawValue)
|
||||||
let refcon = Unmanaged.passUnretained(self).toOpaque()
|
let refcon = Unmanaged.passUnretained(self).toOpaque()
|
||||||
guard let tap = CGEvent.tapCreate(
|
guard let tap = CGEvent.tapCreate(
|
||||||
|
|
@ -221,6 +232,10 @@ final class MacOSInputController {
|
||||||
onStateChanged?()
|
onStateChanged?()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func refreshInputSources() {
|
||||||
|
inputSources.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
func openAccessibilitySettings() {
|
func openAccessibilitySettings() {
|
||||||
guard let url = URL(
|
guard let url = URL(
|
||||||
string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"
|
string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"
|
||||||
|
|
@ -328,16 +343,11 @@ final class MacOSInputController {
|
||||||
case .none:
|
case .none:
|
||||||
break
|
break
|
||||||
case .switchToNextInputSource:
|
case .switchToNextInputSource:
|
||||||
// TISSelectInputSource can synchronously trigger more keyboard
|
// The source list is cached before the tap starts, so this path is
|
||||||
// notifications. Let the event tap return first so a rapid key +
|
// deliberately synchronous: the next key must see the new source
|
||||||
// Caps sequence sees the new source before the next key is typed.
|
// even when the user is typing continuously.
|
||||||
DispatchQueue.main.async { [weak self] in
|
if inputSources.selectNextInputSource() {
|
||||||
guard let self, self.isRunning, !self.isPaused else {
|
onStateChanged?()
|
||||||
return
|
|
||||||
}
|
|
||||||
if self.inputSources.selectNextInputSource() {
|
|
||||||
self.onStateChanged?()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case .toggleCapsLock:
|
case .toggleCapsLock:
|
||||||
postSyntheticCapsLock()
|
postSyntheticCapsLock()
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,11 @@ final class StatusBarController: NSObject, NSMenuDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func refreshController() {
|
private func refreshController() {
|
||||||
if inputController.accessibilityTrusted,
|
if inputController.accessibilityTrusted {
|
||||||
!inputController.isRunning {
|
if !inputController.isRunning {
|
||||||
try? inputController.start()
|
try? inputController.start()
|
||||||
|
}
|
||||||
|
inputController.refreshInputSources()
|
||||||
}
|
}
|
||||||
update()
|
update()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,8 @@ tasks:
|
||||||
- grep -q "LSUIElement" Resources/Info.plist
|
- grep -q "LSUIElement" Resources/Info.plist
|
||||||
- grep -q ".flagsChanged" Sources/CapswitchApp/MacOSInputController.swift
|
- grep -q ".flagsChanged" Sources/CapswitchApp/MacOSInputController.swift
|
||||||
- grep -q "keyboardEventKeycode" Sources/CapswitchApp/MacOSInputController.swift
|
- grep -q "keyboardEventKeycode" Sources/CapswitchApp/MacOSInputController.swift
|
||||||
- grep -q "DispatchQueue.main.async" Sources/CapswitchApp/MacOSInputController.swift
|
- grep -q "orderedSources" Sources/CapswitchApp/MacOSInputController.swift
|
||||||
|
- grep -q "inputSources.refresh" Sources/CapswitchApp/MacOSInputController.swift
|
||||||
- grep -q "CGEvent.tapCreate" Sources/CapswitchApp/MacOSInputController.swift
|
- grep -q "CGEvent.tapCreate" Sources/CapswitchApp/MacOSInputController.swift
|
||||||
- grep -q "CGEvent.tapEnable" Sources/CapswitchApp/MacOSInputController.swift
|
- grep -q "CGEvent.tapEnable" Sources/CapswitchApp/MacOSInputController.swift
|
||||||
- test "$(grep -c "CGEventTapCreate" Sources/CapswitchApp/MacOSInputController.swift || true)" -eq 0
|
- test "$(grep -c "CGEventTapCreate" Sources/CapswitchApp/MacOSInputController.swift || true)" -eq 0
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue