10

这是如何将合成鼠标事件插入 X11 输入队列的后续内容

我正在尝试创建一个程序,该程序从外部设备获取输入并生成鼠标点击,以便GTK+获取和处理事件,就好像鼠标点击正常发生一样。

似乎我可以使用一个GdkEventButton结构: https ://developer.gnome.org/gdk/stable/gdk-Event-Structures.html#GdkEventButton

但我不确定如何确定要为每个字段输入的值。我正在寻找一小段示例代码或来自使用gtk_event_put()GdkEventButton结构的人的建议。

编辑:如果有人知道与我的答案不同或更好的方法,请告诉我。

4

2 回答 2

6

还有另一种方法,但我要介绍的这种方法涉及使用纯 X11,尽管看到您的问题标签,使用 X11 的答案也是可以接受的。

也就是说,让我首先介绍所有发生的功能,一件事,我会有点冗长,以防其他人不了解如何使用此功能。


void
mouse_click(Display *display, int x, int y, int click_type, struct timeval *t);
  • 先前返回的显示XOpenDisplay()结构包含有关 X 服务器的所有信息。
  • x指针相对于屏幕根的 x 坐标。
  • y指针相对于屏幕根的 y 坐标。
  • click_type点击的类型。对于这个答案,MOUSE_RIGHT_CLICK要么MOUSE_LEFT_CLICK
  • t timeval结构,指定单击应保持按下的时间间隔。

执行

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

#define portable_usleep(t) select(0, NULL, NULL,NULL, t)

enum { MOUSE_RIGHT_CLICK, MOUSE_LEFT_CLICK };

void
mouse_click(Display *display, int x, int y, int click_type, struct timeval *t)
{
        Window root;
        XEvent event;

        root = DefaultRootWindow(display);
        XWarpPointer(display, None, root, 0, 0, 0, 0, x, y);

        memset(&event, 0, sizeof(event));

        event.xbutton.type        = ButtonPress;
        event.xbutton.button      = click_type;
        event.xbutton.same_screen = True;

        XQueryPointer(display, root, &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)
                fprintf(stderr, "XSendEvent()\n");

        XFlush(display);
        portable_usleep(t); /* keeps the click pressed */

        event.type = ButtonRelease;
        event.xbutton.state = 0x100;

        if(XSendEvent(display, PointerWindow, True, 0xfff, &event)==0)
                fprintf(stderr, "XSendEvent()\n");

        XFlush(display);
}

嗯,这个函数很简单,例如,左键单击位置 500,645 按钮按下半秒,是这样的:

int
main(void)
{
        int x;
        int y;
        Display        *display;
        struct timeval t;

        display = XOpenDisplay(NULL);

        if(!display) {
                fprintf(stderr, "Can't open display!\n");
                exit(EXIT_FAILURE);
        }

        x = 500;
        y = 645;

        t.tv_sec  = 0;
        t.tv_usec = 500000;  /* 0.5 secs */

        mouse_click(display, x, y, MOUSE_LEFT_CLICK, &t);

        XCloseDisplay(display);
        return 0;
}

编译

$ gcc -o click click.c -lX11
于 2013-07-13T06:37:45.560 回答
4

经过一些研究,我了解到GTK+/GDK2.14 和更高版本具有一些用于为GTK+应用程序创建自动化测试套件的功能。

我能够使用gdk_test_simulate_button来模拟鼠标点击。这可能不是最佳解决方案,但现在看来效果很好。

于 2013-07-08T16:33:59.637 回答