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

我有一台运行Linux / X11的嵌入式设备连接到通过USB连接提供触摸事件的设备。 此设备无法识别为任何forms的标准指针/鼠标输入。 我想要做的是找到一种方法,在外部设备报告事件时将鼠标事件“注入”X11。

这样做将不再需要我的应用程序(使用Gtk +用C语言编写)来伪造用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 ); } 

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

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

有几种方法。

  1. 使用XSendEvent 。 警告:一些应用程序框架忽略使用XSendEvent发送的事件。 我认为Gtk +没有,但我没有检查过。
  2. 使用XTestFakeMotionEventXTestFakeButtonEvent 。 您的X服务器上需要XTest扩展。
  3. 为您的设备编写内核驱动程序,使其显示为鼠标/触摸板。

最酷的事情是在内核中实现一个设备驱动程序,它创建一个说出evdev协议的/dev/input/eventX文件。 如果你想这样做,我建议你阅读一本名为Linux Device Drivers的书。 这本书可以在网上免费获得。

如果你想在用户空间中这样做,我建议你使用Xlib(或XCB)。 在普通的Xlib(C语言)上,您可以使用X Test ExtensionXSendEvent()

还有一个名为xte的二进制文件来自xautomation包(在Debian上, sudo apt-get install xautomation然后是man xte )。 xte非常易于使用,您还可以查看其源代码以了解如何使用X Test Extension。

指针:

似乎经过一番研究后,Gtk +使用了一个GDK库,可以做我想做的事情,而无需深入研究X11编码或编写内核驱动程序。 虽然,如果我有时间,我宁愿写一个Linux内核鼠标驱动程序。

使用GDK 2参考手册我发现我可以执行以下操作:

使用gtk_event_put()附加GdkEvent类型的GdkEventButton

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()