diff --git a/VisualC/SDL/SDL.vcxproj b/VisualC/SDL/SDL.vcxproj
index a061864e1..e592e94e3 100644
--- a/VisualC/SDL/SDL.vcxproj
+++ b/VisualC/SDL/SDL.vcxproj
@@ -299,6 +299,7 @@
     <ClInclude Include="..\..\src\audio\wasapi\SDL_wasapi.h" />
     <ClInclude Include="..\..\src\audio\winmm\SDL_winmm.h" />
     <ClInclude Include="..\..\src\core\windows\SDL_directx.h" />
+    <ClInclude Include="..\..\src\core\windows\SDL_hid.h" />
     <ClInclude Include="..\..\src\core\windows\SDL_windows.h" />
     <ClInclude Include="..\..\src\core\windows\SDL_xinput.h" />
     <ClInclude Include="..\..\src\dynapi\SDL_dynapi.h" />
@@ -405,6 +406,7 @@
     <ClCompile Include="..\..\src\audio\winmm\SDL_winmm.c" />
     <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
     <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi_win32.c" />
+    <ClCompile Include="..\..\src\core\windows\SDL_hid.c" />
     <ClCompile Include="..\..\src\core\windows\SDL_windows.c" />
     <ClCompile Include="..\..\src\core\windows\SDL_xinput.c" />
     <ClCompile Include="..\..\src\cpuinfo\SDL_cpuinfo.c" />
@@ -426,7 +428,7 @@
     <ClCompile Include="..\..\src\haptic\windows\SDL_dinputhaptic.c" />
     <ClCompile Include="..\..\src\haptic\windows\SDL_windowshaptic.c" />
     <ClCompile Include="..\..\src\haptic\windows\SDL_xinputhaptic.c" />
-    <ClCompile Include="..\..\src\hidapi\windows\hid.c" />
+    <ClCompile Include="..\..\src\hidapi\SDL_hidapi.c" />
     <ClCompile Include="..\..\src\joystick\dummy\SDL_sysjoystick.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapijoystick.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_gamecube.c" />
diff --git a/VisualC/SDL/SDL.vcxproj.filters b/VisualC/SDL/SDL.vcxproj.filters
index af4c6b28a..f14a8b556 100644
--- a/VisualC/SDL/SDL.vcxproj.filters
+++ b/VisualC/SDL/SDL.vcxproj.filters
@@ -231,6 +231,7 @@
     <ClInclude Include="..\..\include\SDL_vulkan.h">
       <Filter>API Headers</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\SDL_misc.h" />
     <ClInclude Include="..\..\src\audio\directsound\SDL_directsound.h" />
     <ClInclude Include="..\..\src\audio\disk\SDL_diskaudio.h" />
     <ClInclude Include="..\..\src\audio\dummy\SDL_dummyaudio.h" />
@@ -262,12 +263,15 @@
     <ClInclude Include="..\..\src\haptic\windows\SDL_dinputhaptic_c.h" />
     <ClInclude Include="..\..\src\haptic\windows\SDL_windowshaptic_c.h" />
     <ClInclude Include="..\..\src\haptic\windows\SDL_xinputhaptic_c.h" />
+    <ClInclude Include="..\..\src\hidapi\hidapi\hidapi.h" />
     <ClInclude Include="..\..\src\joystick\controller_type.h" />
     <ClInclude Include="..\..\src\joystick\hidapi\SDL_hidapijoystick_c.h" />
+    <ClInclude Include="..\..\src\joystick\SDL_gamecontrollerdb.h" />
     <ClInclude Include="..\..\src\joystick\SDL_joystick_c.h" />
     <ClInclude Include="..\..\src\joystick\SDL_sysjoystick.h" />
     <ClInclude Include="..\..\src\joystick\virtual\SDL_virtualjoystick_c.h" />
     <ClInclude Include="..\..\src\joystick\windows\SDL_dinputjoystick_c.h" />
+    <ClInclude Include="..\..\src\joystick\windows\SDL_rawinputjoystick_c.h" />
     <ClInclude Include="..\..\src\joystick\windows\SDL_windowsjoystick_c.h" />
     <ClInclude Include="..\..\src\joystick\windows\SDL_xinputjoystick_c.h" />
     <ClInclude Include="..\..\src\libm\math_libm.h" />
@@ -294,6 +298,7 @@
     <ClInclude Include="..\..\src\sensor\dummy\SDL_dummysensor.h" />
     <ClInclude Include="..\..\src\sensor\SDL_sensor_c.h" />
     <ClInclude Include="..\..\src\sensor\SDL_syssensor.h" />
+    <ClInclude Include="..\..\src\sensor\windows\SDL_windowssensor.h" />
     <ClInclude Include="..\..\src\thread\SDL_systhread.h" />
     <ClInclude Include="..\..\src\thread\SDL_thread_c.h" />
     <ClInclude Include="..\..\src\thread\windows\SDL_systhread_c.h" />
@@ -327,10 +332,7 @@
     <ClInclude Include="..\..\src\video\windows\SDL_windowswindow.h" />
     <ClInclude Include="..\..\src\video\windows\wmmsg.h" />
     <ClInclude Include="..\..\src\video\yuv2rgb\yuv_rgb.h" />
-    <ClInclude Include="..\..\src\joystick\windows\SDL_rawinputjoystick_c.h" />
-    <ClInclude Include="..\..\src\hidapi\hidapi\hidapi.h" />
-    <ClInclude Include="..\..\src\joystick\SDL_gamecontrollerdb.h" />
-    <ClInclude Include="..\..\src\sensor\windows\SDL_windowssensor.h" />
+    <ClInclude Include="..\..\src\core\windows\SDL_hid.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\src\atomic\SDL_atomic.c" />
@@ -348,6 +350,7 @@
     <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
     <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi_win32.c" />
     <ClCompile Include="..\..\src\audio\winmm\SDL_winmm.c" />
+    <ClCompile Include="..\..\src\core\windows\SDL_hid.c" />
     <ClCompile Include="..\..\src\core\windows\SDL_windows.c" />
     <ClCompile Include="..\..\src\core\windows\SDL_xinput.c" />
     <ClCompile Include="..\..\src\cpuinfo\SDL_cpuinfo.c" />
@@ -364,13 +367,16 @@
     <ClCompile Include="..\..\src\events\SDL_windowevents.c" />
     <ClCompile Include="..\..\src\file\SDL_rwops.c" />
     <ClCompile Include="..\..\src\filesystem\windows\SDL_sysfilesystem.c" />
+    <ClCompile Include="..\..\src\haptic\dummy\SDL_syshaptic.c" />
     <ClCompile Include="..\..\src\haptic\SDL_haptic.c" />
     <ClCompile Include="..\..\src\haptic\windows\SDL_dinputhaptic.c" />
     <ClCompile Include="..\..\src\haptic\windows\SDL_windowshaptic.c" />
     <ClCompile Include="..\..\src\haptic\windows\SDL_xinputhaptic.c" />
-    <ClCompile Include="..\..\src\hidapi\windows\hid.c" />
+    <ClCompile Include="..\..\src\hidapi\SDL_hidapi.c" />
+    <ClCompile Include="..\..\src\joystick\dummy\SDL_sysjoystick.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_gamecube.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_ps4.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_ps5.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_rumble.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
@@ -382,6 +388,8 @@
     <ClCompile Include="..\..\src\joystick\virtual\SDL_virtualjoystick.c" />
     <ClCompile Include="..\..\src\joystick\windows\SDL_dinputjoystick.c" />
     <ClCompile Include="..\..\src\joystick\windows\SDL_mmjoystick.c" />
+    <ClCompile Include="..\..\src\joystick\windows\SDL_rawinputjoystick.c" />
+    <ClCompile Include="..\..\src\joystick\windows\SDL_windows_gaming_input.c" />
     <ClCompile Include="..\..\src\joystick\windows\SDL_windowsjoystick.c" />
     <ClCompile Include="..\..\src\joystick\windows\SDL_xinputjoystick.c" />
     <ClCompile Include="..\..\src\libm\e_atan2.c" />
@@ -407,6 +415,8 @@
     <ClCompile Include="..\..\src\loadso\windows\SDL_sysloadso.c" />
     <ClCompile Include="..\..\src\locale\SDL_locale.c" />
     <ClCompile Include="..\..\src\locale\windows\SDL_syslocale.c" />
+    <ClCompile Include="..\..\src\misc\SDL_url.c" />
+    <ClCompile Include="..\..\src\misc\windows\SDL_sysurl.c" />
     <ClCompile Include="..\..\src\power\SDL_power.c" />
     <ClCompile Include="..\..\src\power\windows\SDL_syspower.c" />
     <ClCompile Include="..\..\src\render\direct3d\SDL_render_d3d.c" />
@@ -435,6 +445,8 @@
     <ClCompile Include="..\..\src\SDL_log.c" />
     <ClCompile Include="..\..\src\sensor\dummy\SDL_dummysensor.c" />
     <ClCompile Include="..\..\src\sensor\SDL_sensor.c" />
+    <ClCompile Include="..\..\src\sensor\windows\SDL_windowssensor.c" />
+    <ClCompile Include="..\..\src\stdlib\SDL_crc32.c" />
     <ClCompile Include="..\..\src\stdlib\SDL_getenv.c" />
     <ClCompile Include="..\..\src\stdlib\SDL_iconv.c" />
     <ClCompile Include="..\..\src\stdlib\SDL_malloc.c" />
@@ -488,11 +500,6 @@
     <ClCompile Include="..\..\src\video\windows\SDL_windowsvulkan.c" />
     <ClCompile Include="..\..\src\video\windows\SDL_windowswindow.c" />
     <ClCompile Include="..\..\src\video\yuv2rgb\yuv_rgb.c" />
-    <ClCompile Include="..\..\src\joystick\windows\SDL_rawinputjoystick.c" />
-    <ClCompile Include="..\..\src\sensor\windows\SDL_windowssensor.c" />
-    <ClCompile Include="..\..\src\haptic\dummy\SDL_syshaptic.c" />
-    <ClCompile Include="..\..\src\joystick\dummy\SDL_sysjoystick.c" />
-    <ClCompile Include="..\..\src\joystick\windows\SDL_windows_gaming_input.c" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\..\src\main\windows\version.rc" />
diff --git a/src/core/windows/SDL_hid.c b/src/core/windows/SDL_hid.c
new file mode 100644
index 000000000..155d87a21
--- /dev/null
+++ b/src/core/windows/SDL_hid.c
@@ -0,0 +1,95 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef __WINRT__
+
+#include "SDL_assert.h"
+#include "SDL_hid.h"
+
+
+HidD_GetString_t SDL_HidD_GetManufacturerString;
+HidD_GetString_t SDL_HidD_GetProductString;
+HidD_GetPreparsedData_t SDL_HidD_GetPreparsedData;
+HidD_FreePreparsedData_t SDL_HidD_FreePreparsedData;
+HidP_GetCaps_t SDL_HidP_GetCaps;
+HidP_GetButtonCaps_t SDL_HidP_GetButtonCaps;
+HidP_GetValueCaps_t SDL_HidP_GetValueCaps;
+HidP_MaxDataListLength_t SDL_HidP_MaxDataListLength;
+HidP_GetData_t SDL_HidP_GetData;
+
+static HMODULE s_pHIDDLL = 0;
+static int s_HIDDLLRefCount = 0;
+
+
+int
+WIN_LoadHIDDLL(void)
+{
+    if (s_pHIDDLL) {
+        SDL_assert(s_HIDDLLRefCount > 0);
+        s_HIDDLLRefCount++;
+        return 0;  /* already loaded */
+    }
+
+    s_pHIDDLL = LoadLibrary(L"hid.dll");
+    if (!s_pHIDDLL) {
+        return -1;
+    }
+
+    SDL_assert(s_HIDDLLRefCount == 0);
+    s_HIDDLLRefCount = 1;
+
+    SDL_HidD_GetManufacturerString = (HidD_GetString_t)GetProcAddress(s_pHIDDLL, "HidD_GetManufacturerString");
+    SDL_HidD_GetProductString = (HidD_GetString_t)GetProcAddress(s_pHIDDLL, "HidD_GetProductString");
+    SDL_HidD_GetPreparsedData = (HidD_GetPreparsedData_t)GetProcAddress(s_pHIDDLL, "HidD_GetPreparsedData");
+    SDL_HidD_FreePreparsedData = (HidD_FreePreparsedData_t)GetProcAddress(s_pHIDDLL, "HidD_FreePreparsedData");
+    SDL_HidP_GetCaps = (HidP_GetCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetCaps");
+    SDL_HidP_GetButtonCaps = (HidP_GetButtonCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetButtonCaps");
+    SDL_HidP_GetValueCaps = (HidP_GetValueCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetValueCaps");
+    SDL_HidP_MaxDataListLength = (HidP_MaxDataListLength_t)GetProcAddress(s_pHIDDLL, "HidP_MaxDataListLength");
+    SDL_HidP_GetData = (HidP_GetData_t)GetProcAddress(s_pHIDDLL, "HidP_GetData");
+    if (!SDL_HidD_GetManufacturerString || !SDL_HidD_GetProductString || !SDL_HidD_GetPreparsedData ||
+        !SDL_HidD_FreePreparsedData || !SDL_HidP_GetCaps || !SDL_HidP_GetButtonCaps ||
+        !SDL_HidP_GetValueCaps || !SDL_HidP_MaxDataListLength || !SDL_HidP_GetData) {
+        WIN_UnloadHIDDLL();
+        return -1;
+    }
+
+    return 0;
+}
+
+void
+WIN_UnloadHIDDLL(void)
+{
+    if (s_pHIDDLL) {
+        SDL_assert(s_HIDDLLRefCount > 0);
+        if (--s_HIDDLLRefCount == 0) {
+            FreeLibrary(s_pHIDDLL);
+            s_pHIDDLL = NULL;
+        }
+    } else {
+        SDL_assert(s_HIDDLLRefCount == 0);
+    }
+}
+
+#endif /* !__WINRT__ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/core/windows/SDL_hid.h b/src/core/windows/SDL_hid.h
new file mode 100644
index 000000000..fb4c80ea4
--- /dev/null
+++ b/src/core/windows/SDL_hid.h
@@ -0,0 +1,208 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_hid_h_
+#define SDL_hid_h_
+
+#include "SDL_windows.h"
+
+#ifndef __WINRT__
+
+typedef LONG NTSTATUS;
+typedef USHORT USAGE;
+typedef struct _HIDP_PREPARSED_DATA *PHIDP_PREPARSED_DATA;
+
+typedef struct _HIDD_ATTRIBUTES
+{
+    ULONG Size;
+    USHORT VendorID;
+    USHORT ProductID;
+    USHORT VersionNumber;
+} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
+
+typedef enum {
+    HidP_Input = 0,
+    HidP_Output = 1,
+    HidP_Feature = 2
+} HIDP_REPORT_TYPE;
+
+typedef struct {
+    USAGE   UsagePage;
+    UCHAR   ReportID;
+    BOOLEAN IsAlias;
+    USHORT  BitField;
+    USHORT  LinkCollection;
+    USAGE   LinkUsage;
+    USAGE   LinkUsagePage;
+    BOOLEAN IsRange;
+    BOOLEAN IsStringRange;
+    BOOLEAN IsDesignatorRange;
+    BOOLEAN IsAbsolute;
+    ULONG   Reserved[ 10 ];
+    union {
+        struct {
+            USAGE   UsageMin;
+            USAGE   UsageMax;
+            USHORT  StringMin;
+            USHORT  StringMax;
+            USHORT  DesignatorMin;
+            USHORT  DesignatorMax;
+            USHORT  DataIndexMin;
+            USHORT  DataIndexMax;
+        } Range;
+        struct {
+            USAGE   Usage;
+            USAGE   Reserved1;
+            USHORT  StringIndex;
+            USHORT  Reserved2;
+            USHORT  DesignatorIndex;
+            USHORT  Reserved3;
+            USHORT  DataIndex;
+            USHORT  Reserved4;
+        } NotRange;
+    };
+} HIDP_BUTTON_CAPS, *PHIDP_BUTTON_CAPS;
+
+typedef struct {
+    USAGE   UsagePage;
+    UCHAR   ReportID;
+    BOOLEAN IsAlias;
+    USHORT  BitField;
+    USHORT  LinkCollection;
+    USAGE   LinkUsage;
+    USAGE   LinkUsagePage;
+    BOOLEAN IsRange;
+    BOOLEAN IsStringRange;
+    BOOLEAN IsDesignatorRange;
+    BOOLEAN IsAbsolute;
+    BOOLEAN HasNull;
+    UCHAR   Reserved;
+    USHORT  BitSize;
+    USHORT  ReportCount;
+    USHORT  Reserved2[ 5 ];
+    ULONG   UnitsExp;
+    ULONG   Units;
+    LONG    LogicalMin;
+    LONG    LogicalMax;
+    LONG    PhysicalMin;
+    LONG    PhysicalMax;
+    union {
+        struct {
+            USAGE   UsageMin;
+            USAGE   UsageMax;
+            USHORT  StringMin;
+            USHORT  StringMax;
+            USHORT  DesignatorMin;
+            USHORT  DesignatorMax;
+            USHORT  DataIndexMin;
+            USHORT  DataIndexMax;
+        } Range;
+        struct {
+            USAGE   Usage;
+            USAGE   Reserved1;
+            USHORT  StringIndex;
+            USHORT  Reserved2;
+            USHORT  DesignatorIndex;
+            USHORT  Reserved3;
+            USHORT  DataIndex;
+            USHORT  Reserved4;
+        } NotRange;
+    };
+} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS;
+
+typedef struct {
+    USAGE   Usage;
+    USAGE   UsagePage;
+    USHORT  InputReportByteLength;
+    USHORT  OutputReportByteLength;
+    USHORT  FeatureReportByteLength;
+    USHORT  Reserved[ 17 ];
+    USHORT  NumberLinkCollectionNodes;
+    USHORT  NumberInputButtonCaps;
+    USHORT  NumberInputValueCaps;
+    USHORT  NumberInputDataIndices;
+    USHORT  NumberOutputButtonCaps;
+    USHORT  NumberOutputValueCaps;
+    USHORT  NumberOutputDataIndices;
+    USHORT  NumberFeatureButtonCaps;
+    USHORT  NumberFeatureValueCaps;
+    USHORT  NumberFeatureDataIndices;
+} HIDP_CAPS, *PHIDP_CAPS;
+
+typedef struct {
+    USHORT  DataIndex;
+    USHORT  Reserved;
+    union {
+        ULONG   RawValue;
+        BOOLEAN On;
+    };
+} HIDP_DATA, *PHIDP_DATA;
+
+#define HIDP_ERROR_CODES( p1, p2 ) ((NTSTATUS)(((p1) << 28) | (0x11 << 16) | (p2)))
+#define HIDP_STATUS_SUCCESS                 HIDP_ERROR_CODES( 0x0, 0x0000 )
+#define HIDP_STATUS_NULL                    HIDP_ERROR_CODES( 0x8, 0x0001 )
+#define HIDP_STATUS_INVALID_PREPARSED_DATA  HIDP_ERROR_CODES( 0xC, 0x0001 )
+#define HIDP_STATUS_INVALID_REPORT_TYPE     HIDP_ERROR_CODES( 0xC, 0x0002 )
+#define HIDP_STATUS_INVALID_REPORT_LENGTH   HIDP_ERROR_CODES( 0xC, 0x0003 )
+#define HIDP_STATUS_USAGE_NOT_FOUND         HIDP_ERROR_CODES( 0xC, 0x0004 )
+#define HIDP_STATUS_VALUE_OUT_OF_RANGE      HIDP_ERROR_CODES( 0xC, 0x0005 )
+#define HIDP_STATUS_BAD_LOG_PHY_VALUES      HIDP_ERROR_CODES( 0xC, 0x0006 )
+#define HIDP_STATUS_BUFFER_TOO_SMALL        HIDP_ERROR_CODES( 0xC, 0x0007 )
+#define HIDP_STATUS_INTERNAL_ERROR          HIDP_ERROR_CODES( 0xC, 0x0008 )
+#define HIDP_STATUS_I8042_TRANS_UNKNOWN     HIDP_ERROR_CODES( 0xC, 0x0009 )
+#define HIDP_STATUS_INCOMPATIBLE_REPORT_ID  HIDP_ERROR_CODES( 0xC, 0x000A )
+#define HIDP_STATUS_NOT_VALUE_ARRAY         HIDP_ERROR_CODES( 0xC, 0x000B )
+#define HIDP_STATUS_IS_VALUE_ARRAY          HIDP_ERROR_CODES( 0xC, 0x000C )
+#define HIDP_STATUS_DATA_INDEX_NOT_FOUND    HIDP_ERROR_CODES( 0xC, 0x000D )
+#define HIDP_STATUS_DATA_INDEX_OUT_OF_RANGE HIDP_ERROR_CODES( 0xC, 0x000E )
+#define HIDP_STATUS_BUTTON_NOT_PRESSED      HIDP_ERROR_CODES( 0xC, 0x000F )
+#define HIDP_STATUS_REPORT_DOES_NOT_EXIST   HIDP_ERROR_CODES( 0xC, 0x0010 )
+#define HIDP_STATUS_NOT_IMPLEMENTED         HIDP_ERROR_CODES( 0xC, 0x0020 )
+
+
+extern int WIN_LoadHIDDLL(void);
+extern void WIN_UnloadHIDDLL(void);
+
+typedef BOOLEAN (WINAPI *HidD_GetString_t)(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength);
+typedef BOOLEAN (WINAPI *HidD_GetPreparsedData_t)(HANDLE HidDeviceObject, PHIDP_PREPARSED_DATA *PreparsedData);
+typedef BOOLEAN (WINAPI *HidD_FreePreparsedData_t)(PHIDP_PREPARSED_DATA PreparsedData);
+typedef NTSTATUS (WINAPI *HidP_GetCaps_t)(PHIDP_PREPARSED_DATA PreparsedData, PHIDP_CAPS Capabilities);
+typedef NTSTATUS (WINAPI *HidP_GetButtonCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps, PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData);
+typedef NTSTATUS (WINAPI *HidP_GetValueCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps, PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData);
+typedef ULONG (WINAPI *HidP_MaxDataListLength_t)(HIDP_REPORT_TYPE ReportType, PHIDP_PREPARSED_DATA PreparsedData);
+typedef NTSTATUS (WINAPI *HidP_GetData_t)(HIDP_REPORT_TYPE ReportType, PHIDP_DATA DataList, PULONG DataLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength);
+
+extern HidD_GetString_t SDL_HidD_GetManufacturerString;
+extern HidD_GetString_t SDL_HidD_GetProductString;
+extern HidD_GetPreparsedData_t SDL_HidD_GetPreparsedData;
+extern HidD_FreePreparsedData_t SDL_HidD_FreePreparsedData;
+extern HidP_GetCaps_t SDL_HidP_GetCaps;
+extern HidP_GetButtonCaps_t SDL_HidP_GetButtonCaps;
+extern HidP_GetValueCaps_t SDL_HidP_GetValueCaps;
+extern HidP_MaxDataListLength_t SDL_HidP_MaxDataListLength;
+extern HidP_GetData_t SDL_HidP_GetData;
+
+#endif /* !__WINRT__ */
+
+#endif /* SDL_hid_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/hidapi/SDL_hidapi.c b/src/hidapi/SDL_hidapi.c
index 6372ffa4d..aa44e6930 100644
--- a/src/hidapi/SDL_hidapi.c
+++ b/src/hidapi/SDL_hidapi.c
@@ -129,6 +129,67 @@ static const SDL_UDEV_Symbols *udev_ctx = NULL;
 #undef make_path
 #undef read_thread
 
+#ifdef HAVE_HIDAPI_NVAGIPMAN
+#define HAVE_DRIVER_BACKEND
+#endif
+
+#ifdef HAVE_DRIVER_BACKEND
+
+/* DRIVER HIDAPI Implementation */
+
+#define hid_device_                     DRIVER_hid_device_
+#define hid_device                      DRIVER_hid_device
+#define hid_device_info                 DRIVER_hid_device_info
+#define hid_init                        DRIVER_hid_init
+#define hid_exit                        DRIVER_hid_exit
+#define hid_enumerate                   DRIVER_hid_enumerate
+#define hid_free_enumeration            DRIVER_hid_free_enumeration
+#define hid_open                        DRIVER_hid_open
+#define hid_open_path                   DRIVER_hid_open_path
+#define hid_write                       DRIVER_hid_write
+#define hid_read_timeout                DRIVER_hid_read_timeout
+#define hid_read                        DRIVER_hid_read
+#define hid_set_nonblocking             DRIVER_hid_set_nonblocking
+#define hid_send_feature_report         DRIVER_hid_send_feature_report
+#define hid_get_feature_report          DRIVER_hid_get_feature_report
+#define hid_close                       DRIVER_hid_close
+#define hid_get_manufacturer_string     DRIVER_hid_get_manufacturer_string
+#define hid_get_product_string          DRIVER_hid_get_product_string
+#define hid_get_serial_number_string    DRIVER_hid_get_serial_number_string
+#define hid_get_indexed_string          DRIVER_hid_get_indexed_string
+#define hid_error                       DRIVER_hid_error
+
+#ifdef HAVE_HIDAPI_NVAGIPMAN
+#include "nvagipman/hid.c"
+#else
+#error Need a driver hid.c for this platform!
+#endif
+
+#undef hid_device_
+#undef hid_device
+#undef hid_device_info
+#undef hid_init
+#undef hid_exit
+#undef hid_enumerate
+#undef hid_free_enumeration
+#undef hid_open
+#undef hid_open_path
+#undef hid_write
+#undef hid_read_timeout
+#undef hid_read
+#undef hid_set_nonblocking
+#undef hid_send_feature_report
+#undef hid_get_feature_report
+#undef hid_close
+#undef hid_get_manufacturer_string
+#undef hid_get_product_string
+#undef hid_get_serial_number_string
+#undef hid_get_indexed_string
+#undef hid_error
+
+#endif /* HAVE_DRIVER_BACKEND */
+
+
 #ifdef SDL_LIBUSB_DYNAMIC
 /* libusb HIDAPI Implementation */
 
@@ -298,23 +359,21 @@ SDL_libusb_get_string_descriptor(libusb_device_handle *dev,
 /* Shared HIDAPI Implementation */
 
 #undef HIDAPI_H__
-#include "hidapi.h"
+#include "hidapi/hidapi.h"
 
 struct hidapi_backend {
-#define F(x) typeof(x) *x
-    F(hid_write);
-    F(hid_read_timeout);
-    F(hid_read);
-    F(hid_set_nonblocking);
-    F(hid_send_feature_report);
-    F(hid_get_feature_report);
-    F(hid_close);
-    F(hid_get_manufacturer_string);
-    F(hid_get_product_string);
-    F(hid_get_serial_number_string);
-    F(hid_get_indexed_string);
-    F(hid_error);
-#undef F
+    int  (*hid_write)(hid_device* device, const unsigned char* data, size_t length);
+    int  (*hid_read_timeout)(hid_device* device, unsigned char* data, size_t length, int milliseconds);
+    int  (*hid_read)(hid_device* device, unsigned char* data, size_t length);
+    int  (*hid_set_nonblocking)(hid_device* device, int nonblock);
+    int  (*hid_send_feature_report)(hid_device* device, const unsigned char* data, size_t length);
+    int  (*hid_get_feature_report)(hid_device* device, unsigned char* data, size_t length);
+    void (*hid_close)(hid_device* device);
+    int  (*hid_get_manufacturer_string)(hid_device* device, wchar_t* string, size_t maxlen);
+    int  (*hid_get_product_string)(hid_device* device, wchar_t* string, size_t maxlen);
+    int  (*hid_get_serial_number_string)(hid_device* device, wchar_t* string, size_t maxlen);
+    int  (*hid_get_indexed_string)(hid_device* device, int string_index, wchar_t* string, size_t maxlen);
+    const wchar_t* (*hid_error)(hid_device* device);
 };
 
 #if HAVE_PLATFORM_BACKEND
@@ -334,6 +393,23 @@ static const struct hidapi_backend PLATFORM_Backend = {
 };
 #endif /* HAVE_PLATFORM_BACKEND */
 
+#if HAVE_DRIVER_BACKEND
+static const struct hidapi_backend DRIVER_Backend = {
+    (void*)DRIVER_hid_write,
+    (void*)DRIVER_hid_read_timeout,
+    (void*)DRIVER_hid_read,
+    (void*)DRIVER_hid_set_nonblocking,
+    (void*)DRIVER_hid_send_feature_report,
+    (void*)DRIVER_hid_get_feature_report,
+    (void*)DRIVER_hid_close,
+    (void*)DRIVER_hid_get_manufacturer_string,
+    (void*)DRIVER_hid_get_product_string,
+    (void*)DRIVER_hid_get_serial_number_string,
+    (void*)DRIVER_hid_get_indexed_string,
+    (void*)DRIVER_hid_error
+};
+#endif /* HAVE_DRIVER_BACKEND */
+
 #ifdef SDL_LIBUSB_DYNAMIC
 static const struct hidapi_backend LIBUSB_Backend = {
     (void*)LIBUSB_hid_write,
@@ -361,7 +437,7 @@ struct _HIDDeviceWrapper
 static HIDDeviceWrapper *
 CreateHIDDeviceWrapper(hid_device *device, const struct hidapi_backend *backend)
 {
-    HIDDeviceWrapper *ret = SDL_malloc(sizeof(*ret));
+    HIDDeviceWrapper *ret = (HIDDeviceWrapper *)SDL_malloc(sizeof(*ret));
     ret->device = device;
     ret->backend = backend;
     return ret;
@@ -540,6 +616,10 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
     struct LIBUSB_hid_device_info *usb_devs = NULL;
     struct LIBUSB_hid_device_info *usb_dev;
 #endif
+#if HAVE_DRIVER_BACKEND
+    struct DRIVER_hid_device_info* driver_devs = NULL;
+    struct DRIVER_hid_device_info* driver_dev;
+#endif
 #if HAVE_PLATFORM_BACKEND
     struct PLATFORM_hid_device_info *raw_devs = NULL;
     struct PLATFORM_hid_device_info *raw_dev;
@@ -636,6 +716,15 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsi
         return WrapHIDDevice(wrapper);
     }
 #endif /* HAVE_PLATFORM_BACKEND */
+
+#if HAVE_DRIVER_BACKEND
+    if ((pDevice = (hid_device*) DRIVER_hid_open(vendor_id, product_id, serial_number)) != NULL) {
+
+        HIDDeviceWrapper *wrapper = CreateHIDDeviceWrapper(pDevice, &DRIVER_Backend);
+        return WrapHIDDevice(wrapper);
+    }
+#endif /* HAVE_DRIVER_BACKEND */
+
 #ifdef SDL_LIBUSB_DYNAMIC
     if (libusb_ctx.libhandle &&
         (pDevice = (hid_device*) LIBUSB_hid_open(vendor_id, product_id, serial_number)) != NULL) {
@@ -644,6 +733,7 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsi
         return WrapHIDDevice(wrapper);
     }
 #endif /* SDL_LIBUSB_DYNAMIC */
+
     return NULL;
 }
 
@@ -663,6 +753,16 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path, int bEx
         return WrapHIDDevice(wrapper);
     }
 #endif /* HAVE_PLATFORM_BACKEND */
+
+#if HAVE_DRIVER_BACKEND
+    if (udev_ctx &&
+        (pDevice = (hid_device*) DRIVER_hid_open_path(path, bExclusive)) != NULL) {
+
+        HIDDeviceWrapper *wrapper = CreateHIDDeviceWrapper(pDevice, &DRIVER_Backend);
+        return WrapHIDDevice(wrapper);
+    }
+#endif /* HAVE_DRIVER_BACKEND */
+
 #ifdef SDL_LIBUSB_DYNAMIC
     if (libusb_ctx.libhandle &&
         (pDevice = (hid_device*) LIBUSB_hid_open_path(path, bExclusive)) != NULL) {
@@ -671,6 +771,7 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path, int bEx
         return WrapHIDDevice(wrapper);
     }
 #endif /* SDL_LIBUSB_DYNAMIC */
+
     return NULL;
 }
 
diff --git a/src/hidapi/windows/hid.c b/src/hidapi/windows/hid.c
index 358cc1000..7802924d6 100644
--- a/src/hidapi/windows/hid.c
+++ b/src/hidapi/windows/hid.c
@@ -409,6 +409,11 @@ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor
 			goto cont;
 		}
 
+		/* XInput devices don't get real HID reports and are better handled by the raw input driver */
+		if (strstr(device_interface_detail_data->DevicePath, "&ig_") != NULL) {
+			goto cont;
+		}
+
 		/* Make sure this device is of Setup Class "HIDClass" and has a
 		   driver bound to it. */
 		/* In the main HIDAPI tree this is a loop which will erroneously open 
diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c
index fa9c7c62d..1162a371a 100644
--- a/src/joystick/SDL_gamecontroller.c
+++ b/src/joystick/SDL_gamecontroller.c
@@ -616,7 +616,7 @@ static ControllerMapping_t *SDL_CreateMappingForRAWINPUTController(SDL_JoystickG
     char mapping_string[1024];
 
     SDL_strlcpy(mapping_string, "none,*,", sizeof(mapping_string));
-    SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,", sizeof(mapping_string));
+    SDL_strlcat(mapping_string, "a:b0,b:b1,x:b2,y:b3,back:b6,guide:b10,start:b7,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a1,lefty:a0,rightx:a3,righty:a2,lefttrigger:a4,righttrigger:a5,", sizeof(mapping_string));
 
     return SDL_PrivateAddMappingForGUID(guid, mapping_string,
                       &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index 8516dd903..c9560f5a4 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -51,13 +51,12 @@
 #endif
 
 static SDL_JoystickDriver *SDL_joystick_drivers[] = {
-#ifdef SDL_JOYSTICK_RAWINPUT /* Before WINDOWS_ driver, as WINDOWS wants to check if this driver is handling things */
-    /* Also before HIDAPI, as HIDAPI wants to check if this driver is handling things */
-    &SDL_RAWINPUT_JoystickDriver,
-#endif
 #ifdef SDL_JOYSTICK_HIDAPI /* Before WINDOWS_ driver, as WINDOWS wants to check if this driver is handling things */
     &SDL_HIDAPI_JoystickDriver,
 #endif
+#ifdef SDL_JOYSTICK_RAWINPUT /* Before WINDOWS_ driver, as WINDOWS wants to check if this driver is handling things */
+    &SDL_RAWINPUT_JoystickDriver,
+#endif
 #if defined(SDL_JOYSTICK_WGI)
     &SDL_WGI_JoystickDriver,
 #endif
diff --git a/src/joystick/hidapi/SDL_hidapi_gamecube.c b/src/joystick/hidapi/SDL_hidapi_gamecube.c
index d85516ba3..ab36742bb 100644
--- a/src/joystick/hidapi/SDL_hidapi_gamecube.c
+++ b/src/joystick/hidapi/SDL_hidapi_gamecube.c
@@ -175,11 +175,11 @@ HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
             if (curSlot[0] & 0x30) { /* 0x10 - Wired, 0x20 - Wireless */
                 if (ctx->joysticks[i] == -1) {
                     ResetAxisRange(ctx, i);
-                    HIDAPI_JoystickConnected(device, &ctx->joysticks[i], SDL_FALSE);
+                    HIDAPI_JoystickConnected(device, &ctx->joysticks[i]);
                 }
             } else {
                 if (ctx->joysticks[i] != -1) {
-                    HIDAPI_JoystickDisconnected(device, ctx->joysticks[i], SDL_FALSE);
+                    HIDAPI_JoystickDisconnected(device, ctx->joysticks[i]);
                     ctx->joysticks[i] = -1;
                 }
                 continue;
@@ -251,7 +251,7 @@ HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
             if (curSlot[0] & 0x30) { /* 0x10 - Wired, 0x20 - Wireless */
                 if (ctx->joysticks[i] == -1) {
                     ResetAxisRange(ctx, i);
-                    HIDAPI_JoystickConnected(device, &ctx->joysticks[i], SDL_FALSE);
+                    HIDAPI_JoystickConnected(device, &ctx->joysticks[i]);
                 }
                 joystick = SDL_JoystickFromInstanceID(ctx->joysticks[i]);
 
@@ -261,7 +261,7 @@ HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
                 }
             } else {
                 if (ctx->joysticks[i] != -1) {
-                    HIDAPI_JoystickDisconnected(device, ctx->joysticks[i], SDL_FALSE);
+                    HIDAPI_JoystickDisconnected(device, ctx->joysticks[i]);
                     ctx->joysticks[i] = -1;
                 }
                 continue;
@@ -432,7 +432,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube =
     HIDAPI_DriverGameCube_SetJoystickSensorsEnabled,
     HIDAPI_DriverGameCube_CloseJoystick,
     HIDAPI_DriverGameCube_FreeDevice,
-    NULL,
 };
 
 #endif /* SDL_JOYSTICK_HIDAPI_GAMECUBE */
diff --git a/src/joystick/hidapi/SDL_hidapi_ps4.c b/src/joystick/hidapi/SDL_hidapi_ps4.c
index 1bb753d92..f3d351f97 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps4.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps4.c
@@ -143,7 +143,7 @@ typedef struct {
 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)
 {
-    return (type == SDL_CONTROLLER_TYPE_PS4);
+    return (type == SDL_CONTROLLER_TYPE_PS4) ? SDL_TRUE : SDL_FALSE;
 }
 
 static const char *
@@ -202,7 +202,7 @@ SetLedsForPlayerIndex(DS4EffectsState_t *effects, int player_index)
 static SDL_bool
 HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
 {
-    return HIDAPI_JoystickConnected(device, NULL, SDL_FALSE);
+    return HIDAPI_JoystickConnected(device, NULL);
 }
 
 static int
@@ -769,7 +769,7 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
 
     if (size < 0) {
         /* Read error, device is disconnected */
-        HIDAPI_JoystickDisconnected(device, joystick->instance_id, SDL_FALSE);
+        HIDAPI_JoystickDisconnected(device, joystick->instance_id);
     }
     return (size >= 0);
 }
@@ -807,7 +807,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4 =
     HIDAPI_DriverPS4_SetJoystickSensorsEnabled,
     HIDAPI_DriverPS4_CloseJoystick,
     HIDAPI_DriverPS4_FreeDevice,
-    NULL
 };
 
 #endif /* SDL_JOYSTICK_HIDAPI_PS4 */
diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c
index bbf6d9342..f312c4edf 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps5.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps5.c
@@ -171,7 +171,7 @@ typedef struct {
 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)
 {
-    return (type == SDL_CONTROLLER_TYPE_PS5);
+    return (type == SDL_CONTROLLER_TYPE_PS5) ? SDL_TRUE : SDL_FALSE;
 }
 
 static const char *
@@ -220,7 +220,7 @@ SetLedsForPlayerIndex(DS5EffectsState_t *effects, int player_index)
 static SDL_bool
 HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
 {
-    return HIDAPI_JoystickConnected(device, NULL, SDL_FALSE);
+    return HIDAPI_JoystickConnected(device, NULL);
 }
 
 static int
@@ -885,7 +885,7 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
 
     if (size < 0) {
         /* Read error, device is disconnected */
-        HIDAPI_JoystickDisconnected(device, joystick->instance_id, SDL_FALSE);
+        HIDAPI_JoystickDisconnected(device, joystick->instance_id);
     }
     return (size >= 0);
 }
@@ -923,7 +923,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS5 =
     HIDAPI_DriverPS5_SetJoystickSensorsEnabled,
     HIDAPI_DriverPS5_CloseJoystick,
     HIDAPI_DriverPS5_FreeDevice,
-    NULL
 };
 
 #endif /* SDL_JOYSTICK_HIDAPI_PS5 */
diff --git a/src/joystick/hidapi/SDL_hidapi_steam.c b/src/joystick/hidapi/SDL_hidapi_steam.c
index 0ae4d2243..87827f476 100644
--- a/src/joystick/hidapi/SDL_hidapi_steam.c
+++ b/src/joystick/hidapi/SDL_hidapi_steam.c
@@ -971,7 +971,7 @@ HIDAPI_DriverSteam_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
 static SDL_bool
 HIDAPI_DriverSteam_InitDevice(SDL_HIDAPI_Device *device)
 {
-    return HIDAPI_JoystickConnected(device, NULL, SDL_FALSE);
+    return HIDAPI_JoystickConnected(device, NULL);
 }
 
 static int
@@ -1160,7 +1160,7 @@ HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device *device)
 
         if (r <= 0) {
             /* Failed to read from controller */
-            HIDAPI_JoystickDisconnected(device, device->joysticks[0], SDL_FALSE);
+            HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
             return SDL_FALSE;
         }
     }
@@ -1201,7 +1201,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteam =
     HIDAPI_DriverSteam_SetSensorsEnabled,
     HIDAPI_DriverSteam_CloseJoystick,
     HIDAPI_DriverSteam_FreeDevice,
-    NULL
 };
 
 #endif /* SDL_JOYSTICK_HIDAPI_STEAM */
diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c
index 16e1e242f..aad03de0c 100644
--- a/src/joystick/hidapi/SDL_hidapi_switch.c
+++ b/src/joystick/hidapi/SDL_hidapi_switch.c
@@ -288,7 +288,7 @@ HIDAPI_DriverSwitch_IsSupportedDevice(const char *name, SDL_GameControllerType t
     if (SDL_strcmp( name, "HORI Wireless Switch Pad" ) == 0) {
         return SDL_FALSE;
     }
-    return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO);
+    return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) ? SDL_TRUE : SDL_FALSE;
 }
 
 static const char *
@@ -697,7 +697,7 @@ static Uint8 RemapButton(SDL_DriverSwitch_Context *ctx, Uint8 button)
 static SDL_bool
 HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *device)
 {
-    return HIDAPI_JoystickConnected(device, NULL, SDL_FALSE);
+    return HIDAPI_JoystickConnected(device, NULL);
 }
 
 static int
@@ -1259,7 +1259,7 @@ HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device)
 
     if (size < 0) {
         /* Read error, device is disconnected */
-        HIDAPI_JoystickDisconnected(device, joystick->instance_id, SDL_FALSE);
+        HIDAPI_JoystickDisconnected(device, joystick->instance_id);
     }
     return (size >= 0);
 }
@@ -1307,7 +1307,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch =
     HIDAPI_DriverSwitch_SetJoystickSensorsEnabled,
     HIDAPI_DriverSwitch_CloseJoystick,
     HIDAPI_DriverSwitch_FreeDevice,
-    NULL
 };
 
 #endif /* SDL_JOYSTICK_HIDAPI_SWITCH */
diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360.c b/src/joystick/hidapi/SDL_hidapi_xbox360.c
index dfc7c31a4..5da6cd498 100644
--- a/src/joystick/hidapi/SDL_hidapi_xbox360.c
+++ b/src/joystick/hidapi/SDL_hidapi_xbox360.c
@@ -34,546 +34,10 @@
 
 #ifdef SDL_JOYSTICK_HIDAPI_XBOX360
 
-#ifdef __WIN32__
-#define SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
-/* This requires the Windows 10 SDK to build */
-/*#define SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT*/
-#endif
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
-#include "../../core/windows/SDL_xinput.h"
-#endif
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
-#include "../../core/windows/SDL_windows.h"
-typedef struct WindowsGamingInputGamepadState WindowsGamingInputGamepadState;
-#define GamepadButtons_GUIDE 0x40000000
-#define COBJMACROS
-#include "windows.gaming.input.h"
-#endif
-
-#if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT)
-#define SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
-#endif
-
 typedef struct {
     Uint8 last_state[USB_PACKET_LENGTH];
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
-    Uint32 match_state; /* Low 16 bits for button states, high 16 for 4 4bit axes */
-    Uint32 last_state_packet;
-#endif
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
-    SDL_bool xinput_enabled;
-    SDL_bool xinput_correlated;
-    Uint8 xinput_correlation_id;
-    Uint8 xinput_correlation_count;
-    Uint8 xinput_uncorrelate_count;
-    Uint8 xinput_slot;
-#endif
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
-    SDL_bool wgi_correlated;
-    Uint8 wgi_correlation_id;
-    Uint8 wgi_correlation_count;
-    Uint8 wgi_uncorrelate_count;
-    WindowsGamingInputGamepadState *wgi_slot;
-#endif
 } SDL_DriverXbox360_Context;
 
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
-static struct {
-    Uint32 last_state_packet;
-    SDL_Joystick *joystick;
-    SDL_Joystick *last_joystick;
-} guide_button_candidate;
-
-typedef struct WindowsMatchState {
-    SHORT match_axes[4];
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
-    WORD xinput_buttons;
-#endif
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
-    Uint32 wgi_buttons;
-#endif
-    SDL_bool any_data;
-} WindowsMatchState;
-
-static void HIDAPI_DriverXbox360_FillMatchState(WindowsMatchState *state, Uint32 match_state)
-{
-    int ii;
-    state->any_data = SDL_FALSE;
-    /*  SHORT state->match_axes[4] = {
-            (match_state & 0x000F0000) >> 4,
-            (match_state & 0x00F00000) >> 8,
-            (match_state & 0x0F000000) >> 12,
-            (match_state & 0xF0000000) >> 16,
-        }; */
-    for (ii = 0; ii < 4; ii++) {
-        state->match_axes[ii] = (match_state & (0x000F0000 << (ii * 4))) >> (4 + ii * 4);
-        if ((Uint32)(state->match_axes[ii] + 0x1000) > 0x2000) { /* match_state bit is not 0xF, 0x1, or 0x2 */
-            state->any_data = SDL_TRUE;
-        }
-    }
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
-    /* Match axes by checking if the distance between the high 4 bits of axis and the 4 bits from match_state is 1 or less */
-#define XInputAxesMatch(gamepad) (\
-   (Uint32)(gamepad.sThumbLX - state->match_axes[0] + 0x1000) <= 0x2fff && \
-   (Uint32)(~gamepad.sThumbLY - state->match_axes[1] + 0x1000) <= 0x2fff && \
-   (Uint32)(gamepad.sThumbRX - state->match_axes[2] + 0x1000) <= 0x2fff && \
-   (Uint32)(~gamepad.sThumbRY - state->match_axes[3] + 0x1000) <= 0x2fff)
-    /* Explicit
-#define XInputAxesMatch(gamepad) (\
-    SDL_abs((Sint8)((gamepad.sThumbLX & 0xF000) >> 8) - ((match_state & 0x000F0000) >> 12)) <= 0x10 && \
-    SDL_abs((Sint8)((~gamepad.sThumbLY & 0xF000) >> 8) - ((match_state & 0x00F00000) >> 16)) <= 0x10 && \
-    SDL_abs((Sint8)((gamepad.sThumbRX & 0xF000) >> 8) - ((match_state & 0x0F000000) >> 20)) <= 0x10 && \
-    SDL_abs((Sint8)((~gamepad.sThumbRY & 0xF000) >> 8) - ((match_state & 0xF0000000) >> 24)) <= 0x10) */
-
-
-    state->xinput_buttons =
-        /* Bitwise map .RLDUWVQTS.KYXBA -> YXBA..WVQTKSRLDU */
-        match_state << 12 | (match_state & 0x0780) >> 1 | (match_state & 0x0010) << 1 | (match_state & 0x0040) >> 2 | (match_state & 0x7800) >> 11;
-    /*  Explicit
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_A)) ? XINPUT_GAMEPAD_A : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_B)) ? XINPUT_GAMEPAD_B : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_X)) ? XINPUT_GAMEPAD_X : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_Y)) ? XINPUT_GAMEPAD_Y : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_BACK)) ? XINPUT_GAMEPAD_BACK : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_START)) ? XINPUT_GAMEPAD_START : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_LEFTSTICK)) ? XINPUT_GAMEPAD_LEFT_THUMB : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_RIGHTSTICK)) ? XINPUT_GAMEPAD_RIGHT_THUMB: 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) ? XINPUT_GAMEPAD_LEFT_SHOULDER : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) ? XINPUT_GAMEPAD_RIGHT_SHOULDER : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_UP)) ? XINPUT_GAMEPAD_DPAD_UP : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_DOWN)) ? XINPUT_GAMEPAD_DPAD_DOWN : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_LEFT)) ? XINPUT_GAMEPAD_DPAD_LEFT : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) ? XINPUT_GAMEPAD_DPAD_RIGHT : 0);
-    */
-
-    if (state->xinput_buttons)
-        state->any_data = SDL_TRUE;
-#endif
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
-    /* Match axes by checking if the distance between the high 4 bits of axis and the 4 bits from match_state is 1 or less */
-#define WindowsGamingInputAxesMatch(gamepad) (\
-    (Uint16)(((Sint16)(gamepad.LeftThumbstickX * SDL_MAX_SINT16) & 0xF000) - state->match_axes[0] + 0x1000) <= 0x2fff && \
-    (Uint16)((~(Sint16)(gamepad.LeftThumbstickY * SDL_MAX_SINT16) & 0xF000) - state->match_axes[1] + 0x1000) <= 0x2fff && \
-    (Uint16)(((Sint16)(gamepad.RightThumbstickX * SDL_MAX_SINT16) & 0xF000) - state->match_axes[2] + 0x1000) <= 0x2fff && \
-    (Uint16)((~(Sint16)(gamepad.RightThumbstickY * SDL_MAX_SINT16) & 0xF000) - state->match_axes[3] + 0x1000) <= 0x2fff)
-
-
-    state->wgi_buttons =
-        /* Bitwise map .RLD UWVQ TS.K YXBA -> ..QT WVRL DUYX BAKS */
-        /*  RStick/LStick (QT)         RShould/LShould  (WV)                 DPad R/L/D/U                          YXBA                         bac(K)                      (S)tart */
-        (match_state & 0x0180) << 5 | (match_state & 0x0600) << 1 | (match_state & 0x7800) >> 5 | (match_state & 0x000F) << 2 | (match_state & 0x0010) >> 3 | (match_state & 0x0040) >> 6;
-    /*  Explicit
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_A)) ? GamepadButtons_A : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_B)) ? GamepadButtons_B : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_X)) ? GamepadButtons_X : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_Y)) ? GamepadButtons_Y : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_BACK)) ? GamepadButtons_View : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_START)) ? GamepadButtons_Menu : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_LEFTSTICK)) ? GamepadButtons_LeftThumbstick : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_RIGHTSTICK)) ? GamepadButtons_RightThumbstick: 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) ? GamepadButtons_LeftShoulder: 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) ? GamepadButtons_RightShoulder: 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_UP)) ? GamepadButtons_DPadUp : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_DOWN)) ? GamepadButtons_DPadDown : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_LEFT)) ? GamepadButtons_DPadLeft : 0) |
-        ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) ? GamepadButtons_DPadRight : 0); */
-
-    if (state->wgi_buttons)
-        state->any_data = SDL_TRUE;
-#endif
-
-}
-
-
-#endif
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
-static struct {
-    XINPUT_STATE_EX state;
-    SDL_bool connected; /* Currently has an active XInput device */
-    SDL_bool used; /* Is currently mapped to an SDL device */
-    Uint8 correlation_id;
-} xinput_state[XUSER_MAX_COUNT];
-static SDL_bool xinput_device_change = SDL_TRUE;
-static SDL_bool xinput_state_dirty = SDL_TRUE;
-
-static void
-HIDAPI_DriverXbox360_UpdateXInput()
-{
-    DWORD user_index;
-    if (xinput_device_change) {
-        for (user_index = 0; user_index < XUSER_MAX_COUNT; user_index++) {
-            XINPUT_CAPABILITIES capabilities;
-            xinput_state[user_index].connected = XINPUTGETCAPABILITIES(user_index, XINPUT_FLAG_GAMEPAD, &capabilities) == ERROR_SUCCESS;
-        }
-        xinput_device_change = SDL_FALSE;
-        xinput_state_dirty = SDL_TRUE;
-    }
-    if (xinput_state_dirty) {
-        xinput_state_dirty = SDL_FALSE;
-        for (user_index = 0; user_index < SDL_arraysize(xinput_state); ++user_index) {
-            if (xinput_state[user_index].connected) {
-                if (XINPUTGETSTATE(user_index, &xinput_state[user_index].state) != ERROR_SUCCESS) {
-                    xinput_state[user_index].connected = SDL_FALSE;
-                }
-            }
-        }
-    }
-}
-
-static void
-HIDAPI_DriverXbox360_MarkXInputSlotUsed(Uint8 xinput_slot)
-{
-    if (xinput_slot != XUSER_INDEX_ANY) {
-        xinput_state[xinput_slot].used = SDL_TRUE;
-    }
-}
-
-static void
-HIDAPI_DriverXbox360_MarkXInputSlotFree(Uint8 xinput_slot)
-{
-    if (xinput_slot != XUSER_INDEX_ANY) {
-        xinput_state[xinput_slot].used = SDL_FALSE;
-    }
-}
-static SDL_bool
-HIDAPI_DriverXbox360_MissingXInputSlot()
-{
-    int ii;
-    for (ii = 0; ii < SDL_arraysize(xinput_state); ii++) {
-        if (xinput_state[ii].connected && !xinput_state[ii].used) {
-            return SDL_TRUE;
-        }
-    }
-    return SDL_FALSE;
-}
-
-static SDL_bool
-HIDAPI_DriverXbox360_XInputSlotMatches(const WindowsMatchState *state, Uint8 slot_idx)
-{
-    if (xinput_state[slot_idx].connected) {
-        WORD xinput_buttons = xinput_state[slot_idx].state.Gamepad.wButtons;
-        if ((xinput_buttons & ~XINPUT_GAMEPAD_GUIDE) == state->xinput_buttons && XInputAxesMatch(xinput_state[slot_idx].state.Gamepad)) {
-            return SDL_TRUE;
-        }
-    }
-    return SDL_FALSE;
-}
-
-
-static SDL_bool
-HIDAPI_DriverXbox360_GuessXInputSlot(const WindowsMatchState *state, Uint8 *correlation_id, Uint8 *slot_idx)
-{
-    int user_index;
-    int match_count;
-
-    *slot_idx = 0;
-
-    match_count = 0;
-    for (user_index = 0; user_index < XUSER_MAX_COUNT; ++user_index) {
-        if (!xinput_state[user_index].used && HIDAPI_DriverXbox360_XInputSlotMatches(state, user_index)) {
-            ++match_count;
-            *slot_idx = (Uint8)user_index;
-            /* Incrementing correlation_id for any match, as negative evidence for others being correlated */
-            *correlation_id = ++xinput_state[user_index].correlation_id;
-        }
-    }
-    /* Only return a match if we match exactly one, and we have some non-zero data (buttons or axes) that matched.
-       Note that we're still invalidating *other* potential correlations if we have more than one match or we have no
-       data. */
-    if (match_count == 1 && state->any_data) {
-        return SDL_TRUE;
-    }
-    return SDL_FALSE;
-}
-
-#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
-
-typedef struct WindowsGamingInputGamepadState {
-    __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
-    struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading state;
-    SDL_DriverXbox360_Context *correlated_context;
-    SDL_bool used; /* Is currently mapped to an SDL device */
-    SDL_bool connected; /* Just used during update to track disconnected */
-    Uint8 correlation_id;
-    struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
-} WindowsGamingInputGamepadState;
-
-static struct {
-    WindowsGamingInputGamepadState **per_gamepad;
-    int per_gamepad_count;
-    SDL_bool initialized;
-    SDL_bool dirty;
-    SDL_bool need_device_list_update;
-    int ref_count;
-    __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics *gamepad_statics;
-} wgi_state;
-
-static void
-HIDAPI_DriverXbox360_MarkWindowsGamingInputSlotUsed(WindowsGamingInputGamepadState *wgi_slot, SDL_DriverXbox360_Context *ctx)
-{
-    wgi_slot->used = SDL_TRUE;
-    wgi_slot->correlated_context = ctx;
-}
-
-static void
-HIDAPI_DriverXbox360_MarkWindowsGamingInputSlotFree(WindowsGamingInputGamepadState *wgi_slot)
-{
-    wgi_slot->used = SDL_FALSE;
-    wgi_slot->correlated_context = NULL;
-}
-
-static SDL_bool
-HIDAPI_DriverXbox360_MissingWindowsGamingInputSlot()
-{
-    int ii;
-    for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
-        if (!wgi_state.per_gamepad[ii]->used) {
-            return SDL_TRUE;
-        }
-    }
-    return SDL_FALSE;
-}
-
-static void
-HIDAPI_DriverXbox360_UpdateWindowsGamingInput()
-{
-    int ii;
-    if (!wgi_state.gamepad_statics)
-        return;
-
-    if (!wgi_state.dirty)
-        return;
-    wgi_state.dirty = SDL_FALSE;
-
-    if (wgi_state.need_device_list_update) {
-        wgi_state.need_device_list_update = SDL_FALSE;
-        for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
-            wgi_state.per_gamepad[ii]->connected = SDL_FALSE;
-        }
-        HRESULT hr;
-        __FIVectorView_1_Windows__CGaming__CInput__CGamepad *gamepads;
-
-        hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_get_Gamepads(wgi_state.gamepad_statics, &gamepads);
-        if (SUCCEEDED(hr)) {
-            unsigned int num_gamepads;
-
-            hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_get_Size(gamepads, &num_gamepads);
-            if (SUCCEEDED(hr)) {
-                unsigned int i;
-                for (i = 0; i < num_gamepads; ++i) {
-                    __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
-
-                    hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_GetAt(gamepads, i, &gamepad);
-                    if (SUCCEEDED(hr)) {
-                        SDL_bool found = SDL_FALSE;
-                        int jj;
-                        for (jj = 0; jj < wgi_state.per_gamepad_count ; jj++) {
-                            if (wgi_state.per_gamepad[jj]->gamepad == gamepad) {
-                                found = SDL_TRUE;
-                                wgi_state.per_gamepad[jj]->connected = SDL_TRUE;
-                                break;
-                            }
-                        }
-                        if (!found) {
-                            /* New device, add it */
-                            wgi_state.per_gamepad_count++;
-                            wgi_state.per_gamepad = SDL_realloc(wgi_state.per_gamepad, sizeof(wgi_state.per_gamepad[0]) * wgi_state.per_gamepad_count);
-                            if (!wgi_state.per_gamepad) {
-                                SDL_OutOfMemory();
-                                return;
-                            }
-                            WindowsGamingInputGamepadState *gamepad_state = SDL_calloc(1, sizeof(*gamepad_state));
-                            if (!gamepad_state) {
-                                SDL_OutOfMemory();
-                                return;
-                            }
-                            wgi_state.per_gamepad[wgi_state.per_gamepad_count - 1] = gamepad_state;
-                            gamepad_state->gamepad = gamepad;
-                            gamepad_state->connected = SDL_TRUE;
-                        } else {
-                            /* Already tracked */
-                            __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad);
-                        }
-                    }
-                }
-                for (ii = wgi_state.per_gamepad_count - 1; ii >= 0; ii--) {
-                    WindowsGamingInputGamepadState *gamepad_state = wgi_state.per_gamepad[ii];
-                    if (!gamepad_state->connected) {
-                        /* Device missing, must be disconnected */
-                        if (gamepad_state->correlated_context) {
-                            gamepad_state->correlated_context->wgi_correlated = SDL_FALSE;
-                            gamepad_state->correlated_context->wgi_slot = NULL;
-                        }
-                        __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad_state->gamepad);
-                        SDL_free(gamepad_state);
-                        wgi_state.per_gamepad[ii] = wgi_state.per_gamepad[wgi_state.per_gamepad_count - 1];
-                        --wgi_state.per_gamepad_count;
-                    }
-                }
-            }
-            __FIVectorView_1_Windows__CGaming__CInput__CGamepad_Release(gamepads);
-        }
-    } /* need_device_list_update */
-
-    for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
-        HRESULT hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(wgi_state.per_gamepad[ii]->gamepad, &wgi_state.per_gamepad[ii]->state);
-        if (!SUCCEEDED(hr)) {
-            wgi_state.per_gamepad[ii]->connected = SDL_FALSE; /* Not used by anything, currently */
-        }
-    }
-}
-static void
-HIDAPI_DriverXbox360_InitWindowsGamingInput(SDL_DriverXbox360_Context *ctx)
-{
-    wgi_state.need_device_list_update = SDL_TRUE;
-    wgi_state.ref_count++;
-    if (!wgi_state.initialized) {
-        /* I think this takes care of RoInitialize() in a way that is compatible with the rest of SDL */
-        if (FAILED(WIN_CoInitialize())) {
-            return;
-        }
-        wgi_state.initialized = SDL_TRUE;
-        wgi_state.dirty = SDL_TRUE;
-
-        static const IID SDL_IID_IGamepadStatics = { 0x8BBCE529, 0xD49C, 0x39E9, { 0x95, 0x60, 0xE4, 0x7D, 0xDE, 0x96, 0xB7, 0xC8 } };
-        HRESULT hr;
-        HMODULE hModule = LoadLibraryA("combase.dll");
-        if (hModule != NULL) {
-            typedef HRESULT (WINAPI *WindowsCreateString_t)(PCNZWCH sourceString, UINT32 length, HSTRING* string);
-            typedef HRESULT (WINAPI *WindowsDeleteString_t)(HSTRING string);
-            typedef HRESULT (WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void** factory);
-
-            WindowsCreateString_t WindowsCreateStringFunc = (WindowsCreateString_t)GetProcAddress(hModule, "WindowsCreateString");
-            WindowsDeleteString_t WindowsDeleteStringFunc = (WindowsDeleteString_t)GetProcAddress(hModule, "WindowsDeleteString");
-            RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule, "RoGetActivationFactory");
-            if (WindowsCreateStringFunc && WindowsDeleteStringFunc && RoGetActivationFactoryFunc) {
-                LPTSTR pNamespace = L"Windows.Gaming.Input.Gamepad";
-                HSTRING hNamespaceString;
-
-                hr = WindowsCreateStringFunc(pNamespace, SDL_wcslen(pNamespace), &hNamespaceString);
-                if (SUCCEEDED(hr)) {
-                    RoGetActivationFactoryFunc(hNamespaceString, &SDL_IID_IGamepadStatics, &wgi_state.gamepad_statics);
-                    WindowsDeleteStringFunc(hNamespaceString);
-                }
-            }
-            FreeLibrary(hModule);
-        }
-    }
-}
-
-static SDL_bool
-HIDAPI_DriverXbox360_WindowsGamingInputSlotMatches(const WindowsMatchState *state, WindowsGamingInputGamepadState *slot)
-{
-    Uint32 wgi_buttons = slot->state.Buttons;
-    if ((wgi_buttons & 0x3FFF) == state->wgi_buttons && WindowsGamingInputAxesMatch(slot->state)) {
-        return SDL_TRUE;
-    }
-    return SDL_FALSE;
-}
-
-static SDL_bool
-HIDAPI_DriverXbox360_GuessWindowsGamingInputSlot(const WindowsMatchState *state, Uint8 *correlation_id, WindowsGamingInputGamepadState **slot)
-{
-    int match_count;
-
-    match_count = 0;
-    for (int user_index = 0; user_index < wgi_state.per_gamepad_count; ++user_index) {
-        WindowsGamingInputGamepadState *gamepad_state = wgi_state.per_gamepad[user_index];
-        if (HIDAPI_DriverXbox360_WindowsGamingInputSlotMatches(state, gamepad_state)) {
-            ++match_count;
-            *slot = gamepad_state;
-            /* Incrementing correlation_id for any match, as negative evidence for others being correlated */
-            *correlation_id = ++gamepad_state->correlation_id;
-        }
-    }
-    /* Only return a match if we match exactly one, and we have some non-zero data (buttons or axes) that matched.
-       Note that we're still invalidating *other* potential correlations if we have more than one match or we have no
-       data. */
-    if (match_count == 1 && state->any_data) {
-        return SDL_TRUE;
-    }
-    return SDL_FALSE;
-}
-
-static void
-HIDAPI_DriverXbox360_QuitWindowsGamingInput(SDL_DriverXbox360_Context *ctx)
-{
-    wgi_state.need_device_list_update = SDL_TRUE;
-    --wgi_state.ref_count;
-    if (!wgi_state.ref_count && wgi_state.initialized) {
-        for (int ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
-            __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(wgi_state.per_gamepad[ii]->gamepad);
-        }
-        if (wgi_state.per_gamepad) {
-            SDL_free(wgi_state.per_gamepad);
-            wgi_state.per_gamepad = NULL;
-        }
-        wgi_state.per_gamepad_count = 0;
-        if (wgi_state.gamepad_statics) {
-            __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(wgi_state.gamepad_statics);
-            wgi_state.gamepad_statics = NULL;
-        }
-        WIN_CoUninitialize();
-        wgi_state.initialized = SDL_FALSE;
-    }
-}
-
-#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
-
-static void
-HIDAPI_DriverXbox360_PostUpdate(void)
-{
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
-    SDL_bool unmapped_guide_pressed = SDL_FALSE;
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
-    if (!wgi_state.dirty) {
-        int ii;
-        for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
-            WindowsGamingInputGamepadState *gamepad_state = wgi_state.per_gamepad[ii];
-            if (!gamepad_state->used && (gamepad_state->state.Buttons & GamepadButtons_GUIDE)) {
-                unmapped_guide_pressed = SDL_TRUE;
-                break;
-            }
-        }
-    }
-    wgi_state.dirty = SDL_TRUE;
-#endif
-
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
-    if (!xinput_state_dirty) {
-        int ii;
-        for (ii = 0; ii < SDL_arraysize(xinput_state); ii++) {
-            if (xinput_state[ii].connected && !xinput_state[ii].used && (xinput_state[ii].state.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE)) {
-                unmapped_guide_pressed = SDL_TRUE;
-                break;
-            }
-        }
-    }
-    xinput_state_dirty = SDL_TRUE;
-#endif
-
-    if (unmapped_guide_pressed) {
-        if (guide_button_candidate.joystick && !guide_button_candidate.last_joystick) {
-            SDL_PrivateJoystickButton(guide_button_candidate.joystick, SDL_CONTROLLER_BUTTON_GUIDE, SDL_PRESSED);
-            guide_button_candidate.last_joystick = guide_button_candidate.joystick;
-        }
-    } else if (guide_button_candidate.last_joystick) {
-        SDL_PrivateJoystickButton(guide_button_candidate.last_joystick, SDL_CONTROLLER_BUTTON_GUIDE, SDL_RELEASED);
-        guide_button_candidate.last_joystick = NULL;
-    }
-    guide_button_candidate.joystick = NULL;
-#endif
-}
-
 #if defined(__MACOSX__)
 static SDL_bool
 IsBluetoothXboxOneController(Uint16 vendor_id, Uint16 product_id)
@@ -624,9 +88,9 @@ HIDAPI_DriverXbox360_IsSupportedDevice(const char *name, SDL_GameControllerType
         return SDL_FALSE;
     }
 #endif
-    return (type == SDL_CONTROLLER_TYPE_XBOX360 || type == SDL_CONTROLLER_TYPE_XBOXONE);
+    return (type == SDL_CONTROLLER_TYPE_XBOX360 || type == SDL_CONTROLLER_TYPE_XBOXONE) ? SDL_TRUE : SDL_FALSE;
 #else
-    return (type == SDL_CONTROLLER_TYPE_XBOX360);
+    return (type == SDL_CONTROLLER_TYPE_XBOX360) ? SDL_TRUE : SDL_FALSE;
 #endif
 }
 
@@ -650,7 +114,7 @@ static SDL_bool SetSlotLED(hid_device *dev, Uint8 slot)
 static SDL_bool
 HIDAPI_DriverXbox360_InitDevice(SDL_HIDAPI_Device *device)
 {
-    return HIDAPI_JoystickConnected(device, NULL, SDL_FALSE);
+    return HIDAPI_JoystickConnected(device, NULL);
 }
 
 static int
@@ -662,9 +126,7 @@ HIDAPI_DriverXbox360_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystic
 static void
 HIDAPI_DriverXbox360_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
 {
-    if (device->dev) {
-        SetSlotLED(device->dev, (player_index % 4));
-    }
+    SetSlotLED(device->dev, (player_index % 4));
 }
 
 static SDL_bool
@@ -679,31 +141,17 @@ HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst
         return SDL_FALSE;
     }
 
-    if (device->path) { /* else opened for RAWINPUT driver */
-        device->dev = hid_open_path(device->path, 0);
-        if (!device->dev) {
-            SDL_SetError("Couldn't open %s", device->path);
-            SDL_free(ctx);
-            return SDL_FALSE;
-        }
+    device->dev = hid_open_path(device->path, 0);
+    if (!device->dev) {
+        SDL_SetError("Couldn't open %s", device->path);
+        SDL_free(ctx);
+        return SDL_FALSE;
     }
     device->context = ctx;
 
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
-    xinput_device_change = SDL_TRUE;
-    ctx->xinput_enabled = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_CORRELATE_XINPUT, SDL_TRUE);
-    if (ctx->xinput_enabled && (WIN_LoadXInputDLL() < 0 || !XINPUTGETSTATE)) {
-        ctx->xinput_enabled = SDL_FALSE;
-    }
-    ctx->xinput_slot = XUSER_INDEX_ANY;
-#endif
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
-    HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
-#endif
-
     /* Set the controller LED */
     player_index = SDL_JoystickGetPlayerIndex(joystick);
-    if (player_index >= 0 && device->dev) {
+    if (player_index >= 0) {
         SetSlotLED(device->dev, (player_index % 4));
     }
 
@@ -718,46 +166,6 @@ HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst
 static int
 HIDAPI_DriverXbox360_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
 {
-#if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT)
-    SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
-#endif
-
-#ifdef __WIN32__
-    SDL_bool rumbled = SDL_FALSE;
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
-    if (!rumbled && ctx->wgi_correlated) {
-        WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
-        HRESULT hr;
-        gamepad_state->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
-        gamepad_state->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
-        hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, gamepad_state->vibration);
-        if (SUCCEEDED(hr)) {
-            rumbled = SDL_TRUE;
-        }
-    }
-#endif
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
-    if (!rumbled && ctx->xinput_correlated) {
-        XINPUT_VIBRATION XVibration;
-
-        if (!XINPUTSETSTATE) {
-            return SDL_Unsupported();
-        }
-
-        XVibration.wLeftMotorSpeed = low_frequency_rumble;
-        XVibration.wRightMotorSpeed = high_frequency_rumble;
-        if (XINPUTSETSTATE(ctx->xinput_slot, &XVibration) == ERROR_SUCCESS) {
-            rumbled = SDL_TRUE;
-        } else {
-            return SDL_SetError("XInputSetState() failed");
-        }
-    }
-#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
-
-#else /* !__WIN32__ */
-
 #ifdef __MACOSX__
     if (IsBluetoothXboxOneController(device->vendor_id, device->product_id)) {
         Uint8 rumble_packet[] = { 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00 };
@@ -791,8 +199,6 @@ HIDAPI_DriverXbox360_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
         return SDL_SetError("Couldn't send rumble packet");
     }
 #endif
-#endif /* __WIN32__ */
-
     return 0;
 }
 
@@ -821,149 +227,8 @@ HIDAPI_DriverXbox360_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Jo
     return SDL_Unsupported();
 }
 
-#ifdef __WIN32__
- /* This is the packet format for Xbox 360 and Xbox One controllers on Windows,
-    however with this interface there is no rumble support, no guide button,
-    and the left and right triggers are tied together as a single axis.
-
-    We use XInput and Windows.Gaming.Input to make up for these shortcomings.
-  */
 static void
-HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
-{
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
-    Uint32 match_state = ctx->match_state;
-    /* Update match_state with button bit, then fall through */
-#   define SDL_PrivateJoystickButton(joystick, button, state) if (state) match_state |= 1 << (button); else match_state &=~(1<<(button)); SDL_PrivateJoystickButton(joystick, button, state)
-    /* Grab high 4 bits of value, then fall through */
-#   define SDL_PrivateJoystickAxis(joystick, axis, value) if (axis < 4) match_state = (match_state & ~(0xF << (4 * axis + 16))) | ((value) & 0xF000) << (4 * axis + 4); SDL_PrivateJoystickAxis(joystick, axis, value)
-#endif
-    Sint16 axis;
-    SDL_bool has_trigger_data = SDL_FALSE;
-
-    if (ctx->last_state[10] != data[10]) {
-        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[10] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
-        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[10] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
-        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[10] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
-        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[10] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
-        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[10] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
-        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[10] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
-        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[10] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
-        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[10] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
-    }
-
-    if (ctx->last_state[11] != data[11] || ctx->last_state[12] != data[12]) {
-        SDL_bool dpad_up = SDL_FALSE;
-        SDL_bool dpad_down = SDL_FALSE;
-        SDL_bool dpad_left = SDL_FALSE;
-        SDL_bool dpad_right = SDL_FALSE;
-        Uint8 dpad_state = (((data[11] >> 2) & 0x0F) | (data[12] & 0x0F));
-
-        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[11] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
-        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[11] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
-
-        switch (dpad_state) {
-        case 1:
-            dpad_up = SDL_TRUE;
-            break;
-        case 2:
-            dpad_up = SDL_TRUE;
-            dpad_right = SDL_TRUE;
-            break;
-        case 3:
-            dpad_right = SDL_TRUE;
-            break;
-        case 4:
-            dpad_right = SDL_TRUE;
-            dpad_down = SDL_TRUE;
-            break;
-        case 5:
-            dpad_down = SDL_TRUE;
-            break;
-        case 6:
-            dpad_left = SDL_TRUE;
-            dpad_down = SDL_TRUE;
-            break;
-        case 7:
-            dpad_left = SDL_TRUE;
-            break;
-        case 8:
-            dpad_up = SDL_TRUE;
-            dpad_left = SDL_TRUE;
-            break;
-        default:
-            break;
-        }
-
-        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
-        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
-        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
-        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
-    }
-
-    axis = (int)*(Uint16*)(&data[0]) - 0x8000;
-    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
-    axis = (int)*(Uint16*)(&data[2]) - 0x8000;
-    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
-    axis = (int)*(Uint16*)(&data[4]) - 0x8000;
-    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
-    axis = (int)*(Uint16*)(&data[6]) - 0x8000;
-    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
-#undef SDL_PrivateJoystickAxis
-#endif
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
-    /* Prefer XInput over WindowsGamingInput, it continues to provide data in the background */
-    if (!has_trigger_data && ctx->xinput_enabled && ctx->xinput_correlated) {
-        has_trigger_data = SDL_TRUE;
-    }
-#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
-    if (!has_trigger_data && ctx->wgi_correlated) {
-        has_trigger_data = SDL_TRUE;
-    }
-#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
-
-    if (!has_trigger_data) {
-        axis = (data[9] * 257) - 32768;
-        if (data[9] < 0x80) {
-            axis = -axis * 2 - 32769;
-            SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, SDL_MIN_SINT16);
-            SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
-        } else if (data[9] > 0x80) {
-            axis = axis * 2 - 32767;
-            SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
-            SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, SDL_MIN_SINT16);
-        } else {
-            SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, SDL_MIN_SINT16);
-            SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, SDL_MIN_SINT16);
-        }
-    }
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
-    ctx->match_state = match_state;
-    ctx->last_state_packet = SDL_GetTicks();
-#undef SDL_PrivateJoystickButton
-#endif
-    SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
-}
-
-#ifdef SDL_JOYSTICK_RAWINPUT
-static void
-HIDAPI_DriverXbox360_HandleStatePacketFromRAWINPUT(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 *data, int size)
-{
-    SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
-    HIDAPI_DriverXbox360_HandleStatePacket(joystick, NULL, ctx, data, size);
-}
-#endif
-
-#else
-
-static void
-HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
+HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
 {
     Sint16 axis;
 #ifdef __MACOSX__
@@ -1014,238 +279,6 @@ HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev,
 
     SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
 }
-#endif /* __WIN32__ */
-
-static void
-HIDAPI_DriverXbox360_UpdateOtherAPIs(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
-{
-#if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT)
-    SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
-    SDL_bool has_trigger_data = SDL_FALSE;
-    SDL_bool correlated = SDL_FALSE;
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
-    WindowsMatchState match_state_xinput;
-#endif
-
-    /* Poll for trigger data once (not per-state-packet) */
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
-    /* Prefer XInput over WindowsGamingInput, it continues to provide data in the background */
-    if (!has_trigger_data && ctx->xinput_enabled && ctx->xinput_correlated) {
-        HIDAPI_DriverXbox360_UpdateXInput();
-        if (xinput_state[ctx->xinput_slot].connected) {
-            SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (xinput_state[ctx->xinput_slot].state.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE) ? SDL_PRESSED : SDL_RELEASED);
-            SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, ((int)xinput_state[ctx->xinput_slot].state.Gamepad.bLeftTrigger * 257) - 32768);
-            SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ((int)xinput_state[ctx->xinput_slot].state.Gamepad.bRightTrigger * 257) - 32768);
-            has_trigger_data = SDL_TRUE;
-        }
-    }
-#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
-    if (!has_trigger_data && ctx->wgi_correlated) {
-        HIDAPI_DriverXbox360_UpdateWindowsGamingInput(); /* May detect disconnect / cause uncorrelation */
-        if (ctx->wgi_correlated) { /* Still connected */
-            struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading *state = &ctx->wgi_slot->state;
-            SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (state->Buttons & GamepadButtons_GUIDE) ? SDL_PRESSED : SDL_RELEASED);
-            SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, ((int)(state->LeftTrigger * SDL_MAX_UINT16)) - 32768);
-            SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ((int)(state->RightTrigger * SDL_MAX_UINT16)) - 32768);
-            has_trigger_data = SDL_TRUE;
-        }
-    }
-#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
-    HIDAPI_DriverXbox360_FillMatchState(&match_state_xinput, ctx->match_state);
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
-    /* Parallel logic to WINDOWS_XINPUT below */
-    HIDAPI_DriverXbox360_UpdateWindowsGamingInput();
-    if (ctx->wgi_correlated) {
-        /* We have been previously correlated, ensure we are still matching, see comments in XINPUT section */
-        if (HIDAPI_DriverXbox360_WindowsGamingInputSlotMatches(&match_state_xinput, ctx->wgi_slot)) {
-            ctx->wgi_uncorrelate_count = 0;
-        } else {
-            ++ctx->wgi_uncorrelate_count;
-            /* Only un-correlate if this is consistent over multiple Update() calls - the timing of polling/event
-              pumping can easily cause this to uncorrelate for a frame.  2 seemed reliable in my testing, but
-              let's set it to 3 to be safe.  An incorrect un-correlation will simply result in lower precision
-              triggers for a frame. */
-            if (ctx->wgi_uncorrelate_count >= 3) {
-#ifdef DEBUG_JOYSTICK
-                SDL_Log("UN-Correlated joystick %d to WindowsGamingInput device #%d\n", joystick->instance_id, ctx->wgi_slot);
-#endif
-                HIDAPI_DriverXbox360_MarkWindowsGamingInputSlotFree(ctx->wgi_slot);
-                ctx->wgi_correlated = SDL_FALSE;
-                ctx->wgi_correlation_count = 0;
-                /* Force immediate update of triggers */
-                HIDAPI_DriverXbox360_HandleStatePacket(joystick, NULL, ctx, ctx->last_state, sizeof(ctx->last_state));
-                /* Force release of Guide button, it can't possibly be down on this device now. */
-                /* It gets left down if we were actually correlated incorrectly and it was released on the WindowsGamingInput
-                  device but we didn't get a state packet. */
-                SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, SDL_RELEASED);
-            }
-        }
-    }
-    if (!ctx->wgi_correlated) {
-        SDL_bool new_correlation_count = 0;
-        if (HIDAPI_DriverXbox360_MissingWindowsGamingInputSlot()) {
-            Uint8 correlation_id;
-            WindowsGamingInputGamepadState *slot_idx;
-            if (HIDAPI_DriverXbox360_GuessWindowsGamingInputSlot(&match_state_xinput, &correlation_id, &slot_idx)) {
-                /* we match exactly one WindowsGamingInput device */
-                /* Probably can do without wgi_correlation_count, just check and clear wgi_slot to NULL, unless we need
-                   even more frames to be sure. */
-                if (ctx->wgi_correlation_count && ctx->wgi_slot == slot_idx) {
-                    /* was correlated previously, and still the same device */
-                    if (ctx->wgi_correlation_id + 1 == correlation_id) {
-                        /* no one else was correlated in the meantime */
-                        new_correlation_count = ctx->wgi_correlation_count + 1;
-                        if (new_correlation_count == 2) {
-                            /* correlation stayed steady and uncontested across multiple frames, guaranteed match */
-                            ctx->wgi_correlated = SDL_TRUE;
-#ifdef DEBUG_JOYSTICK
-                            SDL_Log("Correlated joystick %d to WindowsGamingInput device #%d\n", joystick->instance_id, slot_idx);
-#endif
-                            correlated = SDL_TRUE;
-                            HIDAPI_DriverXbox360_MarkWindowsGamingInputSlotUsed(ctx->wgi_slot, ctx);
-                            /* If the generalized Guide button was using us, it doesn't need to anymore */
-                            if (guide_button_candidate.joystick == joystick)
-                                guide_button_candidate.joystick = NULL;
-                            if (guide_button_candidate.last_joystick == joystick)
-                                guide_button_candidate.last_joystick = NULL;
-                            /* Force immediate update of guide button / triggers */
-                            HIDAPI_DriverXbox360_HandleStatePacket(joystick, NULL, ctx, ctx->last_state, sizeof(ctx->last_state));
-                        }
-                    } else {
-                        /* someone else also possibly correlated to this device, start over */
-                        new_correlation_count = 1;
-                    }
-                } else {
-                    /* new possible correlation */
-                    new_correlation_count = 1;
-                    ctx->wgi_slot = slot_idx;
-                }
-                ctx->wgi_correlation_id = correlation_id;
-            } else {
-                /* Match multiple WindowsGamingInput devices, or none (possibly due to no buttons pressed) */
-            }
-        }
-        ctx->wgi_correlation_count = new_correlation_count;
-    } else {
-        correlated = SDL_TRUE;
-    }
-#endif
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
-    /* Parallel logic to WINDOWS_GAMING_INPUT above */
-    if (ctx->xinput_enabled) {
-        HIDAPI_DriverXbox360_UpdateXInput();
-        if (ctx->xinput_correlated) {
-            /* We have been previously correlated, ensure we are still matching */
-            /* This is required to deal with two (mostly) un-preventable mis-correlation situations:
-              A) Since the HID data stream does not provide an initial state (but polling XInput does), if we open
-                 5 controllers (#1-4 XInput mapped, #5 is not), and controller 1 had the A button down (and we don't
-                 know), and the user presses A on controller #5, we'll see exactly 1 controller with A down (#5) and
-                 exactly 1 XInput device with A down (#1), and incorrectly correlate.  This code will then un-correlate
-                 when A is released from either controller #1 or #5.
-              B) Since the app may not open all controllers, we could have a similar situation where only controller #5
-                 is opened, and the user holds A on controllers #1 and #5 simultaneously - again we see only 1 controller
-                 with A down and 1 XInput device with A down, and incorrectly correlate.  This should be very unusual
-                 (only when apps do not open all controllers, yet are listening to Guide button presses, yet
-                 for some reason want to ignore guide button presses on the un-opened controllers, yet users are
-                 pressing buttons on the unopened controllers), and will resolve itself when either button is released
-                 and we un-correlate.  We could prevent this by processing the state packets for *all* controllers,
-                 even un-opened ones, as that would allow more precise correlation.
-            */
-            if (HIDAPI_DriverXbox360_XInputSlotMatches(&match_state_xinput, ctx->xinput_slot)) {
-                ctx->xinput_uncorrelate_count = 0;
-            } else {
-                ++ctx->xinput_uncorrelate_count;
-                /* Only un-correlate if this is consistent over multiple Update() calls - the timing of polling/event
-                  pumping can easily cause this to uncorrelate for a frame.  2 seemed reliable in my testing, but
-                  let's set it to 3 to be safe.  An incorrect un-correlation will simply result in lower precision
-                  triggers for a frame. */
-                if (ctx->xinput_uncorrelate_count >= 3) {
-#ifdef DEBUG_JOYSTICK
-                    SDL_Log("UN-Correlated joystick %d to XInput device #%d\n", joystick->instance_id, ctx->xinput_slot);
-#endif
-                    HIDAPI_DriverXbox360_MarkXInputSlotFree(ctx->xinput_slot);
-                    ctx->xinput_correlated = SDL_FALSE;
-                    ctx->xinput_correlation_count = 0;
-                    /* Force immediate update of triggers */
-                    HIDAPI_DriverXbox360_HandleStatePacket(joystick, NULL, ctx, ctx->last_state, sizeof(ctx->last_state));
-                    /* Force release of Guide button, it can't possibly be down on this device now. */
-                    /* It gets left down if we were actually correlated incorrectly and it was released on the XInput
-                      device but we didn't get a state packet. */
-                    SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, SDL_RELEASED);
-                }
-            }
-        }
-        if (!ctx->xinput_correlated) {
-            SDL_bool new_correlation_count = 0;
-            if (HIDAPI_DriverXbox360_MissingXInputSlot()) {
-                Uint8 correlation_id = 0;
-                Uint8 slot_idx = 0;
-                if (HIDAPI_DriverXbox360_GuessXInputSlot(&match_state_xinput, &correlation_id, &slot_idx)) {
-                    /* we match exactly one XInput device */
-                    /* Probably can do without xinput_correlation_count, just check and clear xinput_slot to ANY, unless
-                       we need even more frames to be sure */
-                    if (ctx->xinput_correlation_count && ctx->xinput_slot == slot_idx) {
-                        /* was correlated previously, and still the same device */
-                        if (ctx->xinput_correlation_id + 1 == correlation_id) {
-                            /* no one else was correlated in the meantime */
-                            new_correlation_count = ctx->xinput_correlation_count + 1;
-                            if (new_correlation_count == 2) {
-                                /* correlation stayed steady and uncontested across multiple frames, guaranteed match */
-                                ctx->xinput_correlated = SDL_TRUE;
-#ifdef DEBUG_JOYSTICK
-                                SDL_Log("Correlated joystick %d to XInput device #%d\n", joystick->instance_id, slot_idx);
-#endif
-                                correlated = SDL_TRUE;
-                                HIDAPI_DriverXbox360_MarkXInputSlotUsed(ctx->xinput_slot);
-                                /* If the generalized Guide button was using us, it doesn't need to anymore */
-                                if (guide_button_candidate.joystick == joystick)
-                                    guide_button_candidate.joystick = NULL;
-                                if (guide_button_candidate.last_joystick == joystick)
-                                    guide_button_candidate.last_joystick = NULL;
-                                /* Force immediate update of guide button / triggers */
-                                HIDAPI_DriverXbox360_HandleStatePacket(joystick, NULL, ctx, ctx->last_state, sizeof(ctx->last_state));
-                            }
-                        } else {
-                            /* someone else also possibly correlated to this device, start over */
-                            new_correlation_count = 1;
-                        }
-                    } else {
-                        /* new possible correlation */
-                        new_correlation_count = 1;
-                        ctx->xinput_slot = slot_idx;
-                    }
-                    ctx->xinput_correlation_id = correlation_id;
-                } else {
-                    /* Match multiple XInput devices, or none (possibly due to no buttons pressed) */
-                }
-            }
-            ctx->xinput_correlation_count = new_correlation_count;
-        } else {
-            correlated = SDL_TRUE;
-        }
-    }
-#endif
-
-    if (!correlated) {
-        if (!guide_button_candidate.joystick ||
-            (ctx->last_state_packet && (
-                !guide_button_candidate.last_state_packet ||
-                SDL_TICKS_PASSED(ctx->last_state_packet, guide_button_candidate.last_state_packet)
-            ))
-        ) {
-            guide_button_candidate.joystick = joystick;
-            guide_button_candidate.last_state_packet = ctx->last_state_packet;
-        }
-    }
-#endif
-#endif
-}
 
 static SDL_bool
 HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device)
@@ -1262,47 +295,20 @@ HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device)
         return SDL_FALSE;
     }
 
-    while (device->dev && (size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
-        HIDAPI_DriverXbox360_HandleStatePacket(joystick, device->dev, ctx, data, size);
+    while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
+        HIDAPI_DriverXbox360_HandleStatePacket(joystick, ctx, data, size);
     }
 
     if (size < 0) {
         /* Read error, device is disconnected */
-        HIDAPI_JoystickDisconnected(device, joystick->instance_id, SDL_FALSE);
-    } else {
-        HIDAPI_DriverXbox360_UpdateOtherAPIs(device, joystick);
+        HIDAPI_JoystickDisconnected(device, joystick->instance_id);
     }
-    
     return (size >= 0);
 }
 
 static void
 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;
-#endif
-    
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
-    if (guide_button_candidate.joystick == joystick)
-        guide_button_candidate.joystick = NULL;
-    if (guide_button_candidate.last_joystick == joystick)
-        guide_button_candidate.last_joystick = NULL;
-#endif
-
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
-    xinput_device_change = SDL_TRUE;
-    if (ctx->xinput_enabled) {
-        if (ctx->xinput_correlated) {
-            HIDAPI_DriverXbox360_MarkXInputSlotFree(ctx->xinput_slot);
-        }
-        WIN_UnloadXInputDLL();
-    }
-#endif
-#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
-    HIDAPI_DriverXbox360_QuitWindowsGamingInput(ctx);
-#endif
-
     if (device->dev) {
         hid_close(device->dev);
         device->dev = NULL;
@@ -1335,10 +341,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 =
     HIDAPI_DriverXbox360_SetJoystickSensorsEnabled,
     HIDAPI_DriverXbox360_CloseJoystick,
     HIDAPI_DriverXbox360_FreeDevice,
-    HIDAPI_DriverXbox360_PostUpdate,
-#ifdef SDL_JOYSTICK_RAWINPUT
-    HIDAPI_DriverXbox360_HandleStatePacketFromRAWINPUT,
-#endif
 };
 
 #endif /* SDL_JOYSTICK_HIDAPI_XBOX360 */
diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360w.c b/src/joystick/hidapi/SDL_hidapi_xbox360w.c
index 294139cf2..2a2513422 100644
--- a/src/joystick/hidapi/SDL_hidapi_xbox360w.c
+++ b/src/joystick/hidapi/SDL_hidapi_xbox360w.c
@@ -255,10 +255,10 @@ HIDAPI_DriverXbox360W_UpdateDevice(SDL_HIDAPI_Device *device)
                 if (connected) {
                     SDL_JoystickID joystickID;
 
-                    HIDAPI_JoystickConnected(device, &joystickID, SDL_FALSE);
+                    HIDAPI_JoystickConnected(device, &joystickID);
 
                 } else if (device->num_joysticks > 0) {
-                    HIDAPI_JoystickDisconnected(device, device->joysticks[0], SDL_FALSE);
+                    HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
                 }
             }
         } else if (size == 29 && data[0] == 0x00 && data[1] == 0x0f && data[2] == 0x00 && data[3] == 0xf0) {
@@ -286,7 +286,7 @@ HIDAPI_DriverXbox360W_UpdateDevice(SDL_HIDAPI_Device *device)
     if (joystick) {
         if (size < 0) {
             /* Read error, device is disconnected */
-            HIDAPI_JoystickDisconnected(device, joystick->instance_id, SDL_FALSE);
+            HIDAPI_JoystickDisconnected(device, joystick->instance_id);
         }
     }
     return (size >= 0);
@@ -325,7 +325,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W =
     HIDAPI_DriverXbox360W_SetJoystickSensorsEnabled,
     HIDAPI_DriverXbox360W_CloseJoystick,
     HIDAPI_DriverXbox360W_FreeDevice,
-    NULL
 };
 
 #endif /* SDL_JOYSTICK_HIDAPI_XBOX360 */
diff --git a/src/joystick/hidapi/SDL_hidapi_xboxone.c b/src/joystick/hidapi/SDL_hidapi_xboxone.c
index 5218cb6ab..4fd366562 100644
--- a/src/joystick/hidapi/SDL_hidapi_xboxone.c
+++ b/src/joystick/hidapi/SDL_hidapi_xboxone.c
@@ -291,7 +291,7 @@ HIDAPI_DriverXboxOne_IsSupportedDevice(const char *name, SDL_GameControllerType
         return SDL_FALSE;
     }
 #endif
-    return (type == SDL_CONTROLLER_TYPE_XBOXONE);
+    return (type == SDL_CONTROLLER_TYPE_XBOXONE) ? SDL_TRUE : SDL_FALSE;
 }
 
 static const char *
@@ -303,7 +303,7 @@ HIDAPI_DriverXboxOne_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
 static SDL_bool
 HIDAPI_DriverXboxOne_InitDevice(SDL_HIDAPI_Device *device)
 {
-    return HIDAPI_JoystickConnected(device, NULL, SDL_FALSE);
+    return HIDAPI_JoystickConnected(device, NULL);
 }
 
 static int
@@ -852,7 +852,7 @@ HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device)
         !ControllerSendsWaitingForInit(device->vendor_id, device->product_id)) {
         if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->start_time + CONTROLLER_INIT_DELAY_MS)) {
             if (!SendControllerInit(device, ctx)) {
-                HIDAPI_JoystickDisconnected(device, joystick->instance_id, SDL_FALSE);
+                HIDAPI_JoystickDisconnected(device, joystick->instance_id);
                 return SDL_FALSE;
             }
             ctx->initialized = SDL_TRUE;
@@ -918,7 +918,7 @@ HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device)
                     SDL_Log("Delay after init: %ums\n", SDL_GetTicks() - ctx->start_time);
 #endif
                     if (!SendControllerInit(device, ctx)) {
-                        HIDAPI_JoystickDisconnected(device, joystick->instance_id, SDL_FALSE);
+                        HIDAPI_JoystickDisconnected(device, joystick->instance_id);
                         return SDL_FALSE;
                     }
                     ctx->initialized = SDL_TRUE;
@@ -973,7 +973,7 @@ HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device)
 
     if (size < 0) {
         /* Read error, device is disconnected */
-        HIDAPI_JoystickDisconnected(device, joystick->instance_id, SDL_FALSE);
+        HIDAPI_JoystickDisconnected(device, joystick->instance_id);
     }
     return (size >= 0);
 }
@@ -1011,7 +1011,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
     HIDAPI_DriverXboxOne_SetJoystickSensorsEnabled,
     HIDAPI_DriverXboxOne_CloseJoystick,
     HIDAPI_DriverXboxOne_FreeDevice,
-    NULL
 };
 
 #endif /* SDL_JOYSTICK_HIDAPI_XBOXONE */
diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c
index f303440ee..a93bd18f4 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick.c
+++ b/src/joystick/hidapi/SDL_hidapijoystick.c
@@ -443,13 +443,6 @@ HIDAPI_GetDeviceDriver(SDL_HIDAPI_Device *device)
         return NULL;
     }
 
-#ifdef SDL_JOYSTICK_RAWINPUT
-    if (RAWINPUT_IsDevicePresent(device->vendor_id, device->product_id, device->version)) {
-        /* The RAWINPUT driver is taking care of this device */
-        return NULL;
-    }
-#endif
-
 	if (device->vendor_id != USB_VENDOR_VALVE) {
         if (device->usage_page && device->usage_page != USAGE_PAGE_GENERIC_DESKTOP) {
             return NULL;
@@ -535,7 +528,7 @@ HIDAPI_CleanupDeviceDriver(SDL_HIDAPI_Device *device)
 
     /* Disconnect any joysticks */
     while (device->num_joysticks) {
-        HIDAPI_JoystickDisconnected(device, device->joysticks[0], SDL_FALSE);
+        HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
     }
 
     device->driver->FreeDevice(device);
@@ -608,11 +601,6 @@ HIDAPI_JoystickInit(void)
         return -1;
     }
 
-#ifdef __WINDOWS__
-    /* On Windows, turns out HIDAPI for Xbox controllers doesn't allow background input, so off by default */
-    SDL_SetHintWithPriority(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0", SDL_HINT_DEFAULT);
-#endif
-
     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);
@@ -629,7 +617,7 @@ HIDAPI_JoystickInit(void)
 }
 
 SDL_bool
-HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID, SDL_bool is_external)
+HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID)
 {
     SDL_JoystickID joystickID;
     SDL_JoystickID *joysticks = (SDL_JoystickID *)SDL_realloc(device->joysticks, (device->num_joysticks + 1)*sizeof(*device->joysticks));
@@ -640,9 +628,7 @@ HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID,
     joystickID = SDL_GetNextJoystickInstanceID();
     device->joysticks = joysticks;
     device->joysticks[device->num_joysticks++] = joystickID;
-    if (!is_external) {
-        ++SDL_HIDAPI_numjoysticks;
-    }
+    ++SDL_HIDAPI_numjoysticks;
 
     SDL_PrivateJoystickAdded(joystickID);
 
@@ -653,14 +639,14 @@ HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID,
 }
 
 void
-HIDAPI_JoystickDisconnected(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID, SDL_bool is_external)
+HIDAPI_JoystickDisconnected(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID)
 {
     int i, size;
 
     for (i = 0; i < device->num_joysticks; ++i) {
         if (device->joysticks[i] == joystickID) {
             SDL_Joystick *joystick = SDL_JoystickFromInstanceID(joystickID);
-            if (joystick && !is_external) {
+            if (joystick) {
                 HIDAPI_JoystickClose(joystick);
             }
 
@@ -668,9 +654,7 @@ HIDAPI_JoystickDisconnected(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID
             SDL_memmove(&device->joysticks[i], &device->joysticks[i+1], size);
             --device->num_joysticks;
 
-            if (!is_external) {
-                --SDL_HIDAPI_numjoysticks;
-            }
+            --SDL_HIDAPI_numjoysticks;
             if (device->num_joysticks == 0) {
                 SDL_free(device->joysticks);
                 device->joysticks = NULL;
@@ -932,7 +916,6 @@ HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, cons
 static void
 HIDAPI_JoystickDetect(void)
 {
-    int i;
     if (SDL_AtomicTryLock(&SDL_HIDAPI_spinlock)) {
         HIDAPI_UpdateDiscovery();
         if (SDL_HIDAPI_discovery.m_bHaveDevicesChanged) {
@@ -942,12 +925,6 @@ HIDAPI_JoystickDetect(void)
         }
         SDL_AtomicUnlock(&SDL_HIDAPI_spinlock);
     }
-    for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
-        SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
-        if (driver->enabled && driver->PostUpdate) {
-            driver->PostUpdate();
-        }
-    }
 }
 
 void
diff --git a/src/joystick/hidapi/SDL_hidapijoystick_c.h b/src/joystick/hidapi/SDL_hidapijoystick_c.h
index f5c995176..d16a67360 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick_c.h
+++ b/src/joystick/hidapi/SDL_hidapijoystick_c.h
@@ -38,11 +38,6 @@
 #define SDL_JOYSTICK_HIDAPI_XBOXONE
 #define SDL_JOYSTICK_HIDAPI_GAMECUBE
 
-#ifdef __WINDOWS__
-/* On Windows, Xbox One controllers are handled by the Xbox 360 driver */
-#undef SDL_JOYSTICK_HIDAPI_XBOXONE
-#endif
-
 #if defined(__IPHONEOS__) || defined(__TVOS__) || defined(__ANDROID__)
 /* Very basic Steam Controller support on mobile devices */
 #define SDL_JOYSTICK_HIDAPI_STEAM
@@ -102,10 +97,6 @@ typedef struct _SDL_HIDAPI_DeviceDriver
     int (*SetJoystickSensorsEnabled)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled);
     void (*CloseJoystick)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick);
     void (*FreeDevice)(SDL_HIDAPI_Device *device);
-    void (*PostUpdate)(void);
-#ifdef SDL_JOYSTICK_RAWINPUT
-    void (*HandleStatePacketFromRAWINPUT)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 *data, int size);
-#endif
 
 } SDL_HIDAPI_DeviceDriver;
 
@@ -124,8 +115,8 @@ extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube;
 extern SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name);
 
 extern void HIDAPI_UpdateDevices(void);
-extern SDL_bool HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID, SDL_bool is_external);
-extern void HIDAPI_JoystickDisconnected(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID, SDL_bool is_external);
+extern SDL_bool HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID);
+extern void HIDAPI_JoystickDisconnected(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID);
 
 extern void HIDAPI_DumpPacket(const char *prefix, Uint8 *data, int size);
 
diff --git a/src/joystick/usb_ids.h b/src/joystick/usb_ids.h
index 00de4bd68..3b37a77af 100644
--- a/src/joystick/usb_ids.h
+++ b/src/joystick/usb_ids.h
@@ -53,6 +53,29 @@
 #define USB_PRODUCT_XBOX_ONE_SERIES_X                   0x0b12
 #define USB_PRODUCT_XBOX_ONE_SERIES_X_BLUETOOTH         0x0b13
 
+/* USB usage pages */
+#define USB_USAGEPAGE_GENERIC_DESKTOP   0x0001
+#define USB_USAGEPAGE_BUTTON            0x0009
+
+/* USB usages for USAGE_PAGE_GENERIC_DESKTOP */
+#define USB_USAGE_GENERIC_POINTER               0x0001
+#define USB_USAGE_GENERIC_MOUSE                 0x0002
+#define USB_USAGE_GENERIC_JOYSTICK              0x0004
+#define USB_USAGE_GENERIC_GAMEPAD               0x0005
+#define USB_USAGE_GENERIC_KEYBOARD              0x0006
+#define USB_USAGE_GENERIC_KEYPAD                0x0007
+#define USB_USAGE_GENERIC_MULTIAXISCONTROLLER   0x0008
+#define USB_USAGE_GENERIC_X                     0x0030
+#define USB_USAGE_GENERIC_Y                     0x0031
+#define USB_USAGE_GENERIC_Z                     0x0032
+#define USB_USAGE_GENERIC_RX                    0x0033
+#define USB_USAGE_GENERIC_RY                    0x0034
+#define USB_USAGE_GENERIC_RZ                    0x0035
+#define USB_USAGE_GENERIC_SLIDER                0x0036
+#define USB_USAGE_GENERIC_DIAL                  0x0037
+#define USB_USAGE_GENERIC_WHEEL                 0x0038
+#define USB_USAGE_GENERIC_HAT                   0x0039
+
 #endif /* usb_ids_h_ */
 
 /* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/joystick/windows/SDL_rawinputjoystick.c b/src/joystick/windows/SDL_rawinputjoystick.c
index 4bd0f5d08..6ec92a3fc 100644
--- a/src/joystick/windows/SDL_rawinputjoystick.c
+++ b/src/joystick/windows/SDL_rawinputjoystick.c
@@ -35,15 +35,39 @@
 
 #include "SDL_assert.h"
 #include "SDL_endian.h"
+#include "SDL_events.h"
 #include "SDL_hints.h"
+#include "SDL_timer.h"
+#include "../usb_ids.h"
 #include "../SDL_sysjoystick.h"
 #include "../../core/windows/SDL_windows.h"
+#include "../../core/windows/SDL_hid.h"
 #include "../hidapi/SDL_hidapijoystick_c.h"
 
-#if !defined(SDL_JOYSTICK_HIDAPI) || !defined(SDL_JOYSTICK_HIDAPI_XBOX360)
-#error RAWINPUT requires the XBOX360 HIDAPI driver
+#ifdef __WIN32__
+#define SDL_JOYSTICK_RAWINPUT_XINPUT
+/* This requires the Windows 10 SDK to build */
+/*#define SDL_JOYSTICK_RAWINPUT_GAMING_INPUT*/
 #endif
 
+#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
+#include "../../core/windows/SDL_xinput.h"
+#endif
+
+#ifdef SDL_JOYSTICK_RAWINPUT_GAMING_INPUT
+#include "../../core/windows/SDL_windows.h"
+typedef struct WindowsGamingInputGamepadState WindowsGamingInputGamepadState;
+#define GamepadButtons_GUIDE 0x40000000
+#define COBJMACROS
+#include "windows.gaming.input.h"
+#endif
+
+#if defined(SDL_JOYSTICK_RAWINPUT_XINPUT) || defined(SDL_JOYSTICK_RAWINPUT_GAMING_INPUT)
+#define SDL_JOYSTICK_RAWINPUT_MATCHING
+#endif
+
+/* #define DEBUG_RAWINPUT */
+
 #ifndef RIDEV_EXINPUTSINK
 #define RIDEV_EXINPUTSINK       0x00001000
 #define RIDEV_DEVNOTIFY         0x00002000
@@ -60,38 +84,17 @@
 #define GIDC_REMOVAL             2
 #endif
 
-
-/* #define DEBUG_RAWINPUT */
-
-#define USB_PACKET_LENGTH   64
-
-#define SDL_callocStruct(type) (type *)SDL_calloc(1, sizeof(type))
-#define SDL_callocStructs(type, count) (type *)SDL_calloc((count), sizeof(type))
-
-#define USAGE_PAGE_GENERIC_DESKTOP 0x0001
-#define USAGE_JOYSTICK 0x0004
-#define USAGE_GAMEPAD 0x0005
-#define USAGE_MULTIAXISCONTROLLER 0x0008
-
-
 /* external variables referenced. */
 extern HWND SDL_HelperWindow;
 
 
-static SDL_HIDAPI_DeviceDriver *SDL_RAWINPUT_drivers[] = {
-#ifdef SDL_JOYSTICK_HIDAPI_XBOX360
-    &SDL_HIDAPI_DriverXbox360,
-#endif
-};
-
 static SDL_bool SDL_RAWINPUT_inited = SDL_FALSE;
 static int SDL_RAWINPUT_numjoysticks = 0;
 static SDL_bool SDL_RAWINPUT_need_pump = SDL_TRUE;
 
 static void RAWINPUT_JoystickDetect(void);
 static void RAWINPUT_PumpMessages(void);
-static SDL_bool RAWINPUT_IsDeviceSupported(Uint16 vendor_id, Uint16 product_id, Uint16 version);
-static void RAWINPUT_JoystickClose(SDL_Joystick * joystick);
+static void RAWINPUT_JoystickClose(SDL_Joystick *joystick);
 
 typedef struct _SDL_RAWINPUT_Device
 {
@@ -101,10 +104,8 @@ typedef struct _SDL_RAWINPUT_Device
     Uint16 product_id;
     Uint16 version;
     SDL_JoystickGUID guid;
-    Uint16 usage_page;
-    Uint16 usage;
-    SDL_HIDAPI_Device hiddevice;
-    SDL_HIDAPI_DeviceDriver *driver;
+    SDL_bool is_xinput;
+    PHIDP_PREPARSED_DATA preparsed_data;
 
     HANDLE hDevice;
     SDL_Joystick *joystick;
@@ -115,74 +116,502 @@ typedef struct _SDL_RAWINPUT_Device
 
 struct joystick_hwdata
 {
-    void *reserved; /* reserving a value here to ensure the new SDL_hidapijoystick.c code never dereferences this */
+    SDL_bool is_xinput;
+    PHIDP_PREPARSED_DATA preparsed_data;
+    ULONG max_data_length;
+    HIDP_DATA *data;
+    USHORT *button_indices;
+    USHORT *axis_indices;
+    USHORT *hat_indices;
+    SDL_bool guide_hack;
+    SDL_bool trigger_hack;
+    USHORT trigger_hack_index;
+
+#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
+    Uint32 match_state; /* Low 16 bits for button states, high 16 for 4 4bit axes */
+    Uint32 last_state_packet;
+#endif
+
+#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
+    SDL_bool xinput_enabled;
+    SDL_bool xinput_correlated;
+    Uint8 xinput_correlation_id;
+    Uint8 xinput_correlation_count;
+    Uint8 xinput_uncorrelate_count;
+    Uint8 xinput_slot;
+#endif
+
+#ifdef SDL_JOYSTICK_RAWINPUT_GAMING_INPUT
+    SDL_bool wgi_correlated;
+    Uint8 wgi_correlation_id;
+    Uint8 wgi_correlation_count;
+    Uint8 wgi_uncorrelate_count;
+    WindowsGamingInputGamepadState *wgi_slot;
+#endif
+
     SDL_RAWINPUT_Device *device;
 };
+typedef struct joystick_hwdata RAWINPUT_DeviceContext;
 
 SDL_RAWINPUT_Device *SDL_RAWINPUT_devices;
 
 static const Uint16 subscribed_devices[] = {
-    USAGE_GAMEPAD,
+    USB_USAGE_GENERIC_GAMEPAD,
     /* Don't need Joystick for any devices we're handling here (XInput-capable)
-    USAGE_JOYSTICK,
-    USAGE_MULTIAXISCONTROLLER,
+    USB_USAGE_GENERIC_JOYSTICK,
+    USB_USAGE_GENERIC_MULTIAXISCONTROLLER,
     */
 };
 
-SDL_bool RAWINPUT_AllXInputDevicesSupported() {
-    UINT i, device_count = 0;
-    PRAWINPUTDEVICELIST devices;
-    SDL_bool any_unsupported = SDL_FALSE;
+#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
 
-    if ((GetRawInputDeviceList(NULL, &device_count, sizeof(RAWINPUTDEVICELIST)) == -1) || (!device_count)) {
-        return SDL_FALSE;
+static struct {
+    Uint32 last_state_packet;
+    SDL_Joystick *joystick;
+    SDL_Joystick *last_joystick;
+} guide_button_candidate;
+
+typedef struct WindowsMatchState {
+    SHORT match_axes[4];
+#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
+    WORD xinput_buttons;
+#endif
+#ifdef SDL_JOYSTICK_RAWINPUT_GAMING_INPUT
+    Uint32 wgi_buttons;
+#endif
+    SDL_bool any_data;
+} WindowsMatchState;
+
+static void RAWINPUT_FillMatchState(WindowsMatchState *state, Uint32 match_state)
+{
+    int ii;
+    state->any_data = SDL_FALSE;
+    /*  SHORT state->match_axes[4] = {
+            (match_state & 0x000F0000) >> 4,
+            (match_state & 0x00F00000) >> 8,
+            (match_state & 0x0F000000) >> 12,
+            (match_state & 0xF0000000) >> 16,
+        }; */
+    for (ii = 0; ii < 4; ii++) {
+        state->match_axes[ii] = (match_state & (0x000F0000 << (ii * 4))) >> (4 + ii * 4);
+        if ((Uint32)(state->match_axes[ii] + 0x1000) > 0x2000) { /* match_state bit is not 0xF, 0x1, or 0x2 */
+            state->any_data = SDL_TRUE;
+        }
     }
 
-    devices = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * device_count);
-    if (devices == NULL) {
-        return SDL_FALSE;
+#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
+    /* Match axes by checking if the distance between the high 4 bits of axis and the 4 bits from match_state is 1 or less */
+#define XInputAxesMatch(gamepad) (\
+   (Uint32)(gamepad.sThumbLX - state->match_axes[0] + 0x1000) <= 0x2fff && \
+   (Uint32)(~gamepad.sThumbLY - state->match_axes[1] + 0x1000) <= 0x2fff && \
+   (Uint32)(gamepad.sThumbRX - state->match_axes[2] + 0x1000) <= 0x2fff && \
+   (Uint32)(~gamepad.sThumbRY - state->match_axes[3] + 0x1000) <= 0x2fff)
+    /* Explicit
+#define XInputAxesMatch(gamepad) (\
+    SDL_abs((Sint8)((gamepad.sThumbLX & 0xF000) >> 8) - ((match_state & 0x000F0000) >> 12)) <= 0x10 && \
+    SDL_abs((Sint8)((~gamepad.sThumbLY & 0xF000) >> 8) - ((match_state & 0x00F00000) >> 16)) <= 0x10 && \
+    SDL_abs((Sint8)((gamepad.sThumbRX & 0xF000) >> 8) - ((match_state & 0x0F000000) >> 20)) <= 0x10 && \
+    SDL_abs((Sint8)((~gamepad.sThumbRY & 0xF000) >> 8) - ((match_state & 0xF0000000) >> 24)) <= 0x10) */
+
+    state->xinput_buttons =
+        /* Bitwise map .RLDUWVQTS.KYXBA -> YXBA..WVQTKSRLDU */
+        match_state << 12 | (match_state & 0x0780) >> 1 | (match_state & 0x0010) << 1 | (match_state & 0x0040) >> 2 | (match_state & 0x7800) >> 11;
+    /*  Explicit
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_A)) ? XINPUT_GAMEPAD_A : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_B)) ? XINPUT_GAMEPAD_B : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_X)) ? XINPUT_GAMEPAD_X : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_Y)) ? XINPUT_GAMEPAD_Y : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_BACK)) ? XINPUT_GAMEPAD_BACK : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_START)) ? XINPUT_GAMEPAD_START : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_LEFTSTICK)) ? XINPUT_GAMEPAD_LEFT_THUMB : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_RIGHTSTICK)) ? XINPUT_GAMEPAD_RIGHT_THUMB: 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) ? XINPUT_GAMEPAD_LEFT_SHOULDER : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) ? XINPUT_GAMEPAD_RIGHT_SHOULDER : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_UP)) ? XINPUT_GAMEPAD_DPAD_UP : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_DOWN)) ? XINPUT_GAMEPAD_DPAD_DOWN : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_LEFT)) ? XINPUT_GAMEPAD_DPAD_LEFT : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) ? XINPUT_GAMEPAD_DPAD_RIGHT : 0);
+    */
+
+    if (state->xinput_buttons)
+        state->any_data = SDL_TRUE;
+#endif
+
+#ifdef SDL_JOYSTICK_RAWINPUT_GAMING_INPUT
+    /* Match axes by checking if the distance between the high 4 bits of axis and the 4 bits from match_state is 1 or less */
+#define WindowsGamingInputAxesMatch(gamepad) (\
+    (Uint16)(((Sint16)(gamepad.LeftThumbstickX * SDL_MAX_SINT16) & 0xF000) - state->match_axes[0] + 0x1000) <= 0x2fff && \
+    (Uint16)((~(Sint16)(gamepad.LeftThumbstickY * SDL_MAX_SINT16) & 0xF000) - state->match_axes[1] + 0x1000) <= 0x2fff && \
+    (Uint16)(((Sint16)(gamepad.RightThumbstickX * SDL_MAX_SINT16) & 0xF000) - state->match_axes[2] + 0x1000) <= 0x2fff && \
+    (Uint16)((~(Sint16)(gamepad.RightThumbstickY * SDL_MAX_SINT16) & 0xF000) - state->match_axes[3] + 0x1000) <= 0x2fff)
+
+
+    state->wgi_buttons =
+        /* Bitwise map .RLD UWVQ TS.K YXBA -> ..QT WVRL DUYX BAKS */
+        /*  RStick/LStick (QT)         RShould/LShould  (WV)                 DPad R/L/D/U                          YXBA                         bac(K)                      (S)tart */
+        (match_state & 0x0180) << 5 | (match_state & 0x0600) << 1 | (match_state & 0x7800) >> 5 | (match_state & 0x000F) << 2 | (match_state & 0x0010) >> 3 | (match_state & 0x0040) >> 6;
+    /*  Explicit
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_A)) ? GamepadButtons_A : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_B)) ? GamepadButtons_B : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_X)) ? GamepadButtons_X : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_Y)) ? GamepadButtons_Y : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_BACK)) ? GamepadButtons_View : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_START)) ? GamepadButtons_Menu : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_LEFTSTICK)) ? GamepadButtons_LeftThumbstick : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_RIGHTSTICK)) ? GamepadButtons_RightThumbstick: 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) ? GamepadButtons_LeftShoulder: 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) ? GamepadButtons_RightShoulder: 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_UP)) ? GamepadButtons_DPadUp : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_DOWN)) ? GamepadButtons_DPadDown : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_LEFT)) ? GamepadButtons_DPadLeft : 0) |
+        ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) ? GamepadButtons_DPadRight : 0); */
+
+    if (state->wgi_buttons)
+        state->any_data = SDL_TRUE;
+#endif
+
+}
+
+#endif /* SDL_JOYSTICK_RAWINPUT_MATCHING */
+
+#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
+
+static struct {
+    XINPUT_STATE_EX state;
+    SDL_bool connected; /* Currently has an active XInput device */
+    SDL_bool used; /* Is currently mapped to an SDL device */
+    Uint8 correlation_id;
+} xinput_state[XUSER_MAX_COUNT];
+static SDL_bool xinput_device_change = SDL_TRUE;
+static SDL_bool xinput_state_dirty = SDL_TRUE;
+
+static void
+RAWINPUT_UpdateXInput()
+{
+    DWORD user_index;
+    if (xinput_device_change) {
+        for (user_index = 0; user_index < XUSER_MAX_COUNT; user_index++) {
+            XINPUT_CAPABILITIES capabilities;
+            xinput_state[user_index].connected = (XINPUTGETCAPABILITIES(user_index, XINPUT_FLAG_GAMEPAD, &capabilities) == ERROR_SUCCESS) ? SDL_TRUE : SDL_FALSE;
+        }
+        xinput_device_change = SDL_FALSE;
+        xinput_state_dirty = SDL_TRUE;
     }
-
-    if (GetRawInputDeviceList(devices, &device_count, sizeof(RAWINPUTDEVICELIST)) == -1) {
-        SDL_free(devices);
-        return SDL_FALSE;
-    }
-
-    for (i = 0; i < device_count; i++) {
-        RID_DEVICE_INFO rdi;
-        char devName[128];
-        UINT rdiSize = sizeof(rdi);
-        UINT nameSize = SDL_arraysize(devName);
-
-        rdi.cbSize = sizeof(rdi);
-        if ((devices[i].dwType == RIM_TYPEHID) &&
-            (GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) &&
-            (GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) &&
-            (SDL_strstr(devName, "IG_") != NULL)
-        ) {
-            /* XInput-capable */
-            if (!RAWINPUT_IsDeviceSupported((Uint16)rdi.hid.dwVendorId, (Uint16)rdi.hid.dwProductId, (Uint16)rdi.hid.dwVersionNumber)) {
-                /* But not supported, probably Valve virtual controller */
-                any_unsupported = SDL_TRUE;
+    if (xinput_state_dirty) {
+        xinput_state_dirty = SDL_FALSE;
+        for (user_index = 0; user_index < SDL_arraysize(xinput_state); ++user_index) {
+            if (xinput_state[user_index].connected) {
+                if (XINPUTGETSTATE(user_index, &xinput_state[user_index].state) != ERROR_SUCCESS) {
+                    xinput_state[user_index].connected = SDL_FALSE;
+                }
             }
         }
     }
-    SDL_free(devices);
-    if (any_unsupported) {
-        /* This happens with Valve virtual controllers that shows up in the RawInputDeviceList, but do not
-            generate WM_INPUT events, so we must use XInput or DInput to read from it, and with XInput if we
-            have some supported and some not, we can't easily tell which device is actually showing up in
-            RawInput, so we must just disable RawInput for now.  Additionally, if these unsupported devices
-            are locally connected, they still show up in RawInput under a *different* HID path, with
-            different vendor/product IDs, so there's no way to reconcile. */
-#ifdef DEBUG_RAWINPUT
-        SDL_Log("Found some supported and some unsupported XInput devices, disabling RawInput\n");
-#endif
-        return SDL_FALSE;
-    }
-    return SDL_TRUE;
 }
 
+static void
+RAWINPUT_MarkXInputSlotUsed(Uint8 xinput_slot)
+{
+    if (xinput_slot != XUSER_INDEX_ANY) {
+        xinput_state[xinput_slot].used = SDL_TRUE;
+    }
+}
+
+static void
+RAWINPUT_MarkXInputSlotFree(Uint8 xinput_slot)
+{
+    if (xinput_slot != XUSER_INDEX_ANY) {
+        xinput_state[xinput_slot].used = SDL_FALSE;
+    }
+}
+static SDL_bool
+RAWINPUT_MissingXInputSlot()
+{
+    int ii;
+    for (ii = 0; ii < SDL_arraysize(xinput_state); ii++) {
+        if (xinput_state[ii].connected && !xinput_state[ii].used) {
+            return SDL_TRUE;
+        }
+    }
+    return SDL_FALSE;
+}
+
+static SDL_bool
+RAWINPUT_XInputSlotMatches(const WindowsMatchState *state, Uint8 slot_idx)
+{
+    if (xinput_state[slot_idx].connected) {
+        WORD xinput_buttons = xinput_state[slot_idx].state.Gamepad.wButtons;
+        if ((xinput_buttons & ~XINPUT_GAMEPAD_GUIDE) == state->xinput_buttons && XInputAxesMatch(xinput_state[slot_idx].state.Gamepad)) {
+            return SDL_TRUE;
+        }
+    }
+    return SDL_FALSE;
+}
+
+
+static SDL_bool
+RAWINPUT_GuessXInputSlot(const WindowsMatchState *state, Uint8 *correlation_id, Uint8 *slot_idx)
+{
+    int user_index;
+    int match_count;
+
+    *slot_idx = 0;
+
+    match_count = 0;
+    for (user_index = 0; user_index < XUSER_MAX_COUNT; ++user_index) {
+        if (!xinput_state[user_index].used && RAWINPUT_XInputSlotMatches(state, user_index)) {
+            ++match_count;
+            *slot_idx = (Uint8)user_index;
+            /* Incrementing correlation_id for any match, as negative evidence for others being correlated */
+            *correlation_id = ++xinput_state[user_index].correlation_id;
+        }
+    }
+    /* Only return a match if we match exactly one, and we have some non-zero data (buttons or axes) that matched.
+       Note that we're still invalidating *other* potential correlations if we have more than one match or we have no
+       data. */
+    if (match_count == 1 && state->any_data) {
+        return SDL_TRUE;
+    }
+    return SDL_FALSE;
+}
+
+#endif /* SDL_JOYSTICK_RAWINPUT_XINPUT */
+
+#ifdef SDL_JOYSTICK_RAWINPUT_GAMING_INPUT
+
+typedef struct WindowsGamingInputGamepadState {
+    __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
+    struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading state;
+    RAWINPUT_DeviceContext *correlated_context;
+    SDL_bool used; /* Is currently mapped to an SDL device */
+    SDL_bool connected; /* Just used during update to track disconnected */
+    Uint8 correlation_id;
+    struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
+} WindowsGamingInputGamepadState;
+
+static struct {
+    WindowsGamingInputGamepadState **per_gamepad;
+    int per_gamepad_count;
+    SDL_bool initialized;
+    SDL_bool dirty;
+    SDL_bool need_device_list_update;
+    int ref_count;
+    __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics *gamepad_statics;
+} wgi_state;
+
+static void
+RAWINPUT_MarkWindowsGamingInputSlotUsed(WindowsGamingInputGamepadState *wgi_slot, RAWINPUT_DeviceContext *ctx)
+{
+    wgi_slot->used = SDL_TRUE;
+    wgi_slot->correlated_context = ctx;
+}
+
+static void
+RAWINPUT_MarkWindowsGamingInputSlotFree(WindowsGamingInputGamepadState *wgi_slot)
+{
+    wgi_slot->used = SDL_FALSE;
+    wgi_slot->correlated_context = NULL;
+}
+
+static SDL_bool
+RAWINPUT_MissingWindowsGamingInputSlot()
+{
+    int ii;
+    for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
+        if (!wgi_state.per_gamepad[ii]->used) {
+            return SDL_TRUE;
+        }
+    }
+    return SDL_FALSE;
+}
+
+static void
+RAWINPUT_UpdateWindowsGamingInput()
+{
+    int ii;
+    if (!wgi_state.gamepad_statics)
+        return;
+
+    if (!wgi_state.dirty)
+        return;
+
+    wgi_state.dirty = SDL_FALSE;
+
+    if (wgi_state.need_device_list_update) {
+        wgi_state.need_device_list_update = SDL_FALSE;
+        for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
+            wgi_state.per_gamepad[ii]->connected = SDL_FALSE;
+        }
+        HRESULT hr;
+        __FIVectorView_1_Windows__CGaming__CInput__CGamepad *gamepads;
+
+        hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_get_Gamepads(wgi_state.gamepad_statics, &gamepads);
+        if (SUCCEEDED(hr)) {
+            unsigned int num_gamepads;
+
+            hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_get_Size(gamepads, &num_gamepads);
+            if (SUCCEEDED(hr)) {
+                unsigned int i;
+                for (i = 0; i < num_gamepads; ++i) {
+                    __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
+
+                    hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_GetAt(gamepads, i, &gamepad);
+                    if (SUCCEEDED(hr)) {
+                        SDL_bool found = SDL_FALSE;
+                        int jj;
+                        for (jj = 0; jj < wgi_state.per_gamepad_count ; jj++) {
+                            if (wgi_state.per_gamepad[jj]->gamepad == gamepad) {
+                                found = SDL_TRUE;
+                                wgi_state.per_gamepad[jj]->connected = SDL_TRUE;
+                                break;
+                            }
+                        }
+                        if (!found) {
+                            /* New device, add it */
+                            wgi_state.per_gamepad_count++;
+                            wgi_state.per_gamepad = SDL_realloc(wgi_state.per_gamepad, sizeof(wgi_state.per_gamepad[0]) * wgi_state.per_gamepad_count);
+                            if (!wgi_state.per_gamepad) {
+                                SDL_OutOfMemory();
+                                return;
+                            }
+                            WindowsGamingInputGamepadState *gamepad_state = SDL_calloc(1, sizeof(*gamepad_state));
+                            if (!gamepad_state) {
+                                SDL_OutOfMemory();
+                                return;
+                            }
+                            wgi_state.per_gamepad[wgi_state.per_gamepad_count - 1] = gamepad_state;
+                            gamepad_state->gamepad = gamepad;
+                            gamepad_state->connected = SDL_TRUE;
+                        } else {
+                            /* Already tracked */
+                            __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad);
+                        }
+                    }
+                }
+                for (ii = wgi_state.per_gamepad_count - 1; ii >= 0; ii--) {
+                    WindowsGamingInputGamepadState *gamepad_state = wgi_state.per_gamepad[ii];
+                    if (!gamepad_state->connected) {
+                        /* Device missing, must be disconnected */
+                        if (gamepad_state->correlated_context) {
+                            gamepad_state->correlated_context->wgi_correlated = SDL_FALSE;
+                            gamepad_state->correlated_context->wgi_slot = NULL;
+                        }
+                        __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad_state->gamepad);
+                        SDL_free(gamepad_state);
+                        wgi_state.per_gamepad[ii] = wgi_state.per_gamepad[wgi_state.per_gamepad_count - 1];
+                        --wgi_state.per_gamepad_count;
+                    }
+                }
+            }
+            __FIVectorView_1_Windows__CGaming__CInput__CGamepad_Release(gamepads);
+        }
+    } /* need_device_list_update */
+
+    for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
+        HRESULT hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(wgi_state.per_gamepad[ii]->gamepad, &wgi_state.per_gamepad[ii]->state);
+        if (!SUCCEEDED(hr)) {
+            wgi_state.per_gamepad[ii]->connected = SDL_FALSE; /* Not used by anything, currently */
+        }
+    }
+}
+static void
+RAWINPUT_InitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
+{
+    wgi_state.need_device_list_update = SDL_TRUE;
+    wgi_state.ref_count++;
+    if (!wgi_state.initialized) {
+        /* I think this takes care of RoInitialize() in a way that is compatible with the rest of SDL */
+        if (FAILED(WIN_CoInitialize())) {
+            return;
+        }
+        wgi_state.initialized = SDL_TRUE;
+        wgi_state.dirty = SDL_TRUE;
+
+        static const IID SDL_IID_IGamepadStatics = { 0x8BBCE529, 0xD49C, 0x39E9, { 0x95, 0x60, 0xE4, 0x7D, 0xDE, 0x96, 0xB7, 0xC8 } };
+        HRESULT hr;
+        HMODULE hModule = LoadLibraryA("combase.dll");
+        if (hModule != NULL) {
+            typedef HRESULT (WINAPI *WindowsCreateString_t)(PCNZWCH sourceString, UINT32 length, HSTRING* string);
+            typedef HRESULT (WINAPI *WindowsDeleteString_t)(HSTRING string);
+            typedef HRESULT (WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void** factory);
+
+            WindowsCreateString_t WindowsCreateStringFunc = (WindowsCreateString_t)GetProcAddress(hModule, "WindowsCreateString");
+            WindowsDeleteString_t WindowsDeleteStringFunc = (WindowsDeleteString_t)GetProcAddress(hModule, "WindowsDeleteString");
+            RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule, "RoGetActivationFactory");
+            if (WindowsCreateStringFunc && WindowsDeleteStringFunc && RoGetActivationFactoryFunc) {
+                LPTSTR pNamespace = L"Windows.Gaming.Input.Gamepad";
+                HSTRING hNamespaceString;
+
+                hr = WindowsCreateStringFunc(pNamespace, SDL_wcslen(pNamespace), &hNamespaceString);
+                if (SUCCEEDED(hr)) {
+                    RoGetActivationFactoryFunc(hNamespaceString, &SDL_IID_IGamepadStatics, &wgi_state.gamepad_statics);
+                    WindowsDeleteStringFunc(hNamespaceString);
+                }
+            }
+            FreeLibrary(hModule);
+        }
+    }
+}
+
+static SDL_bool
+RAWINPUT_WindowsGamingInputSlotMatches(const WindowsMatchState *state, WindowsGamingInputGamepadState *slot)
+{
+    Uint32 wgi_buttons = slot->state.Buttons;
+    if ((wgi_buttons & 0x3FFF) == state->wgi_buttons && WindowsGamingInputAxesMatch(slot->state)) {
+        return SDL_TRUE;
+    }
+    return SDL_FALSE;
+}
+
+static SDL_bool
+RAWINPUT_GuessWindowsGamingInputSlot(const WindowsMatchState *state, Uint8 *correlation_id, WindowsGamingInputGamepadState **slot)
+{
+    int match_count;
+
+    match_count = 0;
+    for (int user_index = 0; user_index < wgi_state.per_gamepad_count; ++user_index) {
+        WindowsGamingInputGamepadState *gamepad_state = wgi_state.per_gamepad[user_index];
+        if (RAWINPUT_WindowsGamingInputSlotMatches(state, gamepad_state)) {
+            ++match_count;
+            *slot = gamepad_state;
+            /* Incrementing correlation_id for any match, as negative evidence for others being correlated */
+            *correlation_id = ++gamepad_state->correlation_id;
+        }
+    }
+    /* Only return a match if we match exactly one, and we have some non-zero data (buttons or axes) that matched.
+       Note that we're still invalidating *other* potential correlations if we have more than one match or we have no
+       data. */
+    if (match_count == 1 && state->any_data) {
+        return SDL_TRUE;
+    }
+    return SDL_FALSE;
+}
+
+static void
+RAWINPUT_QuitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
+{
+    wgi_state.need_device_list_update = SDL_TRUE;
+    --wgi_state.ref_count;
+    if (!wgi_state.ref_count && wgi_state.initialized) {
+        for (int ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
+            __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(wgi_state.per_gamepad[ii]->gamepad);
+        }
+        if (wgi_state.per_gamepad) {
+            SDL_free(wgi_state.per_gamepad);
+            wgi_state.per_gamepad = NULL;
+        }
+        wgi_state.per_gamepad_count = 0;
+        if (wgi_state.gamepad_statics) {
+            __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(wgi_state.gamepad_statics);
+            wgi_state.gamepad_statics = NULL;
+        }
+        WIN_CoUninitialize();
+        wgi_state.initialized = SDL_FALSE;
+    }
+}
+
+#endif /* SDL_JOYSTICK_RAWINPUT_GAMING_INPUT */
+
 static int
 RAWINPUT_JoystickInit(void)
 {
@@ -191,15 +620,16 @@ RAWINPUT_JoystickInit(void)
     SDL_assert(!SDL_RAWINPUT_inited);
     SDL_assert(SDL_HelperWindow);
 
-    if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT, SDL_TRUE))
+    if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT, SDL_TRUE)) {
         return -1;
+    }
 
-    if (!RAWINPUT_AllXInputDevicesSupported()) {
+    if (WIN_LoadHIDDLL() < 0) {
         return -1;
     }
 
     for (ii = 0; ii < SDL_arraysize(subscribed_devices); ii++) {
-        rid[ii].usUsagePage = USAGE_PAGE_GENERIC_DESKTOP;
+        rid[ii].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
         rid[ii].usUsage = subscribed_devices[ii];
         rid[ii].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; /* Receive messages when in background, including device add/remove */
         rid[ii].hwndTarget = SDL_HelperWindow;
@@ -207,6 +637,7 @@ RAWINPUT_JoystickInit(void)
 
     if (!RegisterRawInputDevices(rid, SDL_arraysize(rid), sizeof(RAWINPUTDEVICE))) {
         SDL_SetError("Couldn't initialize RAWINPUT");
+        WIN_UnloadHIDDLL();
         return -1;
     }
 
@@ -234,6 +665,9 @@ static void
 RAWINPUT_ReleaseDevice(SDL_RAWINPUT_Device *device)
 {
     if (SDL_AtomicDecRef(&device->refcount)) {
+        if (device->preparsed_data) {
+            SDL_HidD_FreePreparsedData(device->preparsed_data);
+        }
         SDL_free(device->name);
         SDL_free(device);
     }
@@ -251,47 +685,22 @@ RAWINPUT_DeviceFromHandle(HANDLE hDevice)
     return NULL;
 }
 
-static SDL_HIDAPI_DeviceDriver *
-RAWINPUT_GetDeviceDriver(SDL_RAWINPUT_Device *device)
-{
-    int i;
-    SDL_GameControllerType type;
-
-    if (SDL_ShouldIgnoreJoystick(device->name, device->guid)) {
-        return NULL;
-    }
-
-    if (device->usage_page && device->usage_page != USAGE_PAGE_GENERIC_DESKTOP) {
-        return NULL;
-    }
-    if (device->usage && device->usage != USAGE_JOYSTICK && device->usage != USAGE_GAMEPAD && device->usage != USAGE_MULTIAXISCONTROLLER) {
-        return NULL;
-    }
-
-    type = SDL_GetJoystickGameControllerType("", device->vendor_id, device->product_id, -1, 0, 0, 0);
-
-    for (i = 0; i < SDL_arraysize(SDL_RAWINPUT_drivers); ++i) {
-        SDL_HIDAPI_DeviceDriver *driver = SDL_RAWINPUT_drivers[i];
-        if (/*driver->enabled && */driver->IsSupportedDevice(NULL, type, device->vendor_id, device->product_id, device->version, -1, 0, 0, 0)) {
-            return driver;
-        }
-    }
-    return NULL;
-}
-
 static void
 RAWINPUT_AddDevice(HANDLE hDevice)
 {
 #define CHECK(exp) { if(!(exp)) goto err; }
     SDL_RAWINPUT_Device *device = NULL;
+    SDL_RAWINPUT_Device *curr, *last;
     RID_DEVICE_INFO rdi;
     UINT rdi_size = sizeof(rdi);
-    char dev_name[128];
+    char dev_name[MAX_PATH];
     UINT name_size = SDL_arraysize(dev_name);
-    const char *name;
-    SDL_RAWINPUT_Device *curr, *last;
+    HANDLE hFile = INVALID_HANDLE_VALUE;
 
-    SDL_assert(!RAWINPUT_DeviceFromHandle(hDevice));
+    /* Make sure we're not trying to add the same device twice */
+    if (RAWINPUT_DeviceFromHandle(hDevice)) {
+        return;
+    }
 
     /* Figure out what kind of device it is */
     CHECK(GetRawInputDeviceInfoA(hDevice, RIDI_DEVICEINFO, &rdi, &rdi_size) != (UINT)-1);
@@ -301,14 +710,17 @@ RAWINPUT_AddDevice(HANDLE hDevice)
     CHECK(GetRawInputDeviceInfoA(hDevice, RIDI_DEVICENAME, dev_name, &name_size) != (UINT)-1);
     /* Only take XInput-capable devices */
     CHECK(SDL_strstr(dev_name, "IG_") != NULL);
+#ifdef SDL_JOYSTICK_HIDAPI
+    /* Don't take devices handled by HIDAPI */
+    CHECK(!HIDAPI_IsDevicePresent((Uint16)rdi.hid.dwVendorId, (Uint16)rdi.hid.dwProductId, (Uint16)rdi.hid.dwVersionNumber, ""));
+#endif
 
-    CHECK(device = SDL_callocStruct(SDL_RAWINPUT_Device));
+    CHECK(device = (SDL_RAWINPUT_Device *)SDL_calloc(1, sizeof(SDL_RAWINPUT_Device)));
     device->hDevice = hDevice;
     device->vendor_id = (Uint16)rdi.hid.dwVendorId;
     device->product_id = (Uint16)rdi.hid.dwProductId;
     device->version = (Uint16)rdi.hid.dwVersionNumber;
-    device->usage = rdi.hid.usUsage;
-    device->usage_page = rdi.hid.usUsagePage;
+    device->is_xinput = SDL_TRUE;
 
     {
         const Uint16 vendor = device->vendor_id;
@@ -330,36 +742,19 @@ RAWINPUT_AddDevice(HANDLE hDevice)
         device->guid.data[15] = 0;
     }
 
-    CHECK(device->driver = RAWINPUT_GetDeviceDriver(device));
+    hFile = CreateFileA(dev_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+    CHECK(hFile != INVALID_HANDLE_VALUE);
 
-    name = device->driver->GetDeviceName(device->vendor_id, device->product_id);
-    if (name) {
-        device->name = SDL_strdup(name);
-    } else {
+    {
         char *manufacturer_string = NULL;
         char *product_string = NULL;
-        HMODULE hHID;
+        WCHAR string[128];
 
-        hHID = LoadLibrary( TEXT( "hid.dll" ) );
-        if (hHID) {
-            typedef BOOLEAN (WINAPI * HidD_GetStringFunc)(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength);
-            HidD_GetStringFunc GetManufacturerString = (HidD_GetStringFunc)GetProcAddress(hHID, "HidD_GetManufacturerString");
-            HidD_GetStringFunc GetProductString = (HidD_GetStringFunc)GetProcAddress(hHID, "HidD_GetProductString");
-            if (GetManufacturerString && GetProductString) {
-                HANDLE hFile = CreateFileA(dev_name, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
-                if (hFile != INVALID_HANDLE_VALUE) {
-                    WCHAR string[128];
-
-                    if (GetManufacturerString(hFile, string, sizeof(string))) {
-                        manufacturer_string = WIN_StringToUTF8(string);
-                    }
-                    if (GetProductString(hFile, string, sizeof(string))) {
-                        product_string = WIN_StringToUTF8(string);
-                    }
-                    CloseHandle(hFile);
-                }
-            }
-            FreeLibrary(hHID);
+        if (SDL_HidD_GetManufacturerString(hFile, string, sizeof(string))) {
+            manufacturer_string = WIN_StringToUTF8(string);
+        }
+        if (SDL_HidD_GetProductString(hFile, string, sizeof(string))) {
+            product_string = WIN_StringToUTF8(string);
         }
 
         device->name = SDL_CreateJoystickName(device->vendor_id, device->product_id, manufacturer_string, product_string);
@@ -372,6 +767,14 @@ RAWINPUT_AddDevice(HANDLE hDevice)
         }
     }
 
+    CHECK(SDL_HidD_GetPreparsedData(hFile, &device->preparsed_data));
+
+    CloseHandle(hFile);
+    hFile = INVALID_HANDLE_VALUE;
+
+    device->joystick_id = SDL_GetNextJoystickInstanceID();
+
+#define DEBUG_RAWINPUT
 #ifdef DEBUG_RAWINPUT
     SDL_Log("Adding RAWINPUT device '%s' VID 0x%.4x, PID 0x%.4x, version %d, handle 0x%.8x\n", device->name, device->vendor_id, device->product_id, device->version, device->hDevice);
 #endif
@@ -388,19 +791,21 @@ RAWINPUT_AddDevice(HANDLE hDevice)
     }
 
     ++SDL_RAWINPUT_numjoysticks;
-    /* HIDAPI_JoystickConnected calls SDL_GetNextJoystickInstanceID() and SDL_PrivateJoystickAdded(), and calls back in to us, so
-      the device list must be updated before calling this. */
-    CHECK(HIDAPI_JoystickConnected(&device->hiddevice, &device->joystick_id, SDL_TRUE));
-    /* Old: CHECK(device->driver->InitDevice(&device->hiddevice)); But, we need the joystick_id */
+
+    SDL_PrivateJoystickAdded(device->joystick_id);
 
     return;
 
 err:
+    if (hFile != INVALID_HANDLE_VALUE) {
+        CloseHandle(hFile);
+    }
     if (device) {
         if (device->name)
             SDL_free(device->name);
         SDL_free(device);
     }
+#undef CHECK
 }
 
 static void
@@ -416,8 +821,7 @@ RAWINPUT_DelDevice(SDL_RAWINPUT_Device *device, SDL_bool send_event)
             }
             --SDL_RAWINPUT_numjoysticks;
 
-            /* Calls SDL_PrivateJoystickRemoved() */
-            HIDAPI_JoystickDisconnected(&device->hiddevice, device->joystick_id, SDL_TRUE);
+            SDL_PrivateJoystickRemoved(device->joystick_id);
 
 #ifdef DEBUG_RAWINPUT
             SDL_Log("Removing RAWINPUT device '%s' VID 0x%.4x, PID 0x%.4x, version %d, handle 0x%.8x\n", device->name, device->vendor_id, device->product_id, device->version, device->hDevice);
@@ -453,24 +857,70 @@ RAWINPUT_UpdateDeviceList(void)
     }
 }
 
-static SDL_bool
-RAWINPUT_IsDeviceSupported(Uint16 vendor_id, Uint16 product_id, Uint16 version)
+static void
+RAWINPUT_PostUpdate(void)
 {
-    int i;
+#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
+    SDL_bool unmapped_guide_pressed = SDL_FALSE;
 
-    SDL_GameControllerType type = SDL_GetJoystickGameControllerType("", vendor_id, product_id, -1, 0, 0, 0);
-
-    for (i = 0; i < SDL_arraysize(SDL_RAWINPUT_drivers); ++i) {
-        SDL_HIDAPI_DeviceDriver *driver = SDL_RAWINPUT_drivers[i];
-        /* Ignoring driver->enabled here, and elsewhere in this file, as the if the driver is enabled by disabling HID,
-            we still want RawInput to use it.  If we end up with more than one RawInput driver, we may need to rework
-            how the hints interact (separate enabled state, perhaps).
-        */
-        if (/*driver->enabled && */driver->IsSupportedDevice(NULL, type, vendor_id, product_id, version, -1, 0, 0, 0)) {
-            return SDL_TRUE;
+#ifdef SDL_JOYSTICK_RAWINPUT_GAMING_INPUT
+    if (!wgi_state.dirty) {
+        int ii;
+        for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
+            WindowsGamingInputGamepadState *gamepad_state = wgi_state.per_gamepad[ii];
+            if (!gamepad_state->used && (gamepad_state->state.Buttons & GamepadButtons_GUIDE)) {
+                unmapped_guide_pressed = SDL_TRUE;
+                break;
+            }
         }
     }
-    return SDL_FALSE;
+    wgi_state.dirty = SDL_TRUE;
+#endif
+
+
+#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
+    if (!xinput_state_dirty) {
+        int ii;
+        for (ii = 0; ii < SDL_arraysize(xinput_state); ii++) {
+            if (xinput_state[ii].connected && !xinput_state[ii].used && (xinput_state[ii].state.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE)) {
+                unmapped_guide_pressed = SDL_TRUE;
+                break;
+            }
+        }
+    }
+    xinput_state_dirty = SDL_TRUE;
+#endif
+
+    if (unmapped_guide_pressed) {
+        if (guide_button_candidate.joystick && !guide_button_candidate.last_joystick) {
+            SDL_Joystick *joystick = guide_button_candidate.joystick;
+            RAWINPUT_DeviceContext *ctx = joystick->hwdata;
+            if (ctx->guide_hack) {
+                int guide_button = joystick->nbuttons - 1;
+
+                SDL_PrivateJoystickButton(guide_button_candidate.joystick, guide_button, SDL_PRESSED);
+            }
+            guide_button_candidate.last_joystick = guide_button_candidate.joystick;
+        }
+    } else if (guide_button_candidate.last_joystick) {
+        SDL_Joystick *joystick = guide_button_candidate.last_joystick;
+        RAWINPUT_DeviceContext *ctx = joystick->hwdata;
+        if (ctx->guide_hack) {
+            int guide_button = joystick->nbuttons - 1;
+
+            SDL_PrivateJoystickButton(joystick, guide_button, SDL_RELEASED);
+        }
+        guide_button_candidate.last_joystick = NULL;
+    }
+    guide_button_candidate.joystick = NULL;
+
+#endif /* SDL_JOYSTICK_RAWINPUT_MATCHING */
+}
+
+SDL_bool
+RAWINPUT_IsEnabled()
+{
+    return SDL_RAWINPUT_inited;
 }
 
 SDL_bool
@@ -478,11 +928,6 @@ RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version)
 {
     SDL_RAWINPUT_Device *device;
 
-    /* Don't update the device list for devices we know aren't supported */
-    if (!RAWINPUT_IsDeviceSupported(vendor_id, product_id, version)) {
-        return SDL_FALSE;
-    }
-
     /* Make sure the device list is completely up to date when we check for device presence */
     RAWINPUT_UpdateDeviceList();
 
@@ -499,138 +944,306 @@ RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version)
 static void
 RAWINPUT_JoystickDetect(void)
 {
-    int i;
     /* Just ensure the window's add/remove messages have been pumped */
     RAWINPUT_UpdateDeviceList();
 
-    for (i = 0; i < SDL_arraysize(SDL_RAWINPUT_drivers); ++i) {
-        SDL_HIDAPI_DeviceDriver *driver = SDL_RAWINPUT_drivers[i];
-        /* Running PostUpdate here only if it's *not* enabled (and ran elsewhere) */
-        if (!driver->enabled && driver->PostUpdate) {
-            driver->PostUpdate();
-        }
-    }
+    RAWINPUT_PostUpdate();
+
     SDL_RAWINPUT_need_pump = SDL_TRUE;
 }
 
 static SDL_RAWINPUT_Device *
-RAWINPUT_GetJoystickByIndex(int device_index, SDL_JoystickID *pJoystickID)
+RAWINPUT_GetDeviceByIndex(int device_index)
 {
     SDL_RAWINPUT_Device *device = SDL_RAWINPUT_devices;
     while (device) {
-        if (device->driver) {
-            SDL_assert(device->hiddevice.num_joysticks == 1);
-            if (device_index < device->hiddevice.num_joysticks) {
-                if (pJoystickID) {
-                    *pJoystickID = device->hiddevice.joysticks[device_index];
-                }
-                return device;
-            }
-            device_index -= device->hiddevice.num_joysticks;
+        if (device_index == 0) {
+            break;
         }
+        --device_index;
         device = device->next;
     }
-    return NULL;
+    return device;
 }
 
 static const char *
 RAWINPUT_JoystickGetDeviceName(int device_index)
 {
-    return RAWINPUT_GetJoystickByIndex(device_index, NULL)->name;
+    return RAWINPUT_GetDeviceByIndex(device_index)->name;
 }
 
 static int
 RAWINPUT_JoystickGetDevicePlayerIndex(int device_index)
 {
-    SDL_RAWINPUT_Device *device;
-    SDL_JoystickID instance_id;
-    int player_index = -1;
-
-    device = RAWINPUT_GetJoystickByIndex(device_index, &instance_id);
-    if (device && device->driver) {
-        player_index = device->driver->GetDevicePlayerIndex(&device->hiddevice, instance_id);
-    }
-
-    return player_index;
+    return -1;
 }
 
 static void
 RAWINPUT_JoystickSetDevicePlayerIndex(int device_index, int player_index)
 {
-    SDL_RAWINPUT_Device *device;
-    SDL_JoystickID instance_id;
-
-    device = RAWINPUT_GetJoystickByIndex(device_index, &instance_id);
-    if (device) {
-        device->driver->SetDevicePlayerIndex(&device->hiddevice, instance_id, player_index);
-    }
 }
 
 
 static SDL_JoystickGUID
 RAWINPUT_JoystickGetDeviceGUID(int device_index)
 {
-    return RAWINPUT_GetJoystickByIndex(device_index, NULL)->guid;
+    return RAWINPUT_GetDeviceByIndex(device_index)->guid;
 }
 
 static SDL_JoystickID
 RAWINPUT_JoystickGetDeviceInstanceID(int device_index)
 {
-    SDL_JoystickID instance_id = -1;
-    RAWINPUT_GetJoystickByIndex(device_index, &instance_id);
-    return instance_id;
+    return RAWINPUT_GetDeviceByIndex(device_index)->joystick_id;
 }
 
 static int
-RAWINPUT_JoystickOpen(SDL_Joystick * joystick, int device_index)
+RAWINPUT_JoystickOpen(SDL_Joystick *joystick, int device_index)
 {
-    SDL_RAWINPUT_Device *device = RAWINPUT_GetJoystickByIndex(device_index, NULL);
-    struct joystick_hwdata *hwdata = SDL_callocStruct(struct joystick_hwdata);
+    SDL_RAWINPUT_Device *device = RAWINPUT_GetDeviceByIndex(device_index);
+    RAWINPUT_DeviceContext *ctx;
+    HIDP_CAPS caps;
+    HIDP_BUTTON_CAPS *button_caps;
+    HIDP_VALUE_CAPS *value_caps;
+    ULONG i;
 
-    if (!hwdata) {
+    ctx = (RAWINPUT_DeviceContext *)SDL_calloc(1, sizeof(RAWINPUT_DeviceContext));
+    if (!ctx) {
+        return SDL_OutOfMemory();
+    }
+    joystick->hwdata = ctx;
+
+    ctx->device = RAWINPUT_AcquireDevice(device);
+    device->joystick = joystick;
+
+    if (device->is_xinput) {
+        /* We'll try to get guide button and trigger axes from XInput */
+#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
+        xinput_device_change = SDL_TRUE;
+        ctx->xinput_enabled = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_CORRELATE_XINPUT, SDL_TRUE);
+        if (ctx->xinput_enabled && (WIN_LoadXInputDLL() < 0 || !XINPUTGETSTATE)) {
+            ctx->xinput_enabled = SDL_FALSE;
+        }
+        ctx->xinput_slot = XUSER_INDEX_ANY;
+#endif
+#ifdef SDL_JOYSTICK_RAWINPUT_GAMING_INPUT
+        RAWINPUT_InitWindowsGamingInput(ctx);
+#endif
+    }
+
+    ctx->is_xinput = device->is_xinput;
+    ctx->preparsed_data = device->preparsed_data;
+    ctx->max_data_length = SDL_HidP_MaxDataListLength(HidP_Input, ctx->preparsed_data);
+    ctx->data = (HIDP_DATA *)SDL_malloc(ctx->max_data_length * sizeof(*ctx->data));
+    if (!ctx->data) {
+        RAWINPUT_JoystickClose(joystick);
         return SDL_OutOfMemory();
     }
 
-    if (!device->driver->OpenJoystick(&device->hiddevice, joystick)) {
-        SDL_free(hwdata);
-        return -1;
+    if (SDL_HidP_GetCaps(ctx->preparsed_data, &caps) != HIDP_STATUS_SUCCESS) {
+        RAWINPUT_JoystickClose(joystick);
+        return SDL_SetError("Couldn't get device capabilities");
     }
 
-    hwdata->reserved = (void*)-1; /* crash if some code slips by that tries to use this */
-    hwdata->device = RAWINPUT_AcquireDevice(device);
-    device->joystick = joystick;
+    button_caps = SDL_stack_alloc(HIDP_BUTTON_CAPS, caps.NumberInputButtonCaps);
+    if (SDL_HidP_GetButtonCaps(HidP_Input, button_caps, &caps.NumberInputButtonCaps, ctx->preparsed_data) != HIDP_STATUS_SUCCESS) {
+        RAWINPUT_JoystickClose(joystick);
+        return SDL_SetError("Couldn't get device button capabilities");
+    }
 
-    joystick->hwdata = hwdata;
+    value_caps = SDL_stack_alloc(HIDP_VALUE_CAPS, caps.NumberInputValueCaps);
+    if (SDL_HidP_GetValueCaps(HidP_Input, value_caps, &caps.NumberInputValueCaps, ctx->preparsed_data) != HIDP_STATUS_SUCCESS) {
+        RAWINPUT_JoystickClose(joystick);
+        return SDL_SetError("Couldn't get device value capabilities");
+    }
+
+    for (i = 0; i < caps.NumberInputButtonCaps; ++i) {
+        HIDP_BUTTON_CAPS *cap = &button_caps[i];
+
+        if (cap->UsagePage == USB_USAGEPAGE_BUTTON) {
+            int count;
+
+            if (cap->IsRange) {
+                count = 1 + (cap->Range.DataIndexMax - cap->Range.DataIndexMin);
+            } else {
+                count = 1;
+            }
+
+            joystick->nbuttons += count;
+        }
+    }
+
+    if (joystick->nbuttons > 0) {
+        int button_index = 0;
+
+        ctx->button_indices = (USHORT *)SDL_malloc(joystick->nbuttons * sizeof(*ctx->button_indices));
+        if (!ctx->button_indices) {
+            RAWINPUT_JoystickClose(joystick);
+            return SDL_OutOfMemory();
+        }
+
+        for (i = 0; i < caps.NumberInputButtonCaps; ++i) {
+            HIDP_BUTTON_CAPS *cap = &button_caps[i];
+
+            if (cap->UsagePage == USB_USAGEPAGE_BUTTON) {
+                if (cap->IsRange) {
+                    int j, count = 1 + (cap->Range.DataIndexMax - cap->Range.DataIndexMin);
+
+                    for (j = 0; j < count; ++j) {
+                        ctx->button_indices[button_index++] = cap->Range.DataIndexMin + j;
+                    }
+                } else {
+                    ctx->button_indices[button_index++] = cap->NotRange.DataIndex;
+                }
+            }
+        }
+    }
+    if (ctx->is_xinput && joystick->nbuttons == 10) {
+        ctx->guide_hack = SDL_TRUE;
+        joystick->nbuttons += 1;
+    }
+
+    for (i = 0; i < caps.NumberInputValueCaps; ++i) {
+        HIDP_VALUE_CAPS *cap = &value_caps[i];
+
+        if (cap->IsRange) {
+            continue;
+        }
+
+        if (ctx->trigger_hack && cap->NotRange.Usage == USB_USAGE_GENERIC_Z) {
+            continue;
+        }
+
+        if (cap->NotRange.Usage == USB_USAGE_GENERIC_HAT) {
+            joystick->nhats += 1;
+            continue;
+        }
+
+        if (ctx->is_xinput && cap->NotRange.Usage == USB_USAGE_GENERIC_Z) {
+            continue;
+        }
+
+        joystick->naxes += 1;
+    }
+
+    if (joystick->naxes > 0) {
+        int axis_index = 0;
+
+        ctx->axis_indices = (USHORT *)SDL_malloc(joystick->naxes * sizeof(*ctx->axis_indices));
+        if (!ctx->axis_indices) {
+            RAWINPUT_JoystickClose(joystick);
+            return SDL_OutOfMemory();
+        }
+
+        for (i = 0; i < caps.NumberInputValueCaps; ++i) {
+            HIDP_VALUE_CAPS *cap = &value_caps[i];
+
+            if (cap->IsRange) {
+                continue;
+            }
+
+            if (cap->NotRange.Usage == USB_USAGE_GENERIC_HAT) {
+                continue;
+            }
+
+            if (ctx->is_xinput && cap->NotRange.Usage == USB_USAGE_GENERIC_Z) {
+                ctx->trigger_hack = SDL_TRUE;
+                ctx->trigger_hack_index = cap->NotRange.DataIndex;
+                continue;
+            }
+
+            ctx->axis_indices[axis_index++] = cap->NotRange.DataIndex;
+        }
+    }
+    if (ctx->trigger_hack) {
+        joystick->naxes += 2;
+    }
+
+    if (joystick->nhats > 0) {
+        int hat_index = 0;
+
+        ctx->hat_indices = (USHORT *)SDL_malloc(joystick->nhats * sizeof(*ctx->hat_indices));
+        if (!ctx->hat_indices) {
+            RAWINPUT_JoystickClose(joystick);
+            return SDL_OutOfMemory();
+        }
+
+        for (i = 0; i < caps.NumberInputValueCaps; ++i) {
+            HIDP_VALUE_CAPS *cap = &value_caps[i];
+
+            if (cap->IsRange) {
+                continue;
+            }
+
+            if (cap->NotRange.Usage != USB_USAGE_GENERIC_HAT) {
+                continue;
+            }
+
+            ctx->hat_indices[hat_index++] = cap->NotRange.DataIndex;
+        }
+    }
+
+    joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
 
     return 0;
 }
 
 static int
-RAWINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
+RAWINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
 {
-    struct joystick_hwdata *hwdata = joystick->hwdata;
-    SDL_RAWINPUT_Device *device = hwdata->device;
+#if defined(SDL_JOYSTICK_RAWINPUT_GAMING_INPUT) || defined(SDL_JOYSTICK_RAWINPUT_XINPUT)
+    RAWINPUT_DeviceContext *ctx = joystick->hwdata;
+#endif
 
-    return device->driver->RumbleJoystick(&device->hiddevice, joystick, low_frequency_rumble, high_frequency_rumble);
+    SDL_bool rumbled = SDL_FALSE;
+
+#ifdef SDL_JOYSTICK_RAWINPUT_GAMING_INPUT
+    if (!rumbled && ctx->wgi_correlated) {
+        WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
+        HRESULT hr;
+        gamepad_state->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
+        gamepad_state->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
+        hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, gamepad_state->vibration);
+        if (SUCCEEDED(hr)) {
+            rumbled = SDL_TRUE;
+        }
+    }
+#endif
+
+#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
+    if (!rumbled && ctx->xinput_correlated) {
+        XINPUT_VIBRATION XVibration;
+
+        if (!XINPUTSETSTATE) {
+            return SDL_Unsupported();
+        }
+
+        XVibration.wLeftMotorSpeed = low_frequency_rumble;
+        XVibration.wRightMotorSpeed = high_frequency_rumble;
+        if (XINPUTSETSTATE(ctx->xinput_slot, &XVibration) == ERROR_SUCCESS) {
+            rumbled = SDL_TRUE;
+        } else {
+            return SDL_SetError("XInputSetState() failed");
+        }
+    }
+#endif /* SDL_JOYSTICK_RAWINPUT_XINPUT */
+
+    return 0;
 }
 
 static int
-RAWINPUT_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
+RAWINPUT_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
 {
-    struct joystick_hwdata *hwdata = joystick->hwdata;
-    SDL_RAWINPUT_Device *device = hwdata->device;
-
-    return device->driver->RumbleJoystickTriggers(&device->hiddevice, joystick, left_rumble, right_rumble);
+    return SDL_Unsupported();
 }
 
 static SDL_bool
-RAWINPUT_JoystickHasLED(SDL_Joystick * joystick)
+RAWINPUT_JoystickHasLED(SDL_Joystick *joystick)
 {
     return SDL_FALSE;
 }
 
 static int
-RAWINPUT_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue)
+RAWINPUT_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
 {
     return SDL_Unsupported();
 }
@@ -641,37 +1254,445 @@ RAWINPUT_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
     return SDL_Unsupported();
 }
 
-
-static void
-RAWINPUT_JoystickUpdate(SDL_Joystick * joystick)
+static HIDP_DATA *GetData(USHORT index, HIDP_DATA *data, ULONG length)
 {
-    struct joystick_hwdata *hwdata;
-    SDL_RAWINPUT_Device *device;
-    /* Ensure data messages have been pumped */
-    RAWINPUT_PumpMessages();
-    hwdata = joystick->hwdata;
-    device = hwdata->device;
+    ULONG i;
 
-    device->driver->UpdateDevice(&device->hiddevice);
+    /* Check to see if the data is at the expected offset */
+    if (index < length && data[index].DataIndex == index) {
+        return &data[index];
+    }
+
+    /* Loop through the data to find it */
+    for (i = 0; i < length; ++i) {
+        if (data[i].DataIndex == index) {
+            return &data[i];
+        }
+    }
+    return NULL;
+}
+
+/* This is the packet format for Xbox 360 and Xbox One controllers on Windows,
+   however with this interface there is no rumble support, no guide button,
+   and the left and right triggers are tied together as a single axis.
+
+   We use XInput and Windows.Gaming.Input to make up for these shortcomings.
+ */
+static void
+RAWINPUT_HandleStatePacket(SDL_Joystick *joystick, Uint8 *data, int size)
+{
+    RAWINPUT_DeviceContext *ctx = joystick->hwdata;
+#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
+    /* Map new buttons and axes into game controller controls */
+    static int axis_map[] = {
+        SDL_CONTROLLER_AXIS_LEFTY,
+        SDL_CONTROLLER_AXIS_LEFTX,
+        SDL_CONTROLLER_AXIS_RIGHTY,
+        SDL_CONTROLLER_AXIS_RIGHTX
+    };
+    static int button_map[] = {
+        SDL_CONTROLLER_BUTTON_A,
+        SDL_CONTROLLER_BUTTON_B,
+        SDL_CONTROLLER_BUTTON_X,
+        SDL_CONTROLLER_BUTTON_Y,
+        SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
+        SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
+        SDL_CONTROLLER_BUTTON_BACK,
+        SDL_CONTROLLER_BUTTON_START,
+        SDL_CONTROLLER_BUTTON_LEFTSTICK,
+        SDL_CONTROLLER_BUTTON_RIGHTSTICK
+    };
+    Uint32 match_state = ctx->match_state;
+    /* Update match_state with button bit, then fall through */
+#define SDL_PrivateJoystickButton(joystick, button, state) if (button < SDL_arraysize(button_map)) if (state) match_state |= 1 << button_map[button]; else match_state &= ~(1 << button_map[button]); SDL_PrivateJoystickButton(joystick, button, state)
+    /* Grab high 4 bits of value, then fall through */
+#define SDL_PrivateJoystickAxis(joystick, axis, value) if (axis < SDL_arraysize(axis_map)) match_state = (match_state & ~(0xF << (4 * axis_map[axis] + 16))) | ((value) & 0xF000) << (4 * axis_map[axis] + 4); SDL_PrivateJoystickAxis(joystick, axis, value)
+#endif
+    ULONG data_length = ctx->max_data_length;
+    int i;
+    int nbuttons = joystick->nbuttons - (ctx->guide_hack * 1);
+    int naxes = joystick->naxes - (ctx->trigger_hack * 2);
+    int nhats = joystick->nhats;
+    Uint32 button_mask = 0;
+
+    if (SDL_HidP_GetData(HidP_Input, ctx->data, &data_length, ctx->preparsed_data, (PCHAR)data, size) != HIDP_STATUS_SUCCESS) {
+        return;
+    }
+
+    for (i = 0; i < nbuttons; ++i) {
+        HIDP_DATA *item = GetData(ctx->button_indices[i], ctx->data, data_length);
+        if (item && item->On) {
+            button_mask |= (1 << i);
+        }
+    }
+    for (i = 0; i < nbuttons; ++i) {
+        SDL_PrivateJoystickButton(joystick, i, (button_mask & (1 << i)) ? SDL_PRESSED : SDL_RELEASED);
+    }
+
+    for (i = 0; i < naxes; ++i) {
+        HIDP_DATA *item = GetData(ctx->axis_indices[i], ctx->data, data_length);
+        if (item) {
+            Sint16 axis = (int)(Uint16)item->RawValue - 0x8000;
+            SDL_PrivateJoystickAxis(joystick, i, axis);
+        }
+    }
+
+    for (i = 0; i < nhats; ++i) {
+        HIDP_DATA *item = GetData(ctx->hat_indices[i], ctx->data, data_length);
+        if (item) {
+            const Uint8 hat_states[] = {
+                SDL_HAT_CENTERED,
+                SDL_HAT_UP,
+                SDL_HAT_UP | SDL_HAT_RIGHT,
+                SDL_HAT_RIGHT,
+                SDL_HAT_DOWN | SDL_HAT_RIGHT,
+                SDL_HAT_DOWN,
+                SDL_HAT_DOWN | SDL_HAT_LEFT,
+                SDL_HAT_LEFT,
+                SDL_HAT_UP | SDL_HAT_LEFT,
+            };
+            ULONG state = item->RawValue;
+
+            if (state < SDL_arraysize(hat_states)) {
+                SDL_PrivateJoystickHat(joystick, i, hat_states[state]);
+            }
+        }
+    }
+
+#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
+#undef SDL_PrivateJoystickButton
+#undef SDL_PrivateJoystickAxis
+#endif
+
+    if (ctx->trigger_hack) {
+        SDL_bool has_trigger_data = SDL_FALSE;
+
+#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
+        /* Prefer XInput over WindowsGamingInput, it continues to provide data in the background */
+        if (!has_trigger_data && ctx->xinput_enabled && ctx->xinput_correlated) {
+            has_trigger_data = SDL_TRUE;
+        }
+#endif /* SDL_JOYSTICK_RAWINPUT_XINPUT */
+
+#ifdef SDL_JOYSTICK_RAWINPUT_GAMING_INPUT
+        if (!has_trigger_data && ctx->wgi_correlated) {
+            has_trigger_data = SDL_TRUE;
+        }
+#endif /* SDL_JOYSTICK_RAWINPUT_GAMING_INPUT */
+
+        if (!has_trigger_data) {
+            HIDP_DATA *item = GetData(ctx->trigger_hack_index, ctx->data, data_length);
+            if (item) {
+                int left_trigger = joystick->naxes - 2;
+                int right_trigger = joystick->naxes - 1;
+                Sint16 value = (int)(Uint16)item->RawValue - 0x8000;
+                if (value < 0) {
+                    value = -value * 2 - 32769;
+                    SDL_PrivateJoystickAxis(joystick, left_trigger, SDL_MIN_SINT16);
+                    SDL_PrivateJoystickAxis(joystick, right_trigger, value);
+                } else if (value > 0) {
+                    value = value * 2 - 32767;
+                    SDL_PrivateJoystickAxis(joystick, left_trigger, value);
+                    SDL_PrivateJoystickAxis(joystick, right_trigger, SDL_MIN_SINT16);
+                } else {
+                    SDL_PrivateJoystickAxis(joystick, left_trigger, SDL_MIN_SINT16);
+                    SDL_PrivateJoystickAxis(joystick, right_trigger, SDL_MIN_SINT16);
+                }
+            }
+        }
+    }
+
+#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
+    if (ctx->is_xinput) {
+        ctx->match_state = match_state;
+        ctx->last_state_packet = SDL_GetTicks();
+    }
+#endif
 }
 
 static void
-RAWINPUT_JoystickClose(SDL_Joystick * joystick)
+RAWINPUT_UpdateOtherAPIs(SDL_Joystick *joystick)
 {
-    struct joystick_hwdata *hwdata = joystick->hwdata;
+#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
+    RAWINPUT_DeviceContext *ctx = joystick->hwdata;
+    SDL_bool has_trigger_data = SDL_FALSE;
+    SDL_bool correlated = SDL_FALSE;
+    WindowsMatchState match_state_xinput;
+    int guide_button = joystick->nbuttons - 1;
+    int left_trigger = joystick->naxes - 2;
+    int right_trigger = joystick->naxes - 1;
 
-    if (hwdata) {
+    RAWINPUT_FillMatchState(&match_state_xinput, ctx->match_state);
+
+#ifdef SDL_JOYSTICK_RAWINPUT_GAMING_INPUT
+    /* Parallel logic to WINDOWS_XINPUT below */
+    RAWINPUT_UpdateWindowsGamingInput();
+    if (ctx->wgi_correlated) {
+        /* We have been previously correlated, ensure we are still matching, see comments in XINPUT section */
+        if (RAWINPUT_WindowsGamingInputSlotMatches(&match_state_xinput, ctx->wgi_slot)) {
+            ctx->wgi_uncorrelate_count = 0;
+        } else {
+            ++ctx->wgi_uncorrelate_count;
+            /* Only un-correlate if this is consistent over multiple Update() calls - the timing of polling/event
+              pumping can easily cause this to uncorrelate for a frame.  2 seemed reliable in my testing, but
+              let's set it to 3 to be safe.  An incorrect un-correlation will simply result in lower precision
+              triggers for a frame. */
+            if (ctx->wgi_uncorrelate_count >= 3) {
+#ifdef DEBUG_JOYSTICK
+                SDL_Log("UN-Correlated joystick %d to WindowsGamingInput device #%d\n", joystick->instance_id, ctx->wgi_slot);
+#endif
+                RAWINPUT_MarkWindowsGamingInputSlotFree(ctx->wgi_slot);
+                ctx->wgi_correlated = SDL_FALSE;
+                ctx->wgi_correlation_count = 0;
+                /* Force release of Guide button, it can't possibly be down on this device now. */
+                /* It gets left down if we were actually correlated incorrectly and it was released on the WindowsGamingInput
+                  device but we didn't get a state packet. */
+                if (ctx->guide_hack) {
+                    SDL_PrivateJoystickButton(joystick, guide_button, SDL_RELEASED);
+                }
+            }
+        }
+    }
+    if (!ctx->wgi_correlated) {
+        SDL_bool new_correlation_count = 0;
+        if (RAWINPUT_MissingWindowsGamingInputSlot()) {
+            Uint8 correlation_id;
+            WindowsGamingInputGamepadState *slot_idx;
+            if (RAWINPUT_GuessWindowsGamingInputSlot(&match_state_xinput, &correlation_id, &slot_idx)) {
+                /* we match exactly one WindowsGamingInput device */
+                /* Probably can do without wgi_correlation_count, just check and clear wgi_slot to NULL, unless we need
+                   even more frames to be sure. */
+                if (ctx->wgi_correlation_count && ctx->wgi_slot == slot_idx) {
+                    /* was correlated previously, and still the same device */
+                    if (ctx->wgi_correlation_id + 1 == correlation_id) {
+                        /* no one else was correlated in the meantime */
+                        new_correlation_count = ctx->wgi_correlation_count + 1;
+                        if (new_correlation_count == 2) {
+                            /* correlation stayed steady and uncontested across multiple frames, guaranteed match */
+                            ctx->wgi_correlated = SDL_TRUE;
+#ifdef DEBUG_JOYSTICK
+                            SDL_Log("Correlated joystick %d to WindowsGamingInput device #%d\n", joystick->instance_id, slot_idx);
+#endif
+                            correlated = SDL_TRUE;
+                            RAWINPUT_MarkWindowsGamingInputSlotUsed(ctx->wgi_slot, ctx);
+                            /* If the generalized Guide button was using us, it doesn't need to anymore */
+                            if (guide_button_candidate.joystick == joystick)
+                                guide_button_candidate.joystick = NULL;
+                            if (guide_button_candidate.last_joystick == joystick)
+                                guide_button_candidate.last_joystick = NULL;
+                        }
+                    } else {
+                        /* someone else also possibly correlated to this device, start over */
+                        new_correlation_count = 1;
+                    }
+                } else {
+                    /* new possible correlation */
+                    new_correlation_count = 1;
+                    ctx->wgi_slot = slot_idx;
+                }
+                ctx->wgi_correlation_id = correlation_id;
+            } else {
+                /* Match multiple WindowsGamingInput devices, or none (possibly due to no buttons pressed) */
+            }
+        }
+        ctx->wgi_correlation_count = new_correlation_count;
+    } else {
+        correlated = SDL_TRUE;
+    }
+#endif /* SDL_JOYSTICK_RAWINPUT_GAMING_INPUT */
+
+#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
+    /* Parallel logic to WINDOWS_GAMING_INPUT above */
+    if (ctx->xinput_enabled) {
+        RAWINPUT_UpdateXInput();
+        if (ctx->xinput_correlated) {
+            /* We have been previously correlated, ensure we are still matching */
+            /* This is required to deal with two (mostly) un-preventable mis-correlation situations:
+              A) Since the HID data stream does not provide an initial state (but polling XInput does), if we open
+                 5 controllers (#1-4 XInput mapped, #5 is not), and controller 1 had the A button down (and we don't
+                 know), and the user presses A on controller #5, we'll see exactly 1 controller with A down (#5) and
+                 exactly 1 XInput device with A down (#1), and incorrectly correlate.  This code will then un-correlate
+                 when A is released from either controller #1 or #5.
+              B) Since the app may not open all controllers, we could have a similar situation where only controller #5
+                 is opened, and the user holds A on controllers #1 and #5 simultaneously - again we see only 1 controller
+                 with A down and 1 XInput device with A down, and incorrectly correlate.  This should be very unusual
+                 (only when apps do not open all controllers, yet are listening to Guide button presses, yet
+                 for some reason want to ignore guide button presses on the un-opened controllers, yet users are
+                 pressing buttons on the unopened controllers), and will resolve itself when either button is released
+                 and we un-correlate.  We could prevent this by processing the state packets for *all* controllers,
+                 even un-opened ones, as that would allow more precise correlation.
+            */
+            if (RAWINPUT_XInputSlotMatches(&match_state_xinput, ctx->xinput_slot)) {
+                ctx->xinput_uncorrelate_count = 0;
+            } else {
+                ++ctx->xinput_uncorrelate_count;
+                /* Only un-correlate if this is consistent over multiple Update() calls - the timing of polling/event
+                  pumping can easily cause this to uncorrelate for a frame.  2 seemed reliable in my testing, but
+                  let's set it to 3 to be safe.  An incorrect un-correlation will simply result in lower precision
+                  triggers for a frame. */
+                if (ctx->xinput_uncorrelate_count >= 3) {
+#ifdef DEBUG_JOYSTICK
+                    SDL_Log("UN-Correlated joystick %d to XInput device #%d\n", joystick->instance_id, ctx->xinput_slot);
+#endif
+                    RAWINPUT_MarkXInputSlotFree(ctx->xinput_slot);
+                    ctx->xinput_correlated = SDL_FALSE;
+                    ctx->xinput_correlation_count = 0;
+                    /* Force release of Guide button, it can't possibly be down on this device now. */
+                    /* It gets left down if we were actually correlated incorrectly and it was released on the XInput
+                      device but we didn't get a state packet. */
+                    if (ctx->guide_hack) {
+                        SDL_PrivateJoystickButton(joystick, guide_button, SDL_RELEASED);
+                    }
+                }
+            }
+        }
+        if (!ctx->xinput_correlated) {
+            Uint8 new_correlation_count = 0;
+            if (RAWINPUT_MissingXInputSlot()) {
+                Uint8 correlation_id = 0;
+                Uint8 slot_idx = 0;
+                if (RAWINPUT_GuessXInputSlot(&match_state_xinput, &correlation_id, &slot_idx)) {
+                    /* we match exactly one XInput device */
+                    /* Probably can do without xinput_correlation_count, just check and clear xinput_slot to ANY, unless
+                       we need even more frames to be sure */
+                    if (ctx->xinput_correlation_count && ctx->xinput_slot == slot_idx) {
+                        /* was correlated previously, and still the same device */
+                        if (ctx->xinput_correlation_id + 1 == correlation_id) {
+                            /* no one else was correlated in the meantime */
+                            new_correlation_count = ctx->xinput_correlation_count + 1;
+                            if (new_correlation_count == 2) {
+                                /* correlation stayed steady and uncontested across multiple frames, guaranteed match */
+                                ctx->xinput_correlated = SDL_TRUE;
+#ifdef DEBUG_JOYSTICK
+                                SDL_Log("Correlated joystick %d to XInput device #%d\n", joystick->instance_id, slot_idx);
+#endif
+                                correlated = SDL_TRUE;
+                                RAWINPUT_MarkXInputSlotUsed(ctx->xinput_slot);
+                                /* If the generalized Guide button was using us, it doesn't need to anymore */
+                                if (guide_button_candidate.joystick == joystick)
+                                    guide_button_candidate.joystick = NULL;
+                                if (guide_button_candidate.last_joystick == joystick)
+                                    guide_button_candidate.last_joystick = NULL;
+                            }
+                        } else {
+                            /* someone else also possibly correlated to this device, start over */
+                            new_correlation_count = 1;
+                        }
+                    } else {
+                        /* new possible correlation */
+                        new_correlation_count = 1;
+                        ctx->xinput_slot = slot_idx;
+                    }
+                    ctx->xinput_correlation_id = correlation_id;
+                } else {
+                    /* Match multiple XInput devices, or none (possibly due to no buttons pressed) */
+                }
+            }
+            ctx->xinput_correlation_count = new_correlation_count;
+        } else {
+            correlated = SDL_TRUE;
+        }
+    }
+#endif /* SDL_JOYSTICK_RAWINPUT_XINPUT */
+
+    /* Poll for trigger data once (not per-state-packet) */
+#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
+    /* Prefer XInput over WindowsGamingInput, it continues to provide data in the background */
+    if (!has_trigger_data && ctx->xinput_enabled && ctx->xinput_correlated) {
+        RAWINPUT_UpdateXInput();
+        if (xinput_state[ctx->xinput_slot].connected) {
+            if (ctx->guide_hack) {
+                SDL_PrivateJoystickButton(joystick, guide_button, (xinput_state[ctx->xinput_slot].state.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE) ? SDL_PRESSED : SDL_RELEASED);
+            }
+            if (ctx->trigger_hack) {
+                SDL_PrivateJoystickAxis(joystick, left_trigger, ((int)xinput_state[ctx->xinput_slot].state.Gamepad.bLeftTrigger * 257) - 32768);
+                SDL_PrivateJoystickAxis(joystick, right_trigger, ((int)xinput_state[ctx->xinput_slot].state.Gamepad.bRightTrigger * 257) - 32768);
+            }
+            has_trigger_data = SDL_TRUE;
+        }
+    }
+#endif /* SDL_JOYSTICK_RAWINPUT_XINPUT */
+
+#ifdef SDL_JOYSTICK_RAWINPUT_GAMING_INPUT
+    if (!has_trigger_data && ctx->wgi_correlated) {
+        RAWINPUT_UpdateWindowsGamingInput(); /* May detect disconnect / cause uncorrelation */
+        if (ctx->wgi_correlated) { /* Still connected */
+            struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading *state = &ctx->wgi_slot->state;
+
+            if (ctx->guide_hack) {
+                SDL_PrivateJoystickButton(joystick, guide_button, (state->Buttons & GamepadButtons_GUIDE) ? SDL_PRESSED : SDL_RELEASED);
+            }
+            if (ctx->trigger_hack) {
+                SDL_PrivateJoystickAxis(joystick, left_trigger, ((int)(state->LeftTrigger * SDL_MAX_UINT16)) - 32768);
+                SDL_PrivateJoystickAxis(joystick, right_trigger, ((int)(state->RightTrigger * SDL_MAX_UINT16)) - 32768);
+            }
+            has_trigger_data = SDL_TRUE;
+        }
+    }
+#endif /* SDL_JOYSTICK_RAWINPUT_GAMING_INPUT */
+
+    if (!correlated) {
+        if (!guide_button_candidate.joystick ||
+            (ctx->last_state_packet && (
+                !guide_button_candidate.last_state_packet ||
+                SDL_TICKS_PASSED(ctx->last_state_packet, guide_button_candidate.last_state_packet)
+            ))
+        ) {
+            guide_button_candidate.joystick = joystick;
+            guide_button_candidate.last_state_packet = ctx->last_state_packet;
+        }
+    }
+#endif /* SDL_JOYSTICK_RAWINPUT_MATCHING */
+}
+
+static void
+RAWINPUT_JoystickUpdate(SDL_Joystick *joystick)
+{
+    /* Ensure data messages have been pumped */
+    RAWINPUT_PumpMessages();
+    RAWINPUT_UpdateOtherAPIs(joystick);
+}
+
+static void
+RAWINPUT_JoystickClose(SDL_Joystick *joystick)
+{
+    RAWINPUT_DeviceContext *ctx = joystick->hwdata;
+
+#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
+    if (guide_button_candidate.joystick == joystick)
+        guide_button_candidate.joystick = NULL;
+    if (guide_button_candidate.last_joystick == joystick)
+        guide_button_candidate.last_joystick = NULL;
+#endif
+
+    if (ctx) {
         SDL_RAWINPUT_Device *device;
 
-        device = hwdata->device;
+#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
+        xinput_device_change = SDL_TRUE;
+        if (ctx->xinput_enabled) {
+            if (ctx->xinput_correlated) {
+                RAWINPUT_MarkXInputSlotFree(ctx->xinput_slot);
+            }
+            WIN_UnloadXInputDLL();
+        }
+#endif
+#ifdef SDL_JOYSTICK_RAWINPUT_GAMING_INPUT
+        RAWINPUT_QuitWindowsGamingInput(ctx);
+#endif
+
+        device = ctx->device;
         if (device) {
             SDL_assert(device->joystick == joystick);
-            device->driver->CloseJoystick(&device->hiddevice, joystick);
             device->joystick = NULL;
             RAWINPUT_ReleaseDevice(device);
         }
 
-        SDL_free(hwdata);
+        SDL_free(ctx->data);
+        SDL_free(ctx->button_indices);
+        SDL_free(ctx->axis_indices);
+        SDL_free(ctx->hat_indices);
+        SDL_free(ctx);
         joystick->hwdata = NULL;
     }
 }
@@ -702,6 +1723,7 @@ LRESULT RAWINPUT_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
             }
         }
         return 0;
+
         case WM_INPUT:
         {
             Uint8 data[sizeof(RAWINPUTHEADER) + sizeof(RAWHID) + USB_PACKET_LENGTH];
@@ -711,10 +1733,9 @@ LRESULT RAWINPUT_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
                 PRAWINPUT raw_input = (PRAWINPUT)data;
                 SDL_RAWINPUT_Device *device = RAWINPUT_DeviceFromHandle(raw_input->header.hDevice);
                 if (device) {
-                    SDL_HIDAPI_DeviceDriver *driver = device->driver;
                     SDL_Joystick *joystick = device->joystick;
                     if (joystick) {
-                        driver->HandleStatePacketFromRAWINPUT(&device->hiddevice, joystick, &raw_input->data.hid.bRawData[1], raw_input->data.hid.dwSizeHid - 1);
+                        RAWINPUT_HandleStatePacket(joystick, raw_input->data.hid.bRawData, raw_input->data.hid.dwSizeHid);
                     }
                 }
             }
@@ -734,7 +1755,7 @@ RAWINPUT_JoystickQuit(void)
         return;
 
     for (ii = 0; ii < SDL_arraysize(subscribed_devices); ii++) {
-        rid[ii].usUsagePage = USAGE_PAGE_GENERIC_DESKTOP;
+        rid[ii].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
         rid[ii].usUsage = subscribed_devices[ii];
         rid[ii].dwFlags = RIDEV_REMOVE;
         rid[ii].hwndTarget = NULL;
@@ -748,6 +1769,8 @@ RAWINPUT_JoystickQuit(void)
         RAWINPUT_DelDevice(SDL_RAWINPUT_devices, SDL_FALSE);
     }
 
+    WIN_UnloadHIDDLL();
+
     SDL_RAWINPUT_numjoysticks = 0;
 
     SDL_RAWINPUT_inited = SDL_FALSE;
diff --git a/src/joystick/windows/SDL_rawinputjoystick_c.h b/src/joystick/windows/SDL_rawinputjoystick_c.h
index f95e0debe..a683364f9 100644
--- a/src/joystick/windows/SDL_rawinputjoystick_c.h
+++ b/src/joystick/windows/SDL_rawinputjoystick_c.h
@@ -20,6 +20,9 @@
 */
 #include "../../SDL_internal.h"
 
+/* Return true if the RawInput driver is enabled */
+extern SDL_bool RAWINPUT_IsEnabled();
+
 /* Return true if a RawInput device is present and supported as a joystick */
 extern SDL_bool RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version);
 
diff --git a/src/joystick/windows/SDL_windows_gaming_input.c b/src/joystick/windows/SDL_windows_gaming_input.c
index 1af18af72..90f018b84 100644
--- a/src/joystick/windows/SDL_windows_gaming_input.c
+++ b/src/joystick/windows/SDL_windows_gaming_input.c
@@ -26,6 +26,7 @@
 #include "SDL_events.h"
 #include "../SDL_sysjoystick.h"
 #include "../hidapi/SDL_hidapijoystick_c.h"
+#include "SDL_rawinputjoystick_c.h"
 
 #include "../../core/windows/SDL_windows.h"
 #define COBJMACROS
@@ -247,6 +248,12 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdde
         }
 #endif
 
+#ifdef SDL_JOYSTICK_RAWINPUT
+        if (!ignore_joystick && RAWINPUT_IsDevicePresent(vendor, product, version)) {
+            ignore_joystick = SDL_TRUE;
+        }
+#endif
+
         if (!ignore_joystick && SDL_DINPUT_JoystickPresent(vendor, product, version)) {
             ignore_joystick = SDL_TRUE;
         }
diff --git a/src/joystick/windows/SDL_xinputjoystick.c b/src/joystick/windows/SDL_xinputjoystick.c
index 72fa4391a..40ba799fa 100644
--- a/src/joystick/windows/SDL_xinputjoystick.c
+++ b/src/joystick/windows/SDL_xinputjoystick.c
@@ -65,6 +65,11 @@ SDL_XINPUT_JoystickInit(void)
 {
     s_bXInputEnabled = SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, SDL_TRUE);
 
+    if (RAWINPUT_IsEnabled()) {
+        /* The raw input driver handles more than 4 controllers, so prefer that when available */
+        s_bXInputEnabled = SDL_FALSE;
+    }
+
     if (s_bXInputEnabled && WIN_LoadXInputDLL() < 0) {
         s_bXInputEnabled = SDL_FALSE;  /* oh well. */
     }
@@ -208,7 +213,7 @@ GuessXInputDevice(Uint8 userid, Uint16 *pVID, Uint16 *pPID, Uint16 *pVersion)
         }
     }
     SDL_free(devices);
-#endif  /* ifndef __WINRT__ */
+#endif  /* !__WINRT__ */
 
     /* The device wasn't in the raw HID device list, it's probably Bluetooth */
     *pVID = 0x045e; /* Microsoft */