feat: don't show the UI on very fast shortcut triggers from the user
By listening to keyboard events from another thread, that thread is able to cancel tasks scheduled on the main UI thread. This means that if the user activates the app, and very quickly release the keys to focus the other window, that key release event may be processed before the main UI thread tasks have finished. The keyboard processing thread may then cancel the UI work resulting in the UI not showing, which is good here
This commit is contained in:
1 parent
a5873d557a
commit
4b5fa1a9db
2 files changed
+19
-18
No files matched your search
@@ -22,21 +22,23 @@ class Keyboard {
|
||||
var eventTap: CFMachPort?
|
||||
|
||||
func listenToGlobalKeyboardEvents(_ delegate: Application) {
|
||||
let eventMask = [CGEventType.keyDown, CGEventType.keyUp, CGEventType.flagsChanged].reduce(CGEventMask(0), { $0 | (1 << $1.rawValue) })
|
||||
eventTap = CGEvent.tapCreate(
|
||||
tap: .cgSessionEventTap,
|
||||
place: .headInsertEventTap,
|
||||
options: .defaultTap,
|
||||
eventsOfInterest: CGEventMask(eventMask),
|
||||
callback: { (_, _, event, delegate_) -> Unmanaged<CGEvent>? in
|
||||
let d = Unmanaged<Application>.fromOpaque(delegate_!).takeUnretainedValue()
|
||||
return keyboardHandler(event, d)
|
||||
},
|
||||
userInfo: UnsafeMutableRawPointer(Unmanaged.passUnretained(delegate).toOpaque()))
|
||||
let runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0)
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, .commonModes)
|
||||
CGEvent.tapEnable(tap: eventTap!, enable: true)
|
||||
CFRunLoopRun()
|
||||
DispatchQueue.global(qos: .userInteractive).async {
|
||||
let eventMask = [CGEventType.keyDown, CGEventType.keyUp, CGEventType.flagsChanged].reduce(CGEventMask(0), { $0 | (1 << $1.rawValue) })
|
||||
eventTap = CGEvent.tapCreate(
|
||||
tap: .cgSessionEventTap,
|
||||
place: .headInsertEventTap,
|
||||
options: .defaultTap,
|
||||
eventsOfInterest: CGEventMask(eventMask),
|
||||
callback: { (_, _, event, delegate_) -> Unmanaged<CGEvent>? in
|
||||
let d = Unmanaged<Application>.fromOpaque(delegate_!).takeUnretainedValue()
|
||||
return keyboardHandler(event, d)
|
||||
},
|
||||
userInfo: UnsafeMutableRawPointer(Unmanaged.passUnretained(delegate).toOpaque()))
|
||||
let runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0)
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, .commonModes)
|
||||
CGEvent.tapEnable(tap: eventTap!, enable: true)
|
||||
CFRunLoopRun()
|
||||
}
|
||||
}
|
||||
|
||||
func keyboardHandler(_ cgEvent: CGEvent, _ delegate: Application) -> Unmanaged<CGEvent>? {
|
||||
|
||||
@@ -47,7 +47,7 @@ class Application: NSApplication, NSApplicationDelegate, NSWindowDelegate {
|
||||
|
||||
func hideUi() {
|
||||
debugPrint("hideUi")
|
||||
thumbnailsPanel!.orderOut(nil)
|
||||
DispatchQueue.main.async(execute: { self.thumbnailsPanel!.orderOut(nil) })
|
||||
appIsBeingUsed = false
|
||||
isFirstSummon = true
|
||||
}
|
||||
@@ -96,7 +96,7 @@ class Application: NSApplication, NSApplicationDelegate, NSWindowDelegate {
|
||||
|
||||
func cycleSelection(_ step: Int) {
|
||||
selectedOpenWindow = cellWithStep(step)
|
||||
thumbnailsPanel!.highlightCellAt(step)
|
||||
DispatchQueue.main.async(execute: { self.thumbnailsPanel!.highlightCellAt(step) })
|
||||
}
|
||||
|
||||
func showUiOrCycleSelection(_ step: Int) {
|
||||
@@ -117,7 +117,6 @@ class Application: NSApplication, NSApplicationDelegate, NSWindowDelegate {
|
||||
}
|
||||
workItems.append(workItem)
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Preferences.windowDisplayDelay!, execute: workItem)
|
||||
|
||||
} else {
|
||||
cycleSelection(step)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user