Skip to content

Commit 671d89e

Browse files
Surface QMK discovery results to the user (v4.1.43)
Previously: enabling the QMK Keyboards toggle with no boards plugged in flashed the button on and then back off with no console output, no dialog — looking exactly like a bug. Now: - QmkRawHidDiscovery logs the full enumeration breakdown to the console (HID device count, Raw HID candidates found, open-failures, handshake misses, final usable count). When a candidate fails handshake the log includes the reason — most usefully, "could not open the Raw HID interface (likely held exclusively by another app — close VIA / Vial / OpenRGB and try again)". - SettingsViewModel's enable handler now logs "Scanning..." before discovery, and pops a localised "No QMK Keyboards Found" dialog when discovery returns empty so the user can see exactly why the toggle didn't take. Strings routed through LocalizationService.Instance per the localization rule; en.json + the six non-EN locales updated via translate.py. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f5b19a8 commit 671d89e

11 files changed

Lines changed: 101 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
All notable changes to Chromatics are documented here.
44

5-
## 4.1.42
5+
## 4.1.43
66

77
- **New:** QMK Raw HID keyboard support (Beta). Covers custom keyboards from NovelKeys, KBDFans, Drop, GMMK, Glorious and any other brand running QMK firmware with Raw HID enabled. Enable it from Settings → Device Providers, or pick it on the first-run device selector. Chromatics auto-detects compatible boards on USB and adopts them — no firmware flashing or extra software required. Per-key lighting is driven via the OpenRGB-QMK plugin when the firmware has it installed; otherwise Chromatics drives the firmware's built-in RGB matrix base colour and effect mode (VIA). For per-key LED boards, Chromatics looks up the physical key layout from the via-keyboards database automatically on first connect so the Highlight / Keybind layers line up with the right keys out of the box.
88
- Updated dependency libraries to latest version

Chromatics/Chromatics.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<OutputType>WinExe</OutputType>
55
<TargetFramework>net10.0-windows7.0</TargetFramework>
66
<StartupObject>Chromatics.Program</StartupObject>
7-
<Version>4.1.42.0</Version>
7+
<Version>4.1.43.0</Version>
88
<Authors>Danielle Thompson</Authors>
99
<ApplicationManifest>app.manifest</ApplicationManifest>
1010
<Copyright>logicallysynced 2026</Copyright>

Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/Protocol/QmkRawHidDiscovery.cs

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using Chromatics.Core;
2+
using Chromatics.Enums;
13
using HidSharp;
24
using HidSharp.Reports;
35
using System;
@@ -44,17 +46,48 @@ public static IReadOnlyList<Candidate> Discover()
4446
var results = new List<Candidate>();
4547
HidDevice[] all;
4648
try { all = DeviceList.Local.GetHidDevices() as HidDevice[] ?? new List<HidDevice>(DeviceList.Local.GetHidDevices()).ToArray(); }
47-
catch { return results; }
49+
catch (Exception ex)
50+
{
51+
Logger.WriteConsole(LoggerTypes.Devices,
52+
$"[QMK] HID enumeration failed: {ex.Message}",
53+
forwardToSentry: false);
54+
return results;
55+
}
56+
57+
Logger.WriteConsole(LoggerTypes.Devices,
58+
$"[QMK] Enumerated {all.Length} HID device(s) on the USB bus; scanning for the Raw HID interface (usage page 0x{QmkRawHidConstants.RawHidUsagePage:X4}, usage 0x{QmkRawHidConstants.RawHidUsage:X2})...");
59+
60+
int rawHidCandidates = 0;
61+
int openFailures = 0;
62+
int handshakeMisses = 0;
4863

4964
foreach (HidDevice hid in all)
5065
{
5166
if (!ExposesRawHidUsage(hid)) continue;
67+
rawHidCandidates++;
68+
69+
Logger.WriteConsole(LoggerTypes.Devices,
70+
$"[QMK] Candidate: VID=0x{hid.VendorID:X4} PID=0x{hid.ProductID:X4} ({SafeProductName(hid)} / {SafeManufacturer(hid)})");
5271

53-
if (!TryHandshake(hid, out var protocol, out int ledCount, out byte cols, out byte rows, out string fwName))
72+
if (!TryHandshake(hid, out var protocol, out int ledCount, out byte cols, out byte rows, out string fwName, out string failureReason))
73+
{
74+
openFailures++;
75+
Logger.WriteConsole(LoggerTypes.Devices,
76+
$"[QMK] handshake skipped — {failureReason}",
77+
forwardToSentry: false);
5478
continue;
79+
}
5580

56-
if (protocol == ProtocolSupport.None) continue;
81+
if (protocol == ProtocolSupport.None)
82+
{
83+
handshakeMisses++;
84+
Logger.WriteConsole(LoggerTypes.Devices,
85+
"[QMK] neither VIA nor OpenRGB-QMK responded; firmware probably doesn't have Raw HID enabled.");
86+
continue;
87+
}
5788

89+
Logger.WriteConsole(LoggerTypes.Devices,
90+
$"[QMK] handshake OK — protocol: {protocol}, LEDs: {ledCount}, matrix: {cols}x{rows}");
5891
results.Add(new Candidate(hid, protocol, ledCount, cols, rows, fwName));
5992
}
6093

@@ -65,9 +98,18 @@ public static IReadOnlyList<Candidate> Discover()
6598
return a.Hid.ProductID.CompareTo(b.Hid.ProductID);
6699
});
67100

101+
Logger.WriteConsole(LoggerTypes.Devices,
102+
$"[QMK] Discovery done: {all.Length} HID devices total, {rawHidCandidates} with Raw HID interface, " +
103+
$"{openFailures} could not be opened, {handshakeMisses} did not respond to handshake, {results.Count} usable.");
104+
68105
return results;
69106
}
70107

108+
private static string SafeManufacturer(HidDevice hid)
109+
{ try { return hid.GetManufacturer() ?? ""; } catch { return "?"; } }
110+
private static string SafeProductName(HidDevice hid)
111+
{ try { return hid.GetProductName() ?? ""; } catch { return "?"; } }
112+
71113
// Returns true if any of the HidDevice's top-level collections
72114
// declares usage page 0xFF60, usage 0x61. Multi-interface USB
73115
// devices expose each interface as a separate HidDevice, so
@@ -97,17 +139,26 @@ private static bool ExposesRawHidUsage(HidDevice hid)
97139
// strictly more capable protocol. Stream is disposed before
98140
// we return; the provider will reopen it for the device's
99141
// permanent UpdateQueue.
100-
private static bool TryHandshake(HidDevice hid, out ProtocolSupport protocol, out int ledCount, out byte cols, out byte rows, out string firmwareDeviceName)
142+
private static bool TryHandshake(HidDevice hid, out ProtocolSupport protocol, out int ledCount, out byte cols, out byte rows, out string firmwareDeviceName, out string failureReason)
101143
{
102144
protocol = ProtocolSupport.None;
103145
ledCount = 0; cols = 0; rows = 0; firmwareDeviceName = string.Empty;
146+
failureReason = string.Empty;
104147

105148
HidStream stream;
106149
try
107150
{
108-
if (!hid.TryOpen(out stream)) return false;
151+
if (!hid.TryOpen(out stream))
152+
{
153+
failureReason = "could not open the Raw HID interface (likely held exclusively by another app — close VIA / Vial / OpenRGB and try again)";
154+
return false;
155+
}
156+
}
157+
catch (Exception ex)
158+
{
159+
failureReason = $"open threw: {ex.Message}";
160+
return false;
109161
}
110-
catch { return false; }
111162

112163
try
113164
{

Chromatics/ViewModels/SettingsViewModel.cs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Chromatics.Models;
1111
using Chromatics.Helpers;
1212
using Chromatics.Views;
13+
using Chromatics.Views.Dialogs;
1314
using Microsoft.VisualBasic.FileIO;
1415
using Microsoft.Win32;
1516
using RGB.NET.Devices.Asus;
@@ -281,15 +282,18 @@ private void BuildDeviceToggles(Models.SettingsModel s)
281282
"QMK Keyboards (Beta)",
282283
"[BETA] Enable/disable QMK Raw HID keyboard support. Auto-adopts any QMK-compatible keyboard with Raw HID enabled (covers NovelKeys, KBDFans, Drop, GMMK, Glorious, and other custom QMK boards). Default: Disabled",
283284
s.deviceQmkRawHidEnabled,
284-
() =>
285+
async () =>
285286
{
286287
var cur = AppSettings.GetSettings();
287288

289+
Logger.WriteConsole(LoggerTypes.Devices,
290+
"[QMK] Scanning for QMK-compatible keyboards on the USB bus...");
291+
288292
// Discovery + auto-adopt: run on a background thread to
289293
// keep the Settings dialog responsive — per-device VIA
290294
// handshakes can take 200-500ms each on a sluggish USB
291295
// stack, and discovery + handshake of 5+ boards adds up.
292-
return Task.Run(() =>
296+
bool result = await Task.Run(() =>
293297
{
294298
var discovered = Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.Protocol.QmkRawHidDiscovery.Discover();
295299
if (discovered.Count == 0)
@@ -334,6 +338,22 @@ private void BuildDeviceToggles(Models.SettingsModel s)
334338
Chromatics.Extensions.RGB.NET.Devices.QmkRawHid.QmkRawHidRGBDeviceProvider.Instance);
335339
return true;
336340
});
341+
342+
if (!result)
343+
{
344+
// The "no boards found" path. Logger.WriteConsole has
345+
// already written the detailed enumeration breakdown
346+
// (count of HID devices seen, candidates with the
347+
// Raw HID interface, open-failures, etc.). Surface a
348+
// short user-facing dialog too so it's obvious why
349+
// the toggle didn't take — without this the toggle
350+
// flashes on then back off with no visible feedback.
351+
await DialogService.ShowAsync(
352+
LocalizationService.Instance["No QMK Keyboards Found"],
353+
LocalizationService.Instance["Chromatics didn't detect any QMK keyboards on this PC. Make sure your keyboard is plugged in over USB and that its firmware has Raw HID enabled (this is the default for any VIA-compatible build). If you have VIA, Vial, or OpenRGB running, close it before enabling this provider — they hold the Raw HID interface exclusively. See the console for a detailed breakdown of which HID devices were enumerated."]);
354+
}
355+
356+
return result;
337357
},
338358
() =>
339359
{

Chromatics/locale/de.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -840,5 +840,7 @@
840840
"Couldn't read lights from the bridge: {0}": "Lampen konnten nicht von der Bridge gelesen werden: {0}",
841841
"QMK Keyboards (Beta)": "QMK-Tastaturen (Beta)",
842842
"QMK keyboards over Raw HID. Covers NovelKeys, KBDFans, Drop, GMMK, Glorious and any other custom keyboard running QMK with Raw HID enabled.": "QMK-Tastaturen über Raw HID. Umfasst NovelKeys, KBDFans, Drop, GMMK, Glorious und jede andere benutzerdefinierte Tastatur, auf der QMK mit aktiviertem Raw HID läuft.",
843-
"[BETA] Enable/disable QMK Raw HID keyboard support. Auto-adopts any QMK-compatible keyboard with Raw HID enabled (covers NovelKeys, KBDFans, Drop, GMMK, Glorious, and other custom QMK boards). Default: Disabled": "[BETA] QMK-Raw-HID-Tastaturunterstützung aktivieren/deaktivieren. Übernimmt automatisch jede QMK-kompatible Tastatur mit aktiviertem Raw HID (umfasst NovelKeys, KBDFans, Drop, GMMK, Glorious und andere benutzerdefinierte QMK-Boards). Standard: Deaktiviert"
843+
"[BETA] Enable/disable QMK Raw HID keyboard support. Auto-adopts any QMK-compatible keyboard with Raw HID enabled (covers NovelKeys, KBDFans, Drop, GMMK, Glorious, and other custom QMK boards). Default: Disabled": "[BETA] QMK-Raw-HID-Tastaturunterstützung aktivieren/deaktivieren. Übernimmt automatisch jede QMK-kompatible Tastatur mit aktiviertem Raw HID (umfasst NovelKeys, KBDFans, Drop, GMMK, Glorious und andere benutzerdefinierte QMK-Boards). Standard: Deaktiviert",
844+
"No QMK Keyboards Found": "Keine QMK-Tastaturen gefunden",
845+
"Chromatics didn't detect any QMK keyboards on this PC. Make sure your keyboard is plugged in over USB and that its firmware has Raw HID enabled (this is the default for any VIA-compatible build). If you have VIA, Vial, or OpenRGB running, close it before enabling this provider — they hold the Raw HID interface exclusively. See the console for a detailed breakdown of which HID devices were enumerated.": "Chromatics hat auf diesem PC keine QMK-Tastaturen erkannt. Stelle sicher, dass deine Tastatur über USB angeschlossen ist und dass in ihrer Firmware Raw HID aktiviert ist (dies ist die Standardeinstellung für jeden VIA-kompatiblen Build). Falls VIA, Vial oder OpenRGB ausgeführt wird, schließe es, bevor du diesen Anbieter aktivierst — sie belegen die Raw-HID-Schnittstelle exklusiv. In der Konsole findest du eine detaillierte Aufschlüsselung, welche HID-Geräte aufgelistet wurden."
844846
}

Chromatics/locale/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,8 @@
621621
"PlayStation (Beta)": "PlayStation (Beta)",
622622
"QMK Keyboards (Beta)": "QMK Keyboards (Beta)",
623623
"QMK keyboards over Raw HID. Covers NovelKeys, KBDFans, Drop, GMMK, Glorious and any other custom keyboard running QMK with Raw HID enabled.": "QMK keyboards over Raw HID. Covers NovelKeys, KBDFans, Drop, GMMK, Glorious and any other custom keyboard running QMK with Raw HID enabled.",
624+
"No QMK Keyboards Found": "No QMK Keyboards Found",
625+
"Chromatics didn't detect any QMK keyboards on this PC. Make sure your keyboard is plugged in over USB and that its firmware has Raw HID enabled (this is the default for any VIA-compatible build). If you have VIA, Vial, or OpenRGB running, close it before enabling this provider — they hold the Raw HID interface exclusively. See the console for a detailed breakdown of which HID devices were enumerated.": "Chromatics didn't detect any QMK keyboards on this PC. Make sure your keyboard is plugged in over USB and that its firmware has Raw HID enabled (this is the default for any VIA-compatible build). If you have VIA, Vial, or OpenRGB running, close it before enabling this provider — they hold the Raw HID interface exclusively. See the console for a detailed breakdown of which HID devices were enumerated.",
624626
"[BETA] Enable/disable QMK Raw HID keyboard support. Auto-adopts any QMK-compatible keyboard with Raw HID enabled (covers NovelKeys, KBDFans, Drop, GMMK, Glorious, and other custom QMK boards). Default: Disabled": "[BETA] Enable/disable QMK Raw HID keyboard support. Auto-adopts any QMK-compatible keyboard with Raw HID enabled (covers NovelKeys, KBDFans, Drop, GMMK, Glorious, and other custom QMK boards). Default: Disabled",
625627
"Enable/disable Razer device library. Default: Enabled": "Enable/disable Razer device library. Default: Enabled",
626628
"Enable/disable Logitech device library. Default: Enabled": "Enable/disable Logitech device library. Default: Enabled",

Chromatics/locale/es.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -840,5 +840,7 @@
840840
"Couldn't read lights from the bridge: {0}": "No se pudieron leer las luces del puente: {0}",
841841
"QMK Keyboards (Beta)": "Teclados QMK (Beta)",
842842
"QMK keyboards over Raw HID. Covers NovelKeys, KBDFans, Drop, GMMK, Glorious and any other custom keyboard running QMK with Raw HID enabled.": "Teclados QMK mediante Raw HID. Cubre NovelKeys, KBDFans, Drop, GMMK, Glorious y cualquier otro teclado personalizado que ejecute QMK con Raw HID habilitado.",
843-
"[BETA] Enable/disable QMK Raw HID keyboard support. Auto-adopts any QMK-compatible keyboard with Raw HID enabled (covers NovelKeys, KBDFans, Drop, GMMK, Glorious, and other custom QMK boards). Default: Disabled": "[BETA] Activa/desactiva la compatibilidad con teclados QMK Raw HID. Adopta automáticamente cualquier teclado compatible con QMK que tenga Raw HID habilitado (cubre NovelKeys, KBDFans, Drop, GMMK, Glorious y otros teclados QMK personalizados). Valor predeterminado: Desactivado"
843+
"[BETA] Enable/disable QMK Raw HID keyboard support. Auto-adopts any QMK-compatible keyboard with Raw HID enabled (covers NovelKeys, KBDFans, Drop, GMMK, Glorious, and other custom QMK boards). Default: Disabled": "[BETA] Activa/desactiva la compatibilidad con teclados QMK Raw HID. Adopta automáticamente cualquier teclado compatible con QMK que tenga Raw HID habilitado (cubre NovelKeys, KBDFans, Drop, GMMK, Glorious y otros teclados QMK personalizados). Valor predeterminado: Desactivado",
844+
"No QMK Keyboards Found": "No se encontraron teclados QMK",
845+
"Chromatics didn't detect any QMK keyboards on this PC. Make sure your keyboard is plugged in over USB and that its firmware has Raw HID enabled (this is the default for any VIA-compatible build). If you have VIA, Vial, or OpenRGB running, close it before enabling this provider — they hold the Raw HID interface exclusively. See the console for a detailed breakdown of which HID devices were enumerated.": "Chromatics no detectó ningún teclado QMK en este PC. Asegúrate de que el teclado esté conectado por USB y de que su firmware tenga habilitado Raw HID (esto es lo predeterminado en cualquier compilación compatible con VIA). Si tienes VIA, Vial u OpenRGB en ejecución, ciérralo antes de habilitar este proveedor, ya que mantienen la interfaz Raw HID en exclusiva. Consulta la consola para ver un desglose detallado de los dispositivos HID que se enumeraron."
844846
}

Chromatics/locale/fr.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -840,5 +840,7 @@
840840
"Couldn't read lights from the bridge: {0}": "Impossible de lire les lumières depuis le pont : {0}",
841841
"QMK Keyboards (Beta)": "Claviers QMK (bêta)",
842842
"QMK keyboards over Raw HID. Covers NovelKeys, KBDFans, Drop, GMMK, Glorious and any other custom keyboard running QMK with Raw HID enabled.": "Claviers QMK via Raw HID. Couvre NovelKeys, KBDFans, Drop, GMMK, Glorious et tout autre clavier personnalisé exécutant QMK avec Raw HID activé.",
843-
"[BETA] Enable/disable QMK Raw HID keyboard support. Auto-adopts any QMK-compatible keyboard with Raw HID enabled (covers NovelKeys, KBDFans, Drop, GMMK, Glorious, and other custom QMK boards). Default: Disabled": "[BÊTA] Activer/désactiver la prise en charge des claviers QMK Raw HID. Adopte automatiquement tout clavier compatible QMK avec Raw HID activé (couvre NovelKeys, KBDFans, Drop, GMMK, Glorious et autres claviers QMK personnalisés). Par défaut : désactivé"
843+
"[BETA] Enable/disable QMK Raw HID keyboard support. Auto-adopts any QMK-compatible keyboard with Raw HID enabled (covers NovelKeys, KBDFans, Drop, GMMK, Glorious, and other custom QMK boards). Default: Disabled": "[BÊTA] Activer/désactiver la prise en charge des claviers QMK Raw HID. Adopte automatiquement tout clavier compatible QMK avec Raw HID activé (couvre NovelKeys, KBDFans, Drop, GMMK, Glorious et autres claviers QMK personnalisés). Par défaut : désactivé",
844+
"No QMK Keyboards Found": "Aucun clavier QMK trouvé",
845+
"Chromatics didn't detect any QMK keyboards on this PC. Make sure your keyboard is plugged in over USB and that its firmware has Raw HID enabled (this is the default for any VIA-compatible build). If you have VIA, Vial, or OpenRGB running, close it before enabling this provider — they hold the Raw HID interface exclusively. See the console for a detailed breakdown of which HID devices were enumerated.": "Chromatics n’a détecté aucun clavier QMK sur ce PC. Assurez-vous que votre clavier est branché en USB et que le Raw HID est activé dans son firmware (c’est le réglage par défaut pour toute version compatible VIA). Si VIA, Vial ou OpenRGB est en cours d’exécution, fermez-le avant d’activer ce fournisseur — ils monopolisent l’interface Raw HID. Consultez la console pour obtenir le détail des périphériques HID qui ont été énumérés."
844846
}

0 commit comments

Comments
 (0)