Skip to main content

openlogi_device/write/
pointer_scaling.rs

1//! HID++ `0x2205 PointerMotionScaling` reads and writes.
2
3use std::sync::Arc;
4
5pub use hidpp::feature::pointer_motion_scaling::PointerScaling;
6use hidpp::{
7    channel::HidppChannel, device::Device, feature::CreatableFeature,
8    feature::pointer_motion_scaling::PointerMotionScalingFeature,
9};
10use tracing::debug;
11
12use super::{HidppOperation, WriteError, classify_hidpp_error, open_feature, with_route};
13use crate::backend::HidBackend;
14use crate::channel::route::DeviceRoute;
15
16/// Read the pointer-motion scaling of the device `route` reaches.
17pub async fn get_pointer_scaling(
18    backend: &dyn HidBackend,
19    route: &DeviceRoute,
20) -> Result<PointerScaling, WriteError> {
21    let index = route.device_index();
22    with_route(backend, route, move |channel| async move {
23        let feature = open_scaling_feature(&channel, index).await?;
24        read_scaling(&feature).await
25    })
26    .await
27}
28
29/// Write a pointer-motion scaling and return the value the device reports
30/// afterwards.
31///
32/// The returned read-back is the applied value: the spec lets firmware clip
33/// the request, though some devices store any non-zero value unchanged, so a
34/// caller exposing this to users must bound `scaling` itself.
35pub async fn set_pointer_scaling(
36    backend: &dyn HidBackend,
37    route: &DeviceRoute,
38    scaling: PointerScaling,
39) -> Result<PointerScaling, WriteError> {
40    let index = route.device_index();
41    with_route(backend, route, move |channel| async move {
42        let feature = open_scaling_feature(&channel, index).await?;
43        feature
44            .set_pointer_scaling(scaling)
45            .await
46            .map_err(|error| {
47                classify_hidpp_error(
48                    error,
49                    HidppOperation::WritePointerScaling,
50                    PointerMotionScalingFeature::ID,
51                )
52            })?;
53        let applied = read_scaling(&feature).await?;
54        debug!(
55            index,
56            requested = scaling.raw(),
57            applied = applied.raw(),
58            "pointer scaling written"
59        );
60        Ok(applied)
61    })
62    .await
63}
64
65async fn open_scaling_feature(
66    channel: &Arc<HidppChannel>,
67    index: u8,
68) -> Result<Arc<PointerMotionScalingFeature>, WriteError> {
69    let mut device = Device::new(Arc::clone(channel), index)
70        .await
71        .map_err(|_| WriteError::DeviceUnreachable { index })?;
72    open_feature::<PointerMotionScalingFeature>(&mut device).await
73}
74
75async fn read_scaling(feature: &PointerMotionScalingFeature) -> Result<PointerScaling, WriteError> {
76    feature.get_pointer_scaling().await.map_err(|error| {
77        classify_hidpp_error(
78            error,
79            HidppOperation::ReadPointerScaling,
80            PointerMotionScalingFeature::ID,
81        )
82    })
83}