sidorares/node-x11

How can I listen to the root events?

Closed this issue · 20 comments

arnm commented

I see the examples show how to listen to a specific window's events but is there a way to listen to the root window's events?

I need to manage global events.

You need to set root window event mask to your events set using ChangeWindowAttributes:

var x11 = require('x11');
x11.createClient(function(err, display) {
    var X = display.client;
    var root = display.screen[0].root;
    X.ChangeWindowAttributes(wid, { eventMask: x11.eventMask.PointerMotion|x11.eventMask.KeyPress });
    X.on('event', function(ev) {
        console.log(ev);
    });
});

Each window keeps separate copy of events mask per client, so here you are not changing global root event mask, but telling it "this is set of events this client is after". In xlib this is usually done with XSelectInput call (wich internally does ChangeWindowAttributes request).

arnm commented

The code you posted does not work. Where is wid coming from? Did you mean to put root?

It does not work for me with root as the first parameter to ChangeWindowAttributes.

Yes, wid should be root
Works for me as expected:

root-events

arnm commented

Ok. So what is the environment you ran the code in? I am running i3 window manager, could that possibly cause a conflict? The code "works" as in I do not get any errors but I do not get the constant stream of events you got. I have only seen one event's output displayed while running the code. I also tried in Gnome 3 but I got the same result. I'm a little confused because it works as expected when I create a window and listen for it's events.

Edit: Ok so since I was running it in i3 the windows are maximized by default. I placed my windows in floating mode which allowed me to drag my mouse around the desktop. When I dragged my mouse around the desktop I got the constant stream of MotionNotify events but no key press events.

That's probably because root window is covered by another window. Try to do "xwininfo", click on desktop and compare output with "xwininfo -root". In gnome, there is full screen "nautilus" window. Also composite manager might prevent events from bubbling ( it usually opens overlay window on top ).

Try to run it inside Xnest or Xephyr server - my example gif captured in Xephyr on mac/xorg

arnm commented

Yes I just came to the same conclusion. So is there a way I can get a stream of the events for all the windows?

I need to process all events.

Which events are you interested in? I don't think there is an easy way ( the only one comes to me is very hardcore: monitor x11 socket / port 6000 for all packets and extract information you need )

arnm commented

I most importantly interested in KeyPress and KeyRelease events. I'm was looking at this as an alternative to reading straight from /dev/input/* which requires root

You can do "GrabKeyboard" (but don't forget to post key events manually to a focused window) - read http://tronche.com/gui/x/xlib/input/XGrabKeyboard.html

arnm commented

Does this lib provide GrabModeAsync or GrabModeSync? How would I specify the pointer and keyboard modes?

Yes. https://github.com/sidorares/node-x11/blob/master/lib/corereqs.js#L512
According to http://www.x.org/releases/X11R7.6/doc/xproto/x11protocol.txt
GrabModeAsync is 1 and GrabModeSync is 0 for both pointer mode and keyboard mode

arnm commented

I see XGrabKeyboard being used with XNextEvent. Is this available?

Yes. client.on('event', handler)

arnm commented

XGrabKeyboard is not going to work for me because it is still specific to a window. I need to process global key events for all windows.
I believe XQueryKeymap is the right approach.

Something similar to this python implementation here.

Does this lib support it?

No, not yet (feel free to add: https://github.com/sidorares/node-x11/blob/master/lib/corereqs.js , format is

QueryKeymap
     1     44                              opcode
     1                                     unused
     2     1                               request length

▶
     1     1                               Reply
     1                                     unused
     2     CARD16                          sequence number
     4     2                               reply length
     32     LISTofCARD8                    keys

)

Note that you need to poll keyboard with QueryKeymap request and might miss some keypresses if they happen to be between polls

I want to track the mouse.
I'm using Gnome, but i believe we can get a generic and simple way.

Why events don't bubble? Or... node-x11 can't force composite wms to bubble events to be listen at root?

can you see them with xev(1) ?
node-x11 only can see what network protocol allows. If events ton't reach root window you won't see them. Does it work for you without wm? (or without composite manager?)

I could not find how to get this information with xev, but i can do with xdotool getmouselocation.
So, what dark magic is xdotool using? :-)