0x1B04 · specialKeysMSEButtons
Full control enumeration and diversion — enumerate every button and key, then divert, persistently remap, or stream raw pointer and wheel events per control.
SpecialKeysMSEButtons (also called ReprogControlsV4) enumerates every
physical and virtual control on a device — buttons, function keys, and hotkeys
— and lets host software divert or remap them. getCount reports the number of
entries in the control table; getCidInfo returns one row at a time, including
the control's default TaskId, its CidFlags capability bits, and its group
membership. getCidReporting / setCidReporting read and write the active
reporting state for a given ControlId.
When a control is diverted the device stops sending its default HID report and emits HID++ events instead. Four event kinds are defined:
DivertedButtons— up to four simultaneously pressed diverted controls.DivertedRawMouseXy— rawdx/dypointer delta while a diverted control is held.AnalyticsKeyEvents— batch of up to fiveAnalyticsKeyEvententries (CID + device-defined event code).DivertedRawWheel— raw vertical wheel delta withRawWheelResolution(Low/High) and a period count.
getCapabilities (v6 devices) exposes whether resetAllCidReportSettings is
supported, which clears all diversion and remapping in one call.
Spec: Logitech HID++ 2.0 — specialKeysMSEButtons / ReprogControlsV4. Used by: Gesture Button diversion, button remapping in
openlogi-hid.
Function reference
The ReprogControlsFeature wrapper (0x1b04) exposes:
Methods
| Function | HID++ fn | Signature | Returns |
|---|---|---|---|
get_count | 0 | () | u8 |
get_cid_info | 1 | (index: u8) | CidInfo |
get_cid_reporting | 2 | (cid: ControlId) | CidReporting |
set_cid_reporting | 3 | (cid: ControlId, change: CidReportingChange) | CidReportingChangeEcho |
get_capabilities | 4 | () | ReprogControlsCapabilities |
reset_all_cid_report_settings | 5 | () | () |
listen | event | () | Receiver<ReprogControlsEvent> |
All methods are async and return Result<…, Hidpp20Error>. listen is synchronous and returns an async_channel::Receiver<ReprogControlsEvent> directly.
Types
ControlId
A HID++ control ID (newtype wrapper around u16).
| Field | Type | Description |
|---|---|---|
0 | u16 | Raw control ID value. |
TaskId
A HID++ task ID (newtype wrapper around u16); represents the behaviour a control performs.
| Field | Type | Description |
|---|---|---|
0 | u16 | Raw task ID value. |
CidInfo
One getCidInfo row.
| Field | Type | Description |
|---|---|---|
cid | ControlId | Control ID. |
task_id | TaskId | Default task ID currently associated with the control. |
flags | CidFlags | Capability and classification flags. |
position | u8 | Physical position value reported by the device. |
group | u8 | Control group number. |
group_mask | GroupMask | Bit mask of groups this control belongs to. |
CidFlags
Capability and classification flags for one control ID (bitflags).
| Flag | Bit | Description |
|---|---|---|
MOUSE | 1 << 0 | Control belongs to a mouse/pointer device. |
FUNCTION_KEY | 1 << 1 | Control is a keyboard function key. |
HOTKEY | 1 << 2 | Control is a hotkey. |
FN_TOGGLE | 1 << 3 | Control toggles Fn behavior. |
REPROGRAMMABLE | 1 << 4 | Control can be reprogrammed. |
DIVERTABLE | 1 << 5 | Control can be temporarily diverted to HID++ events. |
PERSISTENTLY_DIVERTABLE | 1 << 6 | Control can be persistently diverted. |
VIRTUAL_CONTROL | 1 << 7 | Control is virtual rather than a physical input. |
RAW_XY | 1 << 8 | Control supports raw XY reporting. |
FORCE_RAW_XY | 1 << 9 | Control supports force raw XY reporting. |
ANALYTICS_KEY_EVENTS | 1 << 10 | Control supports analytics key events. |
RAW_WHEEL | 1 << 11 | Control supports raw wheel events. |
GroupMask
Group mask g1..g8 from getCidInfo (newtype wrapper around u8).
| Field | Type | Description |
|---|---|---|
0 | u8 | Bitmask where each bit represents a group membership slot. |
CidReporting
Current reporting/remapping state returned by getCidReporting.
| Field | Type | Description |
|---|---|---|
cid | ControlId | Control ID whose reporting state was read. |
diverted | bool | Whether temporary diversion is enabled. |
persistently_diverted | bool | Whether persistent diversion is enabled. |
force_raw_xy | bool | Whether force raw XY reporting is enabled. |
raw_xy | bool | Whether raw XY reporting is enabled. |
remap | Option<ControlId> | Optional remapping target control ID. |
analytics_key_events | bool | Whether analytics key events are enabled. |
raw_wheel | bool | Whether raw wheel reporting is enabled. |
CidReportingChange
Changes for setCidReporting. For boolean fields, None means "leave unchanged".
| Field | Type | Description |
|---|---|---|
diverted | Option<bool> | New temporary diversion state, or None to leave unchanged. |
persistently_diverted | Option<bool> | New persistent diversion state, or None to leave unchanged. |
force_raw_xy | Option<bool> | New force raw XY state, or None to leave unchanged. |
raw_xy | Option<bool> | New raw XY state, or None to leave unchanged. |
remap | Option<ControlId> | Remaps to another control ID; None sends 0 (no persistent remapping). |
analytics_key_events | Option<bool> | New analytics key event state, or None to leave unchanged. |
raw_wheel | Option<bool> | New raw wheel state, or None to leave unchanged. |
CidReportingChangeEcho
Echo returned by setCidReporting.
| Field | Type | Description |
|---|---|---|
cid | ControlId | Control ID whose reporting state was changed. |
diverted | Option<bool> | Echoed temporary diversion state when changed. |
persistently_diverted | Option<bool> | Echoed persistent diversion state when changed. |
force_raw_xy | Option<bool> | Echoed force raw XY state when changed. |
raw_xy | Option<bool> | Echoed raw XY state when changed. |
remap | Option<ControlId> | Echoed remapping target when present. |
analytics_key_events | Option<bool> | Echoed analytics key event state when changed. |
raw_wheel | Option<bool> | Echoed raw wheel state when changed. |
ReprogControlsCapabilities
Feature-level capabilities returned by getCapabilities on v6 devices.
| Field | Type | Description |
|---|---|---|
reset_all_cid_report_settings | bool | Whether resetAllCidReportSettings is supported. |
Events
ReprogControlsFeature implements EmittingFeature<ReprogControlsEvent>; call listen() to receive a channel of ReprogControlsEvent values.
ReprogControlsEvent
Event emitted by 0x1b04.
| Variant | Event fn | Description |
|---|---|---|
DivertedButtons | 0 | Up to four currently pressed diverted controls ([ControlId; 4]). |
DivertedRawMouseXy | 1 | Raw pointer movement while a diverted control is held; fields dx: i16, dy: i16. |
AnalyticsKeyEvents | 2 | Batch of five analytics key event entries ([AnalyticsKeyEvent; 5]). |
DivertedRawWheel | 4 | Raw wheel movement; fields resolution: RawWheelResolution, periods: U4, delta_vertical: i16. |
AnalyticsKeyEvent
One analytics key event entry.
| Field | Type | Description |
|---|---|---|
cid | ControlId | Control ID associated with the analytics event. |
event | u8 | Device-defined analytics event code. |
U4
An unsigned 4-bit value (nibble) encoded as a byte; used for the periods field in DivertedRawWheel.
| Method | Description |
|---|---|
from_lo(raw: u8) | Constructs a nibble from the 4 low/rightmost bits of a byte. |
from_hi(raw: u8) | Constructs a nibble from the 4 high/leftmost bits of a byte. |
to_lo() -> u8 | Returns a byte with the nibble in the 4 low/rightmost bits. |
to_hi() -> u8 | Returns a byte with the nibble in the 4 high/leftmost bits. |
RawWheelResolution
Raw wheel movement resolution.
| Variant | Value | Description |
|---|---|---|
Low | 0 | Low-resolution wheel movement. |
High | 1 | High-resolution wheel movement. |
Wire format
Getter requests carry a short 3-byte payload; getCidInfo and setCidReporting use a long 16-byte request payload and always return a long 16-byte response payload. All other responses are also read from the 16-byte long payload via extend_payload().
get_count (fn 0)
Request: [0x00, 0x00, 0x00]
Response (byte → field):
| Byte | Field | Notes |
|---|---|---|
| 0 | count | Number of rows in the control ID table. |
get_cid_info (fn 1)
Request (16-byte long payload):
| Byte | Field | Notes |
|---|---|---|
| 0 | index | Row index to retrieve; bytes 1–15 are 0x00. |
Response (16-byte long payload → CidInfo):
| Byte(s) | Field | Notes |
|---|---|---|
| 0–1 | cid | Big-endian u16 control ID. |
| 2–3 | task_id | Big-endian u16 task ID. |
| 4 | flags (primary) | Bits 0–7 of CidFlags (MOUSE through VIRTUAL_CONTROL). |
| 5 | position | Physical position value. |
| 6 | group | Control group number. |
| 7 | group_mask | Bitmask of group memberships. |
| 8 | flags (additional) | Bits 8–11 of CidFlags (RAW_XY through RAW_WHEEL); shifted left by 8 when combined. |
get_cid_reporting (fn 2)
Request: [cid_hi, cid_lo, 0x00] (big-endian ControlId)
Response (16-byte long payload → CidReporting):
| Byte(s) | Field | Notes |
|---|---|---|
| 0–1 | cid | Big-endian u16 control ID. |
| 2 bit 0 | diverted | 1 = temporary diversion enabled. |
| 2 bit 2 | persistently_diverted | 1 = persistent diversion enabled. |
| 2 bit 4 | raw_xy | 1 = raw XY reporting enabled. |
| 2 bit 6 | force_raw_xy | 1 = force raw XY enabled. |
| 3–4 | remap | Big-endian u16 remap target CID; 0x0000 = no remapping (None). |
| 5 bit 0 | analytics_key_events | 1 = analytics key events enabled. |
| 5 bit 2 | raw_wheel | 1 = raw wheel reporting enabled. |
set_cid_reporting (fn 3)
Request (16-byte long payload built by CidReportingChange::to_payload):
| Byte(s) | Field | Notes |
|---|---|---|
| 0–1 | cid | Big-endian u16 control ID. |
| 2 bit 1 | diverted-valid | 1 = the diverted value bit is being changed. |
| 2 bit 0 | diverted value | New temporary diversion state (only meaningful when bit 1 is set). |
| 2 bit 3 | persistently_diverted-valid | 1 = the persistently_diverted value bit is being changed. |
| 2 bit 2 | persistently_diverted value | New persistent diversion state (only meaningful when bit 3 is set). |
| 2 bit 5 | raw_xy-valid | 1 = the raw_xy value bit is being changed. |
| 2 bit 4 | raw_xy value | New raw XY state (only meaningful when bit 5 is set). |
| 2 bit 7 | force_raw_xy-valid | 1 = the force_raw_xy value bit is being changed. |
| 2 bit 6 | force_raw_xy value | New force raw XY state (only meaningful when bit 7 is set). |
| 3–4 | remap | Big-endian u16 remap target CID; 0x0000 when remap is None. |
| 5 bit 1 | analytics_key_events-valid | 1 = the analytics_key_events value bit is being changed. |
| 5 bit 0 | analytics_key_events value | New analytics key event state (only meaningful when bit 1 is set). |
| 5 bit 3 | raw_wheel-valid | 1 = the raw_wheel value bit is being changed. |
| 5 bit 2 | raw_wheel value | New raw wheel state (only meaningful when bit 3 is set). |
Response echoes the same layout as the request; each value field is only valid when its corresponding valid bit is set (see CidReportingChangeEcho).
get_capabilities (fn 4)
Request: [0x00, 0x00, 0x00]
Response (byte → field):
| Byte | Field | Notes |
|---|---|---|
| 0 bit 0 | reset_all_cid_report_settings | 1 = resetAllCidReportSettings is supported. |
reset_all_cid_report_settings (fn 5)
Request: [0x00, 0x00, 0x00]
Response carries no defined fields; success is indicated by the absence of a Hidpp20Error.
Events
Events arrive as unsolicited long messages (function_id in the sub-ID nibble, software_id nibble = 0).
DivertedButtons (event fn 0)
| Byte(s) | Field | Notes |
|---|---|---|
| 0–1 | slot 0 CID | Big-endian u16; 0x0000 = slot not in use. |
| 2–3 | slot 1 CID | Big-endian u16. |
| 4–5 | slot 2 CID | Big-endian u16. |
| 6–7 | slot 3 CID | Big-endian u16. |
DivertedRawMouseXy (event fn 1)
| Byte(s) | Field | Notes |
|---|---|---|
| 0–1 | dx | Big-endian i16 horizontal delta. |
| 2–3 | dy | Big-endian i16 vertical delta. |
AnalyticsKeyEvents (event fn 2)
Five packed 3-byte entries (bytes 0–14); each entry:
| Offset within entry | Field | Notes |
|---|---|---|
| 0–1 | cid | Big-endian u16 control ID. |
| 2 | event | Device-defined analytics event code. |
DivertedRawWheel (event fn 4)
| Byte(s) | Field | Notes |
|---|---|---|
| 0 bits 7–5 | (reserved) | Unused upper bits. |
| 0 bit 4 | resolution | 0 = Low, 1 = High (RawWheelResolution). |
| 0 bits 3–0 | periods | 4-bit period count (U4, decoded via U4::from_lo). |
| 1–2 | delta_vertical | Big-endian i16 vertical wheel delta. |
Usage (Rust)
use hidpp::{device::Device, feature::reprog_controls::{ReprogControlsFeature, CidReportingChange}};
// device: &mut Device, already created via Device::new(channel, index)
device.enumerate_features().await?;
if let Some(feat) = device.get_feature::<ReprogControlsFeature>() {
// How many controls does this device expose?
let count = feat.get_count().await?;
for i in 0..count {
let info = feat.get_cid_info(i).await?;
println!("CID {:04x} divertable={}", info.cid.0, info.flags.is_divertable());
}
// Temporarily divert the first divertable control and stream its events.
let info = feat.get_cid_info(0).await?;
if info.flags.is_divertable() {
let change = CidReportingChange::temporary_diversion(true, false);
feat.set_cid_reporting(info.cid, change).await?;
let rx = feat.listen();
if let Ok(event) = rx.recv().await {
println!("event: {:?}", event);
}
// Un-divert before exit.
feat.set_cid_reporting(info.cid, CidReportingChange::temporary_diversion(false, false)).await?;
}
}