Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending X11 click event doesn't work with some windows

Tags:

c

x11

The following snippet of code works most of the time, except in certain windows. For instance, under the latest Ubuntu it does not work for selecting folders in the file explorer. It seems to work just about everywhere else, but this gap is significant. I suspect it has to do with how I am using XQueryPointer, but I've tried nearly every example I can find. If I use the computer's mouse instead, it work's fine. FYI: I've already tried the answers to these questions: Sending Programmatic events Capuring Mouse Input but they don't work any different...

Here's the code:

#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

void SendClick(int button, int down) {
    Display *display = XOpenDisplay(NULL);
    XEvent event;

    if(display == NULL)
    {
        return;
    }

    memset(&event, 0, sizeof(event));

    event.xbutton.button = button;
    event.xbutton.same_screen = True;
    event.xbutton.subwindow = DefaultRootWindow (display);

    while (event.xbutton.subwindow)
    {
      event.xbutton.window = event.xbutton.subwindow;
      XQueryPointer (display, event.xbutton.window,
             &event.xbutton.root, &event.xbutton.subwindow,
             &event.xbutton.x_root, &event.xbutton.y_root,
             &event.xbutton.x, &event.xbutton.y,
             &event.xbutton.state);
    }

    event.type = down ? ButtonPress : ButtonRelease;

    XSendEvent(display, PointerWindow, True, down ? ButtonPressMask : ButtonReleaseMask, &event); 

    XFlush(display);

    XCloseDisplay(display);
}
like image 932
Phil Avatar asked Oct 03 '12 02:10

Phil


1 Answers

Thanks to ninjalj's comment above for putting me on the right track. I don't like the idea of relying on an extension to do this and the extra dependency it creates, but it is a pretty standard extension too. Works perfect...

For those running into the same issue as me, the following code block replaces the code I was using before and works well:

#include <X11/extensions/XTest.h>

void SendClick(int button, Bool down) {
    Display *display = XOpenDisplay(NULL);
    XTestFakeButtonEvent(display, button, down, CurrentTime);
    XFlush(display);
    XCloseDisplay(display);
}

Much shorter!

For Ubuntu, don't forget to install the libxtst-dev package. Be sure to add -lXtst to your LDFLAGS.

like image 144
Phil Avatar answered Sep 21 '22 05:09

Phil