@@ -281,6 +281,9 @@ bool LogitechLED::TryHIDPPDiscovery(HANDLE h, USHORT outLen, USHORT inLen)
281281 // --- Enumerate ALL features ---
282282 BYTE bestLedIdx = 0 ;
283283 USHORT bestLedFid = 0 ;
284+ BYTE probeIdx[8 ] = {0 };
285+ USHORT probeFid[8 ] = {0 };
286+ int numProbe = 0 ;
284287
285288 for (int fi = 1 ; fi <= featureCount && fi < 128 ; fi++)
286289 {
@@ -301,17 +304,24 @@ bool LogitechLED::TryHIDPPDiscovery(HANDLE h, USHORT outLen, USHORT inLen)
301304 BYTE ftype = resp[6 ];
302305
303306 const char * name = " " ;
307+ bool isKnown = true ;
304308 switch (fid)
305309 {
306310 case 0x0001 : name = " (IFeatureSet)" ; break ;
307311 case 0x0003 : name = " (DeviceInfo)" ; break ;
308312 case 0x0005 : name = " (DeviceName)" ; break ;
309313 case 0x0007 : name = " (FriendlyName)" ; break ;
314+ case 0x00C1 : name = " (DfuControlUnsigned)" ; break ;
310315 case 0x00C2 : name = " (DfuControl)" ; break ;
311316 case 0x00D0 : name = " (Dfu)" ; break ;
312317 case 0x1000 : name = " (BatteryStatus)" ; break ;
313318 case 0x1300 : name = " (LEDControl)" ; break ;
319+ case 0x1800 : name = " (GenericTest)" ; break ;
320+ case 0x1802 : name = " (DeviceReset)" ; break ;
314321 case 0x1814 : name = " (ChangeHost)" ; break ;
322+ case 0x1BC0 : name = " (ReportHIDUsage)" ; break ;
323+ case 0x1E00 : name = " (EnableHiddenFeatures)" ; break ;
324+ case 0x1F1F : name = " (FirmwareProperties)" ; break ;
315325 case 0x1982 : name = " (Backlight2)" ; break ;
316326 case 0x1B04 : name = " (SpecialKeys)" ; break ;
317327 case 0x2201 : name = " (AdjDPI)" ; break ;
@@ -321,116 +331,137 @@ bool LogitechLED::TryHIDPPDiscovery(HANDLE h, USHORT outLen, USHORT inLen)
321331 case 0x8071 : name = " (RGBEffects)" ; break ;
322332 case 0x8081 : name = " (PerKeyLighting)" ; break ;
323333 case 0x8100 : name = " (OnboardProfiles)" ; break ;
334+ case 0x8120 : name = " (GamingAttachments)" ; break ;
335+ case 0x8123 : name = " (ForceFeedback)" ; break ;
336+ case 0x8127 : name = " (ForceFeedbackG923)" ; break ;
337+ default : isKnown = false ; break ;
324338 }
325339
326340 Log (" [%02d] 0x%04X type=0x%02X%s" , fi, fid, ftype, name);
327341
328- // Track LED-related features
342+ // Track candidate features to probe for LED control:
343+ // 1. Known LED features
344+ // 2. ANY unknown feature in 0x80xx range (could be wheel-specific LEDs)
329345 if (fid == 0x8070 || fid == 0x1300 || fid == 0x8071 ||
330346 fid == 0x8040 || fid == 0x1982 )
331347 {
348+ // Known LED features - highest priority
332349 if (bestLedIdx == 0 || fid == 0x8070 ||
333350 (bestLedFid != 0x8070 && fid == 0x1300 ))
334351 {
335352 bestLedIdx = (BYTE)fi;
336353 bestLedFid = fid;
337354 }
338355 }
356+
357+ // Store ALL unknown 0x8xxx features for probing
358+ if (!isKnown && (fid & 0xF000 ) == 0x8000 && numProbe < 8 )
359+ {
360+ probeIdx[numProbe] = (BYTE)fi;
361+ probeFid[numProbe] = fid;
362+ numProbe++;
363+ }
339364 }
340365
341366 Log (" " );
342367
343- if (bestLedIdx == 0 )
368+ // --- Probe known LED features first ---
369+ if (bestLedIdx != 0 )
344370 {
345- Log (" No LED-related feature found" );
346- Log (" Check feature list above for alternative LED features" );
347- continue ;
371+ Log (" >>> Known LED feature: 0x%04X at index %d" , bestLedFid, bestLedIdx);
372+ }
373+ else
374+ {
375+ Log (" No standard LED feature found" );
376+ if (numProbe > 0 )
377+ Log (" Will probe %d unknown 0x8xxx features" , numProbe);
348378 }
349379
350- Log (" >>> LED feature: 0x%04X at index %d" , bestLedFid, bestLedIdx);
351- Log (" " );
352-
353- // --- Probe LED feature: call func0 (getInfo) ---
354- memset (req, 0 , sizeof (req));
355- req[0 ] = reportId;
356- req[1 ] = devIdx;
357- req[2 ] = bestLedIdx;
358- req[3 ] = (0 << 4 ) | 0x01 ;
380+ // If no known LED feature, use the first unknown 0x8xxx feature
381+ if (bestLedIdx == 0 && numProbe > 0 )
382+ {
383+ bestLedIdx = probeIdx[0 ];
384+ bestLedFid = probeFid[0 ];
385+ Log (" >>> Trying unknown feature 0x%04X at index %d" , bestLedFid, bestLedIdx);
386+ }
359387
360- Log (" LED func0 (getInfo):" );
361- if (SendReport (h, req, outLen))
388+ if (bestLedIdx == 0 )
362389 {
363- memset (resp, 0 , sizeof (resp));
364- if (ReadReport (h, resp, inLen, 500 ))
365- {
366- if (resp[2 ] == 0xFF )
367- Log (" error: 0x%02X" , resp[5 ]);
368- else
369- Log (" data: %02X %02X %02X %02X %02X %02X %02X %02X" ,
370- resp[4 ], resp[5 ], resp[6 ], resp[7 ],
371- resp[8 ], resp[9 ], resp[10 ], resp[11 ]);
372- }
373- else Log (" no response" );
390+ Log (" Nothing to probe" );
391+ continue ;
374392 }
375393
376- // --- Try LED control commands ---
394+ // --- Probe ALL unknown 0x8xxx features with getInfo ---
377395 Log (" " );
378- Log (" === LED ATTEMPTS (watch the wheel!) ===" );
379-
380- struct LedTry { BYTE func; BYTE p[8 ]; const char * desc; };
381- LedTry tries[] = {
382- { 1 , {0x1F ,0x00 ,0 ,0 ,0 ,0 ,0 ,0 }, " func1(mask=0x1F)" },
383- { 1 , {0x1F ,0xFF ,0 ,0 ,0 ,0 ,0 ,0 }, " func1(0x1F,0xFF)" },
384- { 2 , {0x1F ,0x00 ,0 ,0 ,0 ,0 ,0 ,0 }, " func2(mask=0x1F)" },
385- { 2 , {0x1F ,0xFF ,0 ,0 ,0 ,0 ,0 ,0 }, " func2(0x1F,0xFF)" },
386- { 3 , {0x1F ,0x00 ,0 ,0 ,0 ,0 ,0 ,0 }, " func3(mask=0x1F)" },
387- { 1 , {0x00 ,0x01 ,0 ,0 ,0 ,0 ,0 ,0 }, " func1(led=0,on)" },
388- { 2 , {0x00 ,0x01 ,0 ,0 ,0 ,0 ,0 ,0 }, " func2(led=0,on)" },
389- { 1 , {0xFF ,0x00 ,0 ,0 ,0 ,0 ,0 ,0 }, " func1(0xFF)" },
390- { 2 , {0xFF ,0x00 ,0 ,0 ,0 ,0 ,0 ,0 }, " func2(0xFF)" },
391- { 1 , {0x64 ,0x00 ,0 ,0 ,0 ,0 ,0 ,0 }, " func1(rpm=100)" },
392- };
393- int numTries = sizeof (tries) / sizeof (tries[0 ]);
394- BYTE workingFunc = 0 ;
395-
396- for (int t = 0 ; t < numTries; t++)
396+ Log (" === Probing unknown features ===" );
397+ for (int pi = 0 ; pi < numProbe; pi++)
397398 {
398399 memset (req, 0 , sizeof (req));
399400 req[0 ] = reportId;
400401 req[1 ] = devIdx;
401- req[2 ] = bestLedIdx;
402- req[3 ] = (tries[t].func << 4 ) | 0x01 ;
403- memcpy (&req[4 ], tries[t].p , 8 );
404-
405- bool ok = SendReport (h, req, outLen);
406-
407- BYTE tryResp[64 ] = {0 };
408- bool gotResp = ok ? ReadReport (h, tryResp, inLen, 300 ) : false ;
402+ req[2 ] = probeIdx[pi];
403+ req[3 ] = (0 << 4 ) | 0x01 ; // func0 = getInfo
409404
410- if (!ok)
411- Log (" [%02d] %-22s SEND FAIL" , t, tries[t].desc );
412- else if (gotResp && tryResp[2 ] == 0xFF )
413- Log (" [%02d] %-22s ERR 0x%02X" , t, tries[t].desc , tryResp[5 ]);
414- else if (gotResp)
405+ if (SendReport (h, req, outLen))
415406 {
416- Log (" [%02d] %-22s OK resp=%02X %02X %02X %02X" ,
417- t, tries[t].desc ,
418- tryResp[4 ], tryResp[5 ], tryResp[6 ], tryResp[7 ]);
419- if (workingFunc == 0 ) workingFunc = tries[t].func ;
407+ memset (resp, 0 , sizeof (resp));
408+ if (ReadReport (h, resp, inLen, 500 ))
409+ {
410+ if (resp[2 ] == 0xFF )
411+ Log (" 0x%04X[%d] func0: ERR 0x%02X" ,
412+ probeFid[pi], probeIdx[pi], resp[5 ]);
413+ else
414+ Log (" 0x%04X[%d] func0: %02X %02X %02X %02X %02X %02X %02X %02X" ,
415+ probeFid[pi], probeIdx[pi],
416+ resp[4 ], resp[5 ], resp[6 ], resp[7 ],
417+ resp[8 ], resp[9 ], resp[10 ], resp[11 ]);
418+ }
419+ else
420+ Log (" 0x%04X[%d] func0: no response" , probeFid[pi], probeIdx[pi]);
420421 }
421- else
422+ }
423+
424+ // --- Try LED commands on each unknown 0x8xxx feature ---
425+ Log (" " );
426+ Log (" === LED attempts on unknown features (WATCH THE WHEEL!) ===" );
427+
428+ for (int pi = 0 ; pi < numProbe; pi++)
429+ {
430+ Log (" " );
431+ Log (" --- Feature 0x%04X at index %d ---" , probeFid[pi], probeIdx[pi]);
432+
433+ // Try func1-3 with LED bitmask 0x1F (all 5 LEDs)
434+ for (BYTE funcId = 1 ; funcId <= 3 ; funcId++)
422435 {
423- Log (" [%02d] %-22s OK (no resp)" , t, tries[t].desc );
424- if (workingFunc == 0 ) workingFunc = tries[t].func ;
425- }
436+ memset (req, 0 , sizeof (req));
437+ req[0 ] = reportId;
438+ req[1 ] = devIdx;
439+ req[2 ] = probeIdx[pi];
440+ req[3 ] = (funcId << 4 ) | 0x01 ;
441+ req[4 ] = 0x1F ; // all LEDs on
442+
443+ bool ok = SendReport (h, req, outLen);
444+ BYTE tryResp[64 ] = {0 };
445+ bool gotResp = ok ? ReadReport (h, tryResp, inLen, 300 ) : false ;
446+
447+ if (!ok)
448+ Log (" func%d(0x1F): SEND FAIL" , funcId);
449+ else if (gotResp && tryResp[2 ] == 0xFF )
450+ Log (" func%d(0x1F): ERR 0x%02X" , funcId, tryResp[5 ]);
451+ else if (gotResp)
452+ Log (" func%d(0x1F): OK resp=%02X %02X %02X %02X" ,
453+ funcId, tryResp[4 ], tryResp[5 ], tryResp[6 ], tryResp[7 ]);
454+ else
455+ Log (" func%d(0x1F): OK (no resp)" , funcId);
426456
427- Sleep (400 );
457+ Sleep (400 );
458+ }
428459 }
429460
430- // Save whatever we found
461+ // Save best guess
431462 m_method = METHOD_HIDPP;
432463 m_ledFeatureIdx = bestLedIdx;
433- m_ledFunctionId = (workingFunc > 0 ) ? workingFunc : 1 ;
464+ m_ledFunctionId = 1 ;
434465 m_deviceIdx = devIdx;
435466 Log (" " );
436467 Log (" HID++ saved: feat=0x%04X idx=%d func=%d devIdx=0x%02X" ,
0 commit comments