sdl2-compat: Added support for SDL2 prerelease mouse events

From 26f81ebdf52d213fe1371016b5ccffb5f349e050 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 31 Jan 2025 22:27:20 -0800
Subject: [PATCH] Added support for SDL2 prerelease mouse events

This is the version of SDL used by the Torchlight Linux port in the Humble Bundle.

Fixes https://github.com/libsdl-org/sdl2-compat/issues/151
---
 src/sdl2_compat.c | 56 +++++++++++++++++++++++++++++++++++++----------
 src/sdl2_compat.h | 37 +++++++++++++++++++++++++++++++
 2 files changed, 81 insertions(+), 12 deletions(-)

diff --git a/src/sdl2_compat.c b/src/sdl2_compat.c
index 0963a72..9939898 100644
--- a/src/sdl2_compat.c
+++ b/src/sdl2_compat.c
@@ -352,6 +352,9 @@ UnloadSDL3(void)
     CloseSDL3Library();
 }
 
+// This is used for the Torchlight Linux port which predates the official SDL2 release
+static bool UseSDL2PrereleaseEvents;
+
 typedef struct QuirkEntryType
 {
     const char *exe_name;
@@ -601,6 +604,9 @@ SDL2Compat_ApplyQuirks(bool force_x11)
             }
         }
     }
+    if (SDL3_strcmp(exe_name, "Torchlight.bin.x86_64") == 0) {
+        UseSDL2PrereleaseEvents = true;
+    }
 }
 
 static int
@@ -1382,10 +1388,20 @@ Event3to2(const SDL_Event *event3, SDL2_Event *event2)
                 event3 = &cvtevent3;
             }
         }
-        event2->motion.x = (Sint32)event3->motion.x;
-        event2->motion.y = (Sint32)event3->motion.y;
-        event2->motion.xrel = (Sint32)event3->motion.xrel;
-        event2->motion.yrel = (Sint32)event3->motion.yrel;
+        if (UseSDL2PrereleaseEvents) {
+            SDL2PRERELEASE_MouseMotionEvent *motion = (SDL2PRERELEASE_MouseMotionEvent *)&event2->motion;
+            motion->state = (Uint8)event3->motion.state;
+            motion->x = (Sint32)event3->motion.x;
+            motion->y = (Sint32)event3->motion.y;
+            motion->xrel = (Sint32)event3->motion.xrel;
+            motion->yrel = (Sint32)event3->motion.yrel;
+        } else {
+            SDL2_MouseMotionEvent *motion = &event2->motion;
+            motion->x = (Sint32)event3->motion.x;
+            motion->y = (Sint32)event3->motion.y;
+            motion->xrel = (Sint32)event3->motion.xrel;
+            motion->yrel = (Sint32)event3->motion.yrel;
+        }
         break;
     case SDL_EVENT_MOUSE_BUTTON_DOWN:
     case SDL_EVENT_MOUSE_BUTTON_UP:
@@ -1399,8 +1415,17 @@ Event3to2(const SDL_Event *event3, SDL2_Event *event2)
                 event3 = &cvtevent3;
             }
         }
-        event2->button.x = (Sint32)event3->button.x;
-        event2->button.y = (Sint32)event3->button.y;
+        if (UseSDL2PrereleaseEvents) {
+            SDL2PRERELEASE_MouseButtonEvent *button = (SDL2PRERELEASE_MouseButtonEvent *)&event2->button;
+            button->button = event3->button.button;
+            button->state = event3->button.down;
+            button->x = (Sint32)event3->button.x;
+            button->y = (Sint32)event3->button.y;
+        } else {
+            SDL2_MouseButtonEvent *button = &event2->button;
+            button->x = (Sint32)event3->button.x;
+            button->y = (Sint32)event3->button.y;
+        }
         break;
     case SDL_EVENT_MOUSE_WHEEL:
         renderer = SDL3_GetRenderer(SDL3_GetWindowFromID(event3->wheel.windowID));
@@ -1413,12 +1438,19 @@ Event3to2(const SDL_Event *event3, SDL2_Event *event2)
                 event3 = &cvtevent3;
             }
         }
-        event2->wheel.x = (Sint32)event3->wheel.x;
-        event2->wheel.y = (Sint32)event3->wheel.y;
-        event2->wheel.preciseX = event3->wheel.x;
-        event2->wheel.preciseY = event3->wheel.y;
-        event2->wheel.mouseX = (Sint32)event3->wheel.mouse_x;
-        event2->wheel.mouseY = (Sint32)event3->wheel.mouse_y;
+        if (UseSDL2PrereleaseEvents) {
+            SDL2PRERELEASE_MouseWheelEvent *wheel = (SDL2PRERELEASE_MouseWheelEvent *)&event2->wheel;
+            wheel->x = (Sint32)event3->wheel.x;
+            wheel->y = (Sint32)event3->wheel.y;
+        } else {
+            SDL2_MouseWheelEvent *wheel = &event2->wheel;
+            wheel->x = (Sint32)event3->wheel.x;
+            wheel->y = (Sint32)event3->wheel.y;
+            wheel->preciseX = event3->wheel.x;
+            wheel->preciseY = event3->wheel.y;
+            wheel->mouseX = (Sint32)event3->wheel.mouse_x;
+            wheel->mouseY = (Sint32)event3->wheel.mouse_y;
+        }
         break;
     case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
     case SDL_EVENT_GAMEPAD_BUTTON_UP:
diff --git a/src/sdl2_compat.h b/src/sdl2_compat.h
index 05cbbce..a0d07df 100644
--- a/src/sdl2_compat.h
+++ b/src/sdl2_compat.h
@@ -785,6 +785,21 @@ typedef struct SDL2_MouseMotionEvent
     Sint32 yrel;
 } SDL2_MouseMotionEvent;
 
+typedef struct SDL2PRERELEASE_MouseMotionEvent
+{
+    Uint32 type;
+    Uint32 timestamp;
+    Uint32 windowID;
+    Uint8 state;
+    Uint8 padding1;
+    Uint8 padding2;
+    Uint8 padding3;
+    int x;
+    int y;
+    int xrel;
+    int yrel;
+} SDL2PRERELEASE_MouseMotionEvent;
+
 typedef struct SDL2_MouseButtonEvent
 {
     Uint32 type;
@@ -799,6 +814,19 @@ typedef struct SDL2_MouseButtonEvent
     Sint32 y;
 } SDL2_MouseButtonEvent;
 
+typedef struct SDL2PRERELEASE_MouseButtonEvent
+{
+    Uint32 type;
+    Uint32 timestamp;
+    Uint32 windowID;
+    Uint8 button;
+    Uint8 state;
+    Uint8 padding1;
+    Uint8 padding2;
+    int x;
+    int y;
+} SDL2PRERELEASE_MouseButtonEvent;
+
 typedef struct SDL2_MouseWheelEvent
 {
     Uint32 type;
@@ -814,6 +842,15 @@ typedef struct SDL2_MouseWheelEvent
     Sint32 mouseY;
 } SDL2_MouseWheelEvent;
 
+typedef struct SDL2PRERELEASE_MouseWheelEvent
+{
+    Uint32 type;
+    Uint32 timestamp;
+    Uint32 windowID;
+    int x;
+    int y;
+} SDL2PRERELEASE_MouseWheelEvent;
+
 typedef struct SDL2_JoyAxisEvent
 {
     Uint32 type;