Skip to main content

hidpp/feature/
touch_mouse_raw.rs

1//! Implements the `TouchMouseRaw` feature (ID `0x6110`) that exposes a touch
2//! mouse's raw touch points: pad characteristics, the raw-data mode, and the
3//! raw-data / status events.
4
5pub mod event;
6
7#[cfg(test)]
8mod tests;
9
10use num_enum::{IntoPrimitive, TryFromPrimitive};
11use openlogi_hidpp_derive::Feature;
12
13pub use event::{TouchMousePoint, TouchMouseRawEvent, TouchMouseStatus};
14
15use crate::{
16    feature::{EventSource, FeatureEndpoint},
17    protocol::v20::Hidpp20Error,
18};
19
20/// The position of the touch surface's coordinate origin, viewed from above.
21#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, TryFromPrimitive)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize))]
23#[non_exhaustive]
24#[repr(u8)]
25pub enum Origin {
26    /// Lower-left corner.
27    LowerLeft = 1,
28    /// Lower-right corner.
29    LowerRight = 2,
30    /// Upper-left corner.
31    UpperLeft = 3,
32    /// Upper-right corner.
33    UpperRight = 4,
34}
35
36/// The raw-reporting mode of a touch mouse.
37#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, TryFromPrimitive)]
38#[cfg_attr(feature = "serde", derive(serde::Serialize))]
39#[non_exhaustive]
40#[repr(u8)]
41pub enum RawMode {
42    /// Native gestures only (out of the box).
43    NativeGestures = 0,
44    /// Filtered raw data.
45    RawFiltered = 1,
46    /// Unfiltered raw data plus native gestures.
47    RawUnfilteredAndGestures = 2,
48    /// Unfiltered raw data, sent even while lifted or with a button active.
49    RawUnfilteredAlways = 3,
50    /// Like [`RawUnfilteredAndGestures`](Self::RawUnfilteredAndGestures) but with
51    /// Z information in place of width.
52    RawUnfilteredWithZ = 4,
53}
54
55/// Touch-mouse characteristics from
56/// [`get_touchpad_info`](TouchMouseRawFeature::get_touchpad_info).
57#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
58#[cfg_attr(feature = "serde", derive(serde::Serialize))]
59#[non_exhaustive]
60pub struct TouchMouseInfo {
61    /// Maximum X count in dots.
62    pub x_max_count: u16,
63    /// Maximum Y count in dots.
64    pub y_max_count: u16,
65    /// Sensor resolution in DPI (assumed equal for X and Y).
66    pub resolution_dpi: u16,
67    /// Position of the coordinate origin.
68    pub origin: Origin,
69    /// Maximum number of reported fingers.
70    pub max_finger_count: u8,
71    /// Maximum value of the touch-point width/height data.
72    pub width_height_data_range: u8,
73}
74
75impl TouchMouseInfo {
76    fn from_payload(payload: &[u8; 16]) -> Result<Self, Hidpp20Error> {
77        Ok(Self {
78            x_max_count: u16::from_be_bytes([payload[0], payload[1]]),
79            y_max_count: u16::from_be_bytes([payload[2], payload[3]]),
80            resolution_dpi: u16::from_be_bytes([payload[4], payload[5]]),
81            origin: Origin::try_from(payload[6]).map_err(|_| Hidpp20Error::UnsupportedResponse)?,
82            max_finger_count: payload[7],
83            width_height_data_range: payload[8],
84        })
85    }
86}
87
88/// Implements the `TouchMouseRaw` / `0x6110` feature.
89#[derive(Feature)]
90#[creatable(id = 0x6110, version = 0)]
91pub struct TouchMouseRawFeature {
92    /// The endpoint this feature talks to.
93    endpoint: FeatureEndpoint,
94
95    /// Publishes decoded events to listeners.
96    events: EventSource<TouchMouseRawEvent>,
97}
98
99impl TouchMouseRawFeature {
100    /// Retrieves the touch mouse's characteristics.
101    pub async fn get_touchpad_info(&self) -> Result<TouchMouseInfo, Hidpp20Error> {
102        let payload = self.endpoint.call(0, [0; 3]).await?.extend_payload();
103        TouchMouseInfo::from_payload(&payload)
104    }
105
106    /// Retrieves the current raw-reporting mode.
107    pub async fn get_raw_mode(&self) -> Result<RawMode, Hidpp20Error> {
108        let payload = self.endpoint.call(1, [0; 3]).await?.extend_payload();
109        RawMode::try_from(payload[0]).map_err(|_| Hidpp20Error::UnsupportedResponse)
110    }
111
112    /// Sets the raw-reporting mode.
113    ///
114    /// A raw mode must be selected for [`TouchMouseRawEvent::RawData`] events to
115    /// be emitted.
116    pub async fn set_raw_mode(&self, mode: RawMode) -> Result<(), Hidpp20Error> {
117        self.endpoint.call(2, [mode.into(), 0, 0]).await?;
118        Ok(())
119    }
120}