openlogi_hid/reprog_controls/
event.rs1use hidpp::protocol::v20;
2
3use super::{ControlId, ReprogControlsEvent, decode_full_event};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum RawControlEvent {
8 DivertedButtons([u16; 4]),
12 RawXy {
15 dx: i16,
17 dy: i16,
19 },
20}
21
22impl RawControlEvent {
23 #[must_use]
25 pub fn is_pressed(&self, cid: u16) -> bool {
26 matches!(self, Self::DivertedButtons(cids) if cids.contains(&cid))
27 }
28}
29
30impl TryFrom<ReprogControlsEvent> for RawControlEvent {
31 type Error = ReprogControlsEvent;
32
33 fn try_from(event: ReprogControlsEvent) -> Result<Self, Self::Error> {
34 match event {
35 ReprogControlsEvent::DivertedButtons(cids) => {
36 Ok(Self::DivertedButtons(cids.map(ControlId::into)))
37 }
38 ReprogControlsEvent::DivertedRawMouseXy { dx, dy } => Ok(Self::RawXy { dx, dy }),
39 ReprogControlsEvent::AnalyticsKeyEvents(_)
40 | ReprogControlsEvent::DivertedRawWheel { .. } => Err(event),
41 }
42 }
43}
44
45#[must_use]
52pub fn decode_event(
53 msg: &v20::Message,
54 device_index: u8,
55 feature_index: u8,
56) -> Option<RawControlEvent> {
57 decode_full_event(msg, device_index, feature_index)?
58 .try_into()
59 .ok()
60}
61
62#[cfg(test)]
63mod tests {
64 use hidpp::{nibble::U4, protocol::v20};
65
66 use super::*;
67 use crate::reprog_controls::GESTURE_BUTTON_CID;
68
69 fn event(function_id: u8, software_id: u8, payload: [u8; 16]) -> v20::Message {
70 v20::Message::Long(
71 v20::MessageHeader {
72 device_index: 2,
73 feature_index: 7,
74 function_id: U4::from_lo(function_id),
75 software_id: U4::from_lo(software_id),
76 },
77 payload,
78 )
79 }
80
81 #[test]
82 fn decodes_diverted_buttons() {
83 let mut p = [0u8; 16];
84 p[0..2].copy_from_slice(&GESTURE_BUTTON_CID.to_be_bytes());
85 let decoded = decode_event(&event(0, 0, p), 2, 7);
86 assert_eq!(
87 decoded,
88 Some(RawControlEvent::DivertedButtons([
89 GESTURE_BUTTON_CID,
90 0,
91 0,
92 0,
93 ]))
94 );
95 assert!(decoded.is_some_and(|e| e.is_pressed(GESTURE_BUTTON_CID)));
96 }
97
98 #[test]
99 fn decodes_signed_raw_xy() {
100 let mut p = [0u8; 16];
101 p[0..2].copy_from_slice(&(-5i16).to_be_bytes());
102 p[2..4].copy_from_slice(&12i16.to_be_bytes());
103 assert_eq!(
104 decode_event(&event(1, 0, p), 2, 7),
105 Some(RawControlEvent::RawXy { dx: -5, dy: 12 })
106 );
107 }
108
109 #[test]
110 fn ignores_responses_and_foreign_messages() {
111 let p = [0u8; 16];
112 assert_eq!(decode_event(&event(0, 5, p), 2, 7), None);
114 assert_eq!(decode_event(&event(2, 0, p), 2, 7), None);
116 assert_eq!(decode_event(&event(0, 0, p), 2, 9), None);
118 }
119}