mirror of
https://github.com/Xyverle/neutuino.git
synced 2026-06-26 22:23:14 -04:00
tons of various things but no major changes + rename
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "neutrino"
|
name = "neutuino"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
|
|||||||
19
src/ansi.rs
19
src/ansi.rs
@@ -14,9 +14,12 @@ pub fn rgb_color_code(red: u8, green: u8, blue: u8) -> String {
|
|||||||
///
|
///
|
||||||
/// The title must be only in ASCII characters or **weird** things will happen
|
/// The title must be only in ASCII characters or **weird** things will happen
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn set_window_title(title: [u8; 255]) -> String {
|
pub fn set_window_title<T: Into<String>>(title: T) -> Option<String> {
|
||||||
let title = String::from_utf8_lossy(&title);
|
let title = title.into();
|
||||||
format!("\x1b]0;{title}\x1b\x5c")
|
if title.len() > 255 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(format!("\x1b]0;{title}\x1b\x5c"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves the cursor up {num} characters
|
/// Moves the cursor up {num} characters
|
||||||
@@ -67,6 +70,16 @@ pub fn move_cursor_to_position(column: u16, line: u16) -> String {
|
|||||||
format!("\x1b[{};{}H", line.saturating_add(1), column.saturating_add(1))
|
format!("\x1b[{};{}H", line.saturating_add(1), column.saturating_add(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sends input when terminal is in focus
|
||||||
|
pub const FOCUS_REPORTING_ENABLE: &str = "\x1b[?1004h";
|
||||||
|
/// Stops sending input when terminal is in focus
|
||||||
|
pub const FOCUS_REPORTING_DISABLE: &str = "\x1b[?1004l";
|
||||||
|
|
||||||
|
/// Makes all pasted text treated differently
|
||||||
|
pub const BRACKETED_PASTE_ENABLE: &str = "\x1b[?2004h";
|
||||||
|
/// Disables bracketed paste
|
||||||
|
pub const BRACKETED_PASTE_DISABLE: &str = "\x1b[?2004l";
|
||||||
|
|
||||||
/// Saves the current cursor position
|
/// Saves the current cursor position
|
||||||
pub const CURSOR_POSITION_SAVE: &str = "\x1b7";
|
pub const CURSOR_POSITION_SAVE: &str = "\x1b7";
|
||||||
/// Restores the saved cursor position
|
/// Restores the saved cursor position
|
||||||
|
|||||||
153
src/input.rs
153
src/input.rs
@@ -2,59 +2,106 @@
|
|||||||
//!
|
//!
|
||||||
//! Very incomplete currently
|
//! Very incomplete currently
|
||||||
|
|
||||||
use std::io::{self, Read};
|
|
||||||
use std::sync::mpsc;
|
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
/// An asynchronous reader.
|
// pub(crate) fn parse_event(
|
||||||
///
|
// buffer: &[u8],
|
||||||
/// This acts as any other stream, with the exception that reading from it won't block. Instead,
|
// input_available: bool,
|
||||||
/// the buffer will only be partially updated based on how much the internal buffer holds.
|
// ) -> io::Result<Option<InternalEvent>> {
|
||||||
///
|
// if buffer.is_empty() {
|
||||||
/// Taken from the Termion crate
|
// return Ok(None);
|
||||||
pub struct AsyncReader {
|
// }
|
||||||
recv: mpsc::Receiver<io::Result<u8>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Read for AsyncReader {
|
// match buffer[0] {
|
||||||
/// Read from the byte stream.
|
// b'\x1B' => {
|
||||||
///
|
// if buffer.len() == 1 {
|
||||||
/// This will never block, but try to drain the event queue until empty. If the total number of
|
// if input_available {
|
||||||
/// bytes written is lower than the buffer's length, the event queue is empty or that the event
|
// // Possible Esc sequence
|
||||||
/// stream halted.
|
// Ok(None)
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
// } else {
|
||||||
let mut total = 0;
|
// Ok(Some(InternalEvent::Event(Event::Key(KeyCode::Esc.into()))))
|
||||||
loop {
|
// }
|
||||||
if total >= buf.len() {
|
// } else {
|
||||||
break;
|
// match buffer[1] {
|
||||||
}
|
// b'O' => {
|
||||||
|
// if buffer.len() == 2 {
|
||||||
|
// Ok(None)
|
||||||
|
// } else {
|
||||||
|
// match buffer[2] {
|
||||||
|
// b'D' => {
|
||||||
|
// Ok(Some(InternalEvent::Event(Event::Key(KeyCode::Left.into()))))
|
||||||
|
// }
|
||||||
|
// b'C' => Ok(Some(InternalEvent::Event(Event::Key(
|
||||||
|
// KeyCode::Right.into(),
|
||||||
|
// )))),
|
||||||
|
// b'A' => {
|
||||||
|
// Ok(Some(InternalEvent::Event(Event::Key(KeyCode::Up.into()))))
|
||||||
|
// }
|
||||||
|
// b'B' => {
|
||||||
|
// Ok(Some(InternalEvent::Event(Event::Key(KeyCode::Down.into()))))
|
||||||
|
// }
|
||||||
|
// b'H' => {
|
||||||
|
// Ok(Some(InternalEvent::Event(Event::Key(KeyCode::Home.into()))))
|
||||||
|
// }
|
||||||
|
// b'F' => {
|
||||||
|
// Ok(Some(InternalEvent::Event(Event::Key(KeyCode::End.into()))))
|
||||||
|
// }
|
||||||
|
// // F1-F4
|
||||||
|
// val @ b'P'..=b'S' => Ok(Some(InternalEvent::Event(Event::Key(
|
||||||
|
// KeyCode::F(1 + val - b'P').into(),
|
||||||
|
// )))),
|
||||||
|
// _ => Err(could_not_parse_event_error()),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// b'[' => parse_csi(buffer),
|
||||||
|
// b'\x1B' => Ok(Some(InternalEvent::Event(Event::Key(KeyCode::Esc.into())))),
|
||||||
|
// _ => parse_event(&buffer[1..], input_available).map(|event_option| {
|
||||||
|
// event_option.map(|event| {
|
||||||
|
// if let InternalEvent::Event(Event::Key(key_event)) = event {
|
||||||
|
// let mut alt_key_event = key_event;
|
||||||
|
// alt_key_event.modifiers |= KeyModifiers::ALT;
|
||||||
|
// InternalEvent::Event(Event::Key(alt_key_event))
|
||||||
|
// } else {
|
||||||
|
// event
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// b'\r' => Ok(Some(InternalEvent::Event(Event::Key(
|
||||||
|
// KeyCode::Enter.into(),
|
||||||
|
// )))),
|
||||||
|
// // Issue #371: \n = 0xA, which is also the keycode for Ctrl+J. The only reason we get
|
||||||
|
// // newlines as input is because the terminal converts \r into \n for us. When we
|
||||||
|
// // enter raw mode, we disable that, so \n no longer has any meaning - it's better to
|
||||||
|
// // use Ctrl+J. Waiting to handle it here means it gets picked up later
|
||||||
|
// b'\n' if !crate::terminal::sys::is_raw_mode_enabled() => Ok(Some(InternalEvent::Event(
|
||||||
|
// Event::Key(KeyCode::Enter.into()),
|
||||||
|
// ))),
|
||||||
|
// b'\t' => Ok(Some(InternalEvent::Event(Event::Key(KeyCode::Tab.into())))),
|
||||||
|
// b'\x7F' => Ok(Some(InternalEvent::Event(Event::Key(
|
||||||
|
// KeyCode::Backspace.into(),
|
||||||
|
// )))),
|
||||||
|
// c @ b'\x01'..=b'\x1A' => Ok(Some(InternalEvent::Event(Event::Key(KeyEvent::new(
|
||||||
|
// KeyCode::Char((c - 0x1 + b'a') as char),
|
||||||
|
// KeyModifiers::CONTROL,
|
||||||
|
// ))))),
|
||||||
|
// c @ b'\x1C'..=b'\x1F' => Ok(Some(InternalEvent::Event(Event::Key(KeyEvent::new(
|
||||||
|
// KeyCode::Char((c - 0x1C + b'4') as char),
|
||||||
|
// KeyModifiers::CONTROL,
|
||||||
|
// ))))),
|
||||||
|
// b'\0' => Ok(Some(InternalEvent::Event(Event::Key(KeyEvent::new(
|
||||||
|
// KeyCode::Char(' '),
|
||||||
|
// KeyModifiers::CONTROL,
|
||||||
|
// ))))),
|
||||||
|
// _ => parse_utf8_char(buffer).map(|maybe_char| {
|
||||||
|
// maybe_char
|
||||||
|
// .map(KeyCode::Char)
|
||||||
|
// .map(char_code_to_event)
|
||||||
|
// .map(Event::Key)
|
||||||
|
// .map(InternalEvent::Event)
|
||||||
|
// }),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
match self.recv.try_recv() {
|
|
||||||
Ok(Ok(b)) => {
|
|
||||||
buf[total] = b;
|
|
||||||
total += 1;
|
|
||||||
}
|
|
||||||
Ok(Err(e)) => return Err(e),
|
|
||||||
Err(_) => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(total)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsyncReader {
|
|
||||||
pub fn new<R: Read + Send + 'static>(reader: R) -> Self {
|
|
||||||
let (send, recv) = mpsc::channel();
|
|
||||||
|
|
||||||
thread::spawn(move || {
|
|
||||||
for i in reader.bytes() {
|
|
||||||
if send.send(i).is_err() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Self { recv }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
16
src/input_sequences.md
Normal file
16
src/input_sequences.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
* 0x1b = Escape
|
||||||
|
* 0x1b1b = Escape
|
||||||
|
* 0x1b41 = Up Arrow
|
||||||
|
* 0x1b42 = Down Arrow
|
||||||
|
* 0x1b43 = Right Arrow
|
||||||
|
* 0x1b44 = Left Arrow
|
||||||
|
* 0x1b46 = End
|
||||||
|
* 0x1b48 = Home
|
||||||
|
* 0x1b5b41 = Up Arrow
|
||||||
|
* 0x1b5b42 = Down Arrow
|
||||||
|
* 0x1b5b43 = Right Arrow
|
||||||
|
* 0x1b5b44 = Left Arrow
|
||||||
|
* 0x1b5b46 = End
|
||||||
|
* 0x1b5b48 = Home
|
||||||
|
* 0x20-7e = Char(n)
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#![warn(clippy::all, clippy::pedantic)]
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
|
|
||||||
pub mod ansi;
|
pub mod ansi;
|
||||||
pub mod input;
|
// pub mod input;
|
||||||
pub mod os;
|
pub mod os;
|
||||||
|
|||||||
107
src/unix.rs
107
src/unix.rs
@@ -3,31 +3,26 @@ use std::io;
|
|||||||
|
|
||||||
unsafe extern "C" {
|
unsafe extern "C" {
|
||||||
fn ioctl(fd: c_int, request: c_ulong, argp: *mut u8) -> c_int;
|
fn ioctl(fd: c_int, request: c_ulong, argp: *mut u8) -> c_int;
|
||||||
fn tcgetattr(fd: c_int, termios_p: *mut Termios) -> c_int;
|
safe fn cfmakeraw(termios: *mut Termios);
|
||||||
|
fn tcgetattr(fd: c_int, termios: *mut Termios) -> c_int;
|
||||||
fn tcsetattr(fd: c_int, optional_actions: c_int, termios: *mut Termios) -> c_int;
|
fn tcsetattr(fd: c_int, optional_actions: c_int, termios: *mut Termios) -> c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "redox"))]
|
const STDIN_FILENO: c_int = 0x0;
|
||||||
|
const STDOUT_FILENO: c_int = 0x1;
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
const TIOCGWINSZ: c_ulong = 0x5413;
|
const TIOCGWINSZ: c_ulong = 0x5413;
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
const NCCS: usize = 0x20;
|
||||||
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
|
#[cfg(target_os = "macos")]
|
||||||
const TIOCGWINSZ: c_ulong = 0x40087468;
|
const TIOCGWINSZ: c_ulong = 0x4008_7468;
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
#[cfg(any(target_os = "linux", target_os = "redox"))]
|
const NCCS: usize = 0x14;
|
||||||
const NCCS: usize = 32;
|
|
||||||
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
|
|
||||||
const NCCS: usize = 20;
|
|
||||||
|
|
||||||
const STDIN_FILENO: c_int = 0;
|
|
||||||
const STDOUT_FILENO: c_int = 1;
|
|
||||||
|
|
||||||
const ECHO: c_uint = 8;
|
|
||||||
const ICANON: c_uint = 2;
|
|
||||||
const ISIG: c_uint = 1;
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Default, Debug, Clone, Copy)]
|
||||||
struct Winsize {
|
struct Winsize {
|
||||||
row: c_ushort,
|
row: c_ushort,
|
||||||
col: c_ushort,
|
col: c_ushort,
|
||||||
@@ -36,7 +31,7 @@ struct Winsize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
struct Termios {
|
struct Termios {
|
||||||
iflag: c_uint,
|
iflag: c_uint,
|
||||||
oflag: c_uint,
|
oflag: c_uint,
|
||||||
@@ -45,6 +40,42 @@ struct Termios {
|
|||||||
cc: [u8; NCCS],
|
cc: [u8; NCCS],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This struct represents a raw terminal
|
||||||
|
///
|
||||||
|
/// This struct will automatically enable raw mode when it is created
|
||||||
|
/// and disable raw mode when it is destructed
|
||||||
|
///
|
||||||
|
/// This insures that you never exit with a terminal still in raw mode which is problematic for
|
||||||
|
/// users
|
||||||
|
pub struct RawTerminal {
|
||||||
|
orig_termios: Termios
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawTerminal {
|
||||||
|
/// This constructs a terminal, automatically making it raw
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// If there is no stdin,
|
||||||
|
/// stdin is not a tty,
|
||||||
|
/// if it fails to change terminal settings
|
||||||
|
pub fn new() -> io::Result<Self> {
|
||||||
|
let mut orig_termios = Termios::default();
|
||||||
|
get_attributes(STDIN_FILENO, &mut orig_termios)?;
|
||||||
|
let mut termios = orig_termios.clone();
|
||||||
|
cfmakeraw(&raw mut termios);
|
||||||
|
set_attributes(STDIN_FILENO, &mut termios)?;
|
||||||
|
Ok(Self { orig_termios })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for RawTerminal {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let mut termios = self.orig_termios.clone();
|
||||||
|
set_attributes(STDIN_FILENO, &mut termios).expect("Failed to disable terminal raw mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Enables ANSI support on Windows terminals
|
/// Enables ANSI support on Windows terminals
|
||||||
///
|
///
|
||||||
/// ANSI is on by default on *nix machines but still exists on them for simpler usage
|
/// ANSI is on by default on *nix machines but still exists on them for simpler usage
|
||||||
@@ -72,50 +103,16 @@ pub fn enable_ansi() -> io::Result<()> {
|
|||||||
/// if stdout isn't a TTY, or
|
/// if stdout isn't a TTY, or
|
||||||
/// if it fails to retrieve the terminal size
|
/// if it fails to retrieve the terminal size
|
||||||
pub fn get_terminal_size() -> io::Result<(u16, u16)> {
|
pub fn get_terminal_size() -> io::Result<(u16, u16)> {
|
||||||
let mut winsize = unsafe { std::mem::zeroed::<Winsize>() };
|
let mut winsize = Winsize::default();
|
||||||
let ioctl_result = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, (&raw mut winsize).cast::<u8>()) };
|
let ioctl_result = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, (&raw mut winsize).cast::<u8>()) };
|
||||||
|
|
||||||
if ioctl_result == 0 {
|
if ioctl_result == 0 {
|
||||||
Ok((winsize.col as u16, winsize.row as u16))
|
Ok((winsize.col, winsize.row))
|
||||||
} else {
|
} else {
|
||||||
Err(io::Error::last_os_error())
|
Err(io::Error::last_os_error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enables raw mode
|
|
||||||
///
|
|
||||||
/// Disables input echoing, line feeding, etc.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// If there is no stdout,
|
|
||||||
/// if stdout isn't a TTY, or
|
|
||||||
/// if it fails to get or set terminal settings
|
|
||||||
pub fn enable_raw_mode() -> io::Result<()> {
|
|
||||||
let mut termios = unsafe { std::mem::zeroed::<Termios>() };
|
|
||||||
get_attributes(STDIN_FILENO, &mut termios)?;
|
|
||||||
termios.lflag &= !(ECHO | ISIG | ICANON);
|
|
||||||
set_attributes(STDIN_FILENO, &mut termios)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Disables raw mode
|
|
||||||
///
|
|
||||||
/// Enables input echoing, line feeding, etc.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// If there is no stdout,
|
|
||||||
/// if stdout isn't a TTY, or
|
|
||||||
/// if it fails to get or set terminal settings
|
|
||||||
pub fn disable_raw_mode() -> io::Result<()> {
|
|
||||||
let mut termios = unsafe { std::mem::zeroed::<Termios>() };
|
|
||||||
get_attributes(STDIN_FILENO, &mut termios)?;
|
|
||||||
termios.lflag |= ECHO | ISIG | ICANON;
|
|
||||||
set_attributes(STDIN_FILENO, &mut termios)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_attributes(fd: c_int, termios: &mut Termios) -> io::Result<()> {
|
fn get_attributes(fd: c_int, termios: &mut Termios) -> io::Result<()> {
|
||||||
if unsafe { tcgetattr(fd, &raw mut *termios) } != 0 {
|
if unsafe { tcgetattr(fd, &raw mut *termios) } != 0 {
|
||||||
return Err(io::Error::last_os_error());
|
return Err(io::Error::last_os_error());
|
||||||
|
|||||||
@@ -26,6 +26,43 @@ struct ConsoleScreenBufferInfo {
|
|||||||
_unused: [u16; 9],
|
_unused: [u16; 9],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This struct represents a raw terminal
|
||||||
|
///
|
||||||
|
/// This struct will automatically enable raw mode when it is created
|
||||||
|
/// and disable raw mode when it is destructed
|
||||||
|
///
|
||||||
|
/// This insures that you never exit with a terminal still in raw mode which is problematic for
|
||||||
|
/// users
|
||||||
|
pub struct RawTerminal;
|
||||||
|
|
||||||
|
impl RawTerminal {
|
||||||
|
/// This constructs a terminal, automatically making it raw
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// If there is no stdin,
|
||||||
|
/// stdin is not a tty,
|
||||||
|
/// if it fails to change terminal settings
|
||||||
|
pub fn new() -> io::Result<Self> {
|
||||||
|
let handle = get_std_handle(STD_INPUT_HANDLE)?;
|
||||||
|
let mut mode = 0;
|
||||||
|
get_console_mode(handle, &mut mode)?;
|
||||||
|
mode &= !(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
|
||||||
|
set_console_mode(handle, &mut mode)?;
|
||||||
|
Ok(Self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for RawTerminal {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let handle = get_std_handle(STD_INPUT_HANDLE).expect("Failed to disable terminal raw mode");
|
||||||
|
let mut mode = 0;
|
||||||
|
get_console_mode(handle, &mut mode).expect("Failed to disable terminal raw mode");
|
||||||
|
mode |= ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
|
||||||
|
set_console_mode(handle, &mut mode).expect("Failed to disable terminal raw mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Enables ANSI support on Windows terminals
|
/// Enables ANSI support on Windows terminals
|
||||||
///
|
///
|
||||||
/// ANSI is on by default on *nix machines but still exists on them for simpler usage
|
/// ANSI is on by default on *nix machines but still exists on them for simpler usage
|
||||||
@@ -40,9 +77,9 @@ struct ConsoleScreenBufferInfo {
|
|||||||
pub fn enable_ansi() -> io::Result<()> {
|
pub fn enable_ansi() -> io::Result<()> {
|
||||||
let handle = get_std_handle(STD_OUTPUT_HANDLE)?;
|
let handle = get_std_handle(STD_OUTPUT_HANDLE)?;
|
||||||
let mut mode = 0;
|
let mut mode = 0;
|
||||||
get_console_mode(handle, &raw mut mode)?;
|
get_console_mode(handle, &mut mode)?;
|
||||||
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
set_console_mode(handle, &raw mut mode)?;
|
set_console_mode(handle, &mut mode)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,42 +103,6 @@ pub fn get_terminal_size() -> io::Result<(u16, u16)> {
|
|||||||
Err(io::Error::last_os_error())
|
Err(io::Error::last_os_error())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enables raw mode
|
|
||||||
///
|
|
||||||
/// Disables input echoing, line feeding, etc.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// If there is no stdout,
|
|
||||||
/// if stdout isn't a TTY, or
|
|
||||||
/// if it fails to get or set terminal settings
|
|
||||||
pub fn enable_raw_mode() -> io::Result<()> {
|
|
||||||
let handle = get_std_handle(STD_INPUT_HANDLE)?;
|
|
||||||
let mut mode = 0;
|
|
||||||
get_console_mode(handle, &raw mut mode)?;
|
|
||||||
mode &= !(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
|
|
||||||
set_console_mode(handle, &raw mut mode)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Disables raw mode
|
|
||||||
///
|
|
||||||
/// Enables input echoing, line feeding, etc.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// If there is no stdout,
|
|
||||||
/// if stdout isn't a TTY, or
|
|
||||||
/// if it fails to get or set terminal settings
|
|
||||||
pub fn disable_raw_mode() -> io::Result<()> {
|
|
||||||
let handle = get_std_handle(STD_INPUT_HANDLE)?;
|
|
||||||
let mut mode = 0;
|
|
||||||
get_console_mode(handle, &raw mut mode)?;
|
|
||||||
mode |= ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
|
|
||||||
set_console_mode(handle, &raw mut mode)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_std_handle(handle: u32) -> io::Result<usize> {
|
fn get_std_handle(handle: u32) -> io::Result<usize> {
|
||||||
let handle = unsafe { GetStdHandle(handle) };
|
let handle = unsafe { GetStdHandle(handle) };
|
||||||
if handle == INVALID_HANDLE_VALUE {
|
if handle == INVALID_HANDLE_VALUE {
|
||||||
@@ -111,7 +112,7 @@ fn get_std_handle(handle: u32) -> io::Result<usize> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_console_mode(handle: usize, mode: *mut u32) -> io::Result<()> {
|
fn set_console_mode(handle: usize, mode: &mut u32) -> io::Result<()> {
|
||||||
if unsafe { SetConsoleMode(handle, mode) == 0 } {
|
if unsafe { SetConsoleMode(handle, mode) == 0 } {
|
||||||
Err(io::Error::last_os_error())
|
Err(io::Error::last_os_error())
|
||||||
} else {
|
} else {
|
||||||
@@ -119,7 +120,7 @@ fn set_console_mode(handle: usize, mode: *mut u32) -> io::Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_console_mode(handle: usize, mode: *mut u32) -> io::Result<()> {
|
fn get_console_mode(handle: usize, mode: &mut u32) -> io::Result<()> {
|
||||||
if unsafe { GetConsoleMode(handle, mode) == 0 } {
|
if unsafe { GetConsoleMode(handle, mode) == 0 } {
|
||||||
Err(io::Error::last_os_error())
|
Err(io::Error::last_os_error())
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user