2012-04-25 8 views
11

Tengo un dispositivo integrado que ejecuta Linux/X11 que está conectado a un dispositivo que proporciona eventos táctiles a través de una conexión USB. Este dispositivo no se reconoce como ninguna forma de entrada estándar de puntero/mouse. Lo que intento hacer es encontrar una forma de "inyectar" eventos del mouse en X11 cuando el dispositivo externo informa un evento.Cómo insertar eventos de mouse sintéticos en la cola de entrada X11

Al hacerlo eliminaría la necesidad de mi aplicación (escrita en C usando Gtk +) para falsificar las pulsaciones del mouse con llamadas Gtk +.

Si esto se puede hacer, mi aplicación Gtk + no necesitaría saber o preocuparse por el dispositivo que genera los eventos táctiles. Simplemente aparecería en la aplicación como eventos estándar del mouse.

¿Alguien sabe cómo hacer para insertar eventos de mouse sintéticos en X11?

En este momento estoy haciendo lo siguiente que funciona, pero no es óptimo.

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); 
} 

Respuesta

9

El sistema de entrada de Linux tiene una facilidad para la implementación del espacio de usuario de los dispositivos de entrada llamados uinput. Puede escribir un programa en segundo plano que use la biblioteca de devolución de llamada de su dispositivo para enviar eventos de entrada al kernel. El servidor X (suponiendo que esté usando el módulo de entrada evdev) los procesará como cualquier otro evento de mouse.

Hay una biblioteca llamada libsuinput que hace que esto sea bastante fácil de hacer. Incluso incluye un example mouse input program que probablemente pueda usar como modelo. Sin embargo, dado que su dispositivo es un dispositivo táctil, probablemente use ejes absolutos (ABS_X, ABS_Y) en lugar de relativos (REL_X, REL_Y).

+0

Excelente ... esta puede ser la respuesta. Tendré que ver si mi dispositivo Linux incorporado admite el sistema 'uinput'. Gracias. – Chimera

9

Existen varios métodos.

  1. Use XSendEvent. Advertencia: algunos marcos de aplicaciones ignoran los eventos enviados con XSendEvent. Creo que Gtk + no, pero no lo he comprobado.
  2. Utilice XTestFakeMotionEvent y XTestFakeButtonEvent. Necesita la extensión XTest en su servidor X.
  3. Escriba un controlador de kernel para su dispositivo para que aparezca como un mouse/touchpad.
+0

Gracias por su respuesta. – Chimera

6

Lo mejor sería implementar un controlador de dispositivo dentro del Kernel que crea un archivo /dev/input/eventX que habla el protocolo evdev. Te recomiendo que leas el libro llamado Linux Device Drivers si quieres hacer esto. El libro está disponible gratuitamente en la web.

Si desea hacer esto en el espacio de usuario, le sugiero que use Xlib (o XCB). En Xlib normal (lenguaje C), puede usar X Test Extension o XSendEvent().

También hay un binario llamado xte del paquete xautomation (en Debian, sudo apt-get install xautomation y luego man xte). xte es muy fácil de usar, y también puede consultar su código fuente para aprender a usar X Test Extension.

Punteros:

+0

Gracias por la respuesta detallada. – Chimera

1

Parece que faet Para investigar un poco más, Gtk + usa una biblioteca GDK que puede hacer lo que yo quiero sin tener que profundizar en la codificación X11 o escribir un controlador Kernel. Aunque, si tuviera tiempo, preferiría escribir un controlador de Linux Kernel Mouse.

Utilizando el GDK 2 Reference Manual me di cuenta de que puede hacer lo siguiente:

Uso gtk_event_put() para anexar un GdkEvent de tipo GdkEventButton

La estructura para un GdkEventButton es:

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; 
}; 

La mayoría de estos campos será trivial para completar con la excepción de:

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. 

Voy a necesitar investigar cómo convertir las coordenadas de la raíz de la pantalla las coordenadas relativas de la ventana.

*device - No estoy seguro de si necesito usar este campo (establecer en NULL) porque esto es para un dispositivo de entrada extendido. Sin embargo, si necesito tener un dispositivo válido aquí, debería poder usar gdk_devices_list()

Cuestiones relacionadas