From 8ffdb00b10f1eb99bb3cb64d719c1026eb8a48c5 Mon Sep 17 00:00:00 2001 From: scauligi Date: Sat, 16 Feb 2019 01:50:42 -0800 Subject: [PATCH] Raw `read_char` for unix (#89) --- crossterm_input/src/input/unix_input.rs | 15 +++++++-- crossterm_input/src/sys/unix.rs | 44 +++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/crossterm_input/src/input/unix_input.rs b/crossterm_input/src/input/unix_input.rs index b7b5cfe..abd0427 100644 --- a/crossterm_input/src/input/unix_input.rs +++ b/crossterm_input/src/input/unix_input.rs @@ -1,7 +1,7 @@ //! This is a UNIX specific implementation for input related action. use super::*; -use crate::sys::unix::{get_tty, read_char}; +use crate::sys::unix::{get_tty, read_char, read_char_raw}; use crossterm_utils::TerminalOutput; use std::char; @@ -16,8 +16,17 @@ impl UnixInput { } impl ITerminalInput for UnixInput { - fn read_char(&self, __stdout: &Option<&Arc>) -> io::Result { - read_char() + fn read_char(&self, stdout: &Option<&Arc>) -> io::Result { + let is_raw_screen = match stdout { + Some(output) => output.is_in_raw_mode, + None => false, + }; + + if is_raw_screen { + read_char_raw() + } else { + read_char() + } } fn read_async(&self, __stdout: &Option<&Arc>) -> AsyncReader { diff --git a/crossterm_input/src/sys/unix.rs b/crossterm_input/src/sys/unix.rs index e9c45c6..892ad2a 100644 --- a/crossterm_input/src/sys/unix.rs +++ b/crossterm_input/src/sys/unix.rs @@ -68,3 +68,47 @@ pub fn read_char() -> io::Result { rv } + +fn get_tty_fd() -> io::Result { + let fd = unsafe { + if libc::isatty(libc::STDIN_FILENO) == 1 { + libc::STDIN_FILENO + } else { + let tty_f = fs::File::open("/dev/tty")?; + tty_f.as_raw_fd() + } + }; + Ok(fd) +} + +pub fn read_char_raw() -> io::Result { + let mut buf = [0u8; 20]; + + let fd = get_tty_fd()?; + + // read input and convert it to char + let rv = unsafe { + let read = libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void, 20); + + if read < 0 { + Err(io::Error::last_os_error()) + } else { + let mut pressed_char = Ok(' '); + + if let Ok(s) = ::std::str::from_utf8(&buf[..read as usize]) { + if let Some(c) = s.chars().next() { + pressed_char = Ok(c); + } + } else { + pressed_char = Err(io::Error::new( + io::ErrorKind::Interrupted, + "Could not parse char to utf8 char", + )); + } + + pressed_char + } + }; + + rv +}