Mission Control Turbo: macOS multitasking turbocharged
at main 86 lines 2.8 kB view raw
1import Carbon 2import AppKit 3 4/// Manages global hotkey registration using Carbon RegisterEventHotKey. 5final class HotKeyManager { 6 typealias Handler = () -> Void 7 8 private var hotKeyRef: EventHotKeyRef? 9 private var eventHandler: EventHandlerRef? 10 private let handler: Handler 11 12 /// The signature used to identify our hotkey events. 13 private static let hotKeySignature: FourCharCode = { 14 let chars: [UInt8] = [0x4D, 0x43, 0x54, 0x48] // "MCTH" 15 return FourCharCode(chars[0]) << 24 | FourCharCode(chars[1]) << 16 | FourCharCode(chars[2]) << 8 | FourCharCode(chars[3]) 16 }() 17 18 private static let hotKeyID = EventHotKeyID(signature: hotKeySignature, id: 1) 19 20 init(handler: @escaping Handler) { 21 self.handler = handler 22 } 23 24 deinit { 25 unregister() 26 } 27 28 /// Register the global hotkey. Default: Ctrl+Up Arrow. 29 func register(keyCode: UInt32 = UInt32(kVK_UpArrow), modifiers: UInt32 = UInt32(controlKey)) { 30 unregister() 31 32 // Install Carbon event handler 33 var eventType = EventTypeSpec(eventClass: OSType(kEventClassKeyboard), eventKind: UInt32(kEventHotKeyPressed)) 34 let selfPtr = Unmanaged.passUnretained(self).toOpaque() 35 36 InstallEventHandler( 37 GetApplicationEventTarget(), 38 { (_, event, userData) -> OSStatus in 39 guard let userData = userData else { return OSStatus(eventNotHandledErr) } 40 let manager = Unmanaged<HotKeyManager>.fromOpaque(userData).takeUnretainedValue() 41 var hotKeyID = EventHotKeyID() 42 GetEventParameter( 43 event, 44 EventParamName(kEventParamDirectObject), 45 EventParamType(typeEventHotKeyID), 46 nil, 47 MemoryLayout<EventHotKeyID>.size, 48 nil, 49 &hotKeyID 50 ) 51 if hotKeyID.signature == HotKeyManager.hotKeySignature { 52 DispatchQueue.main.async { 53 manager.handler() 54 } 55 } 56 return noErr 57 }, 58 1, 59 &eventType, 60 selfPtr, 61 &eventHandler 62 ) 63 64 // Register the hotkey 65 let hotKeyIDVar = Self.hotKeyID 66 RegisterEventHotKey( 67 keyCode, 68 modifiers, 69 hotKeyIDVar, 70 GetApplicationEventTarget(), 71 0, 72 &hotKeyRef 73 ) 74 } 75 76 func unregister() { 77 if let ref = hotKeyRef { 78 UnregisterEventHotKey(ref) 79 hotKeyRef = nil 80 } 81 if let handler = eventHandler { 82 RemoveEventHandler(handler) 83 eventHandler = nil 84 } 85 } 86}