From 2c4e6ed3585ec63adee2e9a680de3c52b4db3c0c Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 14 May 2026 10:18:58 -0700
Subject: [PATCH] Enable GameInput v3 by default if it's available
GameInput is now the most functional Windows API for handling XInput controllers.
---
src/core/windows/SDL_gameinput.cpp | 5 +++
src/core/windows/SDL_gameinput.h | 1 +
src/joystick/gdk/SDL_gameinputjoystick.cpp | 30 ++++++++++++-----
src/joystick/gdk/SDL_gameinputjoystick_c.h | 33 +++++++++++++++++++
src/joystick/windows/SDL_dinputjoystick.c | 4 ++-
src/joystick/windows/SDL_rawinputjoystick.c | 4 ++-
.../windows/SDL_windows_gaming_input.c | 4 ++-
src/joystick/windows/SDL_xinputjoystick.c | 8 ++++-
8 files changed, 77 insertions(+), 12 deletions(-)
create mode 100644 src/joystick/gdk/SDL_gameinputjoystick_c.h
diff --git a/src/core/windows/SDL_gameinput.cpp b/src/core/windows/SDL_gameinput.cpp
index baf7ed2165433..7139a4c36d225 100644
--- a/src/core/windows/SDL_gameinput.cpp
+++ b/src/core/windows/SDL_gameinput.cpp
@@ -77,6 +77,11 @@ bool SDL_InitGameInput(IGameInput **ppGameInput)
return true;
}
+bool SDL_GameInputReady(void)
+{
+ return (g_pGameInput != NULL);
+}
+
void SDL_QuitGameInput(void)
{
SDL_assert(g_nGameInputRefCount > 0);
diff --git a/src/core/windows/SDL_gameinput.h b/src/core/windows/SDL_gameinput.h
index d283831ff14e1..cf8a978a576be 100644
--- a/src/core/windows/SDL_gameinput.h
+++ b/src/core/windows/SDL_gameinput.h
@@ -49,6 +49,7 @@ using namespace GameInput::v1;
#endif
extern bool SDL_InitGameInput(IGameInput **ppGameInput);
+extern bool SDL_GameInputReady(void);
extern void SDL_QuitGameInput(void);
#endif // HAVE_GAMEINPUT_H
diff --git a/src/joystick/gdk/SDL_gameinputjoystick.cpp b/src/joystick/gdk/SDL_gameinputjoystick.cpp
index f05c62c487b6f..7456190615bc0 100644
--- a/src/joystick/gdk/SDL_gameinputjoystick.cpp
+++ b/src/joystick/gdk/SDL_gameinputjoystick.cpp
@@ -20,6 +20,8 @@
*/
#include "SDL_internal.h"
+#include "SDL_gameinputjoystick_c.h"
+
#ifdef SDL_JOYSTICK_GAMEINPUT
#include "../SDL_sysjoystick.h"
@@ -28,7 +30,7 @@
#include "../../core/windows/SDL_gameinput.h"
// Default value for SDL_HINT_JOYSTICK_GAMEINPUT
-#if defined(SDL_PLATFORM_GDK)
+#if defined(SDL_PLATFORM_GDK) || (GAMEINPUT_API_VERSION >= 3)
#define SDL_GAMEINPUT_DEFAULT true
#else
#define SDL_GAMEINPUT_DEFAULT false
@@ -81,10 +83,6 @@ static IGameInput *g_pGameInput = NULL;
static GameInputCallbackToken g_GameInputCallbackToken = 0;
static Uint64 g_GameInputTimestampOffset;
-extern "C"
-{
- extern bool SDL_XINPUT_Enabled(void);
-}
static bool GAMEINPUT_InternalIsGamepad(const GameInputDeviceInfo *info)
{
@@ -242,9 +240,9 @@ static bool GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice)
#endif
if (!GAMEINPUT_InternalIsGamepad(info) && raw_type == SDL_GAMEINPUT_RAWTYPE_NONE) {
-#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT)
- if (SDL_GetHintBoolean(SDL_HINT_JOYSTICK_DIRECTINPUT, true) || SDL_XINPUT_Enabled()) {
- // Let other backends handle non-gamepad controllers to possibly avoid bugs and/or regressions.
+#if defined(SDL_JOYSTICK_DINPUT)
+ // Let other backends handle non-gamepad controllers to possibly avoid bugs and/or regressions.
+ if (SDL_GetHintBoolean(SDL_HINT_JOYSTICK_DIRECTINPUT, true)) {
return true;
}
#endif
@@ -1055,6 +1053,15 @@ static bool GAMEINPUT_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap
return true;
}
+bool SDL_UsingGameInputForXInputControllers(void)
+{
+ if (SDL_GetHintBoolean(SDL_HINT_JOYSTICK_GAMEINPUT, SDL_GAMEINPUT_DEFAULT) &&
+ SDL_GameInputReady()) {
+ return true;
+ }
+ return false;
+}
+
SDL_JoystickDriver SDL_GAMEINPUT_JoystickDriver =
{
@@ -1082,4 +1089,11 @@ SDL_JoystickDriver SDL_GAMEINPUT_JoystickDriver =
};
+#else
+
+bool SDL_UsingGameInputForXInputControllers(void)
+{
+ return false;
+}
+
#endif // SDL_JOYSTICK_GAMEINPUT
diff --git a/src/joystick/gdk/SDL_gameinputjoystick_c.h b/src/joystick/gdk/SDL_gameinputjoystick_c.h
new file mode 100644
index 0000000000000..814166b63f704
--- /dev/null
+++ b/src/joystick/gdk/SDL_gameinputjoystick_c.h
@@ -0,0 +1,33 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2026 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"
+
+// Set up for C function definitions, even when using C++
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern bool SDL_UsingGameInputForXInputControllers(void);
+
+// Ends C function definitions when using C++
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/joystick/windows/SDL_dinputjoystick.c b/src/joystick/windows/SDL_dinputjoystick.c
index 62ffbb46ec9fa..e9c818aa0063e 100644
--- a/src/joystick/windows/SDL_dinputjoystick.c
+++ b/src/joystick/windows/SDL_dinputjoystick.c
@@ -29,6 +29,7 @@
#include "SDL_rawinputjoystick_c.h"
#include "SDL_xinputjoystick_c.h"
#include "../hidapi/SDL_hidapijoystick_c.h"
+#include "../gdk/SDL_gameinputjoystick_c.h"
#ifndef DIDFT_OPTIONAL
#define DIDFT_OPTIONAL 0x80000000
@@ -238,11 +239,12 @@ static bool SDL_IsXInputDevice(Uint16 vendor_id, Uint16 product_id, const char *
#if defined(SDL_JOYSTICK_XINPUT) || defined(SDL_JOYSTICK_RAWINPUT)
SDL_GamepadType type;
- // XInput and RawInput backends will pick up XInput-compatible devices
+ // Some other backends will pick up XInput-compatible devices
if (!SDL_XINPUT_Enabled()
#ifdef SDL_JOYSTICK_RAWINPUT
&& !RAWINPUT_IsEnabled()
#endif
+ && !SDL_UsingGameInputForXInputControllers()
) {
return false;
}
diff --git a/src/joystick/windows/SDL_rawinputjoystick.c b/src/joystick/windows/SDL_rawinputjoystick.c
index 7a69775e2627f..92c9e026a5c8e 100644
--- a/src/joystick/windows/SDL_rawinputjoystick.c
+++ b/src/joystick/windows/SDL_rawinputjoystick.c
@@ -38,6 +38,7 @@
#include "../../core/windows/SDL_windows.h"
#include "../../core/windows/SDL_hid.h"
#include "../hidapi/SDL_hidapijoystick_c.h"
+#include "../gdk/SDL_gameinputjoystick_c.h"
/* SDL_JOYSTICK_RAWINPUT_XINPUT is disabled because using XInput at the same time as
raw input will turn off the Xbox Series X controller when it is connected via the
@@ -1022,7 +1023,8 @@ static bool RAWINPUT_JoystickInit(void)
{
SDL_assert(!SDL_RAWINPUT_inited);
- if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT, false)) {
+ if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT, false) ||
+ SDL_UsingGameInputForXInputControllers()) {
return true;
}
diff --git a/src/joystick/windows/SDL_windows_gaming_input.c b/src/joystick/windows/SDL_windows_gaming_input.c
index 6b74873a9c50d..f8840ac2304d8 100644
--- a/src/joystick/windows/SDL_windows_gaming_input.c
+++ b/src/joystick/windows/SDL_windows_gaming_input.c
@@ -24,6 +24,7 @@
#include "../SDL_sysjoystick.h"
#include "../hidapi/SDL_hidapijoystick_c.h"
+#include "../gdk/SDL_gameinputjoystick_c.h"
#include "SDL_rawinputjoystick_c.h"
#include "../../core/windows/SDL_windows.h"
@@ -586,7 +587,8 @@ static bool WGI_JoystickInit(void)
{
HRESULT hr;
- if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_WGI, false)) {
+ if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_WGI, false) ||
+ SDL_UsingGameInputForXInputControllers()) {
return true;
}
diff --git a/src/joystick/windows/SDL_xinputjoystick.c b/src/joystick/windows/SDL_xinputjoystick.c
index d7a132e1d15ca..377defb07d3b2 100644
--- a/src/joystick/windows/SDL_xinputjoystick.c
+++ b/src/joystick/windows/SDL_xinputjoystick.c
@@ -28,6 +28,7 @@
#include "SDL_xinputjoystick_c.h"
#include "SDL_rawinputjoystick_c.h"
#include "../hidapi/SDL_hidapijoystick_c.h"
+#include "../gdk/SDL_gameinputjoystick_c.h"
// Set up for C function definitions, even when using C++
#ifdef __cplusplus
@@ -46,7 +47,12 @@ bool SDL_XINPUT_Enabled(void)
bool SDL_XINPUT_JoystickInit(void)
{
- bool enabled = SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, true);
+ bool enabled = true;
+
+ if (!SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, true) ||
+ SDL_UsingGameInputForXInputControllers()) {
+ enabled = false;
+ }
if (enabled && !WIN_LoadXInputDLL()) {
enabled = false; // oh well.