OpenLogi

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 — raw dx/dy pointer delta while a diverted control is held.
  • AnalyticsKeyEvents — batch of up to five AnalyticsKeyEvent entries (CID + device-defined event code).
  • DivertedRawWheel — raw vertical wheel delta with RawWheelResolution (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

FunctionHID++ fnSignatureReturns
get_count0()u8
get_cid_info1(index: u8)CidInfo
get_cid_reporting2(cid: ControlId)CidReporting
set_cid_reporting3(cid: ControlId, change: CidReportingChange)CidReportingChangeEcho
get_capabilities4()ReprogControlsCapabilities
reset_all_cid_report_settings5()()
listenevent()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).

FieldTypeDescription
0u16Raw control ID value.

TaskId

A HID++ task ID (newtype wrapper around u16); represents the behaviour a control performs.

FieldTypeDescription
0u16Raw task ID value.

CidInfo

One getCidInfo row.

FieldTypeDescription
cidControlIdControl ID.
task_idTaskIdDefault task ID currently associated with the control.
flagsCidFlagsCapability and classification flags.
positionu8Physical position value reported by the device.
groupu8Control group number.
group_maskGroupMaskBit mask of groups this control belongs to.

CidFlags

Capability and classification flags for one control ID (bitflags).

FlagBitDescription
MOUSE1 << 0Control belongs to a mouse/pointer device.
FUNCTION_KEY1 << 1Control is a keyboard function key.
HOTKEY1 << 2Control is a hotkey.
FN_TOGGLE1 << 3Control toggles Fn behavior.
REPROGRAMMABLE1 << 4Control can be reprogrammed.
DIVERTABLE1 << 5Control can be temporarily diverted to HID++ events.
PERSISTENTLY_DIVERTABLE1 << 6Control can be persistently diverted.
VIRTUAL_CONTROL1 << 7Control is virtual rather than a physical input.
RAW_XY1 << 8Control supports raw XY reporting.
FORCE_RAW_XY1 << 9Control supports force raw XY reporting.
ANALYTICS_KEY_EVENTS1 << 10Control supports analytics key events.
RAW_WHEEL1 << 11Control supports raw wheel events.

GroupMask

Group mask g1..g8 from getCidInfo (newtype wrapper around u8).

FieldTypeDescription
0u8Bitmask where each bit represents a group membership slot.

CidReporting

Current reporting/remapping state returned by getCidReporting.

FieldTypeDescription
cidControlIdControl ID whose reporting state was read.
divertedboolWhether temporary diversion is enabled.
persistently_divertedboolWhether persistent diversion is enabled.
force_raw_xyboolWhether force raw XY reporting is enabled.
raw_xyboolWhether raw XY reporting is enabled.
remapOption<ControlId>Optional remapping target control ID.
analytics_key_eventsboolWhether analytics key events are enabled.
raw_wheelboolWhether raw wheel reporting is enabled.

CidReportingChange

Changes for setCidReporting. For boolean fields, None means "leave unchanged".

FieldTypeDescription
divertedOption<bool>New temporary diversion state, or None to leave unchanged.
persistently_divertedOption<bool>New persistent diversion state, or None to leave unchanged.
force_raw_xyOption<bool>New force raw XY state, or None to leave unchanged.
raw_xyOption<bool>New raw XY state, or None to leave unchanged.
remapOption<ControlId>Remaps to another control ID; None sends 0 (no persistent remapping).
analytics_key_eventsOption<bool>New analytics key event state, or None to leave unchanged.
raw_wheelOption<bool>New raw wheel state, or None to leave unchanged.

CidReportingChangeEcho

Echo returned by setCidReporting.

FieldTypeDescription
cidControlIdControl ID whose reporting state was changed.
divertedOption<bool>Echoed temporary diversion state when changed.
persistently_divertedOption<bool>Echoed persistent diversion state when changed.
force_raw_xyOption<bool>Echoed force raw XY state when changed.
raw_xyOption<bool>Echoed raw XY state when changed.
remapOption<ControlId>Echoed remapping target when present.
analytics_key_eventsOption<bool>Echoed analytics key event state when changed.
raw_wheelOption<bool>Echoed raw wheel state when changed.

ReprogControlsCapabilities

Feature-level capabilities returned by getCapabilities on v6 devices.

FieldTypeDescription
reset_all_cid_report_settingsboolWhether resetAllCidReportSettings is supported.

Events

ReprogControlsFeature implements EmittingFeature<ReprogControlsEvent>; call listen() to receive a channel of ReprogControlsEvent values.

ReprogControlsEvent

Event emitted by 0x1b04.

VariantEvent fnDescription
DivertedButtons0Up to four currently pressed diverted controls ([ControlId; 4]).
DivertedRawMouseXy1Raw pointer movement while a diverted control is held; fields dx: i16, dy: i16.
AnalyticsKeyEvents2Batch of five analytics key event entries ([AnalyticsKeyEvent; 5]).
DivertedRawWheel4Raw wheel movement; fields resolution: RawWheelResolution, periods: U4, delta_vertical: i16.

AnalyticsKeyEvent

One analytics key event entry.

FieldTypeDescription
cidControlIdControl ID associated with the analytics event.
eventu8Device-defined analytics event code.

U4

An unsigned 4-bit value (nibble) encoded as a byte; used for the periods field in DivertedRawWheel.

MethodDescription
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() -> u8Returns a byte with the nibble in the 4 low/rightmost bits.
to_hi() -> u8Returns a byte with the nibble in the 4 high/leftmost bits.

RawWheelResolution

Raw wheel movement resolution.

VariantValueDescription
Low0Low-resolution wheel movement.
High1High-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):

ByteFieldNotes
0countNumber of rows in the control ID table.

get_cid_info (fn 1)

Request (16-byte long payload):

ByteFieldNotes
0indexRow index to retrieve; bytes 1–15 are 0x00.

Response (16-byte long payload → CidInfo):

Byte(s)FieldNotes
0–1cidBig-endian u16 control ID.
2–3task_idBig-endian u16 task ID.
4flags (primary)Bits 0–7 of CidFlags (MOUSE through VIRTUAL_CONTROL).
5positionPhysical position value.
6groupControl group number.
7group_maskBitmask of group memberships.
8flags (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)FieldNotes
0–1cidBig-endian u16 control ID.
2 bit 0diverted1 = temporary diversion enabled.
2 bit 2persistently_diverted1 = persistent diversion enabled.
2 bit 4raw_xy1 = raw XY reporting enabled.
2 bit 6force_raw_xy1 = force raw XY enabled.
3–4remapBig-endian u16 remap target CID; 0x0000 = no remapping (None).
5 bit 0analytics_key_events1 = analytics key events enabled.
5 bit 2raw_wheel1 = raw wheel reporting enabled.

set_cid_reporting (fn 3)

Request (16-byte long payload built by CidReportingChange::to_payload):

Byte(s)FieldNotes
0–1cidBig-endian u16 control ID.
2 bit 1diverted-valid1 = the diverted value bit is being changed.
2 bit 0diverted valueNew temporary diversion state (only meaningful when bit 1 is set).
2 bit 3persistently_diverted-valid1 = the persistently_diverted value bit is being changed.
2 bit 2persistently_diverted valueNew persistent diversion state (only meaningful when bit 3 is set).
2 bit 5raw_xy-valid1 = the raw_xy value bit is being changed.
2 bit 4raw_xy valueNew raw XY state (only meaningful when bit 5 is set).
2 bit 7force_raw_xy-valid1 = the force_raw_xy value bit is being changed.
2 bit 6force_raw_xy valueNew force raw XY state (only meaningful when bit 7 is set).
3–4remapBig-endian u16 remap target CID; 0x0000 when remap is None.
5 bit 1analytics_key_events-valid1 = the analytics_key_events value bit is being changed.
5 bit 0analytics_key_events valueNew analytics key event state (only meaningful when bit 1 is set).
5 bit 3raw_wheel-valid1 = the raw_wheel value bit is being changed.
5 bit 2raw_wheel valueNew 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):

ByteFieldNotes
0 bit 0reset_all_cid_report_settings1 = 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)FieldNotes
0–1slot 0 CIDBig-endian u16; 0x0000 = slot not in use.
2–3slot 1 CIDBig-endian u16.
4–5slot 2 CIDBig-endian u16.
6–7slot 3 CIDBig-endian u16.

DivertedRawMouseXy (event fn 1)

Byte(s)FieldNotes
0–1dxBig-endian i16 horizontal delta.
2–3dyBig-endian i16 vertical delta.

AnalyticsKeyEvents (event fn 2)

Five packed 3-byte entries (bytes 0–14); each entry:

Offset within entryFieldNotes
0–1cidBig-endian u16 control ID.
2eventDevice-defined analytics event code.

DivertedRawWheel (event fn 4)

Byte(s)FieldNotes
0 bits 7–5(reserved)Unused upper bits.
0 bit 4resolution0 = Low, 1 = High (RawWheelResolution).
0 bits 3–0periods4-bit period count (U4, decoded via U4::from_lo).
1–2delta_verticalBig-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?;
    }
}

On this page