Add hint SDL_HINT_MOUSE_TOUCH_EVENTS for mouse events to generate touch events

controlling whether mouse events should generate synthetic touch events
By default SDL will *not* generate touch events for mouse events
diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index ac605db..90d0e81 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -316,6 +316,18 @@
 #define SDL_HINT_TOUCH_MOUSE_EVENTS    "SDL_TOUCH_MOUSE_EVENTS"
 
 /**
+ *  \brief  A variable controlling whether mouse events should generate synthetic touch events
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - Mouse events will not generate touch events
+ *    "1"       - Mouse events will generate touch events
+ *
+ *  By default SDL will *not* generate touch events for mouse events
+ */
+
+#define SDL_HINT_MOUSE_TOUCH_EVENTS    "SDL_MOUSE_TOUCH_EVENTS"
+
+/**
  *  \brief Minimize your SDL_Window if it loses key focus when in fullscreen mode. Defaults to true.
  *
  */
diff --git a/include/SDL_touch.h b/include/SDL_touch.h
index ae94abf..99dbcb8 100644
--- a/include/SDL_touch.h
+++ b/include/SDL_touch.h
@@ -60,6 +60,9 @@
 /* Used as the device ID for mouse events simulated with touch input */
 #define SDL_TOUCH_MOUSEID ((Uint32)-1)
 
+/* Used as the SDL_TouchID for touch events simulated with mouse input */
+#define SDL_MOUSE_TOUCHID ((Sint64)-1)
+
 
 /* Function prototypes */
 
diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c
index 451b451..893ecc7 100644
--- a/src/events/SDL_mouse.c
+++ b/src/events/SDL_mouse.c
@@ -37,6 +37,9 @@
 /* The mouse state */
 static SDL_Mouse SDL_mouse;
 
+/* for mapping mouse events to touch */
+static SDL_bool track_mouse_down = SDL_FALSE;
+
 static int
 SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y);
 
@@ -104,6 +107,21 @@
     }
 }
 
+static void SDLCALL
+SDL_MouseTouchEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
+{
+    SDL_Mouse *mouse = (SDL_Mouse *)userdata;
+
+    if (hint && (*hint == '1' || SDL_strcasecmp(hint, "true") == 0)) {
+
+        SDL_AddTouch(SDL_MOUSE_TOUCHID, SDL_TOUCH_DEVICE_DIRECT, "mouse_input");
+
+        mouse->mouse_touch_events = SDL_TRUE;
+    } else {
+        mouse->mouse_touch_events = SDL_FALSE;
+    }
+}
+
 /* Public functions */
 int
 SDL_MouseInit(void)
@@ -127,6 +145,9 @@
     SDL_AddHintCallback(SDL_HINT_TOUCH_MOUSE_EVENTS,
                         SDL_TouchMouseEventsChanged, mouse);
 
+    SDL_AddHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS,
+                        SDL_MouseTouchEventsChanged, mouse);
+
     mouse->cursor_shown = SDL_TRUE;
 
     return (0);
@@ -298,6 +319,17 @@
     int xrel;
     int yrel;
 
+    /* SDL_HINT_MOUSE_TOUCH_EVENTS: controlling whether mouse events should generate synthetic touch events */
+    if (mouse->mouse_touch_events) {
+        if (mouseID != SDL_TOUCH_MOUSEID && !relative && track_mouse_down) {
+            if (window) {
+                float fx = (float)x / (float)window->w;
+                float fy = (float)y / (float)window->h;
+                SDL_SendTouchMotion(SDL_MOUSE_TOUCHID, 0, fx, fy, 1.0f);
+            }
+        }
+    }
+
     if (mouseID != SDL_TOUCH_MOUSEID && mouse->relative_mode_warp) {
         int center_x = 0, center_y = 0;
         SDL_GetWindowSize(window, &center_x, &center_y);
@@ -443,6 +475,22 @@
     Uint32 type;
     Uint32 buttonstate = mouse->buttonstate;
 
+    /* SDL_HINT_MOUSE_TOUCH_EVENTS: controlling whether mouse events should generate synthetic touch events */
+    if (mouse->mouse_touch_events) {
+        if (mouseID != SDL_TOUCH_MOUSEID && button == SDL_BUTTON_LEFT) {
+            if (window) {
+                float fx = (float)mouse->x / (float)window->w;
+                float fy = (float)mouse->y / (float)window->h;
+                if (state == SDL_PRESSED) {
+                    track_mouse_down = SDL_TRUE;
+                } else {
+                    track_mouse_down = SDL_FALSE;
+                }
+                SDL_SendTouch(SDL_MOUSE_TOUCHID, 0, track_mouse_down, fx, fy, 1.0f);
+            }
+        }
+    }
+
     /* Figure out which event to perform */
     switch (state) {
     case SDL_PRESSED:
diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h
index 8994e02..9f88d40 100644
--- a/src/events/SDL_mouse_c.h
+++ b/src/events/SDL_mouse_c.h
@@ -93,6 +93,7 @@
     Uint32 double_click_time;
     int double_click_radius;
     SDL_bool touch_mouse_events;
+    SDL_bool mouse_touch_events;
 
     /* Data for double-click tracking */
     int num_clickstates;
diff --git a/src/events/SDL_touch.c b/src/events/SDL_touch.c
index 1f5810a..3274cc5 100644
--- a/src/events/SDL_touch.c
+++ b/src/events/SDL_touch.c
@@ -249,22 +249,25 @@
     {
         SDL_Mouse *mouse = SDL_GetMouse();
         if (mouse->touch_mouse_events) {
-            SDL_Window *window = SDL_GetMouseFocus();
-            if (window) {
-                if (down) {
-                    if (finger_touching == SDL_FALSE) {
-                        int pos_x = (int)(x * (float)window->w);
-                        int pos_y = (int)(y * (float)window->h);
-                        finger_touching = SDL_TRUE;
-                        track_touchid = id;
-                        track_fingerid = fingerid;
-                        SDL_SendMouseMotion(window, SDL_TOUCH_MOUSEID, 0, pos_x, pos_y);
-                        SDL_SendMouseButton(window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
-                    }
-                } else {
-                    if (finger_touching == SDL_TRUE && track_touchid == id && track_fingerid == fingerid) {
-                        SDL_SendMouseButton(window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
-                        finger_touching = SDL_FALSE;
+            /* FIXME: maybe we should only restrict to a few SDL_TouchDeviceType */
+            if (id != SDL_MOUSE_TOUCHID) {
+                SDL_Window *window = SDL_GetMouseFocus();
+                if (window) {
+                    if (down) {
+                        if (finger_touching == SDL_FALSE) {
+                            int pos_x = (int)(x * (float)window->w);
+                            int pos_y = (int)(y * (float)window->h);
+                            finger_touching = SDL_TRUE;
+                            track_touchid = id;
+                            track_fingerid = fingerid;
+                            SDL_SendMouseMotion(window, SDL_TOUCH_MOUSEID, 0, pos_x, pos_y);
+                            SDL_SendMouseButton(window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
+                        }
+                    } else {
+                        if (finger_touching == SDL_TRUE && track_touchid == id && track_fingerid == fingerid) {
+                            SDL_SendMouseButton(window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
+                            finger_touching = SDL_FALSE;
+                        }
                     }
                 }
             }
@@ -339,12 +342,14 @@
     {
         SDL_Mouse *mouse = SDL_GetMouse();
         if (mouse->touch_mouse_events) {
-            SDL_Window *window = SDL_GetMouseFocus();
-            if (window) {
-                if (finger_touching == SDL_TRUE && track_touchid == id && track_fingerid == fingerid) {
-                    int pos_x = (int)(x * (float)window->w);
-                    int pos_y = (int)(y * (float)window->h);
-                    SDL_SendMouseMotion(window, SDL_TOUCH_MOUSEID, 0, pos_x, pos_y);
+            if (id != SDL_MOUSE_TOUCHID) {
+                SDL_Window *window = SDL_GetMouseFocus();
+                if (window) {
+                    if (finger_touching == SDL_TRUE && track_touchid == id && track_fingerid == fingerid) {
+                        int pos_x = (int)(x * (float)window->w);
+                        int pos_y = (int)(y * (float)window->h);
+                        SDL_SendMouseMotion(window, SDL_TOUCH_MOUSEID, 0, pos_x, pos_y);
+                    }
                 }
             }
         }