0x4600 · crown
查询和配置旋转表冠,并接收其转向后的转动、传感器、手势和按钮更新。
0x4600 控制受支持 MX Master 设备的旋转表冠。它公开能力和当前模式读取。它可以修改上报方式、棘轮模式和三个时间值。
规格: Logitech HID++ 2.0 —— x4600 crown(v0)。用于: OpenLogi 只提供类型化 openlogi-hidpp 包装器。
CrownFeature 实现 feature 版本 0。
| 函数 | HID++ fn | 签名 | 返回值 |
|---|
get_info | 0 | () | CrownInfo |
get_mode | 1 | () | CrownMode |
set_mode | 2 | (mode: SetCrownMode) | () |
listen | event | () | async_channel::Receiver<CrownEvent> |
前三个方法是 async,并返回 Result<…, Hidpp20Error>。listen 是同步方法。
| 字段 | 类型 | 说明 |
|---|
controls | CrownControlCapabilities | 控制能力位。 |
sensors | CrownSensorCapabilities | 传感器能力位。 |
slots | u16 | 每圈的槽位数。 |
ratchets | u16 | 每圈的棘齿数。 |
| 字段 | 值 | 说明 |
|---|
BUTTON | 1 << 0 | 表冠有按钮。 |
BUTTON_LONG_PRESS | 1 << 1 | 按钮报告长按。 |
MECHANIZED_RATCHET | 1 << 2 | 棘轮是机械式的。 |
ROTATION_TIMEOUT_CONFIGURABLE | 1 << 3 | 可以配置转动超时。 |
SHORT_LONG_TIMEOUT_CONFIGURABLE | 1 << 4 | 可以配置短按和长按阈值。 |
DOUBLE_TAP_SPEED_CONFIGURABLE | 1 << 5 | 可以配置双击速度。 |
| 字段 | 值 | 说明 |
|---|
PROXIMITY | 1 << 0 | 表冠有近接传感器。 |
TOUCH | 1 << 1 | 表冠有触摸传感器。 |
TAP_GESTURE | 1 << 2 | 表冠识别单击。 |
DOUBLE_TAP_GESTURE | 1 << 3 | 表冠识别双击。 |
| 字段 | CrownMode 类型 | SetCrownMode 类型 | 说明 |
|---|
diverting | ReportingMode | Option<ReportingMode> | 事件上报目标。 |
ratchet_mode | RatchetMode | Option<RatchetMode> | 自由或棘轮转动。 |
rotation_timeout | u8 | Option<NonZeroU8> | 以 10 ms 为步进的超时。 |
short_long_timeout | u8 | Option<NonZeroU8> | 以 10 ms 为步进的按压阈值。 |
double_tap_speed | u8 | Option<NonZeroU8> | 以 10 ms 为步进的双击速度。 |
SetCrownMode 中的 None 会写入协议的零保持不变标记。设备会将 rotation_timeout 限制为 0x40。CrownMode 会拒绝该标记和其他未知模式值。
| 类型 | 变体 | 值 | 说明 |
|---|
ReportingMode | Hid | 1 | 事件发送到原生 HID。 |
ReportingMode | Diverted | 2 | 事件发送到 HID++。 |
RatchetMode | Free | 1 | 自由转动。 |
RatchetMode | Ratchet | 2 | 有刻度的转动。 |
CrownFeature 实现 EmittingFeature<CrownEvent>。它只接受事件子 ID 0。
| 变体或字段 | 类型 | 说明 |
|---|
Update(CrownUpdate) | CrownEvent | 上报转向时的一条表冠更新。 |
rotation_state | RotationState | 转动生命周期状态。 |
relative_slot_rotation | i8 | 带符号的槽位增量。 |
relative_ratchet_rotation | i8 | 带符号的棘齿增量。 |
proximity | ActivityState | 近接生命周期状态。 |
touch | ActivityState | 触摸生命周期状态。 |
gesture | CrownGesture | 触摸手势。 |
button | ButtonState | 按钮生命周期状态。 |
speed | i16 | 每秒带符号的槽位数。 |
| 类型 | 变体 | 值 |
|---|
RotationState | Inactive、Start、Active、Stop、Other(u8) | 0–3、其他 |
ActivityState | Inactive、Start、Active、Stop、Other(u8) | 0–3、其他 |
CrownGesture | None、Tap、DoubleTap、Other(u8) | 0–2、其他 |
ButtonState | Inactive、Press、ShortPressActive、LongPress、LongPressActive、Release、Other(u8) | 0–5、其他 |
事件枚举会将未建模字节保留为 Other(u8)。
get_info 和 get_mode 发送三个零字节。set_mode 发送 16 字节长负载。OpenLogi 忽略下表未列出的响应字节。
| 字节 | 字段 | 备注 |
|---|
| 0 | controls | CrownControlCapabilities;未知位会保留。 |
| 1 | sensors | CrownSensorCapabilities;未知位会保留。 |
| 2–3 | slots | u16,BE。 |
| 4–5 | ratchets | u16,BE。 |
| 6–15 | — | OpenLogi 忽略这些字节。 |
| 字节 | 字段 | 备注 |
|---|
| 0 | diverting | 1 = Hid;2 = Diverted。0 和其他值会被拒绝。 |
| 1 | ratchet_mode | 1 = Free;2 = Ratchet。0 和其他值会被拒绝。 |
| 2 | rotation_timeout | u8,以 10 ms 为步进。 |
| 3 | short_long_timeout | u8,以 10 ms 为步进。 |
| 4 | double_tap_speed | u8,以 10 ms 为步进。 |
| 5–15 | — | OpenLogi 忽略这些字节。 |
| 字节 | 字段 | 备注 |
|---|
| 0 | diverting | Some(Hid) = 1;Some(Diverted) = 2;None = 0。 |
| 1 | ratchet_mode | Some(Free) = 1;Some(Ratchet) = 2;None = 0。 |
| 2 | rotation_timeout | NonZeroU8 值,或 None 的 0。 |
| 3 | short_long_timeout | NonZeroU8 值,或 None 的 0。 |
| 4 | double_tap_speed | NonZeroU8 值,或 None 的 0。 |
| 5–15 | — | OpenLogi 写入 0x00。 |
协议响应回显请求字节。OpenLogi 不解码该响应。调用 get_mode 可读取结果模式。
| 字节 | 字段 | 备注 |
|---|
| 0 | rotation_state | RotationState,包括 Other(u8)。 |
| 1 | relative_slot_rotation | i8。 |
| 2 | relative_ratchet_rotation | i8。 |
| 3 | proximity | ActivityState,包括 Other(u8)。 |
| 4 | touch | ActivityState,包括 Other(u8)。 |
| 5 | gesture | CrownGesture,包括 Other(u8)。 |
| 6 | button | ButtonState,包括 Other(u8)。 |
| 7–13 | — | OpenLogi 忽略这些字节。 |
| 14–15 | speed | i16,BE。 |
v0.8.15 的设备层和代理层没有使用 CrownFeature。类型化包装器向库使用者公开此功能。它不执行能力门控、读改写、读回检查或会话恢复。
use std::num::NonZeroU8;
use hidpp::{
device::Device,
feature::{
EmittingFeature,
crown::{CrownFeature, RatchetMode, ReportingMode, SetCrownMode},
},
};
// device: &mut Device, already created via Device::new(channel, index)
device.enumerate_features().await?;
if let Some(feature) = device.get_feature::<CrownFeature>() {
feature
.set_mode(SetCrownMode {
diverting: Some(ReportingMode::Diverted),
ratchet_mode: Some(RatchetMode::Ratchet),
rotation_timeout: Some(NonZeroU8::new(10).unwrap()),
short_long_timeout: None,
double_tap_speed: None,
})
.await?;
println!("{:?}", feature.get_mode().await?);
let receiver = feature.listen();
while let Ok(event) = receiver.recv().await {
println!("{event:?}");
}
}