12

我有一个运行 Linux/X11 的嵌入式设备,它连接到通过 USB 连接提供触摸事件的设备。该设备不被识别为任何形式的标准指针/鼠标输入。我正在尝试做的是找到一种在外部设备报告事件时将鼠标事件“注入”到 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 );
}
4

4 回答 4

10

有几种方法。

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

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

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

于 2012-04-25T19:01:52.623 回答
6

最酷的事情是在内核中实现一个设备驱动程序,该驱动程序创建一个/dev/input/eventX使用 evdev 协议的文件。Linux Device Drivers如果你想这样做,我建议你阅读这本书。这本书在网络上免费提供。

如果您想在用户空间执行此操作,我建议您使用 Xlib(或 XCB)。在普通 Xlib(C 语言)上,您可以使用X Test Extensionor XSendEvent()

xautomation 包中还有一个名为 xte 的二进制文件(在 Debian 上,sudo apt-get install xautomation然后是man xte)。xte非常好用,你也可以看看它的源码来学习如何使用X Test Extension。

指针:

于 2012-04-25T16:27:26.150 回答
1

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

使用GDK 2 Reference Manual我发现我可以执行以下操作:

用于gtk_event_put()附加一个GdkEvent类型GdkEventButton

a 的结构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()

于 2012-04-25T18:47:00.410 回答