cleaning up

parse-tree
Jordan Orelli 2 years ago
parent 79e41a376a
commit 755e16d045

@ -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<Console::INPUT_RECORD> 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!() }
}
}
}

@ -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, "<S-C-A-{}>", self.char)
} else {
// write!(f, "⇧⎈ {}", self.char)
write!(f, "<S-C-{}>", self.char)
}
} else {
if self.alt {
// write!(f, "⇧⎇ {}", self.char)
write!(f, "<S-A-{}>", self.char)
} else {
write!(f, "<S-{}>", self.char)
}
}
} else {
if self.ctrl {
if self.alt {
// write!(f, "⎈⎇ {}", self.char)
write!(f, "<C-A-{}>", self.char)
} else {
// write!(f, "⎈ {}", self.char)
write!(f, "<C-{}>", self.char)
}
} else {
if self.alt {
// write!(f, "⎇ {}", self.char)
write!(f, "<A-{}>", 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

@ -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 => {},
}
}
}

Loading…
Cancel
Save