Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between XTestFakeButtonEvent & XSendEvent

I'm trying to write simple mouse clicker for ubuntu via x11.

For first i wrote first variant (based on XSendEvent) of clicking procedure:

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

void mouseClick(int button)
{
    Display *display = XOpenDisplay(NULL);

    XEvent event;

    if(display == NULL)
    {
        std::cout << "clicking error 0" << std::endl;
        exit(EXIT_FAILURE);
    }

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

    event.type = ButtonPress;
    event.xbutton.button = button;
    event.xbutton.same_screen = True;

    XQueryPointer(display, RootWindow(display, DefaultScreen(display)), &event.xbutton.root, &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y, &event.xbutton.state);

    event.xbutton.subwindow = event.xbutton.window;

    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);
    }

    if(XSendEvent(display, PointerWindow, True, 0xfff, &event) == 0)
        std::cout << "clicking error 1" << std::endl;

    XFlush(display);

    event.type = ButtonRelease;
    event.xbutton.state = 0x100;

    if(XSendEvent(display, PointerWindow, True, 0xfff, &event) == 0)
        std::cout << "clicking error 2" << std::endl;

    XFlush(display);

    XCloseDisplay(display);
}

This code works fine on every application except chrome (with mozilla works fine too).

So i wrote second variant (based on XTestFakeButtonEvent):

#include <X11/extensions/XTest.h>

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

And this code works fine everyvere include chrome.

Calling of those functions is very simple

// XSendEvent variant
mouseClick(1);

// XTestFakeButtonEvent variant
SendClick(1, true);   // press lmb
SendClick(1, false);  // release lmb

1: help me to understand what i'm doing wrong (or what wrong in chrome maybe) in first variant.

1.1: I think that i'm trying to send event not for needed window, when i open display with XOpenDisplay(NULL);. Does chrome have different connection system with x11 server?

2: is it good idea to use second variant in applications? It pretty short and works fine with every app i have)

P.S. to compile this code you need add -lX11 -lXtst libs

like image 603
goldstar Avatar asked Feb 02 '17 21:02

goldstar


1 Answers

XSendEvent produces events that are marked as sent. Events sent by the server are not marked.

   typedef struct {
           int type;
           unsigned long serial; 
           Bool send_event;        // <----- here
           Display *display;
           Window window;
   } XAnyEvent;

Some applications ignore events that have this flag set, for security reasons. Think of malware that somehow gets access to your X11 server — it can trick any application into doing whatever it wants by sending those events.

It is perfectly OK to use the second variant on your own machine, but it relies on an extension that can be disabled (again, for security reasons) and so not necessarily works on other people's X11 servers.

like image 50
n. 1.8e9-where's-my-share m. Avatar answered Sep 30 '22 16:09

n. 1.8e9-where's-my-share m.