sdl2-compat: hidapi: Deal with SDL_hid_device_info internals changing in SDL3.

From 1f3483131fdcf2302f0d4e747dcea57390f38d79 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Sat, 27 May 2023 23:01:10 -0400
Subject: [PATCH] hidapi: Deal with SDL_hid_device_info internals changing in
 SDL3.

---
 src/dynapi/SDL_dynapi_procs.h |  4 +-
 src/sdl2_compat.c             | 89 +++++++++++++++++++++++++++++++++++
 src/sdl2_compat.h             |  3 ++
 src/sdl2_protos.h             |  4 +-
 src/sdl3_syms.h               |  4 +-
 5 files changed, 98 insertions(+), 6 deletions(-)

diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 5d83d27..6f79280 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -902,8 +902,8 @@ SDL_DYNAPI_PROC(const char*,SDL_GameControllerGetAppleSFSymbolsNameForAxis,(SDL_
 SDL_DYNAPI_PROC(int,SDL_hid_init,(void),(),return)
 SDL_DYNAPI_PROC(int,SDL_hid_exit,(void),(),return)
 SDL_DYNAPI_PROC(Uint32,SDL_hid_device_change_count,(void),(),return)
-SDL_DYNAPI_PROC(SDL_hid_device_info*,SDL_hid_enumerate,(unsigned short a, unsigned short b),(a,b),return)
-SDL_DYNAPI_PROC(void,SDL_hid_free_enumeration,(SDL_hid_device_info *a),(a),)
+SDL_DYNAPI_PROC(SDL2_hid_device_info*,SDL_hid_enumerate,(unsigned short a, unsigned short b),(a,b),return)
+SDL_DYNAPI_PROC(void,SDL_hid_free_enumeration,(SDL2_hid_device_info *a),(a),)
 SDL_DYNAPI_PROC(SDL_hid_device*,SDL_hid_open,(unsigned short a, unsigned short b, const wchar_t *c),(a,b,c),return)
 SDL_DYNAPI_PROC(SDL_hid_device*,SDL_hid_open_path,(const char *a, int b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_hid_write,(SDL_hid_device *a, const unsigned char *b, size_t c),(a,b,c),return)
diff --git a/src/sdl2_compat.c b/src/sdl2_compat.c
index 6f48913..97aa826 100644
--- a/src/sdl2_compat.c
+++ b/src/sdl2_compat.c
@@ -1083,6 +1083,27 @@ typedef struct EventFilterWrapperData
 } EventFilterWrapperData;
 
 
+/* SDL3 added a bus_type field we need to workaround. */
+typedef struct SDL2_hid_device_info
+{
+    char *path;
+    unsigned short vendor_id;
+    unsigned short product_id;
+    wchar_t *serial_number;
+    unsigned short release_number;
+    wchar_t *manufacturer_string;
+    wchar_t *product_string;
+    unsigned short usage_page;
+    unsigned short usage;
+    int interface_number;
+    int interface_class;
+    int interface_subclass;
+    int interface_protocol;
+    struct SDL2_hid_device_info *next;
+} SDL2_hid_device_info;
+
+
+
 /* Some SDL2 state we need to keep... */
 
 /* !!! FIXME: unify coding convention on the globals: some are MyVariableName and some are my_variable_name */
@@ -5585,6 +5606,74 @@ SDL_hid_open_path(const char *path, int bExclusive)
 }
 
 
+DECLSPEC void SDLCALL
+SDL_hid_free_enumeration(SDL2_hid_device_info *devs)
+{
+    while (devs) {
+        struct SDL2_hid_device_info *next = devs->next;
+        SDL_free(devs->path);
+        SDL_free(devs->serial_number);
+        SDL_free(devs->manufacturer_string);
+        SDL_free(devs->product_string);
+        SDL_free(devs);
+        devs = next;
+    }
+}
+
+DECLSPEC SDL2_hid_device_info * SDLCALL
+SDL_hid_enumerate(unsigned short vendor_id, unsigned short product_id)
+{
+    /* the struct is slightly different in SDL3, convert it. */
+    SDL2_hid_device_info *retval = NULL;
+    SDL_hid_device_info *list3 = SDL3_hid_enumerate(vendor_id, product_id);
+
+    if (list3 != NULL) {
+        SDL2_hid_device_info *tail = NULL;
+        SDL_hid_device_info *i;
+        for (i = list3; i != NULL; i = i->next) {
+            SDL2_hid_device_info *info = (SDL2_hid_device_info *) SDL_calloc(1, sizeof (SDL2_hid_device_info));
+            char *path = SDL3_strdup(i->path);
+            wchar_t *serial_number = SDL3_wcsdup(i->serial_number);
+            wchar_t *manufacturer_string = SDL3_wcsdup(i->manufacturer_string);
+            wchar_t *product_string = SDL3_wcsdup(i->product_string);
+            if (!info || !path || !serial_number || !manufacturer_string || !product_string) {
+                SDL_hid_free_enumeration(retval);
+                SDL3_free(info);
+                SDL3_free(path);
+                SDL3_free(serial_number);
+                SDL3_free(manufacturer_string);
+                SDL3_free(product_string);
+                SDL3_OutOfMemory();
+                return NULL;
+            }
+            if (tail) {
+                tail->next = info;
+            } else {
+                retval = info;
+            }
+            info->path = path;
+            info->vendor_id = i->vendor_id;
+            info->product_id = i->product_id;
+            info->serial_number = serial_number;
+            info->release_number = i->release_number;
+            info->manufacturer_string = manufacturer_string;
+            info->product_string = product_string;
+            info->usage_page = i->usage_page;
+            info->usage = i->usage;
+            info->interface_number = i->interface_number;
+            info->interface_class = i->interface_class;
+            info->interface_subclass = i->interface_subclass;
+            info->interface_protocol = i->interface_protocol;
+            info->next = NULL;
+            tail = info;
+        }
+        SDL3_hid_free_enumeration(list3);
+    }
+
+    return retval;
+}
+
+
 #ifdef __WINRT__
 DECLSPEC int SDLCALL
 SDL_WinRTRunApp(SDL_main_func mainFunction, void *reserved)
diff --git a/src/sdl2_compat.h b/src/sdl2_compat.h
index 6676815..501765d 100644
--- a/src/sdl2_compat.h
+++ b/src/sdl2_compat.h
@@ -44,6 +44,9 @@ typedef Sint64 SDL2_GestureID;
 typedef struct SDL2_RWops SDL2_RWops;
 typedef struct SDL2_DisplayMode SDL2_DisplayMode;
 
+
+typedef struct SDL2_hid_device_info SDL2_hid_device_info;
+
 typedef union SDL2_Event SDL2_Event;
 typedef int (SDLCALL *SDL2_EventFilter) (void *userdata, SDL2_Event *event);
 
diff --git a/src/sdl2_protos.h b/src/sdl2_protos.h
index 7ddc88d..0c49047 100644
--- a/src/sdl2_protos.h
+++ b/src/sdl2_protos.h
@@ -887,8 +887,8 @@ SDL2_PROTO(const char*,GameControllerGetAppleSFSymbolsNameForAxis,(SDL_GameContr
 SDL2_PROTO(int,hid_init,(void))
 SDL2_PROTO(int,hid_exit,(void))
 SDL2_PROTO(Uint32,hid_device_change_count,(void))
-SDL2_PROTO(SDL_hid_device_info*,hid_enumerate,(unsigned short a, unsigned short b))
-SDL2_PROTO(void,hid_free_enumeration,(SDL_hid_device_info *a))
+SDL2_PROTO(SDL2_hid_device_info*,hid_enumerate,(unsigned short a, unsigned short b))
+SDL2_PROTO(void,hid_free_enumeration,(SDL2_hid_device_info *a))
 SDL2_PROTO(SDL_hid_device*,hid_open,(unsigned short a, unsigned short b, const wchar_t *c))
 SDL2_PROTO(SDL_hid_device*,hid_open_path,(const char *a, int b))
 SDL2_PROTO(int,hid_write,(SDL_hid_device *a, const unsigned char *b, size_t c))
diff --git a/src/sdl3_syms.h b/src/sdl3_syms.h
index 0d6a485..4a70ab9 100644
--- a/src/sdl3_syms.h
+++ b/src/sdl3_syms.h
@@ -802,8 +802,8 @@ SDL3_SYM_RENAMED(const char*,GameControllerGetAppleSFSymbolsNameForAxis,GetGamep
 SDL3_SYM_PASSTHROUGH(int,hid_init,(void),(),return)
 SDL3_SYM_PASSTHROUGH(int,hid_exit,(void),(),return)
 SDL3_SYM_PASSTHROUGH(Uint32,hid_device_change_count,(void),(),return)
-SDL3_SYM_PASSTHROUGH(SDL_hid_device_info*,hid_enumerate,(unsigned short a, unsigned short b),(a,b),return)
-SDL3_SYM_PASSTHROUGH(void,hid_free_enumeration,(SDL_hid_device_info *a),(a),)
+SDL3_SYM(SDL_hid_device_info*,hid_enumerate,(unsigned short a, unsigned short b),(a,b),return)
+SDL3_SYM(void,hid_free_enumeration,(SDL_hid_device_info *a),(a),)
 SDL3_SYM_PASSTHROUGH(SDL_hid_device*,hid_open,(unsigned short a, unsigned short b, const wchar_t *c),(a,b,c),return)
 SDL3_SYM(SDL_hid_device*,hid_open_path,(const char *a),(a),return)
 SDL3_SYM_PASSTHROUGH(int,hid_write,(SDL_hid_device *a, const unsigned char *b, size_t c),(a,b,c),return)