fix: ui would sometimes stay open (closes #588)

This commit is contained in:
Louis Pontoise authored and lwouis committed 2020-10-10 13:39:17 +09:00
1 parent 3019dd58d7
commit 8912c70bcd
5 files changed
+37 -23

No files matched your search

-5
View File
@@ -25,11 +25,6 @@ class ATShortcut {
state = state == .down ? .up : .down
if state == .up {
KeyRepeatTimer.timer?.invalidate()
} else {
// macOS bug: the app doesn't receive either local or global modifierChanged events during Space transition
// we force holdShortcut to be .down if nextWindowShortcut trigger during a transition, since we know it has to be down at that point
let suffix = shortcutId == "nextWindowShortcut" ? "" : "2"
ControlsTab.shortcuts["holdShortcut" + suffix]!.state = .down
}
if (triggerPhase == .down && shortcutState == .down) || (triggerPhase == .up && shortcutState == .up) {
return true
-2
View File
@@ -11,8 +11,6 @@ class Spaces {
debugPrint("OS event", "activeSpaceDidChangeNotification")
idsAndIndexes = allIdsAndIndexes()
updateCurrentSpace()
guard App.app.appIsBeingUsed else { return }
App.app.reopenUi()
})
}
+34 -15
View File
@@ -14,7 +14,6 @@ class KeyboardEvents {
"holdShortcut2": 3,
]
static var eventHotKeyRefs = [String: EventHotKeyRef?]()
static var hotModifierEventHandler: EventHandlerRef?
static var hotKeyPressedEventHandler: EventHandlerRef?
static var hotKeyReleasedEventHandler: EventHandlerRef?
static var localMonitor: Any!
@@ -70,22 +69,33 @@ class KeyboardEvents {
}
}
static func addLocalEventHandler() {
localMonitor = NSEvent.addLocalMonitorForEvents(matching: [.keyDown, .keyUp, .flagsChanged]) { event in
static func addEventHandlers() {
addLocalMonitorForKeyDownAndKeyUp()
addCgEventTapForModifierFlags()
}
private static func addLocalMonitorForKeyDownAndKeyUp() {
localMonitor = NSEvent.addLocalMonitorForEvents(matching: [.keyDown, .keyUp]) { event in
return handleEvent(nil, nil, event.type == .keyDown ? UInt32(event.keyCode) : nil, cocoaToCarbonFlags(event.modifierFlags), event.type == .keyDown ? event.isARepeat : false) ? nil : event
}
}
private static func addCgEventTapForModifierFlags() {
let eventMask = [CGEventType.flagsChanged].reduce(CGEventMask(0), { $0 | (1 << $1.rawValue) })
// CGEvent.tapCreate returns null if ensureAccessibilityCheckboxIsChecked() didn't pass
// CGEvent.tapCreate is unaffected by SecureInput for .flagsChanged
eventTap = CGEvent.tapCreate(
tap: .cgSessionEventTap,
place: .headInsertEventTap,
options: .defaultTap,
eventsOfInterest: eventMask,
callback: cgEventFlagsChangedHandler,
userInfo: nil)
let runLoopSource = CFMachPortCreateRunLoopSource(nil, eventTap, 0)
CFRunLoopAddSource(CFRunLoopGetMain(), runLoopSource, .commonModes)
}
private static func addGlobalHandlerIfNeeded(_ shortcut: Shortcut) {
if shortcut.keyCode == .none && hotModifierEventHandler == nil {
var eventTypes = [EventTypeSpec(eventClass: OSType(kEventClassKeyboard), eventKind: OSType(kEventRawKeyModifiersChanged))]
InstallEventHandler(GetEventMonitorTarget(), { (_: EventHandlerCallRef?, event: EventRef?, _: UnsafeMutableRawPointer?) -> OSStatus in
var modifiers = UInt32(0)
GetEventParameter(event, EventParamName(kEventParamKeyModifiers), EventParamType(typeUInt32), nil, MemoryLayout<UInt32>.size, nil, &modifiers)
handleEvent(nil, nil, nil, modifiers, false)
return noErr
}, eventTypes.count, &eventTypes, nil, &hotModifierEventHandler)
}
if shortcut.keyCode != .none && hotKeyPressedEventHandler == nil {
var eventTypes = [EventTypeSpec(eventClass: OSType(kEventClassKeyboard), eventKind: OSType(kEventHotKeyPressed))]
InstallEventHandler(shortcutEventTarget, { (_: EventHandlerCallRef?, event: EventRef?, _: UnsafeMutableRawPointer?) -> OSStatus in
@@ -114,9 +124,6 @@ class KeyboardEvents {
hotKeyPressedEventHandler = nil
RemoveEventHandler(hotKeyReleasedEventHandler_)
hotKeyReleasedEventHandler = nil
} else if let hotModifierEventHandler_ = hotModifierEventHandler, (globalShortcuts.allSatisfy { $0.shortcut.keyCode != .none }) {
RemoveEventHandler(hotModifierEventHandler_)
hotModifierEventHandler = nil
}
}
}
@@ -132,3 +139,15 @@ fileprivate func handleEvent(_ id: EventHotKeyID?, _ shortcutState: ShortcutStat
}
return someShortcutTriggered
}
fileprivate func cgEventFlagsChangedHandler(proxy: CGEventTapProxy, type: CGEventType, cgEvent: CGEvent, userInfo: UnsafeMutableRawPointer?) -> Unmanaged<CGEvent>? {
if type == .flagsChanged {
let modifiers = cocoaToCarbonFlags(NSEvent.ModifierFlags(rawValue: UInt(cgEvent.flags.rawValue)))
if handleEvent(nil, nil, nil, modifiers, false) {
return nil // focused app won't receive the event
}
} else if (type == .tapDisabledByUserInput || type == .tapDisabledByTimeout) {
CGEvent.tapEnable(tap: eventTap!, enable: true)
}
return Unmanaged.passUnretained(cgEvent) // focused app will receive the event
}
+1 -1
View File
@@ -60,7 +60,7 @@ class App: AppCenterApplication, NSApplicationDelegate {
Applications.initialDiscovery()
self.preferencesWindow = PreferencesWindow()
self.feedbackWindow = FeedbackWindow()
KeyboardEvents.addLocalEventHandler()
KeyboardEvents.addEventHandlers()
MouseEvents.observe()
// TODO: undeterministic; events in the queue may still be processing; good enough for now
DispatchQueue.main.async { () -> () in Windows.sortByLevel() }
+2
View File
@@ -15,6 +15,8 @@ class ThumbnailsPanel: NSPanel {
contentView!.addSubview(thumbnailsView)
preservesContentDuringLiveResize = false
disableSnapshotRestoration()
// triggering AltTab before or during Space transition animation brings the window on the Space post-transition
collectionBehavior = .canJoinAllSpaces
// 2nd highest level possible; this allows the app to go on top of context menus
// highest level is .screenSaver but makes drag and drop on top the main window impossible
level = .popUpMenu