diff --git a/src/input.rs b/src/input.rs index 8cd6c51..cbad1d5 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,5 +1,5 @@ use anyhow::{Context, Result}; -use crate::{error::Error, log::*}; +use crate::{error::Error, log::*, key}; use windows::Win32::System::Console; use windows::Win32::Foundation::HANDLE; @@ -149,7 +149,7 @@ impl Reader { // All buffered items have been processed, ask the OS for new event records if self.buf_idx as u32 >= self.buf_len { unsafe { - Error::check(Console::ReadConsoleInputW(self.input, &mut self.buf, &mut self.buf_len))?; + Error::check(Console::ReadConsoleInputA(self.input, &mut self.buf, &mut self.buf_len))?; } self.buf_idx = 0; } @@ -159,3 +159,71 @@ impl Reader { return Ok(rec); } } + +#[derive(Debug)] +pub enum Event { + Focus(bool), + Menu, + Key(key::Event), + Mouse, + Size, +} + +const ALT_KEYS: u32 = 0x0002 | 0x0001; +const CTRL_KEYS: u32 = 0x0008 | 0x0004; +const SHIFT_PRESSED: u32 = 0x0010; + +impl From for Event { + fn from(rec: Console::INPUT_RECORD) -> Self { + // This is documented here: + // https://learn.microsoft.com/en-us/windows/console/input-record-str + match rec.EventType as u32 { + Console::FOCUS_EVENT => { + unsafe { + let event = rec.Event.FocusEvent; + Event::Focus(event.bSetFocus.as_bool()) + } + } + Console::MENU_EVENT => { + // The Event member contains a MENU_EVENT_RECORD structure. These events are + // used internally and should be ignored. + unsafe { + let event = rec.Event.MenuEvent; + debug!("Menu Event: {:?}", event); + } + Event::Menu + } + Console::KEY_EVENT => { + // https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes + unsafe { + let event = rec.Event.KeyEvent; + // pub struct KEY_EVENT_RECORD { + // pub bKeyDown: super::super::Foundation::BOOL, + // pub wRepeatCount: u16, + // pub wVirtualKeyCode: u16, + // pub wVirtualScanCode: u16, + // pub uChar: KEY_EVENT_RECORD_0, + // pub dwControlKeyState: u32, + // } + let mstate = event.dwControlKeyState; + + Event::Key(key::Event{ + down: event.bKeyDown.as_bool(), + repeats: event.wRepeatCount, + code: event.wVirtualKeyCode, + alt: mstate & ALT_KEYS > 0, + ctrl: mstate & CTRL_KEYS > 0, + shift: mstate & SHIFT_PRESSED > 0, + }) + } + } + Console::MOUSE_EVENT => { + Event::Mouse + } + Console::WINDOW_BUFFER_SIZE_EVENT => { + Event::Size + } + _ => { unreachable!() } + } + } +} diff --git a/src/key.rs b/src/key.rs new file mode 100644 index 0000000..0845aba --- /dev/null +++ b/src/key.rs @@ -0,0 +1,209 @@ +type Code = u16; + +#[derive(Debug)] +pub struct Event { + pub down: bool, + pub repeats: u16, + pub code: Code, + pub alt: bool, + pub ctrl: bool, + pub shift: bool, +} + +macro_rules! keycodes { + ($($c:literal $n:ident $x:literal)*) => {$( + #[allow(dead_code)] + pub const $n: Code = $c; + )*}; +} + +keycodes!{ + 0x08 BACKSPACE '⌫' + 0x09 TAB '↹' + // 0x0A-0B Reserved + // 0x0C CLEAR + 0x0D ENTER '↩' + // 0x0E-0F Undefined + 0x10 SHIFT '⇧' + 0x11 CTRL '⎈' + 0x12 ALT '⎇' + 0x13 BREAK '⎉' + 0x14 CAPS_LOCK '⇪' + // 0x15 IME Kana mode + // 0x15 IME Hanguel mode (maintained for compatibility; use VK_HANGUL) + // 0x15 IME Hangul mode + // 0x16 IME On + // 0x17 IME Junja mode + // 0x18 IME final mode + // 0x19 IME Hanja mode + // 0x19 IME Kanji mode + // 0x1A IME Off + // 0x1C IME convert + 0x1B ESC '⎋' + 0x20 SPACE '␣' + 0x23 END '⇲' + 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' + 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' + // 0x70 F1 + // 0x71 F2 + // 0x72 F3 + // 0x73 F4 + // 0x74 F5 + // 0x75 F6 + // 0x76 F7 + // 0x77 F8 + // 0x78 F9 + // 0x79 F10 + // 0x7A F11 + // 0x7B F12 + // 0x7C F13 + // 0x7D F14 + // 0x7E F15 + // 0x7F F16 + // 0x80 F17 + // 0x81 F18 + // 0x82 F19 + // 0x83 F20 + // 0x84 F21 + // 0x85 F22 + // 0x86 F23 + // 0x87 F24 + 0x21 PAGE_UP '↟' + 0x22 PAGE_DOWN '↡' + 0x25 LEFT '←' + 0x26 UP '↑' + 0x27 RIGHT '→' + 0x28 DOWN '↓' + 0xA0 LEFT_SHIFT '⇧' + 0xA1 RIGHT_SHIFT '⇧' +} + +/* +VK_NONCONVERT 0x1D IME nonconvert +VK_ACCEPT 0x1E IME accept +VK_MODECHANGE 0x1F IME mode change request +VK_HOME 0x24 HOME key +VK_SELECT 0x29 SELECT key +VK_PRINT 0x2A PRINT key +VK_EXECUTE 0x2B EXECUTE key +VK_SNAPSHOT 0x2C PRINT SCREEN key +VK_INSERT 0x2D INS key +VK_DELETE 0x2E DEL key +VK_HELP 0x2F HELP key +- 0x3A-40 Undefined +VK_LWIN 0x5B Left Windows key (Natural keyboard) +VK_RWIN 0x5C Right Windows key (Natural keyboard) +VK_APPS 0x5D Applications key (Natural keyboard) +- 0x5E Reserved +VK_SLEEP 0x5F Computer Sleep key +VK_NUMPAD0 0x60 Numeric keypad 0 key +VK_NUMPAD1 0x61 Numeric keypad 1 key +VK_NUMPAD2 0x62 Numeric keypad 2 key +VK_NUMPAD3 0x63 Numeric keypad 3 key +VK_NUMPAD4 0x64 Numeric keypad 4 key +VK_NUMPAD5 0x65 Numeric keypad 5 key +VK_NUMPAD6 0x66 Numeric keypad 6 key +VK_NUMPAD7 0x67 Numeric keypad 7 key +VK_NUMPAD8 0x68 Numeric keypad 8 key +VK_NUMPAD9 0x69 Numeric keypad 9 key +VK_MULTIPLY 0x6A Multiply key +VK_ADD 0x6B Add key +VK_SEPARATOR 0x6C Separator key +VK_SUBTRACT 0x6D Subtract key +VK_DECIMAL 0x6E Decimal key +VK_DIVIDE 0x6F Divide key +- 0x88-8F Unassigned +VK_NUMLOCK 0x90 NUM LOCK key +VK_SCROLL 0x91 SCROLL LOCK key + 0x92-96 OEM specific +- 0x97-9F Unassigned +VK_LCONTROL 0xA2 Left CONTROL key +VK_RCONTROL 0xA3 Right CONTROL key +VK_LMENU 0xA4 Left ALT key +VK_RMENU 0xA5 Right ALT key +VK_BROWSER_BACK 0xA6 Browser Back key +VK_BROWSER_FORWARD 0xA7 Browser Forward key +VK_BROWSER_REFRESH 0xA8 Browser Refresh key +VK_BROWSER_STOP 0xA9 Browser Stop key +VK_BROWSER_SEARCH 0xAA Browser Search key +VK_BROWSER_FAVORITES 0xAB Browser Favorites key +VK_BROWSER_HOME 0xAC Browser Start and Home key +VK_VOLUME_MUTE 0xAD Volume Mute key +VK_VOLUME_DOWN 0xAE Volume Down key +VK_VOLUME_UP 0xAF Volume Up key +VK_MEDIA_NEXT_TRACK 0xB0 Next Track key +VK_MEDIA_PREV_TRACK 0xB1 Previous Track key +VK_MEDIA_STOP 0xB2 Stop Media key +VK_MEDIA_PLAY_PAUSE 0xB3 Play/Pause Media key +VK_LAUNCH_MAIL 0xB4 Start Mail key +VK_LAUNCH_MEDIA_SELECT 0xB5 Select Media key +VK_LAUNCH_APP1 0xB6 Start Application 1 key +VK_LAUNCH_APP2 0xB7 Start Application 2 key +- 0xB8-B9 Reserved +VK_OEM_1 0xBA Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ';:' key +VK_OEM_PLUS 0xBB For any country/region, the '+' key +VK_OEM_COMMA 0xBC For any country/region, the ',' key +VK_OEM_MINUS 0xBD For any country/region, the '-' key +VK_OEM_PERIOD 0xBE For any country/region, the '.' key +VK_OEM_2 0xBF Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '/?' key +VK_OEM_3 0xC0 Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '`~' key +- 0xC1-D7 Reserved +- 0xD8-DA Unassigned +VK_OEM_4 0xDB Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '[{' key +VK_OEM_5 0xDC Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '\|' key +VK_OEM_6 0xDD Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ']}' key +VK_OEM_7 0xDE Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the 'single-quote/double-quote' key +VK_OEM_8 0xDF Used for miscellaneous characters; it can vary by keyboard. +- 0xE0 Reserved + 0xE1 OEM specific +VK_OEM_102 0xE2 The <> keys on the US standard keyboard, or the \\| key on the non-US 102-key keyboard + 0xE3-E4 OEM specific +VK_PROCESSKEY 0xE5 IME PROCESS key + 0xE6 OEM specific +VK_PACKET 0xE7 Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP +- 0xE8 Unassigned + 0xE9-F5 OEM specific +VK_ATTN 0xF6 Attn key +VK_CRSEL 0xF7 CrSel key +VK_EXSEL 0xF8 ExSel key +VK_EREOF 0xF9 Erase EOF key +VK_PLAY 0xFA Play key +VK_ZOOM 0xFB Zoom key +VK_NONAME 0xFC Reserved +VK_PA1 0xFD PA1 key +VK_OEM_CLEAR 0xFE Clear key +*/ diff --git a/src/main.rs b/src/main.rs index c14ba15..07f9591 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ mod line; mod log; mod input; mod prompt; +mod key; use line::Line; use prompt::Prompt; @@ -149,7 +150,14 @@ fn main() -> Result<()> { prompt.print()?; loop { let rec = input.next()?; + let event: input::Event = rec.into(); debug!("Event Type: {}", rec.EventType); + if let input::Event::Key(event) = &event { + debug!("Key Event: {:?}", event); + if event.code == key::ENTER { + debug!("ENTER!!!"); + } + } match rec.EventType as u32 { Console::FOCUS_EVENT => { // The Event member contains a FOCUS_EVENT_RECORD structure. These events are