You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
216 lines
6.3 KiB
Rust
216 lines
6.3 KiB
Rust
use std::fmt;
|
|
use windows::Win32::System::Console;
|
|
|
|
/// an abstract keycode
|
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
pub struct Code {
|
|
/// The integer value of the keycode, as defined by the Windows api. These associate to windows
|
|
/// virtual key codes.
|
|
pub val: u16,
|
|
|
|
/// The unicode symbol that represents the keycode, if any
|
|
pub sym: Option<char>,
|
|
}
|
|
|
|
/// An individual keypress event
|
|
#[derive(Debug)]
|
|
pub struct Event {
|
|
/// True for key press events, false for key release events
|
|
pub down: bool,
|
|
|
|
/// The number of times this event has happened in sequence
|
|
pub repeats: u16,
|
|
|
|
/// The virtual keycode for the keyboard event. This represents the associated character
|
|
/// pressed on a keyboard, not the physical button. For example, on an AZERTY keyboard,
|
|
/// pressing the key whose legend says A but is in the position of the Q key on a QWERTY
|
|
/// keyboard,
|
|
///
|
|
/// For more info, see here:
|
|
/// https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
|
pub code: Code,
|
|
|
|
/// The hardware-provided scancode. This is the location of the physical button, with no
|
|
/// relationship to the user's chosen layout.
|
|
pub scancode: u16,
|
|
|
|
/// the untranslated windows virtual keycode
|
|
pub keycode: u16,
|
|
|
|
/// The unicode character of the Event. Note this these correspond to virtual terminal
|
|
/// sequences. For example, when you press F1, you get an escape sequence of [OP, you'll see
|
|
/// the chars O and P but not related to their keys, because they're virtual keys. Hey wait a
|
|
/// second, that means I have to be folding the escape sequences into events.
|
|
pub char: char,
|
|
|
|
/// Whether or not one of the CTRL keys was held when the event was triggered
|
|
pub ctrl: bool,
|
|
|
|
/// Whether or not one of the ALT keys was held when the event was triggered
|
|
pub alt: bool,
|
|
|
|
/// Whether or not one of the SHIFT keys was held when the event was triggered
|
|
pub shift: bool,
|
|
}
|
|
|
|
// HEY where did these come from who left these here
|
|
const ALT_KEYS: u32 = 0x0002 | 0x0001;
|
|
const CTRL_KEYS: u32 = 0x0008 | 0x0004;
|
|
const SHIFT_PRESSED: u32 = 0x0010;
|
|
|
|
impl From<Console::KEY_EVENT_RECORD> for Event {
|
|
fn from(record: Console::KEY_EVENT_RECORD) -> Self {
|
|
unsafe {
|
|
let mstate = record.dwControlKeyState;
|
|
let c = char::from_u32(record.uChar.UnicodeChar as u32).unwrap_or('💀');
|
|
let keycode = codes::lookup(record.wVirtualKeyCode as usize);
|
|
|
|
Self {
|
|
down: record.bKeyDown.as_bool(),
|
|
repeats: record.wRepeatCount,
|
|
code: keycode,
|
|
scancode: record.wVirtualScanCode,
|
|
keycode: record.wVirtualKeyCode,
|
|
alt: mstate & ALT_KEYS > 0,
|
|
ctrl: mstate & CTRL_KEYS > 0,
|
|
shift: mstate & SHIFT_PRESSED > 0,
|
|
char: c,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Event {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
let down = if self.down { '↓' } else { '↑' };
|
|
let sym = match self.code.sym {
|
|
Some(c) => c,
|
|
None => '·',
|
|
};
|
|
let ctrl = if self.ctrl { 'C' } else { '·' };
|
|
let alt = if self.alt { 'A' } else { '·' };
|
|
let shift = if self.shift { 'S' } else { '·' };
|
|
let glyph = if !self.char.is_control() {
|
|
self.char
|
|
} else if self.char as u32 == 27 {
|
|
'⁝'
|
|
} else {
|
|
'·'
|
|
};
|
|
write!(
|
|
f,
|
|
"{down} {ctrl} {alt} {shift} {glyph} {charcode: <3} {sym} {code: <3} {keycode: <3} {scancode: <3}",
|
|
charcode = self.char as u32,
|
|
code = self.code.val,
|
|
keycode = self.keycode,
|
|
scancode = self.scancode,
|
|
)
|
|
}
|
|
}
|
|
|
|
macro_rules! codes {
|
|
($($val:literal $name:ident $sym:literal)*) => {
|
|
|
|
/// stores our key code constants
|
|
pub mod codes {
|
|
use super::Code;
|
|
$(
|
|
#[allow(unused)]
|
|
pub const $name: Code = Code{val: $val, sym: Some($sym)};
|
|
)*
|
|
|
|
/// generates a table of key codes
|
|
/// https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
|
const fn gen_codes() -> [Code; 256] {
|
|
let mut codes = [Code{val: 0, sym: None}; 256];
|
|
let mut i = 0 as usize;
|
|
while i < 256 {
|
|
codes[i] = Code{val: i as u16, sym: None};
|
|
i = i + 1;
|
|
}
|
|
|
|
$(
|
|
codes[$val] = Code{val: $val, sym: Some($sym)};
|
|
)*
|
|
codes
|
|
}
|
|
|
|
/// Lookup table to retrieve keycodes by their numeric value
|
|
const INDEX: [Code; 256] = gen_codes();
|
|
|
|
/// Translates the numeric value of a win32 VirtualKeyCode into a key::Code value
|
|
pub const fn lookup(vk_code: usize) -> Code {
|
|
INDEX[vk_code]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
codes! {
|
|
0x01 MOUSE_LEFT ' '
|
|
0x02 MOUSE_RIGHT ' '
|
|
0x03 CTRL_BREAK ' ' // control-break processing
|
|
0x04 MIDDLE_MOUSE ' '
|
|
0x05 X1_MOUSE ' '
|
|
0x06 X2_MOUSE ' ' // 0x07 is reserved
|
|
0x08 BACKSPACE '⌫'
|
|
0x09 TAB '↹' // 0x0A-0B Reserved
|
|
0x0C CLEAR ' '
|
|
0x0D ENTER '↩' // 0x0E-0F Unassigned
|
|
0x10 SHIFT '⇧'
|
|
0x11 CTRL '⎈'
|
|
0x12 ALT '⎇'
|
|
0x13 PAUSE '⎉'
|
|
0x14 CAPS_LOCK '⇪'
|
|
0x15 KANA_MODE ' '
|
|
0x1B ESC '⎋'
|
|
0x20 SPACE '␣'
|
|
0x21 PAGE_UP '↟'
|
|
0x22 PAGE_DOWN '↡'
|
|
0x23 END '⇲'
|
|
0x25 LEFT '←'
|
|
0x26 UP '↑'
|
|
0x27 RIGHT '→'
|
|
0x28 DOWN '↓'
|
|
0x30 NUM_0 '0'
|
|
0x31 NUM_1 '1'
|
|
0x32 NUM_2 '2'
|
|
0x33 NUM_3 '3'
|
|
0x34 NUM_4 '4'
|
|
0x35 NUM_5 '5'
|
|
0x36 NUM_6 '6'
|
|
0x37 NUM_7 '7'
|
|
0x38 NUM_8 '8'
|
|
0x39 NUM_9 '9'
|
|
0x41 A 'a'
|
|
0x42 B 'b'
|
|
0x43 C 'c'
|
|
0x44 D 'd'
|
|
0x45 E 'e'
|
|
0x46 F 'f'
|
|
0x47 G 'g'
|
|
0x48 H 'h'
|
|
0x49 I 'i'
|
|
0x4A J 'j'
|
|
0x4B K 'k'
|
|
0x4C L 'l'
|
|
0x4D M 'm'
|
|
0x4E N 'n'
|
|
0x4F O 'o'
|
|
0x50 P 'p'
|
|
0x51 Q 'q'
|
|
0x52 R 'r'
|
|
0x53 S 's'
|
|
0x54 T 't'
|
|
0x55 U 'u'
|
|
0x56 V 'v'
|
|
0x57 W 'w'
|
|
0x58 X 'x'
|
|
0x59 Y 'y'
|
|
0x5A Z 'z'
|
|
0xA0 LEFT_SHIFT '⇧'
|
|
0xA1 RIGHT_SHIFT '⇧'
|
|
0xBE PERIOD '.'
|
|
0xDE QUOTE '\''
|
|
}
|