1use crate::device::Device;
2use core::time::Duration;
3use std::thread;
4
5#[repr(u8)]
6#[derive(Copy, Clone)]
7pub enum Key {
8 A = 0x4,
9 B = 0x5,
10 C = 0x6,
11 D = 0x7,
12 E = 0x8,
13 F = 0x9,
14 G = 0xA,
15 H = 0xB,
16 I = 0xC,
17 J = 0xD,
18 K = 0xE,
19 L = 0xF,
20 M = 0x10,
21 N = 0x11,
22 O = 0x12,
23 P = 0x13,
24 Q = 0x14,
25 R = 0x15,
26 S = 0x16,
27 T = 0x17,
28 U = 0x18,
29 V = 0x19,
30 W = 0x1A,
31 X = 0x1B,
32 Y = 0x1C,
33 Z = 0x1D,
34 N1 = 0x1E,
35 N2 = 0x1F,
36 N3 = 0x20,
37 N4 = 0x21,
38 N5 = 0x22,
39 N6 = 0x23,
40 N7 = 0x24,
41 N8 = 0x25,
42 N9 = 0x26,
43 N0 = 0x27,
44 Enter = 0x28,
45 Esc = 0x29,
46 BackSpace = 0x2A,
47 Tab = 0x2B,
48 Space = 0x2C,
49 Minus = 0x2D,
50 Equal = 0x2E,
51 SquareBracketLeft = 0x2F,
52 SquareBracketRight = 0x30,
53 BackSlash = 0x31,
54 BackSlash_ = 0x32,
55 Column = 0x33,
56 Quote = 0x34,
57 BackTick = 0x35,
58 Comma = 0x36,
59 Period = 0x37,
60 Slash = 0x38,
61 Cap = 0x39,
62 F1 = 0x3A,
63 F2 = 0x3B,
64 F3 = 0x3C,
65 F4 = 0x3D,
66 F5 = 0x3E,
67 F6 = 0x3F,
68 F7 = 0x40,
69 F8 = 0x41,
70 F9 = 0x42,
71 F10 = 0x43,
72 F11 = 0x44,
73 F12 = 0x45,
74 Snapshot = 0x46,
75 ScrollLock = 0x47,
76 Pause = 0x48,
77 Insert = 0x49,
78 Home = 0x4A,
79 PageUp = 0x4B,
80 Del = 0x4C,
81 End = 0x4D,
82 PageDown = 0x4E,
83 Right = 0x4F,
84 Left = 0x50,
85 Down = 0x51,
86 Up = 0x52,
87 Numlock = 0x53,
88 NumpadDiv = 0x54,
89 NumpadMul = 0x55,
90 NumpadMinus = 0x56,
91 NumpadPlus = 0x57,
92 NumpadEnter = 0x58,
93 Numpad1 = 0x59,
94 Numpad2 = 0x5A,
95 Numpad3 = 0x5B,
96 Numpad4 = 0x5C,
97 Numpad5 = 0x5D,
98 Numpad6 = 0x5E,
99 Numpad7 = 0x5F,
100 Numpad8 = 0x60,
101 Numpad9 = 0x61,
102 Numpad0 = 0x62,
103 NumpadDec = 0x63,
104 Apps = 0x65,
105 F13 = 0x68,
106 F14 = 0x69,
107 F15 = 0x6A,
108 F16 = 0x6B,
109 F17 = 0x6C,
110 F18 = 0x6D,
111 F19 = 0x6E,
112 F20 = 0x6F,
113 F21 = 0x70,
114 F22 = 0x71,
115 F23 = 0x72,
116 F24 = 0x73,
117 Rwin = 0x8C,
118 F24_ = 0x94,
119 Lctrl = 0xE0,
120 Lshift = 0xE1,
121 Lalt = 0xE2,
122 Lwin = 0xE3,
123 Rctrl = 0xE4,
124 Rshift = 0xE5,
125 Ralt = 0xE6,
126 Rwin_ = 0xE7,
127 NONE = 0x0,
128}
129
130impl From<Key> for u8 {
131 #[inline]
132 fn from(button: Key) -> Self {
133 button as Self
134 }
135}
136
137impl TryFrom<char> for Key {
138 type Error = String;
139
140 fn try_from(c: char) -> Result<Self, Self::Error> {
141 match c.to_ascii_uppercase() {
142 'A' => Ok(Self::A),
143 'B' => Ok(Self::B),
144 'C' => Ok(Self::C),
145 'D' => Ok(Self::D),
146 'E' => Ok(Self::E),
147 'F' => Ok(Self::F),
148 'G' => Ok(Self::G),
149 'H' => Ok(Self::H),
150 'I' => Ok(Self::I),
151 'J' => Ok(Self::J),
152 'K' => Ok(Self::K),
153 'L' => Ok(Self::L),
154 'M' => Ok(Self::M),
155 'N' => Ok(Self::N),
156 'O' => Ok(Self::O),
157 'P' => Ok(Self::P),
158 'Q' => Ok(Self::Q),
159 'R' => Ok(Self::R),
160 'S' => Ok(Self::S),
161 'T' => Ok(Self::T),
162 'U' => Ok(Self::U),
163 'V' => Ok(Self::V),
164 'W' => Ok(Self::W),
165 'X' => Ok(Self::X),
166 'Y' => Ok(Self::Y),
167 'Z' => Ok(Self::Z),
168 '\n' => Ok(Self::Enter),
169 '\t' => Ok(Self::Tab),
170 ' ' => Ok(Self::Space),
171 '1' | '!' => Ok(Self::N1), '2' | '@' => Ok(Self::N2), '3' | '#' => Ok(Self::N3), '4' | '$' => Ok(Self::N4), '5' | '%' => Ok(Self::N5), '6' | '^' => Ok(Self::N6), '7' | '&' => Ok(Self::N7), '8' | '*' => Ok(Self::N8), '9' | '(' => Ok(Self::N9), '0' | ')' => Ok(Self::N0), '-' | '_' => Ok(Self::Minus), '=' => Ok(Self::Equal), '[' | '{' => Ok(Self::SquareBracketLeft), ']' | '}' => Ok(Self::SquareBracketRight), ';' | ':' => Ok(Self::Column), '\'' | '"' => Ok(Self::Quote), '\\' | '|' => Ok(Self::BackSlash), ',' | '<' => Ok(Self::Comma), '.' | '>' => Ok(Self::Period), '/' | '?' => Ok(Self::Slash), '`' | '~' => Ok(Self::BackTick), _ => Err(format!("Unsupported character: {c}")),
193 }
194 }
195}
196
197pub struct Keyboard<'a> {
201 device: &'a Device,
203}
204
205impl<'a> Keyboard<'a> {
206 #[must_use]
208 pub const fn new(device: &'a Device) -> Self {
209 Self { device }
210 }
211
212 #[inline]
220 pub fn press(&self, button: Key) {
221 self.device
222 .call_keyboard(button, Key::NONE, Key::NONE, Key::NONE, Key::NONE, Key::NONE);
223 }
224
225 #[inline]
229 pub fn release(&self) {
230 self.device
231 .call_keyboard(Key::NONE, Key::NONE, Key::NONE, Key::NONE, Key::NONE, Key::NONE);
232 }
233
234 pub fn press_and_release(&self, button: Key, millis: u64) {
243 self.device
244 .call_keyboard(button, Key::NONE, Key::NONE, Key::NONE, Key::NONE, Key::NONE);
245 thread::sleep(Duration::from_millis(millis));
246 self.device
247 .call_keyboard(Key::NONE, Key::NONE, Key::NONE, Key::NONE, Key::NONE, Key::NONE);
248 }
249
250 #[inline]
263 pub fn multi_press(&self, button1: Key, button2: Key, button3: Key, button4: Key, button5: Key, button6: Key) {
264 self.device
265 .call_keyboard(button1, button2, button3, button4, button5, button6);
266 }
267
268 pub fn type_string(&self, string: &str, millis: u64) -> Result<(), String> {
280 for c in string.chars() {
281 let key = Key::try_from(c)?;
282 match c {
283 'a'..='z'
284 | '0'..='9'
285 | '\n'
286 | '\t'
287 | ' '
288 | '-'
289 | '='
290 | '['
291 | ']'
292 | '\\'
293 | ';'
294 | '\''
295 | '`'
296 | ','
297 | '.'
298 | '/' => self.press_and_release(key, millis),
299
300 'A'..='Z'
301 | '!'
302 | '@'
303 | '#'
304 | '$'
305 | '%'
306 | '^'
307 | '&'
308 | '*'
309 | '('
310 | ')'
311 | '_'
312 | '+'
313 | '{'
314 | '}'
315 | ':'
316 | '"'
317 | '|'
318 | '<'
319 | '>'
320 | '?'
321 | '~' => {
322 self.multi_press(Key::Lshift, key, Key::NONE, Key::NONE, Key::NONE, Key::NONE);
323 thread::sleep(Duration::from_millis(millis));
324 self.release();
325 }
326 _ => {}
327 }
328 }
329
330 Ok(())
331 }
332}