Skip to content

Commit 3402e6e

Browse files
Switch QMK keymap fetcher to snakkarike/qmk_firmware + chromatics-docs index (v4.1.41)
The original fetcher pointed at www.caniusevia.com URLs that don't exist and assumed a JSON schema (keycap labels embedded as "row,col\n\n\nA" strings) that via-keyboards doesn't actually use. Rewriting against QMK's keyboard.json instead: - Source: snakkarike/qmk_firmware master branch (covers all the NovelKeys boards plus 2500+ other QMK keyboards). NovelKeys boards land under keyboards/novelkeys/ with proper VID/PID and rgb_matrix layouts. - Index: 2650 unique VID/PID entries built once by scripts/build_qmk_keymap_index.py and hosted at raw.githubusercontent.com/logicallysynced/chromatics-docs/main/qmk_keymap_index.json. - Schema: QMK keyboard.json's layouts.<first>.layout array. Each entry has matrix=[row,col] and (often, not always) a label="Esc"/"F1"/etc. Label coverage is inconsistent across boards — NK87 has it, NK65 doesn't — so the merge step gracefully falls back to LedId.Custom_* for LEDs whose matrix position has no label in the JSON. Partial semantic mapping is still better than the alternative of no mapping at all. - Cache: moved to FileOperationsHelper.GetConfigDirectory()/QmkKeymaps so it lives alongside the rest of the user's Chromatics state under %AppData%/Chromatics. SettingsViewModel.ResetChromatics now wipes this cache and the in-memory index when the user hits Reset. QmkKeycodeMap expanded to accept both QMK keycode shortforms ("ESC", "BSPC"), the long KC_ prefix form ("KC_ESC"), and the human legend form QMK keyboard.json's label field actually uses ("Esc", "Backspace", "Page Up"). All three resolve to the same LedId.Keyboard_*. Caveats: - Label coverage is partial — boards without labels in their keyboard.json land in Custom_* and the user maps via Mapping tab. - The OpenRGB-QMK command IDs (0x20-0x2A) in OpenRgbQmkProtocol.cs still need verification against the upstream OpenRGB master firmware fork. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent c0a1a74 commit 3402e6e

5 files changed

Lines changed: 327 additions & 193 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
All notable changes to Chromatics are documented here.
44

5-
## 4.1.40
5+
## 4.1.41
66

7-
- **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 (the VIA fallback path). For per-key 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.
7+
- **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
99

1010
## 4.1.38

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.40.0</Version>
7+
<Version>4.1.41.0</Version>
88
<Authors>Danielle Thompson</Authors>
99
<ApplicationManifest>app.manifest</ApplicationManifest>
1010
<Copyright>logicallysynced 2026</Copyright>

Chromatics/Extensions/RGB.NET/Devices/QmkRawHid/QmkKeycodeMap.cs

Lines changed: 164 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,33 @@
44

55
namespace Chromatics.Extensions.RGB.NET.Devices.QmkRawHid
66
{
7-
// QMK keycode string → RGB.NET LedId. Covers the canonical ANSI 104
8-
// and the common alternates (numpad, media, ISO Enter / split-keys);
9-
// unknown keycodes return LedId.Invalid so the layout merger falls
10-
// back to LedId.Custom1+i for that LED. QMK keycodes follow the
11-
// KC_<name> convention; the via-keyboards JSON sometimes strips
12-
// the prefix, so the lookup matches both forms.
7+
// QMK label / keycode string → RGB.NET LedId. QMK boards label their keys
8+
// inconsistently across the keyboards/ tree — some entries use the QMK
9+
// keycode short form ("ESC", "BSPC"), some the full prefix ("KC_ESC"),
10+
// and many use human-readable legends ("Esc", "Backspace", "Page Up").
11+
// This map covers all three styles for the canonical ANSI 104 plus
12+
// numpad and ISO-only keys; lookup is case-insensitive and the "KC_"
13+
// prefix is stripped if present so all conventions resolve.
14+
//
15+
// Unknown labels return LedId.Invalid so the layout merger falls back
16+
// to LedId.Custom1+i for that LED.
1317
internal static class QmkKeycodeMap
1418
{
15-
public static LedId ToLedId(string keycode)
19+
public static LedId ToLedId(string label)
1620
{
17-
if (string.IsNullOrEmpty(keycode)) return LedId.Invalid;
18-
string key = keycode.Trim();
21+
if (string.IsNullOrEmpty(label)) return LedId.Invalid;
22+
string key = label.Trim();
1923
if (key.StartsWith("KC_")) key = key.Substring(3);
2024
return _map.TryGetValue(key, out var id) ? id : LedId.Invalid;
2125
}
2226

2327
// Stored as a FrozenDictionary because lookups happen during layout
2428
// construction (once per device + LED count) and the table never
25-
// changes at runtime.
29+
// changes at runtime. Case-insensitive — covers "Esc"/"ESC"/"esc".
2630
private static readonly FrozenDictionary<string, LedId> _map =
2731
new Dictionary<string, LedId>(System.StringComparer.OrdinalIgnoreCase)
2832
{
29-
// Letters
33+
// ── Letters ──────────────────────────────────────────
3034
["A"] = LedId.Keyboard_A, ["B"] = LedId.Keyboard_B, ["C"] = LedId.Keyboard_C,
3135
["D"] = LedId.Keyboard_D, ["E"] = LedId.Keyboard_E, ["F"] = LedId.Keyboard_F,
3236
["G"] = LedId.Keyboard_G, ["H"] = LedId.Keyboard_H, ["I"] = LedId.Keyboard_I,
@@ -37,67 +41,154 @@ public static LedId ToLedId(string keycode)
3741
["V"] = LedId.Keyboard_V, ["W"] = LedId.Keyboard_W, ["X"] = LedId.Keyboard_X,
3842
["Y"] = LedId.Keyboard_Y, ["Z"] = LedId.Keyboard_Z,
3943

40-
// Top row digits
44+
// ── Top-row digits ───────────────────────────────────
4145
["1"] = LedId.Keyboard_1, ["2"] = LedId.Keyboard_2, ["3"] = LedId.Keyboard_3,
4246
["4"] = LedId.Keyboard_4, ["5"] = LedId.Keyboard_5, ["6"] = LedId.Keyboard_6,
4347
["7"] = LedId.Keyboard_7, ["8"] = LedId.Keyboard_8, ["9"] = LedId.Keyboard_9,
4448
["0"] = LedId.Keyboard_0,
4549

46-
// Function row
50+
// ── Function row ─────────────────────────────────────
4751
["F1"] = LedId.Keyboard_F1, ["F2"] = LedId.Keyboard_F2, ["F3"] = LedId.Keyboard_F3,
4852
["F4"] = LedId.Keyboard_F4, ["F5"] = LedId.Keyboard_F5, ["F6"] = LedId.Keyboard_F6,
4953
["F7"] = LedId.Keyboard_F7, ["F8"] = LedId.Keyboard_F8, ["F9"] = LedId.Keyboard_F9,
5054
["F10"] = LedId.Keyboard_F10, ["F11"] = LedId.Keyboard_F11, ["F12"] = LedId.Keyboard_F12,
55+
// F13+ exists on the QMK side (full-size + macropad layouts) but
56+
// RGB.NET's LedId enum tops out at F12; entries above that drop
57+
// to LedId.Custom_* via the merge step's fallback.
5158

52-
// Symbols / punctuation (US ANSI)
53-
["MINS"] = LedId.Keyboard_MinusAndUnderscore,
54-
["EQL"] = LedId.Keyboard_EqualsAndPlus,
55-
["LBRC"] = LedId.Keyboard_BracketLeft,
56-
["RBRC"] = LedId.Keyboard_BracketRight,
57-
["BSLS"] = LedId.Keyboard_Backslash,
58-
["SCLN"] = LedId.Keyboard_SemicolonAndColon,
59-
["QUOT"] = LedId.Keyboard_ApostropheAndDoubleQuote,
60-
["COMM"] = LedId.Keyboard_CommaAndLessThan,
61-
["DOT"] = LedId.Keyboard_PeriodAndBiggerThan,
62-
["SLSH"] = LedId.Keyboard_SlashAndQuestionMark,
63-
["GRV"] = LedId.Keyboard_GraveAccentAndTilde,
59+
// ── Punctuation: QMK keycode forms ───────────────────
60+
["MINS"] = LedId.Keyboard_MinusAndUnderscore,
61+
["EQL"] = LedId.Keyboard_EqualsAndPlus,
62+
["LBRC"] = LedId.Keyboard_BracketLeft,
63+
["RBRC"] = LedId.Keyboard_BracketRight,
64+
["BSLS"] = LedId.Keyboard_Backslash,
65+
["SCLN"] = LedId.Keyboard_SemicolonAndColon,
66+
["QUOT"] = LedId.Keyboard_ApostropheAndDoubleQuote,
67+
["COMM"] = LedId.Keyboard_CommaAndLessThan,
68+
["DOT"] = LedId.Keyboard_PeriodAndBiggerThan,
69+
["SLSH"] = LedId.Keyboard_SlashAndQuestionMark,
70+
["GRV"] = LedId.Keyboard_GraveAccentAndTilde,
6471

65-
// Modifiers + edit keys
66-
["ESC"] = LedId.Keyboard_Escape,
67-
["TAB"] = LedId.Keyboard_Tab,
68-
["CAPS"] = LedId.Keyboard_CapsLock,
69-
["LSFT"] = LedId.Keyboard_LeftShift,
70-
["RSFT"] = LedId.Keyboard_RightShift,
71-
["LCTL"] = LedId.Keyboard_LeftCtrl,
72-
["RCTL"] = LedId.Keyboard_RightCtrl,
73-
["LALT"] = LedId.Keyboard_LeftAlt,
74-
["RALT"] = LedId.Keyboard_RightAlt,
75-
["LGUI"] = LedId.Keyboard_LeftGui,
76-
["RGUI"] = LedId.Keyboard_RightGui,
77-
["ENT"] = LedId.Keyboard_Enter,
78-
["BSPC"] = LedId.Keyboard_Backspace,
79-
["SPC"] = LedId.Keyboard_Space,
80-
["APP"] = LedId.Keyboard_Application,
72+
// ── Punctuation: human-legend forms ──────────────────
73+
["-"] = LedId.Keyboard_MinusAndUnderscore,
74+
["="] = LedId.Keyboard_EqualsAndPlus,
75+
["["] = LedId.Keyboard_BracketLeft,
76+
["]"] = LedId.Keyboard_BracketRight,
77+
["\\"] = LedId.Keyboard_Backslash,
78+
[";"] = LedId.Keyboard_SemicolonAndColon,
79+
["'"] = LedId.Keyboard_ApostropheAndDoubleQuote,
80+
[","] = LedId.Keyboard_CommaAndLessThan,
81+
["."] = LedId.Keyboard_PeriodAndBiggerThan,
82+
["/"] = LedId.Keyboard_SlashAndQuestionMark,
83+
["`"] = LedId.Keyboard_GraveAccentAndTilde,
8184

82-
// Navigation cluster
83-
["INS"] = LedId.Keyboard_Insert,
84-
["DEL"] = LedId.Keyboard_Delete,
85-
["HOME"] = LedId.Keyboard_Home,
86-
["END"] = LedId.Keyboard_End,
87-
["PGUP"] = LedId.Keyboard_PageUp,
88-
["PGDN"] = LedId.Keyboard_PageDown,
89-
["UP"] = LedId.Keyboard_ArrowUp,
90-
["DOWN"] = LedId.Keyboard_ArrowDown,
91-
["LEFT"] = LedId.Keyboard_ArrowLeft,
92-
["RGHT"] = LedId.Keyboard_ArrowRight,
85+
// ── Modifiers + edit: short + long forms ─────────────
86+
["ESC"] = LedId.Keyboard_Escape,
87+
["Escape"] = LedId.Keyboard_Escape,
88+
["TAB"] = LedId.Keyboard_Tab,
89+
["Tab"] = LedId.Keyboard_Tab,
90+
["CAPS"] = LedId.Keyboard_CapsLock,
91+
["Caps"] = LedId.Keyboard_CapsLock,
92+
["Caps Lock"] = LedId.Keyboard_CapsLock,
93+
["CapsLock"] = LedId.Keyboard_CapsLock,
94+
["LSFT"] = LedId.Keyboard_LeftShift,
95+
["LShift"] = LedId.Keyboard_LeftShift,
96+
["Left Shift"] = LedId.Keyboard_LeftShift,
97+
["Shift"] = LedId.Keyboard_LeftShift, // ambiguous label; first occurrence wins, second falls back to Custom_*
98+
["RSFT"] = LedId.Keyboard_RightShift,
99+
["RShift"] = LedId.Keyboard_RightShift,
100+
["Right Shift"] = LedId.Keyboard_RightShift,
101+
["LCTL"] = LedId.Keyboard_LeftCtrl,
102+
["LCtrl"] = LedId.Keyboard_LeftCtrl,
103+
["Left Ctrl"] = LedId.Keyboard_LeftCtrl,
104+
["Ctrl"] = LedId.Keyboard_LeftCtrl,
105+
["Control"] = LedId.Keyboard_LeftCtrl,
106+
["RCTL"] = LedId.Keyboard_RightCtrl,
107+
["RCtrl"] = LedId.Keyboard_RightCtrl,
108+
["Right Ctrl"] = LedId.Keyboard_RightCtrl,
109+
["LALT"] = LedId.Keyboard_LeftAlt,
110+
["LAlt"] = LedId.Keyboard_LeftAlt,
111+
["Left Alt"] = LedId.Keyboard_LeftAlt,
112+
["Alt"] = LedId.Keyboard_LeftAlt,
113+
["RALT"] = LedId.Keyboard_RightAlt,
114+
["RAlt"] = LedId.Keyboard_RightAlt,
115+
["Right Alt"] = LedId.Keyboard_RightAlt,
116+
["AltGr"] = LedId.Keyboard_RightAlt,
117+
["LGUI"] = LedId.Keyboard_LeftGui,
118+
["LGui"] = LedId.Keyboard_LeftGui,
119+
["Left GUI"] = LedId.Keyboard_LeftGui,
120+
["Left Win"] = LedId.Keyboard_LeftGui,
121+
["Win"] = LedId.Keyboard_LeftGui,
122+
["Windows"] = LedId.Keyboard_LeftGui,
123+
["Cmd"] = LedId.Keyboard_LeftGui,
124+
["RGUI"] = LedId.Keyboard_RightGui,
125+
["RGui"] = LedId.Keyboard_RightGui,
126+
["Right GUI"] = LedId.Keyboard_RightGui,
127+
["Right Win"] = LedId.Keyboard_RightGui,
128+
["ENT"] = LedId.Keyboard_Enter,
129+
["ENTER"] = LedId.Keyboard_Enter,
130+
["Enter"] = LedId.Keyboard_Enter,
131+
["Return"] = LedId.Keyboard_Enter,
132+
["BSPC"] = LedId.Keyboard_Backspace,
133+
["Backspace"] = LedId.Keyboard_Backspace,
134+
["BkSp"] = LedId.Keyboard_Backspace,
135+
["SPC"] = LedId.Keyboard_Space,
136+
["Space"] = LedId.Keyboard_Space,
137+
["APP"] = LedId.Keyboard_Application,
138+
["Menu"] = LedId.Keyboard_Application,
139+
["App"] = LedId.Keyboard_Application,
93140

94-
// System / lock keys
95-
["PSCR"] = LedId.Keyboard_PrintScreen,
96-
["SCRL"] = LedId.Keyboard_ScrollLock,
97-
["PAUS"] = LedId.Keyboard_PauseBreak,
98-
["NLCK"] = LedId.Keyboard_NumLock,
141+
// ── Navigation cluster ───────────────────────────────
142+
["INS"] = LedId.Keyboard_Insert,
143+
["Ins"] = LedId.Keyboard_Insert,
144+
["Insert"] = LedId.Keyboard_Insert,
145+
["DEL"] = LedId.Keyboard_Delete,
146+
["Del"] = LedId.Keyboard_Delete,
147+
["Delete"] = LedId.Keyboard_Delete,
148+
["HOME"] = LedId.Keyboard_Home,
149+
["Home"] = LedId.Keyboard_Home,
150+
["END"] = LedId.Keyboard_End,
151+
["End"] = LedId.Keyboard_End,
152+
["PGUP"] = LedId.Keyboard_PageUp,
153+
["PgUp"] = LedId.Keyboard_PageUp,
154+
["Page Up"] = LedId.Keyboard_PageUp,
155+
["PageUp"] = LedId.Keyboard_PageUp,
156+
["PGDN"] = LedId.Keyboard_PageDown,
157+
["PgDn"] = LedId.Keyboard_PageDown,
158+
["Page Down"] = LedId.Keyboard_PageDown,
159+
["PageDown"] = LedId.Keyboard_PageDown,
160+
["UP"] = LedId.Keyboard_ArrowUp,
161+
["Up"] = LedId.Keyboard_ArrowUp,
162+
["↑"] = LedId.Keyboard_ArrowUp,
163+
["DOWN"] = LedId.Keyboard_ArrowDown,
164+
["Down"] = LedId.Keyboard_ArrowDown,
165+
["↓"] = LedId.Keyboard_ArrowDown,
166+
["LEFT"] = LedId.Keyboard_ArrowLeft,
167+
["Left"] = LedId.Keyboard_ArrowLeft,
168+
["←"] = LedId.Keyboard_ArrowLeft,
169+
["RGHT"] = LedId.Keyboard_ArrowRight,
170+
["Right"] = LedId.Keyboard_ArrowRight,
171+
["→"] = LedId.Keyboard_ArrowRight,
99172

100-
// Numpad
173+
// ── System / locks ───────────────────────────────────
174+
["PSCR"] = LedId.Keyboard_PrintScreen,
175+
["PrtSc"] = LedId.Keyboard_PrintScreen,
176+
["PrintScreen"] = LedId.Keyboard_PrintScreen,
177+
["Print Screen"] = LedId.Keyboard_PrintScreen,
178+
["SCRL"] = LedId.Keyboard_ScrollLock,
179+
["ScrLk"] = LedId.Keyboard_ScrollLock,
180+
["Scroll Lock"] = LedId.Keyboard_ScrollLock,
181+
["ScrollLock"] = LedId.Keyboard_ScrollLock,
182+
["PAUS"] = LedId.Keyboard_PauseBreak,
183+
["Pause"] = LedId.Keyboard_PauseBreak,
184+
["Break"] = LedId.Keyboard_PauseBreak,
185+
["Pause/Break"] = LedId.Keyboard_PauseBreak,
186+
["NLCK"] = LedId.Keyboard_NumLock,
187+
["NumLk"] = LedId.Keyboard_NumLock,
188+
["Num Lock"] = LedId.Keyboard_NumLock,
189+
["NumLock"] = LedId.Keyboard_NumLock,
190+
191+
// ── Numpad: QMK keycode forms (P0..P9, PDOT etc.) ────
101192
["P0"] = LedId.Keyboard_Num0, ["P1"] = LedId.Keyboard_Num1,
102193
["P2"] = LedId.Keyboard_Num2, ["P3"] = LedId.Keyboard_Num3,
103194
["P4"] = LedId.Keyboard_Num4, ["P5"] = LedId.Keyboard_Num5,
@@ -110,10 +201,23 @@ public static LedId ToLedId(string keycode)
110201
["PPLS"] = LedId.Keyboard_NumPlus,
111202
["PENT"] = LedId.Keyboard_NumEnter,
112203

113-
// Some firmwares emit ISO-only keys; map to closest ANSI siblings.
204+
// ── Numpad: human-legend forms (KP_0..KP_9, KP_Plus, etc.) ──
205+
["KP_0"] = LedId.Keyboard_Num0, ["KP_1"] = LedId.Keyboard_Num1,
206+
["KP_2"] = LedId.Keyboard_Num2, ["KP_3"] = LedId.Keyboard_Num3,
207+
["KP_4"] = LedId.Keyboard_Num4, ["KP_5"] = LedId.Keyboard_Num5,
208+
["KP_6"] = LedId.Keyboard_Num6, ["KP_7"] = LedId.Keyboard_Num7,
209+
["KP_8"] = LedId.Keyboard_Num8, ["KP_9"] = LedId.Keyboard_Num9,
210+
["KP_."] = LedId.Keyboard_NumPeriodAndDelete,
211+
["KP_/"] = LedId.Keyboard_NumSlash,
212+
["KP_*"] = LedId.Keyboard_NumAsterisk,
213+
["KP_-"] = LedId.Keyboard_NumMinus,
214+
["KP_+"] = LedId.Keyboard_NumPlus,
215+
["KP_Enter"] = LedId.Keyboard_NumEnter,
216+
217+
// ── ISO-only keys: map to closest ANSI siblings ──────
114218
// NUHS = ISO non-US hash (between Enter and ' on ISO layouts).
115219
["NUHS"] = LedId.Keyboard_Backslash,
116-
// NUBS = ISO non-US backslash (next to Left Shift on ISO layouts).
220+
// NUBS = ISO non-US backslash (next to Left Shift on ISO).
117221
["NUBS"] = LedId.Keyboard_NonUsBackslash,
118222
}.ToFrozenDictionary(System.StringComparer.OrdinalIgnoreCase);
119223
}

0 commit comments

Comments
 (0)