SDL: Check for wine_get_version() to detect Wine/Proton

From e2e8f86076a815303836514bb4ba661a84532d24 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 12 Nov 2025 21:40:05 -0800
Subject: [PATCH] Check for wine_get_version() to detect Wine/Proton

If this application is being run under Wine but Steam doesn't know that, Steam won't set STEAM_COMPAT_PROTON. So we'll use wine_get_version() to detect that we're running under Wine instead.
---
 src/core/windows/SDL_windows.c | 18 ++++++++++++++++++
 src/core/windows/SDL_windows.h |  3 +++
 src/joystick/SDL_gamepad.c     | 11 ++++++-----
 3 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/src/core/windows/SDL_windows.c b/src/core/windows/SDL_windows.c
index 4621531ca545f..6bcc8f5ee3147 100644
--- a/src/core/windows/SDL_windows.c
+++ b/src/core/windows/SDL_windows.c
@@ -325,6 +325,24 @@ static BOOL IsWindowsBuildVersionAtLeast(DWORD dwBuildNumber)
         return result;
 #endif
 
+BOOL WIN_IsWine(void)
+{
+    static bool checked;
+    static bool is_wine;
+
+    if (!checked) {
+        HMODULE ntdll = LoadLibrary(TEXT("ntdll.dll"));
+        if (ntdll) {
+            if (GetProcAddress(ntdll, "wine_get_version") != NULL) {
+                is_wine = true;
+            }
+            FreeLibrary(ntdll);
+        }
+        checked = true;
+    }
+    return is_wine;
+}
+
 // this is the oldest thing we run on (and we may lose support for this in SDL3 at any time!),
 //  so there's no "OrGreater" as that would always be TRUE. The other functions are here to
 //  ask "can we support a specific feature?" but this function is here to ask "do we need to do
diff --git a/src/core/windows/SDL_windows.h b/src/core/windows/SDL_windows.h
index f26b653b92d61..7dfbc7daf6439 100644
--- a/src/core/windows/SDL_windows.h
+++ b/src/core/windows/SDL_windows.h
@@ -168,6 +168,9 @@ extern void WIN_CoUninitialize(void);
 extern HRESULT WIN_RoInitialize(void);
 extern void WIN_RoUninitialize(void);
 
+// Returns true if we're running on Wine
+extern BOOL WIN_IsWine(void);
+
 // Returns true if we're running on Windows XP (any service pack). DOES NOT CHECK XP "OR GREATER"!
 extern BOOL WIN_IsWindowsXP(void);
 
diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c
index b63a47a8791e2..cdb7714e4542a 100644
--- a/src/joystick/SDL_gamepad.c
+++ b/src/joystick/SDL_gamepad.c
@@ -34,10 +34,11 @@
 #include "hidapi/SDL_hidapi_sinput.h"
 #include "../events/SDL_events_c.h"
 
-
-#ifdef SDL_PLATFORM_ANDROID
+#ifdef SDL_PLATFORM_WIN32
+#include "../core/windows/SDL_windows.h"
 #endif
 
+
 // Many gamepads turn the center button into an instantaneous button press
 #define SDL_MINIMUM_GUIDE_BUTTON_DELAY_MS 250
 
@@ -3262,10 +3263,10 @@ bool SDL_ShouldIgnoreGamepad(Uint16 vendor_id, Uint16 product_id, Uint16 version
 
 #ifdef SDL_PLATFORM_WIN32
     if (SDL_GetHintBoolean("SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD", false) &&
-        SDL_GetHintBoolean("STEAM_COMPAT_PROTON", false)) {
-        // We are launched by Steam and running under Proton
+        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 Proton is doing the appropriate filtering of controllers
+        // so assume that is doing the appropriate filtering of controllers
         // and anything we see here is fine to use.
         return false;
     }