summaryrefslogtreecommitdiffstats
path: root/osdep
diff options
context:
space:
mode:
authorStefano Pigozzi <stefano.pigozzi@gmail.com>2013-06-04 22:12:23 +0200
committerStefano Pigozzi <stefano.pigozzi@gmail.com>2013-06-04 23:02:23 +0200
commit213ad5d6c41f32cf9086fa377cd6d6df1236bb76 (patch)
treed265eda1e4deca9ad58de8e2137852d1cf3e8c1e /osdep
parent1b6888ae8e30331033bf197b862742d9bda21843 (diff)
downloadmpv-213ad5d6c41f32cf9086fa377cd6d6df1236bb76.tar.bz2
mpv-213ad5d6c41f32cf9086fa377cd6d6df1236bb76.tar.xz
osx: improve Media Keys support
This commit addresses some issues with the users had with the previous implementation in commit c39efb9. Here's the changes: * Use Quartz Event Taps to remove Media Key events mpv handles from the global OS X queue. This prevents conflicts with iTunes. I did this on the main thread since it is mostly idling. It's the playloop thread that actually does all the work so there is no danger of blocking the event tap callback. * Introduce `--no-media-keys` switch so that users can disable all of mpv's media key handling at runtime (some prefer iTunes for example). * Use mpv's bindings so that users can customize what the media keys do via input.conf. Current bindings are: MK_PLAY cycle pause MK_PREV playlist_prev MK_NEXT playlist_next An additional benefit of this implementation is that it is completly handled by the `macosx_events` file instead of `macosx_application` making the project organization more straightforward.
Diffstat (limited to 'osdep')
-rw-r--r--osdep/macosx_application.m14
-rw-r--r--osdep/macosx_application_objc.h5
-rw-r--r--osdep/macosx_events.h8
-rw-r--r--osdep/macosx_events.m113
4 files changed, 109 insertions, 31 deletions
diff --git a/osdep/macosx_application.m b/osdep/macosx_application.m
index 1329091e12..665a04b222 100644
--- a/osdep/macosx_application.m
+++ b/osdep/macosx_application.m
@@ -120,19 +120,7 @@ static NSString *escape_loadfile_name(NSString *input)
- (void)sendEvent:(NSEvent *)event
{
- if ([event type] == NSSystemDefined && [event subtype] == 8) {
- // It's a media key! Handle it specially. The magic numbers are reverse
- // engineered and found on several blog posts. Unfortunately there is
- // no public API for this. F-bomb.
- int code = (([event data1] & 0xFFFF0000) >> 16);
- int flags = ([event data1] & 0x0000FFFF);
- int down = (((flags & 0xFF00) >> 8)) == 0xA;
-
- if (down)
- [self.eventsResponder handleMediaKey:code];
- } else {
- [super sendEvent:event];
- }
+ [super sendEvent:event];
if (self.inputContext)
mp_input_wakeup(self.inputContext);
diff --git a/osdep/macosx_application_objc.h b/osdep/macosx_application_objc.h
index 3ab74698c3..c8026cfc14 100644
--- a/osdep/macosx_application_objc.h
+++ b/osdep/macosx_application_objc.h
@@ -28,10 +28,13 @@ struct cocoa_input_queue;
@end
@interface EventsResponder : NSObject <HIDRemoteDelegate>
-- (void)handleMediaKey:(int)key;
+- (BOOL)handleMediaKey:(int)key;
- (NSEvent *)handleKeyDown:(NSEvent *)event;
- (void)startAppleRemote;
- (void)stopAppleRemote;
+- (void)startMediaKeys;
+- (void)restartMediaKeys;
+- (void)stopMediaKeys;
@property(nonatomic, retain) HIDRemote *remote;
@end
diff --git a/osdep/macosx_events.h b/osdep/macosx_events.h
index 9557aeab5c..b8162dc125 100644
--- a/osdep/macosx_events.h
+++ b/osdep/macosx_events.h
@@ -23,7 +23,11 @@
void cocoa_put_key(int keycode);
void cocoa_check_events(void);
-void cocoa_start_apple_remote(void);
-void cocoa_stop_apple_remote(void);
+
+void cocoa_init_apple_remote(void);
+void cocoa_uninit_apple_remote(void);
+
+void cocoa_init_media_keys(void);
+void cocoa_uninit_media_keys(void);
#endif
diff --git a/osdep/macosx_events.m b/osdep/macosx_events.m
index 86d0ebaa3e..7970f0b5d5 100644
--- a/osdep/macosx_events.m
+++ b/osdep/macosx_events.m
@@ -92,18 +92,67 @@ static int convert_key(unsigned key, unsigned charcode)
return charcode;
}
-void cocoa_start_apple_remote(void)
+void cocoa_init_apple_remote(void)
{
Application *app = mpv_shared_app();
[app.eventsResponder startAppleRemote];
}
-void cocoa_stop_apple_remote(void)
+void cocoa_uninit_apple_remote(void)
{
Application *app = mpv_shared_app();
[app.eventsResponder stopAppleRemote];
}
+static CGEventRef tap_event_callback(CGEventTapProxy proxy, CGEventType type,
+ CGEventRef event, void *ctx)
+{
+ EventsResponder *responder = ctx;
+
+ if (type == kCGEventTapDisabledByTimeout) {
+ // The Mach Port receiving the taps became unresponsive for some
+ // reason, restart listening on it.
+ [responder restartMediaKeys];
+ return event;
+ }
+
+ if (type == kCGEventTapDisabledByUserInput)
+ return event;
+
+ NSEvent *nse = [NSEvent eventWithCGEvent:event];
+
+ if ([nse type] != NSSystemDefined || [nse subtype] != 8)
+ // This is not a media key
+ return event;
+
+ // It's a media key! Handle it specially. The magic numbers are reverse
+ // engineered and found on several blog posts. Unfortunately there is
+ // no public API for this. F-bomb.
+ int code = (([nse data1] & 0xFFFF0000) >> 16);
+ int flags = ([nse data1] & 0x0000FFFF);
+ int down = (((flags & 0xFF00) >> 8)) == 0xA;
+
+ if (down && [responder handleMediaKey:code]) {
+ // Handled this event, return nil so that it is removed from the
+ // global queue.
+ return nil;
+ } else {
+ // Was a media key but we were not interested in it. Leave it in the
+ // global queue by returning the original event.
+ return event;
+ }
+}
+
+void cocoa_init_media_keys(void) {
+ Application *app = mpv_shared_app();
+ [app.eventsResponder startMediaKeys];
+}
+
+void cocoa_uninit_media_keys(void) {
+ Application *app = mpv_shared_app();
+ [app.eventsResponder stopMediaKeys];
+}
+
void cocoa_check_events(void)
{
Application *app = mpv_shared_app();
@@ -117,7 +166,9 @@ void cocoa_put_key(int keycode)
[mpv_shared_app().iqueue push:keycode];
}
-@implementation EventsResponder
+@implementation EventsResponder {
+ CFMachPortRef _mk_tap_port;
+}
- (void)startAppleRemote
{
dispatch_async(dispatch_get_main_queue(), ^{
@@ -135,24 +186,56 @@ void cocoa_put_key(int keycode)
[self.remote stopRemoteControl];
});
}
+- (void)restartMediaKeys
+{
+ CGEventTapEnable(self->_mk_tap_port, true);
+}
+- (void)startMediaKeys
+{
+ dispatch_async(dispatch_get_main_queue(), ^{
+ // Install a Quartz Event Tap. This will notify mpv through the
+ // returned Mach Port and cause mpv to execute the `tap_event_callback`
+ // function.
+ self->_mk_tap_port = CGEventTapCreate(kCGSessionEventTap,
+ kCGHeadInsertEventTap,
+ kCGEventTapOptionDefault,
+ CGEventMaskBit(NX_SYSDEFINED),
+ tap_event_callback,
+ self);
+
+ assert(self->_mk_tap_port != nil);
+
+ NSMachPort *port = (NSMachPort *)self->_mk_tap_port;
+ [[NSRunLoop mainRunLoop] addPort:port forMode:NSRunLoopCommonModes];
+ });
+}
+- (void)stopMediaKeys
+{
+ dispatch_async(dispatch_get_main_queue(), ^{
+ NSMachPort *port = (NSMachPort *)self->_mk_tap_port;
+ [[NSRunLoop mainRunLoop] removePort:port forMode:NSRunLoopCommonModes];
+ CFRelease(self->_mk_tap_port);
+ self->_mk_tap_port = nil;
+ });
+}
- (NSArray *) keyEquivalents
{
return @[@"h", @"q", @"Q", @"0", @"1", @"2"];
}
-- (void)handleMediaKey:(int)key
+- (BOOL)handleMediaKey:(int)key
{
- switch (key) {
- case NX_KEYTYPE_PLAY:
- cocoa_put_key(MP_KEY_PLAY);
- break;
-
- case NX_KEYTYPE_FAST:
- cocoa_put_key(MP_KEY_NEXT);
- break;
+ NSDictionary *keymap = @{
+ @(NX_KEYTYPE_PLAY): @(MP_MK_PLAY),
+ @(NX_KEYTYPE_REWIND): @(MP_MK_PREV),
+ @(NX_KEYTYPE_FAST): @(MP_MK_NEXT),
+ };
- case NX_KEYTYPE_REWIND:
- cocoa_put_key(MP_KEY_PREV);
- break;
+ int mpkey = [keymap[@(key)] intValue];
+ if (mpkey > 0) {
+ cocoa_put_key(mpkey);
+ return YES;
+ } else {
+ return NO;
}
}
- (NSEvent*)handleKeyDown:(NSEvent *)event