0x2202 · extendedAdjustableDpi
扩展的按传感器 DPI 控制——X/Y 分辨率、离地距离、DPI 状态 LED 控制和校准。
0x2202 按传感器控制 DPI 参数。它在 0x2201 adjustableDpi 的基础上,增加可选的 X/Y DPI、离地距离(LOD)、DPI 状态 LED 控制、配置文件和校准。
**规格:**Logitech HID++ 2.0 —— x2202 extendedAdjustableDpi。**交叉核对:**Logi Options+ 2.8(静态分析)、Solaar。用于:DPI。
函数参考
ExtendedDpiFeature 是 OpenLogi 对 0x2202 的封装。异步方法返回 Result<T, Hidpp20Error>。listen 是同步方法,并返回 async_channel::Receiver<ExtendedDpiEvent>。
方法
| 函数 | HID++ fn | 签名 | 返回值 |
|---|---|---|---|
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> |
类型
DpiDirection
| 变体 | 值 | 说明 |
|---|---|---|
X | 0 | 水平轴。 |
Y | 1 | 垂直轴。 |
Lod
LOD 是传感器停止追踪移动时,相对表面的高度。
| 变体 | 值 | 说明 |
|---|---|---|
NotSupported | 0 | 传感器不支持 LOD 控制。 |
Low | 1 | 低离地距离。 |
Medium | 2 | 中离地距离。 |
High | 3 | 高离地距离。 |
LedHoldType
| 变体 | 值 | 说明 |
|---|---|---|
TimerBased | 0 | 在设备定义的超时后关闭 LED。 |
EventBased | 1 | 在设备定义的事件后关闭 LED。 |
SwControlOn | 2 | 由软件控制打开 LED。 |
SwControlOff | 3 | 由软件控制关闭 LED。 |
CalibrationType
| 变体 | 值 | 说明 |
|---|---|---|
Hardware | 0 | 传感器固件执行校准计算。 |
Software | 1 | 主机软件执行校准计算。 |
SensorCapabilities
| 字段 | 位 | 说明 |
|---|---|---|
DPI_Y | 1 << 0 | 传感器支持独立的 Y 轴 DPI。 |
LOD | 1 << 1 | 传感器支持 LOD 控制。 |
CALIBRATION | 1 << 2 | 传感器支持校准。 |
PROFILE | 1 << 3 | 传感器支持 DPI 配置文件。 |
get_sensor_capabilities 会保留未知能力位。SetDpiParameters::for_sensor 只使用 DPI_Y 和 LOD 来准备写入。
SensorCapabilitiesInfo
| 字段 | 类型 | 说明 |
|---|---|---|
sensor_index | u8 | 回复中的传感器索引。 |
dpi_level_count | u8 | 可选 DPI 等级数量。0 表示设备不管理 DPI 等级。 |
capabilities | SensorCapabilities | 该传感器的能力位。 |
DpiRange
| 变体 | 说明 |
|---|---|
Fixed(u16) | 一个可选 DPI 值。 |
Stepped | 带公开 from: u16、to: u16 和 step: u16 字段的闭区间 DPI 范围。 |
相邻的步进范围可以共享一个端点。
DpiParameters
| 字段 | 类型 | 说明 |
|---|---|---|
sensor_index | u8 | 传感器索引。 |
dpi_x | u16 | 当前 X 轴 DPI。 |
default_dpi_x | u16 | 默认 X 轴 DPI。 |
dpi_y | u16 | 当前 Y 轴 DPI。没有 DPI_Y 时为 0。 |
default_dpi_y | u16 | 默认 Y 轴 DPI。没有 DPI_Y 时为 0。 |
lod | Lod | 当前离地距离。 |
SetDpiParameters
| 字段 | 类型 | 说明 |
|---|---|---|
dpi_x | u16 | 新的 X 轴 DPI。协议范围为 1..=57343。 |
dpi_y | u16 | 新的 Y 轴 DPI。没有 DPI_Y 时为 0。 |
lod | Lod | 新的离地距离。 |
SetDpiParameters::for_sensor(capabilities, dpi_x, dpi_y, lod) 仅在存在 DPI_Y 时发送 Y 值,并仅在存在 LOD 时发送 LOD。原始 setter 不检查能力或 DPI 范围。
ShowDpiStatus
| 字段 | 类型 | 说明 |
|---|---|---|
dpi_level | u8 | 要显示的等级。协议范围为 1..=dpi_level_count。 |
led_hold_type | LedHoldType | LED 的保持方式。 |
button_num | u8 | 触发变更的 HID 按钮号。从 1 开始。 |
DpiCalibrationInfo
| 字段 | 类型 | 说明 |
|---|---|---|
sensor_index | u8 | 传感器索引。 |
mouse_width | u8 | 设备宽度,单位为毫米。 |
mouse_length | u16 | 设备长度,单位为毫米。 |
calib_dpi_x | u16 | 校准使用的 X 轴 DPI。 |
calib_dpi_y | u16 | 校准使用的 Y 轴 DPI。没有 DPI_Y 时为 0。 |
StartDpiCalibration
| 字段 | 类型 | 说明 |
|---|---|---|
direction | DpiDirection | 要校准的轴。 |
expected_count | u16 | 预期移动像素数。软件校准会忽略该值。 |
calib_type | CalibrationType | 校准执行位置。 |
start_timeout | u8 | 开始超时,单位为秒。协议允许的最大值为 60。 |
hw_process_timeout | u8 | 硬件处理超时,单位为秒。协议允许的最大值为 60。 |
sw_process_timeout | u8 | 软件处理超时,单位为秒。协议允许的最大值为 60。 |
DpiCalibrationCorrection
| 变体 | 说明 |
|---|---|
Adjust(i16) | 按 (1024 + value) / 1024 缩放分辨率。有效值为 -1023 至 1023。 |
RevertToOob | 恢复出厂配置文件设置。线值为 0x0000。 |
RevertToProfile | 恢复当前配置文件设置。线值为 0x8000。 |
Adjust(0) 与 RevertToOob 使用相同的线值。超出范围的调整会返回 Hidpp20Error::Feature(ErrorType::InvalidArgument)。
事件
ExtendedDpiFeature 实现了 EmittingFeature<ExtendedDpiEvent>。设备发送主动报告前,调用 listen()。
DpiParametersChanged
ExtendedDpiEvent::ParametersChanged 报告由设备发起的 DPI 参数变更。
| 字段 | 类型 | 说明 |
|---|---|---|
sensor_index | u8 | 发生变更的传感器。 |
dpi_x | u16 | 新的 X 轴 DPI。 |
dpi_y | u16 | 新的 Y 轴 DPI。没有 DPI_Y 时为 0。 |
lod | Option<Lod> | 新的 LOD。未知线值会变为 None。 |
DpiCalibrationCompleted
ExtendedDpiEvent::CalibrationCompleted 报告校准完成或超时。
| 字段 | 类型 | 说明 |
|---|---|---|
sensor_index | u8 | 已校准的传感器。 |
direction | Option<DpiDirection> | 已校准的轴。未知线值会变为 None。 |
correction | i16 | BE 校准值。i16::MIN 表示传感器级失败。 |
delta | i16 | BE 垂直轴位移,单位为像素。 |
使用 DpiCalibrationCompleted::failed() 检查 i16::MIN 失败哨兵。
线格式
函数 0~5 和 8 使用 3 字节短请求。函数 6、7、9 和 10 使用 16 字节长请求。OpenLogi 会将长请求中未指定的字节写为零。下面所有多字节字段均采用 BE 字节序。
get_sensor_count(fn 0)
请求:[0x00, 0x00, 0x00]。
| 字节 | 字段 | 说明 |
|---|---|---|
| 0 | sensor_count | 运动传感器数量。 |
| 1–15 | / | OpenLogi 忽略这些字节。 |
get_sensor_capabilities(fn 1)
请求:[sensor_index, 0x00, 0x00]。
| 字节 | 字段 | 说明 |
|---|---|---|
| 0 | 回显的 sensor_index | OpenLogi 要求该值匹配。不同则返回 Hidpp20Error::UnsupportedResponse。 |
| 1 | dpi_level_count | 0 表示设备不管理 DPI 等级。 |
| 2 | capabilities | 位 0~3 分别是 DPI_Y、LOD、CALIBRATION 和 PROFILE。未知位会保留。 |
| 3–15 | / | OpenLogi 忽略这些字节。 |
get_sensor_dpi_ranges(fn 2)
请求:[sensor_index, direction, page]。direction 的 X 为 0,Y 为 1。page 从 0 开始。
| 字节 | 字段 | 说明 |
|---|---|---|
| 0 | 回显的 sensor_index | OpenLogi 要求该值匹配。 |
| 1 | 回显的 direction | OpenLogi 要求该值匹配。 |
| 2 | 回显的 page | OpenLogi 要求该值匹配。 |
| 3–15 | 范围流 | 13 字节的流。一个 BE 字可以跨越分页边界。 |
字面值的最高 3 位不是 0b111。最高 3 位为 0b111 的字携带相邻字面端点之间的正步长。0x0000 终止完整数据流。OpenLogi 最多读取 16 页,忽略首个终止符之后的字节,并拒绝格式错误或未终止的范围。
get_sensor_dpi_list(fn 3)
请求:[sensor_index, direction, 0x00]。
| 字节 | 字段 | 说明 |
|---|---|---|
| 0 | 回显的 sensor_index | OpenLogi 要求该值匹配。 |
| 1 | 回显的 direction | OpenLogi 要求该值匹配。 |
| 2–15 | DPI 字 | 最多 7 个 BE u16 条目。0x0000 终止列表。 |
此函数仅在具有 SensorCapabilities::PROFILE 时有意义。完整列表可以没有终止符。OpenLogi 会保留列出的顺序和重复值。
get_sensor_lod_list(fn 4)
请求:[sensor_index, 0x00, 0x00]。
| 字节 | 字段 | 说明 |
|---|---|---|
| 0 | 回显的 sensor_index | OpenLogi 要求该值匹配。 |
| 1 起 | LOD 条目 | 每个 DPI 等级占一个字节。0、1、2、3 分别映射到 Lod。 |
调用者提供 dpi_level_count,通常来自 fn 1。列表没有终止符。OpenLogi 只读取该数量的条目,并拒绝未知 LOD 或不可能的长度。它会忽略剩余载荷字节。
get_sensor_dpi_parameters(fn 5)
请求:[sensor_index, 0x00, 0x00]。
| 字节 | 字段 | 说明 |
|---|---|---|
| 0 | 回显的 sensor_index | OpenLogi 要求该值匹配。 |
| 1–2 | dpi_x | BE u16。 |
| 3–4 | default_dpi_x | BE u16。 |
| 5–6 | dpi_y | BE u16。没有 DPI_Y 时为 0。 |
| 7–8 | default_dpi_y | BE u16。没有 DPI_Y 时为 0。 |
| 9 | lod | Lod 值。OpenLogi 会拒绝未知值。 |
| 10–15 | / | OpenLogi 忽略这些字节。 |
OpenLogi 要求此函数使用长回复。短回复会返回 Hidpp20Error::UnsupportedResponse。
set_sensor_dpi_parameters(fn 6)
| 字节 | 字段 | 说明 |
|---|---|---|
| 0 | sensor_index | 目标传感器。 |
| 1–2 | dpi_x | BE u16。 |
| 3–4 | dpi_y | BE u16。没有 DPI_Y 时,协议要求为零。 |
| 5 | lod | Lod 值。没有 LOD 时,协议要求为零。 |
| 6–15 | / | OpenLogi 写入零。 |
OpenLogi 要求回复的字节 0 回显 sensor_index。SetDpiParameters::for_sensor 会为不支持的 Y 和 LOD 字段生成必需的零值。
show_sensor_dpi_status(fn 7)
| 字节 | 字段 | 说明 |
|---|---|---|
| 0 | sensor_index | 目标传感器。 |
| 1 | dpi_level | 要显示的 DPI 等级。 |
| 2 | led_hold_type | 0~3 分别映射到 LedHoldType。 |
| 3 | button_num | HID 按钮号。 |
| 4–15 | / | OpenLogi 写入零。 |
此函数只在主机模式下有效。OpenLogi 要求回复的字节 0 回显 sensor_index。
get_dpi_calibration_info(fn 8)
请求:[sensor_index, 0x00, 0x00]。
| 字节 | 字段 | 说明 |
|---|---|---|
| 0 | 回显的 sensor_index | OpenLogi 要求该值匹配。 |
| 1 | mouse_width | 设备宽度,单位为毫米。 |
| 2–3 | mouse_length | BE u16 设备长度,单位为毫米。 |
| 4–5 | calib_dpi_x | BE u16。 |
| 6–7 | calib_dpi_y | BE u16。没有 DPI_Y 时为 0。 |
| 8–15 | / | OpenLogi 忽略这些字节。 |
OpenLogi 要求此函数使用长回复。短回复会返回 Hidpp20Error::UnsupportedResponse。
start_dpi_calibration(fn 9)
| 字节 | 字段 | 说明 |
|---|---|---|
| 0 | sensor_index | 目标传感器。 |
| 1 | direction | X 为 0,Y 为 1。 |
| 2–3 | expected_count | BE u16。软件校准会忽略该值。 |
| 4 | calib_type | 硬件为 0,软件为 1。 |
| 5 | start_timeout | 单位为秒。协议允许的最大值为 60。 |
| 6 | hw_process_timeout | 单位为秒。协议允许的最大值为 60。 |
| 7 | sw_process_timeout | 单位为秒。协议允许的最大值为 60。 |
| 8–15 | / | OpenLogi 写入零。 |
此函数需要 SensorCapabilities::CALIBRATION。设备通过 CalibrationCompleted 事件报告结果。软件校准随后使用 fn 10 应用校正值。OpenLogi 要求回复的字节 0 回显 sensor_index。
set_dpi_calibration(fn 10)
| 字节 | 字段 | 说明 |
|---|---|---|
| 0 | sensor_index | 目标传感器。 |
| 1 | direction | X 为 0,Y 为 1。 |
| 2–3 | correction | BE 有符号 i16。0x0000 为出厂设置。0x8000 为配置文件恢复。 |
| 4–15 | / | OpenLogi 写入零。 |
OpenLogi 会在发送前验证 Adjust 的范围。它要求回复的字节 0 回显 sensor_index。
事件
主动报告使用子 ID 0 或 1。OpenLogi 解码前 6 个载荷字节,并忽略字节 6~15。
ParametersChanged(sub-id 0)
| 字节 | 字段 | 说明 |
|---|---|---|
| 0 | sensor_index | 发生变更的传感器。 |
| 1–2 | dpi_x | BE u16。 |
| 3–4 | dpi_y | BE u16。没有 DPI_Y 时为 0。 |
| 5 | lod | Lod 值。未知值会变为 None。 |
CalibrationCompleted(sub-id 1)
| 字节 | 字段 | 说明 |
|---|---|---|
| 0 | sensor_index | 完成校准的传感器。 |
| 1 | direction | X 为 0,Y 为 1。未知值会变为 None。 |
| 2–3 | correction | BE 有符号 i16。0x8000 是失败哨兵。 |
| 4–5 | delta | BE 有符号 i16 垂直轴位移,单位为像素。 |
未知事件子 ID 不会生成 ExtendedDpiEvent。
OpenLogi 的用法
设备未公开 0x2201 时,设备层才使用 0x2202。它只操作传感器 0。它通过 fn 5 读取 X DPI,并通过 fn 2 读取 X 轴范围。它不使用配置文件列表、LOD 列表、LED 或校准函数。
写入 DPI 前,OpenLogi 会展平设备报告的 X 轴范围。请求值不在该列表中时,它返回 WriteError::DpiUnsupported。它读取传感器能力和当前参数。SetDpiParameters::for_sensor 仅在具有 DPI_Y 时写入等于 X 的 Y 值。它仅在具有 LOD 时保留当前 LOD;否则写入零。fn 6 的确认回复必须回显传感器。
每次确认写入后,OpenLogi 都读取 X DPI,并重试一次。第二次读到不同值时,它返回 WriteError::DpiNotApplied。读取失败不会撤销已确认的写入。桌面端会在异步写入前保存请求,因此被拒绝或未应用的写入可能会保留在桌面端状态中,直到后续实时读取。
从 v0.8.14 起,库存监听器会识别主动 fn 0 DPI 参数广播。它增加设备设置修订号,因此客户端会重新读取权威设置。监听器不会解码事件载荷,也不会持久化设备发起的变更。它会忽略 fn 1 校准完成广播。
传感器设置是易失性的,因此代理会在重连后重新应用保存的 DPI。OpenLogi 退出时不会执行此功能的专用重置。面向用户的控制见 DPI 页面。
Rust 用法
use hidpp::{
device::Device,
feature::{
EmittingFeature,
extended_dpi::{DpiDirection, ExtendedDpiFeature, SetDpiParameters},
},
protocol::v20::Hidpp20Error,
};
async fn inspect_extended_dpi(device: &mut Device) -> Result<(), Hidpp20Error> {
device.enumerate_features().await?;
if let Some(feature) = device.get_feature::<ExtendedDpiFeature>() {
let capabilities = feature.get_sensor_capabilities(0).await?;
let ranges = feature.get_sensor_dpi_ranges(0, DpiDirection::X).await?;
let current = feature.get_sensor_dpi_parameters(0).await?;
println!("X ranges: {ranges:?}");
let write = SetDpiParameters::for_sensor(
capabilities.capabilities,
1600,
1600,
current.lod,
);
feature.set_sensor_dpi_parameters(0, write).await?;
let events = feature.listen();
if let Ok(event) = events.recv().await {
println!("DPI event: {event:?}");
}
}
Ok(())
}