mirror of
https://github.com/Xyverle/neutuino.git
synced 2026-06-26 22:23:14 -04:00
Finish stuff up
This commit is contained in:
@@ -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 (Unix)
|
||||||
- [x] Output (Windows)
|
- [x] Output (Windows)
|
||||||
- [x] Input (Unix) (Appears to work, more testing needed)
|
- [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) (Unix)
|
||||||
- [ ] Events (Focus reporting, Bracketed-paste) (Windows)
|
- [ ] Events (Focus reporting, Bracketed-paste) (Windows)
|
||||||
- [ ] Mouse input (Unix)
|
- [ ] Mouse input (Unix)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#![warn(clippy::all, clippy::pedantic)]
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
|
|
||||||
use neutuino::prelude::*;
|
use neutuino::prelude::*;
|
||||||
use std::{io, time::Duration};
|
|
||||||
use std::io::IsTerminal;
|
use std::io::IsTerminal;
|
||||||
|
use std::{io, time::Duration};
|
||||||
|
|
||||||
fn print_line_style_reset(string: &str) {
|
fn print_line_style_reset(string: &str) {
|
||||||
println!("{}{}{}", string, STYLE_RESET, move_cursor_to_column(0));
|
println!("{}{}{}", string, STYLE_RESET, move_cursor_to_column(0));
|
||||||
@@ -38,7 +38,7 @@ fn main() -> io::Result<()> {
|
|||||||
COLORS_BG[next(counter)]
|
COLORS_BG[next(counter)]
|
||||||
));
|
));
|
||||||
// q to quit
|
// q to quit
|
||||||
if input == Event::Key(KeyEvent::Char('q')) {
|
if input == Event::Key(Key::Char('q'), KeyType::Press, KeyModifiers::none()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
counter = next(counter);
|
counter = next(counter);
|
||||||
|
|||||||
16
src/input.rs
16
src/input.rs
@@ -12,18 +12,14 @@
|
|||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
/// An event that happens upon a key being pressed
|
/// 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
|
/// An event that happens upon focus to the terminal window being gained
|
||||||
FocusGained,
|
FocusGained,
|
||||||
/// An event that happens upon focus to the terminal window being lost
|
/// An event that happens upon focus to the terminal window being lost
|
||||||
FocusLost,
|
FocusLost,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An event that happens upon a key being pressed
|
/// The base key that was 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
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Key {
|
pub enum Key {
|
||||||
/// The Backspace key
|
/// The Backspace key
|
||||||
@@ -46,8 +42,6 @@ pub enum Key {
|
|||||||
PageDown,
|
PageDown,
|
||||||
/// The Tab key
|
/// The Tab key
|
||||||
Tab,
|
Tab,
|
||||||
/// Shift + Tab key
|
|
||||||
ShiftTab,
|
|
||||||
/// The delete key
|
/// The delete key
|
||||||
Delete,
|
Delete,
|
||||||
/// The insert key
|
/// The insert key
|
||||||
@@ -119,12 +113,6 @@ pub enum KeyType {
|
|||||||
Release,
|
Release,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<KeyEvent> for Event {
|
|
||||||
fn from(value: KeyEvent) -> Self {
|
|
||||||
Self::Key(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub use crate::unix::input::*;
|
pub use crate::unix::input::*;
|
||||||
|
|
||||||
|
|||||||
89
src/unix.rs
89
src/unix.rs
@@ -11,7 +11,6 @@ unsafe extern "C" {
|
|||||||
const STDIN_FILENO: c_int = 0;
|
const STDIN_FILENO: c_int = 0;
|
||||||
const STDOUT_FILENO: c_int = 1;
|
const STDOUT_FILENO: c_int = 1;
|
||||||
const POLLIN: c_short = 1;
|
const POLLIN: c_short = 1;
|
||||||
const ICRNL: c_uint = 0x40;
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
const TIOCGWINSZ: c_ulong = 0x5413;
|
const TIOCGWINSZ: c_ulong = 0x5413;
|
||||||
@@ -146,7 +145,7 @@ pub mod os {
|
|||||||
|
|
||||||
pub mod input {
|
pub mod input {
|
||||||
use super::{POLLIN, STDIN_FILENO};
|
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::ffi::{c_int, c_short, c_ulong, c_void};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@@ -228,44 +227,40 @@ pub mod input {
|
|||||||
{
|
{
|
||||||
match item {
|
match item {
|
||||||
b'\x1b' => try_parse_ansi_sequence(iter),
|
b'\x1b' => try_parse_ansi_sequence(iter),
|
||||||
b'\r' => Ok(Event::Key(KeyEvent(
|
b'\r' => Ok(Event::Key(
|
||||||
Key::Char('\n'),
|
Key::Char('\n'),
|
||||||
KeyType::Press,
|
KeyType::Press,
|
||||||
KeyModifiers::none(),
|
KeyModifiers::none(),
|
||||||
))),
|
)),
|
||||||
b'\n' => Ok(Event::Key(KeyEvent(
|
b'\n' => Ok(Event::Key(
|
||||||
Key::Char('j'),
|
Key::Char('j'),
|
||||||
KeyType::Press,
|
KeyType::Press,
|
||||||
KeyModifiers::none().ctrl(),
|
KeyModifiers::none().ctrl(),
|
||||||
))),
|
)),
|
||||||
b'\t' => Ok(Event::Key(KeyEvent(
|
b'\t' => Ok(Event::Key(
|
||||||
Key::Char('\t'),
|
Key::Char('\t'),
|
||||||
KeyType::Press,
|
KeyType::Press,
|
||||||
KeyModifiers::none(),
|
KeyModifiers::none(),
|
||||||
))),
|
)),
|
||||||
b'\x7f' => Ok(Event::Key(KeyEvent(
|
b'\x7f' => Ok(Event::Key(
|
||||||
Key::Backspace,
|
Key::Backspace,
|
||||||
KeyType::Press,
|
KeyType::Press,
|
||||||
KeyModifiers::none(),
|
KeyModifiers::none(),
|
||||||
))),
|
)),
|
||||||
b'\0' => Ok(Event::Key(KeyEvent(
|
b'\0' => Ok(Event::Key(Key::Null, KeyType::Press, KeyModifiers::none())),
|
||||||
Key::Null,
|
c @ b'\x01'..=b'\x1a' => Ok(Event::Key(
|
||||||
KeyType::Press,
|
|
||||||
KeyModifiers::none(),
|
|
||||||
))),
|
|
||||||
c @ b'\x01'..=b'\x1a' => Ok(Event::Key(KeyEvent(
|
|
||||||
Key::Char((c + 96) as char),
|
Key::Char((c + 96) as char),
|
||||||
KeyType::Press,
|
KeyType::Press,
|
||||||
KeyModifiers::none().ctrl(),
|
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),
|
Key::Char((c + 24) as char),
|
||||||
KeyType::Press,
|
KeyType::Press,
|
||||||
KeyModifiers::none().ctrl(),
|
KeyModifiers::none().ctrl(),
|
||||||
))),
|
)),
|
||||||
c => {
|
c => {
|
||||||
let character = parse_utf8_char(c, iter)?;
|
let character = parse_utf8_char(c, iter)?;
|
||||||
Ok(Event::Key(KeyEvent(
|
Ok(Event::Key(
|
||||||
Key::Char(parse_utf8_char(c, iter)?),
|
Key::Char(parse_utf8_char(c, iter)?),
|
||||||
KeyType::Press,
|
KeyType::Press,
|
||||||
KeyModifiers {
|
KeyModifiers {
|
||||||
@@ -274,7 +269,7 @@ pub mod input {
|
|||||||
ctrl: false,
|
ctrl: false,
|
||||||
meta: false,
|
meta: false,
|
||||||
},
|
},
|
||||||
)))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -302,11 +297,11 @@ pub mod input {
|
|||||||
let error = io::Error::other("Could not parse event");
|
let error = io::Error::other("Could not parse event");
|
||||||
match iter.next() {
|
match iter.next() {
|
||||||
Some(Ok(b'O')) => 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'),
|
Key::F(1 + val - b'P'),
|
||||||
KeyType::Press,
|
KeyType::Press,
|
||||||
KeyModifiers::none(),
|
KeyModifiers::none(),
|
||||||
))),
|
)),
|
||||||
_ => Err(error),
|
_ => Err(error),
|
||||||
},
|
},
|
||||||
Some(Ok(b'[')) => try_parse_csi_sequence(iter).ok_or(error),
|
Some(Ok(b'[')) => try_parse_csi_sequence(iter).ok_or(error),
|
||||||
@@ -320,48 +315,24 @@ pub mod input {
|
|||||||
{
|
{
|
||||||
match iter.next() {
|
match iter.next() {
|
||||||
Some(Ok(b'[')) => 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'),
|
Key::F(1 + val - b'A'),
|
||||||
KeyType::Press,
|
KeyType::Press,
|
||||||
KeyModifiers::none(),
|
KeyModifiers::none(),
|
||||||
))),
|
)),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
Some(Ok(b'D')) => Some(Event::Key(KeyEvent(
|
Some(Ok(b'D')) => Some(Event::Key(Key::Left, KeyType::Press, KeyModifiers::none())),
|
||||||
Key::Left,
|
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,
|
KeyType::Press,
|
||||||
KeyModifiers::none(),
|
KeyModifiers::none().shift(),
|
||||||
))),
|
)),
|
||||||
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(),
|
|
||||||
))),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ pub mod os {
|
|||||||
|
|
||||||
pub mod input {
|
pub mod input {
|
||||||
use super::get_stdin_handle;
|
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::os::windows::raw::HANDLE;
|
||||||
use std::{io, mem, time::Duration};
|
use std::{io, mem, time::Duration};
|
||||||
@@ -241,7 +241,7 @@ pub mod input {
|
|||||||
// more this will have to do
|
// more this will have to do
|
||||||
return Err(io::ErrorKind::Other.into());
|
return Err(io::ErrorKind::Other.into());
|
||||||
}
|
}
|
||||||
Ok(Event::Key(parse_key_event(&key_event)))
|
Ok(parse_key_event(&key_event))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
//TODO Make this better
|
//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 ctrl = event.control_key_state & (0x0008 | 0x0004) != 0; // LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED
|
||||||
let shift = event.control_key_state & 0x0010 != 0; // SHIFT_PRESSED
|
let shift = event.control_key_state & 0x0010 != 0; // SHIFT_PRESSED
|
||||||
|
|
||||||
match event.virtual_key_code {
|
match event.virtual_key_code {
|
||||||
0x08 => KeyEvent(Key::Backspace, KeyType::Press, KeyModifiers::none()),
|
0x08 => Event::Key(Key::Backspace, KeyType::Press, KeyModifiers::none()),
|
||||||
0x09 => {
|
0x09 => {
|
||||||
if shift {
|
if shift {
|
||||||
KeyEvent(Key::ShiftTab, KeyType::Press, KeyModifiers::none().shift())
|
Event::Key(Key::Tab, KeyType::Press, KeyModifiers::none().shift())
|
||||||
} else {
|
} 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()),
|
0x0D => Event::Key(Key::Char('\n'), KeyType::Press, KeyModifiers::none()),
|
||||||
0x1B => KeyEvent(Key::Escape, KeyType::Press, KeyModifiers::none()),
|
0x1B => Event::Key(Key::Escape, KeyType::Press, KeyModifiers::none()),
|
||||||
0x21 => KeyEvent(Key::PageUp, KeyType::Press, KeyModifiers::none()),
|
0x21 => Event::Key(Key::PageUp, KeyType::Press, KeyModifiers::none()),
|
||||||
0x22 => KeyEvent(Key::PageDown, KeyType::Press, KeyModifiers::none()),
|
0x22 => Event::Key(Key::PageDown, KeyType::Press, KeyModifiers::none()),
|
||||||
0x23 => KeyEvent(Key::End, KeyType::Press, KeyModifiers::none()),
|
0x23 => Event::Key(Key::End, KeyType::Press, KeyModifiers::none()),
|
||||||
0x24 => KeyEvent(Key::Home, KeyType::Press, KeyModifiers::none()),
|
0x24 => Event::Key(Key::Home, KeyType::Press, KeyModifiers::none()),
|
||||||
0x25 => KeyEvent(Key::Left, KeyType::Press, KeyModifiers::none()),
|
0x25 => Event::Key(Key::Left, KeyType::Press, KeyModifiers::none()),
|
||||||
0x26 => KeyEvent(Key::Up, KeyType::Press, KeyModifiers::none()),
|
0x26 => Event::Key(Key::Up, KeyType::Press, KeyModifiers::none()),
|
||||||
0x27 => KeyEvent(Key::Right, KeyType::Press, KeyModifiers::none()),
|
0x27 => Event::Key(Key::Right, KeyType::Press, KeyModifiers::none()),
|
||||||
0x28 => KeyEvent(Key::Down, KeyType::Press, KeyModifiers::none()),
|
0x28 => Event::Key(Key::Down, KeyType::Press, KeyModifiers::none()),
|
||||||
0x2D => KeyEvent(Key::Insert, KeyType::Press, KeyModifiers::none()),
|
0x2D => Event::Key(Key::Insert, KeyType::Press, KeyModifiers::none()),
|
||||||
0x2E => KeyEvent(Key::Delete, 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
|
// I don't think anybody is going to try to press F256 clippy
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
#[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 =
|
let c =
|
||||||
char::from_u32(u32::from(unsafe { event.u_char.unicode_char })).unwrap_or(' ');
|
char::from_u32(u32::from(unsafe { event.u_char.unicode_char })).unwrap_or(' ');
|
||||||
if ctrl && c.is_ascii_alphabetic() {
|
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 {
|
} else {
|
||||||
KeyEvent(Key::Char(c), KeyType::Press, KeyModifiers::none())
|
Event::Key(Key::Char(c), KeyType::Press, KeyModifiers::none())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user