hidpp/feature/vertical_scrolling/
mod.rs1use std::sync::Arc;
4
5use num_enum::TryFromPrimitive;
6
7use crate::{
8 channel::HidppChannel,
9 feature::{CreatableFeature, Feature, FeatureEndpoint},
10 protocol::v20::Hidpp20Error,
11};
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TryFromPrimitive)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize))]
16#[non_exhaustive]
17#[repr(u8)]
18pub enum RollerType {
19 Standard = 0x01,
21 ThreeG = 0x03,
23 MicroRatchet = 0x04,
25 Touchpad = 0x05,
27 TouchpadNaturalDefault = 0x06,
29}
30
31#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize))]
34#[non_exhaustive]
35pub enum ScrollLines {
36 SystemDefault,
38 Lines(u8),
40 Page,
42}
43
44#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
46#[cfg_attr(feature = "serde", derive(serde::Serialize))]
47#[non_exhaustive]
48pub struct RollerInfo {
49 pub roller_type: RollerType,
51 pub ratchets_per_turn: u8,
53 pub scroll_lines: ScrollLines,
55}
56
57#[derive(Clone)]
59pub struct VerticalScrollingFeature {
60 endpoint: FeatureEndpoint,
62}
63
64impl CreatableFeature for VerticalScrollingFeature {
65 const ID: u16 = 0x2100;
66 const STARTING_VERSION: u8 = 0;
67
68 fn new(chan: Arc<HidppChannel>, device_index: u8, feature_index: u8) -> Self {
69 Self {
70 endpoint: FeatureEndpoint::new(chan, device_index, feature_index),
71 }
72 }
73}
74
75impl Feature for VerticalScrollingFeature {}
76
77impl VerticalScrollingFeature {
78 pub async fn get_roller_info(&self) -> Result<RollerInfo, Hidpp20Error> {
80 let payload = self.endpoint.call(0, [0; 3]).await?.extend_payload();
81 RollerInfo::from_payload(payload)
82 }
83}
84
85impl RollerInfo {
86 fn from_payload(payload: [u8; 16]) -> Result<Self, Hidpp20Error> {
87 Ok(Self {
88 roller_type: RollerType::try_from(payload[0])
89 .map_err(|_| Hidpp20Error::UnsupportedResponse)?,
90 ratchets_per_turn: payload[1],
91 scroll_lines: ScrollLines::from(payload[2]),
92 })
93 }
94}
95
96impl From<u8> for ScrollLines {
97 fn from(value: u8) -> Self {
98 match value {
99 0x00 => Self::SystemDefault,
100 0xff => Self::Page,
101 lines => Self::Lines(lines),
102 }
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::{RollerInfo, RollerType, ScrollLines};
109
110 #[test]
111 fn parses_roller_info() {
112 let mut payload = [0; 16];
113 payload[0] = 0x04;
114 payload[1] = 24;
115 payload[2] = 0xff;
116
117 let info = RollerInfo::from_payload(payload).unwrap();
118
119 assert_eq!(info.roller_type, RollerType::MicroRatchet);
120 assert_eq!(info.ratchets_per_turn, 24);
121 assert_eq!(info.scroll_lines, ScrollLines::Page);
122 }
123}