logitech_cve/keyboard.rs
1use crate::device::Device;
2use core::time::Duration;
3use std::thread;
4
5#[repr(u8)]
6#[derive(Copy, Clone)]
7/// Represents keyboard keys with their corresponding scan codes.
8///
9/// This enum maps keyboard keys to their usage codes, which are used
10/// for sending keyboard input to device. Each variant corresponds to a specific
11/// physical key on a standard keyboard layout.
12pub enum Key {
13 /// The 'A' key
14 A = 0x4,
15 /// The 'B' key
16 B = 0x5,
17 /// The 'C' key
18 C = 0x6,
19 /// The 'D' key
20 D = 0x7,
21 /// The 'E' key
22 E = 0x8,
23 /// The 'F' key
24 F = 0x9,
25 /// The 'G' key
26 G = 0xA,
27 /// The 'H' key
28 H = 0xB,
29 /// The 'I' key
30 I = 0xC,
31 /// The 'J' key
32 J = 0xD,
33 /// The 'K' key
34 K = 0xE,
35 /// The 'L' key
36 L = 0xF,
37 /// The 'M' key
38 M = 0x10,
39 /// The 'N' key
40 N = 0x11,
41 /// The 'O' key
42 O = 0x12,
43 /// The 'P' key
44 P = 0x13,
45 /// The 'Q' key
46 Q = 0x14,
47 /// The 'R' key
48 R = 0x15,
49 /// The 'S' key
50 S = 0x16,
51 /// The 'T' key
52 T = 0x17,
53 /// The 'U' key
54 U = 0x18,
55 /// The 'V' key
56 V = 0x19,
57 /// The 'W' key
58 W = 0x1A,
59 /// The 'X' key
60 X = 0x1B,
61 /// The 'Y' key
62 Y = 0x1C,
63 /// The 'Z' key
64 Z = 0x1D,
65 /// The '1' number key
66 N1 = 0x1E,
67 /// The '2' number key
68 N2 = 0x1F,
69 /// The '3' number key
70 N3 = 0x20,
71 /// The '4' number key
72 N4 = 0x21,
73 /// The '5' number key
74 N5 = 0x22,
75 /// The '6' number key
76 N6 = 0x23,
77 /// The '7' number key
78 N7 = 0x24,
79 /// The '8' number key
80 N8 = 0x25,
81 /// The '9' number key
82 N9 = 0x26,
83 /// The '0' number key
84 N0 = 0x27,
85 /// The Enter/Return key
86 Enter = 0x28,
87 /// The Escape key
88 Esc = 0x29,
89 /// The Backspace key
90 BackSpace = 0x2A,
91 /// The Tab key
92 Tab = 0x2B,
93 /// The Space bar
94 Space = 0x2C,
95 /// The minus/hyphen key (-)
96 Minus = 0x2D,
97 /// The equals key (=)
98 Equal = 0x2E,
99 /// The left square bracket key ([)
100 SquareBracketLeft = 0x2F,
101 /// The right square bracket key (])
102 SquareBracketRight = 0x30,
103 /// The backslash key (\)
104 BackSlash = 0x31,
105 /// Alternative backslash key
106 BackSlash_ = 0x32,
107 /// The semicolon/colon key (;)
108 Column = 0x33,
109 /// The single quote/apostrophe key (')
110 Quote = 0x34,
111 /// The backtick/grave accent key (\`)
112 BackTick = 0x35,
113 /// The comma key (,)
114 Comma = 0x36,
115 /// The period/dot key (.)
116 Period = 0x37,
117 /// The forward slash key (/)
118 Slash = 0x38,
119 /// The Caps Lock key
120 Cap = 0x39,
121 /// Function key F1
122 F1 = 0x3A,
123 /// Function key F2
124 F2 = 0x3B,
125 /// Function key F3
126 F3 = 0x3C,
127 /// Function key F4
128 F4 = 0x3D,
129 /// Function key F5
130 F5 = 0x3E,
131 /// Function key F6
132 F6 = 0x3F,
133 /// Function key F7
134 F7 = 0x40,
135 /// Function key F8
136 F8 = 0x41,
137 /// Function key F9
138 F9 = 0x42,
139 /// Function key F10
140 F10 = 0x43,
141 /// Function key F11
142 F11 = 0x44,
143 /// Function key F12
144 F12 = 0x45,
145 /// Print Screen/Snapshot key
146 Snapshot = 0x46,
147 /// Scroll Lock key
148 ScrollLock = 0x47,
149 /// Pause/Break key
150 Pause = 0x48,
151 /// Insert key
152 Insert = 0x49,
153 /// Home key
154 Home = 0x4A,
155 /// Page Up key
156 PageUp = 0x4B,
157 /// Delete key
158 Del = 0x4C,
159 /// End key
160 End = 0x4D,
161 /// Page Down key
162 PageDown = 0x4E,
163 /// Right arrow key
164 Right = 0x4F,
165 /// Left arrow key
166 Left = 0x50,
167 /// Down arrow key
168 Down = 0x51,
169 /// Up arrow key
170 Up = 0x52,
171 /// Num Lock key
172 Numlock = 0x53,
173 /// Numeric keypad division key (/)
174 NumpadDiv = 0x54,
175 /// Numeric keypad multiplication key (*)
176 NumpadMul = 0x55,
177 /// Numeric keypad minus key (-)
178 NumpadMinus = 0x56,
179 /// Numeric keypad plus key (+)
180 NumpadPlus = 0x57,
181 /// Numeric keypad Enter key
182 NumpadEnter = 0x58,
183 /// Numeric keypad 1 key
184 Numpad1 = 0x59,
185 /// Numeric keypad 2 key
186 Numpad2 = 0x5A,
187 /// Numeric keypad 3 key
188 Numpad3 = 0x5B,
189 /// Numeric keypad 4 key
190 Numpad4 = 0x5C,
191 /// Numeric keypad 5 key
192 Numpad5 = 0x5D,
193 /// Numeric keypad 6 key
194 Numpad6 = 0x5E,
195 /// Numeric keypad 7 key
196 Numpad7 = 0x5F,
197 /// Numeric keypad 8 key
198 Numpad8 = 0x60,
199 /// Numeric keypad 9 key
200 Numpad9 = 0x61,
201 /// Numeric keypad 0 key
202 Numpad0 = 0x62,
203 /// Numeric keypad decimal point key (.)
204 NumpadDec = 0x63,
205 /// Application/Menu key
206 Apps = 0x65,
207 /// Function key F13
208 F13 = 0x68,
209 /// Function key F14
210 F14 = 0x69,
211 /// Function key F15
212 F15 = 0x6A,
213 /// Function key F16
214 F16 = 0x6B,
215 /// Function key F17
216 F17 = 0x6C,
217 /// Function key F18
218 F18 = 0x6D,
219 /// Function key F19
220 F19 = 0x6E,
221 /// Function key F20
222 F20 = 0x6F,
223 /// Function key F21
224 F21 = 0x70,
225 /// Function key F22
226 F22 = 0x71,
227 /// Function key F23
228 F23 = 0x72,
229 /// Function key F24
230 F24 = 0x73,
231 /// Right Windows key
232 Rwin = 0x8C,
233 /// Alternative F24 key
234 F24_ = 0x94,
235 /// Left Control key
236 Lctrl = 0xE0,
237 /// Left Shift key
238 Lshift = 0xE1,
239 /// Left Alt key
240 Lalt = 0xE2,
241 /// Left Windows key
242 Lwin = 0xE3,
243 /// Right Control key
244 Rctrl = 0xE4,
245 /// Right Shift key
246 Rshift = 0xE5,
247 /// Right Alt key
248 Ralt = 0xE6,
249 /// Alternative Right Windows key
250 Rwin_ = 0xE7,
251 /// No key pressed (release state)
252 Release = 0x0,
253}
254
255impl From<Key> for u8 {
256 #[inline]
257 fn from(button: Key) -> Self {
258 button as Self
259 }
260}
261
262impl TryFrom<char> for Key {
263 type Error = String;
264
265 fn try_from(c: char) -> Result<Self, Self::Error> {
266 match c.to_ascii_uppercase() {
267 'A' => Ok(Self::A),
268 'B' => Ok(Self::B),
269 'C' => Ok(Self::C),
270 'D' => Ok(Self::D),
271 'E' => Ok(Self::E),
272 'F' => Ok(Self::F),
273 'G' => Ok(Self::G),
274 'H' => Ok(Self::H),
275 'I' => Ok(Self::I),
276 'J' => Ok(Self::J),
277 'K' => Ok(Self::K),
278 'L' => Ok(Self::L),
279 'M' => Ok(Self::M),
280 'N' => Ok(Self::N),
281 'O' => Ok(Self::O),
282 'P' => Ok(Self::P),
283 'Q' => Ok(Self::Q),
284 'R' => Ok(Self::R),
285 'S' => Ok(Self::S),
286 'T' => Ok(Self::T),
287 'U' => Ok(Self::U),
288 'V' => Ok(Self::V),
289 'W' => Ok(Self::W),
290 'X' => Ok(Self::X),
291 'Y' => Ok(Self::Y),
292 'Z' => Ok(Self::Z),
293 '\n' => Ok(Self::Enter),
294 '\t' => Ok(Self::Tab),
295 ' ' => Ok(Self::Space),
296 '1' | '!' => Ok(Self::N1), // ! for Shift + 1
297 '2' | '@' => Ok(Self::N2), // @ for Shift + 2
298 '3' | '#' => Ok(Self::N3), // # for Shift + 3
299 '4' | '$' => Ok(Self::N4), // $ for Shift + 4
300 '5' | '%' => Ok(Self::N5), // % for Shift + 5
301 '6' | '^' => Ok(Self::N6), // ^ for Shift + 6
302 '7' | '&' => Ok(Self::N7), // & for Shift + 7
303 '8' | '*' => Ok(Self::N8), // * for Shift + 8
304 '9' | '(' => Ok(Self::N9), // ( for Shift + 9
305 '0' | ')' => Ok(Self::N0), // ) for Shift + 0
306 '-' | '_' => Ok(Self::Minus), // _ for Shift + -
307 '=' => Ok(Self::Equal), // + for Shift + =
308 '[' | '{' => Ok(Self::SquareBracketLeft), // { for Shift + [
309 ']' | '}' => Ok(Self::SquareBracketRight), // } for Shift + ]
310 ';' | ':' => Ok(Self::Column), // : for Shift + ;
311 '\'' | '"' => Ok(Self::Quote), // " for Shift + '
312 '\\' | '|' => Ok(Self::BackSlash), // | for Shift + \
313 ',' | '<' => Ok(Self::Comma), // < for Shift + ,
314 '.' | '>' => Ok(Self::Period), // > for Shift + .
315 '/' | '?' => Ok(Self::Slash), // ? for Shift + /
316 '`' | '~' => Ok(Self::BackTick), // ~ for Shift + `
317 _ => Err(format!("Unsupported character: {c}")),
318 }
319 }
320}
321
322/// A struct for controlling a virtual keyboard.
323///
324/// It holds a reference to a `Device` which is used to send the keyboard commands.
325pub struct Keyboard<'a> {
326 /// A reference to the device used to send keyboard commands.
327 device: &'a Device,
328}
329
330impl<'a> Keyboard<'a> {
331 /// Creates a new [`Keyboard`].
332 #[must_use]
333 pub const fn new(device: &'a Device) -> Self {
334 Self { device }
335 }
336
337 /// Presses a single keyboard button.
338 ///
339 /// The button is held down until a `release()` or `multi_press()` with `Key::NONE` is called.
340 ///
341 /// # Arguments
342 ///
343 /// * `button` - The `Key` to press.
344 #[inline]
345 pub fn press(&self, button: Key) {
346 self.device.call_keyboard(
347 button,
348 Key::Release,
349 Key::Release,
350 Key::Release,
351 Key::Release,
352 Key::Release,
353 );
354 }
355
356 /// Releases all currently pressed keyboard buttons.
357 ///
358 /// This effectively sends a "no keys pressed" command to the device.
359 #[inline]
360 pub fn release(&self) {
361 self.device.call_keyboard(
362 Key::Release,
363 Key::Release,
364 Key::Release,
365 Key::Release,
366 Key::Release,
367 Key::Release,
368 );
369 }
370
371 /// Presses and releases a single keyboard button.
372 ///
373 /// The button is pressed down, held for the specified duration, then released.
374 ///
375 /// # Arguments
376 ///
377 /// * `button` - The `Key` to press and release.
378 /// * `millis` - The duration in milliseconds to hold the button down before releasing it.
379 pub fn press_and_release(&self, button: Key, millis: u64) {
380 self.device.call_keyboard(
381 button,
382 Key::Release,
383 Key::Release,
384 Key::Release,
385 Key::Release,
386 Key::Release,
387 );
388 thread::sleep(Duration::from_millis(millis));
389 self.device.call_keyboard(
390 Key::Release,
391 Key::Release,
392 Key::Release,
393 Key::Release,
394 Key::Release,
395 Key::Release,
396 );
397 }
398
399 /// Presses up to six keyboard buttons simultaneously.
400 ///
401 /// This can be used for pressing modifier keys and other keys at the same time.
402 ///
403 /// # Arguments
404 ///
405 /// * `button1` - The first `Key` to press.
406 /// * `button2` - The second `Key` to press.
407 /// * `button3` - The third `Key` to press.
408 /// * `button4` - The fourth `Key` to press.
409 /// * `button5` - The fifth `Key` to press.
410 /// * `button6` - The sixth `Key` to press.
411 #[inline]
412 pub fn multi_press(&self, button1: Key, button2: Key, button3: Key, button4: Key, button5: Key, button6: Key) {
413 self.device
414 .call_keyboard(button1, button2, button3, button4, button5, button6);
415 }
416
417 /// Types a string by simulating individual key presses for each character.
418 ///
419 /// # Arguments
420 ///
421 /// * `string` - The string to be typed.
422 /// * `millis` - The duration in milliseconds to hold the button down before releasing it.
423 ///
424 /// # Errors
425 ///
426 /// This function will return an error if a character in the input string
427 /// cannot be converted into a valid `Key` enum variant.
428 pub fn type_string(&self, string: &str, millis: u64) -> Result<(), String> {
429 for c in string.chars() {
430 let key = Key::try_from(c)?;
431 match c {
432 'a'..='z'
433 | '0'..='9'
434 | '\n'
435 | '\t'
436 | ' '
437 | '-'
438 | '='
439 | '['
440 | ']'
441 | '\\'
442 | ';'
443 | '\''
444 | '`'
445 | ','
446 | '.'
447 | '/' => self.press_and_release(key, millis),
448
449 'A'..='Z'
450 | '!'
451 | '@'
452 | '#'
453 | '$'
454 | '%'
455 | '^'
456 | '&'
457 | '*'
458 | '('
459 | ')'
460 | '_'
461 | '+'
462 | '{'
463 | '}'
464 | ':'
465 | '"'
466 | '|'
467 | '<'
468 | '>'
469 | '?'
470 | '~' => {
471 self.multi_press(Key::Lshift, key, Key::Release, Key::Release, Key::Release, Key::Release);
472 thread::sleep(Duration::from_millis(millis));
473 self.release();
474 }
475 _ => {}
476 }
477 }
478
479 Ok(())
480 }
481}