Catching Media Key Events

There was a great question on Stack Overflow today about how to catch media key events (such as play/pause or seek forward/backward) in your own app. I thought I’d post the solution I use in Transcriva.

My approach (which may not be the only or best approach) was to subclass NSApplication and catch calls to -sendEvent: (through which keyboard events, among other kinds, are sent). If the event is a media key press, I translate it to the appropriate action call to my app delegate.

The complete (relevant) code listing:

import
 (void)sendEvent:(NSEvent *)event
 {
 // Catch media key events
 if ([event type] == NSSystemDefined && [event subtype] == 8)
 {
 int keyCode = (([event data1] & 0xFFFF0000) >> 16);
 int keyFlags = ([event data1] & 0x0000FFFF);
 int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA;
 // Process the media key event and return
 [self mediaKeyEvent:keyCode state:keyState];
 return;
 }
 // Continue on to super
 [super sendEvent:event]; 
 }
 (void)mediaKeyEvent:(int)key state:(BOOL)state
 {
 switch (key)
 {
 // Play pressed
 case NX_KEYTYPE_PLAY:
 if (state == NO)
 [(TSAppController *)[self delegate] togglePlayPause:self];
 break;
 // Rewind
 case NX_KEYTYPE_FAST:
 if (state == YES)
 [(TSAppController *)[self delegate] seekForward:self];
 break;
 // Previous
 case NX_KEYTYPE_REWIND:
 if (state == YES)
 [(TSAppController *)[self delegate] seekBack:self];
 break;
 } 
 }
Setting Your App’s Principal Class

Just remember to set your app’s principal class to your new NSApplication subclass (see below) and implement the -togglePlayPause:, -seekForward:, and -seekBack: actions in your app delegate (and make sure you have an app delegate).