diff options
Diffstat (limited to 'osdep')
-rw-r--r-- | osdep/macOS_swift_bridge.h | 3 | ||||
-rw-r--r-- | osdep/macos/remote_command_center.swift | 159 | ||||
-rw-r--r-- | osdep/macosx_application.m | 15 | ||||
-rw-r--r-- | osdep/macosx_application_objc.h | 3 | ||||
-rw-r--r-- | osdep/macosx_events.m | 127 | ||||
-rw-r--r-- | osdep/macosx_events_objc.h | 3 |
6 files changed, 184 insertions, 126 deletions
diff --git a/osdep/macOS_swift_bridge.h b/osdep/macOS_swift_bridge.h index f0b549ca40..29cd8bf016 100644 --- a/osdep/macOS_swift_bridge.h +++ b/osdep/macOS_swift_bridge.h @@ -44,11 +44,8 @@ static int SWIFT_MBTN_BACK = MP_MBTN_BACK; static int SWIFT_MBTN_FORWARD = MP_MBTN_FORWARD; static int SWIFT_MBTN9 = MP_MBTN9; -static int SWIFT_KEY_CLOSE_WIN = MP_KEY_CLOSE_WIN; static int SWIFT_KEY_MOUSE_LEAVE = MP_KEY_MOUSE_LEAVE; static int SWIFT_KEY_MOUSE_ENTER = MP_KEY_MOUSE_ENTER; -static int SWIFT_KEY_STATE_DOWN = MP_KEY_STATE_DOWN; -static int SWIFT_KEY_STATE_UP = MP_KEY_STATE_UP; // only used from Swift files and therefore seen as unused by the c compiler static void SWIFT_TARRAY_STRING_APPEND(void *t, char ***a, int *i, char *s) __attribute__ ((unused)); diff --git a/osdep/macos/remote_command_center.swift b/osdep/macos/remote_command_center.swift new file mode 100644 index 0000000000..585a2e5698 --- /dev/null +++ b/osdep/macos/remote_command_center.swift @@ -0,0 +1,159 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see <http://www.gnu.org/licenses/>. + */ + +import MediaPlayer + +@available(macOS 10.12.2, *) +class RemoteCommandCenter: NSObject { + + enum KeyType { + case normal + case repeatable + } + + var config: [MPRemoteCommand:[String:Any]] = [ + MPRemoteCommandCenter.shared().pauseCommand: [ + "mpKey": MP_KEY_PAUSE, + "keyType": KeyType.normal + ], + MPRemoteCommandCenter.shared().playCommand: [ + "mpKey": MP_KEY_PLAY, + "keyType": KeyType.normal + ], + MPRemoteCommandCenter.shared().stopCommand: [ + "mpKey": MP_KEY_STOP, + "keyType": KeyType.normal + ], + MPRemoteCommandCenter.shared().nextTrackCommand: [ + "mpKey": MP_KEY_NEXT, + "keyType": KeyType.normal + ], + MPRemoteCommandCenter.shared().previousTrackCommand: [ + "mpKey": MP_KEY_PREV, + "keyType": KeyType.normal + ], + MPRemoteCommandCenter.shared().togglePlayPauseCommand: [ + "mpKey": MP_KEY_PLAYPAUSE, + "keyType": KeyType.normal + ], + MPRemoteCommandCenter.shared().seekForwardCommand: [ + "mpKey": MP_KEY_FORWARD, + "keyType": KeyType.repeatable, + "state": MP_KEY_STATE_UP + ], + MPRemoteCommandCenter.shared().seekBackwardCommand: [ + "mpKey": MP_KEY_REWIND, + "keyType": KeyType.repeatable, + "state": MP_KEY_STATE_UP + ], + ] + + var nowPlayingInfo: [String: Any] = [ + MPNowPlayingInfoPropertyMediaType: NSNumber(value: MPNowPlayingInfoMediaType.video.rawValue), + MPNowPlayingInfoPropertyDefaultPlaybackRate: NSNumber(value: 1), + MPNowPlayingInfoPropertyPlaybackProgress: NSNumber(value: 0.0), + MPMediaItemPropertyPlaybackDuration: NSNumber(value: 0), + MPMediaItemPropertyTitle: "mpv", + MPMediaItemPropertyAlbumTitle: "mpv", + MPMediaItemPropertyArtist: "mpv", + ] + + let disabledCommands: [MPRemoteCommand] = [ + MPRemoteCommandCenter.shared().changePlaybackRateCommand, + MPRemoteCommandCenter.shared().changeRepeatModeCommand, + MPRemoteCommandCenter.shared().changeShuffleModeCommand, + MPRemoteCommandCenter.shared().skipForwardCommand, + MPRemoteCommandCenter.shared().skipBackwardCommand, + MPRemoteCommandCenter.shared().changePlaybackPositionCommand, + MPRemoteCommandCenter.shared().enableLanguageOptionCommand, + MPRemoteCommandCenter.shared().disableLanguageOptionCommand, + MPRemoteCommandCenter.shared().ratingCommand, + MPRemoteCommandCenter.shared().likeCommand, + MPRemoteCommandCenter.shared().dislikeCommand, + MPRemoteCommandCenter.shared().bookmarkCommand, + ] + + let application: Application; + + @objc init(app: Application) { + application = app + + super.init() + + for cmd in disabledCommands { + cmd.isEnabled = false + } + } + + @objc func makeCurrent() { + MPNowPlayingInfoCenter.default().playbackState = .paused + MPNowPlayingInfoCenter.default().playbackState = .playing + } + + @objc func start() { + for (cmd, _) in config { + cmd.isEnabled = true + cmd.addTarget { [unowned self] event in + return self.cmdHandler(event) + } + } + + if let icon = application.getMPVIcon(), #available(macOS 10.13.2, *) { + let albumArt = MPMediaItemArtwork(boundsSize:icon.size) { _ in + return icon + } + nowPlayingInfo[MPMediaItemPropertyArtwork] = albumArt + } + + MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo + MPNowPlayingInfoCenter.default().playbackState = .playing + } + + @objc func stop() { + for (cmd, _) in config { + cmd.isEnabled = false + cmd.removeTarget(nil) + } + + MPNowPlayingInfoCenter.default().nowPlayingInfo = nil + MPNowPlayingInfoCenter.default().playbackState = .unknown + } + + func cmdHandler(_ event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus { + guard let cmdConfig = config[event.command], + let mpKey = cmdConfig["mpKey"] as? Int32, + let keyType = cmdConfig["keyType"] as? KeyType else + { + return .commandFailed + } + + var state = cmdConfig["state"] as? UInt32 ?? 0 + + if let currentState = cmdConfig["state"] as? UInt32, keyType == .repeatable { + state = MP_KEY_STATE_DOWN + config[event.command]?["state"] = MP_KEY_STATE_DOWN + if currentState == MP_KEY_STATE_DOWN { + state = MP_KEY_STATE_UP + config[event.command]?["state"] = MP_KEY_STATE_UP + } + } + + application.handleMPKey(mpKey, withMask: Int32(state)); + + return .success + } +}
\ No newline at end of file diff --git a/osdep/macosx_application.m b/osdep/macosx_application.m index 8b3fac95a4..3d420a3152 100644 --- a/osdep/macosx_application.m +++ b/osdep/macosx_application.m @@ -105,6 +105,7 @@ static void terminate_cocoa_application(void) @synthesize menuBar = _menu_bar; @synthesize openCount = _open_count; @synthesize cocoaCB = _cocoa_cb; +@synthesize remoteCommandCenter = _remoteCommandCenter; - (void)sendEvent:(NSEvent *)event { @@ -199,6 +200,11 @@ static const char macosx_icon[] = [_eventsResponder queueCommand:cmd]; } +- (void)handleMPKey:(int)key withMask:(int)mask +{ + [_eventsResponder handleMPKey:key withMask:mask]; +} + - (void)stopMPV:(char *)cmd { if (![_eventsResponder queueCommand:cmd]) @@ -216,7 +222,7 @@ static const char macosx_icon[] = - (void)applicationWillBecomeActive:(NSNotification *)notification { - [_eventsResponder setHighestPriotityMediaKeysTap]; + [_remoteCommandCenter makeCurrent]; } - (void)handleQuitEvent:(NSAppleEventDescriptor *)event @@ -293,6 +299,13 @@ static void init_cocoa_application(bool regular) [NSApp setDelegate:NSApp]; [NSApp setMenuBar:[[MenuBar alloc] init]]; +#if HAVE_MACOS_10_12_2_FEATURES + // 10.12.2 runtime availability check + if ([NSApp respondsToSelector:@selector(touchBar)]) { + [NSApp setRemoteCommandCenter:[[RemoteCommandCenter alloc] initWithApp:NSApp]]; + } +#endif + // Will be set to Regular from cocoa_common during UI creation so that we // don't create an icon when playing audio only files. [NSApp setActivationPolicy: regular ? diff --git a/osdep/macosx_application_objc.h b/osdep/macosx_application_objc.h index 11959a83ea..4bd5b55b1a 100644 --- a/osdep/macosx_application_objc.h +++ b/osdep/macosx_application_objc.h @@ -20,6 +20,7 @@ #import "osdep/macosx_menubar_objc.h" @class CocoaCB; +@class RemoteCommandCenter; struct mpv_event; struct mpv_handle; @@ -28,6 +29,7 @@ struct mpv_handle; - (NSImage *)getMPVIcon; - (void)processEvent:(struct mpv_event *)event; - (void)queueCommand:(char *)cmd; +- (void)handleMPKey:(int)key withMask:(int)mask; - (void)stopMPV:(char *)cmd; - (void)openFiles:(NSArray *)filenames; - (void)setMpvHandle:(struct mpv_handle *)ctx; @@ -37,4 +39,5 @@ struct mpv_handle; @property(nonatomic, retain) MenuBar *menuBar; @property(nonatomic, assign) size_t openCount; @property(nonatomic, retain) CocoaCB *cocoaCB; +@property(nonatomic, retain) RemoteCommandCenter *remoteCommandCenter; @end diff --git a/osdep/macosx_events.m b/osdep/macosx_events.m index 14aa7063fb..3f40e41f6c 100644 --- a/osdep/macosx_events.m +++ b/osdep/macosx_events.m @@ -49,15 +49,12 @@ struct mpv_handle *_ctx; BOOL _is_application; NSCondition *_input_lock; - CFMachPortRef _mk_tap_port; } -- (BOOL)handleMediaKey:(NSEvent *)event; - (NSEvent *)handleKey:(NSEvent *)event; - (BOOL)setMpvHandle:(struct mpv_handle *)ctx; - (void)readEvents; - (void)startMediaKeys; -- (void)restartMediaKeys; - (void)stopMediaKeys; - (int)mapKeyModifiers:(int)cocoaModifiers; - (int)keyModifierMask:(NSEvent *)event; @@ -121,53 +118,6 @@ static int convert_key(unsigned key, unsigned charcode) return charcode; } -static int mk_code(NSEvent *event) -{ - return (([event data1] & 0xFFFF0000) >> 16); -} - -static int mk_flags(NSEvent *event) -{ - return ([event data1] & 0x0000FFFF); -} - -static int mk_down(NSEvent *event) -{ - return (((mk_flags(event) & 0xFF00) >> 8)) == 0xA; -} - -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] != NSEventTypeSystemDefined || [nse subtype] != 8) - // This is not a media key - return event; - - if (mk_down(nse) && [responder handleMediaKey:nse]) { - // 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) { [[EventsResponder sharedInstance] startMediaKeys]; @@ -337,77 +287,18 @@ void cocoa_set_mpv_handle(struct mpv_handle *ctx) } } -- (void)restartMediaKeys -{ - if (self->_mk_tap_port) - CGEventTapEnable(self->_mk_tap_port, true); -} - -- (void)setHighestPriotityMediaKeysTap -{ - if (self->_mk_tap_port == nil) - return; - - CGEventTapInformation *taps = ta_alloc_size(nil, sizeof(CGEventTapInformation)); - uint32_t numTaps = 0; - CGError err = CGGetEventTapList(1, taps, &numTaps); - - if (err == kCGErrorSuccess && numTaps > 0) { - pid_t processID = [NSProcessInfo processInfo].processIdentifier; - if (taps[0].tappingProcess != processID) { - [self stopMediaKeys]; - [self startMediaKeys]; - } - } - talloc_free(taps); -} - - (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); - - if (self->_mk_tap_port) { - NSMachPort *port = (NSMachPort *)self->_mk_tap_port; - [[NSRunLoop mainRunLoop] addPort:port forMode:NSRunLoopCommonModes]; - } - }); + if ([(Application *)NSApp remoteCommandCenter]) { + [[(Application *)NSApp remoteCommandCenter] start]; + } } - (void)stopMediaKeys { - dispatch_async(dispatch_get_main_queue(), ^{ - NSMachPort *port = (NSMachPort *)self->_mk_tap_port; - if (port) { - CGEventTapEnable(self->_mk_tap_port, false); - [[NSRunLoop mainRunLoop] removePort:port forMode:NSRunLoopCommonModes]; - CFRelease(self->_mk_tap_port); - self->_mk_tap_port = nil; - } - }); -} - -- (BOOL)handleMediaKey:(NSEvent *)event -{ - NSDictionary *keymapd = @{ - @(NX_KEYTYPE_PLAY): @(MP_KEY_PLAY), - @(NX_KEYTYPE_REWIND): @(MP_KEY_PREV), - @(NX_KEYTYPE_FAST): @(MP_KEY_NEXT), - @(NX_KEYTYPE_PREVIOUS): @(MP_KEY_REWIND), - @(NX_KEYTYPE_NEXT): @(MP_KEY_FORWARD), - }; - - return [self handleKey:mk_code(event) - withMask:[self keyModifierMask:event] - andMapping:keymapd]; + if ([(Application *)NSApp remoteCommandCenter]) { + [[(Application *)NSApp remoteCommandCenter] stop]; + } } - (int)mapKeyModifiers:(int)cocoaModifiers @@ -452,12 +343,6 @@ void cocoa_set_mpv_handle(struct mpv_handle *ctx) } } --(BOOL)handleKey:(int)key withMask:(int)mask andMapping:(NSDictionary *)mapping -{ - int mpkey = [mapping[@(key)] intValue]; - return [self handleMPKey:mpkey withMask:mask]; -} - - (NSEvent*)handleKey:(NSEvent *)event { if ([event isARepeat]) return nil; diff --git a/osdep/macosx_events_objc.h b/osdep/macosx_events_objc.h index 42f6ee234a..efc4e8f7ec 100644 --- a/osdep/macosx_events_objc.h +++ b/osdep/macosx_events_objc.h @@ -32,10 +32,11 @@ struct input_ctx; - (void)waitForInputContext; - (void)wakeup; - (void)putKey:(int)keycode; -- (void)setHighestPriotityMediaKeysTap; - (void)handleFilesArray:(NSArray *)files; - (bool)queueCommand:(char *)cmd; - (bool)processKeyEvent:(NSEvent *)event; +- (BOOL)handleMPKey:(int)key withMask:(int)mask; + @end |