pub mod event;
#[cfg(test)]
mod tests;
use std::sync::Arc;
use num_enum::{IntoPrimitive, TryFromPrimitive};
pub use event::{TouchMousePoint, TouchMouseRawEvent, TouchMouseStatus};
use crate::{
channel::{HidppChannel, MessageListenerGuard},
event::EventEmitter,
feature::{CreatableFeature, EmittingFeature, Feature, FeatureEndpoint, event_payload},
protocol::v20::Hidpp20Error,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, TryFromPrimitive)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
#[repr(u8)]
pub enum Origin {
LowerLeft = 1,
LowerRight = 2,
UpperLeft = 3,
UpperRight = 4,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, TryFromPrimitive)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
#[repr(u8)]
pub enum RawMode {
NativeGestures = 0,
RawFiltered = 1,
RawUnfilteredAndGestures = 2,
RawUnfilteredAlways = 3,
RawUnfilteredWithZ = 4,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct TouchMouseInfo {
pub x_max_count: u16,
pub y_max_count: u16,
pub resolution_dpi: u16,
pub origin: Origin,
pub max_finger_count: u8,
pub width_height_data_range: u8,
}
impl TouchMouseInfo {
fn from_payload(payload: &[u8; 16]) -> Result<Self, Hidpp20Error> {
Ok(Self {
x_max_count: u16::from_be_bytes([payload[0], payload[1]]),
y_max_count: u16::from_be_bytes([payload[2], payload[3]]),
resolution_dpi: u16::from_be_bytes([payload[4], payload[5]]),
origin: Origin::try_from(payload[6]).map_err(|_| Hidpp20Error::UnsupportedResponse)?,
max_finger_count: payload[7],
width_height_data_range: payload[8],
})
}
}
pub struct TouchMouseRawFeature {
endpoint: FeatureEndpoint,
emitter: Arc<EventEmitter<TouchMouseRawEvent>>,
_msg_listener: MessageListenerGuard,
}
impl CreatableFeature for TouchMouseRawFeature {
const ID: u16 = 0x6110;
const STARTING_VERSION: u8 = 0;
fn new(chan: Arc<HidppChannel>, device_index: u8, feature_index: u8) -> Self {
let emitter = Arc::new(EventEmitter::new());
let listener = chan.add_msg_listener_guarded({
let emitter = Arc::clone(&emitter);
move |raw, matched| {
let Some((func, payload)) =
event_payload(raw, matched, device_index, feature_index)
else {
return;
};
if let Some(event) = event::decode_event(func.to_lo(), &payload) {
emitter.emit(event);
}
}
});
Self {
endpoint: FeatureEndpoint::new(chan, device_index, feature_index),
emitter,
_msg_listener: listener,
}
}
}
impl Feature for TouchMouseRawFeature {}
impl EmittingFeature<TouchMouseRawEvent> for TouchMouseRawFeature {
fn listen(&self) -> async_channel::Receiver<TouchMouseRawEvent> {
self.emitter.create_receiver()
}
}
impl TouchMouseRawFeature {
pub async fn get_touchpad_info(&self) -> Result<TouchMouseInfo, Hidpp20Error> {
let payload = self.endpoint.call(0, [0; 3]).await?.extend_payload();
TouchMouseInfo::from_payload(&payload)
}
pub async fn get_raw_mode(&self) -> Result<RawMode, Hidpp20Error> {
let payload = self.endpoint.call(1, [0; 3]).await?.extend_payload();
RawMode::try_from(payload[0]).map_err(|_| Hidpp20Error::UnsupportedResponse)
}
pub async fn set_raw_mode(&self, mode: RawMode) -> Result<(), Hidpp20Error> {
self.endpoint.call(2, [mode.into(), 0, 0]).await?;
Ok(())
}
}