Я пытаюсь написать простой кликер мыши для Ubuntu через X11.
Для первого я написал первый вариант (на основе 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);
}
Этот код прекрасно работает на всех приложениях, кроме Chrome (с Mozilla тоже работает нормально).
Итак, я написал второй вариант (на основе 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);
}
И этот код прекрасно работает, включая Chrome.
Вызов этих функций очень прост
// XSendEvent variant
mouseClick(1);
// XTestFakeButtonEvent variant
SendClick(1, true); // press lmb
SendClick(1, false); // release lmb
1: помогите мне понять, что я делаю неправильно (или что неправильно в chrome, может быть) в первом варианте.
1.1: Я думаю, что я пытаюсь отправить событие не для нужного окна, когда я открываю дисплей с помощью XOpenDisplay (NULL) ;. Есть ли в Chrome другая система соединения с сервером x11?
2: это хорошая идея использовать второй вариант в приложениях? Он довольно короткий и отлично работает с каждым приложением, которое у меня есть)
Постскриптум для компиляции этого кода вам нужно добавить -lX11 -lXtst libs
XSendEvent
производит события, которые помечены как отправленные. События, отправленные сервером, не отмечены.
typedef struct {
int type;
unsigned long serial;
Bool send_event; // <----- here
Display *display;
Window window;
} XAnyEvent;
Некоторые приложения игнорируют события, для которых установлен этот флаг, в целях безопасности. Подумайте о вредоносных программах, которые каким-то образом получают доступ к вашему серверу X11 — они могут обмануть любое приложение, отправив эти события, как ему захочется.
Вполне нормально использовать второй вариант на своей машине, но он опирается на расширение, которое можно отключить (опять же, по соображениям безопасности) и поэтому не обязательно работает на серверах X11 других людей.
В XCB вы можете использовать следующую функцию, чтобы проверить, было ли отправлено событие через API XSendEvent () / xcb_send_event ():
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;
}
На самом деле, невозможно определить, было ли событие отправлено через расширение XTest.
Вам следует использовать XTest, так как он будет работать лучше, XSendEvents ничего не знает о состоянии внутреннего X-сервера. Fom XSendEvent инструкция:
Msgstr «X-сервер не изменяет и не проверяет содержимое события, за исключением того, что принудительно отправляет send_event в True».
Так что с XSendEvent у вас могут возникнуть непредвиденные проблемы в некоторых ситуациях.