import Carbon.HIToolbox import Foundation final class HotkeyManager { private var hotkey: EventHotKeyRef? private var handler: EventHandlerRef? private var action: (() -> Void)? init() { var type = EventTypeSpec( eventClass: OSType(kEventClassKeyboard), eventKind: UInt32(kEventHotKeyPressed) ) InstallEventHandler( GetApplicationEventTarget(), { _, event, context in guard let event, let context else { return noErr } var identifier = EventHotKeyID() let status = GetEventParameter( event, EventParamName(kEventParamDirectObject), EventParamType(typeEventHotKeyID), nil, MemoryLayout.size, nil, &identifier ) guard status == noErr, identifier.id == 1 else { return status } let manager = Unmanaged.fromOpaque(context).takeUnretainedValue() DispatchQueue.main.async { manager.action?() } return noErr }, 1, &type, Unmanaged.passUnretained(self).toOpaque(), &handler ) } deinit { unregister() if let handler { RemoveEventHandler(handler) } } @discardableResult func register(_ shortcut: HotkeyShortcut, action: @escaping () -> Void) -> Bool { let identifier = EventHotKeyID(signature: Self.signature, id: 1) var candidate: EventHotKeyRef? let status = RegisterEventHotKey( shortcut.keyCode, shortcut.modifiers, identifier, GetApplicationEventTarget(), 0, &candidate ) guard status == noErr, let candidate else { return false } unregister() hotkey = candidate self.action = action return true } private func unregister() { if let hotkey { UnregisterEventHotKey(hotkey) } hotkey = nil } private static let signature: OSType = 0x5452_5549 // TRUI }