123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- //
- // Created by Tobias Hieta on 21/08/15.
- //
- #include "InputAppleMediaKeys.h"
- #include "SPMediaKeyTap.h"
- #include "QsLog.h"
- #import <dlfcn.h>
- #import <MediaPlayer/MediaPlayer.h>
- @interface MediaKeysDelegate : NSObject
- {
- SPMediaKeyTap* keyTap;
- InputAppleMediaKeys* input;
- }
- -(instancetype)initWithInput:(InputAppleMediaKeys*)input;
- @end
- @implementation MediaKeysDelegate
- - (instancetype)initWithInput:(InputAppleMediaKeys*)input_
- {
- self = [super init];
- if (self) {
- input = input_;
- if (NSClassFromString(@"MPRemoteCommandCenter")) {
- MPRemoteCommandCenter* center = [MPRemoteCommandCenter sharedCommandCenter];
- #define CONFIG_CMD(name) \
- [center.name ## Command addTarget:self action:@selector(gotCommand:)]
- CONFIG_CMD(play);
- CONFIG_CMD(pause);
- CONFIG_CMD(togglePlayPause);
- CONFIG_CMD(stop);
- CONFIG_CMD(nextTrack);
- CONFIG_CMD(previousTrack);
- CONFIG_CMD(seekForward);
- CONFIG_CMD(seekBackward);
- CONFIG_CMD(skipForward);
- CONFIG_CMD(skipBackward);
- [center.changePlaybackPositionCommand addTarget:self action:@selector(gotPlaybackPosition:)];
- } else {
- keyTap = [[SPMediaKeyTap alloc] initWithDelegate:self];
- if ([SPMediaKeyTap usesGlobalMediaKeyTap])
- [keyTap startWatchingMediaKeys];
- else
- QLOG_WARN() << "Could not grab global media keys";
- }
- }
- return self;
- }
- - (void)dealloc
- {
- [super dealloc];
- }
- -(MPRemoteCommandHandlerStatus)gotCommand:(MPRemoteCommandEvent *)event
- {
- QString keyPressed;
- MPRemoteCommand* command = [event command];
- #define CMD(name) [MPRemoteCommandCenter sharedCommandCenter].name ## Command
- if (command == CMD(play)) {
- keyPressed = INPUT_KEY_PLAY;
- } else if (command == CMD(pause)) {
- keyPressed = INPUT_KEY_PAUSE;
- } else if (command == CMD(togglePlayPause)) {
- keyPressed = INPUT_KEY_PLAY_PAUSE;
- } else if (command == CMD(stop)) {
- keyPressed = INPUT_KEY_STOP;
- } else if (command == CMD(nextTrack)) {
- keyPressed = INPUT_KEY_NEXT;
- } else if (command == CMD(previousTrack)) {
- keyPressed = INPUT_KEY_PREV;
- } else {
- return MPRemoteCommandHandlerStatusCommandFailed;
- }
- emit input->receivedInput("AppleMediaKeys", keyPressed, InputBase::KeyPressed);
- return MPRemoteCommandHandlerStatusSuccess;
- }
- -(MPRemoteCommandHandlerStatus)gotPlaybackPosition:(MPChangePlaybackPositionCommandEvent *)event
- {
- PlayerComponent::Get().seekTo(event.positionTime * 1000);
- return MPRemoteCommandHandlerStatusSuccess;
- }
- -(void)mediaKeyTap:(SPMediaKeyTap *)keyTap receivedMediaKeyEvent:(NSEvent *)event
- {
- int keyCode = (([event data1] & 0xFFFF0000) >> 16);
- int keyFlags = ([event data1] & 0x0000FFFF);
- BOOL keyIsPressed = (((keyFlags & 0xFF00) >> 8)) == 0xA;
- QString keyPressed;
- switch (keyCode) {
- case NX_KEYTYPE_PLAY:
- keyPressed = INPUT_KEY_PLAY_PAUSE;
- break;
- case NX_KEYTYPE_FAST:
- keyPressed = "KEY_FAST";
- break;
- case NX_KEYTYPE_REWIND:
- keyPressed = "KEY_REWIND";
- break;
- case NX_KEYTYPE_NEXT:
- keyPressed = INPUT_KEY_NEXT;
- break;
- case NX_KEYTYPE_PREVIOUS:
- keyPressed = INPUT_KEY_PREV;
- break;
- default:
- break;
- // More cases defined in hidsystem/ev_keymap.h
- }
- emit input->receivedInput("AppleMediaKeys", keyPressed, keyIsPressed ? InputBase::KeyDown : InputBase::KeyUp);
- }
- @end
- // macOS private enum
- enum {
- MRNowPlayingClientVisibilityUndefined = 0,
- MRNowPlayingClientVisibilityAlwaysVisible,
- MRNowPlayingClientVisibilityVisibleWhenBackgrounded,
- MRNowPlayingClientVisibilityNeverVisible
- };
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- bool InputAppleMediaKeys::initInput()
- {
- m_currentTime = 0;
- m_pendingUpdate = false;
- m_delegate = [[MediaKeysDelegate alloc] initWithInput:this];
- if (NSClassFromString(@"MPNowPlayingInfoCenter")) {
- connect(&PlayerComponent::Get(), &PlayerComponent::stateChanged, this, &InputAppleMediaKeys::handleStateChanged);
- connect(&PlayerComponent::Get(), &PlayerComponent::positionUpdate, this, &InputAppleMediaKeys::handlePositionUpdate);
- connect(&PlayerComponent::Get(), &PlayerComponent::updateDuration, this, &InputAppleMediaKeys::handleUpdateDuration);
- void* lib = dlopen("/System/Library/PrivateFrameworks/MediaRemote.framework/MediaRemote", RTLD_NOW);
- if (lib) {
- #define LOAD_FUNC(name) \
- name = (name ## Func)dlsym(lib, "MRMediaRemote" #name)
- LOAD_FUNC(SetNowPlayingVisibility);
- LOAD_FUNC(GetLocalOrigin);
- LOAD_FUNC(SetCanBeNowPlayingApplication);
- if (SetCanBeNowPlayingApplication)
- SetCanBeNowPlayingApplication(1);
- }
- }
- return true;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- static MPNowPlayingPlaybackState convertState(PlayerComponent::State newState)
- {
- switch (newState) {
- case PlayerComponent::State::finished:
- return MPNowPlayingPlaybackStateStopped;
- case PlayerComponent::State::canceled:
- case PlayerComponent::State::error:
- return MPNowPlayingPlaybackStateInterrupted;
- case PlayerComponent::State::buffering:
- case PlayerComponent::State::paused:
- return MPNowPlayingPlaybackStatePaused;
- case PlayerComponent::State::playing:
- return MPNowPlayingPlaybackStatePlaying;
- default:
- return MPNowPlayingPlaybackStateUnknown;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- void InputAppleMediaKeys::handleStateChanged(PlayerComponent::State newState, PlayerComponent::State oldState)
- {
- MPNowPlayingPlaybackState newMPState = convertState(newState);
- MPNowPlayingInfoCenter *center = [MPNowPlayingInfoCenter defaultCenter];
- NSMutableDictionary *playingInfo = [NSMutableDictionary dictionaryWithDictionary:center.nowPlayingInfo];
- [playingInfo setObject:[NSNumber numberWithDouble:(double)m_currentTime / 1000] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
- center.nowPlayingInfo = playingInfo;
- [MPNowPlayingInfoCenter defaultCenter].playbackState = newMPState;
- if (SetNowPlayingVisibility && GetLocalOrigin) {
- if (newState == PlayerComponent::State::finished || newState == PlayerComponent::State::canceled || newState == PlayerComponent::State::error)
- SetNowPlayingVisibility(GetLocalOrigin(), MRNowPlayingClientVisibilityNeverVisible);
- else if (newState == PlayerComponent::State::paused || newState == PlayerComponent::State::playing || newState == PlayerComponent::State::buffering)
- SetNowPlayingVisibility(GetLocalOrigin(), MRNowPlayingClientVisibilityAlwaysVisible);
- }
- m_pendingUpdate = true;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- void InputAppleMediaKeys::handlePositionUpdate(quint64 position)
- {
- m_currentTime = position;
- if (m_pendingUpdate) {
- MPNowPlayingInfoCenter *center = [MPNowPlayingInfoCenter defaultCenter];
- NSMutableDictionary *playingInfo = [NSMutableDictionary dictionaryWithDictionary:center.nowPlayingInfo];
- [playingInfo setObject:[NSNumber numberWithDouble:(double)position / 1000] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
- center.nowPlayingInfo = playingInfo;
- [MPNowPlayingInfoCenter defaultCenter].playbackState = [MPNowPlayingInfoCenter defaultCenter].playbackState;
- m_pendingUpdate = false;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- void InputAppleMediaKeys::handleUpdateDuration(qint64 duration)
- {
- MPNowPlayingInfoCenter *center = [MPNowPlayingInfoCenter defaultCenter];
- NSMutableDictionary *playingInfo = [NSMutableDictionary dictionaryWithDictionary:center.nowPlayingInfo];
- [playingInfo setObject:[NSNumber numberWithDouble:(double)duration / 1000] forKey:MPMediaItemPropertyPlaybackDuration];
- center.nowPlayingInfo = playingInfo;
- m_pendingUpdate = true;
- }
|