From 517a3d20e8cf52cbd7bc3b9ae48349017e87c095 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 13 Dec 2025 23:42:55 -0800
Subject: [PATCH] Support calling SteamAPI_InitEx() before
SDL_Init(SDL_INIT_GAMEPAD)
Calling SteamAPI_InitEx() will set environment variables that SDL uses to properly support the Steam virtual gamepad. Make sure that we fall back to the real environment for the variables that Steam sets.
---
include/SDL3/SDL_gamepad.h | 3 +++
src/joystick/SDL_gamepad.c | 14 ++++++++++----
src/joystick/SDL_joystick.c | 6 ++++++
src/joystick/SDL_steam_virtual_gamepad.c | 6 ++----
4 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/include/SDL3/SDL_gamepad.h b/include/SDL3/SDL_gamepad.h
index d1a21ca252a3f..4d660ed416797 100644
--- a/include/SDL3/SDL_gamepad.h
+++ b/include/SDL3/SDL_gamepad.h
@@ -48,6 +48,9 @@
* SDL_INIT_GAMEPAD flag. This causes SDL to scan the system for gamepads, and
* load appropriate drivers.
*
+ * If you're using SDL gamepad support in a Steam game, you must call
+ * SteamAPI_InitEx() before calling SDL_Init().
+ *
* If you would like to receive gamepad updates while the application is in
* the background, you should set the following hint before calling
* SDL_Init(): SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS
diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c
index a291ec2694e7c..7ac5862a3fcfc 100644
--- a/src/joystick/SDL_gamepad.c
+++ b/src/joystick/SDL_gamepad.c
@@ -33,6 +33,7 @@
#include "hidapi/SDL_hidapi_nintendo.h"
#include "hidapi/SDL_hidapi_sinput.h"
#include "../events/SDL_events_c.h"
+#include "../SDL_hints_c.h"
#ifdef SDL_PLATFORM_WIN32
#include "../core/windows/SDL_windows.h"
@@ -2616,7 +2617,11 @@ static int SDL_PrivateAddGamepadMapping(const char *mappingString, SDL_GamepadMa
}
} else {
- value = SDL_GetHintBoolean(hint, default_value);
+ const char *hint_value = SDL_GetHint(hint);
+ if (!hint_value) {
+ hint_value = SDL_getenv_unsafe(hint_value);
+ }
+ value = SDL_GetStringBoolean(hint_value, default_value);
if (negate) {
value = !value;
}
@@ -3235,9 +3240,10 @@ bool SDL_ShouldIgnoreGamepad(Uint16 vendor_id, Uint16 product_id, Uint16 version
}
}
+ const char *hint = SDL_getenv_unsafe("SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD");
+ bool allow_steam_virtual_gamepad = SDL_GetStringBoolean(hint, false);
#ifdef SDL_PLATFORM_WIN32
- if (SDL_GetHintBoolean("SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD", false) &&
- WIN_IsWine()) {
+ if (allow_steam_virtual_gamepad && WIN_IsWine()) {
// We are launched by Steam and running under Proton or Wine
// We can't tell whether this controller is a Steam Virtual Gamepad,
// so assume that is doing the appropriate filtering of controllers
@@ -3247,7 +3253,7 @@ bool SDL_ShouldIgnoreGamepad(Uint16 vendor_id, Uint16 product_id, Uint16 version
#endif // SDL_PLATFORM_WIN32
if (SDL_IsJoystickSteamVirtualGamepad(vendor_id, product_id, version)) {
- return !SDL_GetHintBoolean("SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD", false);
+ return !allow_steam_virtual_gamepad;
}
if (SDL_allowed_gamepads.num_included_entries > 0) {
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index 3e3c66b221e0b..f095629d8222b 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -3961,9 +3961,15 @@ void SDL_LoadVIDPIDList(SDL_vidpid_list *list)
if (list->included_hint_name) {
included_list = SDL_GetHint(list->included_hint_name);
+ if (!included_list) {
+ included_list = SDL_getenv_unsafe(list->included_hint_name);
+ }
}
if (list->excluded_hint_name) {
excluded_list = SDL_GetHint(list->excluded_hint_name);
+ if (!excluded_list) {
+ excluded_list = SDL_getenv_unsafe(list->excluded_hint_name);
+ }
}
SDL_LoadVIDPIDListFromHints(list, included_list, excluded_list);
}
diff --git a/src/joystick/SDL_steam_virtual_gamepad.c b/src/joystick/SDL_steam_virtual_gamepad.c
index e44610664002c..c59dff7aa19ea 100644
--- a/src/joystick/SDL_steam_virtual_gamepad.c
+++ b/src/joystick/SDL_steam_virtual_gamepad.c
@@ -33,8 +33,6 @@
#include <sys/stat.h>
#endif
-#define SDL_HINT_STEAM_VIRTUAL_GAMEPAD_INFO_FILE "SteamVirtualGamepadInfo"
-
static char *SDL_steam_virtual_gamepad_info_file SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
static Uint64 SDL_steam_virtual_gamepad_info_file_mtime SDL_GUARDED_BY(SDL_joystick_lock) = 0;
static Uint64 SDL_steam_virtual_gamepad_info_check_time SDL_GUARDED_BY(SDL_joystick_lock) = 0;
@@ -135,14 +133,14 @@ void SDL_InitSteamVirtualGamepadInfo(void)
return;
}
- file = SDL_GetHint(SDL_HINT_STEAM_VIRTUAL_GAMEPAD_INFO_FILE);
+ file = SDL_getenv_unsafe("SteamVirtualGamepadInfo");
if (file && *file) {
#ifdef SDL_PLATFORM_LINUX
// Older versions of Wine will blacklist the Steam Virtual Gamepad if
// it appears to have the real controller's VID/PID, so ignore this.
const char *exe = SDL_GetExeName();
if (exe && SDL_strcmp(exe, "wine64-preloader") == 0) {
- SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Wine launched by Steam, ignoring %s", SDL_HINT_STEAM_VIRTUAL_GAMEPAD_INFO_FILE);
+ SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Wine launched by Steam, ignoring SteamVirtualGamepadInfo");
return;
}
#endif