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

From 15a9890919448cb463ab27f0e69be950be11ea87 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 5 Nov 2022 16:44:52 -0700
Subject: [PATCH] Added SDL_HINT_HIDAPI_IGNORE_DEVICES to specify devices that
 should be ignored in SDL_hid_enumerate()

---
 include/SDL_hints.h        |  8 ++++++++
 src/hidapi/android/hid.cpp | 13 +++++++++++++
 src/hidapi/ios/hid.m       | 13 ++++++++++++-
 src/hidapi/libusb/hid.c    | 13 +++++++++++++
 src/hidapi/linux/hid.c     | 13 +++++++++++++
 src/hidapi/mac/hid.c       | 13 +++++++++++++
 src/hidapi/windows/hid.c   | 13 +++++++++++++
 7 files changed, 85 insertions(+), 1 deletion(-)

diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index 8bc4828fa117..ce2225440fb3 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -539,6 +539,14 @@ extern "C" {
  */
 #define SDL_HINT_GRAB_KEYBOARD              "SDL_GRAB_KEYBOARD"
 
+/**
+ *  \brief  A variable containing a list of devices to ignore in SDL_hid_enumerate()
+ *
+ *  For example, to ignore the Shanwan DS3 controller and any Valve controller, you might
+ *  have the string "0x2563/0x0523,0x28de/0x0000"
+ */
+#define SDL_HINT_HIDAPI_IGNORE_DEVICES "SDL_HIDAPI_IGNORE_DEVICES"
+
 /**
  *  \brief  A variable controlling whether the idle timer is disabled on iOS.
  *
diff --git a/src/hidapi/android/hid.cpp b/src/hidapi/android/hid.cpp
index 2b2af72dbc40..34fda42d3dfb 100644
--- a/src/hidapi/android/hid.cpp
+++ b/src/hidapi/android/hid.cpp
@@ -1085,10 +1085,23 @@ 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 )
 	{
 		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 ( ( vendor_id == 0x0 || info->vendor_id == vendor_id ) &&
 		     ( product_id == 0x0 || info->product_id == product_id ) )
 		{
diff --git a/src/hidapi/ios/hid.m b/src/hidapi/ios/hid.m
index 111b8f236466..55845701a4a9 100644
--- a/src/hidapi/ios/hid.m
+++ b/src/hidapi/ios/hid.m
@@ -836,7 +836,18 @@ 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 ( ( vendor_id == 0 && product_id == 0 ) ||
 		 ( vendor_id == VALVE_USB_VID && product_id == D0G_BLE2_PID ) )
 	{
diff --git a/src/hidapi/libusb/hid.c b/src/hidapi/libusb/hid.c
index e86aa51cb9d3..1f08aedfa275 100644
--- a/src/hidapi/libusb/hid.c
+++ b/src/hidapi/libusb/hid.c
@@ -29,6 +29,7 @@
 
 #include "../../SDL_internal.h"
 #include "../../thread/SDL_systhread.h"
+#include "SDL_hints.h"
 #include "SDL_mutex.h"
 #include "SDL_thread.h"
 
@@ -761,6 +762,7 @@ struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
 
 	struct hid_device_info *root = NULL; /* return object */
 	struct hid_device_info *cur_dev = NULL;
+	const char *hint = SDL_GetHint(SDL_HINT_HIDAPI_IGNORE_DEVICES);
 
 	if(hid_init() < 0)
 		return NULL;
@@ -778,10 +780,21 @@ struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
 		unsigned short dev_vid = desc.idVendor;
 		unsigned short dev_pid = desc.idProduct;
 
+		/* 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", dev_vid);
+			SDL_snprintf(product_match, sizeof(product_match), "0x%.4x/0x%.4x", dev_vid, dev_pid);
+			if (SDL_strcasestr(hint, vendor_match) || SDL_strcasestr(hint, product_match)) {
+				continue;
+			}
+		}
+
 		res = libusb_get_active_config_descriptor(dev, &conf_desc);
 		if (res < 0)
 			libusb_get_config_descriptor(dev, 0, &conf_desc);
 		if (conf_desc) {
+
 			for (j = 0; j < conf_desc->bNumInterfaces; j++) {
 				const struct libusb_interface *intf = &conf_desc->interface[j];
 				for (k = 0; k < intf->num_altsetting; k++) {
diff --git a/src/hidapi/linux/hid.c b/src/hidapi/linux/hid.c
index 6507dde71256..fbd010144a2e 100644
--- a/src/hidapi/linux/hid.c
+++ b/src/hidapi/linux/hid.c
@@ -22,6 +22,8 @@
 ********************************************************/
 #include "../../SDL_internal.h"
 
+#include "SDL_hints.h"
+
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE /* needed for wcsdup() before glibc 2.10 */
 #endif
@@ -481,6 +483,7 @@ struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
 	struct hid_device_info *root = NULL; /* return object */
 	struct hid_device_info *cur_dev = NULL;
 	struct hid_device_info *prev_dev = NULL; /* previous device */
+	const char *hint = SDL_GetHint(SDL_HINT_HIDAPI_IGNORE_DEVICES);
 
 	hid_init();
 
@@ -552,6 +555,16 @@ struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
 			goto next;
 		}
 
+		/* 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", dev_vid);
+			SDL_snprintf(product_match, sizeof(product_match), "0x%.4x/0x%.4x", dev_vid, dev_pid);
+			if (SDL_strcasestr(hint, vendor_match) || SDL_strcasestr(hint, product_match)) {
+				continue;
+			}
+		}
+
 		/* Check the VID/PID against the arguments */
 		if ((vendor_id == 0x0 || vendor_id == dev_vid) &&
 		    (product_id == 0x0 || product_id == dev_pid)) {
diff --git a/src/hidapi/mac/hid.c b/src/hidapi/mac/hid.c
index d52b94f0ab47..d5dfbc2961b7 100644
--- a/src/hidapi/mac/hid.c
+++ b/src/hidapi/mac/hid.c
@@ -21,6 +21,8 @@
  ********************************************************/
 #include "../../SDL_internal.h"
 
+#include "SDL_hints.h"
+
 /* See Apple Technical Note TN2187 for details on IOHidManager. */
 
 #include <IOKit/hid/IOHIDManager.h>
@@ -517,6 +519,7 @@ struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
 	CFSetRef device_set;
 	IOHIDDeviceRef *device_array;
 	int i;
+	const char *hint = SDL_GetHint(SDL_HINT_HIDAPI_IGNORE_DEVICES);
 	
 	/* Set up the HID Manager if it hasn't been done */
 	if (hid_init() < 0)
@@ -567,6 +570,16 @@ struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
 		dev_vid = get_vendor_id(dev);
 		dev_pid = get_product_id(dev);
 		
+		/* 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", dev_vid);
+			SDL_snprintf(product_match, sizeof(product_match), "0x%.4x/0x%.4x", dev_vid, dev_pid);
+			if (SDL_strcasestr(hint, vendor_match) || SDL_strcasestr(hint, product_match)) {
+				continue;
+			}
+		}
+
 		/* Check the VID/PID against the arguments */
 		if ((vendor_id == 0x0 || dev_vid == vendor_id) &&
 		    (product_id == 0x0 || dev_pid == product_id)) {
diff --git a/src/hidapi/windows/hid.c b/src/hidapi/windows/hid.c
index 8dfd11d05620..27c09e52ef72 100644
--- a/src/hidapi/windows/hid.c
+++ b/src/hidapi/windows/hid.c
@@ -21,6 +21,8 @@
 ********************************************************/
 #include "../../SDL_internal.h"
 
+#include "SDL_hints.h"
+
 #include <windows.h>
 
 #ifndef _WIN32_WINNT_WIN8
@@ -371,6 +373,7 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
 	SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL;
 	HDEVINFO device_info_set = INVALID_HANDLE_VALUE;
 	int device_index = 0;
+	const char *hint = SDL_GetHint(SDL_HINT_HIDAPI_IGNORE_DEVICES);
 
 	if (hid_init() < 0)
 		return NULL;
@@ -488,6 +491,16 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
 		HidD_GetAttributes(write_handle, &attrib);
 		//wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID);
 
+		/* 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", attrib.VendorID);
+			SDL_snprintf(product_match, sizeof(product_match), "0x%.4x/0x%.4x", attrib.VendorID, attrib.ProductID);
+			if (SDL_strcasestr(hint, vendor_match) || SDL_strcasestr(hint, product_match)) {
+				continue;
+			}
+		}
+
 		/* Check the VID/PID to see if we should add this
 		   device to the enumeration list. */
 		if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&