Skip to main content

hidpp/feature/
touchpad_raw_xy.rs

1//! Implements the `TouchpadRawXy` feature (ID `0x6100`) that exposes a
2//! touchpad's raw multi-touch data: pad characteristics, the raw-report mode,
3//! and a per-frame [`DualXyData`] event.
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::{DualXyData, TouchPoint, TouchpadRawEvent};
14
15use crate::{
16    feature::{EventSource, FeatureEndpoint},
17    protocol::v20::Hidpp20Error,
18};
19
20bitflags::bitflags! {
21    /// Raw-report mode flags from
22    /// [`get_raw_report_state`](TouchpadRawXyFeature::get_raw_report_state).
23    ///
24    /// Some combinations are mutually exclusive; common valid bitmaps are `0x00`
25    /// (off), `0x05`, `0x09`, `0x21` and `0x41` (see the feature spec).
26    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
27    #[cfg_attr(feature = "serde", derive(serde::Serialize))]
28    pub struct RawReportFlags: u8 {
29        /// Raw reporting enabled.
30        const RAW = 1 << 0;
31        /// Add force data to 16-bit reporting (deprecated).
32        const FORCE_ADD = 1 << 1;
33        /// Enhanced reporting enabled.
34        const ENHANCED = 1 << 2;
35        /// Report width/height instead of area.
36        const WIDTH_HEIGHT = 1 << 3;
37        /// Report native gestures.
38        const NATIVE_GESTURE = 1 << 4;
39        /// Report major/minor/orientation.
40        const MAJOR_MINOR = 1 << 5;
41        /// Report 8-bit width and height bytes instead of area.
42        const WIDTH_HEIGHT_8BIT = 1 << 6;
43    }
44}
45
46/// The position of a touchpad's coordinate origin, viewed from above.
47#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, TryFromPrimitive)]
48#[cfg_attr(feature = "serde", derive(serde::Serialize))]
49#[non_exhaustive]
50#[repr(u8)]
51pub enum Origin {
52    /// Lower-left corner.
53    LowerLeft = 1,
54    /// Lower-right corner.
55    LowerRight = 2,
56    /// Upper-left corner.
57    UpperLeft = 3,
58    /// Upper-right corner.
59    UpperRight = 4,
60}
61
62/// Touchpad characteristics from
63/// [`get_touchpad_info`](TouchpadRawXyFeature::get_touchpad_info).
64#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
65#[cfg_attr(feature = "serde", derive(serde::Serialize))]
66#[non_exhaustive]
67pub struct TouchpadInfo {
68    /// Pad width in native coordinate units.
69    pub x_size: u16,
70    /// Pad height in native coordinate units.
71    pub y_size: u16,
72    /// Z-data range (`0x00` = none, `0x0f` = 16-bit).
73    pub z_data_range: u8,
74    /// Area-data range (`0x0f` = 16-bit).
75    pub area_data_range: u8,
76    /// Timestamp increment, in units of 0.1 ms.
77    pub timestamp_units: u8,
78    /// Maximum number of fingers that can be tracked.
79    pub max_finger_count: u8,
80    /// Position of the coordinate origin.
81    pub origin: Origin,
82    /// Whether pen input is supported.
83    pub pen_support: bool,
84    /// Raw-report mapping version.
85    pub raw_report_mapping_version: u8,
86    /// Native sensor DPI.
87    pub dpi: u16,
88}
89
90impl TouchpadInfo {
91    fn from_payload(payload: &[u8; 16]) -> Result<Self, Hidpp20Error> {
92        Ok(Self {
93            x_size: u16::from_be_bytes([payload[0], payload[1]]),
94            y_size: u16::from_be_bytes([payload[2], payload[3]]),
95            z_data_range: payload[4],
96            area_data_range: payload[5],
97            timestamp_units: payload[6],
98            max_finger_count: payload[7],
99            origin: Origin::try_from(payload[8]).map_err(|_| Hidpp20Error::UnsupportedResponse)?,
100            pen_support: payload[9] != 0,
101            raw_report_mapping_version: payload[12],
102            dpi: u16::from_be_bytes([payload[13], payload[14]]),
103        })
104    }
105}
106
107/// Implements the `TouchpadRawXy` / `0x6100` feature.
108#[derive(Feature)]
109#[creatable(id = 0x6100, version = 0)]
110pub struct TouchpadRawXyFeature {
111    /// The endpoint this feature talks to.
112    endpoint: FeatureEndpoint,
113
114    /// Publishes decoded events to listeners.
115    events: EventSource<TouchpadRawEvent>,
116}
117
118impl TouchpadRawXyFeature {
119    /// Retrieves the touchpad's characteristics.
120    pub async fn get_touchpad_info(&self) -> Result<TouchpadInfo, Hidpp20Error> {
121        let payload = self.endpoint.call(0, [0; 3]).await?.extend_payload();
122        TouchpadInfo::from_payload(&payload)
123    }
124
125    /// Retrieves the current raw-report mode.
126    pub async fn get_raw_report_state(&self) -> Result<RawReportFlags, Hidpp20Error> {
127        let payload = self.endpoint.call(1, [0; 3]).await?.extend_payload();
128        Ok(RawReportFlags::from_bits_retain(payload[0]))
129    }
130
131    /// Sets the raw-report mode.
132    ///
133    /// Enable [`RawReportFlags::RAW`] for [`TouchpadRawEvent`]s to be emitted.
134    pub async fn set_raw_report_state(&self, flags: RawReportFlags) -> Result<(), Hidpp20Error> {
135        self.endpoint.call(2, [flags.bits(), 0, 0]).await?;
136        Ok(())
137    }
138}