System wide global hotkey - Help on XCB/Linux and Carbon/OSX APIs

Seeing the awesome collaboration between the guys here - https://discourse.mozilla-community.org/t/tear-off-tab-with-sdk/7085/35 - I’m hoping I could get some collaboration too :slight_smile:

For one of my addons I need a global hotkey. Meaning from wherever they are, if they hit a the key combination, it will trigger my addon. I am trying to do this off the mainthread, so in a ChromeWorker.

I am making this “module” style so others who find this useful can use it as well. My module is here - https://github.com/Noitidart/System-Hotkey - you can make this an XPI and install. On Windows, hitting the “Print Screen” button will trigger a message to be logged in the console.

The way to do this is:

  • Windows - RegisterHotkey
  • Linux - xcb_grab_key
  • Mac - RegisterEventHotKey - This is a Carbon API but it is the way to register hotkeys, everyone says so, Apple hasn’t deprecated it. ObjC does not have a method yet to do it.

I knocked out Windows, that just worked on first try. However I was stuck on Linux and Mac OS X.

Linux - XCB - status: no events catching

On Linux I was having a tough time. It worked with this X11 code:

Hotkey is Space bar

// var rez_init = ostypes.API('XInitThreads')(); // This function returns a nonzero status if initialization was successful; otherwise, it returns zero. On systems that do not support threads, this function always returns zero. 
// console.log('rez_init:', rez_init);

// based on https://jnativehook.googlecode.com/svn/branches/test_code/linux/XGrabKey.c
//    i copied it here as it might come in handy - https://gist.github.com/Noitidart/e12ad03d21bbb91cd214

//Try to attach to the default X11 display.
var display = ostypes.HELPER.cachedXOpenDisplay();

//Get the default global window to listen on for the selected X11 display.
var grabWin = ostypes.HELPER.cachedDefaultRootWindow();
// var rez_allow = ostypes.API('XAllowEvents')(display, ostypes.CONST.AsyncKeyboard, ostypes.CONST.CurrentTime);
// console.log('rez_allow:', rez_allow);
// XkbSetDetectableAutoRepeat(display, true, NULL);

//Find the X11 KeyCode we are listening for.
var key = ostypes.API('XKeysymToKeycode')(display, ostypes.CONST.XK_Space);
console.log('key:', key);
OSStuff.key = key;

//No Modifier
var rez_grab = ostypes.API('XGrabKey')(display, key, ostypes.CONST.None, grabWin, true, ostypes.CONST.GrabModeAsync, ostypes.CONST.GrabModeAsync);
console.log('rez_grab:', rez_grab);

// var rez_sel = ostypes.API('XSelectInput')(display, grabWin, ostypes.CONST.KeyPressMask);
// console.log('rez_sel:', rez_sel);

However x11 is not thread safe, even though I called XInitThreads it would crash. So I switched to XCB. However the xcb_grab_key call is not grabbing the key. I am using the Space Bar as a hotkey.

Mac OS X - not working - status: invalid params on RegisterEventHotKey

This line is where I get stuck:

var rez_reg = ostypes.API('RegisterEventHotKey')(49, ctypes_math.UInt64.add(ctypes.UInt64(ostypes.CONST.shiftKey), ctypes.UInt64(ostypes.CONST.cmdKey)), gMyHotKeyID, rez_appTarget2, 0, gMyHotKeyRef.address());

Hotkey is spacebar

It returns a OSStatus value of 50 which is errSecAllocate which means “invalid parameters passed to method” - https://developer.apple.com/library/mac/documentation/Security/Reference/keychainservices/index.html#//apple_ref/c/econst/errSecAllocate

There is a possibility that RegisterEventHotKey will not work from the spawned thread. However we won’t know till we can get passed this “invalid params” error. I tried this same code on main thread and get the same error.

My question

I created this as a module you can drop in. Maybe others can find it useful. But I was wondering if any Carbon experts and XCB experts could help me tackle this situation.

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 - I included this ino the System-Hotkey repository as a git submodule.

So the mac hotkey is working. I was passing in something as a 64bit long when it should have been 32bit, ouch.

But I’m still stuck on the Linux. I’m using xcb, this code here SHOULD grab the a lower case a key. Meaning whenever you hit the a button it should have no effect. However it’s not working.

My code is here, you can copy paste it and run from scratchpad -

I was wondering if there are any XCB experts out here who would be able to help troubleshoot this snippet?

I hear Carbon no longer works for Firefox, which is 64-bit now.

1 Like

Thanks very much for your reply!

I actually figured this out and also the linux one phew! Was such a silly thing.

For global hotkey, the Carbon API is still accepted. Apple admits they haven’t introduced a feesible solution in ObjC so have continued to support this carbon api into 64bit. I asked on Stackoverflow the exact same thing. I’ll go grab that link and paste it here.