sidorares / node-x11

X11 node.js network protocol client
MIT License
519 stars 72 forks source link

How can I listen to the root events? #69

Closed arnm closed 10 years ago

arnm commented 10 years ago

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.

sidorares commented 10 years ago

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 10 years ago

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.

sidorares commented 10 years ago

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

root-events

arnm commented 10 years ago

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.

sidorares commented 10 years ago

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 10 years ago

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.

sidorares commented 10 years ago

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 10 years ago

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

sidorares commented 10 years ago

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 10 years ago

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

sidorares commented 10 years ago

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 10 years ago

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

sidorares commented 10 years ago

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

arnm commented 10 years ago

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?

sidorares commented 10 years ago

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

aurium commented 9 years ago

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?

sidorares commented 9 years ago

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?)

aurium commented 9 years ago

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? :-)

polpo commented 9 years ago

Looks like all xdotool does is use XQueryPointer: https://github.com/jordansissel/xdotool/blob/f5309ecea01463b3bddb4964978631cd201fb7c6/xdo.c#L866

aurium commented 9 years ago

Nice... https://tronche.com/gui/x/xlib/window-information/XQueryPointer.html I believe that is it. :-)