Skip to main content

hidpp/feature/
smartshift.rs

1//! Implements the `SmartShift` feature (ID `0x2110`) that allows controlling a
2//! smart shift enhanced scroll wheel.
3
4use std::hash::Hash;
5
6use num_enum::{IntoPrimitive, TryFromPrimitive};
7use openlogi_hidpp_derive::Feature;
8
9use crate::{feature::FeatureEndpoint, protocol::v20::Hidpp20Error};
10
11/// Implements the `SmartShift` / `0x2110` feature.
12#[derive(Feature)]
13#[creatable(id = 0x2110, version = 0)]
14pub struct SmartShiftFeature {
15    /// The endpoint this feature talks to.
16    endpoint: FeatureEndpoint,
17}
18
19impl SmartShiftFeature {
20    /// Retrieves the current ratchet control mode.
21    ///
22    /// [`RatchetControlMode::wheel_mode`] will only reflect the value set
23    /// either by software or the wheel mode button. It will not provide
24    /// information about whether the wheel is in auto-disengaged mode.
25    pub async fn get_ratchet_control_mode(&self) -> Result<RatchetControlMode, Hidpp20Error> {
26        let payload = self.endpoint.call(0, [0; 3]).await?.extend_payload();
27
28        Ok(RatchetControlMode {
29            wheel_mode: WheelMode::try_from(payload[0])
30                .map_err(|_| Hidpp20Error::UnsupportedResponse)?,
31            auto_disengage: payload[1],
32            auto_disengage_default: payload[2],
33        })
34    }
35
36    /// Sets the ratchet control mode.
37    ///
38    /// For `auto_disengage` (and `auto_disengage_default` respectively), the
39    /// values `0x01..=0xfe` correspond to the amount of quarter-turns the wheel
40    /// has to make per second for the wheel to disengage.
41    /// `0xff` enables permanent ratchet mode.
42    ///
43    /// All values are optional and will stay as they are if provided with
44    /// [`None`].
45    ///
46    /// For `auto_disengage` and `auto_disengange_default`, `0` will have the
47    /// same effect as [`None`].
48    pub async fn set_ratchet_control_mode(
49        &self,
50        wheel_mode: Option<WheelMode>,
51        auto_disengage: Option<u8>,
52        auto_disengage_default: Option<u8>,
53    ) -> Result<(), Hidpp20Error> {
54        self.endpoint
55            .call(
56                1,
57                [
58                    wheel_mode.map_or(0, u8::from),
59                    auto_disengage.unwrap_or(0),
60                    auto_disengage_default.unwrap_or(0),
61                ],
62            )
63            .await?;
64
65        Ok(())
66    }
67}
68
69/// Represents the ratchet control mode of the mouse wheel.
70#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
71#[cfg_attr(feature = "serde", derive(serde::Serialize))]
72#[non_exhaustive]
73pub struct RatchetControlMode {
74    /// The mode the wheel is currently set to.
75    ///
76    /// This does not reflect the automatic disengage state.
77    pub wheel_mode: WheelMode,
78
79    /// The amount of quarter-turns per second it takes for the wheel to
80    /// automatically disengage.
81    ///
82    /// If this value is `0xff`, the wheel will not disengage automatically.
83    pub auto_disengage: u8,
84
85    /// The default value of [`Self::auto_disengage`].
86    pub auto_disengage_default: u8,
87}
88
89/// Represents the ratchet mode of the scroll wheel.
90#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, TryFromPrimitive)]
91#[cfg_attr(feature = "serde", derive(serde::Serialize))]
92#[non_exhaustive]
93#[repr(u8)]
94pub enum WheelMode {
95    /// Free-spin wheel mode.
96    Freespin = 1,
97    /// Ratchet wheel mode.
98    Ratchet = 2,
99}