2017-02-02 1 views
0

J'essaie d'écrire un simple clicker de souris pour Ubuntu via x11.Différence entre XTestFakeButtonEvent et XSendEvent

Pour la première variante i a d'abord écrit (basé sur XSendEvent) de la procédure en cliquant sur:

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

Ce code fonctionne très bien sur toutes les applications sauf chrome (avec des œuvres mozilla bien aussi).

j'ai donc écrit deuxième variante (basée sur 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); 
} 

Et ce code fonctionne très bien everyvere comprennent chrome.

appel de ces fonctions est très simple

// XSendEvent variant 
mouseClick(1); 

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

1: aidez-moi à comprendre ce que je fais mal (ou ce mal dans le chrome peut-être) dans la première variante.

1.1: Je pense que j'essaye d'envoyer l'événement pas pour la fenêtre nécessaire, quand j'ouvre l'affichage avec XOpenDisplay (NULL) ;. Le chrome a-t-il un système de connexion différent avec le serveur x11? 2: est-ce une bonne idée d'utiliser une deuxième variante dans les applications? C'est assez court et fonctionne bien avec chaque application que j'ai)

P.S. Pour compiler ce code, vous devez ajouter -lX11 -lXtst libs

Répondre

1

XSendEvent génère des événements marqués comme envoyés. Les événements envoyés par le serveur ne sont pas marqués.

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

Certaines applications ignorent les événements pour lesquels cet indicateur est défini, pour des raisons de sécurité. Pensez à un logiciel malveillant qui accède en quelque sorte à votre serveur X11 - il peut tromper n'importe quelle application en faisant ce qu'il veut en envoyant ces événements. Il est parfaitement possible d'utiliser la deuxième variante sur votre propre machine, mais elle repose sur une extension qui peut être désactivée (encore une fois, pour des raisons de sécurité) et ne fonctionne donc pas nécessairement sur les serveurs X11 d'autres personnes.

+0

Thx man. Comme je comprends chrome avoir une protection anti-clicker et vous ne pouvez pas utiliser XSendEvent parce XSendEvent permettre d'envoyer cliquez non seulement pour la fenêtre active, mais pour toute fenêtre, de sorte que vous pouvez faire des clics dans la fenêtre non active pendant que l'utilisateur ne voit pas) Je suis regardé le code source de xdotool._xdo_mousebutton utilise XTestFakeButtonEvent si vous envoyez un clic sur CURRENTWINDOW et XSendEvent dans les autres cas. – goldstar

0

Sur XCB vous pouvez utiliser la fonction suivante pour vérifier si l'événement a été envoyé par XSendEvent()/xcb_send_event() API:

static bool fromSendEvent(const void *event) 
{ 
    // From X11 protocol: Every event contains an 8-bit type code. The most 
    // significant bit in this code is set if the event was generated from 
    // a SendEvent request. 
    const xcb_generic_event_t *e = reinterpret_cast<const xcb_generic_event_t *>(event); 
    return (e->response_type & 0x80) != 0; 
} 

AFACT, il n'y a pas moyen de savoir si l'événement a été envoyé via l'extension XTest .

Vous devriez utiliser XTest car cela fonctionnera mieux, XSendEvents ne sait rien de l'état interne du serveur X. Fom XSendEvent manual:

"Le contenu de l'événement est par ailleurs inchangé et non coché par le serveur X, sauf pour forcer send_event à True". Avec XSendEvent, vous risquez de rencontrer des problèmes inattendus dans certaines situations.