Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capture Mac media control keys in a Chrome extension

Two part question:

  1. Is there a way to capture (react to the pressing of) the media playback control keys on a Mac keyboard (previous, play/pause, next) in a Google Chrome extension using strictly JavaScript?
  2. if (answerToQuestion1 === "no") is there a way to do it using some sort of native plugin (C/C++)?

I know that this should be possible, as Unity Music Media Keys does it (albeit I know that they're using a native plugin).

What I've looked at so far is this plugin, which claims to do it, but actually requires FunctionFlip to make the keys act as function keys, and reacts to the pressing of F7, F8, and F8.

like image 346
Whymarrh Avatar asked Oct 01 '12 11:10

Whymarrh


2 Answers

1 - nope =[

2 - Whoa - holy crap. I hadn't seen this extension before, so thank you for that. I dug into it a bit, and it seems that they install a .plugin on osx and a dll for windows support.

The decompiled plugin is only a couple hundred lines - https://gist.github.com/3849247.

They are using https://github.com/nevyn/SPMediaKeyTap as a way to plug in directly to the media keys (on os x). They are relaying that through a local socket.io server running on port 12345 to the browser, and the plugin is listening for events fired on it.

supppper neat.

EDIT: This is now natively supported in chrome

like image 198
Patrick Avatar answered Nov 15 '22 13:11

Patrick


Eventually I managed to accomplish what I was getting at. The final Chrome Extension can be see on GitHub.

How does it work?

The extension I originally linked to required that the function keys be "flipped" to actually be function keys and not have a special purpose, but doing so requires an extra keystroke to then perform the special functions (such as controlling keyboard backlights, volume, etc).

With great help from Patrick's answer, I used parts from nevyn/SPMediaKeyTap to capture the key presses outside the extension and libwebsockets to fire them over to the extension:

- (void) handleKeyCode: (int) kcode withKeyState: (int) kstate
{
    if (kstate) {
        return; // keydown
    }
    // keyup
    int len = 1;
    unsigned char data[LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING];
    data[LWS_SEND_BUFFER_PRE_PADDING] = kcode;
    for (int i = 0; i < num_clients; i++) {
        libwebsocket_write(clients[i], &data[LWS_SEND_BUFFER_PRE_PADDING], len, LWS_WRITE_TEXT);
        NSLog(@"Sent %d", kcode);
    }
}

Inside Chrome, the extension simply injects the appropriate piece of JS into the host page:

this.onmessage = function (message) {
    var keyCode = message.data.charCodeAt(0);
    if (keyCode === 20) {
        inject(function () {
            window.R.player.previous();
        });
    }
    if (keyCode === 16) {
        inject(function () {
            window.R.player.playPause();
        });
    }
    if (keyCode === 19) {
        inject(function () {
            window.R.player.next();
        });
    }
};
like image 25
Whymarrh Avatar answered Nov 15 '22 13:11

Whymarrh