0x2202 · extendedAdjustableDpi
Extended per-sensor DPI control — independent X/Y resolution, lift-off distance, DPI-status LED, and firmware or host-side calibration.
The modern successor to 0x2201 adjustableDpi, adding independent
X/Y DPI, lift-off distance (LOD) control, DPI-status LED management, and a
firmware/software calibration flow. Rather than a flat DPI list, supported DPI is
described as a mix of DpiRange::Fixed values and DpiRange::Stepped ranges (each with
from, to, and step). get_sensor_capabilities reports which optional sub-features
a sensor supports via the SensorCapabilities flags.
get_sensor_dpi_parameters / set_sensor_dpi_parameters read and write the active DPI
for both axes and the LOD in a single call. show_sensor_dpi_status drives the device's
DPI indicator LED. The calibration sub-flow (get_dpi_calibration_info →
start_dpi_calibration → set_dpi_calibration) can run on firmware or host. Two
unsolicited events are emitted: ParametersChanged fires when the user presses a DPI
button, and CalibrationCompleted fires when a calibration finishes or times out.
SensorCapabilities—DPI_Y(independent Y-axis DPI),LOD(lift-off control),CALIBRATION,PROFILE(per-profile DPI lists).Lod—NotSupported,Low,Medium,High.LedHoldType—TimerBased,EventBased,SwControlOn,SwControlOff.CalibrationType—Hardware(on-sensor) orSoftware(host-computed).DpiCalibrationCorrection—Adjust(i16)scales resolution by(1024 + value) / 1024;RevertToOob/RevertToProfilereset to defaults.
Spec: Logitech HID++ 2.0 — x2202 extendedAdjustableDpi. Used by: DPI presets.
Function reference
The ExtendedDpiFeature wrapper (0x2202) exposes:
Methods
| Function | HID++ fn | Signature | Returns |
|---|---|---|---|
get_sensor_count | 0 | () | u8 |
get_sensor_capabilities | 1 | (sensor_index: u8) | SensorCapabilitiesInfo |
get_sensor_dpi_ranges | 2 | (sensor_index: u8, direction: DpiDirection) | Vec<DpiRange> |
get_sensor_dpi_list | 3 | (sensor_index: u8, direction: DpiDirection) | Vec<u16> |
get_sensor_lod_list | 4 | (sensor_index: u8, dpi_level_count: u8) | Vec<Lod> |
get_sensor_dpi_parameters | 5 | (sensor_index: u8) | DpiParameters |
set_sensor_dpi_parameters | 6 | (sensor_index: u8, params: SetDpiParameters) | () |
show_sensor_dpi_status | 7 | (sensor_index: u8, params: ShowDpiStatus) | () |
get_dpi_calibration_info | 8 | (sensor_index: u8) | DpiCalibrationInfo |
start_dpi_calibration | 9 | (sensor_index: u8, params: StartDpiCalibration) | () |
set_dpi_calibration | 10 | (sensor_index: u8, direction: DpiDirection, correction: DpiCalibrationCorrection) | () |
listen | event | () | Receiver<ExtendedDpiEvent> |
All async methods return Result<…, Hidpp20Error>; listen is synchronous and returns an async_channel::Receiver<ExtendedDpiEvent> directly.
Types
DpiDirection
The axis a DPI value or calibration applies to.
| Variant | Value | Description |
|---|---|---|
X | 0 | Horizontal (X) axis. |
Y | 1 | Vertical (Y) axis. |
Lod
A sensor's lift-off distance setting: the height above the surface at which the sensor stops tracking motion.
| Variant | Value | Description |
|---|---|---|
NotSupported | 0 | Lift-off distance control is not supported. |
Low | 1 | Low lift-off distance. |
Medium | 2 | Medium lift-off distance. |
High | 3 | High lift-off distance. |
LedHoldType
How the device holds the DPI status LED after a show_sensor_dpi_status request.
| Variant | Value | Description |
|---|---|---|
TimerBased | 0 | Turn the LED off once a device-defined timeout elapses. |
EventBased | 1 | Turn the LED off once a device-defined event completes (e.g. releasing a DPI-shift button). |
SwControlOn | 2 | Turn the LED on under software control. |
SwControlOff | 3 | Turn the LED off under software control. |
CalibrationType
Where a DPI calibration is computed.
| Variant | Value | Description |
|---|---|---|
Hardware | 0 | Calibration is computed by the sensor firmware / hardware. |
Software | 1 | Calibration is computed by host software. |
SensorCapabilities
Per-sensor capability flags reported by get_sensor_capabilities.
| Flag | Bit | Description |
|---|---|---|
DPI_Y | 1 << 0 | The sensor supports an independent Y-axis DPI. |
LOD | 1 << 1 | The sensor supports lift-off distance control. |
CALIBRATION | 1 << 2 | The sensor supports DPI calibration. |
PROFILE | 1 << 3 | The sensor supports DPI profiles. |
SensorCapabilitiesInfo
A sensor's capabilities and DPI-level count, returned by get_sensor_capabilities.
| Field | Type | Description |
|---|---|---|
sensor_index | u8 | Index of the sensor the capabilities belong to. |
dpi_level_count | u8 | Number of selectable DPI levels, or 0 if the device does not manage DPI levels. |
capabilities | SensorCapabilities | Supported capabilities. |
DpiRange
One entry of a sensor's supported-DPI description, returned by get_sensor_dpi_ranges. Fixed values and stepped ranges may be mixed; adjacent ranges may share an endpoint.
| Variant | Description |
|---|---|
Fixed(u16) | A single selectable DPI value. |
Stepped { from: u16, to: u16, step: u16 } | A contiguous range of selectable DPI values from from to to (inclusive) in increments of step. |
DpiParameters
Current and default DPI parameters of a sensor, returned by get_sensor_dpi_parameters. dpi_y and default_dpi_y are 0 when the sensor does not support an independent Y axis.
| Field | Type | Description |
|---|---|---|
sensor_index | u8 | Index of the sensor. |
dpi_x | u16 | Current X-axis DPI. |
default_dpi_x | u16 | Default X-axis DPI. |
dpi_y | u16 | Current Y-axis DPI, or 0 when unsupported. |
default_dpi_y | u16 | Default Y-axis DPI, or 0 when unsupported. |
lod | Lod | Current lift-off distance. |
SetDpiParameters
DPI parameters to apply with set_sensor_dpi_parameters.
| Field | Type | Description |
|---|---|---|
dpi_x | u16 | New X-axis DPI (1..=57343). |
dpi_y | u16 | New Y-axis DPI (1..=57343), or 0 when the sensor has no independent Y axis. |
lod | Lod | New lift-off distance. |
ShowDpiStatus
Parameters for show_sensor_dpi_status.
| Field | Type | Description |
|---|---|---|
dpi_level | u8 | DPI level to display (1..=dpi_level_count). |
led_hold_type | LedHoldType | How the device holds the DPI status LED. |
button_num | u8 | HID button number that initiated the DPI change (starts at 1). |
DpiCalibrationInfo
Calibration reference information returned by get_dpi_calibration_info.
| Field | Type | Description |
|---|---|---|
sensor_index | u8 | Index of the sensor. |
mouse_width | u8 | Device width in millimetres. |
mouse_length | u16 | Device length in millimetres. |
calib_dpi_x | u16 | X-axis DPI configured for calibration. |
calib_dpi_y | u16 | Y-axis DPI configured for calibration, or 0 when unsupported. |
StartDpiCalibration
Parameters for start_dpi_calibration.
| Field | Type | Description |
|---|---|---|
direction | DpiDirection | Axis to calibrate. |
expected_count | u16 | Expected pixel count for the calibration movement (ignored for CalibrationType::Software). |
calib_type | CalibrationType | Where the calibration is computed. |
start_timeout | u8 | Timeout in seconds for the calibration to start (<= 60). |
hw_process_timeout | u8 | Timeout in seconds for the hardware calibration process (<= 60). |
sw_process_timeout | u8 | Timeout in seconds for the software calibration process (<= 60). |
DpiCalibrationCorrection
A DPI calibration correction to apply with set_dpi_calibration.
| Variant | Description |
|---|---|
Adjust(i16) | Scale the sensor resolution by (1024 + value) / 1024. Valid values are -1023..=1023; 0 reverts to the out-of-box setting. |
RevertToOob | Revert to the out-of-box (OOB) profile setting (wire value 0x0000). |
RevertToProfile | Revert to the setting stored in the current profile (wire value 0x8000). |
Events
ExtendedDpiFeature implements EmittingFeature<ExtendedDpiEvent>; call listen() to receive a channel of ExtendedDpiEvent values. The enum has two variants:
DpiParametersChanged
Payload of ExtendedDpiEvent::ParametersChanged. Fired when the sensor's DPI parameters change on the device (e.g. via a DPI button).
| Field | Type | Description |
|---|---|---|
sensor_index | u8 | Index of the sensor whose parameters changed. |
dpi_x | u16 | New X-axis DPI. |
dpi_y | u16 | New Y-axis DPI, or 0 when the sensor has no independent Y axis. |
lod | Lod | New lift-off distance. |
DpiCalibrationCompleted
Payload of ExtendedDpiEvent::CalibrationCompleted. Fired when a DPI calibration finishes or times out.
| Field | Type | Description |
|---|---|---|
sensor_index | u8 | Index of the sensor. |
direction | DpiDirection | Axis that was calibrated. |
correction | i16 | Calibration correction value; i16::MIN (0x8000) signals a sensor-level failure (check failed()). |
delta | i16 | Perpendicular-axis displacement in pixel counts, useful for judging calibration quality. |
Wire format
Most getter requests carry a 3-byte short payload; setter/calibration requests use a 16-byte long payload via call_long. Responses are always read from the 16-byte extended payload returned by extend_payload().
get_sensor_count (fn 0)
Request: [0x00, 0x00, 0x00] (no parameters)
Response (byte → field):
| Byte | Field | Notes |
|---|---|---|
| 0 | sensor_count | Number of motion sensors on the device. |
get_sensor_capabilities (fn 1)
Request: [sensor_index, 0x00, 0x00]
Response (byte → field):
| Byte | Field | Notes |
|---|---|---|
| 0 | sensor_index | Echoed sensor index. |
| 1 | dpi_level_count | Selectable DPI levels; 0 = unmanaged. |
| 2 | capabilities | SensorCapabilities bitfield: bit 0 = DPI_Y, bit 1 = LOD, bit 2 = CALIBRATION, bit 3 = PROFILE. |
get_sensor_dpi_ranges (fn 2)
Fetches pages until a 0x0000 end-of-list terminator is encountered (up to 16 pages).
Request: [sensor_index, direction, page] where direction: 0 = X, 1 = Y; page starts at 0.
Response (byte → field):
| Byte | Field | Notes |
|---|---|---|
| 0 | echoed sensor_index | Validated before trusting the page. |
| 1 | echoed direction | |
| 2 | echoed page | |
| 3–15 | range stream bytes | Big-endian 16-bit words; top 3 bits 0b111 = hyphen (step); 0x0000 = end-of-list. |
get_sensor_dpi_list (fn 3)
Request: [sensor_index, direction, 0x00]
Response (byte → field):
| Byte | Field | Notes |
|---|---|---|
| 0 | echoed sensor_index | Skipped by the parser. |
| 1 | echoed direction | Skipped by the parser. |
| 2–15 | DPI list words | Big-endian u16 values; 0x0000 terminates the list. |
get_sensor_lod_list (fn 4)
Request: [sensor_index, 0x00, 0x00]
Response (byte → field):
| Byte | Field | Notes |
|---|---|---|
| 0 | echoed sensor_index | Skipped by the parser. |
1 … dpi_level_count | LOD entries | One u8 per level: 0 = NotSupported, 1 = Low, 2 = Medium, 3 = High. List length is supplied by the caller as dpi_level_count. |
get_sensor_dpi_parameters (fn 5)
Request: [sensor_index, 0x00, 0x00]
Response (byte → field):
| Byte | Field | Notes |
|---|---|---|
| 0 | sensor_index | |
| 1–2 | dpi_x | Big-endian u16. |
| 3–4 | default_dpi_x | Big-endian u16. |
| 5–6 | dpi_y | Big-endian u16; 0 when Y-axis DPI is unsupported. |
| 7–8 | default_dpi_y | Big-endian u16; 0 when Y-axis DPI is unsupported. |
| 9 | lod | Lod byte: 0–3. |
set_sensor_dpi_parameters (fn 6)
Uses a 16-byte long request payload (call_long).
Request bytes 0–5 (remainder zero-padded):
| Byte | Field | Notes |
|---|---|---|
| 0 | sensor_index | |
| 1 | dpi_x high byte | |
| 2 | dpi_x low byte | |
| 3 | dpi_y high byte | 0 when no independent Y axis. |
| 4 | dpi_y low byte | 0 when no independent Y axis. |
| 5 | lod | Lod byte: 0–3. |
Response: not read (acknowledged by the device's echo).
show_sensor_dpi_status (fn 7)
Uses a 16-byte long request payload (call_long).
Request bytes 0–3 (remainder zero-padded):
| Byte | Field | Notes |
|---|---|---|
| 0 | sensor_index | |
| 1 | dpi_level | Level to display (1..=dpi_level_count). |
| 2 | led_hold_type | 0 = TimerBased, 1 = EventBased, 2 = SwControlOn, 3 = SwControlOff. |
| 3 | button_num | HID button number that triggered the change (starts at 1). |
Response: not read.
get_dpi_calibration_info (fn 8)
Request: [sensor_index, 0x00, 0x00]
Response (byte → field):
| Byte | Field | Notes |
|---|---|---|
| 0 | sensor_index | |
| 1 | mouse_width | Device width in mm. |
| 2–3 | mouse_length | Device length in mm, big-endian u16. |
| 4–5 | calib_dpi_x | X-axis calibration DPI, big-endian u16. |
| 6–7 | calib_dpi_y | Y-axis calibration DPI, big-endian u16; 0 when unsupported. |
start_dpi_calibration (fn 9)
Uses a 16-byte long request payload (call_long).
Request bytes 0–7 (remainder zero-padded):
| Byte | Field | Notes |
|---|---|---|
| 0 | sensor_index | |
| 1 | direction | 0 = X, 1 = Y. |
| 2 | expected_count high byte | Ignored for CalibrationType::Software. |
| 3 | expected_count low byte | |
| 4 | calib_type | 0 = Hardware, 1 = Software. |
| 5 | start_timeout | Seconds; <= 60. |
| 6 | hw_process_timeout | Seconds; <= 60. |
| 7 | sw_process_timeout | Seconds; <= 60. |
Response: not read (result delivered via CalibrationCompleted event).
set_dpi_calibration (fn 10)
Uses a 16-byte long request payload (call_long).
Request bytes 0–3 (remainder zero-padded):
| Byte | Field | Notes |
|---|---|---|
| 0 | sensor_index | |
| 1 | direction | 0 = X, 1 = Y. |
| 2 | correction high byte | DpiCalibrationCorrection::to_wire(): 0x8000 = RevertToProfile, 0x0000 = RevertToOob, signed value = Adjust. |
| 3 | correction low byte |
Response: not read.
Events
ParametersChanged (sub-id 0)
| Byte | Field | Notes |
|---|---|---|
| 0 | sensor_index | |
| 1–2 | dpi_x | Big-endian u16. |
| 3–4 | dpi_y | Big-endian u16; 0 when Y-axis DPI is unsupported. |
| 5 | lod | Lod byte: 0–3. |
CalibrationCompleted (sub-id 1)
| Byte | Field | Notes |
|---|---|---|
| 0 | sensor_index | |
| 1 | direction | 0 = X, 1 = Y. |
| 2–3 | correction | Signed big-endian i16; 0x8000 (i16::MIN) signals sensor-level failure. |
| 4–5 | delta | Signed big-endian i16; perpendicular-axis pixel displacement. |
Usage (Rust)
use hidpp::{
device::Device,
feature::{
extended_dpi::{
DpiDirection, ExtendedDpiFeature, Lod, SetDpiParameters, StartDpiCalibration,
CalibrationType,
},
EmittingFeature,
},
};
// device: &mut Device, already created via Device::new(channel, index).await?
device.enumerate_features().await?;
if let Some(feat) = device.get_feature::<ExtendedDpiFeature>() {
// Query how many sensors the device has.
let sensor_count = feat.get_sensor_count().await?;
// Read the current DPI and lift-off distance for sensor 0.
let params = feat.get_sensor_dpi_parameters(0).await?;
println!("DPI X={} Y={} LOD={:?}", params.dpi_x, params.dpi_y, params.lod);
// Set a new DPI (e.g. 1600 dpi on X, linked Y, medium lift-off).
feat.set_sensor_dpi_parameters(0, SetDpiParameters {
dpi_x: 1600,
dpi_y: 0, // linked to X when sensor has no independent Y axis
lod: Lod::Medium,
}).await?;
// Listen for unsolicited DPI-change events.
let rx = feat.listen();
while let Ok(event) = rx.recv().await {
println!("DPI event: {:?}", event);
}
}