77#include < stdio.h>
88#include < stdarg.h>
99
10+ #define DIRECTINPUT_VERSION 0x0800
11+ #include < dinput.h>
12+
1013#pragma comment(lib, "hid.lib")
1114#pragma comment(lib, "setupapi.lib")
15+ #pragma comment(lib, "dxguid.lib")
1216
1317static const USHORT LOGITECH_VID = 0x046D ;
1418static const USHORT KNOWN_PIDS[] = { 0xC26E , 0xC26D , 0xC267 , 0xC266 , 0xC24F };
@@ -48,15 +52,19 @@ typedef bool (__cdecl *LogiSteeringInitWithWindow_t)(bool, HWND);
4852typedef bool (__cdecl *LogiUpdate_t)();
4953typedef bool (__cdecl *LogiIsConnected_t)(int );
5054typedef bool (__cdecl *LogiPlayLeds_t)(int , float , float , float );
55+ typedef bool (__cdecl *LogiPlayLedsDInput_t)(LPDIRECTINPUTDEVICE8, float , float , float );
5156typedef void (__cdecl *LogiSteeringShutdown_t)();
5257
5358static LogiSteeringInit_t g_SteeringInit = NULL ;
5459static LogiSteeringInitWithWindow_t g_SteeringInitWithWindow = NULL ;
5560static LogiUpdate_t g_SteeringUpdate = NULL ;
5661static LogiIsConnected_t g_IsConnected = NULL ;
5762static LogiPlayLeds_t g_PlayLeds = NULL ;
63+ static LogiPlayLedsDInput_t g_PlayLedsDInput = NULL ;
5864static LogiSteeringShutdown_t g_SteeringShutdown = NULL ;
5965static bool g_SteeringNeedsLateInit = false ;
66+ static LPDIRECTINPUTDEVICE8A g_realDIDevice = NULL ;
67+ static LPDIRECTINPUT8A g_realDI = NULL ;
6068
6169// Bypass flag declared in DllMain.cpp
6270extern volatile bool g_bypassDIWrapper;
@@ -106,8 +114,12 @@ LogitechLED::~LogitechLED()
106114
107115void LogitechLED::Close ()
108116{
109- if (m_method == METHOD_STEERING_SDK && g_SteeringShutdown)
110- g_SteeringShutdown ();
117+ if (m_method == METHOD_STEERING_SDK)
118+ {
119+ if (g_SteeringShutdown) g_SteeringShutdown ();
120+ if (g_realDIDevice) { g_realDIDevice->Release (); g_realDIDevice = NULL ; }
121+ if (g_realDI) { g_realDI->Release (); g_realDI = NULL ; }
122+ }
111123
112124 if (m_method == METHOD_SDK && g_LedShutdown)
113125 g_LedShutdown ();
@@ -137,6 +149,7 @@ void LogitechLED::Close()
137149 g_SteeringUpdate = NULL ;
138150 g_IsConnected = NULL ;
139151 g_PlayLeds = NULL ;
152+ g_PlayLedsDInput = NULL ;
140153 g_SteeringShutdown = NULL ;
141154 g_SteeringNeedsLateInit = false ;
142155 g_LedInit = NULL ;
@@ -269,6 +282,7 @@ bool LogitechLED::TrySteeringSDK()
269282 g_IsConnected = (LogiIsConnected_t)GetProcAddress (m_steeringDll, connNames[i]);
270283 for (int i = 0 ; ledsNames[i] && !g_PlayLeds; i++)
271284 g_PlayLeds = (LogiPlayLeds_t)GetProcAddress (m_steeringDll, ledsNames[i]);
285+ g_PlayLedsDInput = (LogiPlayLedsDInput_t)GetProcAddress (m_steeringDll, " LogiPlayLedsDInput" );
272286 for (int i = 0 ; shutNames[i] && !g_SteeringShutdown; i++)
273287 g_SteeringShutdown = (LogiSteeringShutdown_t)GetProcAddress (m_steeringDll, shutNames[i]);
274288
@@ -278,6 +292,7 @@ bool LogitechLED::TrySteeringSDK()
278292 Log (" Update: %s" , g_SteeringUpdate ? " FOUND" : " not found" );
279293 Log (" IsConnected: %s" , g_IsConnected ? " FOUND" : " not found" );
280294 Log (" PlayLeds: %s" , g_PlayLeds ? " FOUND" : " not found" );
295+ Log (" PlayLedsDInput: %s" , g_PlayLedsDInput ? " FOUND" : " not found" );
281296 Log (" Shutdown: %s" , g_SteeringShutdown ? " FOUND" : " not found" );
282297
283298 if (!g_SteeringUpdate || !g_IsConnected || !g_PlayLeds)
@@ -351,37 +366,126 @@ bool LogitechLED::TrySteeringSDK()
351366 bool connected = g_IsConnected (0 );
352367 Log (" LogiIsConnected(0) -> %s" , connected ? " YES" : " NO" );
353368
354- if (! connected)
369+ if (connected)
355370 {
356- Log (" Wheel not connected via this SDK" );
357- if (g_SteeringShutdown) g_SteeringShutdown ();
358- FreeLibrary (m_steeringDll);
359- m_steeringDll = NULL ;
360- return false ;
361- }
371+ // Standard path: SDK found the wheel by index
372+ g_SteeringUpdate ();
373+ bool led = g_PlayLeds (0 , 100 .0f , 0 .0f , 100 .0f );
374+ Log (" LogiPlayLeds(0, 100, 0, 100) -> %s *** ALL LEDs ***" , led ? " OK" : " FAIL" );
362375
363- // Test LEDs
364- g_SteeringUpdate ();
365- bool led = g_PlayLeds (0 , 100 .0f , 0 .0f , 100 .0f );
366- Log (" LogiPlayLeds(0, 100, 0, 100) -> %s *** ALL LEDs ***" , led ? " OK" : " FAIL" );
376+ if (led)
377+ {
378+ Sleep (1000 );
379+ g_SteeringUpdate ();
380+ g_PlayLeds (0 , 0 .0f , 0 .0f , 100 .0f );
381+ m_method = METHOD_STEERING_SDK;
382+ m_available = true ;
383+ Log (" === LED CONTROL ACTIVE (Steering Wheel SDK) ===" );
384+ return true ;
385+ }
386+ Log (" PlayLeds failed despite connection" );
387+ }
367388
368- if (!led)
389+ // Fallback: SDK doesn't know G923 PID, try LogiPlayLedsDInput
390+ // Create a REAL DirectInput device bypassing our wrapper
391+ if (g_PlayLedsDInput)
369392 {
370- Log (" PlayLeds failed" );
371- if (g_SteeringShutdown) g_SteeringShutdown ();
372- FreeLibrary (m_steeringDll);
373- m_steeringDll = NULL ;
374- return false ;
375- }
393+ Log (" Trying LogiPlayLedsDInput fallback..." );
376394
377- Sleep (1000 );
378- g_SteeringUpdate ();
379- g_PlayLeds (0 , 0 .0f , 0 .0f , 100 .0f );
395+ // Load the real system dinput8.dll
396+ char sysDir[MAX_PATH];
397+ GetSystemDirectoryA (sysDir, MAX_PATH);
398+ strcat_s (sysDir, MAX_PATH, " \\ dinput8.dll" );
380399
381- m_method = METHOD_STEERING_SDK;
382- m_available = true ;
383- Log (" === LED CONTROL ACTIVE (Steering Wheel SDK) ===" );
384- return true ;
400+ typedef HRESULT (WINAPI *DI8Create_t)(HINSTANCE, DWORD, REFIID, LPVOID*, LPUNKNOWN);
401+ HMODULE realDIDll = LoadLibraryA (sysDir);
402+ if (!realDIDll)
403+ {
404+ Log (" Failed to load real dinput8.dll from %s" , sysDir);
405+ }
406+ else
407+ {
408+ DI8Create_t realCreate = (DI8Create_t)GetProcAddress (realDIDll, " DirectInput8Create" );
409+ if (!realCreate)
410+ {
411+ Log (" DirectInput8Create not found in real dll" );
412+ FreeLibrary (realDIDll);
413+ }
414+ else
415+ {
416+ HRESULT hr = realCreate (GetModuleHandle (NULL ), DIRECTINPUT_VERSION,
417+ IID_IDirectInput8A, (LPVOID*)&g_realDI, NULL );
418+ Log (" Real DirectInput8Create -> 0x%08lX" , hr);
419+
420+ if (SUCCEEDED (hr) && g_realDI)
421+ {
422+ // Enumerate to find a Logitech wheel
423+ struct EnumCtx { GUID guid; bool found; };
424+ EnumCtx ctx = {{0 }, false };
425+
426+ g_realDI->EnumDevices (DI8DEVCLASS_GAMECTRL,
427+ [](const DIDEVICEINSTANCEA* inst, VOID* pCtx) -> BOOL {
428+ EnumCtx* c = (EnumCtx*)pCtx;
429+ USHORT vid = LOWORD (inst->guidProduct .Data1 );
430+ USHORT pid = HIWORD (inst->guidProduct .Data1 );
431+ Log (" DI device: VID=0x%04X PID=0x%04X '%s'" ,
432+ vid, pid, inst->tszInstanceName );
433+ if (vid == 0x046D && IsKnownPID (pid))
434+ {
435+ c->guid = inst->guidInstance ;
436+ c->found = true ;
437+ return DIENUM_STOP;
438+ }
439+ return DIENUM_CONTINUE;
440+ }, &ctx, DIEDFL_ATTACHEDONLY);
441+
442+ if (!ctx.found )
443+ {
444+ Log (" No Logitech wheel found via real DirectInput" );
445+ g_realDI->Release ();
446+ g_realDI = NULL ;
447+ }
448+ else
449+ {
450+ hr = g_realDI->CreateDevice (ctx.guid , &g_realDIDevice, NULL );
451+ Log (" CreateDevice -> 0x%08lX" , hr);
452+
453+ if (SUCCEEDED (hr) && g_realDIDevice)
454+ {
455+ // Test LogiPlayLedsDInput
456+ g_SteeringUpdate ();
457+ bool led = g_PlayLedsDInput (g_realDIDevice, 100 .0f , 0 .0f , 100 .0f );
458+ Log (" LogiPlayLedsDInput(dev, 100, 0, 100) -> %s *** ALL LEDs ***" ,
459+ led ? " OK" : " FAIL" );
460+
461+ if (led)
462+ {
463+ Sleep (1000 );
464+ g_SteeringUpdate ();
465+ g_PlayLedsDInput (g_realDIDevice, 0 .0f , 0 .0f , 100 .0f );
466+ m_method = METHOD_STEERING_SDK;
467+ m_available = true ;
468+ Log (" === LED CONTROL ACTIVE (Steering SDK + DInput) ===" );
469+ return true ;
470+ }
471+
472+ // Cleanup on failure
473+ g_realDIDevice->Release ();
474+ g_realDIDevice = NULL ;
475+ }
476+ g_realDI->Release ();
477+ g_realDI = NULL ;
478+ }
479+ }
480+ }
481+ }
482+ }
483+
484+ Log (" Steering SDK exhausted - falling through" );
485+ if (g_SteeringShutdown) g_SteeringShutdown ();
486+ FreeLibrary (m_steeringDll);
487+ m_steeringDll = NULL ;
488+ return false ;
385489 }
386490
387491 g_bypassDIWrapper = false ; // Restore wrapper
@@ -824,57 +928,30 @@ bool LogitechLED::SetLEDsFromPercent(double percent)
824928 if (percent > 1.0 ) percent = 1.0 ;
825929
826930 // For steering SDK, pass percentage directly as RPM for smooth LED progression
827- if (m_method == METHOD_STEERING_SDK && g_PlayLeds && g_SteeringUpdate)
931+ if (m_method == METHOD_STEERING_SDK && g_SteeringUpdate)
828932 {
829- // Deferred init: game window exists now
830- if (g_SteeringNeedsLateInit)
831- {
832- g_SteeringNeedsLateInit = false ;
833- bool ok = false ;
834-
835- HWND fg = GetForegroundWindow ();
836- if (fg && g_SteeringInitWithWindow)
837- {
838- ok = g_SteeringInitWithWindow (false , fg);
839- Log (" LATE InitWithWindow(false, hwnd=0x%p) -> %s" , fg, ok ? " OK" : " FAIL" );
840- }
841- if (!ok && g_SteeringInit)
842- {
843- ok = g_SteeringInit (false );
844- Log (" LATE LogiSteeringInitialize(false) -> %s" , ok ? " OK" : " FAIL" );
845- }
846-
847- if (ok)
848- {
849- for (int retry = 0 ; retry < 10 ; retry++)
850- {
851- Sleep (200 );
852- g_SteeringUpdate ();
853- if (g_IsConnected (0 ))
854- {
855- Log (" LATE: Wheel connected (after %d updates)" , retry + 1 );
856- break ;
857- }
858- }
859- Log (" LATE: LogiIsConnected(0) -> %s" , g_IsConnected (0 ) ? " YES" : " NO" );
860- }
861- else
862- {
863- Log (" LATE init also failed - steering SDK unavailable" );
864- m_method = METHOD_NONE;
865- m_available = false ;
866- return false ;
867- }
868- }
869-
870933 float rpm = (float )(percent * 100.0 );
871934 g_SteeringUpdate ();
872- bool ok = g_PlayLeds (0 , rpm, 0 .0f , 100 .0f );
873935
874- g_setLedsCallCount++;
875- if (g_setLedsCallCount <= 20 || !ok)
876- Log (" SetLEDsFromPercent(%.2f) [SteeringSDK rpm=%.0f] -> %s (#%d)" ,
877- percent, rpm, ok ? " OK" : " FAIL" , g_setLedsCallCount);
936+ bool ok = false ;
937+
938+ // Prefer LogiPlayLedsDInput (works without SDK device detection)
939+ if (g_PlayLedsDInput && g_realDIDevice)
940+ {
941+ ok = g_PlayLedsDInput (g_realDIDevice, rpm, 0 .0f , 100 .0f );
942+ g_setLedsCallCount++;
943+ if (g_setLedsCallCount <= 20 || !ok)
944+ Log (" SetLEDsFromPercent(%.2f) [DInput rpm=%.0f] -> %s (#%d)" ,
945+ percent, rpm, ok ? " OK" : " FAIL" , g_setLedsCallCount);
946+ }
947+ else if (g_PlayLeds)
948+ {
949+ ok = g_PlayLeds (0 , rpm, 0 .0f , 100 .0f );
950+ g_setLedsCallCount++;
951+ if (g_setLedsCallCount <= 20 || !ok)
952+ Log (" SetLEDsFromPercent(%.2f) [SteeringSDK rpm=%.0f] -> %s (#%d)" ,
953+ percent, rpm, ok ? " OK" : " FAIL" , g_setLedsCallCount);
954+ }
878955
879956 return ok;
880957 }
0 commit comments