如何将合成的鼠标事件插入到X11输入队列中

12

我有一个运行Linux/X11的嵌入式设备,连接着通过USB连接提供触摸事件的设备。该设备不被识别为任何形式的标准指针/鼠标输入设备。我尝试的是找到一种方法,在外部设备报告事件时可以“注入”鼠标事件到X11中。

这样做将消除我的应用程序(使用Gtk+编写)使用Gtk+调用来虚拟鼠标点击的需要。

如果可以做到这一点,我的Gtk+应用程序将不需要知道或关心生成触摸事件的设备。它只会出现在应用程序中作为标准的鼠标事件。

有人知道如何插入合成鼠标事件到X11吗?

目前我正在做以下工作,它可以工作,但不是最优的。

GtkWidget *btnSpin;     /* sample button */

gboolean buttonPress_cb( void *btn );
gboolean buttonDePress_cb( void *btn );


/*  make this call after the device library calls the TouchEvent_cb() callback
    and the application has determined which, if any, button was touched

    In this example we are assuming btnSpin was touched.

    This function will, in 5ms, begin the process of causing the button to do it's 
    normal animation ( button in, button out effects ) and then send the actual
    button_clicked event to the button.
*/
g_timeout_add(5, (GSourceFunc) buttonPress_cb, (void *)btnSpin);


/*  this callback is fired 5ms after the g_timeout_add() function above.
    It first sets the button state to ACTIVE to begin the animation cycle (pressed look)
    And then 250ms later calls buttonDePress_cb which will make the button look un-pressed
    and then send the button_clicked event.
*/    
gboolean buttonPress_cb( void *btn )
{

    gtk_widget_set_state((GtkWidget *)btn, GTK_STATE_ACTIVE);
    g_timeout_add(250, (GSourceFunc) buttonDePress_cb, btn);


    return( FALSE );
}

/*  Sets button state back to NORMAL ( not pressed look )
    and sends the button_clicked event so that the registered signal handler for the
    button can be activated
*/
gboolean buttonDePress_cb( void *btn )
{

    gtk_widget_set_state( btn, GTK_STATE_NORMAL);
    gtk_button_clicked( GTK_BUTTON( btn ));

    return( FALSE );
}
4个回答

10

有几种方法。

  1. 使用XSendEvent。注意:某些应用程序框架会忽略使用XSendEvent发送的事件。我认为Gtk+不会,但我没有检查过。
  2. 使用XTestFakeMotionEventXTestFakeButtonEvent。您需要在X服务器上安装XTest扩展程序。
  3. 编写一个内核驱动程序,使您的设备出现为鼠标/触摸板。

10

Linux输入系统提供了一个名为uinput的用户空间实现输入设备的工具。您可以编写一个后台程序,使用设备的回调库来向内核发送输入事件。如果X服务器(假设它正在使用evdev输入模块)使用这些事件来处理,就像处理任何其他鼠标事件一样。

有一个名为libsuinput的库可以使此操作变得相当容易。它甚至包括一个示例鼠标输入程序,您可能可以将其用作模型。但是,由于您的设备是基于触摸的设备,因此它可能会使用绝对轴(ABS_X、ABS_Y)而不是相对轴(REL_X、REL_Y)。


太好了,这可能就是答案。我需要查看一下我的嵌入式Linux设备是否支持“uinput”系统。谢谢。 - Chimera

6
最酷的事情是在内核中实现一个设备驱动程序,创建一个符合evdev协议的/dev/input/eventX文件。如果您想这样做,我建议您阅读名为《Linux设备驱动程序》的书籍。该书可以免费在网上获取。
如果您想在用户空间中进行此操作,我建议您使用Xlib(或XCB)。在普通的Xlib(C语言)中,您可以使用X Test ExtensionXSendEvent()
还有一个二进制文件叫做xte,来自xautomation软件包(在Debian上,sudo apt-get install xautomation然后man xte)。xte非常容易使用,您也可以查看其源代码以了解如何使用X Test Extension。
指针:

1

经过更深入的研究,似乎 Gtk+ 使用一个 GDK 库可以实现我想要的功能,而无需深入了解 X11 编码或编写内核驱动程序。虽然,如果我有时间,我更愿意编写 Linux 内核鼠标驱动程序。

使用 GDK 2 参考手册,我发现可以做到以下几点:

使用 gtk_event_put() 将类型为 GdkEventButtonGdkEvent 追加到其中

GdkEventButton 的结构如下:

struct GdkEventButton {
  GdkEventType type;
  GdkWindow *window;
  gint8 send_event;
  guint32 time;
  gdouble x;
  gdouble y;
  gdouble *axes;
  guint state;
  guint button;
  GdkDevice *device;
  gdouble x_root, y_root;
};

大多数这些字段都很容易填写,除了以下几个例外:
gdouble x;
    the x coordinate of the pointer relative to the window.

gdouble y;
    the y coordinate of the pointer relative to the window.

GdkDevice *device;
    the device where the event originated.

gdouble x_root;
    the x coordinate of the pointer relative to the root of the screen.

gdouble y_root;
    the y coordinate of the pointer relative to the root of the screen.

我需要研究如何将屏幕根坐标转换为窗口相对坐标。

*device - 我不确定是否需要使用此字段(设置为NULL),因为这是用于扩展输入设备的。但是,如果我确实需要在此处有一个有效的设备,我应该能够使用gdk_devices_list()


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接