Below is a copy of my answer here. I tested it only in Gnome 3.22
TL DR
Here is the class:
KeyManager: new Lang.Class({ Name: 'MyKeyManager', _init: function() { this.grabbers = new Map() global.display.connect( 'accelerator-activated', Lang.bind(this, function(display, action, deviceId, timestamp){ log('Accelerator Activated: [display={}, action={}, deviceId={}, timestamp={}]', display, action, deviceId, timestamp) this._onAccelerator(action) })) }, listenFor: function(accelerator, callback){ log('Trying to listen for hot key [accelerator={}]', accelerator) let action = global.display.grab_accelerator(accelerator) if(action == Meta.KeyBindingAction.NONE) { log('Unable to grab accelerator [binding={}]', accelerator) } else { log('Grabbed accelerator [action={}]', action) let name = Meta.external_binding_name_for_action(action) log('Received binding name for action [name={}, action={}]', name, action) log('Requesting WM to allow binding [name={}]', name) Main.wm.allowKeybinding(name, Shell.ActionMode.ALL) this.grabbers.set(action, { name: name, accelerator: accelerator, callback: callback }) } }, _onAccelerator: function(action) { let grabber = this.grabbers.get(action) if(grabber) { this.grabbers.get(action).callback() } else { log('No listeners [action={}]', action) } } })
And how do you use it:
let keyManager = new KeyManager() keyManager.listenFor("<ctrl><shift>a", function(){ log("Hot keys are working!!!") })
You will need to import:
const Lang = imports.lang const Meta = imports.gi.Meta const Shell = imports.gi.Shell const Main = imports.ui.main
Description
Maybe I'm wrong, but this is what I found out in the last couple of days.
First of all, this is Mutter, which is responsible for listening to hot keys. Mutter is an environment for creating window managers, it is not a window manager itself. Gnome Shell has a class written in JS called the โWindow Managerโ โthis is a real window manager that uses the mutter inside to do all the low-level stuff. Mutter has a MetaDisplay object. This is the object that you use to request a listen to a hotkey. But! But Mutter will require Window Manager to approve the use of this hotkey. So what happens when a hotkey is pressed? - MetaDisplay generates a filter-binding event. - Window Manager in Gnome Shell checks if this hotkey is enabled. - Window Manager returns the corresponding MetaDisplay value. - If it is allowed to process this hotkey, MetaDisplay generates an "accelerator activated" event, - your extension should listen to this event and determine by the action id whose hotkey is activated.