diff --git a/Sources/KeyboardShortcuts/CarbonKeyboardShortcuts.swift b/Sources/KeyboardShortcuts/CarbonKeyboardShortcuts.swift index 3d8dc4b8..62373e7f 100644 --- a/Sources/KeyboardShortcuts/CarbonKeyboardShortcuts.swift +++ b/Sources/KeyboardShortcuts/CarbonKeyboardShortcuts.swift @@ -1,3 +1,4 @@ +#if os(macOS) import Carbon.HIToolbox private func carbonKeyboardShortcutsEventHandler(eventHandlerCall: EventHandlerCallRef?, event: EventRef?, userData: UnsafeMutableRawPointer?) -> OSStatus { @@ -345,3 +346,4 @@ extension CarbonKeyboardShortcuts { } } } +#endif \ No newline at end of file diff --git a/Sources/KeyboardShortcuts/Key.swift b/Sources/KeyboardShortcuts/Key.swift index d4666836..faa4ce4c 100644 --- a/Sources/KeyboardShortcuts/Key.swift +++ b/Sources/KeyboardShortcuts/Key.swift @@ -1,3 +1,4 @@ +#if os(macOS) import Carbon.HIToolbox extension KeyboardShortcuts { @@ -192,3 +193,4 @@ extension KeyboardShortcuts.Key { */ var isFunctionKey: Bool { Self.functionKeys.contains(self) } } +#endif \ No newline at end of file diff --git a/Sources/KeyboardShortcuts/KeyboardShortcuts.swift b/Sources/KeyboardShortcuts/KeyboardShortcuts.swift index ae07baed..0bcad958 100644 --- a/Sources/KeyboardShortcuts/KeyboardShortcuts.swift +++ b/Sources/KeyboardShortcuts/KeyboardShortcuts.swift @@ -1,3 +1,4 @@ +#if os(macOS) import AppKit.NSMenu /** @@ -589,3 +590,4 @@ extension KeyboardShortcuts { extension Notification.Name { static let shortcutByNameDidChange = Self("KeyboardShortcuts_shortcutByNameDidChange") } +#endif \ No newline at end of file diff --git a/Sources/KeyboardShortcuts/NSMenuItem++.swift b/Sources/KeyboardShortcuts/NSMenuItem++.swift index 1dd646ba..c10c9f10 100644 --- a/Sources/KeyboardShortcuts/NSMenuItem++.swift +++ b/Sources/KeyboardShortcuts/NSMenuItem++.swift @@ -1,109 +1,111 @@ -import AppKit +#if os(macOS) + import AppKit -extension NSMenuItem { - private enum AssociatedKeys { - static let observer = ObjectAssociation() - } - - private func clearShortcut() { - keyEquivalent = "" - keyEquivalentModifierMask = [] - - if #available(macOS 12, *) { - allowsAutomaticKeyEquivalentLocalization = true + extension NSMenuItem { + private enum AssociatedKeys { + static let observer = ObjectAssociation() } - } - // TODO: Make this a getter/setter. We must first add the ability to create a `Shortcut` from a `keyEquivalent`. - /** - Show a recorded keyboard shortcut in a `NSMenuItem`. + private func clearShortcut() { + keyEquivalent = "" + keyEquivalentModifierMask = [] - The menu item will automatically be kept up to date with changes to the keyboard shortcut. - - Pass in `nil` to clear the keyboard shortcut. + if #available(macOS 12, *) { + allowsAutomaticKeyEquivalentLocalization = true + } + } - This method overrides `.keyEquivalent` and `.keyEquivalentModifierMask`. + // TODO: Make this a getter/setter. We must first add the ability to create a `Shortcut` from a `keyEquivalent`. + /** + Show a recorded keyboard shortcut in a `NSMenuItem`. - ```swift - import Cocoa - import KeyboardShortcuts + The menu item will automatically be kept up to date with changes to the keyboard shortcut. - extension KeyboardShortcuts.Name { - static let toggleUnicornMode = Self("toggleUnicornMode") - } + Pass in `nil` to clear the keyboard shortcut. - // … `Recorder` logic for recording the keyboard shortcut … + This method overrides `.keyEquivalent` and `.keyEquivalentModifierMask`. - let menuItem = NSMenuItem() - menuItem.title = "Toggle Unicorn Mode" - menuItem.setShortcut(for: .toggleUnicornMode) - ``` + ```swift + import Cocoa + import KeyboardShortcuts - You can test this method in the example project. Run it, record a shortcut and then look at the “Test” menu in the app's main menu. + extension KeyboardShortcuts.Name { + static let toggleUnicornMode = Self("toggleUnicornMode") + } - - Important: You will have to disable the global keyboard shortcut while the menu is open, as otherwise, the keyboard events will be buffered up and triggered when the menu closes. This is because `NSMenu` puts the thread in tracking-mode, which prevents the keyboard events from being received. You can listen to whether a menu is open by implementing `NSMenuDelegate#menuWillOpen` and `NSMenuDelegate#menuDidClose`. You then use `KeyboardShortcuts.disable` and `KeyboardShortcuts.enable`. - */ - public func setShortcut(for name: KeyboardShortcuts.Name?) { - guard let name else { - clearShortcut() - AssociatedKeys.observer[self] = nil - return - } + // … `Recorder` logic for recording the keyboard shortcut … - func set() { - let shortcut = KeyboardShortcuts.Shortcut(name: name) - setShortcut(shortcut) - } + let menuItem = NSMenuItem() + menuItem.title = "Toggle Unicorn Mode" + menuItem.setShortcut(for: .toggleUnicornMode) + ``` - set() + You can test this method in the example project. Run it, record a shortcut and then look at the “Test” menu in the app's main menu. - // TODO: Use AsyncStream when targeting macOS 10.15. - AssociatedKeys.observer[self] = NotificationCenter.default.addObserver(forName: .shortcutByNameDidChange, object: nil, queue: nil) { notification in - guard - let nameInNotification = notification.userInfo?["name"] as? KeyboardShortcuts.Name, - nameInNotification == name - else { + - Important: You will have to disable the global keyboard shortcut while the menu is open, as otherwise, the keyboard events will be buffered up and triggered when the menu closes. This is because `NSMenu` puts the thread in tracking-mode, which prevents the keyboard events from being received. You can listen to whether a menu is open by implementing `NSMenuDelegate#menuWillOpen` and `NSMenuDelegate#menuDidClose`. You then use `KeyboardShortcuts.disable` and `KeyboardShortcuts.enable`. + */ + public func setShortcut(for name: KeyboardShortcuts.Name?) { + guard let name else { + clearShortcut() + AssociatedKeys.observer[self] = nil return } + func set() { + let shortcut = KeyboardShortcuts.Shortcut(name: name) + setShortcut(shortcut) + } + set() + + // TODO: Use AsyncStream when targeting macOS 10.15. + AssociatedKeys.observer[self] = NotificationCenter.default.addObserver(forName: .shortcutByNameDidChange, object: nil, queue: nil) { notification in + guard + let nameInNotification = notification.userInfo?["name"] as? KeyboardShortcuts.Name, + nameInNotification == name + else { + return + } + + set() + } } - } - /** - Add a keyboard shortcut to a `NSMenuItem`. + /** + Add a keyboard shortcut to a `NSMenuItem`. - This method is only recommended for dynamic shortcuts. In general, it's preferred to create a static shortcut name and use `NSMenuItem.setShortcut(for:)` instead. + This method is only recommended for dynamic shortcuts. In general, it's preferred to create a static shortcut name and use `NSMenuItem.setShortcut(for:)` instead. - Pass in `nil` to clear the keyboard shortcut. + Pass in `nil` to clear the keyboard shortcut. - This method overrides `.keyEquivalent` and `.keyEquivalentModifierMask`. + This method overrides `.keyEquivalent` and `.keyEquivalentModifierMask`. - - Important: You will have to disable the global keyboard shortcut while the menu is open, as otherwise, the keyboard events will be buffered up and triggered when the menu closes. This is because `NSMenu` puts the thread in tracking-mode, which prevents the keyboard events from being received. You can listen to whether a menu is open by implementing `NSMenuDelegate#menuWillOpen` and `NSMenuDelegate#menuDidClose`. You then use `KeyboardShortcuts.disable` and `KeyboardShortcuts.enable`. - */ - @_disfavoredOverload - public func setShortcut(_ shortcut: KeyboardShortcuts.Shortcut?) { - func set() { - guard let shortcut else { - clearShortcut() - return - } + - Important: You will have to disable the global keyboard shortcut while the menu is open, as otherwise, the keyboard events will be buffered up and triggered when the menu closes. This is because `NSMenu` puts the thread in tracking-mode, which prevents the keyboard events from being received. You can listen to whether a menu is open by implementing `NSMenuDelegate#menuWillOpen` and `NSMenuDelegate#menuDidClose`. You then use `KeyboardShortcuts.disable` and `KeyboardShortcuts.enable`. + */ + @_disfavoredOverload + public func setShortcut(_ shortcut: KeyboardShortcuts.Shortcut?) { + func set() { + guard let shortcut else { + clearShortcut() + return + } - keyEquivalent = shortcut.keyEquivalent - keyEquivalentModifierMask = shortcut.modifiers + keyEquivalent = shortcut.keyEquivalent + keyEquivalentModifierMask = shortcut.modifiers - if #available(macOS 12, *) { - allowsAutomaticKeyEquivalentLocalization = false + if #available(macOS 12, *) { + allowsAutomaticKeyEquivalentLocalization = false + } } - } - // `TISCopyCurrentASCIICapableKeyboardLayoutInputSource` works on a background thread, but crashes when used in a `NSBackgroundActivityScheduler` task, so we ensure it's not run in that queue. - if DispatchQueue.isCurrentQueueNSBackgroundActivitySchedulerQueue { - DispatchQueue.main.async { + // `TISCopyCurrentASCIICapableKeyboardLayoutInputSource` works on a background thread, but crashes when used in a `NSBackgroundActivityScheduler` task, so we ensure it's not run in that queue. + if DispatchQueue.isCurrentQueueNSBackgroundActivitySchedulerQueue { + DispatchQueue.main.async { + set() + } + } else { set() } - } else { - set() } } -} +#endif diff --git a/Sources/KeyboardShortcuts/Name.swift b/Sources/KeyboardShortcuts/Name.swift index a36fd971..49633f9f 100644 --- a/Sources/KeyboardShortcuts/Name.swift +++ b/Sources/KeyboardShortcuts/Name.swift @@ -1,3 +1,4 @@ +#if os(macOS) extension KeyboardShortcuts { /** The strongly-typed name of the keyboard shortcut. @@ -56,3 +57,4 @@ extension KeyboardShortcuts.Name: RawRepresentable { self.init(rawValue) } } +#endif \ No newline at end of file diff --git a/Sources/KeyboardShortcuts/Recorder.swift b/Sources/KeyboardShortcuts/Recorder.swift index 6650a209..f5f18060 100644 --- a/Sources/KeyboardShortcuts/Recorder.swift +++ b/Sources/KeyboardShortcuts/Recorder.swift @@ -1,3 +1,4 @@ +#if os(macOS) import SwiftUI @available(macOS 10.15, *) @@ -161,3 +162,4 @@ struct SwiftUI_Previews: PreviewProvider { } } } +#endif \ No newline at end of file diff --git a/Sources/KeyboardShortcuts/RecorderCocoa.swift b/Sources/KeyboardShortcuts/RecorderCocoa.swift index 8dd3c404..9802b8fe 100644 --- a/Sources/KeyboardShortcuts/RecorderCocoa.swift +++ b/Sources/KeyboardShortcuts/RecorderCocoa.swift @@ -1,3 +1,4 @@ +#if os(macOS) import Cocoa import Carbon.HIToolbox @@ -282,3 +283,4 @@ extension KeyboardShortcuts { } } } +#endif \ No newline at end of file diff --git a/Sources/KeyboardShortcuts/Shortcut.swift b/Sources/KeyboardShortcuts/Shortcut.swift index c048a630..64fd23ed 100644 --- a/Sources/KeyboardShortcuts/Shortcut.swift +++ b/Sources/KeyboardShortcuts/Shortcut.swift @@ -1,3 +1,4 @@ +#if os(macOS) import Cocoa import Carbon.HIToolbox @@ -323,3 +324,4 @@ extension KeyboardShortcuts.Shortcut: CustomStringConvertible { modifiers.description + (keyToCharacter()?.uppercased() ?? "�") } } +#endif \ No newline at end of file diff --git a/Sources/KeyboardShortcuts/Utilities.swift b/Sources/KeyboardShortcuts/Utilities.swift index 5ac686e1..936b2075 100644 --- a/Sources/KeyboardShortcuts/Utilities.swift +++ b/Sources/KeyboardShortcuts/Utilities.swift @@ -1,3 +1,4 @@ +#if os(macOS) import Carbon.HIToolbox import SwiftUI @@ -463,3 +464,4 @@ extension View { .alignmentGuide(.leading) { $0[.controlAlignment] } } } +#endif \ No newline at end of file diff --git a/Sources/KeyboardShortcuts/ViewModifiers.swift b/Sources/KeyboardShortcuts/ViewModifiers.swift index b4017713..0e352620 100644 --- a/Sources/KeyboardShortcuts/ViewModifiers.swift +++ b/Sources/KeyboardShortcuts/ViewModifiers.swift @@ -1,3 +1,4 @@ +#if os(macOS) import SwiftUI @available(macOS 12, *) @@ -38,3 +39,4 @@ extension View { } } } +#endif \ No newline at end of file