Initial commit: Snipping Tool menu bar screenshot app
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import Carbon.HIToolbox
|
||||
import Foundation
|
||||
|
||||
/// Thin wrapper around the Carbon RegisterEventHotKey API to register
|
||||
/// system-wide keyboard shortcuts without requiring Accessibility/Input
|
||||
/// Monitoring permission.
|
||||
final class HotKeyManager {
|
||||
static let shared = HotKeyManager()
|
||||
|
||||
private var hotKeyRefs: [UInt32: EventHotKeyRef] = [:]
|
||||
private var handlers: [UInt32: () -> Void] = [:]
|
||||
private var eventHandlerRef: EventHandlerRef?
|
||||
|
||||
private static let signature: FourCharCode = {
|
||||
var result: FourCharCode = 0
|
||||
for byte in "SNAP".utf8 {
|
||||
result = (result << 8) + FourCharCode(byte)
|
||||
}
|
||||
return result
|
||||
}()
|
||||
|
||||
private init() {
|
||||
installEventHandler()
|
||||
}
|
||||
|
||||
private func installEventHandler() {
|
||||
var eventType = EventTypeSpec(
|
||||
eventClass: OSType(kEventClassKeyboard),
|
||||
eventKind: UInt32(kEventHotKeyPressed)
|
||||
)
|
||||
|
||||
let callback: EventHandlerUPP = { _, event, userData in
|
||||
guard let event, let userData else { return noErr }
|
||||
var hotKeyID = EventHotKeyID()
|
||||
GetEventParameter(
|
||||
event,
|
||||
EventParamName(kEventParamDirectObject),
|
||||
EventParamType(typeEventHotKeyID),
|
||||
nil,
|
||||
MemoryLayout<EventHotKeyID>.size,
|
||||
nil,
|
||||
&hotKeyID
|
||||
)
|
||||
let manager = Unmanaged<HotKeyManager>.fromOpaque(userData).takeUnretainedValue()
|
||||
manager.handlers[hotKeyID.id]?()
|
||||
return noErr
|
||||
}
|
||||
|
||||
InstallEventHandler(
|
||||
GetEventDispatcherTarget(),
|
||||
callback,
|
||||
1,
|
||||
&eventType,
|
||||
Unmanaged.passUnretained(self).toOpaque(),
|
||||
&eventHandlerRef
|
||||
)
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func register(id: UInt32, keyCode: UInt32, modifiers: UInt32, handler: @escaping () -> Void) -> Bool {
|
||||
unregister(id: id)
|
||||
|
||||
var hotKeyRef: EventHotKeyRef?
|
||||
let hotKeyID = EventHotKeyID(signature: Self.signature, id: id)
|
||||
let status = RegisterEventHotKey(
|
||||
keyCode,
|
||||
modifiers,
|
||||
hotKeyID,
|
||||
GetEventDispatcherTarget(),
|
||||
0,
|
||||
&hotKeyRef
|
||||
)
|
||||
|
||||
guard status == noErr, let hotKeyRef else { return false }
|
||||
hotKeyRefs[id] = hotKeyRef
|
||||
handlers[id] = handler
|
||||
return true
|
||||
}
|
||||
|
||||
func unregister(id: UInt32) {
|
||||
if let ref = hotKeyRefs.removeValue(forKey: id) {
|
||||
UnregisterEventHotKey(ref)
|
||||
}
|
||||
handlers.removeValue(forKey: id)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user