//! Input injection module //! //! Handles mouse and keyboard input simulation using Windows SendInput API. mod keyboard; mod mouse; pub use keyboard::vk_is_extended; pub use keyboard::KeyboardController; pub use mouse::MouseController; use anyhow::Result; /// Combined input controller for mouse and keyboard pub struct InputController { mouse: MouseController, keyboard: KeyboardController, } impl InputController { /// Create a new input controller pub fn new() -> Result { Ok(Self { mouse: MouseController::new()?, keyboard: KeyboardController::new()?, }) } /// Get mouse controller #[allow(dead_code)] pub fn mouse(&mut self) -> &mut MouseController { &mut self.mouse } /// Get keyboard controller #[allow(dead_code)] pub fn keyboard(&mut self) -> &mut KeyboardController { &mut self.keyboard } /// Move mouse to absolute position pub fn mouse_move(&mut self, x: i32, y: i32) -> Result<()> { self.mouse.move_to(x, y) } /// Click mouse button pub fn mouse_click(&mut self, button: MouseButton, down: bool) -> Result<()> { if down { self.mouse.button_down(button) } else { self.mouse.button_up(button) } } /// Scroll mouse wheel pub fn mouse_scroll(&mut self, delta_x: i32, delta_y: i32) -> Result<()> { self.mouse.scroll(delta_x, delta_y) } /// Press or release a key by virtual-key code only (scan code derived from the VK). #[allow(dead_code)] pub fn key_event(&mut self, vk_code: u16, down: bool) -> Result<()> { if down { self.keyboard.key_down(vk_code) } else { self.keyboard.key_up(vk_code) } } /// Inject a full-fidelity key event (VK + hardware scan code + extended-key flag). /// /// This is the path used for relayed viewer keystrokes so that scan-code injection /// (layout-independent) and the correct `KEYEVENTF_EXTENDEDKEY` flag are applied. pub fn key_event_full( &mut self, vk_code: u16, scan_code: u16, is_extended: bool, down: bool, ) -> Result<()> { self.keyboard .key_event_full(vk_code, scan_code, is_extended, down) } /// Release any modifier keys currently held down on the remote. /// /// Invoked when the viewer loses focus or the session ends so a Ctrl/Alt/Shift/Win /// whose key-up never arrived does not stay latched on the remote desktop. #[allow(dead_code)] pub fn release_all_modifiers(&mut self) -> Result<()> { self.keyboard.release_all_modifiers() } /// Type a unicode character #[allow(dead_code)] pub fn type_unicode(&mut self, ch: char) -> Result<()> { self.keyboard.type_char(ch) } /// Send Ctrl+Alt+Delete (requires special handling on Windows) pub fn send_ctrl_alt_del(&mut self) -> Result<()> { self.keyboard.send_sas() } } /// Mouse button types #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum MouseButton { Left, Right, Middle, // Extra mouse buttons; not yet produced by the viewer input mapping. #[allow(dead_code)] X1, #[allow(dead_code)] X2, } impl Default for InputController { fn default() -> Self { Self::new().expect("Failed to create input controller") } }