1use crate::{Result, TauriMcpError};
2use enigo::{Enigo, Key, Settings, Button, Coordinate, Direction::Click, Keyboard, Mouse, Axis};
3use std::thread;
4use std::time::Duration;
5use tracing::{debug, info};
6
7pub struct InputSimulator {}
8
9impl InputSimulator {
10 pub fn new() -> Self {
11 Self {}
12 }
13
14 pub async fn send_keyboard_input(&self, process_id: &str, keys: &str) -> Result<()> {
15 info!("Sending keyboard input to process {}: {}", process_id, keys);
16
17 let keys_to_send = keys.to_string();
18 let settings = Settings::default();
19
20 tokio::task::spawn_blocking(move || {
21 let mut enigo = Enigo::new(&settings)
22 .map_err(|e| TauriMcpError::InputError(format!("Failed to create Enigo: {:?}", e)))?;
23
24 if keys_to_send.starts_with("cmd+") || keys_to_send.starts_with("ctrl+") {
25 Self::send_key_combination(&mut enigo, &keys_to_send)?;
26 } else {
27 for ch in keys_to_send.chars() {
28 enigo.text(&ch.to_string())
29 .map_err(|e| TauriMcpError::InputError(format!("Failed to send text: {:?}", e)))?;
30 thread::sleep(Duration::from_millis(10));
31 }
32 }
33
34 Ok::<(), TauriMcpError>(())
35 })
36 .await
37 .map_err(|e| TauriMcpError::InputError(format!("Failed to send keyboard input: {}", e)))??;
38
39 Ok(())
40 }
41
42 pub async fn send_mouse_click(&self, process_id: &str, x: i32, y: i32, button: &str) -> Result<()> {
43 info!("Sending mouse click to process {} at ({}, {}), button: {}", process_id, x, y, button);
44
45 let button_to_click = match button.to_lowercase().as_str() {
46 "left" => Button::Left,
47 "right" => Button::Right,
48 "middle" => Button::Middle,
49 _ => return Err(TauriMcpError::InputError(format!("Invalid mouse button: {}", button))),
50 };
51
52 let settings = Settings::default();
53
54 tokio::task::spawn_blocking(move || {
55 let mut enigo = Enigo::new(&settings)
56 .map_err(|e| TauriMcpError::InputError(format!("Failed to create Enigo: {:?}", e)))?;
57
58 enigo.move_mouse(x, y, Coordinate::Abs)
59 .map_err(|e| TauriMcpError::InputError(format!("Failed to move mouse: {:?}", e)))?;
60 thread::sleep(Duration::from_millis(50));
61
62 enigo.button(button_to_click, Click)
63 .map_err(|e| TauriMcpError::InputError(format!("Failed to click: {:?}", e)))?;
64
65 Ok::<(), TauriMcpError>(())
66 })
67 .await
68 .map_err(|e| TauriMcpError::InputError(format!("Failed to send mouse click: {}", e)))??;
69
70 Ok(())
71 }
72
73 pub async fn send_mouse_move(&self, process_id: &str, x: i32, y: i32) -> Result<()> {
74 info!("Moving mouse for process {} to ({}, {})", process_id, x, y);
75
76 let settings = Settings::default();
77
78 tokio::task::spawn_blocking(move || {
79 let mut enigo = Enigo::new(&settings)
80 .map_err(|e| TauriMcpError::InputError(format!("Failed to create Enigo: {:?}", e)))?;
81 enigo.move_mouse(x, y, Coordinate::Abs)
82 .map_err(|e| TauriMcpError::InputError(format!("Failed to move mouse: {:?}", e)))?;
83 Ok::<(), TauriMcpError>(())
84 })
85 .await
86 .map_err(|e| TauriMcpError::InputError(format!("Failed to move mouse: {}", e)))??;
87
88 Ok(())
89 }
90
91 pub async fn send_mouse_drag(&self, process_id: &str, start_x: i32, start_y: i32, end_x: i32, end_y: i32) -> Result<()> {
92 info!("Dragging mouse for process {} from ({}, {}) to ({}, {})",
93 process_id, start_x, start_y, end_x, end_y);
94
95 let settings = Settings::default();
96
97 tokio::task::spawn_blocking(move || {
98 let mut enigo = Enigo::new(&settings)
99 .map_err(|e| TauriMcpError::InputError(format!("Failed to create Enigo: {:?}", e)))?;
100
101 enigo.move_mouse(start_x, start_y, Coordinate::Abs)
102 .map_err(|e| TauriMcpError::InputError(format!("Failed to move mouse: {:?}", e)))?;
103 thread::sleep(Duration::from_millis(50));
104
105 enigo.button(Button::Left, enigo::Direction::Press)
106 .map_err(|e| TauriMcpError::InputError(format!("Failed to press button: {:?}", e)))?;
107 thread::sleep(Duration::from_millis(50));
108
109 let steps = 10;
110 let dx = (end_x - start_x) as f32 / steps as f32;
111 let dy = (end_y - start_y) as f32 / steps as f32;
112
113 for i in 1..=steps {
114 let x = start_x + (dx * i as f32) as i32;
115 let y = start_y + (dy * i as f32) as i32;
116 enigo.move_mouse(x, y, Coordinate::Abs)
117 .map_err(|e| TauriMcpError::InputError(format!("Failed to move mouse: {:?}", e)))?;
118 thread::sleep(Duration::from_millis(20));
119 }
120
121 enigo.button(Button::Left, enigo::Direction::Release)
122 .map_err(|e| TauriMcpError::InputError(format!("Failed to release button: {:?}", e)))?;
123
124 Ok::<(), TauriMcpError>(())
125 })
126 .await
127 .map_err(|e| TauriMcpError::InputError(format!("Failed to drag mouse: {}", e)))??;
128
129 Ok(())
130 }
131
132 pub async fn send_mouse_scroll(&self, process_id: &str, x: i32, y: i32, delta: i32) -> Result<()> {
133 info!("Scrolling mouse for process {} at ({}, {}), delta: {}", process_id, x, y, delta);
134
135 let settings = Settings::default();
136
137 tokio::task::spawn_blocking(move || {
138 let mut enigo = Enigo::new(&settings)
139 .map_err(|e| TauriMcpError::InputError(format!("Failed to create Enigo: {:?}", e)))?;
140
141 enigo.move_mouse(x, y, Coordinate::Abs)
142 .map_err(|e| TauriMcpError::InputError(format!("Failed to move mouse: {:?}", e)))?;
143 thread::sleep(Duration::from_millis(50));
144
145 enigo.scroll(delta, Axis::Vertical)
146 .map_err(|e| TauriMcpError::InputError(format!("Failed to scroll: {:?}", e)))?;
147
148 Ok::<(), TauriMcpError>(())
149 })
150 .await
151 .map_err(|e| TauriMcpError::InputError(format!("Failed to scroll mouse: {}", e)))??;
152
153 Ok(())
154 }
155
156 fn send_key_combination(enigo: &mut Enigo, combination: &str) -> Result<()> {
157 let parts: Vec<&str> = combination.split('+').collect();
158 if parts.len() < 2 {
159 return Err(TauriMcpError::InputError(format!("Invalid key combination: {}", combination)));
160 }
161
162 let mut modifier_keys = Vec::new();
163 let mut main_key = None;
164
165 for (i, part) in parts.iter().enumerate() {
166 let key_str = part.trim().to_lowercase();
167
168 if i < parts.len() - 1 {
169 match key_str.as_str() {
170 "cmd" | "meta" => modifier_keys.push(Key::Meta),
171 "ctrl" | "control" => modifier_keys.push(Key::Control),
172 "alt" | "option" => modifier_keys.push(Key::Alt),
173 "shift" => modifier_keys.push(Key::Shift),
174 _ => return Err(TauriMcpError::InputError(format!("Unknown modifier key: {}", key_str))),
175 }
176 } else {
177 main_key = Some(Self::string_to_key(&key_str)?);
178 }
179 }
180
181 for key in &modifier_keys {
182 enigo.key(*key, enigo::Direction::Press)
183 .map_err(|e| TauriMcpError::InputError(format!("Failed to press key: {:?}", e)))?;
184 thread::sleep(Duration::from_millis(10));
185 }
186
187 if let Some(key) = main_key {
188 enigo.key(key, Click)
189 .map_err(|e| TauriMcpError::InputError(format!("Failed to click key: {:?}", e)))?;
190 thread::sleep(Duration::from_millis(10));
191 }
192
193 for key in modifier_keys.iter().rev() {
194 enigo.key(*key, enigo::Direction::Release)
195 .map_err(|e| TauriMcpError::InputError(format!("Failed to release key: {:?}", e)))?;
196 thread::sleep(Duration::from_millis(10));
197 }
198
199 Ok(())
200 }
201
202 fn string_to_key(s: &str) -> Result<Key> {
203 match s {
204 "a" => Ok(Key::Unicode('a')),
205 "b" => Ok(Key::Unicode('b')),
206 "c" => Ok(Key::Unicode('c')),
207 "d" => Ok(Key::Unicode('d')),
208 "e" => Ok(Key::Unicode('e')),
209 "f" => Ok(Key::Unicode('f')),
210 "g" => Ok(Key::Unicode('g')),
211 "h" => Ok(Key::Unicode('h')),
212 "i" => Ok(Key::Unicode('i')),
213 "j" => Ok(Key::Unicode('j')),
214 "k" => Ok(Key::Unicode('k')),
215 "l" => Ok(Key::Unicode('l')),
216 "m" => Ok(Key::Unicode('m')),
217 "n" => Ok(Key::Unicode('n')),
218 "o" => Ok(Key::Unicode('o')),
219 "p" => Ok(Key::Unicode('p')),
220 "q" => Ok(Key::Unicode('q')),
221 "r" => Ok(Key::Unicode('r')),
222 "s" => Ok(Key::Unicode('s')),
223 "t" => Ok(Key::Unicode('t')),
224 "u" => Ok(Key::Unicode('u')),
225 "v" => Ok(Key::Unicode('v')),
226 "w" => Ok(Key::Unicode('w')),
227 "x" => Ok(Key::Unicode('x')),
228 "y" => Ok(Key::Unicode('y')),
229 "z" => Ok(Key::Unicode('z')),
230 "enter" | "return" => Ok(Key::Return),
231 "tab" => Ok(Key::Tab),
232 "space" => Ok(Key::Space),
233 "backspace" => Ok(Key::Backspace),
234 "escape" | "esc" => Ok(Key::Escape),
235 "delete" | "del" => Ok(Key::Delete),
236 "home" => Ok(Key::Home),
237 "end" => Ok(Key::End),
238 "pageup" => Ok(Key::PageUp),
239 "pagedown" => Ok(Key::PageDown),
240 "left" => Ok(Key::LeftArrow),
241 "right" => Ok(Key::RightArrow),
242 "up" => Ok(Key::UpArrow),
243 "down" => Ok(Key::DownArrow),
244 "f1" => Ok(Key::F1),
245 "f2" => Ok(Key::F2),
246 "f3" => Ok(Key::F3),
247 "f4" => Ok(Key::F4),
248 "f5" => Ok(Key::F5),
249 "f6" => Ok(Key::F6),
250 "f7" => Ok(Key::F7),
251 "f8" => Ok(Key::F8),
252 "f9" => Ok(Key::F9),
253 "f10" => Ok(Key::F10),
254 "f11" => Ok(Key::F11),
255 "f12" => Ok(Key::F12),
256 _ => Err(TauriMcpError::InputError(format!("Unknown key: {}", s))),
257 }
258 }
259}