Reputation: 58097
Is there a way to make my app respond to the play/pause button on Mac?
EDIT:
Using the suggested code,I get this console message:
Could not connect the action buttonPressed: to target of class NSApplication
Why would that be?
Upvotes: 13
Views: 5094
Reputation: 61228
I accomplished this in my own application by subclassing NSApplication (and setting the app's principal class to this subclass). It catches seek and play/pause keys and translates them to specific actions in my app delegate.
Relevant lines:
#import <IOKit/hidsystem/ev_keymap.h>
- (void)sendEvent:(NSEvent *)event
{
// Catch media key events
if ([event type] == NSSystemDefined && [event subtype] == 8)
{
int keyCode = (([event data1] & 0xFFFF0000) >> 16);
int keyFlags = ([event data1] & 0x0000FFFF);
int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA;
// Process the media key event and return
[self mediaKeyEvent:keyCode state:keyState];
return;
}
// Continue on to super
[super sendEvent:event];
}
- (void)mediaKeyEvent:(int)key state:(BOOL)state
{
switch (key)
{
// Play pressed
case NX_KEYTYPE_PLAY:
if (state == NO)
[(TSAppController *)[self delegate] togglePlayPause:self];
break;
// Rewind
case NX_KEYTYPE_FAST:
if (state == YES)
[(TSAppController *)[self delegate] seekForward:self];
break;
// Previous
case NX_KEYTYPE_REWIND:
if (state == YES)
[(TSAppController *)[self delegate] seekBack:self];
break;
}
}
Edit:
Swift 4:
override func sendEvent(_ event: NSEvent)
{
if event.type == .systemDefined &&
event.subtype == .screenChanged
{
let keyCode : Int32 = (Int32((event.data1 & 0xFFFF0000) >> 16))
let keyFlags = (event.data1 & 0x0000FFFF)
let keyState = ((keyFlags & 0xFF00) >> 8) == 0xA
self.mediaKeyEvent(withKeyCode: keyCode, andState: keyState)
return
}
super.sendEvent(event)
}
private func mediaKeyEvent(withKeyCode keyCode : Int32, andState state : Bool)
{
guard let delegate = self.delegate as? AppDelegate else { return }
switch keyCode
{
// Play pressed
case NX_KEYTYPE_PLAY:
if state == false
{
delegate.musicPlayerWC.handleUserPressedPlayButton()
}
break
// Rewind
case NX_KEYTYPE_FAST:
if state == true
{
delegate.musicPlayerWC.handleUserPressedNextSongButton()
}
break
// Previous
case NX_KEYTYPE_REWIND:
if state == true
{
delegate.musicPlayerWC.handleUserPressedPreviousSongButton()
}
break
default:
break
}
}
Upvotes: 17
Reputation: 4276
In case anyone comes looking, there is sample code to do this here. This approach does allow you to "eat" the events they do not reach iTunes or other media-key-aware apps.
But be warned that event taps are not allowed by the sandbox, so this won't work in the App Store. If anyone has a workaround for that I'd love to hear it.
Upvotes: -1
Reputation: 654
Check this: https://gist.github.com/gauravk92/546311 Works perfectly.
As example, this repo uses it: https://github.com/onepill/PauseIt
Upvotes: -1
Reputation: 70775
Here's a great article on the subject: http://www.rogueamoeba.com/utm/2007/09/29/
Upvotes: 3