C++ XTestFakeButtonEvent与;XSendEvent

C++ XTestFakeButtonEvent与;XSendEvent,c++,linux,google-chrome,x11,C++,Linux,Google Chrome,X11,我正试图通过x11为ubuntu编写简单的鼠标点击器 首先,我编写了click过程的第一个变体(基于XSendEvent): #include <unistd.h> #include <X11/Xlib.h> #include <X11/Xutil.h> void mouseClick(int button) { Display *display = XOpenDisplay(NULL); XEvent event; if(dis

我正试图通过x11为ubuntu编写简单的鼠标点击器

首先,我编写了click过程的第一个变体(基于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);
}
1:帮助我理解我在第一个变体中做错了什么(或者在chrome中可能做错了什么)

1.1:当我用XOpenDisplay(NULL)打开display时,我想我是在尝试发送不需要的窗口的事件;。chrome是否与x11服务器有不同的连接系统

2:在应用程序中使用第二种变体是个好主意吗?它很短,适用于我所有的应用程序)


另外,要编译此代码,需要添加-lX11-lXtst libs

XSendEvent
生成标记为已发送的事件。未标记服务器发送的事件

   typedef struct {
           int type;
           unsigned long serial; 
           Bool send_event;        // <----- here
           Display *display;
           Window window;
   } XAnyEvent;
typedef结构{
int型;
无符号长序列;

Bool send_event;//在XCB上,您可以使用以下函数验证事件是否通过XSendEvent()/XCB_send_event()API发送:

静态bool fromSendEvent(const void*事件)
{
//来自X11协议:每个事件都包含一个8位类型代码
//如果事件是从中生成的,则设置此代码中的有效位
//SendEvent请求。
const xcb_generic_event_t*e=重新解释强制转换(事件);
返回(e->响应类型&0x80)!=0;
}
事实上,无法判断事件是否是通过XTest扩展发送的

您应该使用XTest,因为它会更好地工作,XSendEvents对内部X服务器状态一无所知。Fom XSendEvent手册:

“事件的内容不会被X服务器更改和取消选中,除非强制将send_事件设置为True”


因此,在某些情况下,使用XSendEvent可能会出现意外问题。

虽然不是直接使用Xlib,而是通过python Xlib包装库作为Xlib的代理,但第一种方法目前确实适用于桌面上当前打开的所有窗口,而不是IntelliJ

在第一种方法中,您将事件直接发送到目标窗口,并且,您的事件也会被一个属性值标记(污染),该属性值将其标记为模拟事件。接收窗口可能会像许多应用程序窗口一样对其进行操作

然而,对于第二种方法,您正在模拟实际发生的事情——根据我的理解,实际上与用户请求的事件没有什么区别:事件通过更完整的X11流程处理用户输入事件(而不是盲目地直接调度到目标窗口)这意味着它将像真实用户请求的事件的自然事件流一样,在指针下滴入窗口(或Gnome桌面小部件)

因此,第二种方法似乎比第一种方法更广泛地适用——对于选择不对通过第一种方法发送给他们的事件采取行动的窗口,以及非普通窗口本身的Gnome桌面元素(如语言和电源小部件),也会产生预期的效果.您提供的坐标中没有任何窗口,单击即可通过


如果我必须对这种路由的双重性做出某种解释,我可能会认为这更像是一种通用的事件发送工具,而XTEST提供了专门模拟用户输入事件的方法。

Thx man。据我所知,chrome具有防点击保护,您不能使用XSendEvent,因为XSendEvent允许o发送click不仅适用于活动窗口,也适用于任何窗口,因此您可以在非活动窗口中进行单击,而用户看不到这一点)我还可以查看xdotool的源代码。如果在其他情况下发送click到CURRENTWINDOW和XSendEvent,则鼠标按钮使用XtestFakeButton。
// XSendEvent variant
mouseClick(1);

// XTestFakeButtonEvent variant
SendClick(1, true);   // press lmb
SendClick(1, false);  // release lmb
   typedef struct {
           int type;
           unsigned long serial; 
           Bool send_event;        // <----- here
           Display *display;
           Window window;
   } XAnyEvent;
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;
}