Commit cf31ea14782f758f25fa340a145a9b576ae9727d

Sam Lantinga 2017-02-11T11:14:48

Fixed bug 3583 - X11 touch device can be permanently lost Volumetric In X11 the SDL error "Unknown touch device" can occur after which the application stops recognizing touch events. For a kiosk-type application this results in a hang as far as the user is concerned. This is reproducible on HP Z220/Z230/Z240 workstations by swapping USB cables for a while and it also occurs with no physical changes, probably due to USB device power management. A workaround is to make SDL re-enumerate the touch devices like it does at startup. A patch is attached.

diff --git a/src/events/SDL_touch.c b/src/events/SDL_touch.c
index 4c98885..92e76f2 100644
--- a/src/events/SDL_touch.c
+++ b/src/events/SDL_touch.c
@@ -25,6 +25,7 @@
 #include "SDL_assert.h"
 #include "SDL_events.h"
 #include "SDL_events_c.h"
+#include "../video/SDL_sysvideo.h"
 
 
 static int SDL_num_touch = 0;
@@ -48,7 +49,7 @@ SDL_TouchID
 SDL_GetTouchDevice(int index)
 {
     if (index < 0 || index >= SDL_num_touch) {
-        SDL_SetError("Unknown touch device");
+        SDL_SetError("Unknown touch device index %d", index);
         return 0;
     }
     return SDL_touchDevices[index]->id;
@@ -74,7 +75,12 @@ SDL_GetTouch(SDL_TouchID id)
 {
     int index = SDL_GetTouchIndex(id);
     if (index < 0 || index >= SDL_num_touch) {
-        SDL_SetError("Unknown touch device");
+        if (SDL_GetVideoDevice()->ResetTouch != NULL) {
+            SDL_SetError("Unknown touch id %d, resetting", (int) id);
+            (SDL_GetVideoDevice()->ResetTouch)(SDL_GetVideoDevice());
+        } else {
+            SDL_SetError("Unknown touch device id %d, cannot reset", (int) id);
+        }
         return NULL;
     }
     return SDL_touchDevices[index];
diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index 2778490..b440858 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -163,6 +163,11 @@ struct SDL_VideoDevice
      */
     void (*VideoQuit) (_THIS);
 
+    /*
+     * Reinitialize the touch devices -- called if an unknown touch ID occurs.
+     */
+    void (*ResetTouch) (_THIS);
+
     /* * * */
     /*
      * Display functions
diff --git a/src/video/x11/SDL_x11touch.c b/src/video/x11/SDL_x11touch.c
index ba841f5..12d2ef8 100644
--- a/src/video/x11/SDL_x11touch.c
+++ b/src/video/x11/SDL_x11touch.c
@@ -42,6 +42,13 @@ X11_QuitTouch(_THIS)
     SDL_TouchQuit();
 }
 
+void
+X11_ResetTouch(_THIS)
+{
+    X11_QuitTouch(_this);
+    X11_InitTouch(_this);
+}
+
 #endif /* SDL_VIDEO_DRIVER_X11 */
 
 /* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/x11/SDL_x11touch.h b/src/video/x11/SDL_x11touch.h
index 9c0dfe6..d077f74 100644
--- a/src/video/x11/SDL_x11touch.h
+++ b/src/video/x11/SDL_x11touch.h
@@ -25,6 +25,7 @@
 
 extern void X11_InitTouch(_THIS);
 extern void X11_QuitTouch(_THIS);
+extern void X11_ResetTouch(_THIS);
 
 #endif /* SDL_x11touch_h_ */
 
diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c
index e8e3372..7ced9aa 100644
--- a/src/video/x11/SDL_x11video.c
+++ b/src/video/x11/SDL_x11video.c
@@ -216,6 +216,7 @@ X11_CreateDevice(int devindex)
     /* Set the function pointers */
     device->VideoInit = X11_VideoInit;
     device->VideoQuit = X11_VideoQuit;
+    device->ResetTouch = X11_ResetTouch;
     device->GetDisplayModes = X11_GetDisplayModes;
     device->GetDisplayBounds = X11_GetDisplayBounds;
     device->GetDisplayUsableBounds = X11_GetDisplayUsableBounds;