How do you implement global keyboard hooks in Mac OS X?
Asked Answered
R

2

6

I know this can be done for Windows and that XGrabKey can be used for X11, but what about Mac OS X? I want create a class that allows setting shortcut keys that can be invoked even when the application windows are inactive.

Reynaldoreynard answered 24/5, 2010 at 5:17 Comment(0)
A
2

Take a look at addGlobalMonitorForEventsMatchingMask:handler: class methods of NSEvent. Also you may find Shortcut Recorder handy.

Addend answered 24/5, 2010 at 5:24 Comment(3)
This does not work for global events unless accessibility is enabled. RegisterEventHotKey and InstallEventHandler was the way to go as in below solution, as that works even when accessibility is not enabled. I hear accessibility enabling incurs a performance hit.Af
Then answer is almost 6 years old. So it probably doesn't work anymore.Addend
It works, but its just not global. It can be global if you have accessibility enabled though. I'm mentioning here for the info of other readers that stumble upon this. :)Af
A
4

This is not (yet?) supported in Cocoa. You can still use the old Carbon library for this (which is 64 bit compatible), but unfortunately Apple decided to remove all documentation on the subject.

There's a nice blog article here: http://dbachrach.com/blog/2005/11/program-global-hotkeys-in-cocoa-easily/

The article is a bit lengthy for my taste, so here is the short version:

- (id)init {
    self = [super init];
    if (self) {
        EventHotKeyRef  hotKeyRef;
        EventHotKeyID   hotKeyId;
        EventTypeSpec   eventType;

        eventType.eventClass    = kEventClassKeyboard;
        eventType.eventKind     = kEventHotKeyPressed;

        InstallApplicationEventHandler(&mbHotKeyHandler, 1, &eventType, NULL, NULL);

        hotKeyId.signature  = 'hotk';
        hotKeyId.id         = 1337;

        RegisterEventHotKey(kVK_ANSI_C, cmdKey + shiftKey, hotKeyCopyId, GetApplicationEventTarget(), 0, &hotKeyRef);
    }
}

OSStatus mbHotKeyHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData) {
    // Your hotkey was pressed!     
    return noErr;
}

The hotkey is registered with the RegisterEventHotKey(…) call. In this case it registers CMD + Shift + C.

The ANSI keys are defined in HIToolbox/Events.h, so you can look around there for other keys (just press CMD + Shift + O in XCode, and type Events.h to find it).

You have to do a bit more work if you want multiple hotkeys or if you want to call methods from your handler, but that's all in the link near the top of this answer.

I've been looking for a simple answer to this question, so I hope this helps someone else...

Ariannaarianne answered 17/4, 2013 at 14:2 Comment(2)
+1 thanks!. if you have a moment, i have asked a related question here https://mcmap.net/q/1329740/-how-to-get-other-application-to-paste-from-my-global-hotkey/830899Colly
I verify this is the correct way to register a global hotkey, I have just done it. I was not able to do it on a spawned thread though, I had to do it in the "mainthread". Is it possible to do this from a spawned thread?Af
A
2

Take a look at addGlobalMonitorForEventsMatchingMask:handler: class methods of NSEvent. Also you may find Shortcut Recorder handy.

Addend answered 24/5, 2010 at 5:24 Comment(3)
This does not work for global events unless accessibility is enabled. RegisterEventHotKey and InstallEventHandler was the way to go as in below solution, as that works even when accessibility is not enabled. I hear accessibility enabling incurs a performance hit.Af
Then answer is almost 6 years old. So it probably doesn't work anymore.Addend
It works, but its just not global. It can be global if you have accessibility enabled though. I'm mentioning here for the info of other readers that stumble upon this. :)Af

© 2022 - 2024 — McMap. All rights reserved.