diff options
-rw-r--r-- | DOCS/man/en/options.rst | 3 | ||||
-rw-r--r-- | core/defaultopts.c | 1 | ||||
-rw-r--r-- | core/input/input.c | 17 | ||||
-rw-r--r-- | core/input/keycodes.h | 6 | ||||
-rw-r--r-- | core/options.h | 1 | ||||
-rw-r--r-- | etc/input.conf | 5 | ||||
-rw-r--r-- | osdep/macosx_application.m | 14 | ||||
-rw-r--r-- | osdep/macosx_application_objc.h | 5 | ||||
-rw-r--r-- | osdep/macosx_events.h | 8 | ||||
-rw-r--r-- | osdep/macosx_events.m | 113 |
10 files changed, 140 insertions, 33 deletions
diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst index 8239375079..e0d0dc9f1f 100644 --- a/DOCS/man/en/options.rst +++ b/DOCS/man/en/options.rst @@ -1125,6 +1125,9 @@ --mc=<seconds/frame> Maximum A-V sync correction per frame (in seconds) +--media-keys, --no-media-keys + OSX only: Enabled by default. Enables/disable media keys support. + --mf=<option1:option2:...> Used when decoding from multiple PNG or JPEG files with ``mf://``. diff --git a/core/defaultopts.c b/core/defaultopts.c index a8a6b26930..a03370bed6 100644 --- a/core/defaultopts.c +++ b/core/defaultopts.c @@ -110,6 +110,7 @@ void set_default_mplayer_options(struct MPOpts *opts) .use_lircc = 1, #ifdef CONFIG_COCOA .use_ar = 1, + .use_media_keys = 1, #endif .default_bindings = 1, } diff --git a/core/input/input.c b/core/input/input.c index 4bfc22a08c..8bc877ce79 100644 --- a/core/input/input.c +++ b/core/input/input.c @@ -409,6 +409,10 @@ static const struct key_name key_names[] = { { MP_AR_VDOWN, "AR_VDOWN" }, { MP_AR_VDOWN_HOLD, "AR_VDOWN_HOLD" }, + { MP_MK_PLAY, "MK_PLAY" }, + { MP_MK_PREV, "MK_PREV" }, + { MP_MK_NEXT, "MK_NEXT" }, + { MP_KEY_POWER, "POWER" }, { MP_KEY_MENU, "MENU" }, { MP_KEY_PLAY, "PLAY" }, @@ -553,6 +557,7 @@ static const m_option_t mp_input_opts[] = { OPT_FLAG("lircc", input.use_lircc, CONF_GLOBAL), #ifdef CONFIG_COCOA OPT_FLAG("ar", input.use_ar, CONF_GLOBAL), + OPT_FLAG("media-keys", input.use_media_keys, CONF_GLOBAL), #endif { NULL, NULL, 0, 0, 0, 0, NULL} }; @@ -1830,7 +1835,11 @@ struct input_ctx *mp_input_init(struct input_conf *input_conf, #ifdef CONFIG_COCOA if (input_conf->use_ar) { - cocoa_start_apple_remote(); + cocoa_init_apple_remote(); + } + + if (input_conf->use_media_keys) { + cocoa_init_media_keys(); } #endif @@ -1872,7 +1881,11 @@ void mp_input_uninit(struct input_ctx *ictx, struct input_conf *input_conf) #ifdef CONFIG_COCOA if (input_conf->use_ar) { - cocoa_stop_apple_remote(); + cocoa_uninit_apple_remote(); + } + + if (input_conf->use_media_keys) { + cocoa_uninit_media_keys(); } #endif diff --git a/core/input/keycodes.h b/core/input/keycodes.h index b9d2da23b7..8770f8abfa 100644 --- a/core/input/keycodes.h +++ b/core/input/keycodes.h @@ -189,6 +189,12 @@ #define MP_AR_VDOWN (MP_AR_BASE + 12) #define MP_AR_VDOWN_HOLD (MP_AR_BASE + 13) +// Apple Media Keys input module +#define MP_MK_BASE (MP_KEY_BASE+0xF0) +#define MP_MK_PLAY (MP_AR_BASE + 0) +#define MP_MK_PREV (MP_AR_BASE + 1) +#define MP_MK_NEXT (MP_AR_BASE + 2) + /* Special keys */ #define MP_KEY_INTERN (MP_KEY_BASE+0x1000) #define MP_KEY_CLOSE_WIN (MP_KEY_INTERN+0) diff --git a/core/options.h b/core/options.h index 0504ea0591..eaa908d7bd 100644 --- a/core/options.h +++ b/core/options.h @@ -241,6 +241,7 @@ typedef struct MPOpts { int use_lircc; #ifdef CONFIG_COCOA int use_ar; + int use_media_keys; #endif int default_bindings; int test; diff --git a/etc/input.conf b/etc/input.conf index 1cbd2446ba..3f9cea3c44 100644 --- a/etc/input.conf +++ b/etc/input.conf @@ -152,6 +152,11 @@ AR_VUP_HOLD add chapter 1 AR_VDOWN add volume -1 AR_VDOWN_HOLD add chapter -1 +# Media Keys section +MK_PLAY cycle pause +MK_PREV playlist_prev +MK_NEXT playlist_next + # Joystick section # WARNING: joystick support has to be explicitly enabled at # compiletime with --enable-joystick 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 |