You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
CAP_LIGHTS is the only lighting capability, and it is strictly boolean — lib/capability_descriptors.hpp declares it min_value = 0, max_value = 1, -l <0|1>. There is no capability anywhere in CAPABILITIES_XLIST that can express a colour, so no device in the project can set one, however capable its hardware.
That's a real limitation for headsets whose selling point is RGB. Users install HeadsetControl to get off vendor software and find that the LEDs can only be switched on — and "on" has to mean whatever static colour the device implementation picked.
Why I'm raising it now
While adding support for the Corsair Virtuoso XT (#570) I reverse-engineered its lighting. The hardware side works: it speaks Corsair's Bragi protocol, and driving the lighting handle with a 9-byte planar RGB frame cycles the earcup zones through red, green and blue exactly as asked. I confirmed it visually on real hardware.
I deliberately did not ship that in #570, because there is nowhere in the API to put a colour. setLights(handle, bool) is all the interface offers, so my implementation paints static white for "on" and black for "off" — the hardware can do far more than the interface can ask for.
I doubt Corsair is alone here. Several already-supported families (Logitech G633/G933, SteelSeries Arctis, other Corsair devices) have addressable lighting that the current interface can't reach either.
The design questions
I'd rather agree the shape before writing anything, since this touches the shared plumbing rather than one device.
1. Extend CAP_LIGHTS, or add a separate capability?
Extending keeps one flag and one concept ("lighting"), and -l could accept either 0/1 or a colour. A separate CAP_LIGHTS_COLOR keeps the boolean semantics untouched and lets devices advertise the two independently — plenty of devices can toggle lighting but not colour, and the capability bitmask is how the README table and --capabilities are generated. I lean toward a separate capability for that reason, but it does add a second lighting flag.
2. Parameter representation.
There's already a precedent for non-scalar parameters: FeatureParam is std::variant<std::monostate, int, EqualizerSettings, ParametricEqualizerSettings>, and CAP_EQUALIZER sets min_value/max_value to nullopt with a <curve> value hint. A colour would follow the same pattern — a small LightingColor struct in the variant, with #RRGGBB / RRGGBB on the CLI.
3. Zones.
Most headsets have more than one LED zone (the Virtuoso has three). Is a single colour applied to all zones enough for v1, with per-zone left as a later extension? I'd argue yes — it covers the common request and avoids designing a zone-addressing scheme before there are multiple implementations to generalise from.
4. Effects.
Out of scope in my view. LightsResult already carries an optional mode string, but effects are where vendor protocols diverge hardest, and a static colour is the thing people actually ask for.
Surfaces this would touch
CAPABILITIES_XLIST and the capability enum, CAPABILITY_DESCRIPTORS, FeatureHandlerRegistry, FeatureParam, HIDDevice's virtual interface, both public APIs (headsetcontrol.hpp and headsetcontrol_c.h), the JSON/YAML/ENV serialisers, and the README table.
Offer
Happy to implement whichever shape you prefer, with the Corsair Virtuoso XT as the first implementation since I have the hardware and the protocol already worked out — it would give the feature a tested device from day one rather than landing untested. If you'd rather not take this on at all, that's a completely fine answer too, and I'll note the limitation in the device docs instead.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
The gap
CAP_LIGHTSis the only lighting capability, and it is strictly boolean —lib/capability_descriptors.hppdeclares itmin_value = 0, max_value = 1,-l <0|1>. There is no capability anywhere inCAPABILITIES_XLISTthat can express a colour, so no device in the project can set one, however capable its hardware.That's a real limitation for headsets whose selling point is RGB. Users install HeadsetControl to get off vendor software and find that the LEDs can only be switched on — and "on" has to mean whatever static colour the device implementation picked.
Why I'm raising it now
While adding support for the Corsair Virtuoso XT (#570) I reverse-engineered its lighting. The hardware side works: it speaks Corsair's Bragi protocol, and driving the lighting handle with a 9-byte planar RGB frame cycles the earcup zones through red, green and blue exactly as asked. I confirmed it visually on real hardware.
I deliberately did not ship that in #570, because there is nowhere in the API to put a colour.
setLights(handle, bool)is all the interface offers, so my implementation paints static white for "on" and black for "off" — the hardware can do far more than the interface can ask for.I doubt Corsair is alone here. Several already-supported families (Logitech G633/G933, SteelSeries Arctis, other Corsair devices) have addressable lighting that the current interface can't reach either.
The design questions
I'd rather agree the shape before writing anything, since this touches the shared plumbing rather than one device.
1. Extend
CAP_LIGHTS, or add a separate capability?Extending keeps one flag and one concept ("lighting"), and
-lcould accept either0/1or a colour. A separateCAP_LIGHTS_COLORkeeps the boolean semantics untouched and lets devices advertise the two independently — plenty of devices can toggle lighting but not colour, and the capability bitmask is how the README table and--capabilitiesare generated. I lean toward a separate capability for that reason, but it does add a second lighting flag.2. Parameter representation.
There's already a precedent for non-scalar parameters:
FeatureParamisstd::variant<std::monostate, int, EqualizerSettings, ParametricEqualizerSettings>, andCAP_EQUALIZERsetsmin_value/max_valuetonulloptwith a<curve>value hint. A colour would follow the same pattern — a smallLightingColorstruct in the variant, with#RRGGBB/RRGGBBon the CLI.3. Zones.
Most headsets have more than one LED zone (the Virtuoso has three). Is a single colour applied to all zones enough for v1, with per-zone left as a later extension? I'd argue yes — it covers the common request and avoids designing a zone-addressing scheme before there are multiple implementations to generalise from.
4. Effects.
Out of scope in my view.
LightsResultalready carries an optionalmodestring, but effects are where vendor protocols diverge hardest, and a static colour is the thing people actually ask for.Surfaces this would touch
CAPABILITIES_XLISTand the capability enum,CAPABILITY_DESCRIPTORS,FeatureHandlerRegistry,FeatureParam,HIDDevice's virtual interface, both public APIs (headsetcontrol.hppandheadsetcontrol_c.h), the JSON/YAML/ENV serialisers, and the README table.Offer
Happy to implement whichever shape you prefer, with the Corsair Virtuoso XT as the first implementation since I have the hardware and the protocol already worked out — it would give the feature a tested device from day one rather than landing untested. If you'd rather not take this on at all, that's a completely fine answer too, and I'll note the limitation in the device docs instead.
All reactions