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}