SDL: Added SDL_HINT_HIDAPI_IGNORE_DEVICES to specify devices that should be ignored in SDL_hid_enumerate() (007c3)

From 007c36e5138706e47bec56f6aaee158b1499201e Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 24 May 2023 22:37:38 -0700
Subject: [PATCH] Added SDL_HINT_HIDAPI_IGNORE_DEVICES to specify devices that
 should be ignored in SDL_hid_enumerate()

---
 src/hidapi/SDL_hidapi.c         | 39 +++++++++++++++++++++++++++++++++
 src/hidapi/SDL_hidapi_c.h       |  6 +++--
 src/hidapi/SDL_hidapi_windows.h |  3 ---
 src/hidapi/android/hid.cpp      | 13 +++++------
 src/hidapi/ios/hid.m            | 11 +++-------
 src/hidapi/libusb/hid.c         |  7 ++++++
 src/hidapi/linux/hid.c          | 10 +++++++++
 src/hidapi/mac/hid.c            |  9 ++++++++
 src/hidapi/windows/hid.c        |  7 ++++++
 9 files changed, 84 insertions(+), 21 deletions(-)

diff --git a/src/hidapi/SDL_hidapi.c b/src/hidapi/SDL_hidapi.c
index f0c62634a9da..3d21e788498b 100644
--- a/src/hidapi/SDL_hidapi.c
+++ b/src/hidapi/SDL_hidapi.c
@@ -527,6 +527,8 @@ static void HIDAPI_ShutdownDiscovery(void)
 
 /* Platform HIDAPI Implementation */
 
+#define HIDAPI_IGNORE_DEVICE(VID, PID)  SDL_HIDAPI_ShouldIgnoreDevice(VID, PID)
+
 struct PLATFORM_hid_device_;
 typedef struct PLATFORM_hid_device_ PLATFORM_hid_device;
 
@@ -1029,6 +1031,7 @@ static void CopyHIDDeviceInfo(struct hid_device_info *pSrc, struct SDL_hid_devic
 #undef WCOPY_IF_EXISTS
 
 static int SDL_hidapi_refcount = 0;
+static char *SDL_hidapi_ignored_devices = NULL;
 
 static void SDL_SetHIDAPIError(const wchar_t *error)
 {
@@ -1041,6 +1044,33 @@ static void SDL_SetHIDAPIError(const wchar_t *error)
     }
 }
 
+static void SDLCALL IgnoredDevicesChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
+{
+    if (SDL_hidapi_ignored_devices) {
+        SDL_free(SDL_hidapi_ignored_devices);
+    }
+    if (hint && *hint) {
+        SDL_hidapi_ignored_devices = SDL_strdup(hint);
+    } else {
+        SDL_hidapi_ignored_devices = NULL;
+    }
+}
+
+SDL_bool SDL_HIDAPI_ShouldIgnoreDevice(Uint16 vendor_id, Uint16 product_id)
+{
+    /* See if there are any devices we should skip in enumeration */
+    if (SDL_hidapi_ignored_devices) {
+        char vendor_match[16], product_match[16];
+        SDL_snprintf(vendor_match, sizeof(vendor_match), "0x%.4x/0x0000", vendor_id);
+        SDL_snprintf(product_match, sizeof(product_match), "0x%.4x/0x%.4x", vendor_id, product_id);
+        if (SDL_strcasestr(SDL_hidapi_ignored_devices, vendor_match) ||
+            SDL_strcasestr(SDL_hidapi_ignored_devices, product_match)) {
+            return SDL_TRUE;
+        }
+    }
+    return SDL_FALSE;
+}
+
 int SDL_hid_init(void)
 {
     int attempts = 0, success = 0;
@@ -1050,6 +1080,8 @@ int SDL_hid_init(void)
         return 0;
     }
 
+    SDL_AddHintCallback(SDL_HINT_HIDAPI_IGNORE_DEVICES, IgnoredDevicesChanged, NULL);
+
 #ifdef SDL_USE_LIBUDEV
     if (SDL_getenv("SDL_HIDAPI_JOYSTICK_DISABLE_UDEV") != NULL) {
         SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
@@ -1193,6 +1225,13 @@ int SDL_hid_exit(void)
     }
 #endif /* HAVE_LIBUSB */
 
+    SDL_DelHintCallback(SDL_HINT_HIDAPI_IGNORE_DEVICES, IgnoredDevicesChanged, NULL);
+
+    if (SDL_hidapi_ignored_devices) {
+        SDL_free(SDL_hidapi_ignored_devices);
+        SDL_hidapi_ignored_devices = NULL;
+    }
+
     return result;
 }
 
diff --git a/src/hidapi/SDL_hidapi_c.h b/src/hidapi/SDL_hidapi_c.h
index 2b9b7d21c696..8f69cba4c5bf 100644
--- a/src/hidapi/SDL_hidapi_c.h
+++ b/src/hidapi/SDL_hidapi_c.h
@@ -20,8 +20,11 @@
 */
 #include "SDL_internal.h"
 
-#ifdef SDL_JOYSTICK_HIDAPI
 
+/* Return true if the HIDAPI should ignore a device during enumeration */
+extern SDL_bool SDL_HIDAPI_ShouldIgnoreDevice(Uint16 vendor_id, Uint16 product_id);
+
+#ifdef SDL_JOYSTICK_HIDAPI
 #ifdef HAVE_LIBUSB
 #define HAVE_ENABLE_GAMECUBE_ADAPTORS
 #endif
@@ -29,5 +32,4 @@
 #ifdef HAVE_ENABLE_GAMECUBE_ADAPTORS
 extern void SDL_EnableGameCubeAdaptors(void);
 #endif
-
 #endif /* SDL_JOYSTICK_HIDAPI */
diff --git a/src/hidapi/SDL_hidapi_windows.h b/src/hidapi/SDL_hidapi_windows.h
index b1b6b4d672f7..b09b0457eaad 100644
--- a/src/hidapi/SDL_hidapi_windows.h
+++ b/src/hidapi/SDL_hidapi_windows.h
@@ -25,9 +25,6 @@
 #define free        SDL_free
 #define malloc      SDL_malloc
 #define memcmp      SDL_memcmp
-#define snprintf    SDL_snprintf
-#define strlen      SDL_strlen
-#define _strnicmp   SDL_strncasecmp
 #define swprintf    SDL_swprintf
 #define towupper    SDL_toupper
 #define wcscmp      SDL_wcscmp
diff --git a/src/hidapi/android/hid.cpp b/src/hidapi/android/hid.cpp
index ae4b40c60eb7..6a8dac407db7 100644
--- a/src/hidapi/android/hid.cpp
+++ b/src/hidapi/android/hid.cpp
@@ -51,6 +51,9 @@
 
 #ifndef SDL_HIDAPI_DISABLED
 
+extern "C" {
+#include "../SDL_hidapi_c.h"
+}
 #include "../../core/android/SDL_android.h"
 
 #define hid_close                    PLATFORM_hid_close
@@ -1064,7 +1067,6 @@ int hid_init(void)
 struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
 {
 	struct hid_device_info *root = NULL;
-	const char *hint = SDL_GetHint(SDL_HINT_HIDAPI_IGNORE_DEVICES);
 
 	hid_mutex_guard l( &g_DevicesMutex );
 	for ( hid_device_ref<CHIDDevice> pDevice = g_Devices; pDevice; pDevice = pDevice->next )
@@ -1072,13 +1074,8 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
 		const hid_device_info *info = pDevice->GetDeviceInfo();
 
 		/* See if there are any devices we should skip in enumeration */
-		if (hint) {
-			char vendor_match[16], product_match[16];
-			SDL_snprintf(vendor_match, sizeof(vendor_match), "0x%.4x/0x0000", info->vendor_id);
-			SDL_snprintf(product_match, sizeof(product_match), "0x%.4x/0x%.4x", info->vendor_id, info->product_id);
-			if (SDL_strcasestr(hint, vendor_match) || SDL_strcasestr(hint, product_match)) {
-				continue;
-			}
+		if (SDL_HIDAPI_ShouldIgnoreDevice(info->vendor_id, info->product_id)) {
+			continue;
 		}
 
 		if ( ( vendor_id == 0x0 || info->vendor_id == vendor_id ) &&
diff --git a/src/hidapi/ios/hid.m b/src/hidapi/ios/hid.m
index 8ec0e6f19d91..d67fc1a4ffcc 100644
--- a/src/hidapi/ios/hid.m
+++ b/src/hidapi/ios/hid.m
@@ -22,6 +22,7 @@
 
 #ifndef SDL_HIDAPI_DISABLED
 
+#include "../SDL_hidapi_c.h"
 
 #define hid_close                    PLATFORM_hid_close
 #define hid_device                   PLATFORM_hid_device
@@ -856,16 +857,10 @@ int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
 struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
 { @autoreleasepool {
 	struct hid_device_info *root = NULL;
-	const char *hint = SDL_GetHint(SDL_HINT_HIDAPI_IGNORE_DEVICES);
 
 	/* See if there are any devices we should skip in enumeration */
-	if (hint) {
-		char vendor_match[16], product_match[16];
-		SDL_snprintf(vendor_match, sizeof(vendor_match), "0x%.4x/0x0000", VALVE_USB_VID);
-		SDL_snprintf(product_match, sizeof(product_match), "0x%.4x/0x%.4x", VALVE_USB_VID, D0G_BLE2_PID);
-		if (SDL_strcasestr(hint, vendor_match) || SDL_strcasestr(hint, product_match)) {
-			return NULL;
-		}
+	if (SDL_HIDAPI_ShouldIgnoreDevice(VALVE_USB_VID, D0G_BLE2_PID)) {
+		return NULL;
 	}
 
 	if ( ( vendor_id == 0 && product_id == 0 ) ||
diff --git a/src/hidapi/libusb/hid.c b/src/hidapi/libusb/hid.c
index 47a3e3e1bf3f..cc485042293f 100644
--- a/src/hidapi/libusb/hid.c
+++ b/src/hidapi/libusb/hid.c
@@ -1085,6 +1085,13 @@ struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
 			continue;
 		}
 
+#ifdef HIDAPI_IGNORE_DEVICE
+		/* See if there are any devices we should skip in enumeration */
+		if (HIDAPI_IGNORE_DEVICE(dev_vid, dev_pid)) {
+			continue;
+		}
+#endif
+
 		res = libusb_get_active_config_descriptor(dev, &conf_desc);
 		if (res < 0)
 			libusb_get_config_descriptor(dev, 0, &conf_desc);
diff --git a/src/hidapi/linux/hid.c b/src/hidapi/linux/hid.c
index 265f42474a2e..9498a85569aa 100644
--- a/src/hidapi/linux/hid.c
+++ b/src/hidapi/linux/hid.c
@@ -960,6 +960,16 @@ struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
 				continue;
 		}
 
+#ifdef HIDAPI_IGNORE_DEVICE
+		/* See if there are any devices we should skip in enumeration */
+		if (!parse_hid_vid_pid_from_sysfs(sysfs_path, &bus_type, &dev_vid, &dev_pid))
+			continue;
+
+		if (HIDAPI_IGNORE_DEVICE(dev_vid, dev_pid)) {
+			continue;
+		}
+#endif
+
 		raw_dev = udev_device_new_from_syspath(udev, sysfs_path);
 		if (!raw_dev)
 			continue;
diff --git a/src/hidapi/mac/hid.c b/src/hidapi/mac/hid.c
index 4801579b874b..9bc4d52cfcf6 100644
--- a/src/hidapi/mac/hid.c
+++ b/src/hidapi/mac/hid.c
@@ -833,6 +833,15 @@ struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
 			continue;
 		}
 
+#ifdef HIDAPI_IGNORE_DEVICE
+		/* See if there are any devices we should skip in enumeration */
+		unsigned short dev_vid = get_vendor_id(dev);
+		unsigned short dev_pid = get_product_id(dev);
+		if (HIDAPI_IGNORE_DEVICE(dev_vid, dev_pid)) {
+			continue;
+		}
+#endif
+
 		struct hid_device_info *tmp = create_device_info(dev);
 		if (tmp == NULL) {
 			continue;
diff --git a/src/hidapi/windows/hid.c b/src/hidapi/windows/hid.c
index ed25280b58ab..7c98f5392b0b 100644
--- a/src/hidapi/windows/hid.c
+++ b/src/hidapi/windows/hid.c
@@ -872,6 +872,13 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
 			goto cont_close;
 		}
 
+#ifdef HIDAPI_IGNORE_DEVICE
+		/* See if there are any devices we should skip in enumeration */
+		if (HIDAPI_IGNORE_DEVICE(attrib.VendorID, attrib.ProductID)) {
+			goto cont_close;
+		}
+#endif
+
 		/* Check the VID/PID to see if we should add this
 		   device to the enumeration list. */
 		if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&