2017-02-02 6 views
0

x11을 통해 우분투 용 간단한 마우스 리모콘을 작성하려고합니다. (모질라가 너무 잘 작동과 함께)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); 
} 

이 코드는 크롬을 제외한 모든 응용 프로그램에 잘 작동 :

먼저 들어 내가 클릭 절차 (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);로 디스플레이를 열 때 필요한 윈도우가 아닌 이벤트를 보내려고한다고 생각합니다. 크롬은 x11 서버와 다른 연결 시스템을 가지고 있습니까?

2 : 응용 프로그램에서 두 번째 변형을 사용하는 것이 좋습니까? 그것은 꽤 짧고 내가 가진 모든 애플 리케이션과 잘 작동)

추신. 이 코드를 컴파일하려면 -lX11 -lXtst libs를 추가하십시오.

답변

1

XSendEvent은 보낸 것으로 표시된 이벤트를 생성합니다. 서버가 보낸 이벤트는 표시되지 않습니다.

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

일부 응용 프로그램은 보안상의 이유로이 플래그가 설정된 이벤트를 무시합니다. 어떻게 든 X11 서버에 액세스 할 수있는 맬웨어를 생각해보십시오. 응용 프로그램을 보내면 원하는 모든 작업을 수행 할 수 있습니다.

자신의 컴퓨터에서 두 번째 변형을 사용하는 것이 좋지만 보안상의 이유로 해제 할 수있는 확장 프로그램에 의존하므로 다른 사람의 X11 서버에서 작동하지 않을 수도 있습니다. 당신이 이벤트가 XSendEvent()/xcb_send_event() API를 통해 전송 된 경우 확인하려면 다음 기능을 사용할 수 있습니다 XCB에

+0

Thx man. XSendEvent는 활성 창뿐만 아니라 어떤 창에서도 클릭을 보낼 수 있기 때문에 크롬은 안티 크리커 보호 기능을 사용할 수 있으며 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를 사용하면 일부 상황에서 예기치 않은 문제가 발생할 수 있습니다.