summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorder richter <der.richter@gmx.de>2019-11-30 16:08:32 +0100
committerder richter <der.richter@gmx.de>2019-12-15 20:07:31 +0100
commita32db637b5c66c0304147caadf02d7b28083bcee (patch)
treea078fd47fd36cc853a1422ea05a949fbc9afde60
parent8a6ee7fe947bb01a49beb38152cedb1e1b206ed2 (diff)
downloadmpv-a32db637b5c66c0304147caadf02d7b28083bcee.tar.bz2
mpv-a32db637b5c66c0304147caadf02d7b28083bcee.tar.xz
mac: replace old event tap for media key support with MediaPlayer
the old event tap has several problems, like no proper priority support or having to set accessibility permissions for mpv or the terminal. it is now replaced by the new MediaPlayer which has proper priority support and isn't as greedy as previously. this only includes Media Key support and not any of the other features included in the MediaPlayer framework, like proper Now Playing data (only set dummy data for now). this is only available on macOS 10.12.2 and higher. also removes some unnecessary redefines. Fixes #6389
-rw-r--r--osdep/macOS_swift_bridge.h3
-rw-r--r--osdep/macos/remote_command_center.swift159
-rw-r--r--osdep/macosx_application.m15
-rw-r--r--osdep/macosx_application_objc.h3
-rw-r--r--osdep/macosx_events.m127
-rw-r--r--osdep/macosx_events_objc.h3
-rw-r--r--video/out/cocoa-cb/events_view.swift12
-rw-r--r--video/out/cocoa-cb/window.swift2
-rw-r--r--wscript5
-rw-r--r--wscript_build.py1
10 files changed, 197 insertions, 133 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
diff --git a/video/out/cocoa-cb/events_view.swift b/video/out/cocoa-cb/events_view.swift
index 31533bbb98..73ccba527f 100644
--- a/video/out/cocoa-cb/events_view.swift
+++ b/video/out/cocoa-cb/events_view.swift
@@ -180,20 +180,20 @@ class EventsView: NSView {
}
func signalMouseDown(_ event: NSEvent) {
- signalMouseEvent(event, SWIFT_KEY_STATE_DOWN)
+ signalMouseEvent(event, MP_KEY_STATE_DOWN)
if event.clickCount > 1 {
- signalMouseEvent(event, SWIFT_KEY_STATE_UP)
+ signalMouseEvent(event, MP_KEY_STATE_UP)
}
}
func signalMouseUp(_ event: NSEvent) {
- signalMouseEvent(event, SWIFT_KEY_STATE_UP)
+ signalMouseEvent(event, MP_KEY_STATE_UP)
}
- func signalMouseEvent(_ event: NSEvent, _ state: Int32) {
- hasMouseDown = state == SWIFT_KEY_STATE_DOWN
+ func signalMouseEvent(_ event: NSEvent, _ state: UInt32) {
+ hasMouseDown = state == MP_KEY_STATE_DOWN
let mpkey = getMpvButton(event)
- cocoa_put_key_with_modifiers((mpkey | state), Int32(event.modifierFlags.rawValue));
+ cocoa_put_key_with_modifiers((mpkey | Int32(state)), Int32(event.modifierFlags.rawValue));
}
func signalMouseMovement(_ event: NSEvent) {
diff --git a/video/out/cocoa-cb/window.swift b/video/out/cocoa-cb/window.swift
index 94f80e59b4..6e53ef309c 100644
--- a/video/out/cocoa-cb/window.swift
+++ b/video/out/cocoa-cb/window.swift
@@ -486,7 +486,7 @@ class Window: NSWindow, NSWindowDelegate {
}
func windowShouldClose(_ sender: NSWindow) -> Bool {
- cocoa_put_key(SWIFT_KEY_CLOSE_WIN)
+ cocoa_put_key(MP_KEY_CLOSE_WIN)
return false
}
diff --git a/wscript b/wscript
index 3aa1376995..ff946900da 100644
--- a/wscript
+++ b/wscript
@@ -919,6 +919,11 @@ standalone_features = [
'deps': 'cocoa',
'func': check_macos_sdk('10.11')
}, {
+ 'name': '--macos-10-12-2-features',
+ 'desc': 'macOS 10.12.2 SDK Features',
+ 'deps': 'cocoa',
+ 'func': check_macos_sdk('10.12.2')
+ }, {
'name': '--macos-10-14-features',
'desc': 'macOS 10.14 SDK Features',
'deps': 'cocoa',
diff --git a/wscript_build.py b/wscript_build.py
index 3ad85fd3b5..4c34d94c45 100644
--- a/wscript_build.py
+++ b/wscript_build.py
@@ -174,6 +174,7 @@ def build(ctx):
( "osdep/macos/mpv_helper.swift" ),
( "osdep/macos/swift_extensions.swift" ),
( "osdep/macos/swift_compat.swift" ),
+ ( "osdep/macos/remote_command_center.swift", "macos-10-12-2-features" ),
( "video/out/cocoa-cb/events_view.swift" ),
( "video/out/cocoa-cb/video_layer.swift" ),
( "video/out/cocoa-cb/window.swift" ),