diff options
Diffstat (limited to 'Sources')
| -rw-r--r-- | Sources/DDHotKey/DDHotKey.swift | 6 | ||||
| -rw-r--r-- | Sources/DDHotKey/DDHotKeyCenter.swift | 8 | ||||
| -rw-r--r-- | Sources/DDHotKey/DDHotKeyTextField.swift | 124 |
3 files changed, 131 insertions, 7 deletions
diff --git a/Sources/DDHotKey/DDHotKey.swift b/Sources/DDHotKey/DDHotKey.swift index 0f3c93e..e8523bf 100644 --- a/Sources/DDHotKey/DDHotKey.swift +++ b/Sources/DDHotKey/DDHotKey.swift @@ -15,9 +15,9 @@ public class DDHotKey { internal let uuid = UUID() internal let keyCode: CGKeyCode internal let modifiers: NSEvent.ModifierFlags - internal let handler: (NSEvent) -> Void + public var handler: ((NSEvent) -> Void)? - public init(keyCode: CGKeyCode, modifiers: NSEvent.ModifierFlags, handler: @escaping (NSEvent) -> Void) { + public init(keyCode: CGKeyCode, modifiers: NSEvent.ModifierFlags, handler: ((NSEvent) -> Void)? = nil) { self.keyCode = keyCode self.modifiers = modifiers self.handler = handler @@ -32,7 +32,7 @@ public class DDHotKey { } internal func invoke(with event: NSEvent) { - handler(event) + handler?(event) } } diff --git a/Sources/DDHotKey/DDHotKeyCenter.swift b/Sources/DDHotKey/DDHotKeyCenter.swift index 84a456d..9625890 100644 --- a/Sources/DDHotKey/DDHotKeyCenter.swift +++ b/Sources/DDHotKey/DDHotKeyCenter.swift @@ -14,13 +14,13 @@ public class DDHotKeyCenter { case alreadyRegistered case tooManyHotKeys case conflictsWithExistingHotKey(DDHotKey) - case unableToRegisterHotKey(OSStatus) + case cannotRegisterHotKey(OSStatus) } public enum UnregistrationError: Error { case notRegistered case unknownHotKey - case unableToUnregisterHotKey(OSStatus) + case cannotUnregisterHotKey(OSStatus) } public static let shared = DDHotKeyCenter() @@ -72,7 +72,7 @@ public class DDHotKeyCenter { let error = RegisterEventHotKey(UInt32(hotKey.keyCode), flags, hotKeyID, GetEventDispatcherTarget(), 0, &hotKeyRef) if error != noErr { - throw RegistrationError.unableToRegisterHotKey(error) + throw RegistrationError.cannotRegisterHotKey(error) } hotKey.hotKeyRef = hotKeyRef @@ -94,7 +94,7 @@ public class DDHotKeyCenter { let status = UnregisterEventHotKey(ref) guard status == noErr else { - throw UnregistrationError.unableToUnregisterHotKey(status) + throw UnregistrationError.cannotUnregisterHotKey(status) } registered.removeValue(forKey: hotKey.uuid) diff --git a/Sources/DDHotKey/DDHotKeyTextField.swift b/Sources/DDHotKey/DDHotKeyTextField.swift new file mode 100644 index 0000000..8c71408 --- /dev/null +++ b/Sources/DDHotKey/DDHotKeyTextField.swift @@ -0,0 +1,124 @@ +// +// DDHotKeyTextField.swift +// +// +// Created by Dave DeLong on 12/8/19. +// + +#if canImport(AppKit) + +import AppKit +import Carbon + +fileprivate let DDFieldEditor: DDHotKeyTextFieldEditor = { + let editor = DDHotKeyTextFieldEditor(frame: NSRect(x: 0, y: 0, width: 100, height: 32)) + editor.isFieldEditor = true + return editor +}() + +open class DDHotKeyTextField: NSTextField { + + open override class var cellClass: AnyClass? { + get { return DDHotKeyTextFieldCell.self } + set { super.cellClass = DDHotKeyTextFieldCell.self } + } + + public var hotKey: DDHotKey? { + didSet { + super.stringValue = "" + } + } + + open override var stringValue: String { + get { + print("DDHotKeyTextField.stringValue is not what you want. Use DDHotKeyTextField.hotKey instead.") + return super.stringValue + } + set { + print("DDHotKeyTextField.stringValue is not what you want. Use DDHotKeyTextField.hotKey instead.") + super.stringValue = newValue + } + } + +} + +private class DDHotKeyTextFieldCell: NSTextFieldCell { + + override func fieldEditor(for controlView: NSView) -> NSTextView? { + guard let hkField = controlView as? DDHotKeyTextField else { return nil } + + let editor = DDFieldEditor + editor.insertionPointColor = editor.backgroundColor + editor.hotKeyField = hkField + return editor + } + +} + +fileprivate class DDHotKeyTextFieldEditor: NSTextView { + private var hasSeenKeyDown: Bool = false + private var globalMonitor: Any? + private var originalHotKey: DDHotKey? + + weak var hotKeyField: DDHotKeyTextField? { + didSet { + originalHotKey = hotKeyField?.hotKey + } + } + + override func becomeFirstResponder() -> Bool { + guard super.becomeFirstResponder() else { return false } + + hasSeenKeyDown = false + globalMonitor = NSEvent.addLocalMonitorForEvents(matching: [.keyDown, .flagsChanged], handler: self.processHotKeyEvent(_:)) + + return true + } + + override func resignFirstResponder() -> Bool { + guard super.resignFirstResponder() else { return false } + hasSeenKeyDown = false + hotKeyField = nil + if let m = globalMonitor { + NSEvent.removeMonitor(m) + globalMonitor = nil + } + return true + } + + private func processHotKeyEvent(_ event: NSEvent) -> NSEvent? { + let flags = event.modifierFlags + let hasModifier = flags.contains(.command) || flags.contains(.option) || flags.contains(.control) || flags.contains(.shift) || flags.contains(.function) + + if event.type == .keyDown { + hasSeenKeyDown = true + let char = event.charactersIgnoringModifiers?.first + + if hasModifier == false && (char?.isNewline == true || event.keyCode == Int16(kVK_Escape)) { + if event.keyCode == Int16(kVK_Escape) { + hotKeyField?.hotKey = originalHotKey + + let str = stringFrom(keyCode: event.keyCode, modifiers: flags) + textStorage?.mutableString.setString(str.uppercased()) + } + + hotKeyField?.sendAction(hotKeyField?.action, to: hotKeyField?.target) + window?.makeFirstResponder(nil) + } + } + + if hasModifier && (event.type == .keyDown || (event.type == .flagsChanged && hasSeenKeyDown == false)) { + + hotKeyField?.hotKey = DDHotKey(keyCode: event.keyCode, modifiers: flags, handler: originalHotKey?.handler) + + let str = stringFrom(keyCode: event.keyCode, modifiers: flags) + textStorage?.mutableString.setString(str.uppercased()) + hotKeyField?.sendAction(hotKeyField?.action, to: hotKeyField?.target) + } + + return nil + } + +} + +#endif |
