mirror of
https://github.com/Xyverle/neutuino.git
synced 2026-06-26 22:23:14 -04:00
Many Changes
This commit is contained in:
@@ -38,7 +38,7 @@ fn main() -> io::Result<()> {
|
||||
COLORS_BG[next(counter)]
|
||||
));
|
||||
// q to quit
|
||||
if input == Event::Key(Key::Char('q'), KeyType::Press, KeyModifiers::none()) {
|
||||
if input == Event::Key(Key::Char('q'), KeyType::Press, KeyMods::NONE) {
|
||||
break;
|
||||
}
|
||||
counter = next(counter);
|
||||
|
||||
92
src/ansi.rs
92
src/ansi.rs
@@ -12,6 +12,21 @@ pub use crate::unix::enable_ansi;
|
||||
#[cfg(windows)]
|
||||
pub use crate::windows::enable_ansi;
|
||||
|
||||
fn alt_screen(bool: bool) -> std::io::Result<()> {
|
||||
if bool {
|
||||
print!("{ALT_SCREEN_ENTER}");
|
||||
} else {
|
||||
print!("{ALT_SCREEN_EXIT}");
|
||||
}
|
||||
io::stdout().flush()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates a handler for the alt screen
|
||||
pub fn alt_screen_handler() -> io::Result<crate::Handler> {
|
||||
crate::Handler::new(&alt_screen)
|
||||
}
|
||||
|
||||
/// Sets the terminal to an arbitrary 12-bit/truecolor color in the foreground when printed
|
||||
#[must_use]
|
||||
pub fn rgb_color_code_fg(red: u8, green: u8, blue: u8) -> String {
|
||||
@@ -86,6 +101,11 @@ pub fn move_cursor_to_position(column: u16, line: u16) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
// /// Enables mouse input
|
||||
// pub const ENABLE_MOUSE: &str = "\x1b[?1000h\x1b[?1002h\x1b[?1015h\x1b[?1006h";
|
||||
// /// Disables mouse input
|
||||
// pub const DISABLE_MOUSE: &str = "\x1b[?1006l\x1b[?1015l\x1b[?1002l\x1b[?1000l"";
|
||||
|
||||
/// Saves the current cursor position
|
||||
pub const CURSOR_POSITION_SAVE: &str = "\x1b7";
|
||||
/// Restores the saved cursor position
|
||||
@@ -256,75 +276,3 @@ pub const COLORS: [(&str, &str); 9] = [
|
||||
(COLOR_WHITE_FG, COLOR_WHITE_BG),
|
||||
(COLOR_DEFAULT_FG, COLOR_DEFAULT_BG),
|
||||
];
|
||||
|
||||
/// Struct that prints `ALT_SCREEN_ENTER` on construction
|
||||
/// and `ALT_SCREEN_EXIT` on destruction
|
||||
///
|
||||
/// Prefered over function as it prints `ALT_SCREEN_EXIT` on panic
|
||||
pub struct AltScreenHandler {
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
impl AltScreenHandler {
|
||||
/// Creates a new instance and sets the terminal into the alternate screen
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If it fails to print or flush the output
|
||||
pub fn new() -> io::Result<Self> {
|
||||
print!("{ALT_SCREEN_ENTER}");
|
||||
io::stdout().flush()?;
|
||||
Ok(Self { enabled: true })
|
||||
}
|
||||
/// Enables raw mode
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Never errors if the alt screen is already enabled
|
||||
///
|
||||
/// If it fails to print or flush the output
|
||||
pub fn enable(&mut self) -> io::Result<()> {
|
||||
self.set(true)
|
||||
}
|
||||
/// Disables raw mode
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Never errors if the alt screen is already disabled
|
||||
///
|
||||
/// If it fails to print or flush the output
|
||||
pub fn disable(&mut self) -> io::Result<()> {
|
||||
self.set(false)
|
||||
}
|
||||
/// Sets raw mode
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Never errors if the alt screen is in the same state as the boolean
|
||||
///
|
||||
/// If it fails to print or flush the output
|
||||
pub fn set(&mut self, alt: bool) -> io::Result<()> {
|
||||
if self.enabled == alt {
|
||||
return Ok(());
|
||||
}
|
||||
if alt {
|
||||
print!("{ALT_SCREEN_ENTER}");
|
||||
} else {
|
||||
print!("{ALT_SCREEN_EXIT}");
|
||||
}
|
||||
io::stdout().flush()?;
|
||||
self.enabled = alt;
|
||||
Ok(())
|
||||
}
|
||||
/// Gets if the alt screen is enabled
|
||||
#[must_use]
|
||||
pub fn get(&self) -> bool {
|
||||
self.enabled
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AltScreenHandler {
|
||||
fn drop(&mut self) {
|
||||
self.disable().expect("Failed to disable alternate screen");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,80 +10,16 @@ pub use crate::unix::{disable_raw_mode, enable_raw_mode, get_terminal_size};
|
||||
#[cfg(windows)]
|
||||
pub use crate::windows::{disable_raw_mode, enable_raw_mode, get_terminal_size};
|
||||
|
||||
/// Struct that calls `enable_raw_mode` on construction
|
||||
/// and `disable_raw_mode` on destruction
|
||||
///
|
||||
/// Prefered over function as it calls `disable_raw_mode` on panic
|
||||
pub struct RawModeHandler {
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
impl RawModeHandler {
|
||||
/// Creates a new instance and sets the terminal to raw mode
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If there is no stdin,
|
||||
/// stdin is not a tty,
|
||||
/// or it fails to change terminal settings
|
||||
pub fn new() -> io::Result<Self> {
|
||||
fn raw_mode(bool: bool) -> std::io::Result<()> {
|
||||
if bool {
|
||||
enable_raw_mode()?;
|
||||
Ok(Self { enabled: true })
|
||||
}
|
||||
/// Enables raw mode
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Never errors if raw mode is already enabled
|
||||
///
|
||||
/// If there is no stdin,
|
||||
/// stdin is not a tty,
|
||||
/// or it fails to change terminal settings
|
||||
pub fn enable(&mut self) -> io::Result<()> {
|
||||
self.set(true)
|
||||
}
|
||||
/// Disables raw mode
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Never errors if raw mode is already disabled
|
||||
///
|
||||
/// If there is no stdin,
|
||||
/// stdin is not a tty,
|
||||
/// or it fails to change terminal settings
|
||||
pub fn disable(&mut self) -> io::Result<()> {
|
||||
self.set(false)
|
||||
}
|
||||
/// Sets raw mode
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Never errors if raw mode is in the same state as the boolean
|
||||
///
|
||||
/// If there is no stdin,
|
||||
/// stdin is not a tty,
|
||||
/// or it fails to change terminal settings
|
||||
pub fn set(&mut self, raw: bool) -> io::Result<()> {
|
||||
if self.enabled == raw {
|
||||
return Ok(());
|
||||
}
|
||||
if raw {
|
||||
enable_raw_mode()?;
|
||||
} else {
|
||||
disable_raw_mode()?;
|
||||
}
|
||||
self.enabled = raw;
|
||||
Ok(())
|
||||
}
|
||||
/// Gets if raw mode is enabled
|
||||
#[must_use]
|
||||
pub fn get(&self) -> bool {
|
||||
self.enabled
|
||||
} else {
|
||||
disable_raw_mode()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Drop for RawModeHandler {
|
||||
fn drop(&mut self) {
|
||||
self.disable().expect("Failed to disable terminal raw mode");
|
||||
}
|
||||
/// Creates a handler for raw mode
|
||||
pub fn raw_mode_handler() -> io::Result<crate::Handler> {
|
||||
crate::Handler::new(&raw_mode)
|
||||
}
|
||||
|
||||
63
src/input.rs
63
src/input.rs
@@ -12,7 +12,7 @@
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Event {
|
||||
/// An event that happens upon a key being pressed
|
||||
Key(Key, KeyType, KeyModifiers),
|
||||
Key(Key, KeyType, KeyMods),
|
||||
/// 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
|
||||
@@ -52,54 +52,47 @@ pub enum Key {
|
||||
Char(char),
|
||||
/// The Escape key
|
||||
Escape,
|
||||
/// A null byte sent to the terminal
|
||||
///
|
||||
/// Can mean several different things
|
||||
Null,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
pub struct KeyModifiers {
|
||||
pub struct KeyMods {
|
||||
pub shift: bool,
|
||||
pub alt: bool,
|
||||
pub ctrl: bool,
|
||||
pub meta: bool,
|
||||
}
|
||||
|
||||
impl KeyModifiers {
|
||||
impl KeyMods {
|
||||
pub const NONE: Self = Self {
|
||||
shift: false,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
meta: false,
|
||||
};
|
||||
pub const SHIFT: Self = Self::NONE.shift(true);
|
||||
pub const ALT: Self = Self::NONE.alt(true);
|
||||
pub const CTRL: Self = Self::NONE.ctrl(true);
|
||||
pub const META: Self = Self::NONE.meta(true);
|
||||
#[must_use]
|
||||
pub const fn none() -> Self {
|
||||
Self {
|
||||
shift: false,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
meta: false,
|
||||
}
|
||||
pub const fn shift(mut self, on: bool) -> Self {
|
||||
self.shift = on;
|
||||
self
|
||||
}
|
||||
#[must_use]
|
||||
pub const fn shift(self) -> Self {
|
||||
let mut value = self;
|
||||
value.shift = true;
|
||||
value
|
||||
pub const fn alt(mut self, on: bool) -> Self {
|
||||
self.alt = on;
|
||||
self
|
||||
}
|
||||
#[must_use]
|
||||
pub const fn alt(self) -> Self {
|
||||
let mut value = self;
|
||||
value.alt = true;
|
||||
value
|
||||
pub const fn ctrl(mut self, on: bool) -> Self {
|
||||
self.ctrl = on;
|
||||
self
|
||||
}
|
||||
#[must_use]
|
||||
pub const fn ctrl(self) -> Self {
|
||||
let mut value = self;
|
||||
value.ctrl = true;
|
||||
value
|
||||
}
|
||||
#[must_use]
|
||||
pub const fn meta(self) -> Self {
|
||||
let mut value = self;
|
||||
value.meta = true;
|
||||
value
|
||||
pub const fn meta(mut self, on: bool) -> Self {
|
||||
self.meta = on;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +106,10 @@ pub enum KeyType {
|
||||
Release,
|
||||
}
|
||||
|
||||
pub fn press_key(key: Key, key_mods: KeyMods) -> Event {
|
||||
Event::Key(key, KeyType::Press, key_mods)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub use crate::unix::poll_input;
|
||||
|
||||
|
||||
63
src/lib.rs
63
src/lib.rs
@@ -40,6 +40,8 @@
|
||||
//!
|
||||
//! \* Do not have full support for advanced input
|
||||
|
||||
use std::io;
|
||||
|
||||
#[cfg(unix)]
|
||||
mod unix;
|
||||
|
||||
@@ -56,3 +58,64 @@ pub mod prelude {
|
||||
pub use crate::control::*;
|
||||
pub use crate::input::*;
|
||||
}
|
||||
|
||||
/// Struct that calls `func(true)` on construction
|
||||
/// and `func(false)` on destruction
|
||||
pub struct Handler {
|
||||
enabled: bool,
|
||||
func: &'static dyn Fn(bool) -> io::Result<()>,
|
||||
}
|
||||
|
||||
impl Handler {
|
||||
/// Creates a new instance and turns it on
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If the function errors
|
||||
pub fn new(func: &'static dyn Fn(bool) -> io::Result<()>) -> io::Result<Self> {
|
||||
let mut handler = Self {
|
||||
enabled: true,
|
||||
func,
|
||||
};
|
||||
handler.set(true)?;
|
||||
return Ok(handler);
|
||||
}
|
||||
/// Calls `func(true)`
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If the function errors
|
||||
pub fn enable(&mut self) -> io::Result<()> {
|
||||
self.set(true)
|
||||
}
|
||||
/// Calls `func(false)`
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If the function errors
|
||||
pub fn disable(&mut self) -> io::Result<()> {
|
||||
self.set(false)
|
||||
}
|
||||
/// Calls `func(set)`
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If the function errors
|
||||
pub fn set(&mut self, set: bool) -> io::Result<()> {
|
||||
if self.enabled != set {
|
||||
(self.func)(set)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
/// Gets if it is enabled
|
||||
#[must_use]
|
||||
pub fn get(&self) -> bool {
|
||||
self.enabled
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Handler {
|
||||
fn drop(&mut self) {
|
||||
self.disable().expect("Failed to disable terminal raw mode");
|
||||
}
|
||||
}
|
||||
|
||||
147
src/unix.rs
147
src/unix.rs
@@ -2,7 +2,7 @@ use std::ffi::{c_int, c_uint, c_ulong, c_ushort};
|
||||
use std::io;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use crate::input::{Event, Key, KeyModifiers, KeyType};
|
||||
use crate::input::{Event, Key, KeyMods, KeyType, press_key};
|
||||
use std::ffi::{c_short, c_void};
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -133,6 +133,41 @@ pub fn get_terminal_size() -> io::Result<(u16, u16)> {
|
||||
}
|
||||
}
|
||||
|
||||
// Some of this input code has been modified from [termion](https://github.com/redox-os/termion)
|
||||
|
||||
/// Attempts to fetch input from stdin
|
||||
///
|
||||
/// # Errors
|
||||
/// If the timeout has expired or
|
||||
/// there was an error getting the data
|
||||
pub fn poll_input(timeout: Duration) -> io::Result<Event> {
|
||||
let mut fds = [PollFD {
|
||||
fd: STDIN_FILENO,
|
||||
events: POLLIN,
|
||||
revents: 0,
|
||||
}];
|
||||
let result = unsafe {
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
poll(
|
||||
fds.as_mut_ptr(),
|
||||
fds.len() as c_ulong,
|
||||
timeout.as_millis() as c_int,
|
||||
)
|
||||
};
|
||||
let mut read_iter = ReadIterator::new(STDIN_FILENO);
|
||||
|
||||
let timed_out: io::Error = io::ErrorKind::TimedOut.into();
|
||||
|
||||
match result {
|
||||
1.. => {
|
||||
let item = read_iter.next().ok_or(timed_out)??;
|
||||
try_parse_event(item, &mut read_iter)
|
||||
}
|
||||
0 => Err(timed_out),
|
||||
_ => Err(io::Error::last_os_error()),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
fn poll(fds: *mut PollFD, nfds: c_ulong, timeout: c_int) -> c_int;
|
||||
fn read(fd: c_int, buf: *mut c_void, count: c_ulong) -> c_short;
|
||||
@@ -171,87 +206,25 @@ impl Iterator for ReadIterator {
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to fetch input from stdin
|
||||
///
|
||||
/// # Errors
|
||||
/// If the timeout has expired or
|
||||
/// there was an error getting the data
|
||||
pub fn poll_input(timeout: Duration) -> io::Result<Event> {
|
||||
let mut fds = [PollFD {
|
||||
fd: STDIN_FILENO,
|
||||
events: POLLIN,
|
||||
revents: 0,
|
||||
}];
|
||||
let result = unsafe {
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
poll(
|
||||
fds.as_mut_ptr(),
|
||||
fds.len() as c_ulong,
|
||||
timeout.as_millis() as c_int,
|
||||
)
|
||||
};
|
||||
let mut read_iter = ReadIterator::new(STDIN_FILENO);
|
||||
|
||||
let timed_out: io::Error = io::ErrorKind::TimedOut.into();
|
||||
|
||||
match result {
|
||||
1.. => {
|
||||
let item = read_iter.next().ok_or(timed_out)??;
|
||||
try_parse_event(item, &mut read_iter)
|
||||
}
|
||||
0 => Err(timed_out),
|
||||
_ => Err(io::Error::last_os_error()),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_parse_event<I>(item: u8, iter: &mut I) -> io::Result<Event>
|
||||
where
|
||||
I: Iterator<Item = io::Result<u8>>,
|
||||
{
|
||||
match item {
|
||||
b'\x1b' => try_parse_ansi_sequence(iter),
|
||||
b'\r' => Ok(Event::Key(
|
||||
Key::Char('\n'),
|
||||
KeyType::Press,
|
||||
KeyModifiers::none(),
|
||||
)),
|
||||
b'\n' => Ok(Event::Key(
|
||||
Key::Char('j'),
|
||||
KeyType::Press,
|
||||
KeyModifiers::none().ctrl(),
|
||||
)),
|
||||
b'\t' => Ok(Event::Key(
|
||||
Key::Char('\t'),
|
||||
KeyType::Press,
|
||||
KeyModifiers::none(),
|
||||
)),
|
||||
b'\x7f' => Ok(Event::Key(
|
||||
Key::Backspace,
|
||||
KeyType::Press,
|
||||
KeyModifiers::none(),
|
||||
)),
|
||||
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(
|
||||
Key::Char((c + 24) as char),
|
||||
KeyType::Press,
|
||||
KeyModifiers::none().ctrl(),
|
||||
)),
|
||||
b'\r' => Ok(press_key(Key::Char('\r'), KeyMods::NONE)),
|
||||
b'\n' => Ok(press_key(Key::Char('j'), KeyMods::CTRL)),
|
||||
b'\t' => Ok(press_key(Key::Char('\t'), KeyMods::NONE)),
|
||||
b'\x7f' => Ok(press_key(Key::Backspace, KeyMods::NONE)),
|
||||
b'\0' => Ok(press_key(Key::Char(' '), KeyMods::CTRL)),
|
||||
c @ b'\x01'..=b'\x1a' => Ok(press_key(Key::Char((c + 96) as char), KeyMods::CTRL)),
|
||||
c @ b'\x1c'..=b'\x1f' => Ok(press_key(Key::Char((c + 24) as char), KeyMods::CTRL)),
|
||||
c => {
|
||||
let character = parse_utf8_char(c, iter)?;
|
||||
Ok(Event::Key(
|
||||
Key::Char(parse_utf8_char(c, iter)?),
|
||||
Key::Char(character),
|
||||
KeyType::Press,
|
||||
KeyModifiers {
|
||||
shift: character.is_uppercase(),
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
meta: false,
|
||||
},
|
||||
KeyMods::NONE.shift(character.is_uppercase()),
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -280,11 +253,7 @@ where
|
||||
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(
|
||||
Key::F(1 + val - b'P'),
|
||||
KeyType::Press,
|
||||
KeyModifiers::none(),
|
||||
)),
|
||||
Some(Ok(val @ b'P'..=b's')) => Ok(press_key(Key::F(1 + val - b'P'), KeyMods::NONE)),
|
||||
_ => Err(error),
|
||||
},
|
||||
Some(Ok(b'[')) => try_parse_csi_sequence(iter).ok_or(error),
|
||||
@@ -298,24 +267,16 @@ where
|
||||
{
|
||||
match iter.next() {
|
||||
Some(Ok(b'[')) => match iter.next() {
|
||||
Some(Ok(val @ b'A'..=b'E')) => Some(Event::Key(
|
||||
Key::F(1 + val - b'A'),
|
||||
KeyType::Press,
|
||||
KeyModifiers::none(),
|
||||
)),
|
||||
Some(Ok(val @ b'A'..=b'E')) => Some(press_key(Key::F(1 + val - b'A'), KeyMods::NONE)),
|
||||
_ => None,
|
||||
},
|
||||
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().shift(),
|
||||
)),
|
||||
Some(Ok(b'D')) => Some(press_key(Key::Left, KeyMods::NONE)),
|
||||
Some(Ok(b'C')) => Some(press_key(Key::Right, KeyMods::NONE)),
|
||||
Some(Ok(b'A')) => Some(press_key(Key::Up, KeyMods::NONE)),
|
||||
Some(Ok(b'B')) => Some(press_key(Key::Down, KeyMods::NONE)),
|
||||
Some(Ok(b'H')) => Some(press_key(Key::Home, KeyMods::NONE)),
|
||||
Some(Ok(b'F')) => Some(press_key(Key::End, KeyMods::NONE)),
|
||||
Some(Ok(b'Z')) => Some(press_key(Key::Tab, KeyMods::SHIFT)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::input::{Event, Key, KeyModifiers, KeyType};
|
||||
use crate::input::{Event, Key, KeyMods, KeyType, press_key};
|
||||
use std::os::windows::raw::HANDLE;
|
||||
use std::{io, mem, time::Duration};
|
||||
|
||||
@@ -16,6 +16,7 @@ unsafe extern "system" {
|
||||
const STD_INPUT_HANDLE: i32 = -10;
|
||||
const STD_OUTPUT_HANDLE: i32 = -11;
|
||||
const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 4;
|
||||
const ENABLE_VIRTUAL_TERMINAL_INPUT: u32 = 0x200;
|
||||
const ENABLE_ECHO_INPUT: u32 = 4;
|
||||
const ENABLE_LINE_INPUT: u32 = 2;
|
||||
const ENABLE_PROCESSED_INPUT: u32 = 1;
|
||||
@@ -112,6 +113,12 @@ pub fn enable_ansi() -> io::Result<()> {
|
||||
get_console_mode(handle, &mut mode)?;
|
||||
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
set_console_mode(handle, mode)?;
|
||||
|
||||
let handle = get_stdin_handle()?;
|
||||
let mut mode = 0;
|
||||
get_console_mode(handle, &mut mode)?;
|
||||
mode &= !ENABLE_VIRTUAL_TERMINAL_INPUT;
|
||||
set_console_mode(handle, mode)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -237,40 +244,36 @@ fn parse_key_event(event: &KeyEventRecord) -> Event {
|
||||
let shift = event.control_key_state & 0x0010 != 0; // SHIFT_PRESSED
|
||||
|
||||
match event.virtual_key_code {
|
||||
0x08 => Event::Key(Key::Backspace, KeyType::Press, KeyModifiers::none()),
|
||||
0x08 => press_key(Key::Backspace, KeyMods::NONE),
|
||||
0x09 => {
|
||||
if shift {
|
||||
Event::Key(Key::Tab, KeyType::Press, KeyModifiers::none().shift())
|
||||
press_key(Key::Tab, KeyMods::SHIFT)
|
||||
} else {
|
||||
Event::Key(Key::Tab, KeyType::Press, KeyModifiers::none())
|
||||
press_key(Key::Tab, KeyMods::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()),
|
||||
0x0D => press_key(Key::Char('\n'), KeyMods::NONE),
|
||||
0x1B => press_key(Key::Escape, KeyMods::NONE),
|
||||
0x21 => press_key(Key::PageUp, KeyMods::NONE),
|
||||
0x22 => press_key(Key::PageDown, KeyMods::NONE),
|
||||
0x23 => press_key(Key::End, KeyMods::NONE),
|
||||
0x24 => press_key(Key::Home, KeyMods::NONE),
|
||||
0x25 => press_key(Key::Left, KeyMods::NONE),
|
||||
0x26 => press_key(Key::Up, KeyMods::NONE),
|
||||
0x27 => press_key(Key::Right, KeyMods::NONE),
|
||||
0x28 => press_key(Key::Down, KeyMods::NONE),
|
||||
0x2D => press_key(Key::Insert, KeyMods::NONE),
|
||||
0x2E => press_key(Key::Delete, KeyMods::NONE),
|
||||
// I don't think anybody is going to try to press F256 clippy
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
0x70..=0x87 => Event::Key(
|
||||
Key::F((event.virtual_key_code - 0x6F) as u8),
|
||||
KeyType::Press,
|
||||
KeyModifiers::none(),
|
||||
), // F1-F24
|
||||
0x70..=0x87 => press_key(Key::F(event.virtual_key_code - 0x6F) as u8), KeyMods::NONE),
|
||||
_ => {
|
||||
let num = u32::from(unsafe { event.u_char.unicode_char });
|
||||
let c = char::from_u32(num).unwrap_or(' ');
|
||||
if ctrl && c.is_ascii_alphabetic() {
|
||||
Event::Key(Key::Char(c), KeyType::Press, KeyModifiers::none().ctrl())
|
||||
press_key(Key::Char(c), KeyMods::CTRL)
|
||||
} else {
|
||||
Event::Key(Key::Char(c), KeyType::Press, KeyModifiers::none())
|
||||
press_key(Key::Char(c), KeyMods::NONE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user