[AD] submission: linux touchscreen driver for allegro

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


Hi all,
Attached is an initial implementation for touchscreen driver for Linux using XInput2 for consideration.
I tested on a touchscreen laptop Dell m3800 using Ubuntu 14.04 trusty 64 bit, with multiple windows using ex_touch_input.

It does not support multiple touch-screens, and will only connect to the first touchscreen device.
I don't know if that's a safe assumption to be the primary touchscreen device.

It currently doesn't handle touch_cancel events from x11 but I'm not sure XInput2 catches that event.

First attempt and x11 programming or working with allegro internals so all feedback is welcome.

Cheers,
Pho75.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 516713d..4f73d11 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -611,6 +611,11 @@ if(SUPPORT_X11)
         message(FATAL_ERROR "X11 support requires Xcursor library.")
     endif(CAN_XCURSOR)
 
+    check_include_file("X11/extensions/XInput2.h" CAN_XINPUT2)
+    if(CAN_XINPUT2)
+        list(APPEND X11_LIBRARIES "Xi")
+    endif(CAN_XINPUT2)
+
     if(WANT_X11_XF86VIDMODE)
         check_include_file("X11/extensions/xf86vmode.h" HAVE_XF86VIDMODE_H)
         check_library_exists(Xxf86vm XF86VidModeQueryExtension "" CAN_XF86VIDMODE)
diff --git a/cmake/FileList.cmake b/cmake/FileList.cmake
index a05a67e..e3ae318 100644
--- a/cmake/FileList.cmake
+++ b/cmake/FileList.cmake
@@ -120,6 +120,7 @@ set(ALLEGRO_SRC_X_FILES
     src/x/xmousenu.c
     src/x/xrandr.c
     src/x/xsystem.c
+    src/x/xtouch.c
     src/x/xwindow.c
     src/linux/lhaptic.c
     src/linux/ljoynu.c
diff --git a/include/allegro5/internal/aintern_xtouch.h b/include/allegro5/internal/aintern_xtouch.h
new file mode 100644
index 0000000..1edc3b7
--- /dev/null
+++ b/include/allegro5/internal/aintern_xtouch.h
@@ -0,0 +1,14 @@
+#ifndef __al_included_allegro5_aintern_xtouch_h
+#define __al_included_allegro5_aintern_xtouch_h
+
+#include "allegro5/internal/aintern_touch_input.h"
+
+bool _al_x_init_touch_input_api(void);
+ALLEGRO_TOUCH_INPUT_DRIVER *_al_xwin_touch_driver(void);
+
+void _al_x_touch_input_handle_begin(int id, size_t timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp);
+void _al_x_touch_input_handle_cancel(int id, size_t timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp);
+void _al_x_touch_input_handle_end(int id, size_t timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp);
+void _al_x_touch_input_handle_move(int id, size_t timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp);
+
+#endif
diff --git a/src/x/xdisplay.c b/src/x/xdisplay.c
index 0491a2a..8dbe5af 100644
--- a/src/x/xdisplay.c
+++ b/src/x/xdisplay.c
@@ -1,3 +1,5 @@
+#include <X11/extensions/XInput2.h>
+
 #include "allegro5/allegro.h"
 #include "allegro5/allegro_opengl.h"
 #include "allegro5/internal/aintern_bitmap.h"
@@ -19,6 +21,7 @@ static const ALLEGRO_XWIN_DISPLAY_OVERRIDABLE_INTERFACE *gtk_override_vt = NULL;
 
 static void xdpy_destroy_display(ALLEGRO_DISPLAY *d);
 
+extern int x_touch_devid;
 
 /* XXX where does this belong? */
 static void _al_xglx_use_adapter(ALLEGRO_SYSTEM_XGLX *s, int adapter)
@@ -213,6 +216,27 @@ static bool xdpy_create_display_window(ALLEGRO_SYSTEM_XGLX *system,
 
    _al_xwin_set_size_hints(display, x_off, y_off);
 
+   /* listen for touchscreen events */
+   if (al_is_touch_input_installed())
+   {
+       /* filter select events to listen for */
+       {
+           XIEventMask mask =
+           {
+               .deviceid = x_touch_devid, //XIAllDevices,
+               .mask_len = XIMaskLen(XI_TouchEnd)
+           };
+           mask.mask = (unsigned char*)calloc(3, sizeof(char));
+           XISetMask(mask.mask, XI_TouchBegin);
+           XISetMask(mask.mask, XI_TouchUpdate);
+           XISetMask(mask.mask, XI_TouchEnd);
+
+           XISelectEvents(system->x11display, d->window, &mask, 1);
+
+           free(mask.mask);
+       }
+   }
+
    return true;
 }
 
diff --git a/src/x/xevents.c b/src/x/xevents.c
index a4c7156..5d8d1e4 100644
--- a/src/x/xevents.c
+++ b/src/x/xevents.c
@@ -1,4 +1,5 @@
 #include <sys/time.h>
+#include <X11/extensions/XInput2.h>
 
 #include "allegro5/allegro.h"
 #include "allegro5/platform/aintunix.h"
@@ -10,6 +11,7 @@
 #include "allegro5/internal/aintern_xkeyboard.h"
 #include "allegro5/internal/aintern_xmouse.h"
 #include "allegro5/internal/aintern_xsystem.h"
+#include "allegro5/internal/aintern_xtouch.h"
 
 #ifdef ALLEGRO_RASPBERRYPI
 #include "allegro5/internal/aintern_raspberrypi.h"
@@ -19,6 +21,9 @@
 
 ALLEGRO_DEBUG_CHANNEL("xevents")
 
+extern int xi_opcode;
+extern int primary_devid;
+
 /* Handle an X11 close button event. [X11 thread]
  * Only called from the event handler with the system locked.
  */
@@ -77,7 +82,7 @@ static void process_x11_event(ALLEGRO_SYSTEM_XGLX *s, XEvent event)
          _al_xwin_mouse_button_release_handler(event.xbutton.button,
             &d->display);
          break;
-      case ClientMessage:
+          case ClientMessage:
          if (event.xclient.message_type == s->AllegroAtom) {
             d->mouse_warp = true;
             break;
@@ -157,9 +162,45 @@ static void process_x11_event(ALLEGRO_SYSTEM_XGLX *s, XEvent event)
             d->embedder_window = None;
          }
          break;
- 
       default:
-         _al_xglx_handle_mmon_event(s, d, &event);
+        {
+            Display *x11display = s->x11display;
+            XGenericEventCookie *cookie = &event.xcookie;
+            if (XGetEventData(x11display, cookie)) /* extended event */
+            {
+               /* check if this belongs to XInput */
+               if(cookie->type == GenericEvent && cookie->extension == xi_opcode)
+               {
+                   XIDeviceEvent *devev;
+
+                   devev = cookie->data;
+                   switch(devev->evtype) {
+                   case XI_TouchBegin:
+
+                       /* the next new touch gets primary flag if it's not set */
+                       if (primary_devid < 0)
+                           primary_devid= devev->detail;
+
+                       _al_x_touch_input_handle_begin(devev->detail, al_get_time(), devev->event_x, devev->event_y, primary_devid==devev->detail, &d->display);
+                       break;
+
+                   case XI_TouchUpdate:
+                       _al_x_touch_input_handle_move(devev->detail, al_get_time(), devev->event_x, devev->event_y, primary_devid==devev->detail, &d->display);
+                       break;
+
+                   case XI_TouchEnd:
+
+                       _al_x_touch_input_handle_end(devev->detail, al_get_time(), devev->event_x, devev->event_y, primary_devid==devev->detail, &d->display);
+
+                       if (primary_devid == devev->detail)
+                           primary_devid= -1;
+                       break;
+                   }
+               }
+           }
+
+           _al_xglx_handle_mmon_event(s, d, &event);
+         }
          break;
 #endif
    }
diff --git a/src/x/xsystem.c b/src/x/xsystem.c
index cc51fba..b2a6e49 100644
--- a/src/x/xsystem.c
+++ b/src/x/xsystem.c
@@ -178,6 +178,11 @@ static ALLEGRO_HAPTIC_DRIVER *xglx_get_haptic_driver(void)
    return _al_haptic_driver_list[0].driver;
 }
 
+static ALLEGRO_TOUCH_INPUT_DRIVER *xglx_get_touch_driver(void)
+{
+   return _al_touch_input_driver_list[0].driver;
+}
+
 static int xglx_get_num_video_adapters(void)
 {
    ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver();
@@ -245,6 +250,7 @@ ALLEGRO_SYSTEM_INTERFACE *_al_system_xglx_driver(void)
    xglx_vt->get_mouse_driver = xglx_get_mouse_driver;
    xglx_vt->get_joystick_driver = xglx_get_joystick_driver;
    xglx_vt->get_haptic_driver = xglx_get_haptic_driver;
+   xglx_vt->get_touch_input_driver = xglx_get_touch_driver;
    xglx_vt->get_num_display_modes = xglx_get_num_display_modes;
    xglx_vt->get_display_mode = xglx_get_display_mode;
    xglx_vt->shutdown_system = xglx_shutdown_system;
diff --git a/src/x/xtouch.c b/src/x/xtouch.c
new file mode 100644
index 0000000..519dc87
--- /dev/null
+++ b/src/x/xtouch.c
@@ -0,0 +1,453 @@
+/*         ______   ___    ___
+ *        /\  _  \ /\_ \  /\_ \
+ *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
+ *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
+ *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
+ *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
+ *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
+ *                                           /\____/
+ *                                           \_/__/
+ *
+ *      X-Windows touch module.
+ *
+ *      By Ryan Gumbs.
+ *
+ *      See readme.txt for copyright information.
+ */
+
+
+#define ALLEGRO_NO_COMPATIBILITY
+
+#include <X11/Xlib.h>
+#include <X11/extensions/XInput2.h>
+#include <stdio.h>
+
+#include "allegro5/allegro.h"
+#include "allegro5/internal/aintern.h"
+#include "allegro5/internal/aintern_mouse.h"
+#include "allegro5/internal/aintern_x.h"
+#include "allegro5/internal/aintern_xdisplay.h"
+#include "allegro5/internal/aintern_xmouse.h"
+#include "allegro5/internal/aintern_xsystem.h"
+#include "allegro5/internal/aintern_xtouch.h"
+
+
+ALLEGRO_DEBUG_CHANNEL("touch")
+
+
+/* the one and only touch object */
+static ALLEGRO_TOUCH_INPUT_STATE touch_input_state;
+static ALLEGRO_TOUCH_INPUT touch_input;
+static ALLEGRO_MOUSE_STATE mouse_state;
+int x_touches_devid[ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT]; /* the x11 id for touches */
+int x_touch_devid;  /* device id */
+int primary_devid= -1;
+
+static bool installed = false;
+static size_t initiali_time_stamp = ~0;
+int xi_opcode;
+
+
+static void reset_touch_input_state(void)
+{
+   int i;
+
+   for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; i++) {
+      touch_input_state.touches[i].id = -1;
+   }
+}
+
+
+static void generate_touch_input_event(unsigned int type, double timestamp,
+   int id, float x, float y, float dx, float dy, bool primary,
+   ALLEGRO_DISPLAY *disp)
+{
+   ALLEGRO_EVENT event;
+
+   bool want_touch_event           = _al_event_source_needs_to_generate_event(&touch_input.es);
+   bool want_mouse_emulation_event;
+
+   if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_5_0_x) {
+      want_mouse_emulation_event = _al_event_source_needs_to_generate_event(&touch_input.mouse_emulation_es) && al_is_mouse_installed();
+   }
+   else {
+      want_mouse_emulation_event = _al_event_source_needs_to_generate_event(&touch_input.mouse_emulation_es) && primary && al_is_mouse_installed();
+   }
+
+   if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_NONE)
+      want_mouse_emulation_event = false;
+   else if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_INCLUSIVE)
+      want_touch_event = al_is_mouse_installed() ? (want_touch_event && !primary) : want_touch_event;
+   else if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_EXCLUSIVE)
+      want_touch_event = al_is_mouse_installed() ? false : want_touch_event;
+
+
+   if (!want_touch_event && !want_mouse_emulation_event)
+      return;
+
+   if (want_touch_event) {
+
+      event.touch.type      = type;
+      event.touch.display   = (ALLEGRO_DISPLAY*)disp;
+      event.touch.timestamp = timestamp;
+      event.touch.id        = id;
+      event.touch.x         = x;
+      event.touch.y         = y;
+      event.touch.dx        = dx;
+      event.touch.dy        = dy;
+      event.touch.primary   = primary;
+
+      _al_event_source_lock(&touch_input.es);
+      _al_event_source_emit_event(&touch_input.es, &event);
+      _al_event_source_unlock(&touch_input.es);
+   }
+
+   if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_NONE) {
+      mouse_state.x = (int)x;
+      mouse_state.y = (int)y;
+      if (type == ALLEGRO_EVENT_TOUCH_BEGIN)
+         mouse_state.buttons++;
+      else if (type == ALLEGRO_EVENT_TOUCH_END)
+         mouse_state.buttons--;
+
+      _al_event_source_lock(&touch_input.mouse_emulation_es);
+      if (want_mouse_emulation_event) {
+
+         switch (type) {
+            case ALLEGRO_EVENT_TOUCH_BEGIN: type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN; break;
+            case ALLEGRO_EVENT_TOUCH_CANCEL:
+            case ALLEGRO_EVENT_TOUCH_END:   type = ALLEGRO_EVENT_MOUSE_BUTTON_UP;   break;
+            case ALLEGRO_EVENT_TOUCH_MOVE:  type = ALLEGRO_EVENT_MOUSE_AXES;        break;
+         }
+
+         event.mouse.type      = type;
+         event.mouse.timestamp = timestamp;
+         event.mouse.display   = (ALLEGRO_DISPLAY*)disp;
+         event.mouse.x         = (int)x;
+         event.mouse.y         = (int)y;
+         event.mouse.dx        = (int)dx;
+         event.mouse.dy        = (int)dy;
+         event.mouse.dz        = 0;
+         event.mouse.dw        = 0;
+         if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_5_0_x) {
+            event.mouse.button = 1;
+         }
+         else {
+            event.mouse.button = id;
+         }
+         event.mouse.pressure  = 1.0;
+
+         if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_5_0_x) {
+            al_set_mouse_xy(event.mouse.display, event.mouse.x, event.mouse.y);
+         }
+
+         _al_event_source_emit_event(&touch_input.mouse_emulation_es, &event);
+      }
+      _al_event_source_unlock(&touch_input.mouse_emulation_es);
+   }
+}
+
+
+static int find_free_touch_state_index(void)
+{
+   int i;
+
+   for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i)
+      if (touch_input_state.touches[i].id < 0)
+         return i;
+
+   return -1;
+}
+
+
+static int find_touch_state_index_with_id(int id)
+{
+   int i;
+
+   for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i)
+      if (x_touches_devid[i] == id)
+         return i;
+
+   return -1;
+}
+
+
+void _al_x_touch_input_handle_begin(int id, size_t timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp)
+{
+    int index= find_free_touch_state_index();
+    if (index < 0)
+        return;
+
+    ALLEGRO_TOUCH_STATE* state = touch_input_state.touches + index;
+    (void)primary;
+
+    if (NULL == state)
+       return;
+
+    _al_event_source_lock(&touch_input.es);
+    state->id      = index;
+    state->x       = x;
+    state->y       = y;
+    state->dx      = 0.0f;
+    state->dy      = 0.0f;
+    state->primary = primary;
+    state->display = disp;
+    _al_event_source_unlock(&touch_input.es);
+
+    generate_touch_input_event(ALLEGRO_EVENT_TOUCH_BEGIN, timestamp,
+       state->id, state->x, state->y, state->dx, state->dy, state->primary,
+       disp);
+
+    x_touches_devid[index]= id;
+}
+
+
+void _al_x_touch_input_handle_end(int id, size_t timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp)
+{
+    int index= find_touch_state_index_with_id(id);
+    if (index < 0)
+        return;
+
+    ALLEGRO_TOUCH_STATE* state = touch_input_state.touches + index;
+    (void)primary;
+
+    if (NULL == state)
+       return;
+
+    _al_event_source_lock(&touch_input.es);
+    state->dx      = x - state->x;
+    state->dy      = y - state->y;
+    state->x       = x;
+    state->y       = y;
+    _al_event_source_unlock(&touch_input.es);
+
+    generate_touch_input_event(ALLEGRO_EVENT_TOUCH_END, timestamp,
+       state->id, state->x, state->y, state->dx, state->dy, state->primary,
+       disp);
+
+    _al_event_source_lock(&touch_input.es);
+    state->id = -1;
+    x_touches_devid[index]= -1;
+    _al_event_source_unlock(&touch_input.es);
+}
+
+
+void _al_x_touch_input_handle_move(int id, size_t timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp)
+{
+    int index= find_touch_state_index_with_id(id);
+    if (index < 0)
+        return;
+
+    ALLEGRO_TOUCH_STATE* state = touch_input_state.touches + index;
+    (void)primary;
+
+    if (NULL == state)
+       return;
+
+    if (x==state->x && y==state->y)
+        return; /* coordinates haven't changed */
+
+    _al_event_source_lock(&touch_input.es);
+    state->dx      = x - state->x;
+    state->dy      = y - state->y;
+    state->x       = x;
+    state->y       = y;
+    _al_event_source_unlock(&touch_input.es);
+
+    generate_touch_input_event(ALLEGRO_EVENT_TOUCH_MOVE, timestamp,
+       state->id, state->x, state->y, state->dx, state->dy, state->primary,
+       disp);
+}
+
+
+void _al_x_touch_input_handle_cancel(int id, size_t timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp)
+{
+    int index= find_touch_state_index_with_id(id);
+    if (index < 0)
+        return;
+
+    ALLEGRO_TOUCH_STATE* state = touch_input_state.touches + index;
+    (void)primary;
+
+    if (NULL == state)
+       return;
+
+    _al_event_source_lock(&touch_input.es);
+    state->dx      = x - state->x;
+    state->dy      = y - state->y;
+    state->x       = x;
+    state->y       = y;
+    _al_event_source_unlock(&touch_input.es);
+
+    generate_touch_input_event(ALLEGRO_EVENT_TOUCH_CANCEL, timestamp,
+       state->id, state->x, state->y, state->dx, state->dy, state->primary, disp);
+
+    _al_event_source_lock(&touch_input.es);
+    state->id = -1;
+    _al_event_source_unlock(&touch_input.es);
+}
+
+
+bool _al_x_init_touch_input_api(void)
+{
+    ALLEGRO_SYSTEM_XGLX *system = (void *)al_get_system_driver();
+    Display *dpy = system->x11display;
+
+    /* check XInput extension */
+    {
+        int ev;
+        int err;
+
+        if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &ev, &err))
+        {
+            ALLEGRO_DEBUG("XInput extension not available. Touch input unavailable.\n");
+            return false;
+        }
+    }
+
+    /* check the version of XInput */
+    {
+        int rc;
+        int major = 2;
+        int minor = 2;
+
+        rc = XIQueryVersion(dpy, &major, &minor);
+        if (rc != Success)
+        {
+            ALLEGRO_DEBUG("XInput version is too old (%d.%d): Needs 2.2. Touch input unavailable.\n", major, minor);
+            return false;
+        }
+    }
+
+    /* select device */
+    {
+        XIDeviceInfo *di;
+        XIDeviceInfo *dev;
+        XITouchClassInfo *class;
+        int cnt;
+        int i, j;
+
+        di = XIQueryDevice(dpy, XIAllDevices, &cnt);
+        for (i = 0; i < cnt; i ++)
+        {
+            dev = &di[i];
+            for (j = 0; j < dev->num_classes; j ++)
+            {
+                class = (XITouchClassInfo*)(dev->classes[j]);
+                if (class->type != XITouchClass)
+                {
+                    x_touch_devid = dev->deviceid;
+                    ALLEGRO_DEBUG("Found touchscreen deviceid: %i\n", x_touch_devid);
+                    goto STOP_SEARCH_DEVICE;
+                }
+            }
+        }
+STOP_SEARCH_DEVICE:
+        XIFreeDeviceInfo(di);
+
+        if (i>=cnt)
+        {
+            /* no device found */
+            ALLEGRO_DEBUG("No touchscreen device found.\n");
+            x_touch_devid= -1;
+            return false;
+        }
+    }
+
+    return true;
+}
+
+
+static void _al_x_touch_input_set_time_stamp(size_t timestamp)
+{
+   if (initiali_time_stamp != (size_t)~0)
+      initiali_time_stamp = timestamp;
+}
+
+
+static bool xtouch_init(void)
+{
+    if (installed)
+        return false;
+
+    if (!_al_x_init_touch_input_api())
+      return false;
+
+    ALLEGRO_DEBUG("XInput2 touch input initialized.\n");
+
+    memset(&touch_input, 0, sizeof(touch_input));
+    reset_touch_input_state();
+
+    /* Initialise the touch object for use as an event source. */
+    _al_event_source_init(&touch_input.es);
+
+    _al_event_source_init(&touch_input.mouse_emulation_es);
+    touch_input.mouse_emulation_mode = ALLEGRO_MOUSE_EMULATION_TRANSPARENT;
+
+    _al_x_touch_input_set_time_stamp(al_get_time());
+
+    installed = true;
+
+    return true;
+}
+
+
+static void xtouch_exit(void)
+{}
+
+
+static ALLEGRO_TOUCH_INPUT* get_touch_input(void)
+{
+   return &touch_input;
+}
+
+
+static void get_touch_input_state(ALLEGRO_TOUCH_INPUT_STATE *ret_state)
+{
+   _al_event_source_lock(&touch_input.es);
+   *ret_state = touch_input_state;
+   _al_event_source_unlock(&touch_input.es);
+}
+
+
+static void set_mouse_emulation_mode(int mode)
+{
+   if (touch_input.mouse_emulation_mode != mode) {
+
+      int i;
+
+      for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i) {
+
+         ALLEGRO_TOUCH_STATE* touch = touch_input_state.touches + i;
+
+         if (touch->id > 0) {
+            _al_x_touch_input_handle_cancel(x_touches_devid[i], initiali_time_stamp,
+               touch->x, touch->y, touch->primary, touch->display);
+         }
+      }
+
+      touch_input.mouse_emulation_mode = mode;
+   }
+}
+
+
+/* the driver vtable */
+#define TOUCHDRV_XWIN  AL_ID('X','W','I','N')
+
+static ALLEGRO_TOUCH_INPUT_DRIVER touchdrv_xwin =
+{
+    TOUCHDRV_XWIN,
+    xtouch_init,
+    xtouch_exit,
+    get_touch_input,
+    get_touch_input_state,
+    set_mouse_emulation_mode,
+    NULL
+};
+
+
+_AL_DRIVER_INFO _al_touch_input_driver_list[] =
+{
+   {TOUCHDRV_XWIN, &touchdrv_xwin, true},
+   {0, NULL, 0}
+};


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/