browser-media-keys
browser-media-keys copied to clipboard
Add support for Mac OS X
From what I can tell, the add-on currently doesn't support media keys within Mac OS X (I tested it with Youtube on Firefox 39.0, running OS X 10.8.5).
Thanks for letting us know about this. I'll try to look into it on my friend's Mac next week.
This might help: https://github.com/nightingale-media-player/nightingale-hacking/tree/sb-trunk-oldxul/extensions/apple-mediakeys http://wiki.getnightingale.com/doku.php?id=add-ons#apple_keyboard_media_key_support
It is an extension for Nightingale Media Player (XULRunner-based application) that allows the use of media keys on Mac OS X. The extension needs to be compiled with XCode.
Thanks for the links; I will check them out, probably next week some time.
I tested the plugin on my friend's MacBook air and found that iTunes was hogging all the media key actions so that's probably why it's not working at all.
Here is how it was done with binary components: https://github.com/mstange/mediakeysappleremotesimfy/issues/1
That same issues shows how to do it with Objective-C, although this method may require accessibility. It is likely also possible to accomplish this with Carbon's RegisterEventHotKey. This Carbon routine has not been deprecated as no alternative exists. Here is a topic that shows how: http://stackoverflow.com/questions/4807319/register-hotkey
This is a great repo showing how to tap into CoreFoundation and Carbon routines: https://github.com/philikon/osxtypes
This is some great work!
Hey @carlin-q-scott I'm real excited to see OSX support for this, from my last post how feasible does this look? I love how you do all the work from ChromeWorkers!
I looked at it a little bit and determined that it was too much of a commitment for me. If someone else such as yourself, @Noitidart wants to implement this I'd gladly accept the pull request.
Aw man, I have a lot of projects going on, and have requests from others to help them out. I can add this in line, and will work on it if I have to. It's very close to being done as you did excellent work on the Linux/Windows part.
Here's me setting up event tap on mouse from js-ctypes: https://github.com/Noitidart/MouseControl/blob/master/modules/workers/MMSyncWorker.js#L937-L1144
What I do know is that, the obj-c method cannot run from a chromeworker, that has to be on the mainthread.
What I did above seems to be exact same as what is being done here: https://github.com/mstange/SPMediaKeyTap/blob/master/SPMediaKeyTap.m#L75
The documentation on this says: https://developer.apple.com/library/mac/documentation/Carbon/Reference/QuartzEventServicesRef/index.html#//apple_ref/c/func/CGEventTapCreate
Discussion
Event taps receive key up and key down events if one of the following conditions is true:
The current process is running as the root user.
Access for assistive devices is enabled. In OS X v10.4, you can enable this feature using System Preferences, Universal Access panel, Keyboard view.
Firefox runs as root so we're gold here.
As it seems you will have to use CoreFoundation (with maybe mix of some objc) this will come in handy: https://github.com/philikon/osxtypes/
This screenshot procedure of mine uses CoreFoundation and Objc mix: https://github.com/Noitidart/NativeShot/blob/master/modules/workers/MainWorker.js#L1424
If you do get a chance to work on this before I do, if you need help setting up a mac vm i can help with setting up osx 10.10.1 on oracle virtualbox.
Thanks for all the info @Noitidart and I understand that your time is also valuable. I considered setting up OSX on a VM but a friend of mine is willing to lend me his Macbook Air so that won't be necessary.
Wow thanks so much if you are able to do any of the OS X stuff - I really really appreciate it. I can very much help out. I can also make this a droppable into other peoples addons. :) Via npm and normal bootstrap.
I needed to add global hotkey support for an addon of mine. The hotkey i need, is if user hits the usual print screen button from anywhere it will pull up my screenshot addon. On Mac the combo for screenshot is Cmd + Shift + 3.
I made great progress on Mac. But I'm stuck I keep getting error on RegisterEventHotKey
which means "invalid parameter(s)". I was wondering if you have some time it would be nice if you could put your eyes on this :)
https://github.com/Noitidart/NativeShot/blob/12b460cdf23236cc8ad1dcb762bba66cb0c634f5/modules/hotkey/HotkeyWorker.js#L290
Hey @carlin-q-scott I split it to another repository so its not cluttered by other code: https://github.com/Noitidart/System-Hotkey
The code we need to edit is in - https://github.com/Noitidart/System-Hotkey/blob/master/modules/hotkey/HotkeyWorker.js
To edit the types module that is in this repository - https://github.com/Noitidart/ostypes
Would be absolutely fantastic if you could help.
The linux vesion isn't working either, but I'm trying to use XCB for that, not DBus as you did in Media Keys.
Windows works great, I used your old technique. :)
I got a headache from debugging the Linux and OS X stuff for the past few days so posted for help - https://discourse.mozilla-community.org/t/system-wide-global-hotkey-help-on-xcb-linux-and-osx-carbon/7579
Wooohoo carlin here is mac support!! All thanks to @arai-a and @KenThomasses - So easy. But unfortunaately I couldn't get it to work from ChromeWorker, so this has to run on mainthread:
https://gist.github.com/Noitidart/7fd5569cd64a000e3027966a2ca90a36
The hotkey in that gist is command + shift + spacebar. The number 49
is key for spacebar. To get code for anything else, run this gist:
https://gist.github.com/Noitidart/8645b47b0e46a0eb284e
And then with firefox focused hit any key it will log it.
Super cool stuff!! :)
Any news? @Noitidart @carlin-q-scott
Somehow I missed Noitdart's last update. I can try finishing off his Gist sometime this week I think.
@carlin-q-scott That gist is complete. I am using it in my addon NativeShot too hook into printscrn across all systems (mac doesnt have print screen they use cmd + 3), check it out - https://github.com/Noitidart/NativeShot/blob/master/bootstrap.js#L3149
Fully functional.
@Noitidart Well it's complete in that it registers a hotkey but I need to register a set of hotkeys and bind them to my app logic. I will also take a stab at using a ChromeWorker as I'd prefer it to run independent of the Firefox UI.
Thank you for sharing such complete code and a helper to figure out the key codes.
My pleasure! For Mac my tests showed it had to be on main thread. I asked around but didn't get a definitive answer. If you can get the mac portion to work from a ChromWorker that would superb! I would definitely change my method to yours!
On Mon, Jun 6, 2016 at 7:12 PM, Carlin Scott [email protected] wrote:
@Noitidart https://github.com/Noitidart Well it's complete in that it registers a hotkey but I need to register a set of hotkeys and bind them to my app logic. I will also take a stab at using a ChromeWorker as I'd prefer it to run independent of the Firefox UI.
Thank you for sharing such complete code and a helper to figure out the key codes.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/carlin-q-scott/browser-media-keys/issues/17#issuecomment-224145379, or mute the thread https://github.com/notifications/unsubscribe/AGE8iavnLchxYyKb7Q-IPrlAs6mvm4ROks5qJNOJgaJpZM4FlD8T .
@Noitidart So media key events are not key events but system events which don't have the keyCode merthod but rather a keycode property. So when your code tries to get the keyCode it crashes Firefox. At least that's my interpretation of the Objective-C docs and this Swift code I found that handles media keys.
Here's my modifications to your keycode capture gist: https://gist.github.com/carlin-q-scott/5a5890a9f6d3fd7902164b44b10ab9a7. I would modified yours but thought you'd want to share it elsewhere without the change in the event type being captured.
I'm not finding the Objective-C docs terribly readable so I'm not sure how to modify the code that gets the keycode to use the new class member signature.
Wow very interesting find. Thanks Carlin.
So to get it to work for media key events, you just have to change NSKeyDownMask
to NSSystemDefinedMask
on this line:
var rez_add = objc_msgSend(NSEvent, addLocalMonitorForEventsMatchingMask, TYPES.NSEventMask(CONST.NSKeyDownMask), myBlock_c.address());
?
It looks like you are still accessing keyCode
though. Or does the C
have to be c
?
In Objective-C if the selector has no colons (:
) its a prop. If it has colons then its a method.
I linked your gist for media keys from my original gist, thanks brother this was some awesome team work:
Note To use with Media keys change NSKeyDownMask to NSSystemDefinedMask thanks to @Carlin-Q-Scott - copy paste gist - https://gist.github.com/carlin-q-scott/5a5890a9f6d3fd7902164b44b10ab9a7
@Noitidart Yeah, I figured out the NSSystemDefinedMask bit but getting the keyCode doesn't work, even with that slight casing change.
Try addGlobal instead of addLocalMonitorForEventsMatchingMask it's just a guess that system events may not be local.
This is an excellet article I think all we need is here - http://weblog.rogueamoeba.com/2007/09/29/
You need to check subtype
too and ensure that it is 8
then it should have a keyCode
for the media key but not in the keyCode
field it will be in the data1
field.
if( [event type] == NSSystemDefined && [event subtype] == 8 )
{
int keyCode = (([event data1] & 0xFFFF0000) >> 16);
int keyFlags = ([event data1] & 0x0000FFFF);
int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA;
int keyRepeat = (keyFlags & 0x1);
This makes total sense, as it follows that only NSKeyEvents
would have keyCode
. So NSSystemDefined
would be obtained via data1
. Cool stuff.
This article also states a very important note:
One other thing to note is that these keys act as “global hot keys”, every application receives events for them, not merely just the foreground application. This whole public domain sample code is available in a file here.
Meaning we have no need for RegisterHotKeyEvent
for a global, as by default these are global events. Very cool.
Honestly that swift stuff doesn't make sense too me. I haven't took the time to learn it yet.
Here are the media key magic numbers you need:
# hidsystem/ev_keymap.h
NX_KEYTYPE_SOUND_UP = 0
NX_KEYTYPE_SOUND_DOWN = 1
NX_KEYTYPE_PLAY = 16
NX_KEYTYPE_NEXT = 17
NX_KEYTYPE_PREVIOUS = 18
NX_KEYTYPE_FAST = 19
NX_KEYTYPE_REWIND = 20
I spent hours trying to figure out how to de-refence the pointers to get the data1 value. I didn't realize that the cast function de-references pointers and that I had to access the value
property on the result to get the native js value. I've updated the gist I posted with these changes so that it's printing out all the important values mentioned by @Noitidart.
Maybe i can wrap this up tomorrow but realistically this weekend.
This is looking like its coming out nicely! Awesome team work! Yeah the cast method is pretty cool but no tutorial is going to specifically tell you when you need to cast. It's just based on need based on what CData values we get in our ctypes (which ultimate depends on how we set up the types and how js-ctypes reads them as UInt64 or etc). That's why I console.log
a lot of stuff.
In the code:
cEventType = ctypes.cast(cEventType, TYPES.NSUInteger).value;
var eventData = objc_msgSend(objc_arg1__aNSEventPtr, data1);
I think you should do a test on cEventType
before trying to get the data1
field. As I'm not sure if all event types will have data1
. If it doesn't, it will probably crash, or give a null
pointer (0x0
) but with objc my usual experience is it crashes.
Haha, yes, it usually crashes if I do anything wrong :(.
In the actual code I'm only going to handle subtype 8 but I'm also trying to figure out if I can use that EventTypeSpec you used for the hotkeys to filter the events.
Superior work brother! If you can get media keys working with the carbon method (EventTypeSpec
/RegisterHotKeyEvent
) that would be ideal because this doesn't have the overhead of triggering for all the other keys/system events.
Re getting the objc method or the carbon method into ChromeWorker's - I'm not sure if either method would be easier. I was not able to get either method working from a worker. If you can pull that off that would rock!
So it looks like iTunes gets the events as well, even when I return null from the callback. The official documentation implies that returning nil will kill the event chain but maybe iTunes is called before Firefox.
I've checked in what i have so far into my master branch.