2017-02-02 24 views
0

私はx11経由でubuntu用の簡単なマウスクリッカーを書こうとしています。 (Mozillaはあまりにも正常に動作して)XTestFakeButtonEventとXSendEventの違い

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

このコードは、クロムを除くすべてのアプリケーション上で正常に動作します:

は、最初のiについては、クリックする手順の(XSendEventに基づいて)最初の変種を書きました。

だから私は(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); 
} 

をこのコードは、罰金everyvereはクロムが含まれる作品。これらの機能の

通話は

// XSendEvent variant 
mouseClick(1); 

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

1非常に簡単です:私が間違ってやっているかを理解するために私を助ける最初の変種で(または多分クロムで何が間違って)。

1 1.1:私はXOpenDisplay(NULL)で表示を開くときに、必要なウィンドウではなくイベントを送信しようとしていると思います。 chromeはx11サーバーとは異なる接続システムを持っていますか?

2:アプリケーションで第2の亜種を使用することをお勧めしますか?それはかなり短く、私が持っているすべてのアプリでうまくいく)

P.S.このコードをコンパイルするには、-lX11 -lXtst libsを追加する必要があります。

答えて

1

​​は、sentとしてマークされたイベントを生成します。サーバーから送信されたイベントにはマークが付きません。

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

一部のアプリケーションでは、セキュリティ上の理由から、このフラグが設定されているイベントは無視されます。どのようにしてX11サーバーにアクセスできるマルウェアであると考えても、それを送信することでアプリケーションを望みどおりにすることができます。

自分のマシンで2番目の亜種を使用することは完全にOKですが、セキュリティ上の理由から無効にすることができる拡張機能に依存しているため、他の人のX11サーバーでは必ずしも機能しません。あなたは、イベントがXSendEvent()/ xcb_send_event()APIを経由して送信されたかどうかを確認するには、以下の機能を使用することができますXCBに

+0

Thx man。私はクロムがアンチクリッカープロテクションを持っていることを理解しており、XSendEventはアクティブなウィンドウだけでなく、どのウィンドウに対してもクリックを送信できるので、ユーザーはこれを見ることができないので、非アクティブなウィンドウでクリックを行うことができます) 私はxdotoolのソースコードを見ています。それ以外の場合は、CURRENTWINDOWおよびXSendEventにクリックを送信すると、_xdo_mousebuttonはXTestFakeButtonEventを使用します。 – goldstar

0

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は、イベントがXTEST拡張を経由して送信された場合に指示する方法はありません。

XTestを使うべきですが、XSendEventsは内部のXサーバーの状態について何も知らないので、使用するべきです。 Fom XSendEventのマニュアル:

"send_eventをTrueに強制する以外は、Xサーバーはイベントの内容を変更せずにチェックを外します"。

XSendEventでは、状況によって予期しない問題が発生することがあります。