SDL: Fixed crash when the broken EZFRD64.DLL is present

From f369e804e27731e128caf3b370e0569e0695c57e Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 7 Jan 2026 17:11:57 -0800
Subject: [PATCH] Fixed crash when the broken EZFRD64.DLL is present

Fixes https://github.com/ppy/osu/issues/13634
---
 src/joystick/windows/SDL_dinputjoystick.c | 38 +++++++++++++++++++----
 1 file changed, 32 insertions(+), 6 deletions(-)

diff --git a/src/joystick/windows/SDL_dinputjoystick.c b/src/joystick/windows/SDL_dinputjoystick.c
index d265d9fcd5fa4..62ffbb46ec9fa 100644
--- a/src/joystick/windows/SDL_dinputjoystick.c
+++ b/src/joystick/windows/SDL_dinputjoystick.c
@@ -45,6 +45,7 @@ extern HWND SDL_HelperWindow;
 // local variables
 static bool coinitialized = false;
 static LPDIRECTINPUT8 dinput = NULL;
+static bool has_broken_EZFRD64DLL = false;
 
 // Taken from Wine - Thanks!
 static DIOBJECTDATAFORMAT dfDIJoystick2[] = {
@@ -437,6 +438,29 @@ bool SDL_DINPUT_JoystickInit(void)
         dinput = NULL;
         return SetDIerror("IDirectInput::Initialize", result);
     }
+
+#ifdef _WIN64
+    if (SDL_GetHintBoolean("SDL_JOYSTICK_CHECK_EZFRD64", true)) {
+        // The 64-bit version of EZFRD64.DLL crashes after being loaded,
+        // which happens implicitly when querying the device capabilities,
+        // so make sure we don't do that if there's a possibility of crashing
+        static const char *directories[] = {
+            "C:/Windows/USB_Vibration",
+            "C:/Windows/USB Vibration"
+        };
+        for (int i = 0; i < SDL_arraysize(directories) && !has_broken_EZFRD64DLL; ++i) {
+            int count = 0;
+            char **files = SDL_GlobDirectory(directories[i], "*/EZFRD64.DLL", SDL_GLOB_CASEINSENSITIVE, &count);
+            if (count > 0) {
+                has_broken_EZFRD64DLL = true;
+            }
+            SDL_free(files);
+        }
+        if (has_broken_EZFRD64DLL) {
+            SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Broken EZFRD64.DLL detected, disabling DirectInput force feedback");
+        }
+    }
+#endif
     return true;
 }
 
@@ -778,12 +802,14 @@ bool SDL_DINPUT_JoystickOpen(SDL_Joystick *joystick, JoyStick_DeviceData *joysti
         return SetDIerror("IDirectInputDevice8::SetDataFormat", result);
     }
 
-    // Get device capabilities
-    result =
-        IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice,
-                                            &joystick->hwdata->Capabilities);
-    if (FAILED(result)) {
-        return SetDIerror("IDirectInputDevice8::GetCapabilities", result);
+    if (!has_broken_EZFRD64DLL) {
+        // Get device capabilities to see if we are force feedback capable
+        result =
+            IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice,
+                                                &joystick->hwdata->Capabilities);
+        if (FAILED(result)) {
+            return SetDIerror("IDirectInputDevice8::GetCapabilities", result);
+        }
     }
 
     // Force capable?