Under The Microscope

Archive for September 29th, 2007

Apple Keyboard Media Key Event Handling

The new Apple keyboards now have “media keys” for Previous, Next and Play/Pause. As of yet there doesn’t appear to be any public API for developers to use these keys in your own application. But this post to the CocoaDev mailing list from Peter Maurer reveals a way.

Firing up Xcode, we start by subclassing NSApplication and listening in on -sendEvent. We can see applications are actually passed events for these new keys. The event has a type of NSSystemDefined, and a subtype of 8.

Here is a code snippet showing how to trap them:

- (void)sendEvent: (NSEvent*)event
{
	if( [event type] == NSSystemDefined && [event subtype] == 8 )
	{
		int keyCode = (([event data1] & 0xFFFF0000) >> 16);
		int keyFlags = ([event data1] & 0x0000FFFF);
		int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA;
		int keyRepeat = (keyFlags & 0x1);
		
		[self mediaKeyEvent: keyCode state: keyState repeat: keyRepeat];
	}

	[super sendEvent: event];
}

I’m not completely sure on the “keyState” code, it appears the value alternates between 0xA and 0xB depending on if the key is up or down. There may be other values I don’t know about though.

Moving on, once we got the event, the code for handling would be something like as follows:

- (void)mediaKeyEvent: (int)key state: (BOOL)state repeat: (BOOL)repeat
{
	switch( key )
	{
		case NX_KEYTYPE_PLAY:
			if( state == 0 )
				; //Play pressed and released
		break;
		
		case NX_KEYTYPE_FAST:
			if( state == 0 )
				; //Next pressed and released
		break;
		
		case NX_KEYTYPE_REWIND:
			if( state == 0 )
				; //Previous pressed and released
		break;
	}
}

The key codes constants come from the header IOKit/hidsystem/ev_keymap.h. One other thing to note is that these keys act as “global hot keys”, every application receives events for them, not merely just the foreground application. This whole public domain sample code is available in a file here.

And while we are on the topic of coding: Don’t use strnstr.