use crate::device::Device;
use core::time::Duration;
use std::thread;
#[repr(u8)]
#[derive(Copy, Clone)]
pub enum Key {
A = 0x4,
B = 0x5,
C = 0x6,
D = 0x7,
E = 0x8,
F = 0x9,
G = 0xA,
H = 0xB,
I = 0xC,
J = 0xD,
K = 0xE,
L = 0xF,
M = 0x10,
N = 0x11,
O = 0x12,
P = 0x13,
Q = 0x14,
R = 0x15,
S = 0x16,
T = 0x17,
U = 0x18,
V = 0x19,
W = 0x1A,
X = 0x1B,
Y = 0x1C,
Z = 0x1D,
N1 = 0x1E,
N2 = 0x1F,
N3 = 0x20,
N4 = 0x21,
N5 = 0x22,
N6 = 0x23,
N7 = 0x24,
N8 = 0x25,
N9 = 0x26,
N0 = 0x27,
Enter = 0x28,
Esc = 0x29,
BackSpace = 0x2A,
Tab = 0x2B,
Space = 0x2C,
Minus = 0x2D,
Equal = 0x2E,
SquareBracketLeft = 0x2F,
SquareBracketRight = 0x30,
BackSlash = 0x31,
BackSlash_ = 0x32,
Column = 0x33,
Quote = 0x34,
BackTick = 0x35,
Comma = 0x36,
Period = 0x37,
Slash = 0x38,
Cap = 0x39,
F1 = 0x3A,
F2 = 0x3B,
F3 = 0x3C,
F4 = 0x3D,
F5 = 0x3E,
F6 = 0x3F,
F7 = 0x40,
F8 = 0x41,
F9 = 0x42,
F10 = 0x43,
F11 = 0x44,
F12 = 0x45,
Snapshot = 0x46,
ScrollLock = 0x47,
Pause = 0x48,
Insert = 0x49,
Home = 0x4A,
PageUp = 0x4B,
Del = 0x4C,
End = 0x4D,
PageDown = 0x4E,
Right = 0x4F,
Left = 0x50,
Down = 0x51,
Up = 0x52,
Numlock = 0x53,
NumpadDiv = 0x54,
NumpadMul = 0x55,
NumpadMinus = 0x56,
NumpadPlus = 0x57,
NumpadEnter = 0x58,
Numpad1 = 0x59,
Numpad2 = 0x5A,
Numpad3 = 0x5B,
Numpad4 = 0x5C,
Numpad5 = 0x5D,
Numpad6 = 0x5E,
Numpad7 = 0x5F,
Numpad8 = 0x60,
Numpad9 = 0x61,
Numpad0 = 0x62,
NumpadDec = 0x63,
Apps = 0x65,
F13 = 0x68,
F14 = 0x69,
F15 = 0x6A,
F16 = 0x6B,
F17 = 0x6C,
F18 = 0x6D,
F19 = 0x6E,
F20 = 0x6F,
F21 = 0x70,
F22 = 0x71,
F23 = 0x72,
F24 = 0x73,
Rwin = 0x8C,
F24_ = 0x94,
Lctrl = 0xE0,
Lshift = 0xE1,
Lalt = 0xE2,
Lwin = 0xE3,
Rctrl = 0xE4,
Rshift = 0xE5,
Ralt = 0xE6,
Rwin_ = 0xE7,
Release = 0x0,
}
impl From<Key> for u8 {
#[inline]
fn from(button: Key) -> Self {
button as Self
}
}
impl TryFrom<char> for Key {
type Error = String;
#[inline]
fn try_from(c: char) -> Result<Self, Self::Error> {
match c.to_ascii_uppercase() {
'A' => Ok(Self::A),
'B' => Ok(Self::B),
'C' => Ok(Self::C),
'D' => Ok(Self::D),
'E' => Ok(Self::E),
'F' => Ok(Self::F),
'G' => Ok(Self::G),
'H' => Ok(Self::H),
'I' => Ok(Self::I),
'J' => Ok(Self::J),
'K' => Ok(Self::K),
'L' => Ok(Self::L),
'M' => Ok(Self::M),
'N' => Ok(Self::N),
'O' => Ok(Self::O),
'P' => Ok(Self::P),
'Q' => Ok(Self::Q),
'R' => Ok(Self::R),
'S' => Ok(Self::S),
'T' => Ok(Self::T),
'U' => Ok(Self::U),
'V' => Ok(Self::V),
'W' => Ok(Self::W),
'X' => Ok(Self::X),
'Y' => Ok(Self::Y),
'Z' => Ok(Self::Z),
'\n' => Ok(Self::Enter),
'\t' => Ok(Self::Tab),
' ' => Ok(Self::Space),
'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}")),
}
}
}
pub struct Keyboard<'a> {
device: &'a Device,
}
impl<'a> Keyboard<'a> {
#[must_use]
#[inline]
pub const fn new(device: &'a Device) -> Self {
Self { device }
}
#[inline]
pub fn press(&self, button: Key) {
self.device.call_keyboard(
button,
Key::Release,
Key::Release,
Key::Release,
Key::Release,
Key::Release,
);
}
#[inline]
pub fn release(&self) {
self.device.call_keyboard(
Key::Release,
Key::Release,
Key::Release,
Key::Release,
Key::Release,
Key::Release,
);
}
#[inline]
pub fn press_and_release(&self, button: Key, millis: u64) {
self.device.call_keyboard(
button,
Key::Release,
Key::Release,
Key::Release,
Key::Release,
Key::Release,
);
thread::sleep(Duration::from_millis(millis));
self.device.call_keyboard(
Key::Release,
Key::Release,
Key::Release,
Key::Release,
Key::Release,
Key::Release,
);
}
#[inline]
pub fn multi_press(&self, button1: Key, button2: Key, button3: Key, button4: Key, button5: Key, button6: Key) {
self.device
.call_keyboard(button1, button2, button3, button4, button5, button6);
}
#[inline]
pub fn type_string(&self, string: &str, millis: u64) -> Result<(), String> {
for c in string.chars() {
let key = Key::try_from(c)?;
match c {
'a'..='z'
| '0'..='9'
| '\n'
| '\t'
| ' '
| '-'
| '='
| '['
| ']'
| '\\'
| ';'
| '\''
| '`'
| ','
| '.'
| '/' => self.press_and_release(key, millis),
'A'..='Z'
| '!'
| '@'
| '#'
| '$'
| '%'
| '^'
| '&'
| '*'
| '('
| ')'
| '_'
| '+'
| '{'
| '}'
| ':'
| '"'
| '|'
| '<'
| '>'
| '?'
| '~' => {
self.multi_press(Key::Lshift, key, Key::Release, Key::Release, Key::Release, Key::Release);
thread::sleep(Duration::from_millis(millis));
self.release();
}
_ => {}
}
}
Ok(())
}
}