Skip to content

Commit

Permalink
Fixed bug 4477 - Support more than 4 XInput-capable devices on Windows
Browse files Browse the repository at this point in the history
Jimb Esser

Add new RawInput controller API, and improved correlation with XInput/WGI

Reorder joystick init so drivers can ask the others if they handle a device reliably
Do not poll disconnected XInput devices (major perf issue)
Fix various cases where incorrect correlation could happen
Simple mechanism for propagating unhandled Guide button presses even before guaranteed correlation
Correlate by axis motion as well as button presses
Fix failing to zero other trigger
Fix SDL_HINT_JOYSTICK_HIDAPI not working if set before calling SDL_Init()
Add missing device to device names
Disable RawInput if we have a mismatch of XInput-capable but not RawInput-capable devices

Updated to SDL 2.0.13 code with the following notes:
New HID driver: xbox360w - no idea what that is, hopefully urelated
SDL_hidapijoystick.c had been refactored to couple data handling logic with device opening logic and device lists caused some problems, yields slightly uglier integration than previously when the 360 HID device driver was just handling the data.
SDL_hidapijoystick.c now often pulls the device off of the joystick_hwdata structure for some rumble logic, but it appears that code path is never reached, so probably not a problem.
Looks like joystick_hwdata was refactored to not include a mutex in other drivers, maintainers may want to do the same refactor here if that's useful for some reason.
Something changed in how devices get names, so getting generic names.
Had to fix a (new?) bug where removing an XInput controller caused existing controllers (that moved to a new XInput index) to get identified as 0x045e/0x02fd ("it's probably Bluetooth" in code), rendering the existing HIDAPI_IsDevicePresent and new RAWINPUT_IsDevicePresent unreliable.
  • Loading branch information
slouken committed Mar 16, 2020
1 parent cc37ee8 commit 4dea340
Show file tree
Hide file tree
Showing 22 changed files with 885 additions and 216 deletions.
4 changes: 4 additions & 0 deletions VisualC/SDL/SDL.vcxproj
Expand Up @@ -318,12 +318,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" />
Expand Down Expand Up @@ -432,6 +435,7 @@
<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_windowsjoystick.c" />
<ClCompile Include="..\..\src\joystick\windows\SDL_xinputjoystick.c" />
<ClCompile Include="..\..\src\libm\e_atan2.c" />
Expand Down
4 changes: 4 additions & 0 deletions VisualC/SDL/SDL.vcxproj.filters
Expand Up @@ -323,6 +323,9 @@
<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" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\atomic\SDL_atomic.c" />
Expand Down Expand Up @@ -478,6 +481,7 @@
<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" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\src\main\windows\version.rc" />
Expand Down
2 changes: 2 additions & 0 deletions configure
Expand Up @@ -24336,6 +24336,8 @@ fi

$as_echo "#define SDL_JOYSTICK_HIDAPI 1" >>confdefs.h

$as_echo "#define SDL_JOYSTICK_RAWINPUT 1" >>confdefs.h

EXTRA_CFLAGS="$EXTRA_CFLAGS -I$srcdir/src/hidapi/hidapi"
SOURCES="$SOURCES $srcdir/src/joystick/hidapi/*.c"
SOURCES="$SOURCES $srcdir/src/hidapi/SDL_hidapi.c"
Expand Down
1 change: 1 addition & 0 deletions configure.ac
Expand Up @@ -3316,6 +3316,7 @@ AS_HELP_STRING([--enable-hidapi], [use HIDAPI for low level joystick drivers [[d

if test x$hidapi_support = xyes; then
AC_DEFINE(SDL_JOYSTICK_HIDAPI, 1, [ ])
AC_DEFINE(SDL_JOYSTICK_RAWINPUT, 1, [ ])
EXTRA_CFLAGS="$EXTRA_CFLAGS -I$srcdir/src/hidapi/hidapi"
SOURCES="$SOURCES $srcdir/src/joystick/hidapi/*.c"
SOURCES="$SOURCES $srcdir/src/hidapi/SDL_hidapi.c"
Expand Down
1 change: 1 addition & 0 deletions include/SDL_config.h.in
Expand Up @@ -289,6 +289,7 @@
#undef SDL_JOYSTICK_USBHID
#undef SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H
#undef SDL_JOYSTICK_HIDAPI
#undef SDL_JOYSTICK_RAWINPUT
#undef SDL_JOYSTICK_EMSCRIPTEN
#undef SDL_JOYSTICK_VIRTUAL
#undef SDL_HAPTIC_DUMMY
Expand Down
1 change: 1 addition & 0 deletions include/SDL_config_windows.h
Expand Up @@ -197,6 +197,7 @@ typedef unsigned int uintptr_t;
#define SDL_JOYSTICK_DINPUT 1
#define SDL_JOYSTICK_XINPUT 1
#define SDL_JOYSTICK_HIDAPI 1
#define SDL_JOYSTICK_RAWINPUT 1
#define SDL_HAPTIC_DINPUT 1
#define SDL_HAPTIC_XINPUT 1

Expand Down
24 changes: 23 additions & 1 deletion include/SDL_hints.h
Expand Up @@ -634,10 +634,23 @@ extern "C" {
* "0" - HIDAPI driver is not used
* "1" - HIDAPI driver is used
*
* The default is the value of SDL_HINT_JOYSTICK_HIDAPI
* The default is "0" on Windows, otherwise the value of SDL_HINT_JOYSTICK_HIDAPI
*/
#define SDL_HINT_JOYSTICK_HIDAPI_XBOX "SDL_JOYSTICK_HIDAPI_XBOX"

/**
* \brief A variable controlling whether the HIDAPI driver for XBox controllers on Windows should pull correlated
* data from XInput.
*
* This variable can be set to the following values:
* "0" - HIDAPI Xbox driver will only use HIDAPI data
* "1" - HIDAPI Xbox driver will also pull data from XInput, providing better trigger axes, guide button
* presses, and rumble support
*
* The default is "1". This hint applies to any joysticks opened after setting the hint.
*/
#define SDL_HINT_JOYSTICK_HIDAPI_CORRELATE_XINPUT "SDL_JOYSTICK_HIDAPI_CORRELATE_XINPUT"

/**
* \brief A variable controlling whether the HIDAPI driver for Nintendo GameCube controllers should be used.
*
Expand All @@ -660,6 +673,15 @@ extern "C" {
*/
#define SDL_HINT_ENABLE_STEAM_CONTROLLERS "SDL_ENABLE_STEAM_CONTROLLERS"

/**
* \brief A variable controlling whether the RAWINPUT joystick drivers should be used for better handling XInput-capable devices.
*
* This variable can be set to the following values:
* "0" - RAWINPUT drivers are not used
* "1" - RAWINPUT drivers are used (the default)
*
*/
#define SDL_HINT_JOYSTICK_RAWINPUT "SDL_JOYSTICK_RAWINPUT"

/**
* \brief If set to "0" then never set the top most bit on a SDL Window, even if the video mode expects it.
Expand Down
6 changes: 6 additions & 0 deletions src/joystick/SDL_gamecontroller.c
Expand Up @@ -439,6 +439,12 @@ static ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickG
/* This is a HIDAPI device */
return s_pHIDAPIMapping;
}
#if SDL_JOYSTICK_RAWINPUT
if (SDL_IsJoystickRAWINPUT(*guid)) {
/* This is a RAWINPUT device - same data as HIDAPI */
return s_pHIDAPIMapping;
}
#endif
#if SDL_JOYSTICK_XINPUT
if (SDL_IsJoystickXInput(*guid)) {
/* This is an XInput device */
Expand Down
16 changes: 13 additions & 3 deletions src/joystick/SDL_joystick.c
Expand Up @@ -51,6 +51,13 @@
#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
#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT)
&SDL_WINDOWS_JoystickDriver,
#endif
Expand All @@ -75,9 +82,6 @@ static SDL_JoystickDriver *SDL_joystick_drivers[] = {
#ifdef SDL_JOYSTICK_USBHID /* !!! FIXME: "USBHID" is a generic name, and doubly-confusing with HIDAPI next to it. This is the *BSD interface, rename this. */
&SDL_BSD_JoystickDriver,
#endif
#ifdef SDL_JOYSTICK_HIDAPI
&SDL_HIDAPI_JoystickDriver,
#endif
#ifdef SDL_JOYSTICK_VIRTUAL
&SDL_VIRTUAL_JoystickDriver,
#endif
Expand Down Expand Up @@ -1729,6 +1733,12 @@ SDL_IsJoystickHIDAPI(SDL_JoystickGUID guid)
return (guid.data[14] == 'h') ? SDL_TRUE : SDL_FALSE;
}

SDL_bool
SDL_IsJoystickRAWINPUT(SDL_JoystickGUID guid)
{
return (guid.data[14] == 'r') ? SDL_TRUE : SDL_FALSE;
}

SDL_bool
SDL_IsJoystickVirtual(SDL_JoystickGUID guid)
{
Expand Down
3 changes: 3 additions & 0 deletions src/joystick/SDL_joystick_c.h
Expand Up @@ -73,6 +73,9 @@ extern SDL_bool SDL_IsJoystickXInput(SDL_JoystickGUID guid);
/* Function to return whether a joystick guid comes from the HIDAPI driver */
extern SDL_bool SDL_IsJoystickHIDAPI(SDL_JoystickGUID guid);

/* Function to return whether a joystick guid comes from the RAWINPUT driver */
extern SDL_bool SDL_IsJoystickRAWINPUT(SDL_JoystickGUID guid);

/* Function to return whether a joystick guid comes from the Virtual driver */
extern SDL_bool SDL_IsJoystickVirtual(SDL_JoystickGUID guid);

Expand Down
1 change: 1 addition & 0 deletions src/joystick/SDL_sysjoystick.h
Expand Up @@ -150,6 +150,7 @@ extern SDL_JoystickDriver SDL_DUMMY_JoystickDriver;
extern SDL_JoystickDriver SDL_EMSCRIPTEN_JoystickDriver;
extern SDL_JoystickDriver SDL_HAIKU_JoystickDriver;
extern SDL_JoystickDriver SDL_HIDAPI_JoystickDriver;
extern SDL_JoystickDriver SDL_RAWINPUT_JoystickDriver;
extern SDL_JoystickDriver SDL_IOS_JoystickDriver;
extern SDL_JoystickDriver SDL_LINUX_JoystickDriver;
extern SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver;
Expand Down
8 changes: 4 additions & 4 deletions src/joystick/hidapi/SDL_hidapi_gamecube.c
Expand Up @@ -176,11 +176,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]);
HIDAPI_JoystickConnected(device, &ctx->joysticks[i], SDL_FALSE);
}
} else {
if (ctx->joysticks[i] != -1) {
HIDAPI_JoystickDisconnected(device, ctx->joysticks[i]);
HIDAPI_JoystickDisconnected(device, ctx->joysticks[i], SDL_FALSE);
ctx->joysticks[i] = -1;
}
continue;
Expand Down Expand Up @@ -252,7 +252,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]);
HIDAPI_JoystickConnected(device, &ctx->joysticks[i], SDL_FALSE);
}
joystick = SDL_JoystickFromInstanceID(ctx->joysticks[i]);

Expand All @@ -262,7 +262,7 @@ HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
}
} else {
if (ctx->joysticks[i] != -1) {
HIDAPI_JoystickDisconnected(device, ctx->joysticks[i]);
HIDAPI_JoystickDisconnected(device, ctx->joysticks[i], SDL_FALSE);
ctx->joysticks[i] = -1;
}
continue;
Expand Down
4 changes: 2 additions & 2 deletions src/joystick/hidapi/SDL_hidapi_ps4.c
Expand Up @@ -213,7 +213,7 @@ SetLedsForPlayerIndex(DS4EffectsState_t *effects, int player_index)
static SDL_bool
HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
{
return HIDAPI_JoystickConnected(device, NULL);
return HIDAPI_JoystickConnected(device, NULL, SDL_FALSE);
}

static int
Expand Down Expand Up @@ -496,7 +496,7 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)

if (size < 0) {
/* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
HIDAPI_JoystickDisconnected(device, joystick->instance_id, SDL_FALSE);
}
return (size >= 0);
}
Expand Down
4 changes: 2 additions & 2 deletions src/joystick/hidapi/SDL_hidapi_switch.c
Expand Up @@ -671,7 +671,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);
return HIDAPI_JoystickConnected(device, NULL, SDL_FALSE);
}

static int
Expand Down Expand Up @@ -1121,7 +1121,7 @@ HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device)

if (size < 0) {
/* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
HIDAPI_JoystickDisconnected(device, joystick->instance_id, SDL_FALSE);
}
return (size >= 0);
}
Expand Down

0 comments on commit 4dea340

Please sign in to comment.