Skip to main content

rpk_common/
mouse.rs

1use core::cell::RefCell;
2
3use crate::{f32_from_u16, math::cubic_bezier};
4
5#[derive(Debug, Clone, Copy)]
6pub struct MouseConfig {
7    pub movement: MouseAnalogSetting,
8    pub scroll: MouseAnalogSetting,
9}
10impl Default for MouseConfig {
11    fn default() -> Self {
12        MouseConfig::normal()
13    }
14}
15impl MouseConfig {
16    pub const fn slow() -> Self {
17        Self {
18            movement: MouseAnalogSetting {
19                curve: (0.1, 0.5),
20                max_time: 1_000.0,
21                min_ticks_per_ms: 0.02,
22                max_ticks_per_ms: 1.0,
23            },
24            scroll: MouseAnalogSetting {
25                curve: (0.0, 0.0),
26                max_time: 5_000.0,
27                min_ticks_per_ms: 0.01,
28                max_ticks_per_ms: 0.25,
29            },
30        }
31    }
32    pub const fn normal() -> Self {
33        Self {
34            movement: MouseAnalogSetting {
35                curve: (0.1, 0.5),
36                max_time: 1_000.0,
37                min_ticks_per_ms: 0.02,
38                max_ticks_per_ms: 3.0,
39            },
40            scroll: MouseAnalogSetting {
41                curve: (0.0, 0.0),
42                max_time: 5_000.0,
43                min_ticks_per_ms: 0.01,
44                max_ticks_per_ms: 0.5,
45            },
46        }
47    }
48    pub const fn fast() -> Self {
49        Self {
50            movement: MouseAnalogSetting {
51                curve: (0.1, 0.5),
52                max_time: 1_000.0,
53                min_ticks_per_ms: 0.02,
54                max_ticks_per_ms: 5.0,
55            },
56            scroll: MouseAnalogSetting {
57                curve: (0.0, 0.0),
58                max_time: 5_000.0,
59                min_ticks_per_ms: 0.01,
60                max_ticks_per_ms: 1.0,
61            },
62        }
63    }
64    pub fn input(&self, i: usize) -> &MouseAnalogSetting {
65        if i < 2 {
66            &self.movement
67        } else {
68            &self.scroll
69        }
70    }
71}
72
73#[derive(Debug, Clone, Copy)]
74pub struct MouseAnalogSetting {
75    pub curve: (f32, f32),
76    pub max_time: f32,
77    pub min_ticks_per_ms: f32,
78    pub max_ticks_per_ms: f32,
79}
80impl MouseAnalogSetting {
81    pub fn deserialize(bin: &mut impl Iterator<Item = u16>) -> Option<MouseAnalogSetting> {
82        Some(MouseAnalogSetting {
83            curve: (
84                f32_from_u16(bin.next()?, bin.next()?),
85                f32_from_u16(bin.next()?, bin.next()?),
86            ),
87            max_time: f32_from_u16(bin.next()?, bin.next()?),
88            min_ticks_per_ms: f32_from_u16(bin.next()?, bin.next()?),
89            max_ticks_per_ms: f32_from_u16(bin.next()?, bin.next()?),
90        })
91    }
92
93    pub fn mouse_delta(&self, time_since_last_report: f32, now: u32, k: &MouseMove) -> i8 {
94        if k.start == 0 {
95            return 0;
96        }
97        let mut guard = k.fraction.borrow_mut();
98        let r = self.t2rate(time_since_last_report, now, k.start) + *guard;
99        let ticks = r as i8;
100        *guard = r - ticks as f32;
101        ticks * k.delta
102    }
103
104    fn t2rate(&self, period: f32, now: u32, then: u32) -> f32 {
105        let t = now - then;
106        let (c0, c1) = self.curve;
107        let t = min(t as f32, self.max_time) / self.max_time;
108        min(
109            (self.min_ticks_per_ms + self.max_ticks_per_ms * cubic_bezier(t, c0, c1)) * period,
110            127.0,
111        )
112    }
113}
114
115#[derive(Default)]
116pub struct MouseMove {
117    pub start: u32,
118    pub fraction: RefCell<f32>,
119    pub delta: i8,
120}
121impl MouseMove {
122    pub fn action(&mut self, is_down: bool, delta: i8) {
123        if is_down {
124            if self.start == 0 || delta != self.delta {
125                self.delta = delta;
126            }
127        } else if self.start != 0 && delta == self.delta {
128            self.start = 0;
129        }
130    }
131}
132
133fn min(a: f32, b: f32) -> f32 {
134    if a < b {
135        a
136    } else {
137        b
138    }
139}
140
141#[cfg(test)]
142#[path = "mouse_test.rs"]
143mod test;