lamco_rdp_input/
translator.rs

1//! Input Event Translator
2//!
3//! Top-level coordinator for translating RDP input events to Linux evdev events
4//! with complete keyboard and mouse support.
5
6use crate::coordinates::{CoordinateTransformer, MonitorInfo};
7use crate::error::{InputError, Result};
8use crate::keyboard::{KeyModifiers, KeyboardEvent, KeyboardHandler};
9use crate::mouse::{MouseButton, MouseEvent, MouseHandler};
10use std::time::Instant;
11use tracing::{debug, warn};
12
13/// RDP input event types
14#[derive(Debug, Clone)]
15pub enum RdpInputEvent {
16    /// Keyboard scancode event
17    KeyboardScancode {
18        /// Scancode value
19        scancode: u16,
20        /// Extended scancode (E0 prefix)
21        extended: bool,
22        /// E1 prefix (for Pause/Break)
23        e1_prefix: bool,
24        /// Key pressed (true) or released (false)
25        pressed: bool,
26    },
27
28    /// Mouse movement (absolute)
29    MouseMove {
30        /// X coordinate
31        x: u32,
32        /// Y coordinate
33        y: u32,
34    },
35
36    /// Mouse movement (relative)
37    MouseMoveRelative {
38        /// X delta
39        delta_x: i32,
40        /// Y delta
41        delta_y: i32,
42    },
43
44    /// Mouse button event
45    MouseButton {
46        /// Button flags (RDP format)
47        button: u16,
48        /// Button pressed (true) or released (false)
49        pressed: bool,
50    },
51
52    /// Mouse wheel scroll
53    MouseWheel {
54        /// Horizontal scroll delta
55        delta_x: i32,
56        /// Vertical scroll delta
57        delta_y: i32,
58    },
59}
60
61/// Translated Linux input event
62#[derive(Debug, Clone)]
63pub enum LinuxInputEvent {
64    /// Keyboard key event
65    Keyboard {
66        /// Event type (KeyDown, KeyUp, or KeyRepeat)
67        event_type: KeyboardEventType,
68        /// Linux evdev keycode
69        keycode: u32,
70        /// RDP scancode
71        scancode: u16,
72        /// Active modifiers
73        modifiers: KeyModifiers,
74        /// Event timestamp
75        timestamp: Instant,
76    },
77
78    /// Mouse movement event
79    MouseMove {
80        /// Absolute X coordinate
81        x: f64,
82        /// Absolute Y coordinate
83        y: f64,
84        /// Event timestamp
85        timestamp: Instant,
86    },
87
88    /// Mouse button event
89    MouseButton {
90        /// Linux button code
91        button_code: u32,
92        /// Button name
93        button: MouseButton,
94        /// Button pressed (true) or released (false)
95        pressed: bool,
96        /// Event timestamp
97        timestamp: Instant,
98    },
99
100    /// Mouse wheel scroll event
101    MouseWheel {
102        /// Horizontal scroll delta
103        delta_x: i32,
104        /// Vertical scroll delta
105        delta_y: i32,
106        /// Event timestamp
107        timestamp: Instant,
108    },
109}
110
111/// Keyboard event type
112#[derive(Debug, Clone, Copy, PartialEq, Eq)]
113pub enum KeyboardEventType {
114    /// Key pressed
115    KeyDown,
116    /// Key released
117    KeyUp,
118    /// Key repeat
119    KeyRepeat,
120}
121
122/// Input event translator
123pub struct InputTranslator {
124    /// Keyboard event handler
125    keyboard: KeyboardHandler,
126
127    /// Mouse event handler
128    mouse: MouseHandler,
129
130    /// Coordinate transformer
131    coord_transformer: CoordinateTransformer,
132
133    /// Total events processed
134    events_processed: u64,
135
136    /// Events per second counter
137    events_this_second: u64,
138
139    /// Last EPS calculation time
140    last_eps_time: Instant,
141}
142
143impl InputTranslator {
144    /// Create a new input translator
145    pub fn new(monitors: Vec<MonitorInfo>) -> Result<Self> {
146        Ok(Self {
147            keyboard: KeyboardHandler::new(),
148            mouse: MouseHandler::new(),
149            coord_transformer: CoordinateTransformer::new(monitors)?,
150            events_processed: 0,
151            events_this_second: 0,
152            last_eps_time: Instant::now(),
153        })
154    }
155
156    /// Translate an RDP input event to Linux format
157    pub fn translate_event(&mut self, event: RdpInputEvent) -> Result<LinuxInputEvent> {
158        self.events_processed += 1;
159        self.events_this_second += 1;
160
161        // Update EPS counter
162        if self.last_eps_time.elapsed().as_secs() >= 1 {
163            debug!("Input events per second: {}", self.events_this_second);
164            self.events_this_second = 0;
165            self.last_eps_time = Instant::now();
166        }
167
168        match event {
169            RdpInputEvent::KeyboardScancode {
170                scancode,
171                extended,
172                e1_prefix,
173                pressed,
174            } => self.translate_keyboard(scancode, extended, e1_prefix, pressed),
175
176            RdpInputEvent::MouseMove { x, y } => self.translate_mouse_move(x, y),
177
178            RdpInputEvent::MouseMoveRelative { delta_x, delta_y } => {
179                self.translate_mouse_move_relative(delta_x, delta_y)
180            }
181
182            RdpInputEvent::MouseButton { button, pressed } => self.translate_mouse_button(button, pressed),
183
184            RdpInputEvent::MouseWheel { delta_x, delta_y } => self.translate_mouse_wheel(delta_x, delta_y),
185        }
186    }
187
188    /// Translate keyboard event
189    fn translate_keyboard(
190        &mut self,
191        scancode: u16,
192        extended: bool,
193        e1_prefix: bool,
194        pressed: bool,
195    ) -> Result<LinuxInputEvent> {
196        let kbd_event = if pressed {
197            self.keyboard.handle_key_down(scancode, extended, e1_prefix)?
198        } else {
199            self.keyboard.handle_key_up(scancode, extended, e1_prefix)?
200        };
201
202        match kbd_event {
203            KeyboardEvent::KeyDown {
204                keycode,
205                scancode,
206                modifiers,
207                timestamp,
208            } => Ok(LinuxInputEvent::Keyboard {
209                event_type: KeyboardEventType::KeyDown,
210                keycode,
211                scancode,
212                modifiers,
213                timestamp,
214            }),
215
216            KeyboardEvent::KeyUp {
217                keycode,
218                scancode,
219                modifiers,
220                timestamp,
221            } => Ok(LinuxInputEvent::Keyboard {
222                event_type: KeyboardEventType::KeyUp,
223                keycode,
224                scancode,
225                modifiers,
226                timestamp,
227            }),
228
229            KeyboardEvent::KeyRepeat {
230                keycode,
231                scancode,
232                modifiers,
233                timestamp,
234            } => Ok(LinuxInputEvent::Keyboard {
235                event_type: KeyboardEventType::KeyRepeat,
236                keycode,
237                scancode,
238                modifiers,
239                timestamp,
240            }),
241        }
242    }
243
244    /// Translate mouse move event (absolute)
245    fn translate_mouse_move(&mut self, x: u32, y: u32) -> Result<LinuxInputEvent> {
246        let mouse_event = self.mouse.handle_absolute_move(x, y, &mut self.coord_transformer)?;
247
248        match mouse_event {
249            MouseEvent::Move { x, y, timestamp } => Ok(LinuxInputEvent::MouseMove { x, y, timestamp }),
250            _ => Err(InputError::InvalidState("Unexpected mouse event type".to_string())),
251        }
252    }
253
254    /// Translate mouse move event (relative)
255    fn translate_mouse_move_relative(&mut self, delta_x: i32, delta_y: i32) -> Result<LinuxInputEvent> {
256        let mouse_event = self
257            .mouse
258            .handle_relative_move(delta_x, delta_y, &mut self.coord_transformer)?;
259
260        match mouse_event {
261            MouseEvent::Move { x, y, timestamp } => Ok(LinuxInputEvent::MouseMove { x, y, timestamp }),
262            _ => Err(InputError::InvalidState("Unexpected mouse event type".to_string())),
263        }
264    }
265
266    /// Translate mouse button event
267    fn translate_mouse_button(&mut self, button_flags: u16, pressed: bool) -> Result<LinuxInputEvent> {
268        let button = MouseButton::from_rdp_button(button_flags).ok_or_else(|| {
269            warn!("Unknown RDP mouse button: 0x{:04X}", button_flags);
270            InputError::Unknown(format!("Unknown mouse button: 0x{:04X}", button_flags))
271        })?;
272
273        let mouse_event = if pressed {
274            self.mouse.handle_button_down(button)?
275        } else {
276            self.mouse.handle_button_up(button)?
277        };
278
279        match mouse_event {
280            MouseEvent::ButtonDown { button, timestamp } => Ok(LinuxInputEvent::MouseButton {
281                button_code: button.to_linux_button(),
282                button,
283                pressed: true,
284                timestamp,
285            }),
286
287            MouseEvent::ButtonUp { button, timestamp } => Ok(LinuxInputEvent::MouseButton {
288                button_code: button.to_linux_button(),
289                button,
290                pressed: false,
291                timestamp,
292            }),
293
294            _ => Err(InputError::InvalidState("Unexpected mouse event type".to_string())),
295        }
296    }
297
298    /// Translate mouse wheel event
299    fn translate_mouse_wheel(&mut self, delta_x: i32, delta_y: i32) -> Result<LinuxInputEvent> {
300        let mouse_event = self.mouse.handle_scroll(delta_x, delta_y)?;
301
302        match mouse_event {
303            MouseEvent::Scroll {
304                delta_x,
305                delta_y,
306                timestamp,
307            } => Ok(LinuxInputEvent::MouseWheel {
308                delta_x,
309                delta_y,
310                timestamp,
311            }),
312            _ => Err(InputError::InvalidState("Unexpected mouse event type".to_string())),
313        }
314    }
315
316    /// Update monitor configuration
317    pub fn update_monitors(&mut self, monitors: Vec<MonitorInfo>) -> Result<()> {
318        self.coord_transformer.update_monitors(monitors)
319    }
320
321    /// Set keyboard layout
322    pub fn set_keyboard_layout(&mut self, layout: &str) {
323        self.keyboard.set_layout(layout);
324    }
325
326    /// Get current keyboard layout
327    pub fn keyboard_layout(&self) -> &str {
328        self.keyboard.layout()
329    }
330
331    /// Set mouse acceleration enabled
332    pub fn set_mouse_acceleration(&mut self, enabled: bool) {
333        self.coord_transformer.set_acceleration_enabled(enabled);
334    }
335
336    /// Set mouse acceleration factor
337    pub fn set_mouse_acceleration_factor(&mut self, factor: f64) {
338        self.coord_transformer.set_acceleration_factor(factor);
339    }
340
341    /// Set high-precision mouse scrolling
342    pub fn set_high_precision_scroll(&mut self, enabled: bool) {
343        self.mouse.set_high_precision_scroll(enabled);
344    }
345
346    /// Reset input state (release all keys and buttons)
347    pub fn reset(&mut self) {
348        self.keyboard.reset();
349        self.mouse.reset();
350        debug!("Input translator reset");
351    }
352
353    /// Get total events processed
354    pub fn events_processed(&self) -> u64 {
355        self.events_processed
356    }
357
358    /// Get current mouse position
359    pub fn mouse_position(&self) -> (f64, f64) {
360        self.mouse.current_position()
361    }
362
363    /// Get current keyboard modifiers
364    pub fn keyboard_modifiers(&self) -> KeyModifiers {
365        self.keyboard.modifiers()
366    }
367
368    /// Get number of monitors
369    pub fn monitor_count(&self) -> usize {
370        self.coord_transformer.monitor_count()
371    }
372}
373
374#[cfg(test)]
375mod tests {
376    use super::*;
377
378    fn create_test_monitor() -> MonitorInfo {
379        MonitorInfo {
380            id: 1,
381            name: "Primary".to_string(),
382            x: 0,
383            y: 0,
384            width: 1920,
385            height: 1080,
386            dpi: 96.0,
387            scale_factor: 1.0,
388            stream_x: 0,
389            stream_y: 0,
390            stream_width: 1920,
391            stream_height: 1080,
392            is_primary: true,
393        }
394    }
395
396    #[test]
397    fn test_translator_creation() {
398        let translator = InputTranslator::new(vec![create_test_monitor()]).unwrap();
399        assert_eq!(translator.events_processed(), 0);
400        assert_eq!(translator.monitor_count(), 1);
401    }
402
403    #[test]
404    fn test_translate_keyboard_event() {
405        let mut translator = InputTranslator::new(vec![create_test_monitor()]).unwrap();
406
407        // Key down
408        let event = RdpInputEvent::KeyboardScancode {
409            scancode: 0x1E, // A key
410            extended: false,
411            e1_prefix: false,
412            pressed: true,
413        };
414
415        let result = translator.translate_event(event).unwrap();
416
417        match result {
418            LinuxInputEvent::Keyboard {
419                event_type, keycode, ..
420            } => {
421                assert_eq!(event_type, KeyboardEventType::KeyDown);
422                assert!(keycode > 0);
423            }
424            _ => panic!("Expected Keyboard event"),
425        }
426
427        assert_eq!(translator.events_processed(), 1);
428    }
429
430    #[test]
431    fn test_translate_mouse_move() {
432        let mut translator = InputTranslator::new(vec![create_test_monitor()]).unwrap();
433
434        let event = RdpInputEvent::MouseMove { x: 960, y: 540 };
435
436        let result = translator.translate_event(event).unwrap();
437
438        match result {
439            LinuxInputEvent::MouseMove { x, y, .. } => {
440                assert!(x >= 0.0);
441                assert!(y >= 0.0);
442            }
443            _ => panic!("Expected MouseMove event"),
444        }
445    }
446
447    #[test]
448    fn test_translate_mouse_button() {
449        let mut translator = InputTranslator::new(vec![create_test_monitor()]).unwrap();
450
451        let event = RdpInputEvent::MouseButton {
452            button: 0x1000, // Left button
453            pressed: true,
454        };
455
456        let result = translator.translate_event(event).unwrap();
457
458        match result {
459            LinuxInputEvent::MouseButton {
460                button,
461                pressed,
462                button_code,
463                ..
464            } => {
465                assert_eq!(button, MouseButton::Left);
466                assert!(pressed);
467                assert_eq!(button_code, 0x110);
468            }
469            _ => panic!("Expected MouseButton event"),
470        }
471    }
472
473    #[test]
474    fn test_translate_mouse_wheel() {
475        let mut translator = InputTranslator::new(vec![create_test_monitor()]).unwrap();
476
477        let event = RdpInputEvent::MouseWheel {
478            delta_x: 0,
479            delta_y: 120,
480        };
481
482        let result = translator.translate_event(event).unwrap();
483
484        match result {
485            LinuxInputEvent::MouseWheel { delta_y, .. } => {
486                assert_eq!(delta_y, 1);
487            }
488            _ => panic!("Expected MouseWheel event"),
489        }
490    }
491
492    #[test]
493    fn test_keyboard_modifiers() {
494        let mut translator = InputTranslator::new(vec![create_test_monitor()]).unwrap();
495
496        // Press Shift
497        let event = RdpInputEvent::KeyboardScancode {
498            scancode: 0x2A, // Left Shift
499            extended: false,
500            e1_prefix: false,
501            pressed: true,
502        };
503
504        translator.translate_event(event).unwrap();
505
506        let modifiers = translator.keyboard_modifiers();
507        assert!(modifiers.shift);
508    }
509
510    #[test]
511    fn test_layout_change() {
512        let mut translator = InputTranslator::new(vec![create_test_monitor()]).unwrap();
513
514        assert_eq!(translator.keyboard_layout(), "us");
515
516        translator.set_keyboard_layout("de");
517        assert_eq!(translator.keyboard_layout(), "de");
518    }
519
520    #[test]
521    fn test_reset() {
522        let mut translator = InputTranslator::new(vec![create_test_monitor()]).unwrap();
523
524        // Press some keys
525        translator
526            .translate_event(RdpInputEvent::KeyboardScancode {
527                scancode: 0x1E,
528                extended: false,
529                e1_prefix: false,
530                pressed: true,
531            })
532            .unwrap();
533
534        // Reset
535        translator.reset();
536
537        let modifiers = translator.keyboard_modifiers();
538        assert!(!modifiers.shift);
539        assert!(!modifiers.ctrl);
540    }
541
542    #[test]
543    fn test_events_counter() {
544        let mut translator = InputTranslator::new(vec![create_test_monitor()]).unwrap();
545
546        for i in 0..10 {
547            translator
548                .translate_event(RdpInputEvent::MouseMove { x: i * 100, y: i * 100 })
549                .unwrap();
550        }
551
552        assert_eq!(translator.events_processed(), 10);
553    }
554
555    #[test]
556    fn test_mouse_position_tracking() {
557        let mut translator = InputTranslator::new(vec![create_test_monitor()]).unwrap();
558
559        translator
560            .translate_event(RdpInputEvent::MouseMove { x: 100, y: 200 })
561            .unwrap();
562
563        let (x, y) = translator.mouse_position();
564        assert!(x >= 0.0);
565        assert!(y >= 0.0);
566    }
567}