OpenLogi

HID++ Reference

Logitech's vendor protocol for mice, keyboards, and receivers, as OpenLogi speaks it — message format, errors, feature discovery, and how to read the feature pages.

HID++ is Logitech's vendor protocol for configuring mice, keyboards, lights, and receivers. It runs over USB HID and Bluetooth HID. OpenLogi speaks it directly through openlogi-hidpp, its hard fork of the hidpp Rust crate. The library name stays hidpp, so code examples on these pages write use hidpp::....

Two generations

  • HID++ 1.0 uses a fixed set of numbered registers. Unifying and Bolt receivers still use it for pairing and device enumeration.
  • HID++ 2.0 uses a discoverable set of features. A 16-bit ID names each feature, written 0xZZZZ, for example 0x2201. Modern devices use this generation for every setting.

Message format

Every HID++ message is a short or a long HID report. OpenLogi uses only these two report types for HID++.

ReportReport IDLengthParameter bytes
Short0x107 bytes3
Long0x1120 bytes16

The first four bytes have the same meaning in both reports:

ByteHID++ 2.0HID++ 1.0
0Report ID (0x10 or 0x11)Report ID
1Device indexDevice index
2Feature indexSub-ID (0x80–0x83 for register access)
3Function ID (high nibble) and software ID (low nibble)Register address
4…ParametersRegister data

The device index selects the target. 0xFF addresses a receiver itself, or the features of a directly connected device (Bluetooth or USB cable). A device paired to a receiver is addressed by its slot number, starting at 1. See Receivers.

The feature index is a per-device runtime number, not the feature ID. A host resolves it once through 0x0000 root. The function ID selects one function of that feature. The feature pages write it as fn 0, fn 1, and so on.

Software ID

The software ID lets a host match a reply to its request. Requests carry 1–15. A device sends 0 in its own notifications, so a report with software ID 0 is an event, not a reply. OpenLogi assigns the ID per channel: a fixed ID, a rotating ID, or an ID leased for the life of the channel. The lease keeps two concurrent opens of the same HID node from sharing an ID.

A reply echoes bytes 1–3 of its request. OpenLogi matches a reply to the oldest pending request with the same three bytes. It never has two requests with the same three bytes in flight at once, because a wireless receiver can deliver their replies out of order.

Register access (HID++ 1.0)

Sub-IDRequest
0x80Set a short register (3 data bytes)
0x81Get a short register
0x82Set a long register (16 data bytes)
0x83Get a long register
0x8FError reply

Errors

A HID++ 2.0 error reply has feature index 0xFF. Byte 3 repeats the feature index of the failed request, byte 4 repeats its function and software ID byte, and byte 5 holds the error code. OpenLogi returns the code as Hidpp20Error::Feature(ErrorType). An unknown code becomes Hidpp20Error::UnsupportedResponse.

CodeErrorTypeMeaning
0NoErrorNo error
1UnknownUnknown error
2InvalidArgumentInvalid argument
3OutOfRangeArgument out of range
4HwErrorHardware error
5LogitechInternalFirmware-internal error
6InvalidFeatureIndexNo feature at this index
7InvalidFunctionIdThe feature has no such function
8BusyThe device is busy
9UnsupportedThe operation is not supported

A HID++ 1.0 error reply has sub-ID 0x8F. Bytes 3 and 4 repeat the request's sub-ID and register address, and byte 5 holds the error code. OpenLogi returns it as Hidpp10Error::RegisterAccess(ErrorType).

CodeErrorType (1.0)CodeErrorType (1.0)
0x00Success0x07Busy
0x01InvalidSubId0x08UnknownDevice
0x02InvalidAddress0x09ResourceError
0x03InvalidValue0x0ARequestUnavailable
0x04ConnectFail0x0BInvalidParamValue
0x05TooManyDevices0x0CWrongPinCode
0x06AlreadyExists

Feature discovery

A 2.0 device exposes its capabilities through two root features:

OpenLogi enumerates the feature set when it probes a device. It then queries the features it supports: device information, battery, DPI, SmartShift, and others. The feature index lists every catalogued feature and its status in OpenLogi.

Identity

Two things name a device on the wire. A receiver has a USB vendor and product ID; see Receivers. A device reports a model ID through 0x0003 deviceInformation. The model ID index lists every known model ID.

Reading the feature pages

Each implemented feature has one page with the same sections:

  1. Spec line: the sources for the layout and the OpenLogi pages that use the feature.
  2. Function reference: the methods, types, and events of the openlogi-hidpp wrapper at OpenLogi v0.8.15.
  3. Wire format: the request and reply bytes of every function and event. Multi-byte fields name their byte order (BE or LE).
  4. How OpenLogi uses it: the device-layer behavior, such as read-modify-write and read-back checks.
  5. Open questions: points where the sources disagree or no hardware capture exists yet.

No public Logitech specification covers some features or fields. For those, the pages use static analysis of Logitech's own software, done for interoperability. A Notes cell then carries a source tag:

TagSource
Options+ 2.8Static analysis of Logi Options+ 2.8. It shows what that software sends and reads, not what the firmware does.
G HUBStatic analysis of Logitech G HUB. Same limit as above.
SolaarThe Solaar open-source implementation.

A fact without a tag comes from a Logitech HID++ document or from OpenLogi's own tested code.

Attribution & copyright

This HID++ reference is an original summary written for the OpenLogi project. It describes Logitech's HID++ 1.0 and 2.0 protocol from publicly available documentation, the hidpp implementation, Solaar, and static analysis of Logitech software for interoperability. It reproduces no Logitech document or code. “Logitech”, “Unifying”, “Logi Bolt”, “Options+”, and “G HUB” are trademarks of Logitech. OpenLogi is an independent project and is not affiliated with, authorized, or endorsed by Logitech. The material is provided “as is”, without warranty of any kind.

On this page