Browse Source

Added support for detecting previously unknown Xbox 360 and Xbox One controllers using the HIDAPI driver with libusb and Android

Sam Lantinga 5 years ago
parent
commit
43aa1fa9e7

+ 1 - 1
android-project/app/src/main/java/org/libsdl/app/HIDDeviceBLESteamController.java

@@ -470,7 +470,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
             // Only register controller with the native side once it has been fully configured
             // Only register controller with the native side once it has been fully configured
             if (!isRegistered()) {
             if (!isRegistered()) {
                 Log.v(TAG, "Registering Steam Controller with ID: " + getId());
                 Log.v(TAG, "Registering Steam Controller with ID: " + getId());
-                mManager.HIDDeviceConnected(getId(), getIdentifier(), getVendorId(), getProductId(), getSerialNumber(), getVersion(), getManufacturerName(), getProductName(), 0);
+                mManager.HIDDeviceConnected(getId(), getIdentifier(), getVendorId(), getProductId(), getSerialNumber(), getVersion(), getManufacturerName(), getProductName(), 0, 0, 0, 0);
                 setRegistered();
                 setRegistered();
             }
             }
         }
         }

+ 7 - 18
android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java

@@ -241,17 +241,7 @@ public class HIDDeviceManager {
         }
         }
     }
     }
 
 
-    private boolean isHIDDeviceUSB(UsbDevice usbDevice) {
-        for (int interface_number = 0; interface_number < usbDevice.getInterfaceCount(); ++interface_number) {
-            if (isHIDDeviceInterface(usbDevice, interface_number)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean isHIDDeviceInterface(UsbDevice usbDevice, int interface_number) {
-        UsbInterface usbInterface = usbDevice.getInterface(interface_number);
+    private boolean isHIDDeviceInterface(UsbDevice usbDevice, UsbInterface usbInterface) {
         if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_HID) {
         if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_HID) {
             return true;
             return true;
         }
         }
@@ -331,9 +321,7 @@ public class HIDDeviceManager {
     }
     }
 
 
     private void handleUsbDeviceAttached(UsbDevice usbDevice) {
     private void handleUsbDeviceAttached(UsbDevice usbDevice) {
-        if (isHIDDeviceUSB(usbDevice)) {
-            connectHIDDeviceUSB(usbDevice);
-        }
+        connectHIDDeviceUSB(usbDevice);
     }
     }
 
 
     private void handleUsbDeviceDetached(UsbDevice usbDevice) {
     private void handleUsbDeviceDetached(UsbDevice usbDevice) {
@@ -366,11 +354,12 @@ public class HIDDeviceManager {
     private void connectHIDDeviceUSB(UsbDevice usbDevice) {
     private void connectHIDDeviceUSB(UsbDevice usbDevice) {
         synchronized (this) {
         synchronized (this) {
             for (int interface_number = 0; interface_number < usbDevice.getInterfaceCount(); interface_number++) {
             for (int interface_number = 0; interface_number < usbDevice.getInterfaceCount(); interface_number++) {
-                if (isHIDDeviceInterface(usbDevice, interface_number)) {
-                    HIDDeviceUSB device = new HIDDeviceUSB(this, usbDevice, interface_number);
+                UsbInterface usbInterface = usbDevice.getInterface(interface_number);
+                if (isHIDDeviceInterface(usbDevice, usbInterface)) {
+                    HIDDeviceUSB device = new HIDDeviceUSB(this, usbDevice, usbInterface.getId());
                     int id = device.getId();
                     int id = device.getId();
                     mDevicesById.put(id, device);
                     mDevicesById.put(id, device);
-                    HIDDeviceConnected(id, device.getIdentifier(), device.getVendorId(), device.getProductId(), device.getSerialNumber(), device.getVersion(), device.getManufacturerName(), device.getProductName(), interface_number);
+                    HIDDeviceConnected(id, device.getIdentifier(), device.getVendorId(), device.getProductId(), device.getSerialNumber(), device.getVersion(), device.getManufacturerName(), device.getProductName(), usbInterface.getId(), usbInterface.getInterfaceClass(), usbInterface.getInterfaceSubclass(), usbInterface.getInterfaceProtocol());
                 }
                 }
             }
             }
         }
         }
@@ -670,7 +659,7 @@ public class HIDDeviceManager {
     private native void HIDDeviceRegisterCallback();
     private native void HIDDeviceRegisterCallback();
     private native void HIDDeviceReleaseCallback();
     private native void HIDDeviceReleaseCallback();
 
 
-    native void HIDDeviceConnected(int deviceID, String identifier, int vendorId, int productId, String serial_number, int release_number, String manufacturer_string, String product_string, int interface_number);
+    native void HIDDeviceConnected(int deviceID, String identifier, int vendorId, int productId, String serial_number, int release_number, String manufacturer_string, String product_string, int interface_number, int interface_class, int interface_subclass, int interface_protocol);
     native void HIDDeviceOpenPending(int deviceID);
     native void HIDDeviceOpenPending(int deviceID);
     native void HIDDeviceOpenResult(int deviceID, boolean opened);
     native void HIDDeviceOpenResult(int deviceID, boolean opened);
     native void HIDDeviceDisconnected(int deviceID);
     native void HIDDeviceDisconnected(int deviceID);

+ 6 - 0
src/hidapi/SDL_hidapi.c

@@ -419,6 +419,9 @@ LIBUSB_CopyHIDDeviceInfo(struct LIBUSB_hid_device_info *pSrc,
     pDst->usage_page = pSrc->usage_page;
     pDst->usage_page = pSrc->usage_page;
     pDst->usage = pSrc->usage;
     pDst->usage = pSrc->usage;
     pDst->interface_number = pSrc->interface_number;
     pDst->interface_number = pSrc->interface_number;
+    pDst->interface_class = pSrc->interface_class;
+    pDst->interface_subclass = pSrc->interface_subclass;
+    pDst->interface_protocol = pSrc->interface_protocol;
     pDst->next = NULL;
     pDst->next = NULL;
 }
 }
 #endif /* SDL_LIBUSB_DYNAMIC */
 #endif /* SDL_LIBUSB_DYNAMIC */
@@ -438,6 +441,9 @@ PLATFORM_CopyHIDDeviceInfo(struct PLATFORM_hid_device_info *pSrc,
     pDst->usage_page = pSrc->usage_page;
     pDst->usage_page = pSrc->usage_page;
     pDst->usage = pSrc->usage;
     pDst->usage = pSrc->usage;
     pDst->interface_number = pSrc->interface_number;
     pDst->interface_number = pSrc->interface_number;
+    pDst->interface_class = pSrc->interface_class;
+    pDst->interface_subclass = pSrc->interface_subclass;
+    pDst->interface_protocol = pSrc->interface_protocol;
     pDst->next = NULL;
     pDst->next = NULL;
 }
 }
 #endif /* HAVE_PLATFORM_BACKEND */
 #endif /* HAVE_PLATFORM_BACKEND */

+ 5 - 2
src/hidapi/android/hid.cpp

@@ -739,7 +739,7 @@ extern "C"
 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz);
 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz);
 
 
 extern "C"
 extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, int nDeviceID, jstring sIdentifier, int nVendorId, int nProductId, jstring sSerialNumber, int nReleaseNumber, jstring sManufacturer, jstring sProduct, int nInterface );
+JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, int nDeviceID, jstring sIdentifier, int nVendorId, int nProductId, jstring sSerialNumber, int nReleaseNumber, jstring sManufacturer, jstring sProduct, int nInterface, int nInterfaceClass, int nInterfaceSubclass, int nInterfaceProtocol );
 
 
 extern "C"
 extern "C"
 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, int nDeviceID);
 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, int nDeviceID);
@@ -828,7 +828,7 @@ JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallbac
 }
 }
 
 
 extern "C"
 extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, int nDeviceID, jstring sIdentifier, int nVendorId, int nProductId, jstring sSerialNumber, int nReleaseNumber, jstring sManufacturer, jstring sProduct, int nInterface )
+JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, int nDeviceID, jstring sIdentifier, int nVendorId, int nProductId, jstring sSerialNumber, int nReleaseNumber, jstring sManufacturer, jstring sProduct, int nInterface, int nInterfaceClass, int nInterfaceSubclass, int nInterfaceProtocol )
 {
 {
 	LOGV( "HIDDeviceConnected() id=%d VID/PID = %.4x/%.4x, interface %d\n", nDeviceID, nVendorId, nProductId, nInterface );
 	LOGV( "HIDDeviceConnected() id=%d VID/PID = %.4x/%.4x, interface %d\n", nDeviceID, nVendorId, nProductId, nInterface );
 
 
@@ -842,6 +842,9 @@ JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNI
 	pInfo->manufacturer_string = CreateWStringFromJString( env, sManufacturer );
 	pInfo->manufacturer_string = CreateWStringFromJString( env, sManufacturer );
 	pInfo->product_string = CreateWStringFromJString( env, sProduct );
 	pInfo->product_string = CreateWStringFromJString( env, sProduct );
 	pInfo->interface_number = nInterface;
 	pInfo->interface_number = nInterface;
+	pInfo->interface_class = nInterfaceClass;
+	pInfo->interface_subclass = nInterfaceSubclass;
+	pInfo->interface_protocol = nInterfaceProtocol;
 
 
 	hid_device_ref<CHIDDevice> pDevice( new CHIDDevice( nDeviceID, pInfo ) );
 	hid_device_ref<CHIDDevice> pDevice( new CHIDDevice( nDeviceID, pInfo ) );
 
 

+ 6 - 0
src/hidapi/hidapi/hidapi.h

@@ -78,6 +78,12 @@ namespace NAMESPACE {
 			    only if the device contains more than one interface. */
 			    only if the device contains more than one interface. */
 			int interface_number;
 			int interface_number;
 
 
+			/** Additional information about the USB interface.
+			    Valid on libusb and Android implementations. */
+			int interface_class;
+			int interface_subclass;
+			int interface_protocol;
+
 			/** Pointer to the next device */
 			/** Pointer to the next device */
 			struct hid_device_info *next;
 			struct hid_device_info *next;
 		};
 		};

+ 3 - 0
src/hidapi/libusb/hid.c

@@ -714,6 +714,9 @@ struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
 
 
 							/* Interface Number */
 							/* Interface Number */
 							cur_dev->interface_number = interface_num;
 							cur_dev->interface_number = interface_num;
+							cur_dev->interface_class = intf_desc->bInterfaceClass;
+							cur_dev->interface_subclass = intf_desc->bInterfaceSubClass;
+							cur_dev->interface_protocol = intf_desc->bInterfaceProtocol;
 						}
 						}
 					}
 					}
 				} /* altsettings */
 				} /* altsettings */

+ 24 - 23
src/hidapi/mac/hid.c

@@ -41,10 +41,10 @@
  StackOverflow. It is used with his permission. */
  StackOverflow. It is used with his permission. */
 typedef int pthread_barrierattr_t;
 typedef int pthread_barrierattr_t;
 typedef struct pthread_barrier {
 typedef struct pthread_barrier {
-    pthread_mutex_t mutex;
-    pthread_cond_t cond;
-    int count;
-    int trip_count;
+	pthread_mutex_t mutex;
+	pthread_cond_t cond;
+	int count;
+	int trip_count;
 } pthread_barrier_t;
 } pthread_barrier_t;
 
 
 static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count)
 static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count)
@@ -178,22 +178,22 @@ static void free_hid_device(hid_device *dev)
 	free(dev->input_report_buf);
 	free(dev->input_report_buf);
 
 
 	if (device_list) {
 	if (device_list) {
-    	if (device_list->dev == dev) {
-    		device_list = device_list->next;
-    	}
-    	else {
-    		struct hid_device_list_node *node = device_list;
-    		while (node) {
-    			if (node->next && node->next->dev == dev) {
-    				struct hid_device_list_node *new_next = node->next->next;
-    				free(node->next);
-    				node->next = new_next;
-    				break;
-    			}
-
-    			node = node->next;
-    		}
-    	}
+		if (device_list->dev == dev) {
+			device_list = device_list->next;
+		}
+		else {
+			struct hid_device_list_node *node = device_list;
+			while (node) {
+				if (node->next && node->next->dev == dev) {
+					struct hid_device_list_node *new_next = node->next->next;
+					free(node->next);
+					node->next = new_next;
+					break;
+				}
+
+				node = node->next;
+			}
+		}
 	}
 	}
 	
 	
 	/* Clean up the thread objects */
 	/* Clean up the thread objects */
@@ -478,9 +478,10 @@ struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
 		
 		
 		IOHIDDeviceRef dev = device_array[i];
 		IOHIDDeviceRef dev = device_array[i];
 		
 		
-        if (!dev) {
-            continue;
-        }
+		if (!dev) {
+			continue;
+		}
+
 		dev_vid = get_vendor_id(dev);
 		dev_vid = get_vendor_id(dev);
 		dev_pid = get_product_id(dev);
 		dev_pid = get_product_id(dev);
 		
 		

+ 111 - 28
src/joystick/SDL_joystick.c

@@ -751,17 +751,17 @@ SDL_JoystickSetPlayerIndex(SDL_Joystick * joystick, int player_index)
 int
 int
 SDL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
 SDL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
 {
 {
-	int result;
+    int result;
 
 
     if (!SDL_PrivateJoystickValid(joystick)) {
     if (!SDL_PrivateJoystickValid(joystick)) {
         return -1;
         return -1;
     }
     }
 
 
-	SDL_LockJoysticks();
+    SDL_LockJoysticks();
     result = joystick->driver->Rumble(joystick, low_frequency_rumble, high_frequency_rumble, duration_ms);
     result = joystick->driver->Rumble(joystick, low_frequency_rumble, high_frequency_rumble, duration_ms);
-	SDL_UnlockJoysticks();
+    SDL_UnlockJoysticks();
 
 
-	return result;
+    return result;
 }
 }
 
 
 /*
 /*
@@ -1352,7 +1352,7 @@ SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGUID guid, const char *nam
     Uint16 vendor, product;
     Uint16 vendor, product;
 
 
     SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
     SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
-    type = SDL_GetJoystickGameControllerType(vendor, product, name);
+    type = SDL_GetJoystickGameControllerType(name, vendor, product, -1, 0, 0, 0);
     if (type == SDL_CONTROLLER_TYPE_UNKNOWN) {
     if (type == SDL_CONTROLLER_TYPE_UNKNOWN) {
         if (SDL_IsJoystickXInput(guid)) {
         if (SDL_IsJoystickXInput(guid)) {
             /* This is probably an Xbox One controller */
             /* This is probably an Xbox One controller */
@@ -1363,37 +1363,120 @@ SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGUID guid, const char *nam
 }
 }
 
 
 SDL_GameControllerType
 SDL_GameControllerType
-SDL_GetJoystickGameControllerType(Uint16 vendor, Uint16 product, const char *name)
+SDL_GetJoystickGameControllerType(const char *name, Uint16 vendor, Uint16 product, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
 {
+    SDL_GameControllerType type = SDL_CONTROLLER_TYPE_UNKNOWN;
+
     if (vendor == 0x0000 && product == 0x0000) {
     if (vendor == 0x0000 && product == 0x0000) {
         /* Some devices are only identifiable by their name */
         /* Some devices are only identifiable by their name */
         if (SDL_strcmp(name, "Lic Pro Controller") == 0 ||
         if (SDL_strcmp(name, "Lic Pro Controller") == 0 ||
             SDL_strcmp(name, "Nintendo Wireless Gamepad") == 0 ||
             SDL_strcmp(name, "Nintendo Wireless Gamepad") == 0 ||
             SDL_strcmp(name, "Wireless Gamepad") == 0) {
             SDL_strcmp(name, "Wireless Gamepad") == 0) {
             /* HORI or PowerA Switch Pro Controller clone */
             /* HORI or PowerA Switch Pro Controller clone */
-            return SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
+            type = SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
+        } else {
+            type = SDL_CONTROLLER_TYPE_UNKNOWN;
+        }
+
+    } else if (vendor == 0x0001 && product == 0x0001) {
+        type = SDL_CONTROLLER_TYPE_UNKNOWN;
+
+    } else {
+        switch (GuessControllerType(vendor, product)) {
+        case k_eControllerType_XBox360Controller:
+            type = SDL_CONTROLLER_TYPE_XBOX360;
+            break;
+        case k_eControllerType_XBoxOneController:
+            type = SDL_CONTROLLER_TYPE_XBOXONE;
+            break;
+        case k_eControllerType_PS3Controller:
+            type = SDL_CONTROLLER_TYPE_PS3;
+            break;
+        case k_eControllerType_PS4Controller:
+            type = SDL_CONTROLLER_TYPE_PS4;
+            break;
+        case k_eControllerType_SwitchProController:
+        case k_eControllerType_SwitchInputOnlyController:
+            type = SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
+            break;
+        default:
+            type = SDL_CONTROLLER_TYPE_UNKNOWN;
+            break;
         }
         }
-        return SDL_CONTROLLER_TYPE_UNKNOWN;
-    }
-    if (vendor == 0x0001 && product == 0x0001) {
-        return SDL_CONTROLLER_TYPE_UNKNOWN;
-    }
-
-    switch (GuessControllerType(vendor, product)) {
-    case k_eControllerType_XBox360Controller:
-        return SDL_CONTROLLER_TYPE_XBOX360;
-    case k_eControllerType_XBoxOneController:
-        return SDL_CONTROLLER_TYPE_XBOXONE;
-    case k_eControllerType_PS3Controller:
-        return SDL_CONTROLLER_TYPE_PS3;
-    case k_eControllerType_PS4Controller:
-        return SDL_CONTROLLER_TYPE_PS4;
-    case k_eControllerType_SwitchProController:
-    case k_eControllerType_SwitchInputOnlyController:
-        return SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
-    default:
-        return SDL_CONTROLLER_TYPE_UNKNOWN;
     }
     }
+
+    if (type == SDL_CONTROLLER_TYPE_UNKNOWN) {
+        /* This code should match the checks in libusb/hid.c and HIDDeviceManager.java */
+        static const int LIBUSB_CLASS_VENDOR_SPEC = 0xFF;
+        static const int XB360_IFACE_SUBCLASS = 93;
+        static const int XB360_IFACE_PROTOCOL = 1; /* Wired */
+        static const int XB360W_IFACE_PROTOCOL = 129; /* Wireless */
+        static const int XBONE_IFACE_SUBCLASS = 71;
+        static const int XBONE_IFACE_PROTOCOL = 208;
+
+        if (interface_class == LIBUSB_CLASS_VENDOR_SPEC &&
+            interface_subclass == XB360_IFACE_SUBCLASS &&
+            (interface_protocol == XB360_IFACE_PROTOCOL ||
+             interface_protocol == XB360W_IFACE_PROTOCOL)) {
+
+            static const int SUPPORTED_VENDORS[] = {
+                0x0079, /* GPD Win 2 */
+                0x044f, /* Thrustmaster */
+                0x045e, /* Microsoft */
+                0x046d, /* Logitech */
+                0x056e, /* Elecom */
+                0x06a3, /* Saitek */
+                0x0738, /* Mad Catz */
+                0x07ff, /* Mad Catz */
+                0x0e6f, /* PDP */
+                0x0f0d, /* Hori */
+                0x1038, /* SteelSeries */
+                0x11c9, /* Nacon */
+                0x12ab, /* Unknown */
+                0x1430, /* RedOctane */
+                0x146b, /* BigBen */
+                0x1532, /* Razer Sabertooth */
+                0x15e4, /* Numark */
+                0x162e, /* Joytech */
+                0x1689, /* Razer Onza */
+                0x1bad, /* Harmonix */
+                0x24c6, /* PowerA */
+            };
+
+            int i;
+            for (i = 0; i < SDL_arraysize(SUPPORTED_VENDORS); ++i) {
+                if (vendor == SUPPORTED_VENDORS[i]) {
+                    type = SDL_CONTROLLER_TYPE_XBOX360;
+                    break;
+                }
+            }
+        }
+
+        if (interface_number == 0 &&
+            interface_class == LIBUSB_CLASS_VENDOR_SPEC &&
+            interface_subclass == XBONE_IFACE_SUBCLASS &&
+            interface_protocol == XBONE_IFACE_PROTOCOL) {
+
+            static const int SUPPORTED_VENDORS[] = {
+                0x045e, /* Microsoft */
+                0x0738, /* Mad Catz */
+                0x0e6f, /* PDP */
+                0x0f0d, /* Hori */
+                0x1532, /* Razer Wildcat */
+                0x24c6, /* PowerA */
+                0x2e24, /* Hyperkin */
+            };
+
+            int i;
+            for (i = 0; i < SDL_arraysize(SUPPORTED_VENDORS); ++i) {
+                if (vendor == SUPPORTED_VENDORS[i]) {
+                    type = SDL_CONTROLLER_TYPE_XBOXONE;
+                    break;
+                }
+            }
+        }
+    }
+    return type;
 }
 }
 
 
 SDL_bool
 SDL_bool
@@ -1686,7 +1769,7 @@ SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid)
         }
         }
     }
     }
 
 
-    if (SDL_GetJoystickGameControllerType(vendor, product, name) == SDL_CONTROLLER_TYPE_PS4 && SDL_IsPS4RemapperRunning()) {
+    if (SDL_GetJoystickGameControllerType(name, vendor, product, -1, 0, 0, 0) == SDL_CONTROLLER_TYPE_PS4 && SDL_IsPS4RemapperRunning()) {
         return SDL_TRUE;
         return SDL_TRUE;
     }
     }
 
 

+ 1 - 1
src/joystick/SDL_joystick_c.h

@@ -60,7 +60,7 @@ extern const char *SDL_GetCustomJoystickName(Uint16 vendor, Uint16 product);
 
 
 /* Function to return the type of a controller */
 /* Function to return the type of a controller */
 extern SDL_GameControllerType SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGUID guid, const char *name);
 extern SDL_GameControllerType SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGUID guid, const char *name);
-extern SDL_GameControllerType SDL_GetJoystickGameControllerType(Uint16 vendor, Uint16 product, const char *name);
+extern SDL_GameControllerType SDL_GetJoystickGameControllerType(const char *name, Uint16 vendor, Uint16 product, int interface_number, int interface_class, int interface_subclass, int interface_protocol);
 
 
 /* Function to return whether a joystick is a Nintendo Switch Pro controller */
 /* Function to return whether a joystick is a Nintendo Switch Pro controller */
 extern SDL_bool SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint16 product_id);
 extern SDL_bool SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint16 product_id);

+ 2 - 2
src/joystick/hidapi/SDL_hidapi_gamecube.c

@@ -50,9 +50,9 @@ typedef struct {
 } SDL_DriverGameCube_Context;
 } SDL_DriverGameCube_Context;
 
 
 static SDL_bool
 static SDL_bool
-HIDAPI_DriverGameCube_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name)
+HIDAPI_DriverGameCube_IsSupportedDevice(const char *name, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
 {
-    if (vendor_id == 0x057e && product_id == 0x0337) {
+    if (vendor_id == USB_VENDOR_NINTENDO && product_id == USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER) {
         /* Nintendo Co., Ltd.  Wii U GameCube Controller Adapter */
         /* Nintendo Co., Ltd.  Wii U GameCube Controller Adapter */
         return SDL_TRUE;
         return SDL_TRUE;
     }
     }

+ 15 - 18
src/joystick/hidapi/SDL_hidapi_ps4.c

@@ -37,15 +37,6 @@
 
 
 #ifdef SDL_JOYSTICK_HIDAPI_PS4
 #ifdef SDL_JOYSTICK_HIDAPI_PS4
 
 
-#define SONY_USB_VID        0x054C
-#define SONY_DS4_PID        0x05C4
-#define SONY_DS4_DONGLE_PID 0x0BA0
-#define SONY_DS4_SLIM_PID   0x09CC
-
-#define RAZER_USB_VID       0x1532
-#define RAZER_PANTHERA_PID  0X0401
-#define RAZER_PANTHERA_EVO_PID  0x1008
-
 #define USB_PACKET_LENGTH   64
 #define USB_PACKET_LENGTH   64
 
 
 typedef enum
 typedef enum
@@ -139,15 +130,15 @@ static Uint32 crc32(Uint32 crc, const void *data, int count)
 }
 }
 
 
 static SDL_bool
 static SDL_bool
-HIDAPI_DriverPS4_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name)
+HIDAPI_DriverPS4_IsSupportedDevice(const char *name, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
 {
-    return (SDL_GetJoystickGameControllerType(vendor_id, product_id, name) == SDL_CONTROLLER_TYPE_PS4);
+    return (SDL_GetJoystickGameControllerType(name, vendor_id, product_id, interface_number, interface_class, interface_subclass, interface_protocol) == SDL_CONTROLLER_TYPE_PS4);
 }
 }
 
 
 static const char *
 static const char *
 HIDAPI_DriverPS4_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
 HIDAPI_DriverPS4_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
 {
 {
-    if (vendor_id == SONY_USB_VID) {
+    if (vendor_id == USB_VENDOR_SONY) {
         return "PS4 Controller";
         return "PS4 Controller";
     }
     }
     return NULL;
     return NULL;
@@ -186,8 +177,8 @@ static SDL_bool CheckUSBConnected(hid_device *dev)
 static SDL_bool HIDAPI_DriverPS4_CanRumble(Uint16 vendor_id, Uint16 product_id)
 static SDL_bool HIDAPI_DriverPS4_CanRumble(Uint16 vendor_id, Uint16 product_id)
 {
 {
     /* The Razer Panthera fight stick hangs when trying to rumble */
     /* The Razer Panthera fight stick hangs when trying to rumble */
-    if (vendor_id == RAZER_USB_VID &&
-        (product_id == RAZER_PANTHERA_PID || product_id == RAZER_PANTHERA_EVO_PID)) {
+    if (vendor_id == USB_VENDOR_RAZER &&
+        (product_id == USB_PRODUCT_RAZER_PANTHERA || product_id == USB_PRODUCT_RAZER_PANTHERA_EVO)) {
         return SDL_FALSE;
         return SDL_FALSE;
     }
     }
     return SDL_TRUE;
     return SDL_TRUE;
@@ -232,10 +223,10 @@ HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
     device->context = ctx;
     device->context = ctx;
 
 
     /* Check for type of connection */
     /* Check for type of connection */
-    ctx->is_dongle = (device->vendor_id == SONY_USB_VID && device->product_id == SONY_DS4_DONGLE_PID);
+    ctx->is_dongle = (device->vendor_id == USB_VENDOR_SONY && device->product_id == USB_PRODUCT_SONY_DS4_DONGLE);
     if (ctx->is_dongle) {
     if (ctx->is_dongle) {
         ctx->is_bluetooth = SDL_FALSE;
         ctx->is_bluetooth = SDL_FALSE;
-    } else if (device->vendor_id == SONY_USB_VID) {
+    } else if (device->vendor_id == USB_VENDOR_SONY) {
         ctx->is_bluetooth = !CheckUSBConnected(device->dev);
         ctx->is_bluetooth = !CheckUSBConnected(device->dev);
     } else {
     } else {
         /* Third party controllers appear to all be wired */
         /* Third party controllers appear to all be wired */
@@ -246,8 +237,8 @@ HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
 #endif
 #endif
 
 
     /* Check to see if audio is supported */
     /* Check to see if audio is supported */
-    if (device->vendor_id == SONY_USB_VID &&
-        (device->product_id == SONY_DS4_SLIM_PID || device->product_id == SONY_DS4_DONGLE_PID )) {
+    if (device->vendor_id == USB_VENDOR_SONY &&
+        (device->product_id == USB_PRODUCT_SONY_DS4_SLIM || device->product_id == USB_PRODUCT_SONY_DS4_DONGLE)) {
         ctx->audio_supported = SDL_TRUE;
         ctx->audio_supported = SDL_TRUE;
     }
     }
 
 
@@ -491,6 +482,12 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
 static void
 static void
 HIDAPI_DriverPS4_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
 HIDAPI_DriverPS4_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
 {
 {
+    SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
+
+    if (ctx->rumble_expiration) {
+        HIDAPI_DriverPS4_RumbleJoystick(device, joystick, 0, 0, 0);
+    }
+
     hid_close(device->dev);
     hid_close(device->dev);
     device->dev = NULL;
     device->dev = NULL;
 
 

+ 6 - 2
src/joystick/hidapi/SDL_hidapi_switch.c

@@ -241,9 +241,9 @@ static SDL_bool IsGameCubeFormFactor(int vendor_id, int product_id)
 }
 }
 
 
 static SDL_bool
 static SDL_bool
-HIDAPI_DriverSwitch_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name)
+HIDAPI_DriverSwitch_IsSupportedDevice(const char *name, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
 {
-    return (SDL_GetJoystickGameControllerType(vendor_id, product_id, name) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO);
+    return (SDL_GetJoystickGameControllerType(name, vendor_id, product_id, interface_number, interface_class, interface_subclass, interface_protocol) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO);
 }
 }
 
 
 static const char *
 static const char *
@@ -1094,6 +1094,10 @@ HIDAPI_DriverSwitch_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst
 {
 {
     SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
     SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
 
 
+    if (ctx->m_nRumbleExpiration) {
+        HIDAPI_DriverSwitch_RumbleJoystick(device, joystick, 0, 0, 0);
+    }
+
     if (!ctx->m_bInputOnly) {
     if (!ctx->m_bInputOnly) {
         /* Restore simple input mode for other applications */
         /* Restore simple input mode for other applications */
         SetInputMode(ctx, k_eSwitchInputReportIDs_SimpleControllerState);
         SetInputMode(ctx, k_eSwitchInputReportIDs_SimpleControllerState);

+ 14 - 14
src/joystick/hidapi/SDL_hidapi_xbox360.c

@@ -247,32 +247,30 @@ HIDAPI_DriverXbox360_QuitWindowsGamingInput(SDL_DriverXbox360_Context *ctx)
 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
 
 
 static SDL_bool
 static SDL_bool
-HIDAPI_DriverXbox360_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name)
+HIDAPI_DriverXbox360_IsSupportedDevice(const char *name, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
 {
-    SDL_GameControllerType type = SDL_GetJoystickGameControllerType(vendor_id, product_id, name);
-    const Uint16 MICROSOFT_USB_VID = 0x045e;
-    const Uint16 NVIDIA_USB_VID = 0x0955;
+    const int XB360W_IFACE_PROTOCOL = 129; /* Wireless */
+    SDL_GameControllerType type = SDL_GetJoystickGameControllerType(name, vendor_id, product_id, interface_number, interface_class, interface_subclass, interface_protocol);
 
 
-    if (vendor_id == NVIDIA_USB_VID) {
+    if (vendor_id == USB_VENDOR_NVIDIA) {
         /* This is the NVIDIA Shield controller which doesn't talk Xbox controller protocol */
         /* This is the NVIDIA Shield controller which doesn't talk Xbox controller protocol */
         return SDL_FALSE;
         return SDL_FALSE;
     }
     }
-    if (vendor_id == MICROSOFT_USB_VID) {
-        if (product_id == 0x0291 || product_id == 0x0719) {
-            /* This is the wireless dongle, which talks a different protocol */
-            return SDL_FALSE;
-        }
+    if ((vendor_id == USB_VENDOR_MICROSOFT && (product_id == 0x0291 || product_id == 0x0719)) ||
+        (type == SDL_CONTROLLER_TYPE_XBOX360 && interface_protocol == XB360W_IFACE_PROTOCOL)) {
+        /* This is the wireless dongle, which talks a different protocol */
+        return SDL_FALSE;
     }
     }
     if (interface_number > 0) {
     if (interface_number > 0) {
         /* This is the chatpad or other input interface, not the Xbox 360 interface */
         /* This is the chatpad or other input interface, not the Xbox 360 interface */
         return SDL_FALSE;
         return SDL_FALSE;
     }
     }
 #if defined(__MACOSX__) || defined(__WIN32__)
 #if defined(__MACOSX__) || defined(__WIN32__)
-    if (vendor_id == 0x045e && product_id == 0x028e && version == 1) {
+    if (vendor_id == USB_VENDOR_MICROSOFT && product_id == 0x028e && version == 1) {
         /* This is the Steam Virtual Gamepad, which isn't supported by this driver */
         /* This is the Steam Virtual Gamepad, which isn't supported by this driver */
         return SDL_FALSE;
         return SDL_FALSE;
     }
     }
-    if (vendor_id == 0x045e && product_id == 0x02e0) {
+    if (vendor_id == USB_VENDOR_MICROSOFT && product_id == 0x02e0) {
         /* This is the old Bluetooth Xbox One S firmware, which isn't supported by this driver */
         /* This is the old Bluetooth Xbox One S firmware, which isn't supported by this driver */
         return SDL_FALSE;
         return SDL_FALSE;
     }
     }
@@ -822,9 +820,11 @@ HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device)
 static void
 static void
 HIDAPI_DriverXbox360_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
 HIDAPI_DriverXbox360_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
 {
 {
-#if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT)
     SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
     SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
-#endif
+
+    if (ctx->rumble_expiration) {
+        HIDAPI_DriverXbox360_RumbleJoystick(device, joystick, 0, 0, 0);
+    }
 
 
 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
     if (ctx->xinput_enabled) {
     if (ctx->xinput_enabled) {

+ 11 - 4
src/joystick/hidapi/SDL_hidapi_xbox360w.c

@@ -45,12 +45,14 @@ typedef struct {
 
 
 
 
 static SDL_bool
 static SDL_bool
-HIDAPI_DriverXbox360W_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name)
+HIDAPI_DriverXbox360W_IsSupportedDevice(const char *name, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
 {
-    const Uint16 MICROSOFT_USB_VID = 0x045e;
+    const int XB360W_IFACE_PROTOCOL = 129; /* Wireless */
+    SDL_GameControllerType type = SDL_GetJoystickGameControllerType(name, vendor_id, product_id, interface_number, interface_class, interface_subclass, interface_protocol);
 
 
-    if (vendor_id == MICROSOFT_USB_VID) {
-        return (product_id == 0x0291 || product_id == 0x0719);
+    if ((vendor_id == USB_VENDOR_MICROSOFT && (product_id == 0x0291 || product_id == 0x0719)) ||
+        (type == SDL_CONTROLLER_TYPE_XBOX360 && interface_protocol == XB360W_IFACE_PROTOCOL)) {
+        return SDL_TRUE;
     }
     }
     return SDL_FALSE;
     return SDL_FALSE;
 }
 }
@@ -290,6 +292,11 @@ HIDAPI_DriverXbox360W_UpdateDevice(SDL_HIDAPI_Device *device)
 static void
 static void
 HIDAPI_DriverXbox360W_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
 HIDAPI_DriverXbox360W_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
 {
 {
+    SDL_DriverXbox360W_Context *ctx = (SDL_DriverXbox360W_Context *)device->context;
+
+    if (ctx->rumble_expiration) {
+        HIDAPI_DriverXbox360W_RumbleJoystick(device, joystick, 0, 0, 0);
+    }
 }
 }
 
 
 static void
 static void

+ 3 - 16
src/joystick/hidapi/SDL_hidapi_xboxone.c

@@ -147,11 +147,6 @@ static SDL_bool
 IsBluetoothXboxOneController(Uint16 vendor_id, Uint16 product_id)
 IsBluetoothXboxOneController(Uint16 vendor_id, Uint16 product_id)
 {
 {
     /* Check to see if it's the Xbox One S or Xbox One Elite Series 2 in Bluetooth mode */
     /* Check to see if it's the Xbox One S or Xbox One Elite Series 2 in Bluetooth mode */
-    const Uint16 USB_VENDOR_MICROSOFT = 0x045e;
-    const Uint16 USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH = 0x02e0;
-    const Uint16 USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH = 0x02fd;
-    const Uint16 USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH = 0x0b05;
-
     if (vendor_id == USB_VENDOR_MICROSOFT) {
     if (vendor_id == USB_VENDOR_MICROSOFT) {
         if (product_id == USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH ||
         if (product_id == USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH ||
             product_id == USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH ||
             product_id == USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH ||
@@ -165,9 +160,6 @@ IsBluetoothXboxOneController(Uint16 vendor_id, Uint16 product_id)
 static SDL_bool
 static SDL_bool
 ControllerHasPaddles(Uint16 vendor_id, Uint16 product_id)
 ControllerHasPaddles(Uint16 vendor_id, Uint16 product_id)
 {
 {
-    const Uint16 USB_VENDOR_MICROSOFT = 0x045e;
-    const Uint16 USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2 = 0x0b00;
-
     if (vendor_id == USB_VENDOR_MICROSOFT) {
     if (vendor_id == USB_VENDOR_MICROSOFT) {
         if (product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2) {
         if (product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2) {
             return SDL_TRUE;
             return SDL_TRUE;
@@ -180,8 +172,6 @@ ControllerHasPaddles(Uint16 vendor_id, Uint16 product_id)
 static SDL_bool
 static SDL_bool
 ControllerNeedsRumbleSequenceSynchronized(Uint16 vendor_id, Uint16 product_id)
 ControllerNeedsRumbleSequenceSynchronized(Uint16 vendor_id, Uint16 product_id)
 {
 {
-    const Uint16 USB_VENDOR_MICROSOFT = 0x045e;
-
     if (vendor_id == USB_VENDOR_MICROSOFT) {
     if (vendor_id == USB_VENDOR_MICROSOFT) {
         /* All Xbox One controllers, from model 1537 through Elite Series 2, appear to need this */
         /* All Xbox One controllers, from model 1537 through Elite Series 2, appear to need this */
         return SDL_TRUE;
         return SDL_TRUE;
@@ -221,9 +211,6 @@ SynchronizeRumbleSequence(hid_device *dev, SDL_DriverXboxOne_Context *ctx)
 static SDL_bool
 static SDL_bool
 ControllerSendsWaitingForInit(Uint16 vendor_id, Uint16 product_id)
 ControllerSendsWaitingForInit(Uint16 vendor_id, Uint16 product_id)
 {
 {
-    const Uint16 USB_VENDOR_HYPERKIN = 0x2e24;
-    const Uint16 USB_VENDOR_PDP = 0x0e6f;
-
     if (vendor_id == USB_VENDOR_HYPERKIN) {
     if (vendor_id == USB_VENDOR_HYPERKIN) {
         /* The Hyperkin controllers always send 0x02 when waiting for init,
         /* The Hyperkin controllers always send 0x02 when waiting for init,
            and the Hyperkin Duke plays an Xbox startup animation, so we want
            and the Hyperkin Duke plays an Xbox startup animation, so we want
@@ -310,19 +297,19 @@ SendControllerInit(hid_device *dev, SDL_DriverXboxOne_Context *ctx)
 }
 }
 
 
 static SDL_bool
 static SDL_bool
-HIDAPI_DriverXboxOne_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name)
+HIDAPI_DriverXboxOne_IsSupportedDevice(const char *name, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
 {
 #ifdef __LINUX__
 #ifdef __LINUX__
     if (IsBluetoothXboxOneController(vendor_id, product_id)) {
     if (IsBluetoothXboxOneController(vendor_id, product_id)) {
         /* We can't do rumble on this device, hid_write() fails, so don't try to open it here */
         /* We can't do rumble on this device, hid_write() fails, so don't try to open it here */
         return SDL_FALSE;
         return SDL_FALSE;
     }
     }
-    if (vendor_id == 0x24c6 && product_id == 0x541a) {
+    if (vendor_id == USB_VENDOR_POWERA && product_id == 0x541a) {
         /* The PowerA Mini controller, model 1240245-01, blocks while writing feature reports */
         /* The PowerA Mini controller, model 1240245-01, blocks while writing feature reports */
         return SDL_FALSE;
         return SDL_FALSE;
     }
     }
 #endif
 #endif
-    return (SDL_GetJoystickGameControllerType(vendor_id, product_id, name) == SDL_CONTROLLER_TYPE_XBOXONE);
+    return (SDL_GetJoystickGameControllerType(name, vendor_id, product_id, interface_number, interface_class, interface_subclass, interface_protocol) == SDL_CONTROLLER_TYPE_XBOXONE);
 }
 }
 
 
 static const char *
 static const char *

+ 27 - 14
src/joystick/hidapi/SDL_hidapijoystick.c

@@ -389,7 +389,7 @@ HIDAPI_IsDeviceSupported(Uint16 vendor_id, Uint16 product_id, Uint16 version, co
 
 
     for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
     for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
         SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
         SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
-        if (driver->enabled && driver->IsSupportedDevice(vendor_id, product_id, version, -1, name)) {
+        if (driver->enabled && driver->IsSupportedDevice(name, vendor_id, product_id, version, -1, 0, 0, 0)) {
             return SDL_TRUE;
             return SDL_TRUE;
         }
         }
     }
     }
@@ -418,7 +418,7 @@ HIDAPI_GetDeviceDriver(SDL_HIDAPI_Device *device)
 
 
     for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
     for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
         SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
         SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
-        if (driver->enabled && driver->IsSupportedDevice(device->vendor_id, device->product_id, device->version, device->interface_number, device->name)) {
+        if (driver->enabled && driver->IsSupportedDevice(device->name, device->vendor_id, device->product_id, device->version, device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol)) {
             return driver;
             return driver;
         }
         }
     }
     }
@@ -647,6 +647,9 @@ HIDAPI_AddDevice(struct hid_device_info *info)
     device->product_id = info->product_id;
     device->product_id = info->product_id;
     device->version = info->release_number;
     device->version = info->release_number;
     device->interface_number = info->interface_number;
     device->interface_number = info->interface_number;
+    device->interface_class = info->interface_class;
+    device->interface_subclass = info->interface_subclass;
+    device->interface_protocol = info->interface_protocol;
     device->usage_page = info->usage_page;
     device->usage_page = info->usage_page;
     device->usage = info->usage;
     device->usage = info->usage;
     {
     {
@@ -736,7 +739,7 @@ HIDAPI_AddDevice(struct hid_device_info *info)
     HIDAPI_SetupDeviceDriver(device);
     HIDAPI_SetupDeviceDriver(device);
 
 
 #ifdef DEBUG_HIDAPI
 #ifdef DEBUG_HIDAPI
-    SDL_Log("Added HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, version %d, interface %d, usage page 0x%.4x, usage 0x%.4x, path = %s, driver = %s\n", device->name, device->vendor_id, device->product_id, device->version, device->interface_number, device->usage_page, device->usage, device->path, device->driver ? device->driver->hint : "NONE");
+    SDL_Log("Added HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, version %d, interface %d, interface_class %d, interface_subclass %d, interface_protocol %d, usage page 0x%.4x, usage 0x%.4x, path = %s, driver = %s\n", device->name, device->vendor_id, device->product_id, device->version, device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol, device->usage_page, device->usage, device->path, device->driver ? device->driver->hint : "NONE");
 #endif
 #endif
 }
 }
 
 
@@ -812,6 +815,7 @@ SDL_bool
 HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
 HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
 {
 {
     SDL_HIDAPI_Device *device;
     SDL_HIDAPI_Device *device;
+    SDL_bool supported = SDL_FALSE;
     SDL_bool result = SDL_FALSE;
     SDL_bool result = SDL_FALSE;
 
 
     /* Make sure we're initialized, as this could be called from other drivers during startup */
     /* Make sure we're initialized, as this could be called from other drivers during startup */
@@ -819,15 +823,24 @@ HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, cons
         return SDL_FALSE;
         return SDL_FALSE;
     }
     }
 
 
-    /* Don't update the device list for devices we know aren't supported */
-    if (!HIDAPI_IsDeviceSupported(vendor_id, product_id, version, name)) {
-        return SDL_FALSE;
-    }
-
-    /* Make sure the device list is completely up to date when we check for device presence */
-    if (SDL_AtomicTryLock(&SDL_HIDAPI_spinlock)) {
-        HIDAPI_UpdateDeviceList();
-        SDL_AtomicUnlock(&SDL_HIDAPI_spinlock);
+    /* Only update the device list for devices we know might be supported.
+       If we did this for every device, it would hit the USB driver too hard and potentially 
+       lock up the system. This won't catch devices that we support but can only detect using 
+       USB interface details, like Xbox controllers, but hopefully the device list update is
+       responsive enough to catch those.
+     */
+    supported = HIDAPI_IsDeviceSupported(vendor_id, product_id, version, name);
+#if defined(SDL_JOYSTICK_HIDAPI_XBOX360) || defined(SDL_JOYSTICK_HIDAPI_XBOXONE)
+    if (!supported &&
+        (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box") || SDL_strstr(name, "XBOX"))) {
+        supported = SDL_TRUE;
+    }
+#endif /* SDL_JOYSTICK_HIDAPI_XBOX360 || SDL_JOYSTICK_HIDAPI_XBOXONE */
+    if (supported) {
+        if (SDL_AtomicTryLock(&SDL_HIDAPI_spinlock)) {
+            HIDAPI_UpdateDeviceList();
+            SDL_AtomicUnlock(&SDL_HIDAPI_spinlock);
+        }
     }
     }
 
 
     /* Note that this isn't a perfect check - there may be multiple devices with 0 VID/PID,
     /* Note that this isn't a perfect check - there may be multiple devices with 0 VID/PID,
@@ -845,8 +858,8 @@ HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, cons
     SDL_UnlockJoysticks();
     SDL_UnlockJoysticks();
 
 
     /* If we're looking for the wireless XBox 360 controller, also look for the dongle */
     /* If we're looking for the wireless XBox 360 controller, also look for the dongle */
-    if (!result && vendor_id == 0x045e && product_id == 0x02a1) {
-        return HIDAPI_IsDevicePresent(0x045e, 0x0719, version, name);
+    if (!result && vendor_id == USB_VENDOR_MICROSOFT && product_id == 0x02a1) {
+        return HIDAPI_IsDevicePresent(USB_VENDOR_MICROSOFT, 0x0719, version, name);
     }
     }
 
 
 #ifdef DEBUG_HIDAPI
 #ifdef DEBUG_HIDAPI

+ 5 - 1
src/joystick/hidapi/SDL_hidapijoystick_c.h

@@ -24,6 +24,7 @@
 #define SDL_JOYSTICK_HIDAPI_H
 #define SDL_JOYSTICK_HIDAPI_H
 
 
 #include "../../hidapi/hidapi/hidapi.h"
 #include "../../hidapi/hidapi/hidapi.h"
+#include "../usb_ids.h"
 
 
 /* This is the full set of HIDAPI drivers available */
 /* This is the full set of HIDAPI drivers available */
 #define SDL_JOYSTICK_HIDAPI_PS4
 #define SDL_JOYSTICK_HIDAPI_PS4
@@ -59,6 +60,9 @@ typedef struct _SDL_HIDAPI_Device
     Uint16 version;
     Uint16 version;
     SDL_JoystickGUID guid;
     SDL_JoystickGUID guid;
     int interface_number;   /* Available on Windows and Linux */
     int interface_number;   /* Available on Windows and Linux */
+    int interface_class;
+    int interface_subclass;
+    int interface_protocol;
     Uint16 usage_page;      /* Available on Windows and Mac OS X */
     Uint16 usage_page;      /* Available on Windows and Mac OS X */
     Uint16 usage;           /* Available on Windows and Mac OS X */
     Uint16 usage;           /* Available on Windows and Mac OS X */
 
 
@@ -78,7 +82,7 @@ typedef struct _SDL_HIDAPI_DeviceDriver
 {
 {
     const char *hint;
     const char *hint;
     SDL_bool enabled;
     SDL_bool enabled;
-    SDL_bool (*IsSupportedDevice)(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name);
+    SDL_bool (*IsSupportedDevice)(const char *name, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol);
     const char *(*GetDeviceName)(Uint16 vendor_id, Uint16 product_id);
     const char *(*GetDeviceName)(Uint16 vendor_id, Uint16 product_id);
     SDL_bool (*InitDevice)(SDL_HIDAPI_Device *device);
     SDL_bool (*InitDevice)(SDL_HIDAPI_Device *device);
     int (*GetDevicePlayerIndex)(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id);
     int (*GetDevicePlayerIndex)(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id);

+ 1 - 1
src/joystick/windows/SDL_dinputjoystick.c

@@ -374,7 +374,7 @@ SDL_IsXInputDevice(const GUID* pGuidProductFromDirectInput)
     if (SDL_memcmp(&pGuidProductFromDirectInput->Data4[2], "PIDVID", 6) == 0) {
     if (SDL_memcmp(&pGuidProductFromDirectInput->Data4[2], "PIDVID", 6) == 0) {
         Uint16 vendor_id = (Uint16)LOWORD(pGuidProductFromDirectInput->Data1);
         Uint16 vendor_id = (Uint16)LOWORD(pGuidProductFromDirectInput->Data1);
         Uint16 product_id = (Uint16)HIWORD(pGuidProductFromDirectInput->Data1);
         Uint16 product_id = (Uint16)HIWORD(pGuidProductFromDirectInput->Data1);
-        SDL_GameControllerType type = SDL_GetJoystickGameControllerType(vendor_id, product_id, "");
+        SDL_GameControllerType type = SDL_GetJoystickGameControllerType("", vendor_id, product_id, -1, 0, 0, 0);
         if (type == SDL_CONTROLLER_TYPE_XBOX360 ||
         if (type == SDL_CONTROLLER_TYPE_XBOX360 ||
             type == SDL_CONTROLLER_TYPE_XBOXONE ||
             type == SDL_CONTROLLER_TYPE_XBOXONE ||
             (vendor_id == 0x28DE && product_id == 0x11FF)) {
             (vendor_id == 0x28DE && product_id == 0x11FF)) {