From 755e16d045b6fa0a06713a7eda8ccb9a7fb40bca Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Sat, 4 Mar 2023 17:16:38 -0600 Subject: [PATCH] cleaning up --- src/input.rs | 73 +++++++++++---------- src/key.rs | 70 ++++++++++++++++++--- src/main.rs | 175 +++++++++++++++++---------------------------------- 3 files changed, 162 insertions(+), 156 deletions(-) diff --git a/src/input.rs b/src/input.rs index cbad1d5..8813707 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,7 +1,7 @@ +use crate::{error::Error, key, log::*}; use anyhow::{Context, Result}; -use crate::{error::Error, log::*, key}; -use windows::Win32::System::Console; use windows::Win32::Foundation::HANDLE; +use windows::Win32::System::Console; fn log_input_mode(mode: Console::CONSOLE_MODE) { // Characters read by the ReadFile or ReadConsole function are written to the active screen @@ -149,7 +149,11 @@ 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::ReadConsoleInputA(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; } @@ -163,9 +167,12 @@ impl Reader { #[derive(Debug)] pub enum Event { Focus(bool), - Menu, + Menu(u32), Key(key::Event), - Mouse, + Mouse{ + x: i16, + y: i16, + }, Size, } @@ -178,52 +185,52 @@ impl From for Event { // 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::FOCUS_EVENT => unsafe { + let event = rec.Event.FocusEvent; + Event::Focus(event.bSetFocus.as_bool()) + }, + Console::MENU_EVENT => unsafe { + let event = rec.Event.MenuEvent; + Event::Menu(event.dwCommandId) + }, 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; + let c = char::from_u32(event.uChar.UnicodeChar as u32).unwrap_or('๐Ÿ’€'); - Event::Key(key::Event{ + 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, + char: c, }) } } Console::MOUSE_EVENT => { - Event::Mouse + // OK I think it's safe to ignore these events since we're using the terminal + // escape sequences. I think we never see them because terminal.exe is going to + // turn mouse events into virtual terminal sequences anyway + unsafe { + let event = rec.Event.MouseEvent; + // pub dwMousePosition: COORD, i16 i16 + // pub dwButtonState: u32, + // pub dwControlKeyState: u32, + // pub dwEventFlags: u32, + Event::Mouse{ + x: event.dwMousePosition.X, + y: event.dwMousePosition.Y, + } + } } - Console::WINDOW_BUFFER_SIZE_EVENT => { - Event::Size + Console::WINDOW_BUFFER_SIZE_EVENT => Event::Size, + _ => { + unreachable!() } - _ => { unreachable!() } } } } diff --git a/src/key.rs b/src/key.rs index 0845aba..4c617a6 100644 --- a/src/key.rs +++ b/src/key.rs @@ -2,14 +2,70 @@ type Code = u16; #[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 key code for the keyboard event pub code: Code, - pub alt: bool, + + /// The unicode character, or ๐Ÿ’€ if not applicable + 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, } +impl Event {} + +impl std::fmt::Display for Event { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.shift { + if self.ctrl { + if self.alt { + // write!(f, "โ‡งโŽˆโŽ‡ {}", self.char) + write!(f, "", self.char) + } else { + // write!(f, "โ‡งโŽˆ {}", self.char) + write!(f, "", self.char) + } + } else { + if self.alt { + // write!(f, "โ‡งโŽ‡ {}", self.char) + write!(f, "", self.char) + } else { + write!(f, "", self.char) + } + } + } else { + if self.ctrl { + if self.alt { + // write!(f, "โŽˆโŽ‡ {}", self.char) + write!(f, "", self.char) + } else { + // write!(f, "โŽˆ {}", self.char) + write!(f, "", self.char) + } + } else { + if self.alt { + // write!(f, "โŽ‡ {}", self.char) + write!(f, "", self.char) + } else { + write!(f, "{}", self.char) + } + } + } + } +} + macro_rules! keycodes { ($($c:literal $n:ident $x:literal)*) => {$( #[allow(dead_code)] @@ -17,7 +73,7 @@ macro_rules! keycodes { )*}; } -keycodes!{ +keycodes! { 0x08 BACKSPACE 'โŒซ' 0x09 TAB 'โ†น' // 0x0A-0B Reserved @@ -149,7 +205,7 @@ VK_DIVIDE 0x6F Divide key - 0x88-8F Unassigned VK_NUMLOCK 0x90 NUM LOCK key VK_SCROLL 0x91 SCROLL LOCK key - 0x92-96 OEM specific + 0x92-96 OEM specific - 0x97-9F Unassigned VK_LCONTROL 0xA2 Left CONTROL key VK_RCONTROL 0xA3 Right CONTROL key @@ -189,14 +245,14 @@ VK_OEM_6 0xDD Used for miscellaneous characters; it can vary by keyboard. For 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 + 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 + 0xE3-E4 OEM specific VK_PROCESSKEY 0xE5 IME PROCESS key - 0xE6 OEM specific + 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 + 0xE9-F5 OEM specific VK_ATTN 0xF6 Attn key VK_CRSEL 0xF7 CrSel key VK_EXSEL 0xF8 ExSel key diff --git a/src/main.rs b/src/main.rs index 07f9591..13e7898 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,9 @@ mod error; +mod input; +mod key; mod line; mod log; -mod input; mod prompt; -mod key; use line::Line; use prompt::Prompt; @@ -129,6 +129,18 @@ fn setup_stdout() -> Result<()> { Ok(()) } +fn newline(stdout: HANDLE) -> Result<()> { + unsafe { + Error::check(Console::WriteConsoleA( + stdout, + "\r\n".as_bytes(), + None, + None, + ))?; + } + Ok(()) +} + fn main() -> Result<()> { match Log::file("C:\\Users\\JordanOrelli\\wash.log") { Ok(f) => { @@ -151,127 +163,58 @@ fn main() -> Result<()> { 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 - // used internally and should be ignored. - unsafe { - let event = rec.Event.FocusEvent; - debug!("Focus Event: {:?}", event); + match event { + input::Event::Key(event) => { + if event.down { + continue; } - } - 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); + debug!("Key Event: {}", event); + + if event.code == key::ENTER { + newline(stdout)?; + line.print()?; + newline(stdout)?; + prompt.print()?; + line.clear(); + continue; } - } - Console::KEY_EVENT => { - // The Event member contains a KEY_EVENT_RECORD structure with information - // about a keyboard event. - unsafe { - let event = rec.Event.KeyEvent; - let down = event.bKeyDown.as_bool(); - let repeats = event.wRepeatCount; - let key_code = event.wVirtualKeyCode; - let scan_code = event.wVirtualScanCode; - let c = event.uChar.UnicodeChar; - let modifiers = event.dwControlKeyState; - // handle key presses on key up, not key down. This is a little weird but - // it's sending both down and up events when you hit the key anyway. I - // dunno if this is right. But for some reason, the down events don't have - // the modifiers - if !down { - // Carriage Return (Enter key) - if c == 13 { - let mask = Console::LEFT_ALT_PRESSED - | Console::RIGHT_ALT_PRESSED - | Console::LEFT_CTRL_PRESSED - | Console::RIGHT_CTRL_PRESSED - | Console::SHIFT_PRESSED; - if modifiers & mask == 0 { - Error::check(Console::WriteConsoleA( - stdout, - "\r\n".as_bytes(), - None, - None, - ))?; - line.print()?; - Error::check(Console::WriteConsoleA( - stdout, - "\r\n".as_bytes(), - None, - None, - ))?; - prompt.print()?; - line.clear(); - } - } else if key_code == 68 - && (modifiers & Console::LEFT_CTRL_PRESSED - == Console::LEFT_CTRL_PRESSED) - { - // this is CTRL+D - CloseHandle(stdout); - return Ok(()); - } else if key_code == 74 - && (modifiers & Console::LEFT_CTRL_PRESSED - == Console::LEFT_CTRL_PRESSED) - { - // red bullet - let text = "\x1b[31m\u{2022}\x1b[0m"; - Error::check(Console::WriteConsoleA( - stdout, - text.as_bytes(), - None, - None, - ))?; - } else { - if let Some(c) = char::from_u32(event.uChar.UnicodeChar as u32) { - if !c.is_control() { - let mut buf = [0 as u8; 8]; - let s = c.encode_utf8(&mut buf); - s.chars().for_each(|c| line.append(c)); - Error::check(Console::WriteConsoleW( - stdout, - s.as_bytes(), - None, - None, - ))?; - } - } - } + + if event.ctrl && event.code == key::D { + unsafe { + CloseHandle(stdout); } - debug!( - "Key Event: down: {down:?} repeats: {repeats} key-code: {key_code} scan-code: {scan_code} char: {c} modifiers: {modifiers}" - ); + return Ok(()); } - } - Console::MOUSE_EVENT => { - // The Event member contains a MOUSE_EVENT_RECORD structure with information - // about a mouse movement or button press event. - unsafe { - let event = rec.Event.MouseEvent; - debug!("Mouse Event: {:?}", event); + + if event.ctrl && event.code == key::J { + // red bullet + unsafe { + let text = "\x1b[31m\u{2022}\x1b[0m"; + Error::check(Console::WriteConsoleA(stdout, text.as_bytes(), None, None))?; + } + continue; } - } - Console::WINDOW_BUFFER_SIZE_EVENT => { - // The Event member contains a WINDOW_BUFFER_SIZE_RECORD structure with - // information about the new size of the console screen buffer. - unsafe { - let event = rec.Event.WindowBufferSizeEvent; - debug!("Window Buffer Event: {:?}", event); + + if !event.char.is_control() { + let mut buf = [0 as u8; 8]; + let s = event.char.encode_utf8(&mut buf); + s.chars().for_each(|c| line.append(c)); + unsafe { + Error::check(Console::WriteConsoleW( + stdout, + s.as_bytes(), + None, + None, + ))?; + } + continue; } } - _ => {} + input::Event::Focus(true) => {}, + input::Event::Focus(false) => {}, + input::Event::Menu(_command_id) => {}, + input::Event::Mouse{..} => {}, + input::Event::Size => {}, } } }