Feeds

Digging into Apple's hot-key mechanism

Go global

The essential guide to IT transformation

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!!!");
                return;
        }
        
        [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:

CGSGetSymbolicHotKeyValue
CGSSetSymbolicHotKeyValue

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. ®

Secure remote control for conventional and virtual desktops

More from The Register

next story
Munich considers dumping Linux for ... GULP ... Windows!
Give a penguinista a hug, the Outlook's not good for open source's poster child
The Return of BSOD: Does ANYONE trust Microsoft patches?
Sysadmins, you're either fighting fires or seen as incompetents now
Intel's Raspberry Pi rival Galileo can now run Windows
Behold the Internet of Things. Wintel Things
Microsoft cries UNINSTALL in the wake of Blue Screens of Death™
Cache crash causes contained choloric calamity
Eat up Martha! Microsoft slings handwriting recog into OneNote on Android
Freehand input on non-Windows kit for the first time
Time to move away from Windows 7 ... whoa, whoa, who said anything about Windows 8?
Start migrating now to avoid another XPocalypse – Gartner
You'll find Yoda at the back of every IT conference
The piss always taking is he. Bastard the.
prev story

Whitepapers

Endpoint data privacy in the cloud is easier than you think
Innovations in encryption and storage resolve issues of data privacy and key requirements for companies to look for in a solution.
Implementing global e-invoicing with guaranteed legal certainty
Explaining the role local tax compliance plays in successful supply chain management and e-business and how leading global brands are addressing this.
Top 8 considerations to enable and simplify mobility
In this whitepaper learn how to successfully add mobile capabilities simply and cost effectively.
Solving today's distributed Big Data backup challenges
Enable IT efficiency and allow a firm to access and reuse corporate information for competitive advantage, ultimately changing business outcomes.
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.