44#include < setupapi.h>
55#include < hidsdi.h>
66#include < hidpi.h>
7+ #include < stdio.h>
78
89#pragma comment(lib, "hid.lib")
910#pragma comment(lib, "setupapi.lib")
@@ -21,9 +22,20 @@ static const USHORT G29_PID = 0xC24F;
2122static const BYTE LOGITECH_CMD_SET_LED = 0xF8 ;
2223static const BYTE LOGITECH_LED_SUBCMD = 0x12 ;
2324
25+ // Forward declaration for logging (defined in DllMain.cpp)
26+ extern void LogMessage (const char * fmt, ...);
27+
28+ // Simple log helper - uses OutputDebugString if LogMessage is not available
29+ static void LEDLog (const char * msg)
30+ {
31+ OutputDebugStringA (msg);
32+ OutputDebugStringA (" \n " );
33+ }
34+
2435LogitechLED::LogitechLED ()
2536 : m_deviceHandle(INVALID_HANDLE_VALUE)
2637 , m_available(false )
38+ , m_outputReportLength(0 )
2739{
2840}
2941
@@ -49,6 +61,7 @@ void LogitechLED::Close()
4961 m_deviceHandle = INVALID_HANDLE_VALUE;
5062 }
5163 m_available = false ;
64+ m_outputReportLength = 0 ;
5265}
5366
5467bool LogitechLED::IsAvailable () const
@@ -58,34 +71,43 @@ bool LogitechLED::IsAvailable() const
5871
5972bool LogitechLED::SetLEDs (BYTE ledMask)
6073{
61- if (!m_available || m_deviceHandle == INVALID_HANDLE_VALUE)
74+ if (!m_available || m_deviceHandle == INVALID_HANDLE_VALUE || m_outputReportLength == 0 )
6275 return false ;
6376
64- // Logitech extended HID report for RPM LEDs
65- // Format: [ReportID, CMD, SUBCMD, LED_MASK, 0, 0, 0, 1]
66- BYTE report[8 ] = { 0 };
67- report[0 ] = LOGITECH_CMD_SET_LED; // 0xF8
68- report[1 ] = LOGITECH_LED_SUBCMD; // 0x12
69- report[2 ] = ledMask & 0x1F ; // 5 LEDs, bits 0-4
70- report[3 ] = 0x00 ;
77+ // Allocate buffer matching the device's expected output report length
78+ BYTE* report = (BYTE*)calloc (m_outputReportLength, 1 );
79+ if (!report)
80+ return false ;
81+
82+ // First byte = Report ID (0x00 for default)
83+ // Then the Logitech extended command
84+ report[0 ] = 0x00 ; // Report ID
85+ report[1 ] = LOGITECH_CMD_SET_LED; // 0xF8
86+ report[2 ] = LOGITECH_LED_SUBCMD; // 0x12
87+ report[3 ] = ledMask & 0x1F ; // 5 LEDs, bits 0-4
7188 report[4 ] = 0x00 ;
7289 report[5 ] = 0x00 ;
7390 report[6 ] = 0x00 ;
7491 report[7 ] = 0x01 ;
7592
7693 DWORD bytesWritten = 0 ;
77- BOOL result = WriteFile (m_deviceHandle, report, sizeof (report) , &bytesWritten, NULL );
94+ BOOL result = WriteFile (m_deviceHandle, report, m_outputReportLength , &bytesWritten, NULL );
7895
7996 if (!result)
8097 {
81- // Device may have been disconnected
8298 DWORD err = GetLastError ();
99+ char buf[256 ];
100+ sprintf_s (buf, " LogitechLED: WriteFile failed, error=%lu, reportLen=%u, mask=0x%02X" ,
101+ err, m_outputReportLength, ledMask);
102+ LEDLog (buf);
103+
83104 if (err == ERROR_DEVICE_NOT_CONNECTED || err == ERROR_GEN_FAILURE)
84105 {
85106 Close ();
86107 }
87108 }
88109
110+ free (report);
89111 return result == TRUE ;
90112}
91113
@@ -121,13 +143,21 @@ bool LogitechLED::FindAndOpenDevice()
121143 DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
122144
123145 if (deviceInfoSet == INVALID_HANDLE_VALUE)
146+ {
147+ LEDLog (" LogitechLED: SetupDiGetClassDevs failed" );
124148 return false ;
149+ }
125150
126151 SP_DEVICE_INTERFACE_DATA interfaceData;
127152 interfaceData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);
128153
154+ int deviceCount = 0 ;
155+ int logitechCount = 0 ;
156+
129157 for (DWORD i = 0 ; SetupDiEnumDeviceInterfaces (deviceInfoSet, NULL , &hidGuid, i, &interfaceData); i++)
130158 {
159+ deviceCount++;
160+
131161 // Get required buffer size
132162 DWORD requiredSize = 0 ;
133163 SetupDiGetDeviceInterfaceDetailA (deviceInfoSet, &interfaceData, NULL , 0 , &requiredSize, NULL );
@@ -145,7 +175,7 @@ bool LogitechLED::FindAndOpenDevice()
145175 continue ;
146176 }
147177
148- // Open the device to check VID/PID
178+ // Open the device
149179 HANDLE handle = CreateFileA (
150180 detailData->DevicePath ,
151181 GENERIC_READ | GENERIC_WRITE,
@@ -168,21 +198,39 @@ bool LogitechLED::FindAndOpenDevice()
168198 attrs.ProductID == G923_PID_PS ||
169199 attrs.ProductID == G29_PID))
170200 {
171- // Check this is the right HID interface for output reports
172- // by verifying the output report length
201+ logitechCount++;
202+
173203 PHIDP_PREPARSED_DATA preparsedData = NULL ;
174204 if (HidD_GetPreparsedData (handle, &preparsedData))
175205 {
176206 HIDP_CAPS caps;
177207 if (HidP_GetCaps (preparsedData, &caps) == HIDP_STATUS_SUCCESS)
178208 {
179- // We need an output report length that can hold our 8-byte command
209+ char buf[512 ];
210+ sprintf_s (buf,
211+ " LogitechLED: Found Logitech VID=0x%04X PID=0x%04X "
212+ " UsagePage=0x%04X Usage=0x%04X "
213+ " InputReportLen=%u OutputReportLen=%u FeatureReportLen=%u "
214+ " Path=%s" ,
215+ attrs.VendorID , attrs.ProductID ,
216+ caps.UsagePage , caps.Usage ,
217+ caps.InputReportByteLength ,
218+ caps.OutputReportByteLength ,
219+ caps.FeatureReportByteLength ,
220+ detailData->DevicePath );
221+ LEDLog (buf);
222+
223+ // We need an output report length that can hold our command
180224 if (caps.OutputReportByteLength >= 8 )
181225 {
226+ m_outputReportLength = caps.OutputReportByteLength ;
182227 HidD_FreePreparsedData (preparsedData);
183228 free (detailData);
184229 SetupDiDestroyDeviceInfoList (deviceInfoSet);
185230 m_deviceHandle = handle;
231+
232+ sprintf_s (buf, " LogitechLED: Using device with OutputReportLen=%u" , m_outputReportLength);
233+ LEDLog (buf);
186234 return true ;
187235 }
188236 }
@@ -195,6 +243,11 @@ bool LogitechLED::FindAndOpenDevice()
195243 free (detailData);
196244 }
197245
246+ char buf[128 ];
247+ sprintf_s (buf, " LogitechLED: Enumerated %d HID devices, found %d Logitech matches, none suitable" ,
248+ deviceCount, logitechCount);
249+ LEDLog (buf);
250+
198251 SetupDiDestroyDeviceInfoList (deviceInfoSet);
199252 return false ;
200253}
0 commit comments