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;