Skip to content

Instantly share code, notes, and snippets.

@gvkhna
Created August 23, 2010 20:51
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gvkhna/546311 to your computer and use it in GitHub Desktop.
Save gvkhna/546311 to your computer and use it in GitHub Desktop.
Apple Media Key hotkey override
//
// AppleMediaKeyController.h
//
// Modified by Gaurav Khanna on 8/17/10.
// SOURCE: http://github.com/sweetfm/SweetFM/blob/master/Source/HMediaKeys.h
//
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify,
// merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#import "singleton.h"
#import <IOKit/hidsystem/ev_keymap.h>
extern NSString * const MediaKeyPlayPauseNotification;
extern NSString * const MediaKeyNextNotification;
extern NSString * const MediaKeyPreviousNotification;
@interface AppleMediaKeyController : NSObject {
CFMachPortRef _eventPort;
CFRunLoopSourceRef _runLoopSource;
}
@property(nonatomic, assign, readonly) CFMachPortRef eventPort;
+ (id)sharedController;
@end
//
// AppleMediaKeyController.m
//
// Modified by Gaurav Khanna on 8/17/10.
// SOURCE: http://github.com/sweetfm/SweetFM/blob/master/Source/HMediaKeys.m
// SOURCE: http://stackoverflow.com/questions/2969110/cgeventtapcreate-breaks-down-mysteriously-with-key-down-events
//
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify,
// merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#import "AppleMediaKeyController.h"
NSString * const MediaKeyPlayPauseNotification = @"MediaKeyPlayPauseNotification";
NSString * const MediaKeyNextNotification = @"MediaKeyNextNotification";
NSString * const MediaKeyPreviousNotification = @"MediaKeyPreviousNotification";
#define NX_KEYSTATE_UP 0x0A
#define NX_KEYSTATE_DOWN 0x0B
@implementation AppleMediaKeyController
@synthesize eventPort = _eventPort;
MAKE_SINGLETON(AppleMediaKeyController, sharedController)
CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
if(type == kCGEventTapDisabledByTimeout)
CGEventTapEnable([[AppleMediaKeyController sharedController] eventPort], TRUE);
if(type != NX_SYSDEFINED)
return event;
NSEvent *nsEvent = [NSEvent eventWithCGEvent:event];
if([nsEvent subtype] != 8)
return event;
int data = [nsEvent data1];
int keyCode = (data & 0xFFFF0000) >> 16;
int keyFlags = (data & 0xFFFF);
int keyState = (keyFlags & 0xFF00) >> 8;
BOOL keyIsRepeat = (keyFlags & 0x1) > 0;
if(keyIsRepeat)
return event;
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
switch (keyCode) {
case NX_KEYTYPE_PLAY:
if(keyState == NX_KEYSTATE_DOWN)
[center postNotificationName:MediaKeyPlayPauseNotification object:(AppleMediaKeyController *)refcon];
if(keyState == NX_KEYSTATE_UP || keyState == NX_KEYSTATE_DOWN)
return NULL;
break;
case NX_KEYTYPE_FAST:
if(keyState == NX_KEYSTATE_DOWN)
[center postNotificationName:MediaKeyNextNotification object:(AppleMediaKeyController *)refcon];
if(keyState == NX_KEYSTATE_UP || keyState == NX_KEYSTATE_DOWN)
return NULL;
break;
case NX_KEYTYPE_REWIND:
if(keyState == NX_KEYSTATE_DOWN)
[center postNotificationName:MediaKeyPreviousNotification object:(AppleMediaKeyController *)refcon];
if(keyState == NX_KEYSTATE_UP || keyState == NX_KEYSTATE_DOWN)
return NULL;
break;
}
return event;
}
- (id)init {
if(self = [super init]) {
CFRunLoopRef runLoop;
_eventPort = CGEventTapCreate(kCGSessionEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
CGEventMaskBit(NX_SYSDEFINED),
tapEventCallback,
self);
if(_eventPort == NULL) {
NSLog(@"Fatal Error: Event Tap could not be created");
return self;
}
_runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorSystemDefault, _eventPort, 0);
if(_runLoopSource == NULL) {
NSLog(@"Fatal Error: Run Loop Source could not be created");
return self;
}
runLoop = CFRunLoopGetCurrent();
if(runLoop == NULL) {
NSLog(@"Fatal Error: Couldn't get current threads Run Loop");
return self;
}
CFRunLoopAddSource(runLoop, _runLoopSource, kCFRunLoopCommonModes);
}
return self;
}
- (void)dealloc {
CFRelease(_eventPort);
CFRelease(_runLoopSource);
[super dealloc];
}
@end
@gvkhna
Copy link
Author

gvkhna commented Aug 23, 2010

Purpose

Proper way to implement Apple Media Key override/support for your app

You'll need singleton.h if you want to use it just like this, my macro for making a singleton for 10.6

@inacho
Copy link

inacho commented Apr 20, 2011

Could you post a basic example project or an explanation about how to implement this classes?
Thanks!

@gvkhna
Copy link
Author

gvkhna commented Apr 20, 2011

This is how I implemented it in my own class: http://awesomescreenshot.com/057bq34ab.
This is that file: PandoriumAppDelegate

@inacho
Copy link

inacho commented Apr 21, 2011

Thanks!
I think that in the file AppleMediaKeyController.m, the line:
#import "HotKeyController.h"
should be:
#import "AppleMediaKeyController.h"

@gvkhna
Copy link
Author

gvkhna commented Apr 21, 2011

Corrected, thanks!

@justin-pierce
Copy link

I can't find singleton.h -- the links with your example are also dead.

@Tyson-Skiba
Copy link

Tyson-Skiba commented Oct 14, 2017

singleton.h (non-ARC)

#define OBJC_ARC true
#if OBJC_ARC

#define MAKE_SINGLETON(class_name, shared_method_name) \
+ (id)shared_method_name { \
static dispatch_once_t pred; \
static class_name * z ## class_name ## _ = nil; \
dispatch_once(&pred, ^{ \
z ## class_name ## _ = [[self alloc] init]; \
}); \
return z ## class_name ## _; \
} \
- (id)copy { \
return self; \
}
#else

#define MAKE_SINGLETON(class_name, shared_method_name) \
+ (id)shared_method_name { \
static dispatch_once_t pred; \
static class_name * z ## class_name ## _ = nil; \
dispatch_once(&pred, ^{ \
z ## class_name ## _ = [[self alloc] init]; \
}); \
return z ## class_name ## _; \
} \
- (id)copy { \
return self; \
} \
- (id)retain { \
return self; \
} \
- (NSUInteger)retainCount { \
return UINT_MAX; \
} \
- (void)release { \
} \
- (id)autorelease { \
return self; \
}
#endif

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment