From 160414819e004341a15afc8cae31a14cd7f0484c Mon Sep 17 00:00:00 2001 From: Xyverle Date: Sun, 22 Jun 2025 12:13:03 -0400 Subject: [PATCH] Finish stuff up --- README.md | 3 +- examples/input.rs | 4 +-- src/input.rs | 16 ++------- src/unix.rs | 89 ++++++++++++++++------------------------------- src/windows.rs | 46 +++++++++++++----------- 5 files changed, 61 insertions(+), 97 deletions(-) diff --git a/README.md b/README.md index 5eda69c..18fcb27 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ This project is still highly work in progress and it will be a decent while unti - [x] Output (Unix) - [x] Output (Windows) - [x] Input (Unix) (Appears to work, more testing needed) -- [ ] Input (Windows) (WIP) +- [x] Input (Windows) (Appears to work, more testing needed) +- [ ] Input (Kitty) - [ ] Events (Focus reporting, Bracketed-paste) (Unix) - [ ] Events (Focus reporting, Bracketed-paste) (Windows) - [ ] Mouse input (Unix) diff --git a/examples/input.rs b/examples/input.rs index 5a9b29a..b097b5e 100644 --- a/examples/input.rs +++ b/examples/input.rs @@ -1,8 +1,8 @@ #![warn(clippy::all, clippy::pedantic)] use neutuino::prelude::*; -use std::{io, time::Duration}; use std::io::IsTerminal; +use std::{io, time::Duration}; fn print_line_style_reset(string: &str) { println!("{}{}{}", string, STYLE_RESET, move_cursor_to_column(0)); @@ -38,7 +38,7 @@ fn main() -> io::Result<()> { COLORS_BG[next(counter)] )); // q to quit - if input == Event::Key(KeyEvent::Char('q')) { + if input == Event::Key(Key::Char('q'), KeyType::Press, KeyModifiers::none()) { break; } counter = next(counter); diff --git a/src/input.rs b/src/input.rs index 2754c18..226e5ac 100644 --- a/src/input.rs +++ b/src/input.rs @@ -12,18 +12,14 @@ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum Event { /// An event that happens upon a key being pressed - Key(KeyEvent), + Key(Key, KeyType, KeyModifiers), /// An event that happens upon focus to the terminal window being gained FocusGained, /// An event that happens upon focus to the terminal window being lost FocusLost, } -/// An event that happens upon a key being pressed -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct KeyEvent(pub Key, pub KeyType, pub KeyModifiers); - -/// An event that happens upon a key being pressed +/// The base key that was pressed #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum Key { /// The Backspace key @@ -46,8 +42,6 @@ pub enum Key { PageDown, /// The Tab key Tab, - /// Shift + Tab key - ShiftTab, /// The delete key Delete, /// The insert key @@ -119,12 +113,6 @@ pub enum KeyType { Release, } -impl From for Event { - fn from(value: KeyEvent) -> Self { - Self::Key(value) - } -} - #[cfg(unix)] pub use crate::unix::input::*; diff --git a/src/unix.rs b/src/unix.rs index 775a2da..2e97d6f 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -11,7 +11,6 @@ unsafe extern "C" { const STDIN_FILENO: c_int = 0; const STDOUT_FILENO: c_int = 1; const POLLIN: c_short = 1; -const ICRNL: c_uint = 0x40; #[cfg(not(target_os = "macos"))] const TIOCGWINSZ: c_ulong = 0x5413; @@ -146,7 +145,7 @@ pub mod os { pub mod input { use super::{POLLIN, STDIN_FILENO}; - use crate::input::{Event, Key, KeyEvent, KeyModifiers, KeyType}; + use crate::input::{Event, Key, KeyModifiers, KeyType}; use std::ffi::{c_int, c_short, c_ulong, c_void}; use std::io; use std::time::Duration; @@ -228,44 +227,40 @@ pub mod input { { match item { b'\x1b' => try_parse_ansi_sequence(iter), - b'\r' => Ok(Event::Key(KeyEvent( + b'\r' => Ok(Event::Key( Key::Char('\n'), KeyType::Press, KeyModifiers::none(), - ))), - b'\n' => Ok(Event::Key(KeyEvent( + )), + b'\n' => Ok(Event::Key( Key::Char('j'), KeyType::Press, KeyModifiers::none().ctrl(), - ))), - b'\t' => Ok(Event::Key(KeyEvent( + )), + b'\t' => Ok(Event::Key( Key::Char('\t'), KeyType::Press, KeyModifiers::none(), - ))), - b'\x7f' => Ok(Event::Key(KeyEvent( + )), + b'\x7f' => Ok(Event::Key( Key::Backspace, KeyType::Press, KeyModifiers::none(), - ))), - b'\0' => Ok(Event::Key(KeyEvent( - Key::Null, - KeyType::Press, - KeyModifiers::none(), - ))), - c @ b'\x01'..=b'\x1a' => Ok(Event::Key(KeyEvent( + )), + b'\0' => Ok(Event::Key(Key::Null, KeyType::Press, KeyModifiers::none())), + c @ b'\x01'..=b'\x1a' => Ok(Event::Key( Key::Char((c + 96) as char), KeyType::Press, KeyModifiers::none().ctrl(), - ))), - c @ b'\x1c'..=b'\x1f' => Ok(Event::Key(KeyEvent( + )), + c @ b'\x1c'..=b'\x1f' => Ok(Event::Key( Key::Char((c + 24) as char), KeyType::Press, KeyModifiers::none().ctrl(), - ))), + )), c => { let character = parse_utf8_char(c, iter)?; - Ok(Event::Key(KeyEvent( + Ok(Event::Key( Key::Char(parse_utf8_char(c, iter)?), KeyType::Press, KeyModifiers { @@ -274,7 +269,7 @@ pub mod input { ctrl: false, meta: false, }, - ))) + )) } } } @@ -302,11 +297,11 @@ pub mod input { let error = io::Error::other("Could not parse event"); match iter.next() { Some(Ok(b'O')) => match iter.next() { - Some(Ok(val @ b'P'..=b's')) => Ok(Event::Key(KeyEvent( + Some(Ok(val @ b'P'..=b's')) => Ok(Event::Key( Key::F(1 + val - b'P'), KeyType::Press, KeyModifiers::none(), - ))), + )), _ => Err(error), }, Some(Ok(b'[')) => try_parse_csi_sequence(iter).ok_or(error), @@ -320,48 +315,24 @@ pub mod input { { match iter.next() { Some(Ok(b'[')) => match iter.next() { - Some(Ok(val @ b'A'..=b'E')) => Some(Event::Key(KeyEvent( + Some(Ok(val @ b'A'..=b'E')) => Some(Event::Key( Key::F(1 + val - b'A'), KeyType::Press, KeyModifiers::none(), - ))), + )), _ => None, }, - Some(Ok(b'D')) => Some(Event::Key(KeyEvent( - Key::Left, + Some(Ok(b'D')) => Some(Event::Key(Key::Left, KeyType::Press, KeyModifiers::none())), + Some(Ok(b'C')) => Some(Event::Key(Key::Right, KeyType::Press, KeyModifiers::none())), + Some(Ok(b'A')) => Some(Event::Key(Key::Up, KeyType::Press, KeyModifiers::none())), + Some(Ok(b'B')) => Some(Event::Key(Key::Down, KeyType::Press, KeyModifiers::none())), + Some(Ok(b'H')) => Some(Event::Key(Key::Home, KeyType::Press, KeyModifiers::none())), + Some(Ok(b'F')) => Some(Event::Key(Key::End, KeyType::Press, KeyModifiers::none())), + Some(Ok(b'Z')) => Some(Event::Key( + Key::Tab, KeyType::Press, - KeyModifiers::none(), - ))), - Some(Ok(b'C')) => Some(Event::Key(KeyEvent( - Key::Right, - KeyType::Press, - KeyModifiers::none(), - ))), - Some(Ok(b'A')) => Some(Event::Key(KeyEvent( - Key::Up, - KeyType::Press, - KeyModifiers::none(), - ))), - Some(Ok(b'B')) => Some(Event::Key(KeyEvent( - Key::Down, - KeyType::Press, - KeyModifiers::none(), - ))), - Some(Ok(b'H')) => Some(Event::Key(KeyEvent( - Key::Home, - KeyType::Press, - KeyModifiers::none(), - ))), - Some(Ok(b'F')) => Some(Event::Key(KeyEvent( - Key::End, - KeyType::Press, - KeyModifiers::none(), - ))), - Some(Ok(b'Z')) => Some(Event::Key(KeyEvent( - Key::ShiftTab, - KeyType::Press, - KeyModifiers::none(), - ))), + KeyModifiers::none().shift(), + )), _ => None, } } diff --git a/src/windows.rs b/src/windows.rs index 670e7b2..a8418f8 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -148,7 +148,7 @@ pub mod os { pub mod input { use super::get_stdin_handle; - use crate::input::{Event, KeyEvent, Key, KeyModifiers, KeyType}; + use crate::input::{Event, Key, KeyModifiers, KeyType}; use std::os::windows::raw::HANDLE; use std::{io, mem, time::Duration}; @@ -241,7 +241,7 @@ pub mod input { // more this will have to do return Err(io::ErrorKind::Other.into()); } - Ok(Event::Key(parse_key_event(&key_event))) + Ok(parse_key_event(&key_event)) } _ => { //TODO Make this better @@ -250,41 +250,45 @@ pub mod input { } } - fn parse_key_event(event: &KeyEventRecord) -> KeyEvent { + fn parse_key_event(event: &KeyEventRecord) -> Event { let ctrl = event.control_key_state & (0x0008 | 0x0004) != 0; // LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED let shift = event.control_key_state & 0x0010 != 0; // SHIFT_PRESSED match event.virtual_key_code { - 0x08 => KeyEvent(Key::Backspace, KeyType::Press, KeyModifiers::none()), + 0x08 => Event::Key(Key::Backspace, KeyType::Press, KeyModifiers::none()), 0x09 => { if shift { - KeyEvent(Key::ShiftTab, KeyType::Press, KeyModifiers::none().shift()) + Event::Key(Key::Tab, KeyType::Press, KeyModifiers::none().shift()) } else { - KeyEvent(Key::Tab, KeyType::Press, KeyModifiers::none()) + Event::Key(Key::Tab, KeyType::Press, KeyModifiers::none()) } } - 0x0D => KeyEvent(Key::Char('\n'), KeyType::Press, KeyModifiers::none()), - 0x1B => KeyEvent(Key::Escape, KeyType::Press, KeyModifiers::none()), - 0x21 => KeyEvent(Key::PageUp, KeyType::Press, KeyModifiers::none()), - 0x22 => KeyEvent(Key::PageDown, KeyType::Press, KeyModifiers::none()), - 0x23 => KeyEvent(Key::End, KeyType::Press, KeyModifiers::none()), - 0x24 => KeyEvent(Key::Home, KeyType::Press, KeyModifiers::none()), - 0x25 => KeyEvent(Key::Left, KeyType::Press, KeyModifiers::none()), - 0x26 => KeyEvent(Key::Up, KeyType::Press, KeyModifiers::none()), - 0x27 => KeyEvent(Key::Right, KeyType::Press, KeyModifiers::none()), - 0x28 => KeyEvent(Key::Down, KeyType::Press, KeyModifiers::none()), - 0x2D => KeyEvent(Key::Insert, KeyType::Press, KeyModifiers::none()), - 0x2E => KeyEvent(Key::Delete, KeyType::Press, KeyModifiers::none()), + 0x0D => Event::Key(Key::Char('\n'), KeyType::Press, KeyModifiers::none()), + 0x1B => Event::Key(Key::Escape, KeyType::Press, KeyModifiers::none()), + 0x21 => Event::Key(Key::PageUp, KeyType::Press, KeyModifiers::none()), + 0x22 => Event::Key(Key::PageDown, KeyType::Press, KeyModifiers::none()), + 0x23 => Event::Key(Key::End, KeyType::Press, KeyModifiers::none()), + 0x24 => Event::Key(Key::Home, KeyType::Press, KeyModifiers::none()), + 0x25 => Event::Key(Key::Left, KeyType::Press, KeyModifiers::none()), + 0x26 => Event::Key(Key::Up, KeyType::Press, KeyModifiers::none()), + 0x27 => Event::Key(Key::Right, KeyType::Press, KeyModifiers::none()), + 0x28 => Event::Key(Key::Down, KeyType::Press, KeyModifiers::none()), + 0x2D => Event::Key(Key::Insert, KeyType::Press, KeyModifiers::none()), + 0x2E => Event::Key(Key::Delete, KeyType::Press, KeyModifiers::none()), // I don't think anybody is going to try to press F256 clippy #[allow(clippy::cast_possible_truncation)] - 0x70..=0x87 => KeyEvent(Key::F((event.virtual_key_code - 0x6F) as u8), KeyType::Press, KeyModifiers::none()), // F1-F24 + 0x70..=0x87 => Event::Key( + Key::F((event.virtual_key_code - 0x6F) as u8), + KeyType::Press, + KeyModifiers::none(), + ), // F1-F24 _ => { let c = char::from_u32(u32::from(unsafe { event.u_char.unicode_char })).unwrap_or(' '); if ctrl && c.is_ascii_alphabetic() { - KeyEvent(Key::Char(c), KeyType::Press, KeyModifiers::none().ctrl()) + Event::Key(Key::Char(c), KeyType::Press, KeyModifiers::none().ctrl()) } else { - KeyEvent(Key::Char(c), KeyType::Press, KeyModifiers::none()) + Event::Key(Key::Char(c), KeyType::Press, KeyModifiers::none()) } } }