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:
Louis Pontoise committed 2019-10-28 17:22:04 +09:00
1 parent a5873d557a
commit 4b5fa1a9db
2 files changed
+19 -18

No files matched your search

+17 -15
View File
@@ -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>? {
+2 -3
View File
@@ -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)
}