I've got an embedded device running Linux/X11 that is connected to a device that provides touch events over a USB connection. This device is not recognized as any form of standard pointer/mouse input. What I'm trying to do is find a way to "inject" mouse events into X11 when the external device reports an event.
Doing so would remove the need for my application ( written in C using Gtk+ ) to fake mouse presses with Gtk+ calls.
If this can be done my Gtk+ application would not need to know or care about the device generating the touch events. It would just appear to the application as standard mouse events.
Anybody know how to go about inserting synthetic mouse events into X11?
Right now I'm doing the following which works, but isn't optimal.
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 );
}
The Linux input system has a facility for user-space implementation of input devices called uinput. You can write a background program that uses your device's callback library to send input events to the kernel. The X server (assuming it is using the evdev input module) would then process these just as any other mouse event.
There's a library called libsuinput that makes this fairly easy to do. It even includes an example mouse input program that you can probably use as a model. However, since your device is a touch-based device it will probably use absolute axes (ABS_X, ABS_Y) instead of relative (REL_X, REL_Y).
The coolest thing would be to implement a device driver inside the Kernel that creates a
/dev/input/eventX
file which speaks the evdev protocol. I recommend you to read the book calledLinux Device Drivers
if you want to do this. The book is freely available on the web.If you want to do this in user space, I suggest you to use Xlib (or XCB). On plain Xlib (C language), you can use the
X Test Extension
orXSendEvent()
.There's also a binary called xte from the xautomation package (on Debian,
sudo apt-get install xautomation
and thenman xte
).xte
is very easy to use, and you can also look at its source code to learn how to use the X Test Extension.Pointers:
Seems that after a bit more research, Gtk+ uses a GDK library that can do what I want without having to delve deeply into X11 coding or write a Kernel driver. Although, if I had the time, I would prefer to write a Linux Kernel Mouse driver.
Using the GDK 2 Reference Manual I found I can do the following:
Use
gtk_event_put()
to append aGdkEvent
of typeGdkEventButton
The structure for a
GdkEventButton
is:Most of these fields will be trivial to fill in with the exception of:
I will need to research how to convert the screen root coordinates the window relative coordinates.
*device
- I'm not sure if I need to use this field ( set to NULL ) because this is for an extended input device. However, if I do need to have a valid device here I should be able to use gdk_devices_list()There are several methods.
XSendEvent
. Caveat: some application frameworks ignore events sent withXSendEvent
. I think Gtk+ doesn't, but I have not checked.XTestFakeMotionEvent
andXTestFakeButtonEvent
. You need XTest extension on your X server.