SDL: Added hints for more fine grained control over HIDAPI Xbox controller support

From 52b6899a6b558595d0510bc6544d80b1d9220a82 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 19 Aug 2022 11:11:23 -0700
Subject: [PATCH] Added hints for more fine grained control over HIDAPI Xbox
 controller support

---
 include/SDL_hints.h                        | 33 ++++++++++
 src/joystick/hidapi/SDL_hidapi_combined.c  | 24 ++++++-
 src/joystick/hidapi/SDL_hidapi_gamecube.c  | 25 +++++++-
 src/joystick/hidapi/SDL_hidapi_luna.c      | 25 +++++++-
 src/joystick/hidapi/SDL_hidapi_ps4.c       | 25 +++++++-
 src/joystick/hidapi/SDL_hidapi_ps5.c       | 25 +++++++-
 src/joystick/hidapi/SDL_hidapi_shield.c    | 25 +++++++-
 src/joystick/hidapi/SDL_hidapi_stadia.c    | 25 +++++++-
 src/joystick/hidapi/SDL_hidapi_steam.c     | 25 +++++++-
 src/joystick/hidapi/SDL_hidapi_switch.c    | 73 ++++++++++++++++++++--
 src/joystick/hidapi/SDL_hidapi_xbox360.c   | 30 ++++++++-
 src/joystick/hidapi/SDL_hidapi_xbox360w.c  | 33 +++++++++-
 src/joystick/hidapi/SDL_hidapi_xboxone.c   | 30 ++++++++-
 src/joystick/hidapi/SDL_hidapijoystick.c   | 58 ++++++++---------
 src/joystick/hidapi/SDL_hidapijoystick_c.h | 10 ++-
 15 files changed, 402 insertions(+), 64 deletions(-)

diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index e7cddba0391..c13c206241b 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -851,6 +851,39 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_HIDAPI_XBOX   "SDL_JOYSTICK_HIDAPI_XBOX"
 
+/**
+ *  \brief  A variable controlling whether the HIDAPI driver for XBox 360 controllers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI driver is not used
+ *    "1"       - HIDAPI driver is used
+ *
+ *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI_XBOX
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_XBOX_360   "SDL_JOYSTICK_HIDAPI_XBOX_360"
+
+/**
+ *  \brief  A variable controlling whether the HIDAPI driver for XBox 360 wireless controllers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI driver is not used
+ *    "1"       - HIDAPI driver is used
+ *
+ *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI_XBOX_360
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_WIRELESS   "SDL_JOYSTICK_HIDAPI_XBOX_360_WIRELESS"
+
+/**
+ *  \brief  A variable controlling whether the HIDAPI driver for XBox One should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI driver is not used
+ *    "1"       - HIDAPI driver is used
+ *
+ *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI_XBOX
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE   "SDL_JOYSTICK_HIDAPI_XBOX_ONE"
+
 /**
   *  \brief  A variable controlling whether the RAWINPUT joystick drivers should be used for better handling XInput-capable devices.
   *
diff --git a/src/joystick/hidapi/SDL_hidapi_combined.c b/src/joystick/hidapi/SDL_hidapi_combined.c
index 06f3d5510c3..8dae1a2f250 100644
--- a/src/joystick/hidapi/SDL_hidapi_combined.c
+++ b/src/joystick/hidapi/SDL_hidapi_combined.c
@@ -23,12 +23,28 @@
 
 #ifdef SDL_JOYSTICK_HIDAPI
 
-#include "SDL_hints.h"
 #include "SDL_joystick.h"
 #include "SDL_gamecontroller.h"
 #include "SDL_hidapijoystick_c.h"
 #include "../SDL_sysjoystick.h"
 
+
+static void
+HIDAPI_DriverCombined_RegisterHints(SDL_HintCallback callback, void *userdata)
+{
+}
+
+static void
+HIDAPI_DriverCombined_UnregisterHints(SDL_HintCallback callback, void *userdata)
+{
+}
+
+static SDL_bool
+HIDAPI_DriverCombined_IsEnabled(void)
+{
+    return SDL_TRUE;
+}
+
 static SDL_bool
 HIDAPI_DriverCombined_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
@@ -219,9 +235,11 @@ HIDAPI_DriverCombined_FreeDevice(SDL_HIDAPI_Device *device)
 
 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverCombined =
 {
-    SDL_HINT_JOYSTICK_HIDAPI,
-    SDL_TRUE,
+    "SDL_JOYSTICK_HIDAPI_COMBINED",
     SDL_TRUE,
+    HIDAPI_DriverCombined_RegisterHints,
+    HIDAPI_DriverCombined_UnregisterHints,
+    HIDAPI_DriverCombined_IsEnabled,
     HIDAPI_DriverCombined_IsSupportedDevice,
     HIDAPI_DriverCombined_GetDeviceName,
     HIDAPI_DriverCombined_InitDevice,
diff --git a/src/joystick/hidapi/SDL_hidapi_gamecube.c b/src/joystick/hidapi/SDL_hidapi_gamecube.c
index dad4daeaabb..97321b853be 100644
--- a/src/joystick/hidapi/SDL_hidapi_gamecube.c
+++ b/src/joystick/hidapi/SDL_hidapi_gamecube.c
@@ -22,7 +22,6 @@
 
 #ifdef SDL_JOYSTICK_HIDAPI
 
-#include "SDL_hints.h"
 #include "SDL_events.h"
 #include "SDL_timer.h"
 #include "SDL_haptic.h"
@@ -56,6 +55,26 @@ typedef struct {
     SDL_bool useRumbleBrake;
 } SDL_DriverGameCube_Context;
 
+static void
+HIDAPI_DriverGameCube_RegisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, callback, userdata);
+}
+
+static void
+HIDAPI_DriverGameCube_UnregisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, callback, userdata);
+}
+
+static SDL_bool
+HIDAPI_DriverGameCube_IsEnabled(void)
+{
+    return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE,
+               SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
+                   SDL_HIDAPI_DEFAULT));
+}
+
 static SDL_bool
 HIDAPI_DriverGameCube_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
@@ -562,7 +581,9 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube =
 {
     SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE,
     SDL_TRUE,
-    SDL_TRUE,
+    HIDAPI_DriverGameCube_RegisterHints,
+    HIDAPI_DriverGameCube_UnregisterHints,
+    HIDAPI_DriverGameCube_IsEnabled,
     HIDAPI_DriverGameCube_IsSupportedDevice,
     HIDAPI_DriverGameCube_GetDeviceName,
     HIDAPI_DriverGameCube_InitDevice,
diff --git a/src/joystick/hidapi/SDL_hidapi_luna.c b/src/joystick/hidapi/SDL_hidapi_luna.c
index 4b283e28407..3d285809e12 100644
--- a/src/joystick/hidapi/SDL_hidapi_luna.c
+++ b/src/joystick/hidapi/SDL_hidapi_luna.c
@@ -22,7 +22,6 @@
 
 #ifdef SDL_JOYSTICK_HIDAPI
 
-#include "SDL_hints.h"
 #include "SDL_events.h"
 #include "SDL_joystick.h"
 #include "SDL_gamecontroller.h"
@@ -47,6 +46,26 @@ typedef struct {
 } SDL_DriverLuna_Context;
 
 
+static void
+HIDAPI_DriverLuna_RegisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_LUNA, callback, userdata);
+}
+
+static void
+HIDAPI_DriverLuna_UnregisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_LUNA, callback, userdata);
+}
+
+static SDL_bool
+HIDAPI_DriverLuna_IsEnabled(void)
+{
+    return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_LUNA,
+               SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
+                   SDL_HIDAPI_DEFAULT));
+}
+
 static SDL_bool
 HIDAPI_DriverLuna_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
@@ -438,7 +457,9 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverLuna =
 {
     SDL_HINT_JOYSTICK_HIDAPI_LUNA,
     SDL_TRUE,
-    SDL_TRUE,
+    HIDAPI_DriverLuna_RegisterHints,
+    HIDAPI_DriverLuna_UnregisterHints,
+    HIDAPI_DriverLuna_IsEnabled,
     HIDAPI_DriverLuna_IsSupportedDevice,
     HIDAPI_DriverLuna_GetDeviceName,
     HIDAPI_DriverLuna_InitDevice,
diff --git a/src/joystick/hidapi/SDL_hidapi_ps4.c b/src/joystick/hidapi/SDL_hidapi_ps4.c
index 7c87043cfbf..3d3b617d872 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps4.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps4.c
@@ -25,7 +25,6 @@
 
 #ifdef SDL_JOYSTICK_HIDAPI
 
-#include "SDL_hints.h"
 #include "SDL_events.h"
 #include "SDL_timer.h"
 #include "SDL_joystick.h"
@@ -148,6 +147,26 @@ typedef struct {
 
 static int HIDAPI_DriverPS4_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size);
 
+static void
+HIDAPI_DriverPS4_RegisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS4, callback, userdata);
+}
+
+static void
+HIDAPI_DriverPS4_UnregisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS4, callback, userdata);
+}
+
+static SDL_bool
+HIDAPI_DriverPS4_IsEnabled(void)
+{
+    return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS4,
+               SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
+                   SDL_HIDAPI_DEFAULT));
+}
+
 static SDL_bool
 HIDAPI_DriverPS4_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
@@ -939,7 +958,9 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4 =
 {
     SDL_HINT_JOYSTICK_HIDAPI_PS4,
     SDL_TRUE,
-    SDL_TRUE,
+    HIDAPI_DriverPS4_RegisterHints,
+    HIDAPI_DriverPS4_UnregisterHints,
+    HIDAPI_DriverPS4_IsEnabled,
     HIDAPI_DriverPS4_IsSupportedDevice,
     HIDAPI_DriverPS4_GetDeviceName,
     HIDAPI_DriverPS4_InitDevice,
diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c
index a881a838a6d..8a199f2e7fa 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps5.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps5.c
@@ -22,7 +22,6 @@
 
 #ifdef SDL_JOYSTICK_HIDAPI
 
-#include "SDL_hints.h"
 #include "SDL_events.h"
 #include "SDL_timer.h"
 #include "SDL_joystick.h"
@@ -179,6 +178,26 @@ typedef struct {
 
 static int HIDAPI_DriverPS5_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size);
 
+static void
+HIDAPI_DriverPS5_RegisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5, callback, userdata);
+}
+
+static void
+HIDAPI_DriverPS5_UnregisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5, callback, userdata);
+}
+
+static SDL_bool
+HIDAPI_DriverPS5_IsEnabled(void)
+{
+    return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS5,
+               SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
+                   SDL_HIDAPI_DEFAULT));
+}
+
 static SDL_bool
 HIDAPI_DriverPS5_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
@@ -1121,7 +1140,9 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS5 =
 {
     SDL_HINT_JOYSTICK_HIDAPI_PS5,
     SDL_TRUE,
-    SDL_TRUE,
+    HIDAPI_DriverPS5_RegisterHints,
+    HIDAPI_DriverPS5_UnregisterHints,
+    HIDAPI_DriverPS5_IsEnabled,
     HIDAPI_DriverPS5_IsSupportedDevice,
     HIDAPI_DriverPS5_GetDeviceName,
     HIDAPI_DriverPS5_InitDevice,
diff --git a/src/joystick/hidapi/SDL_hidapi_shield.c b/src/joystick/hidapi/SDL_hidapi_shield.c
index 7e487e51130..36bb794689a 100644
--- a/src/joystick/hidapi/SDL_hidapi_shield.c
+++ b/src/joystick/hidapi/SDL_hidapi_shield.c
@@ -22,7 +22,6 @@
 
 #ifdef SDL_JOYSTICK_HIDAPI
 
-#include "SDL_hints.h"
 #include "SDL_events.h"
 #include "SDL_timer.h"
 #include "SDL_joystick.h"
@@ -82,6 +81,26 @@ typedef struct {
 } SDL_DriverShield_Context;
 
 
+static void
+HIDAPI_DriverShield_RegisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SHIELD, callback, userdata);
+}
+
+static void
+HIDAPI_DriverShield_UnregisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SHIELD, callback, userdata);
+}
+
+static SDL_bool
+HIDAPI_DriverShield_IsEnabled(void)
+{
+    return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_SHIELD,
+               SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
+                   SDL_HIDAPI_DEFAULT));
+}
+
 static SDL_bool
 HIDAPI_DriverShield_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
@@ -445,7 +464,9 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverShield =
 {
     SDL_HINT_JOYSTICK_HIDAPI_SHIELD,
     SDL_TRUE,
-    SDL_TRUE,
+    HIDAPI_DriverShield_RegisterHints,
+    HIDAPI_DriverShield_UnregisterHints,
+    HIDAPI_DriverShield_IsEnabled,
     HIDAPI_DriverShield_IsSupportedDevice,
     HIDAPI_DriverShield_GetDeviceName,
     HIDAPI_DriverShield_InitDevice,
diff --git a/src/joystick/hidapi/SDL_hidapi_stadia.c b/src/joystick/hidapi/SDL_hidapi_stadia.c
index 35025db9ebe..435031b31f6 100644
--- a/src/joystick/hidapi/SDL_hidapi_stadia.c
+++ b/src/joystick/hidapi/SDL_hidapi_stadia.c
@@ -22,7 +22,6 @@
 
 #ifdef SDL_JOYSTICK_HIDAPI
 
-#include "SDL_hints.h"
 #include "SDL_events.h"
 #include "SDL_joystick.h"
 #include "SDL_gamecontroller.h"
@@ -48,6 +47,26 @@ typedef struct {
 } SDL_DriverStadia_Context;
 
 
+static void
+HIDAPI_DriverStadia_RegisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_STADIA, callback, userdata);
+}
+
+static void
+HIDAPI_DriverStadia_UnregisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_STADIA, callback, userdata);
+}
+
+static SDL_bool
+HIDAPI_DriverStadia_IsEnabled(void)
+{
+    return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_STADIA,
+               SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
+                   SDL_HIDAPI_DEFAULT));
+}
+
 static SDL_bool
 HIDAPI_DriverStadia_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
@@ -306,7 +325,9 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverStadia =
 {
     SDL_HINT_JOYSTICK_HIDAPI_STADIA,
     SDL_TRUE,
-    SDL_TRUE,
+    HIDAPI_DriverStadia_RegisterHints,
+    HIDAPI_DriverStadia_UnregisterHints,
+    HIDAPI_DriverStadia_IsEnabled,
     HIDAPI_DriverStadia_IsSupportedDevice,
     HIDAPI_DriverStadia_GetDeviceName,
     HIDAPI_DriverStadia_InitDevice,
diff --git a/src/joystick/hidapi/SDL_hidapi_steam.c b/src/joystick/hidapi/SDL_hidapi_steam.c
index bbf1f0e2b81..27a541cc9d0 100644
--- a/src/joystick/hidapi/SDL_hidapi_steam.c
+++ b/src/joystick/hidapi/SDL_hidapi_steam.c
@@ -22,7 +22,6 @@
 
 #ifdef SDL_JOYSTICK_HIDAPI
 
-#include "SDL_hints.h"
 #include "SDL_events.h"
 #include "SDL_timer.h"
 #include "SDL_joystick.h"
@@ -997,6 +996,26 @@ typedef struct {
 } SDL_DriverSteam_Context;
 
 
+static void
+HIDAPI_DriverSteam_RegisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_STEAM, callback, userdata);
+}
+
+static void
+HIDAPI_DriverSteam_UnregisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_STEAM, callback, userdata);
+}
+
+static SDL_bool
+HIDAPI_DriverSteam_IsEnabled(void)
+{
+    return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_STEAM,
+               SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
+                   SDL_HIDAPI_DEFAULT));
+}
+
 static SDL_bool
 HIDAPI_DriverSteam_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
@@ -1284,7 +1303,9 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteam =
 {
     SDL_HINT_JOYSTICK_HIDAPI_STEAM,
     SDL_TRUE,
-    SDL_FALSE,
+    HIDAPI_DriverSteam_RegisterHints,
+    HIDAPI_DriverSteam_UnregisterHints,
+    HIDAPI_DriverSteam_IsEnabled,
     HIDAPI_DriverSteam_IsSupportedDevice,
     HIDAPI_DriverSteam_GetDeviceName,
     HIDAPI_DriverSteam_InitDevice,
diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c
index baf0d622857..c58895665b1 100644
--- a/src/joystick/hidapi/SDL_hidapi_switch.c
+++ b/src/joystick/hidapi/SDL_hidapi_switch.c
@@ -25,7 +25,6 @@
 
 #ifdef SDL_JOYSTICK_HIDAPI
 
-#include "SDL_hints.h"
 #include "SDL_events.h"
 #include "SDL_timer.h"
 #include "SDL_joystick.h"
@@ -361,6 +360,26 @@ IsGameCubeFormFactor(int vendor_id, int product_id)
     return SDL_FALSE;
 }
 
+static void
+HIDAPI_DriverNintendoClassic_RegisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_NINTENDO_CLASSIC, callback, userdata);
+}
+
+static void
+HIDAPI_DriverNintendoClassic_UnregisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_NINTENDO_CLASSIC, callback, userdata);
+}
+
+static SDL_bool
+HIDAPI_DriverNintendoClassic_IsEnabled(void)
+{
+    return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_NINTENDO_CLASSIC,
+               SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
+                   SDL_HIDAPI_DEFAULT));
+}
+
 static SDL_bool
 HIDAPI_DriverNintendoClassic_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
@@ -387,6 +406,26 @@ HIDAPI_DriverNintendoClassic_IsSupportedDevice(const char *name, SDL_GameControl
     return SDL_FALSE;
 }
 
+static void
+HIDAPI_DriverJoyCons_RegisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, callback, userdata);
+}
+
+static void
+HIDAPI_DriverJoyCons_UnregisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, callback, userdata);
+}
+
+static SDL_bool
+HIDAPI_DriverJoyCons_IsEnabled(void)
+{
+    return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS,
+               SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
+                   SDL_HIDAPI_DEFAULT));
+}
+
 static SDL_bool
 HIDAPI_DriverJoyCons_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
@@ -400,6 +439,26 @@ HIDAPI_DriverJoyCons_IsSupportedDevice(const char *name, SDL_GameControllerType
     return SDL_FALSE;
 }
 
+static void
+HIDAPI_DriverSwitch_RegisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, callback, userdata);
+}
+
+static void
+HIDAPI_DriverSwitch_UnregisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, callback, userdata);
+}
+
+static SDL_bool
+HIDAPI_DriverSwitch_IsEnabled(void)
+{
+    return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_SWITCH,
+               SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
+                   SDL_HIDAPI_DEFAULT));
+}
+
 static SDL_bool
 HIDAPI_DriverSwitch_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
@@ -2147,7 +2206,9 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverNintendoClassic =
 {
     SDL_HINT_JOYSTICK_HIDAPI_NINTENDO_CLASSIC,
     SDL_TRUE,
-    SDL_TRUE,
+    HIDAPI_DriverNintendoClassic_RegisterHints,
+    HIDAPI_DriverNintendoClassic_UnregisterHints,
+    HIDAPI_DriverNintendoClassic_IsEnabled,
     HIDAPI_DriverNintendoClassic_IsSupportedDevice,
     HIDAPI_DriverSwitch_GetDeviceName,
     HIDAPI_DriverSwitch_InitDevice,
@@ -2169,7 +2230,9 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverJoyCons =
 {
     SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS,
     SDL_TRUE,
-    SDL_TRUE,
+    HIDAPI_DriverJoyCons_RegisterHints,
+    HIDAPI_DriverJoyCons_UnregisterHints,
+    HIDAPI_DriverJoyCons_IsEnabled,
     HIDAPI_DriverJoyCons_IsSupportedDevice,
     HIDAPI_DriverSwitch_GetDeviceName,
     HIDAPI_DriverSwitch_InitDevice,
@@ -2191,7 +2254,9 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch =
 {
     SDL_HINT_JOYSTICK_HIDAPI_SWITCH,
     SDL_TRUE,
-    SDL_TRUE,
+    HIDAPI_DriverSwitch_RegisterHints,
+    HIDAPI_DriverSwitch_UnregisterHints,
+    HIDAPI_DriverSwitch_IsEnabled,
     HIDAPI_DriverSwitch_IsSupportedDevice,
     HIDAPI_DriverSwitch_GetDeviceName,
     HIDAPI_DriverSwitch_InitDevice,
diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360.c b/src/joystick/hidapi/SDL_hidapi_xbox360.c
index 53b88914999..2ac3b17ba73 100644
--- a/src/joystick/hidapi/SDL_hidapi_xbox360.c
+++ b/src/joystick/hidapi/SDL_hidapi_xbox360.c
@@ -22,7 +22,6 @@
 
 #ifdef SDL_JOYSTICK_HIDAPI
 
-#include "SDL_hints.h"
 #include "SDL_events.h"
 #include "SDL_timer.h"
 #include "SDL_joystick.h"
@@ -42,6 +41,29 @@ typedef struct {
     Uint8 last_state[USB_PACKET_LENGTH];
 } SDL_DriverXbox360_Context;
 
+static void
+HIDAPI_DriverXbox360_RegisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata);
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360, callback, userdata);
+}
+
+static void
+HIDAPI_DriverXbox360_UnregisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata);
+    SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360, callback, userdata);
+}
+
+static SDL_bool
+HIDAPI_DriverXbox360_IsEnabled(void)
+{
+    return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360,
+               SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX,
+                   SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
+                       SDL_HIDAPI_DEFAULT)));
+}
+
 static SDL_bool
 HIDAPI_DriverXbox360_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
@@ -335,9 +357,11 @@ HIDAPI_DriverXbox360_FreeDevice(SDL_HIDAPI_Device *device)
 
 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 =
 {
-    SDL_HINT_JOYSTICK_HIDAPI_XBOX,
-    SDL_TRUE,
+    SDL_HINT_JOYSTICK_HIDAPI_XBOX_360,
     SDL_TRUE,
+    HIDAPI_DriverXbox360_RegisterHints,
+    HIDAPI_DriverXbox360_UnregisterHints,
+    HIDAPI_DriverXbox360_IsEnabled,
     HIDAPI_DriverXbox360_IsSupportedDevice,
     HIDAPI_DriverXbox360_GetDeviceName,
     HIDAPI_DriverXbox360_InitDevice,
diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360w.c b/src/joystick/hidapi/SDL_hidapi_xbox360w.c
index 3d9895b77e0..a75d1bd599d 100644
--- a/src/joystick/hidapi/SDL_hidapi_xbox360w.c
+++ b/src/joystick/hidapi/SDL_hidapi_xbox360w.c
@@ -22,7 +22,6 @@
 
 #ifdef SDL_JOYSTICK_HIDAPI
 
-#include "SDL_hints.h"
 #include "SDL_events.h"
 #include "SDL_timer.h"
 #include "SDL_joystick.h"
@@ -44,6 +43,32 @@ typedef struct {
 } SDL_DriverXbox360W_Context;
 
 
+static void
+HIDAPI_DriverXbox360W_RegisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata);
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360, callback, userdata);
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_WIRELESS, callback, userdata);
+}
+
+static void
+HIDAPI_DriverXbox360W_UnregisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata);
+    SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360, callback, userdata);
+    SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_WIRELESS, callback, userdata);
+}
+
+static SDL_bool
+HIDAPI_DriverXbox360W_IsEnabled(void)
+{
+    return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_WIRELESS,
+               SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360,
+                   SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX,
+                       SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
+                           SDL_HIDAPI_DEFAULT))));
+}
+
 static SDL_bool
 HIDAPI_DriverXbox360W_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
@@ -332,9 +357,11 @@ HIDAPI_DriverXbox360W_FreeDevice(SDL_HIDAPI_Device *device)
 
 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W =
 {
-    SDL_HINT_JOYSTICK_HIDAPI_XBOX,
-    SDL_TRUE,
+    SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_WIRELESS,
     SDL_TRUE,
+    HIDAPI_DriverXbox360W_RegisterHints,
+    HIDAPI_DriverXbox360W_UnregisterHints,
+    HIDAPI_DriverXbox360W_IsEnabled,
     HIDAPI_DriverXbox360W_IsSupportedDevice,
     HIDAPI_DriverXbox360W_GetDeviceName,
     HIDAPI_DriverXbox360W_InitDevice,
diff --git a/src/joystick/hidapi/SDL_hidapi_xboxone.c b/src/joystick/hidapi/SDL_hidapi_xboxone.c
index 3a3eb9c6208..94f04b6e066 100644
--- a/src/joystick/hidapi/SDL_hidapi_xboxone.c
+++ b/src/joystick/hidapi/SDL_hidapi_xboxone.c
@@ -22,7 +22,6 @@
 
 #ifdef SDL_JOYSTICK_HIDAPI
 
-#include "SDL_hints.h"
 #include "SDL_events.h"
 #include "SDL_timer.h"
 #include "SDL_joystick.h"
@@ -266,6 +265,29 @@ SendControllerInit(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_Context *ctx)
     return SDL_TRUE;
 }
 
+static void
+HIDAPI_DriverXboxOne_RegisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata);
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE, callback, userdata);
+}
+
+static void
+HIDAPI_DriverXboxOne_UnregisterHints(SDL_HintCallback callback, void *userdata)
+{
+    SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata);
+    SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE, callback, userdata);
+}
+
+static SDL_bool
+HIDAPI_DriverXboxOne_IsEnabled(void)
+{
+    return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE,
+               SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX,
+                   SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
+                       SDL_HIDAPI_DEFAULT)));
+}
+
 static SDL_bool
 HIDAPI_DriverXboxOne_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
@@ -1129,9 +1151,11 @@ HIDAPI_DriverXboxOne_FreeDevice(SDL_HIDAPI_Device *device)
 
 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
 {
-    SDL_HINT_JOYSTICK_HIDAPI_XBOX,
-    SDL_TRUE,
+    SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE,
     SDL_TRUE,
+    HIDAPI_DriverXboxOne_RegisterHints,
+    HIDAPI_DriverXboxOne_UnregisterHints,
+    HIDAPI_DriverXboxOne_IsEnabled,
     HIDAPI_DriverXboxOne_IsSupportedDevice,
     HIDAPI_DriverXboxOne_GetDeviceName,
     HIDAPI_DriverXboxOne_InitDevice,
diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c
index 132d3ea0b4a..0bb7954b662 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick.c
+++ b/src/joystick/hidapi/SDL_hidapijoystick.c
@@ -79,6 +79,7 @@ static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = {
 };
 static int SDL_HIDAPI_numdrivers = 0;
 static SDL_SpinLock SDL_HIDAPI_spinlock;
+static SDL_bool SDL_HIDAPI_hints_changed = SDL_FALSE;
 static Uint32 SDL_HIDAPI_change_count = 0;
 static SDL_HIDAPI_Device *SDL_HIDAPI_devices;
 static int SDL_HIDAPI_numjoysticks = 0;
@@ -113,7 +114,7 @@ HIDAPI_RemapVal(float val, float val_min, float val_max, float output_min, float
     return output_min + (output_max - output_min) * (val - val_min) / (val_max - val_min);
 }
 
-static void HIDAPI_JoystickDetect(void);
+static void HIDAPI_UpdateDeviceList(void);
 static void HIDAPI_JoystickClose(SDL_Joystick *joystick);
 
 static SDL_GameControllerType
@@ -349,48 +350,34 @@ HIDAPI_SetupDeviceDriver(SDL_HIDAPI_Device *device)
     }
 }
 
-static void SDLCALL
-SDL_HIDAPIDriverHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
+static void
+SDL_HIDAPI_UpdateDrivers(void)
 {
     int i;
     SDL_HIDAPI_Device *device;
-    SDL_bool enabled = SDL_GetStringBoolean(hint, SDL_TRUE);
-
-    if (SDL_strcmp(name, SDL_HINT_JOYSTICK_HIDAPI) == 0) {
-        for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
-            SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
-            driver->enabled = SDL_GetHintBoolean(driver->hint, enabled);
-        }
-    } else if (SDL_strcmp(name, SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS) == 0) {
-        SDL_HIDAPI_combine_joycons = enabled;
-    } else {
-        for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
-            SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
-            if (SDL_strcmp(name, driver->hint) == 0) {
-                driver->enabled = enabled;
-            }
-        }
-    }
 
     SDL_HIDAPI_numdrivers = 0;
     for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
         SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
-        if (driver->enabled) {
+        driver->enabled = driver->IsEnabled();
+        if (driver->enabled && driver != &SDL_HIDAPI_DriverCombined) {
             ++SDL_HIDAPI_numdrivers;
         }
     }
 
-    /* Update device list if driver availability changes */
-    SDL_LockJoysticks();
-
     for (device = SDL_HIDAPI_devices; device; device = device->next) {
         HIDAPI_SetupDeviceDriver(device);
     }
+}
 
-    /* Update the device list again to pick up any new devices */
+static void SDLCALL
+SDL_HIDAPIDriverHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
+{
+    if (SDL_strcmp(name, SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS) == 0) {
+        SDL_HIDAPI_combine_joycons = SDL_GetStringBoolean(hint, SDL_TRUE);
+    }
+    SDL_HIDAPI_hints_changed = SDL_TRUE;
     SDL_HIDAPI_change_count = 0;
-
-    SDL_UnlockJoysticks();
 }
 
 static int
@@ -430,13 +417,15 @@ HIDAPI_JoystickInit(void)
 
     for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
         SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
-        SDL_AddHintCallback(driver->hint, SDL_HIDAPIDriverHintChanged, NULL);
+        driver->RegisterHints(SDL_HIDAPIDriverHintChanged, driver);
     }
     SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS,
                         SDL_HIDAPIDriverHintChanged, NULL);
     SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI,
                         SDL_HIDAPIDriverHintChanged, NULL);
-    HIDAPI_JoystickDetect();
+
+    SDL_HIDAPI_change_count = SDL_hid_device_change_count();
+    HIDAPI_UpdateDeviceList();
     HIDAPI_UpdateDevices();
 
     initialized = SDL_TRUE;
@@ -685,7 +674,7 @@ HIDAPI_AddDevice(const struct SDL_hid_device_info *info, int num_children, SDL_H
     HIDAPI_SetupDeviceDriver(device);
 
 #ifdef DEBUG_HIDAPI
-    SDL_Log("Added HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, version %d, serial %s, interface %d, interface_class %d, interface_subclass %d, interface_protocol %d, usage page 0x%.4x, usage 0x%.4x, path = %s, driver = %s (%s)\n", device->name, device->vendor_id, device->product_id, device->version, device->serial ? device->serial : "NONE", 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", device->driver && device->driver->enabled ? "ENABLED" : "DISABLED");
+    SDL_Log("Added HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, version %d, serial %s, interface %d, interface_cla

(Patch may be truncated, please check the link at the top of this post.)