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

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 '\''
}