1use super::{EvDevDeviceHandler, EvDevDeviceInfo, EvDevRawEvent};
9use crate::native_unsafe_methods::{abs_axis, axis_event_code, ev_key, ev_type, input_absinfo, input_event};
10use ferroui_base::input::raw::RawPointerEventType;
11use ferroui_base::input::RawInputModifiers;
12use ferroui_base::{Point, Size, Vector};
13
14#[derive(Clone, Debug, Default, PartialEq)]
16pub struct EvDevMouseDeviceDescription {
17 pub path: Option<String>,
18}
19
20pub struct EvDevMouse {
21 axis_x: Option<input_absinfo>,
22 axis_y: Option<input_absinfo>,
23 position: Point,
25 abs_x: i32,
26 abs_y: i32,
27 has_relative_movement: bool,
28 has_absolute_movement: bool,
29 buttons: Vec<(u16, bool)>,
31 wheel: Vector,
32 modifiers: RawInputModifiers,
33}
34
35impl EvDevMouse {
36 pub fn new(device: &EvDevDeviceInfo) -> Self {
37 Self {
38 axis_x: device.abs_x(),
39 axis_y: device.abs_y(),
40 position: Point::default(),
41 abs_x: 0,
42 abs_y: 0,
43 has_relative_movement: false,
44 has_absolute_movement: false,
45 buttons: Vec::new(),
46 wheel: Vector::default(),
47 modifiers: RawInputModifiers::empty(),
48 }
49 }
50
51 fn scale(value: i32, axis: &input_absinfo, size: f64) -> f64 {
52 let range = (axis.maximum - axis.minimum) as f64;
53 if range <= 0.0 {
54 return 0.0;
55 }
56 (value - axis.minimum) as f64 * size / range
57 }
58}
59
60impl EvDevDeviceHandler for EvDevMouse {
61 fn handle_event(&mut self, ev: &input_event, screen_size: Size, out: &mut Vec<EvDevRawEvent>) {
62 match ev.type_ {
63 ev_type::EV_REL => match ev.code {
64 axis_event_code::REL_X => {
65 self.position = Point::new(self.position.x + ev.value as f64, self.position.y);
66 self.has_relative_movement = true;
67 }
68 axis_event_code::REL_Y => {
69 self.position = Point::new(self.position.x, self.position.y + ev.value as f64);
70 self.has_relative_movement = true;
71 }
72 axis_event_code::REL_WHEEL => self.wheel = Vector::new(self.wheel.x, self.wheel.y + ev.value as f64),
75 axis_event_code::REL_HWHEEL => self.wheel = Vector::new(self.wheel.x - ev.value as f64, self.wheel.y),
76 _ => {}
77 },
78 ev_type::EV_ABS => match ev.code {
79 abs_axis::ABS_X => {
80 self.abs_x = ev.value;
81 self.has_absolute_movement = true;
82 }
83 abs_axis::ABS_Y => {
84 self.abs_y = ev.value;
85 self.has_absolute_movement = true;
86 }
87 _ => {}
88 },
89 ev_type::EV_KEY => {
90 if matches!(ev.code, ev_key::BTN_LEFT | ev_key::BTN_RIGHT | ev_key::BTN_MIDDLE) && ev.value != 2 {
91 self.buttons.push((ev.code, ev.value != 0));
92 }
93 }
94 ev_type::EV_SYN => {
95 let timestamp = ev.timestamp();
96 if self.has_absolute_movement {
97 if let (Some(axis_x), Some(axis_y)) = (&self.axis_x, &self.axis_y) {
98 self.position = Point::new(
99 Self::scale(self.abs_x, axis_x, screen_size.width),
100 Self::scale(self.abs_y, axis_y, screen_size.height),
101 );
102 }
103 }
104 if self.has_relative_movement {
105 self.position = Point::new(
107 self.position.x.clamp(0.0, (screen_size.width - 1.0).max(0.0)),
108 self.position.y.clamp(0.0, (screen_size.height - 1.0).max(0.0)),
109 );
110 }
111 if self.has_relative_movement || self.has_absolute_movement {
112 out.push(EvDevRawEvent::Pointer {
113 type_: RawPointerEventType::Move,
114 timestamp,
115 position: self.position,
116 modifiers: self.modifiers,
117 });
118 }
119 for (button, down) in std::mem::take(&mut self.buttons) {
120 let (flag, pressed, released) = match button {
121 ev_key::BTN_LEFT => (
122 RawInputModifiers::LEFT_MOUSE_BUTTON,
123 RawPointerEventType::LeftButtonDown,
124 RawPointerEventType::LeftButtonUp,
125 ),
126 ev_key::BTN_RIGHT => (
127 RawInputModifiers::RIGHT_MOUSE_BUTTON,
128 RawPointerEventType::RightButtonDown,
129 RawPointerEventType::RightButtonUp,
130 ),
131 _ => (
132 RawInputModifiers::MIDDLE_MOUSE_BUTTON,
133 RawPointerEventType::MiddleButtonDown,
134 RawPointerEventType::MiddleButtonUp,
135 ),
136 };
137 self.modifiers.set(flag, down);
138 out.push(EvDevRawEvent::Pointer {
139 type_: if down { pressed } else { released },
140 timestamp,
141 position: self.position,
142 modifiers: self.modifiers,
143 });
144 }
145 if self.wheel != Vector::default() {
146 out.push(EvDevRawEvent::Wheel {
147 timestamp,
148 position: self.position,
149 delta: self.wheel,
150 modifiers: self.modifiers,
151 });
152 }
153 self.has_relative_movement = false;
154 self.has_absolute_movement = false;
155 self.wheel = Vector::default();
156 }
157 _ => {}
158 }
159 }
160
161 fn reset(&mut self, timestamp: u64, _screen_size: Size, out: &mut Vec<EvDevRawEvent>) {
162 for (flag, released) in [
164 (RawInputModifiers::LEFT_MOUSE_BUTTON, RawPointerEventType::LeftButtonUp),
165 (RawInputModifiers::RIGHT_MOUSE_BUTTON, RawPointerEventType::RightButtonUp),
166 (RawInputModifiers::MIDDLE_MOUSE_BUTTON, RawPointerEventType::MiddleButtonUp),
167 ] {
168 if self.modifiers.contains(flag) {
169 self.modifiers.remove(flag);
170 out.push(EvDevRawEvent::Pointer {
171 type_: released,
172 timestamp,
173 position: self.position,
174 modifiers: self.modifiers,
175 });
176 }
177 }
178 self.buttons.clear();
179 self.wheel = Vector::default();
180 self.has_relative_movement = false;
181 self.has_absolute_movement = false;
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::super::ev_dev_touch_screen::tests::{ev, info, run, syn};
188 use super::*;
189 use crate::native_unsafe_methods::syn_code;
190
191 fn pointer(
192 type_: RawPointerEventType,
193 timestamp: u64,
194 x: f64,
195 y: f64,
196 modifiers: RawInputModifiers,
197 ) -> EvDevRawEvent {
198 EvDevRawEvent::Pointer { type_, timestamp, position: Point::new(x, y), modifiers }
199 }
200
201 #[test]
202 fn relative_motion_accumulates_and_stays_on_the_screen() {
203 let mut mouse = EvDevMouse::new(&info(&[]));
204 let screen = Size::new(100.0, 50.0);
205 let none = RawInputModifiers::empty();
206 let events = [
207 ev(1, ev_type::EV_REL, axis_event_code::REL_X, 30),
208 ev(1, ev_type::EV_REL, axis_event_code::REL_Y, 20),
209 syn(1),
210 ev(2, ev_type::EV_REL, axis_event_code::REL_X, 500),
211 syn(2),
212 ev(3, ev_type::EV_REL, axis_event_code::REL_X, -10),
213 ev(3, ev_type::EV_REL, axis_event_code::REL_Y, -100),
214 syn(3),
215 ];
216 assert_eq!(
217 run(&mut mouse, &events, screen),
218 [
219 pointer(RawPointerEventType::Move, 1, 30.0, 20.0, none),
220 pointer(RawPointerEventType::Move, 2, 99.0, 20.0, none),
221 pointer(RawPointerEventType::Move, 3, 89.0, 0.0, none),
222 ]
223 );
224 }
225
226 #[test]
227 fn buttons_follow_the_move_of_their_report_and_are_modifiers_while_held() {
228 let mut mouse = EvDevMouse::new(&info(&[]));
229 let screen = Size::new(100.0, 100.0);
230 let left = RawInputModifiers::LEFT_MOUSE_BUTTON;
231 let right = RawInputModifiers::RIGHT_MOUSE_BUTTON;
232 let events = [
233 ev(1, ev_type::EV_KEY, ev_key::BTN_LEFT, 1),
234 ev(1, ev_type::EV_REL, axis_event_code::REL_X, 5),
235 syn(1),
236 ev(2, ev_type::EV_KEY, ev_key::BTN_RIGHT, 1),
237 syn(2),
238 ev(3, ev_type::EV_KEY, ev_key::BTN_RIGHT, 0),
239 ev(3, ev_type::EV_KEY, ev_key::BTN_LEFT, 0),
240 syn(3),
241 ev(4, ev_type::EV_KEY, ev_key::BTN_MIDDLE, 1),
242 syn(4),
243 ];
244 assert_eq!(
245 run(&mut mouse, &events, screen),
246 [
247 pointer(RawPointerEventType::Move, 1, 5.0, 0.0, RawInputModifiers::empty()),
248 pointer(RawPointerEventType::LeftButtonDown, 1, 5.0, 0.0, left),
249 pointer(RawPointerEventType::RightButtonDown, 2, 5.0, 0.0, left | right),
250 pointer(RawPointerEventType::RightButtonUp, 3, 5.0, 0.0, left),
251 pointer(RawPointerEventType::LeftButtonUp, 3, 5.0, 0.0, RawInputModifiers::empty()),
252 pointer(RawPointerEventType::MiddleButtonDown, 4, 5.0, 0.0, RawInputModifiers::MIDDLE_MOUSE_BUTTON),
253 ]
254 );
255 }
256
257 #[test]
258 fn the_wheel_is_a_delta_at_the_position() {
259 let mut mouse = EvDevMouse::new(&info(&[]));
260 let events = [
261 ev(1, ev_type::EV_REL, axis_event_code::REL_WHEEL, -1),
262 syn(1),
263 ev(2, ev_type::EV_REL, axis_event_code::REL_HWHEEL, 2),
264 syn(2),
265 ];
266 let wheel = |timestamp, x, y| EvDevRawEvent::Wheel {
267 timestamp,
268 position: Point::default(),
269 delta: Vector::new(x, y),
270 modifiers: RawInputModifiers::empty(),
271 };
272 assert_eq!(run(&mut mouse, &events, Size::new(10.0, 10.0)), [wheel(1, 0.0, -1.0), wheel(2, -2.0, 0.0)]);
273 }
274
275 #[test]
276 fn an_absolute_pointer_is_scaled_to_the_screen() {
277 let mut mouse = EvDevMouse::new(&info(&[(abs_axis::ABS_X, 0, 32767), (abs_axis::ABS_Y, 0, 32767)]));
279 let events = [
280 ev(1, ev_type::EV_ABS, abs_axis::ABS_X, 32767),
281 ev(1, ev_type::EV_ABS, abs_axis::ABS_Y, 0),
282 ev(1, ev_type::EV_KEY, ev_key::BTN_LEFT, 1),
283 syn(1),
284 ];
285 let left = RawInputModifiers::LEFT_MOUSE_BUTTON;
286 assert_eq!(
287 run(&mut mouse, &events, Size::new(1024.0, 768.0)),
288 [
289 pointer(RawPointerEventType::Move, 1, 1024.0, 0.0, RawInputModifiers::empty()),
290 pointer(RawPointerEventType::LeftButtonDown, 1, 1024.0, 0.0, left),
291 ]
292 );
293 }
294
295 #[test]
296 fn dropped_events_release_the_held_buttons() {
297 let mut mouse = EvDevMouse::new(&info(&[]));
298 let events = [
299 ev(1, ev_type::EV_KEY, ev_key::BTN_LEFT, 1),
300 syn(1),
301 ev(2, ev_type::EV_SYN, syn_code::SYN_DROPPED, 0),
302 ev(2, ev_type::EV_REL, axis_event_code::REL_X, 5),
303 syn(2),
304 ];
305 let out = run(&mut mouse, &events, Size::new(10.0, 10.0));
306 assert_eq!(out[1], pointer(RawPointerEventType::LeftButtonUp, 2, 0.0, 0.0, RawInputModifiers::empty()));
307 assert_eq!(out.len(), 2);
308 }
309}