1use crate::coordinates::CoordinateTransformer;
7use crate::error::Result;
8use std::time::Instant;
9use tracing::debug;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub enum MouseButton {
14 Left,
16 Right,
18 Middle,
20 Extra1,
22 Extra2,
24}
25
26impl MouseButton {
27 pub fn to_linux_button(&self) -> u32 {
29 match self {
30 MouseButton::Left => 0x110, MouseButton::Right => 0x111, MouseButton::Middle => 0x112, MouseButton::Extra1 => 0x113, MouseButton::Extra2 => 0x114, }
36 }
37
38 pub fn from_rdp_button(button: u16) -> Option<Self> {
40 match button {
41 0x1000 => Some(MouseButton::Left),
42 0x2000 => Some(MouseButton::Right),
43 0x4000 => Some(MouseButton::Middle),
44 0x0080 => Some(MouseButton::Extra1),
45 0x0100 => Some(MouseButton::Extra2),
46 _ => None,
47 }
48 }
49}
50
51#[derive(Debug, Clone)]
53pub enum MouseEvent {
54 Move {
56 x: f64,
58 y: f64,
60 timestamp: Instant,
62 },
63
64 ButtonDown {
66 button: MouseButton,
68 position: Option<(f64, f64)>,
72 timestamp: Instant,
74 },
75
76 ButtonUp {
78 button: MouseButton,
80 position: Option<(f64, f64)>,
82 timestamp: Instant,
84 },
85
86 Scroll {
88 delta_x: i32,
90 delta_y: i32,
92 timestamp: Instant,
94 },
95}
96
97pub struct MouseHandler {
99 current_x: f64,
101 current_y: f64,
102
103 button_states: [bool; 5],
105
106 last_event_time: Option<Instant>,
108
109 high_precision_scroll: bool,
111
112 scroll_accum_x: f64,
114 scroll_accum_y: f64,
115}
116
117impl MouseHandler {
118 pub fn new() -> Self {
120 Self {
121 current_x: 0.0,
122 current_y: 0.0,
123 button_states: [false; 5],
124 last_event_time: None,
125 high_precision_scroll: true,
126 scroll_accum_x: 0.0,
127 scroll_accum_y: 0.0,
128 }
129 }
130
131 pub fn handle_absolute_move(
133 &mut self,
134 rdp_x: u32,
135 rdp_y: u32,
136 transformer: &mut CoordinateTransformer,
137 ) -> Result<MouseEvent> {
138 let (stream_x, stream_y) = transformer.rdp_to_stream(rdp_x as i32, rdp_y as i32)?;
139
140 let (stream_x, stream_y) = transformer.clamp_to_bounds(stream_x, stream_y);
142
143 self.current_x = stream_x;
144 self.current_y = stream_y;
145
146 let timestamp = Instant::now();
147 self.last_event_time = Some(timestamp);
148
149 debug!(
150 "Mouse move: RDP({}, {}) -> Stream({:.2}, {:.2})",
151 rdp_x, rdp_y, stream_x, stream_y
152 );
153
154 Ok(MouseEvent::Move {
155 x: stream_x,
156 y: stream_y,
157 timestamp,
158 })
159 }
160
161 pub fn handle_relative_move(
163 &mut self,
164 delta_x: i32,
165 delta_y: i32,
166 transformer: &mut CoordinateTransformer,
167 ) -> Result<MouseEvent> {
168 let (stream_x, stream_y) = transformer.apply_relative_movement(delta_x, delta_y)?;
169
170 let (stream_x, stream_y) = transformer.clamp_to_bounds(stream_x, stream_y);
172
173 self.current_x = stream_x;
174 self.current_y = stream_y;
175
176 let timestamp = Instant::now();
177 self.last_event_time = Some(timestamp);
178
179 debug!(
180 "Mouse relative move: Delta({}, {}) -> Stream({:.2}, {:.2})",
181 delta_x, delta_y, stream_x, stream_y
182 );
183
184 Ok(MouseEvent::Move {
185 x: stream_x,
186 y: stream_y,
187 timestamp,
188 })
189 }
190
191 pub fn handle_button_down(
202 &mut self,
203 button: MouseButton,
204 position: Option<(u32, u32)>,
205 transformer: &mut CoordinateTransformer,
206 ) -> Result<MouseEvent> {
207 let stream_position = self.apply_button_position(position, transformer)?;
208
209 let button_index = Self::button_to_index(button);
210 self.button_states[button_index] = true;
211
212 let timestamp = Instant::now();
213 self.last_event_time = Some(timestamp);
214
215 debug!("Mouse button down: {:?} at {:?}", button, stream_position);
216
217 Ok(MouseEvent::ButtonDown {
218 button,
219 position: stream_position,
220 timestamp,
221 })
222 }
223
224 pub fn handle_button_up(
227 &mut self,
228 button: MouseButton,
229 position: Option<(u32, u32)>,
230 transformer: &mut CoordinateTransformer,
231 ) -> Result<MouseEvent> {
232 let stream_position = self.apply_button_position(position, transformer)?;
233
234 let button_index = Self::button_to_index(button);
235 self.button_states[button_index] = false;
236
237 let timestamp = Instant::now();
238 self.last_event_time = Some(timestamp);
239
240 debug!("Mouse button up: {:?} at {:?}", button, stream_position);
241
242 Ok(MouseEvent::ButtonUp {
243 button,
244 position: stream_position,
245 timestamp,
246 })
247 }
248
249 fn apply_button_position(
255 &mut self,
256 position: Option<(u32, u32)>,
257 transformer: &mut CoordinateTransformer,
258 ) -> Result<Option<(f64, f64)>> {
259 let Some((rdp_x, rdp_y)) = position else {
260 return Ok(None);
261 };
262
263 let (stream_x, stream_y) = transformer.rdp_to_stream(rdp_x as i32, rdp_y as i32)?;
264 let (stream_x, stream_y) = transformer.clamp_to_bounds(stream_x, stream_y);
265
266 self.current_x = stream_x;
267 self.current_y = stream_y;
268
269 Ok(Some((stream_x, stream_y)))
270 }
271
272 pub fn handle_scroll(&mut self, delta_x: i32, delta_y: i32) -> Result<MouseEvent> {
274 let timestamp = Instant::now();
275 self.last_event_time = Some(timestamp);
276
277 let (final_delta_x, final_delta_y) = if self.high_precision_scroll {
278 self.scroll_accum_x += delta_x as f64 / 120.0;
280 self.scroll_accum_y += delta_y as f64 / 120.0;
281
282 let x = self.scroll_accum_x.trunc() as i32;
283 let y = self.scroll_accum_y.trunc() as i32;
284
285 self.scroll_accum_x -= x as f64;
286 self.scroll_accum_y -= y as f64;
287
288 (x, y)
289 } else {
290 (delta_x / 120, delta_y / 120)
292 };
293
294 debug!("Mouse scroll: ({}, {})", final_delta_x, final_delta_y);
295
296 Ok(MouseEvent::Scroll {
297 delta_x: final_delta_x,
298 delta_y: final_delta_y,
299 timestamp,
300 })
301 }
302
303 pub fn current_position(&self) -> (f64, f64) {
305 (self.current_x, self.current_y)
306 }
307
308 pub fn is_button_pressed(&self, button: MouseButton) -> bool {
310 let index = Self::button_to_index(button);
311 self.button_states[index]
312 }
313
314 pub fn time_since_last_event(&self) -> Option<std::time::Duration> {
316 self.last_event_time.map(|t| t.elapsed())
317 }
318
319 pub fn set_high_precision_scroll(&mut self, enabled: bool) {
321 self.high_precision_scroll = enabled;
322 if !enabled {
323 self.scroll_accum_x = 0.0;
324 self.scroll_accum_y = 0.0;
325 }
326 }
327
328 fn button_to_index(button: MouseButton) -> usize {
330 match button {
331 MouseButton::Left => 0,
332 MouseButton::Right => 1,
333 MouseButton::Middle => 2,
334 MouseButton::Extra1 => 3,
335 MouseButton::Extra2 => 4,
336 }
337 }
338
339 pub fn reset(&mut self) {
341 self.button_states = [false; 5];
342 self.scroll_accum_x = 0.0;
343 self.scroll_accum_y = 0.0;
344 }
345}
346
347impl Default for MouseHandler {
348 fn default() -> Self {
349 Self::new()
350 }
351}
352
353#[cfg(test)]
354mod tests {
355 use super::*;
356 use crate::coordinates::MonitorInfo;
357
358 fn create_test_transformer() -> CoordinateTransformer {
359 let monitor = MonitorInfo {
360 id: 1,
361 name: "Primary".to_string(),
362 x: 0,
363 y: 0,
364 width: 1920,
365 height: 1080,
366 dpi: 96.0,
367 scale_factor: 1.0,
368 stream_x: 0,
369 stream_y: 0,
370 stream_width: 1920,
371 stream_height: 1080,
372 is_primary: true,
373 };
374
375 CoordinateTransformer::new(vec![monitor]).unwrap()
376 }
377
378 #[test]
379 fn test_mouse_handler_creation() {
380 let handler = MouseHandler::new();
381 let (x, y) = handler.current_position();
382 assert_eq!(x, 0.0);
383 assert_eq!(y, 0.0);
384 }
385
386 #[test]
387 fn test_absolute_move() {
388 let mut handler = MouseHandler::new();
389 let mut transformer = create_test_transformer();
390
391 let event = handler.handle_absolute_move(960, 540, &mut transformer).unwrap();
392
393 match event {
394 MouseEvent::Move { x, y, .. } => {
395 assert!(x > 0.0);
396 assert!(y > 0.0);
397 }
398 _ => panic!("Expected Move event"),
399 }
400
401 let (x, y) = handler.current_position();
402 assert!(x > 0.0);
403 assert!(y > 0.0);
404 }
405
406 #[test]
407 fn test_relative_move() {
408 let mut handler = MouseHandler::new();
409 let mut transformer = create_test_transformer();
410
411 let event = handler.handle_relative_move(10, 10, &mut transformer).unwrap();
412
413 match event {
414 MouseEvent::Move { .. } => {}
415 _ => panic!("Expected Move event"),
416 }
417 }
418
419 #[test]
420 fn test_button_press_release() {
421 let mut handler = MouseHandler::new();
422 let mut transformer = create_test_transformer();
423
424 let event = handler
426 .handle_button_down(MouseButton::Left, None, &mut transformer)
427 .unwrap();
428 match event {
429 MouseEvent::ButtonDown { button, .. } => {
430 assert_eq!(button, MouseButton::Left);
431 }
432 _ => panic!("Expected ButtonDown event"),
433 }
434
435 assert!(handler.is_button_pressed(MouseButton::Left));
436
437 let event = handler
439 .handle_button_up(MouseButton::Left, None, &mut transformer)
440 .unwrap();
441 match event {
442 MouseEvent::ButtonUp { button, .. } => {
443 assert_eq!(button, MouseButton::Left);
444 }
445 _ => panic!("Expected ButtonUp event"),
446 }
447
448 assert!(!handler.is_button_pressed(MouseButton::Left));
449 }
450
451 #[test]
452 fn test_button_press_carries_position() {
453 let mut handler = MouseHandler::new();
454 let mut transformer = create_test_transformer();
455
456 let event = handler
457 .handle_button_down(MouseButton::Left, Some((960, 540)), &mut transformer)
458 .unwrap();
459
460 match event {
461 MouseEvent::ButtonDown { button, position, .. } => {
462 assert_eq!(button, MouseButton::Left);
463 let (x, y) = position.expect("position should be carried through");
464 assert!(x > 0.0);
465 assert!(y > 0.0);
466 }
467 _ => panic!("Expected ButtonDown event"),
468 }
469
470 let (x, y) = handler.current_position();
471 assert!(x > 0.0);
472 assert!(y > 0.0);
473 }
474
475 #[test]
476 fn test_button_press_without_position_leaves_current_position_unchanged() {
477 let mut handler = MouseHandler::new();
478 let mut transformer = create_test_transformer();
479
480 handler.handle_absolute_move(960, 540, &mut transformer).unwrap();
481 let (before_x, before_y) = handler.current_position();
482
483 let event = handler
484 .handle_button_down(MouseButton::Left, None, &mut transformer)
485 .unwrap();
486
487 match event {
488 MouseEvent::ButtonDown { position, .. } => {
489 assert!(position.is_none());
490 }
491 _ => panic!("Expected ButtonDown event"),
492 }
493
494 let (after_x, after_y) = handler.current_position();
495 assert_eq!(before_x, after_x);
496 assert_eq!(before_y, after_y);
497 }
498
499 #[test]
500 fn test_scroll_event() {
501 let mut handler = MouseHandler::new();
502
503 let event = handler.handle_scroll(0, 120).unwrap();
504
505 match event {
506 MouseEvent::Scroll { delta_y, .. } => {
507 assert_eq!(delta_y, 1);
508 }
509 _ => panic!("Expected Scroll event"),
510 }
511 }
512
513 #[test]
514 fn test_high_precision_scroll() {
515 let mut handler = MouseHandler::new();
516 handler.set_high_precision_scroll(true);
517
518 for _ in 0..10 {
520 let _ = handler.handle_scroll(0, 12); }
522
523 let event = handler.handle_scroll(0, 0).unwrap();
525 match event {
526 MouseEvent::Scroll { delta_y, .. } => {
527 assert_eq!(delta_y, 0); }
529 _ => panic!("Expected Scroll event"),
530 }
531 }
532
533 #[test]
534 fn test_mouse_button_to_linux() {
535 assert_eq!(MouseButton::Left.to_linux_button(), 0x110);
536 assert_eq!(MouseButton::Right.to_linux_button(), 0x111);
537 assert_eq!(MouseButton::Middle.to_linux_button(), 0x112);
538 assert_eq!(MouseButton::Extra1.to_linux_button(), 0x113);
539 assert_eq!(MouseButton::Extra2.to_linux_button(), 0x114);
540 }
541
542 #[test]
543 fn test_mouse_button_from_rdp() {
544 assert_eq!(MouseButton::from_rdp_button(0x1000), Some(MouseButton::Left));
545 assert_eq!(MouseButton::from_rdp_button(0x2000), Some(MouseButton::Right));
546 assert_eq!(MouseButton::from_rdp_button(0x4000), Some(MouseButton::Middle));
547 assert_eq!(MouseButton::from_rdp_button(0x0080), Some(MouseButton::Extra1));
548 assert_eq!(MouseButton::from_rdp_button(0x0100), Some(MouseButton::Extra2));
549 assert_eq!(MouseButton::from_rdp_button(0x9999), None);
550 }
551
552 #[test]
553 fn test_multiple_button_states() {
554 let mut handler = MouseHandler::new();
555 let mut transformer = create_test_transformer();
556
557 handler
558 .handle_button_down(MouseButton::Left, None, &mut transformer)
559 .unwrap();
560 handler
561 .handle_button_down(MouseButton::Right, None, &mut transformer)
562 .unwrap();
563
564 assert!(handler.is_button_pressed(MouseButton::Left));
565 assert!(handler.is_button_pressed(MouseButton::Right));
566 assert!(!handler.is_button_pressed(MouseButton::Middle));
567
568 handler
569 .handle_button_up(MouseButton::Left, None, &mut transformer)
570 .unwrap();
571
572 assert!(!handler.is_button_pressed(MouseButton::Left));
573 assert!(handler.is_button_pressed(MouseButton::Right));
574 }
575
576 #[test]
577 fn test_mouse_reset() {
578 let mut handler = MouseHandler::new();
579 let mut transformer = create_test_transformer();
580
581 handler
582 .handle_button_down(MouseButton::Left, None, &mut transformer)
583 .unwrap();
584 handler
585 .handle_button_down(MouseButton::Right, None, &mut transformer)
586 .unwrap();
587 handler.scroll_accum_x = 5.0;
588 handler.scroll_accum_y = 5.0;
589
590 handler.reset();
591
592 assert!(!handler.is_button_pressed(MouseButton::Left));
593 assert!(!handler.is_button_pressed(MouseButton::Right));
594 assert_eq!(handler.scroll_accum_x, 0.0);
595 assert_eq!(handler.scroll_accum_y, 0.0);
596 }
597
598 #[test]
599 fn test_time_since_last_event() {
600 let mut handler = MouseHandler::new();
601 let mut transformer = create_test_transformer();
602
603 assert!(handler.time_since_last_event().is_none());
604
605 handler
606 .handle_button_down(MouseButton::Left, None, &mut transformer)
607 .unwrap();
608
609 assert!(handler.time_since_last_event().is_some());
610 assert!(handler.time_since_last_event().unwrap().as_millis() < 100);
611 }
612}