Digging into Apple's hot-key mechanism

Go global

New hybrid storage solutions

Mac Secrets Before Christmas, I explained how to use an undocumented class within PreferencePanes.framework to easily convert key codes and modifiers into human readable string representations.

This time, I make good on my promise to describe the global hot-key mechanism used by Apple software such as Universal Access, Expose, and Dashboard.

For Cocoa developers, a number of different open source hot-key implementations can be found on the internet, one of the most popular being a set of classes developed by (I think!) Quentin Carnicelli. Type "KeyCombo.m" into Google, and you'll soon find an example.

I was never really happy with this stuff, partly because you end up adding several extra classes and source files to your application. It seemed unnecessarily complex to me. In the end, I wrote my own implementation by sub-classing NSApplication and adding just a few methods to that.

However, what had always intrigued me was the built-in hot-key mechanism used by Universal Access, Expose, and so on. Two months ago, I hadn't figured out enough of the details to make this useful, but now things are a lot clearer. The real hot-key mechanism appears to be implemented at a very low-level, probably inside the window server process. Code inside CoreGraphics.framework implements a symbolic hot-key API, which communicates directly with the windows server through Mach IPC calls.

Why "symbolic"? As I mentioned last time, Apple's global hot keys assign a unique, system-wide number to each hot key. Thus, the number eight identifies the hot key that moves focus to the Dock (normally Control-F3). The user might change the actual key-code and modifiers used for the hot-key, but it will always be identified as symbolic hot key eight within the operating system.

Suppose we want to use hot-key number 144, which in Tiger and Leopard isn't currently assigned or enabled. First of all, we'll want to enable the hot key as below: This tells the windows server that the hot key is in use.

CGSSetSymbolicHotKeyEnabled (144, YES);

Next, tell the window server to send notifications for this hot key to our application:

CGSSetSymbolicHotKey (CGSMainConnectionID(), 999, 144);

You may already be familiar with CGSMainConnectionID. If not, suffice to say that it returns a connection ID used to communicate between your application and the window server. This is needed for the call. The second parameter provides an internal, application-specific identifier by which the hot key should be known. We'll see how this works in just a moment.

By default, symbolic hot key 144 corresponds to Control-Option-1 ("1" on the number keypad). Once you've executed the above two statements, the Windows server will start sending events to your app anytime this key combination is pressed. These events can be easily intercepted by sub-classing NSApplication and overriding the sendEvent method as shown below:

- (void) sendEvent: (NSEvent *) event
        if ([event type] == NSSystemDefined && 
      [event subtype] == 6 && 
      [event data1] == 999) 
                NSLog (@"Voila!!!");
        [super sendEvent: event];

There are a couple of things to note here. First, the hot-key events are received as NSSystemDefined events, not as regular key-up or key-down events. Second, notice the use of the event's subtype field in the above code: A value of six indicates that the hot key has been pressed, whereas nine would indicate that it's been released.

You'll also see that we check the value of the data1 field. This should correspond to the arbitrary value (999) that we used earlier in the call to CGSSetSymbolicHotKey. Because sendEvent: never gets to "see" the symbolic hot-key number (144 in this case), we can use the data1 field to easily identify, which hot key has been pressed. This is obviously essential for an application that uses more than one.

Since this value is completely arbitrary, you could get sneaky and store something like an NSInvocation instance into the data1 field. That way, the hot key processing code inside sendEvent: could be pretty much self contained and could invoke your target method without needing to know about any other classes in your app.

Symbolic keys in OS X

Proceed with caution: undocumented calls can change all these

Cool though this stuff is, it wouldn't be a great deal of use if you couldn't actually change the key code and modifier mask of the hot key or keys you're using. This can be done through a couple of calls as shown below:


For the full function prototypes, consult the SymbolicKeys.h file included with this month's project, below. These routines allow you to interrogate the current key combination and change it to something as specified by the user of your application. Note that when calling CGSSetSymbolicHotKeyValue, you should generally use 0xffff for the event flags parameter.

But what about persistence, I hear you say. The Core Graphics routines described above only affect OS X's current state. To persistently change a symbolic hot-key, you'll need to modify the dictionary in the "com.apple.symbolichotkeys" domain. A small program showing how to access this dictionary was included in the earlier article.

For full source code and demo project click here. ®

Security for virtualized datacentres

More from The Register

next story
Not appy with your Chromebook? Well now it can run Android apps
Google offers beta of tricky OS-inside-OS tech
Greater dev access to iOS 8 will put us AT RISK from HACKERS
Knocking holes in Apple's walled garden could backfire, says securo-chap
NHS grows a NoSQL backbone and rips out its Oracle Spine
Open source? In the government? Ha ha! What, wait ...?
Google extends app refund window to two hours
You now have 120 minutes to finish that game instead of 15
Intel: Hey, enterprises, drop everything and DO HADOOP
Big Data analytics projected to run on more servers than any other app
prev story


Providing a secure and efficient Helpdesk
A single remote control platform for user support is be key to providing an efficient helpdesk. Retain full control over the way in which screen and keystroke data is transmitted.
Top 5 reasons to deploy VMware with Tegile
Data demand and the rise of virtualization is challenging IT teams to deliver storage performance, scalability and capacity that can keep up, while maximizing efficiency.
Reg Reader Research: SaaS based Email and Office Productivity Tools
Read this Reg reader report which provides advice and guidance for SMBs towards the use of SaaS based email and Office productivity tools.
Security for virtualized datacentres
Legacy security solutions are inefficient due to the architectural differences between physical and virtual environments.
Secure remote control for conventional and virtual desktops
Balancing user privacy and privileged access, in accordance with compliance frameworks and legislation. Evaluating any potential remote control choice.