Skip to main content

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    #[inline]
266    fn try_from(c: char) -> Result<Self, Self::Error> {
267        match c.to_ascii_uppercase() {
268            'A' => Ok(Self::A),
269            'B' => Ok(Self::B),
270            'C' => Ok(Self::C),
271            'D' => Ok(Self::D),
272            'E' => Ok(Self::E),
273            'F' => Ok(Self::F),
274            'G' => Ok(Self::G),
275            'H' => Ok(Self::H),
276            'I' => Ok(Self::I),
277            'J' => Ok(Self::J),
278            'K' => Ok(Self::K),
279            'L' => Ok(Self::L),
280            'M' => Ok(Self::M),
281            'N' => Ok(Self::N),
282            'O' => Ok(Self::O),
283            'P' => Ok(Self::P),
284            'Q' => Ok(Self::Q),
285            'R' => Ok(Self::R),
286            'S' => Ok(Self::S),
287            'T' => Ok(Self::T),
288            'U' => Ok(Self::U),
289            'V' => Ok(Self::V),
290            'W' => Ok(Self::W),
291            'X' => Ok(Self::X),
292            'Y' => Ok(Self::Y),
293            'Z' => Ok(Self::Z),
294            '\n' => Ok(Self::Enter),
295            '\t' => Ok(Self::Tab),
296            ' ' => Ok(Self::Space),
297            '1' | '!' => Ok(Self::N1),                 // ! for Shift + 1
298            '2' | '@' => Ok(Self::N2),                 // @ for Shift + 2
299            '3' | '#' => Ok(Self::N3),                 // # for Shift + 3
300            '4' | '$' => Ok(Self::N4),                 // $ for Shift + 4
301            '5' | '%' => Ok(Self::N5),                 // % for Shift + 5
302            '6' | '^' => Ok(Self::N6),                 // ^ for Shift + 6
303            '7' | '&' => Ok(Self::N7),                 // & for Shift + 7
304            '8' | '*' => Ok(Self::N8),                 // * for Shift + 8
305            '9' | '(' => Ok(Self::N9),                 // ( for Shift + 9
306            '0' | ')' => Ok(Self::N0),                 // ) for Shift + 0
307            '-' | '_' => Ok(Self::Minus),              // _ for Shift + -
308            '=' => Ok(Self::Equal),                    // + for Shift + =
309            '[' | '{' => Ok(Self::SquareBracketLeft),  // { for Shift + [
310            ']' | '}' => Ok(Self::SquareBracketRight), // } for Shift + ]
311            ';' | ':' => Ok(Self::Column),             // : for Shift + ;
312            '\'' | '"' => Ok(Self::Quote),             // " for Shift + '
313            '\\' | '|' => Ok(Self::BackSlash),         // | for Shift + \
314            ',' | '<' => Ok(Self::Comma),              // < for Shift + ,
315            '.' | '>' => Ok(Self::Period),             // > for Shift + .
316            '/' | '?' => Ok(Self::Slash),              // ? for Shift + /
317            '`' | '~' => Ok(Self::BackTick),           // ~ for Shift + `
318            _ => Err(format!("Unsupported character: {c}")),
319        }
320    }
321}
322
323/// A struct for controlling a virtual keyboard.
324///
325/// It holds a reference to a `Device` which is used to send the keyboard commands.
326pub struct Keyboard<'a> {
327    /// A reference to the device used to send keyboard commands.
328    device: &'a Device,
329}
330
331impl<'a> Keyboard<'a> {
332    /// Creates a new [`Keyboard`].
333    #[must_use]
334    #[inline]
335    pub const fn new(device: &'a Device) -> Self {
336        Self { device }
337    }
338
339    /// Presses a single keyboard button.
340    ///
341    /// The button is held down until a `release()` or `multi_press()` with `Key::NONE` is called.
342    ///
343    /// # Arguments
344    ///
345    /// * `button` - The `Key` to press.
346    #[inline]
347    pub fn press(&self, button: Key) {
348        self.device.call_keyboard(
349            button,
350            Key::Release,
351            Key::Release,
352            Key::Release,
353            Key::Release,
354            Key::Release,
355        );
356    }
357
358    /// Releases all currently pressed keyboard buttons.
359    ///
360    /// This effectively sends a "no keys pressed" command to the device.
361    #[inline]
362    pub fn release(&self) {
363        self.device.call_keyboard(
364            Key::Release,
365            Key::Release,
366            Key::Release,
367            Key::Release,
368            Key::Release,
369            Key::Release,
370        );
371    }
372
373    /// Presses and releases a single keyboard button.
374    ///
375    /// The button is pressed down, held for the specified duration, then released.
376    ///
377    /// # Arguments
378    ///
379    /// * `button` - The `Key` to press and release.
380    /// * `millis` - The duration in milliseconds to hold the button down before releasing it.
381    #[inline]
382    pub fn press_and_release(&self, button: Key, millis: u64) {
383        self.device.call_keyboard(
384            button,
385            Key::Release,
386            Key::Release,
387            Key::Release,
388            Key::Release,
389            Key::Release,
390        );
391        thread::sleep(Duration::from_millis(millis));
392        self.device.call_keyboard(
393            Key::Release,
394            Key::Release,
395            Key::Release,
396            Key::Release,
397            Key::Release,
398            Key::Release,
399        );
400    }
401
402    /// Presses up to six keyboard buttons simultaneously.
403    ///
404    /// This can be used for pressing modifier keys and other keys at the same time.
405    ///
406    /// # Arguments
407    ///
408    /// * `button1` - The first `Key` to press.
409    /// * `button2` - The second `Key` to press.
410    /// * `button3` - The third `Key` to press.
411    /// * `button4` - The fourth `Key` to press.
412    /// * `button5` - The fifth `Key` to press.
413    /// * `button6` - The sixth `Key` to press.
414    #[inline]
415    pub fn multi_press(&self, button1: Key, button2: Key, button3: Key, button4: Key, button5: Key, button6: Key) {
416        self.device
417            .call_keyboard(button1, button2, button3, button4, button5, button6);
418    }
419
420    /// Types a string by simulating individual key presses for each character.
421    ///
422    /// # Arguments
423    ///
424    /// * `string` - The string to be typed.
425    /// * `millis` - The duration in milliseconds to hold the button down before releasing it.
426    ///
427    /// # Errors
428    ///
429    /// This function will return an error if a character in the input string
430    /// cannot be converted into a valid `Key` enum variant.
431    #[inline]
432    pub fn type_string(&self, string: &str, millis: u64) -> Result<(), String> {
433        for c in string.chars() {
434            let key = Key::try_from(c)?;
435            match c {
436                'a'..='z'
437                | '0'..='9'
438                | '\n'
439                | '\t'
440                | ' '
441                | '-'
442                | '='
443                | '['
444                | ']'
445                | '\\'
446                | ';'
447                | '\''
448                | '`'
449                | ','
450                | '.'
451                | '/' => self.press_and_release(key, millis),
452
453                'A'..='Z'
454                | '!'
455                | '@'
456                | '#'
457                | '$'
458                | '%'
459                | '^'
460                | '&'
461                | '*'
462                | '('
463                | ')'
464                | '_'
465                | '+'
466                | '{'
467                | '}'
468                | ':'
469                | '"'
470                | '|'
471                | '<'
472                | '>'
473                | '?'
474                | '~' => {
475                    self.multi_press(Key::Lshift, key, Key::Release, Key::Release, Key::Release, Key::Release);
476                    thread::sleep(Duration::from_millis(millis));
477                    self.release();
478                }
479                _ => {}
480            }
481        }
482
483        Ok(())
484    }
485}