hidpp/feature/reprog_controls/
event.rs1use num_enum::{IntoPrimitive, TryFromPrimitive};
2
3use crate::{nibble::U4, protocol::v20};
4
5use super::ControlId;
6
7fn i16_from_be_payload(bytes: &[u8]) -> i16 {
8 i16::from_be_bytes(bytes.try_into().unwrap())
9}
10
11#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize))]
14pub struct AnalyticsKeyEvent {
15 pub cid: ControlId,
17 pub event: u8,
19}
20
21impl AnalyticsKeyEvent {
22 fn from_payload(bytes: &[u8]) -> Self {
23 Self {
24 cid: ControlId::from_payload(&bytes[0..=1]),
25 event: bytes[2],
26 }
27 }
28}
29
30#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, TryFromPrimitive)]
32#[cfg_attr(feature = "serde", derive(serde::Serialize))]
33#[repr(u8)]
34pub enum RawWheelResolution {
35 Low = 0,
37 High = 1,
39}
40
41#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
43#[cfg_attr(feature = "serde", derive(serde::Serialize))]
44pub enum ReprogControlsEvent {
45 DivertedButtons([ControlId; 4]),
47 DivertedRawMouseXy {
49 dx: i16,
51 dy: i16,
53 },
54 AnalyticsKeyEvents([AnalyticsKeyEvent; 5]),
56 DivertedRawWheel {
58 resolution: RawWheelResolution,
60 periods: U4,
62 delta_vertical: i16,
64 },
65}
66
67impl ReprogControlsEvent {
68 #[must_use]
70 pub fn is_pressed(self, cid: ControlId) -> bool {
71 matches!(self, Self::DivertedButtons(cids) if cids.contains(&cid))
72 }
73}
74
75#[must_use]
77pub fn decode_event(
78 msg: &v20::Message,
79 device_index: u8,
80 feature_index: u8,
81) -> Option<ReprogControlsEvent> {
82 let header = msg.header();
83 if header.device_index != device_index
84 || header.feature_index != feature_index
85 || header.software_id.to_lo() != 0
86 {
87 return None;
88 }
89 decode_event_payload(header.function_id.to_lo(), &msg.extend_payload())
90}
91
92pub(super) fn decode_event_payload(
93 function_id: u8,
94 payload: &[u8; 16],
95) -> Option<ReprogControlsEvent> {
96 match function_id {
97 0 => Some(ReprogControlsEvent::DivertedButtons([
98 ControlId::from_payload(&payload[0..=1]),
99 ControlId::from_payload(&payload[2..=3]),
100 ControlId::from_payload(&payload[4..=5]),
101 ControlId::from_payload(&payload[6..=7]),
102 ])),
103 1 => Some(ReprogControlsEvent::DivertedRawMouseXy {
104 dx: i16_from_be_payload(&payload[0..=1]),
105 dy: i16_from_be_payload(&payload[2..=3]),
106 }),
107 2 => Some(ReprogControlsEvent::AnalyticsKeyEvents([
108 AnalyticsKeyEvent::from_payload(&payload[0..=2]),
109 AnalyticsKeyEvent::from_payload(&payload[3..=5]),
110 AnalyticsKeyEvent::from_payload(&payload[6..=8]),
111 AnalyticsKeyEvent::from_payload(&payload[9..=11]),
112 AnalyticsKeyEvent::from_payload(&payload[12..=14]),
113 ])),
114 4 => Some(ReprogControlsEvent::DivertedRawWheel {
115 resolution: RawWheelResolution::try_from((payload[0] >> 4) & 1).ok()?,
116 periods: U4::from_lo(payload[0]),
117 delta_vertical: i16_from_be_payload(&payload[1..=2]),
118 }),
119 _ => None,
120 }
121}