Re: [AD] submission: linux touchscreen driver for allegro |
[ Thread Index |
Date Index
| More lists.liballeg.org/allegro-developers Archives
]
Attached is the updated allegro touchscreen support for linux with
corrections applied.
Thanks so SiegeLord for his feedback.
Cheers,
Pho75
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 516713d..140da63 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -611,6 +611,13 @@ 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")
+ else(CAN_XINPUT2)
+ message(FATAL_ERROR "X11 support requires XInput2 library.")
+ 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..5d19fca
--- /dev/null
+++ b/include/allegro5/internal/aintern_xtouch.h
@@ -0,0 +1,19 @@
+#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);
+
+extern int _al_xi_touch_devid; /* device id */
+extern int _al_xi_primary_touch_id;
+
+extern int _al_xi_opcode;
+
+#endif
diff --git a/src/x/xdisplay.c b/src/x/xdisplay.c
index 0491a2a..6ce8c97 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"
@@ -8,6 +10,7 @@
#include "allegro5/internal/aintern_xfullscreen.h"
#include "allegro5/internal/aintern_xglx_config.h"
#include "allegro5/internal/aintern_xsystem.h"
+#include "allegro5/internal/aintern_xtouch.h"
#include "allegro5/internal/aintern_xwindow.h"
#include "allegro5/platform/aintxglx.h"
@@ -19,6 +22,7 @@ static const ALLEGRO_XWIN_DISPLAY_OVERRIDABLE_INTERFACE *gtk_override_vt = NULL;
static void xdpy_destroy_display(ALLEGRO_DISPLAY *d);
+//extern int _al_xi_touch_devid;
/* XXX where does this belong? */
static void _al_xglx_use_adapter(ALLEGRO_SYSTEM_XGLX *s, int adapter)
@@ -213,6 +217,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 = _al_xi_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..9518988 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,7 @@
ALLEGRO_DEBUG_CHANNEL("xevents")
+
/* Handle an X11 close button event. [X11 thread]
* Only called from the event handler with the system locked.
*/
@@ -77,7 +80,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 +160,46 @@ 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 == _al_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 (_al_xi_primary_touch_id < 0)
+ _al_xi_primary_touch_id= devev->detail;
+
+ _al_x_touch_input_handle_begin(devev->detail, al_get_time(), devev->event_x, devev->event_y, _al_xi_primary_touch_id==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, _al_xi_primary_touch_id==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, _al_xi_primary_touch_id==devev->detail, &d->display);
+
+ if (_al_xi_primary_touch_id == devev->detail)
+ _al_xi_primary_touch_id= -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..f3301b0
--- /dev/null
+++ b/src/x/xtouch.c
@@ -0,0 +1,452 @@
+/* ______ ___ ___
+ * /\ _ \ /\_ \ /\_ \
+ * \ \ \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 "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 _al_xi_touch_ids[ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT]; /* the XInput id for touches */
+int _al_xi_touch_devid; /* XInput device id */
+int _al_xi_primary_touch_id= -1;
+
+static bool installed = false;
+static size_t initiali_time_stamp = ~0;
+int _al_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 (_al_xi_touch_ids[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);
+
+ _al_xi_touch_ids[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;
+ _al_xi_touch_ids[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", &_al_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)
+ {
+ _al_xi_touch_devid = dev->deviceid;
+ ALLEGRO_DEBUG("Found touchscreen deviceid: %i\n", _al_xi_touch_devid);
+ goto STOP_SEARCH_DEVICE;
+ }
+ }
+ }
+STOP_SEARCH_DEVICE:
+ XIFreeDeviceInfo(di);
+
+ if (i>=cnt)
+ {
+ /* no device found */
+ ALLEGRO_DEBUG("No touchscreen device found.\n");
+ _al_xi_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(_al_xi_touch_ids[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}
+};