Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

macOS App: handling key combinations bound to global keyboard shortcuts

In some apps, it makes sense for the app to directly handle keyboard shortcuts which are otherwise bound to system wide combinations. For example, ⌘-Space (normally Spotlight) or ⌘-Tab (normally app switcher). This works in various Mac apps, such as VMWare Fusion, Apple's own Screen Sharing and Remote Desktop clients (forwarding the events to the VM or server, respectively, instead of handling them locally), and also some similar third-party apps in the App Store.

We would like to implement such a mode in the app we're working on, but are having a hard time working out how to do it. I should point out that the app in question is a regular foreground app, is sandboxed, and any solution must comply with App Store rules. The fact that other apps on the store can do it implies that this must be possible.

To be clear, we want to:

  • Detect and handle all key presses, including those bound to global shortcuts.
  • Prevent global shortcuts from triggering their globally bound effect.

Apple's Event Architecture document suggests that the foreground application should already be receiving these events. (It only talks about earlier levels handling things such as the power and eject buttons, which is fine.) It goes on to suggest, and the key events document also implies that NSApplication's sendEvent: method is what detects potential shortcuts based on modifier flags, dispatching them to the windows and if that fails, on to the menu bar. It's not explicitly stated what happens to globally-bound shortcuts.

I tried subclassing NSApplication and overriding sendEvent:. No matter if I pass through all events to the superclass implementation, or if I say, filter modifier key events, when I press ⌘-Space, I receive the events for pressing and releasing the command (⌘) key, but not the spacebar. The Spotlight UI always pops up.

I haven't found much information on subclassing NSApplication and its early event handling, from Apple or otherwise. I can't seem to find out at what level global shortcuts are detected and handled.

Can someone please point me in the right direction?

Possible solutions which don't work:

Suggestions I've seen in other Stack Overflow posts but which don't apply to the other apps I've seen which do this (and which would break App Store rules):

  • Accessibilty APIs (needs special permission)
  • Event taps/hooks (needs to run as root)

Both of these would be overkill anyway, as they let you intercept all events at all times, not just while your app is the foreground app.

NSevent's addGlobalMonitorForEventsMatchingMask:handler: meanwhile doesn't prevent the global shortcut handler from firing for those events, so I didn't even bother trying it.

like image 477
pmdj Avatar asked Jun 10 '17 11:06

pmdj


People also ask

How do you program keyboard shortcuts on a Mac?

On your Mac, choose Apple menu > System Settings, click Keyboard in the sidebar (you may need to scroll down), then click Keyboard Shortcuts on the right. Select App Shortcuts on the left, click the Add button , click the Application pop-up menu, then choose a specific app or All Applications.

How do I create a global keyboard shortcut?

You can make a shortcut of it by right clicking on the file and selecting the “create shortcut” option. Then open the startup folder with the “Run” window by pressing Windows key+R (or typing Run in the start menu). When the Run window starts just type “shell:startup” and hit enter, like the example below.

How do I change hotkeys combination?

To reassign a keyConnect the keyboard that you want to configure. Select the Start button, and then select Microsoft Mouse and Keyboard Center. From the displayed list of key names, select the key that you want to reassign. In the command list of the key that you want to reassign, select a command.


1 Answers

I solved this ages ago but I only just noticed I never posted it here. The answer ended up involving CGSSetGlobalHotKeyOperatingMode(). This is not a public API, but there are a number of Mac App Store apps which use it by obfuscating the function name and looking it up dynamically. Apple doesn't seem to mind. The API is pretty straightforward to use, and there's plenty of open example source code floating about.

like image 131
pmdj Avatar answered Oct 10 '22 05:10

pmdj