26

How can I add an event or other method to listen to keypresses on a gnome shell extension? e.g. show a dialog with each key press showing the pressed key?

I can not find any example. The documentation mentions a keyboard module, but with that common name searching is hard.

Class explanation
...
- General utils
   - Keyboard: Manage and define the keyboard events, etc. for gnome shell. 

(read above as a quote from the docs linked above. it is styled as code because the quote styling for some reason do not preserve line breaks in this site)

I found some extensions using the bellow code for results similar to what i'm asking, but i, again, failed to find docs for the specific classes and methods:

workViewInjections['_init'] = injectToFunction(WorkspacesView.WorkspacesView.prototype, '_init', function(width, height, x, y, workspaces) {
        this._pickWorkspace = false;
        this._pickWindow = false;
        this._keyPressEventId = global.stage.connect('key-press-event', Lang.bind(this, this._onKeyPress));                                                                                
        this._keyReleaseEventId = global.stage.connect('key-release-event', Lang.bind(this, this._onKeyRelease));
        connectedSignals.push({ obj: global.stage, id: this._keyPressEventId });
        connectedSignals.push({ obj: global.stage, id: this._keyReleaseEventId });
        });

Also, no class named keyboard anywhere there...

--

edit1: more searching... i think i may have to use the Clutter api. but again, not much examples or documentation for that. farthest i went was this

edit2: more searching. looking on the gnome shell source code, on the main ui tree, i think the answer is to use the barelly mentioned global object that is available to the extension code. e.g.

global.connect('key-press-event', function(if, i, know, the, signature){} );

2

2 Answers 2

5
+200

I came across this snippet in gcampax's gtk-js-app template some time ago, which may be related to what you're doing:

// Due to limitations of gobject-introspection wrt GdkEvent and GdkEventKey,
// this needs to be a signal handler
this.connect('key-press-event', Lang.bind(this, this._handleKeyPress));

and

_handleKeyPress: function(self, event) {
    return this.main_search_bar.handle_event(event);
},

I haven't had a need to use keyboard events yet, and this is Gtk in GJS, but the same limitation may be affecting gnome-shell extensions.

UPDATE

I've been doing some keybinding stuff lately, and if attaching a signal handler to the global object is working, you can do something like this:

global.display.connect("key-press-event", (widget, event, user_data) => {
    let [success, keyval] = event.get_keyval(); // integer
    let keyname = Gdk.keyval_name(keyval); // string keyname

    if (keyname === "Control_L") {
        // Dialog code or eg. this.keys_array.push("<Ctrl>");
    }
});

There's also some Shell keybinding code here and some shell-global documentation here that might give you more clues. Wish I could help more but I'm wrestling my own GJS atm ;)

ADDENDUM

There is a good answer here with an example class with informative logging, as well as a speculative explanation. I've also found this functionality is exposed over DBus which might be more convenient in some cases:

Bus Name: org.gnome.Shell -> Path: /org/gnome/Shell -> Interface: org.gnome.Shell

Relevant Methods:

  • GrabAccelerator(String accelerator, UInt32 flags) -> (UInt32 action)
  • UngrabAccelerator(UInt32 action) -> (Boolean success)

Signal:

  • AcceleratorActivate(UInt32, Dict of {String, Variant})
Sign up to request clarification or add additional context in comments.

5 Comments

Interesting, the main method, ... .connect('key-press-event', ... is not mentioned on the shell-global doc.
and on the example linked, they use gobal.display.add_keybinding()... the shell-global list that property as being a Metacity display object. But searching for that term, i only find it on the shell object for gnome source comments.
Best I could find is people.gnome.org/~tthurman/docs/metacity/… MetaDisplay, but it doesn't have an add_keybinding() method.
After some pointed searching, I found an answer on superuser.stackexchange.com that gave me everything I need. I think it will probably do it for you too.
global.display.connect("key-press-event", ...) will not work because "There never was such a signal on MetaDisplay"
0

For me global.stage.connect("key-press-event", _handleKeyPress) did the trick

1 Comment

Doesn't work for me when I type something inside application windows

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.