0x4600 · crown
Control the MX Master rotary crown — query hardware capabilities, read or write reporting and ratchet mode, and receive diverted rotation, touch, gesture, and button events.
The Crown feature controls the rotary crown on the MX Master series.
get_info returns the hardware's CrownControlCapabilities (button, long-press,
mechanized ratchet, configurable rotation timeout, short-long timeout, and
double-tap speed) plus CrownSensorCapabilities (proximity, touch, tap, and
double-tap gestures), together with the slot and ratchet counts per revolution.
get_mode and set_mode read and write the active CrownMode: whether events
are delivered over the native HID channel or diverted into HID++
(ReportingMode), the ratchet vs. free-spin choice (RatchetMode), and three
configurable timings: rotation timeout, short-long press threshold, and
double-tap speed, all in 10 ms steps. Every SetCrownMode field uses a zero /
NoChange sentinel so individual settings can be updated without disturbing the
others.
While diverted, the crown emits a single CrownEvent::Update carrying a
CrownUpdate snapshot:
rotation_state/relative_slot_rotation/relative_ratchet_rotation/speed—RotationStatephase, signed delta slot and ratchet counts, and current speed in slots/s.proximity/touch—ActivityStatelifecycle phases (Start→Active→Stop).gesture—CrownGesture:Tap,DoubleTap, orNone.button—ButtonState:Inactive,Press,ShortPressActive,LongPress,LongPressActive, orRelease.
Spec: Logitech HID++ 2.0 — 0x4600 crown. Used by: Typed wrapper in
openlogi-hidpp.
Function reference
The CrownFeature wrapper (0x4600) exposes:
Methods
| Function | HID++ fn | Signature | Returns |
|---|---|---|---|
get_info | 0 | () | CrownInfo |
get_mode | 1 | () | CrownMode |
set_mode | 2 | (mode: SetCrownMode) | CrownMode |
listen | event | () | Receiver<CrownEvent> |
get_info, get_mode, and set_mode are async and return Result<…, Hidpp20Error>. listen is synchronous and returns an async_channel::Receiver<CrownEvent> directly.
Types
CrownInfo
Crown capabilities and hardware constants returned by get_info.
| Field | Type | Description |
|---|---|---|
controls | CrownControlCapabilities | Control capabilities. |
sensors | CrownSensorCapabilities | Sensor capabilities. |
slots | u16 | Number of slots per revolution. |
ratchets | u16 | Number of ratchets per revolution. |
CrownControlCapabilities
Crown control capabilities, from get_info.
| Flag | Bit/Value | Description |
|---|---|---|
BUTTON | 1 << 0 | The crown has a button. |
BUTTON_LONG_PRESS | 1 << 1 | The button reports long presses. |
MECHANIZED_RATCHET | 1 << 2 | The ratchet is mechanized (no manual control). |
ROTATION_TIMEOUT_CONFIGURABLE | 1 << 3 | The rotation timeout is configurable. |
SHORT_LONG_TIMEOUT_CONFIGURABLE | 1 << 4 | The short-long timeout is configurable. |
DOUBLE_TAP_SPEED_CONFIGURABLE | 1 << 5 | The double-tap speed is configurable. |
CrownSensorCapabilities
Crown sensor capabilities, from get_info.
| Flag | Bit/Value | Description |
|---|---|---|
PROXIMITY | 1 << 0 | The crown has a proximity sensor. |
TOUCH | 1 << 1 | The crown has a touch sensor. |
TAP_GESTURE | 1 << 2 | The crown detects tap gestures. |
DOUBLE_TAP_GESTURE | 1 << 3 | The crown detects double-tap gestures. |
CrownMode
The crown's current mode, returned by get_mode and echoed by set_mode.
| Field | Type | Description |
|---|---|---|
diverting | ReportingMode | How events are reported. |
ratchet_mode | RatchetMode | Ratchet mode. |
rotation_timeout | u8 | Rotation timeout, in 10 ms steps. |
short_long_timeout | u8 | Short-long press timeout, in 10 ms steps. |
double_tap_speed | u8 | Double-tap speed, in 10 ms steps. |
SetCrownMode
Mode settings written by set_mode. Every field uses 0 / ReportingMode::NoChange / RatchetMode::NoChange as a "leave unchanged" sentinel. The rotation timeout is clipped to 0x40.
| Field | Type | Description |
|---|---|---|
diverting | ReportingMode | How events are reported, or ReportingMode::NoChange. |
ratchet_mode | RatchetMode | Ratchet mode, or RatchetMode::NoChange. |
rotation_timeout | u8 | Rotation timeout in 10 ms steps, or 0 to leave unchanged. |
short_long_timeout | u8 | Short-long timeout in 10 ms steps, or 0 to leave unchanged. |
double_tap_speed | u8 | Double-tap speed in 10 ms steps, or 0 to leave unchanged. |
ReportingMode
How crown events are reported.
| Variant | Value | Description |
|---|---|---|
NoChange | 0 | Leave the setting unchanged (write-only sentinel). |
Hid | 1 | Events go to the native HID channel. |
Diverted | 2 | Events are diverted to HID++ (required for CrownEvent). |
RatchetMode
The crown's ratchet mode.
| Variant | Value | Description |
|---|---|---|
NoChange | 0 | Leave the setting unchanged (write-only sentinel). |
Free | 1 | Free-spinning mode. |
Ratchet | 2 | Ratchet (detented) mode. |
RotationState
Rotation phase reported in a CrownUpdate.
| Variant | Value | Description |
|---|---|---|
Inactive | 0 | Not rotating (or not diverted). |
Start | 1 | Rotation started. |
Active | 2 | Rotation ongoing. |
Stop | 3 | Rotation stopped. |
ActivityState
Proximity or touch activity phase reported in a CrownUpdate.
| Variant | Value | Description |
|---|---|---|
Inactive | 0 | Inactive. |
Start | 1 | Started. |
Active | 2 | Ongoing. |
Stop | 3 | Stopped. |
CrownGesture
Touch gesture reported in a CrownUpdate.
| Variant | Value | Description |
|---|---|---|
None | 0 | No gesture. |
Tap | 1 | Single tap. |
DoubleTap | 2 | Double tap. |
ButtonState
Crown button state reported in a CrownUpdate.
| Variant | Value | Description |
|---|---|---|
Inactive | 0 | Inactive (or not diverted). |
Press | 1 | Press started. |
ShortPressActive | 2 | Short press active. |
LongPress | 3 | Long press reached the time threshold. |
LongPressActive | 4 | Long press active. |
Release | 5 | Released. |
Events
CrownFeature implements EmittingFeature<CrownEvent>; call listen() to receive a channel of CrownEvent values. Events are only delivered while the crown is diverted (ReportingMode::Diverted).
CrownEvent
| Variant | Description |
|---|---|
Update(CrownUpdate) | The crown's rotation, proximity, touch, gesture, or button state changed. |
CrownUpdate
Payload of CrownEvent::Update.
| Field | Type | Description |
|---|---|---|
rotation_state | RotationState | Current rotation phase. |
relative_slot_rotation | i8 | Slots rotated since the last event (-127..=127). |
relative_ratchet_rotation | i8 | Ratchets rotated since the last event (-127..=127). |
proximity | ActivityState | Proximity-sensor phase. |
touch | ActivityState | Touch-sensor phase. |
gesture | CrownGesture | Touch gesture detected. |
button | ButtonState | Button state. |
speed | i16 | Crown speed in slots per second (signed). |
Wire format
Getter requests carry a 3-byte zero payload (call). set_mode uses a 16-byte long payload (call_long). All responses are read from the 16-byte extended payload returned by extend_payload(). Events arrive as unsolicited 16-byte messages on function index 0.
get_info (fn 0)
Request: [0x00, 0x00, 0x00]
Response (byte → field):
| Byte | Field | Notes |
|---|---|---|
| 0 | controls | CrownControlCapabilities bitfield |
| 1 | sensors | CrownSensorCapabilities bitfield |
| 2–3 | slots | Big-endian u16 — slots per revolution |
| 4–5 | ratchets | Big-endian u16 — ratchets per revolution |
get_mode (fn 1)
Request: [0x00, 0x00, 0x00]
Response (byte → field):
| Byte | Field | Notes |
|---|---|---|
| 0 | diverting | ReportingMode enum (0=NoChange, 1=Hid, 2=Diverted) |
| 1 | ratchet_mode | RatchetMode enum (0=NoChange, 1=Free, 2=Ratchet) |
| 2 | rotation_timeout | u8, in 10 ms steps |
| 3 | short_long_timeout | u8, in 10 ms steps |
| 4 | double_tap_speed | u8, in 10 ms steps |
set_mode (fn 2)
Request (16-byte long payload — bytes 5–15 are 0x00):
| Byte | Field | Notes |
|---|---|---|
| 0 | diverting | ReportingMode as u8 |
| 1 | ratchet_mode | RatchetMode as u8 |
| 2 | rotation_timeout | u8, in 10 ms steps |
| 3 | short_long_timeout | u8, in 10 ms steps |
| 4 | double_tap_speed | u8, in 10 ms steps |
Response: same layout as get_mode — the device echoes the resulting active mode.
CrownEvent::Update (event fn 0)
Unsolicited event emitted while the crown is diverted:
| Byte | Field | Notes |
|---|---|---|
| 0 | rotation_state | RotationState enum |
| 1 | relative_slot_rotation | i8 — signed slot delta since last event |
| 2 | relative_ratchet_rotation | i8 — signed ratchet delta since last event |
| 3 | proximity | ActivityState enum |
| 4 | touch | ActivityState enum |
| 5 | gesture | CrownGesture enum |
| 6 | button | ButtonState enum |
| 7–13 | (reserved) | not decoded by the driver |
| 14–15 | speed | Big-endian i16 — slots per second |
Usage (Rust)
use hidpp::{
device::Device,
feature::crown::{CrownFeature, ReportingMode, RatchetMode, SetCrownMode},
};
// device: &mut Device, already created via Device::new(channel, index)
device.enumerate_features().await?;
if let Some(feat) = device.get_feature::<CrownFeature>() {
let info = feat.get_info().await?;
println!("slots/rev={}, ratchets/rev={}", info.slots, info.ratchets);
// Divert crown events to HID++ and switch to ratchet mode
let mode = feat.set_mode(SetCrownMode {
diverting: ReportingMode::Diverted,
ratchet_mode: RatchetMode::Ratchet,
rotation_timeout: 0, // leave unchanged
short_long_timeout: 0, // leave unchanged
double_tap_speed: 0, // leave unchanged
}).await?;
println!("active mode: {:?}", mode.diverting);
// Receive crown events
let rx = feat.listen();
while let Ok(event) = rx.recv().await {
println!("{:?}", event);
}
}