diff -r 236241f5d225 CMakeLists.txt --- a/CMakeLists.txt Mon Aug 25 10:55:54 2014 -0700 +++ b/CMakeLists.txt Wed Aug 27 14:05:26 2014 +0200 @@ -234,6 +234,7 @@ set_option(RPATH "Use an rpath when linking SDL" ${UNIX_SYS}) set_option(CLOCK_GETTIME "Use clock_gettime() instead of gettimeofday()" OFF) set_option(INPUT_TSLIB "Use the Touchscreen library for input" ${UNIX_SYS}) +set_option(INPUT_MTDEV "Use mtdev - The Multitouch Protocol Translation Library" ${UNIX_SYS}) set_option(VIDEO_X11 "Use X11 video driver" ${UNIX_SYS}) set_option(VIDEO_WAYLAND "Use Wayland video driver" ${UNIX_SYS}) set_option(VIDEO_MIR "Use Mir video driver" ${UNIX_SYS}) @@ -733,6 +734,16 @@ endif() endif() + if(INPUT_MTDEV) + check_c_source_compiles(" + #include \"mtdev.h\" + int main(int argc, char** argv) { }" HAVE_INPUT_MTDEV) + if(HAVE_INPUT_MTDEV) + set(SDL_INPUT_MTDEV 1) + list(APPEND EXTRA_LIBS mtdev) + endif() + endif() + if(SDL_JOYSTICK) CheckUSBHID() # seems to be BSD specific - limit the test to BSD only? if(LINUX) diff -r 236241f5d225 configure --- a/configure Mon Aug 25 10:55:54 2014 -0700 +++ b/configure Wed Aug 27 14:05:26 2014 +0200 @@ -844,6 +844,7 @@ enable_dbus enable_ibus enable_input_tslib +enable_input_mtdev enable_pthreads enable_pthread_sem enable_directx @@ -1577,6 +1578,8 @@ --enable-ibus enable IBus support [[default=yes]] --enable-input-tslib use the Touchscreen library for input [[default=yes]] + --enable-input-mtdev use the Multitouch Protocol Translation Library + [[default=yes]] --enable-pthreads use POSIX threads for multi-threading [[default=yes]] --enable-pthread-sem use pthread semaphores [[default=yes]] @@ -21590,6 +21593,51 @@ fi } +CheckMTDev() +{ + # Check whether --enable-input-mtdev was given. +if test "${enable_input_mtdev+set}" = set; then : + enableval=$enable_input_mtdev; +else + enable_input_mtdev=yes +fi + + if test x$enable_input_mtdev = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mtdev library" >&5 +$as_echo_n "checking for mtdev library... " >&6; } + enable_input_mtdev=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include "mtdev.h" + +int +main () +{ + + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + enable_input_mtdev=yes + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_input_mtdev" >&5 +$as_echo "$enable_input_mtdev" >&6; } + if test x$enable_input_mtdev = xyes; then + +$as_echo "#define SDL_INPUT_MTDEV 1" >>confdefs.h + + EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lmtdev" + SUMMARY_input="${SUMMARY_input} mtdev" + fi + fi +} + CheckPTHREAD() { # Check whether --enable-pthreads was given. @@ -22813,6 +22861,7 @@ CheckInputEvents CheckInputKD CheckTslib + CheckMTDev CheckUSBHID CheckPTHREAD CheckClockGettime diff -r 236241f5d225 configure.in --- a/configure.in Mon Aug 25 10:55:54 2014 -0700 +++ b/configure.in Wed Aug 27 14:05:26 2014 +0200 @@ -2219,6 +2219,30 @@ fi } +dnl See if we can use the Multitouch Protocol Translation Library +CheckMTDev() +{ + AC_ARG_ENABLE(input-mtdev, +AC_HELP_STRING([--enable-input-mtdev], [use the Multitouch Protocol Translation Library [[default=yes]]]), + , enable_input_mtdev=yes) + if test x$enable_input_mtdev = xyes; then + AC_MSG_CHECKING(for mtdev library) + enable_input_mtdev=no + AC_TRY_COMPILE([ + #include "mtdev.h" + ],[ + ],[ + enable_input_mtdev=yes + ]) + AC_MSG_RESULT($enable_input_mtdev) + if test x$enable_input_mtdev = xyes; then + AC_DEFINE(SDL_INPUT_MTDEV, 1, [ ]) + EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lmtdev" + SUMMARY_input="${SUMMARY_input} mtdev" + fi + fi +} + dnl See what type of thread model to use on Linux and Solaris CheckPTHREAD() { @@ -2804,6 +2828,7 @@ CheckInputEvents CheckInputKD CheckTslib + CheckMTDev CheckUSBHID CheckPTHREAD CheckClockGettime diff -r 236241f5d225 include/SDL_config.h.cmake --- a/include/SDL_config.h.cmake Mon Aug 25 10:55:54 2014 -0700 +++ b/include/SDL_config.h.cmake Wed Aug 27 14:05:26 2014 +0200 @@ -222,6 +222,7 @@ #cmakedefine SDL_INPUT_LINUXEV @SDL_INPUT_LINUXEV@ #cmakedefine SDL_INPUT_LINUXKD @SDL_INPUT_LINUXKD@ #cmakedefine SDL_INPUT_TSLIB @SDL_INPUT_TSLIB@ +#cmakedefine SDL_INPUT_MTDEV @SDL_INPUT_MTDEV@ #cmakedefine SDL_JOYSTICK_HAIKU @SDL_JOYSTICK_HAIKU@ #cmakedefine SDL_JOYSTICK_DINPUT @SDL_JOYSTICK_DINPUT@ #cmakedefine SDL_JOYSTICK_DUMMY @SDL_JOYSTICK_DUMMY@ diff -r 236241f5d225 include/SDL_config.h.in --- a/include/SDL_config.h.in Mon Aug 25 10:55:54 2014 -0700 +++ b/include/SDL_config.h.in Wed Aug 27 14:05:26 2014 +0200 @@ -233,6 +233,7 @@ #undef SDL_INPUT_LINUXEV #undef SDL_INPUT_LINUXKD #undef SDL_INPUT_TSLIB +#undef SDL_INPUT_MTDEV #undef SDL_JOYSTICK_HAIKU #undef SDL_JOYSTICK_DINPUT #undef SDL_JOYSTICK_XINPUT diff -r 236241f5d225 src/core/linux/SDL_evdev.c --- a/src/core/linux/SDL_evdev.c Mon Aug 25 10:55:54 2014 -0700 +++ b/src/core/linux/SDL_evdev.c Wed Aug 27 14:05:26 2014 +0200 @@ -44,6 +44,9 @@ #include #include #endif +#ifdef SDL_INPUT_MTDEV +#include +#endif /* We need this to prevent keystrokes from appear in the console */ @@ -74,7 +77,7 @@ static int SDL_EVDEV_device_removed(const char *devpath); #if SDL_USE_LIBUDEV -static int SDL_EVDEV_device_added(const char *devpath); +static int SDL_EVDEV_device_added(const char *devpath, int udev_class); void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath); #endif /* SDL_USE_LIBUDEV */ @@ -547,13 +550,13 @@ return; } - if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE|SDL_UDEV_DEVICE_KEYBOARD))) { + if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE|SDL_UDEV_DEVICE_KEYBOARD|SDL_UDEV_DEVICE_TOUCHSCREEN))) { return; } switch( udev_type ) { case SDL_UDEV_DEVICEADDED: - SDL_EVDEV_device_added(devpath); + SDL_EVDEV_device_added(devpath, udev_class); break; case SDL_UDEV_DEVICEREMOVED: @@ -567,7 +570,59 @@ #endif /* SDL_USE_LIBUDEV */ -void +#if SDL_INPUT_MTDEV +static void SDL_EVDEV_mt_update_slot(SDL_evdevlist_item *item) +{ + switch (item->mt_slot_state) + { + case SDL_EVDEV_MT_SLOT_UPDATED: + case SDL_EVDEV_MT_SLOT_INVALID: + break; + case SDL_EVDEV_MT_SLOT_INVALIDATING: + SDL_SendTouch(item->fd, item->mt_slot, SDL_FALSE, item->mt_x, item->mt_y, 1.0f); + item->mt_slot_state = SDL_EVDEV_MT_SLOT_INVALID; + break; + case SDL_EVDEV_MT_SLOT_UPDATING: + SDL_SendTouchMotion(item->fd, item->mt_slot, item->mt_x, item->mt_y, 1.0f); + item->mt_slot_state = SDL_EVDEV_MT_SLOT_UPDATED; + break; + } +} + +/* FIXME: Shouldn't this be declared by some header (SDL_touch_c.h) ? */ +extern SDL_Finger * SDL_GetFinger(const SDL_Touch *touch, SDL_FingerID id); + +static SDL_Finger * +SDL_EVDEV_get_finger(SDL_TouchID touchid, SDL_FingerID fingerid) +{ + SDL_Touch *touch = SDL_GetTouch(touchid); + if (!touch) { + return NULL; + } + return SDL_GetFinger(touch, fingerid); +} + +#endif /* SDL_INPUT_MTDEV */ + +static int +SDL_EVDEV_get_events(SDL_evdevlist_item *item, struct input_event *events, unsigned int max_events) +{ + int ret; +#if SDL_INPUT_MTDEV + if (item->mt_device) { + ret = mtdev_get(item->mt_device, item->fd, events, max_events); + return ret; + } +#endif /* SDL_INPUT_MTDEV */ + ret = read(item->fd, events, max_events * sizeof(struct input_event)); + if (ret > 0) { + return ret / sizeof(struct input_event); + } else { + return ret; + } +} + +void SDL_EVDEV_Poll(void) { struct input_event events[32]; @@ -576,6 +631,10 @@ SDL_Scancode scan_code; int mouse_button; SDL_Mouse *mouse; +#if SDL_INPUT_MTDEV + /* Used to scale touch coordinates */ + SDL_DisplayMode display = {0}; +#endif #ifdef SDL_INPUT_LINUXKD Uint16 modstate; struct kbentry kbe; @@ -587,12 +646,14 @@ #if SDL_USE_LIBUDEV SDL_UDEV_Poll(); #endif +#if SDL_INPUT_MTDEV + SDL_GetCurrentDisplayMode(0, &display); +#endif mouse = SDL_GetMouse(); for (item = _this->first; item != NULL; item = item->next) { - while ((len = read(item->fd, events, (sizeof events))) > 0) { - len /= sizeof(events[0]); + while ((len = SDL_EVDEV_get_events(item, events, sizeof(events)/sizeof(events[0]))) > 0) { for (i = 0; i < len; ++i) { switch (events[i].type) { case EV_KEY: @@ -659,11 +720,58 @@ case EV_ABS: switch(events[i].code) { case ABS_X: - SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y); + item->abs_x = events[i].value; + item->abs_state = SDL_EVDEV_UPDATING; break; case ABS_Y: - SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value); + item->abs_y = events[i].value; + item->abs_state = SDL_EVDEV_UPDATING; break; +#if SDL_INPUT_MTDEV + case ABS_MT_SLOT: { + SDL_Finger * finger; + /* Update previous slot */ + SDL_EVDEV_mt_update_slot(item); + /* Switch to new one and restore its previous position */ + item->mt_slot = events[i].value; + finger = SDL_EVDEV_get_finger(item->fd, item->mt_slot); + if (finger != NULL) { + item->mt_x = finger->x; + item->mt_y = finger->y; + } + item->mt_slot_state = SDL_EVDEV_MT_SLOT_UPDATING; + } + break; + case ABS_MT_TRACKING_ID: + item->mt_slot_state = (events[i].value == -1) ? SDL_EVDEV_MT_SLOT_INVALIDATING : SDL_EVDEV_MT_SLOT_UPDATING; + break; + case ABS_MT_POSITION_X: { + int min_x = mtdev_get_abs_minimum(item->mt_device, ABS_MT_POSITION_X); + int max_x = mtdev_get_abs_maximum(item->mt_device, ABS_MT_POSITION_X); + int range_x = max_x - min_x; + /* If the minimum/maximum position is valid, scale to display size - use raw data otherwise */ + if (range_x > 0 && display.w > 0) { + item->mt_x = (float)display.w * ((events[i].value - min_x) / (float)range_x); + } else { + item->mt_x = events[i].value; + } + item->mt_slot_state = SDL_EVDEV_MT_SLOT_UPDATING; + } + break; + case ABS_MT_POSITION_Y: { + int min_y = mtdev_get_abs_minimum(item->mt_device, ABS_MT_POSITION_Y); + int max_y = mtdev_get_abs_maximum(item->mt_device, ABS_MT_POSITION_Y); + int range_y = max_y - min_y; + /* If the minimum/maximum position is valid, scale to display size - use raw data otherwise */ + if (range_y > 0 && display.h > 0) { + item->mt_y = (float)display.h * ((events[i].value - min_y) / (float)range_y); + } else { + item->mt_y = events[i].value; + } + item->mt_slot_state = SDL_EVDEV_MT_SLOT_UPDATING; + } + break; +#endif /* SDL_INPUT_MTDEV */ default: break; } @@ -671,10 +779,12 @@ case EV_REL: switch(events[i].code) { case REL_X: - SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, events[i].value, 0); + item->rel_x = events[i].value; + item->rel_state = SDL_EVDEV_UPDATING; break; case REL_Y: - SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value); + item->rel_y = events[i].value; + item->rel_state = SDL_EVDEV_UPDATING; break; case REL_WHEEL: SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value); @@ -688,6 +798,21 @@ break; case EV_SYN: switch (events[i].code) { + case SYN_REPORT: + if (item->abs_state == SDL_EVDEV_UPDATING) { + SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, item->abs_x, item->abs_y); + item->abs_state = SDL_EVDEV_UPDATED; + } + if (item->rel_state == SDL_EVDEV_UPDATING) { + SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, item->rel_x, item->rel_y); + item->rel_state = SDL_EVDEV_UPDATED; + } +#if SDL_INPUT_MTDEV + if (item->mt_device) { + SDL_EVDEV_mt_update_slot(item); + } +#endif /* SDL_INPUT_MTDEV */ + break; case SYN_DROPPED: SDL_EVDEV_sync_device(item); break; @@ -697,7 +822,7 @@ break; } } - } + } } } @@ -723,9 +848,10 @@ #if SDL_USE_LIBUDEV static int -SDL_EVDEV_device_added(const char *devpath) +SDL_EVDEV_device_added(const char *devpath, int udev_class) { SDL_evdevlist_item *item; + char name[256] = ""; /* Check to make sure it's not already in list. */ for (item = _this->first; item != NULL; item = item->next) { @@ -745,6 +871,12 @@ return SDL_SetError("Unable to open %s", devpath); } + /* Check if device is an event device by getting it's name */ + if (ioctl(item->fd, EVIOCGNAME(sizeof(name)), name) == -1) { + SDL_free(item); + return SDL_SetError("%s is not an event device", devpath); + } + item->path = SDL_strdup(devpath); if (item->path == NULL) { close(item->fd); @@ -754,6 +886,17 @@ /* Non blocking read mode */ fcntl(item->fd, F_SETFL, O_NONBLOCK); + +#if SDL_INPUT_MTDEV + if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) + { + item->mt_device = mtdev_new_open(item->fd); + if (item->mt_device == NULL) { + return SDL_SetError("Unable to initialize mtdev for %s", devpath); + } + SDL_AddTouch(item->fd, name); + } +#endif /* SDL_INPUT_MTDEV */ if (_this->last == NULL) { _this->first = _this->last = item; @@ -786,6 +929,12 @@ if (item == _this->last) { _this->last = prev; } +#if SDL_INPUT_MTDEV + if(item->mt_device != NULL) { + SDL_DelTouch(item->fd); + mtdev_close_delete(item->mt_device); + } +#endif close(item->fd); SDL_free(item->path); SDL_free(item); diff -r 236241f5d225 src/core/linux/SDL_evdev.h --- a/src/core/linux/SDL_evdev.h Mon Aug 25 10:55:54 2014 -0700 +++ b/src/core/linux/SDL_evdev.h Wed Aug 27 14:05:26 2014 +0200 @@ -28,11 +28,47 @@ #include "SDL_events.h" #include +#include + +typedef enum +{ + SDL_EVDEV_UPDATING, + SDL_EVDEV_UPDATED +} SDL_EVDEV_state; + +#if SDL_INPUT_MTDEV +struct mtdev; + +typedef enum +{ + SDL_EVDEV_MT_SLOT_UPDATING, + SDL_EVDEV_MT_SLOT_UPDATED, + SDL_EVDEV_MT_SLOT_INVALIDATING, + SDL_EVDEV_MT_SLOT_INVALID +} SDL_EVDEV_mt_slot_state; +#endif typedef struct SDL_evdevlist_item { char *path; int fd; + + SDL_EVDEV_state abs_state; + int abs_x; + int abs_y; + + SDL_EVDEV_state rel_state; + int rel_x; + int rel_y; + +#if SDL_INPUT_MTDEV + struct mtdev *mt_device; + unsigned int mt_slot; + SDL_EVDEV_mt_slot_state mt_slot_state; + float mt_x; + float mt_y; +#endif + struct SDL_evdevlist_item *next; } SDL_evdevlist_item; diff -r 236241f5d225 src/core/linux/SDL_udev.c --- a/src/core/linux/SDL_udev.c Mon Aug 25 10:55:54 2014 -0700 +++ b/src/core/linux/SDL_udev.c Wed Aug 27 14:05:26 2014 +0200 @@ -307,6 +307,11 @@ devclass |= SDL_UDEV_DEVICE_KEYBOARD; } + val = _this->udev_device_get_property_value(dev, "ID_INPUT_TOUCHSCREEN"); + if (val != NULL && SDL_strcmp(val, "1") == 0 ) { + devclass |= SDL_UDEV_DEVICE_TOUCHSCREEN; + } + if (devclass == 0) { // Fall back to old style input classes val = _this->udev_device_get_property_value(dev, "ID_CLASS"); diff -r 236241f5d225 src/core/linux/SDL_udev.h --- a/src/core/linux/SDL_udev.h Mon Aug 25 10:55:54 2014 -0700 +++ b/src/core/linux/SDL_udev.h Wed Aug 27 14:05:26 2014 +0200 @@ -52,7 +52,8 @@ SDL_UDEV_DEVICE_MOUSE = 0x0001, SDL_UDEV_DEVICE_KEYBOARD = 0x0002, SDL_UDEV_DEVICE_JOYSTICK = 0x0004, - SDL_UDEV_DEVICE_SOUND = 0x0008 + SDL_UDEV_DEVICE_SOUND = 0x0008, + SDL_UDEV_DEVICE_TOUCHSCREEN = 0x0010 } SDL_UDEV_deviceclass; typedef void (*SDL_UDEV_Callback)(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);