minicrossterm/crossterm_input/src/input/unix_input.rs
2019-04-05 15:44:39 +02:00

124 lines
3.5 KiB
Rust

//! This is a UNIX specific implementation for input related action.
use super::*;
use crate::sys::unix::{get_tty, read_char, read_char_raw};
use crossterm_utils::{csi, write, TerminalOutput};
use std::char;
use std::io::Read;
pub struct UnixInput;
impl UnixInput {
pub fn new() -> UnixInput {
UnixInput {}
}
}
impl ITerminalInput for UnixInput {
fn read_char(&self, stdout: &Option<&Arc<TerminalOutput>>) -> io::Result<char> {
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) -> AsyncReader {
AsyncReader::new(Box::new(move |event_tx, cancellation_token| {
for i in get_tty().unwrap().bytes() {
if event_tx.send(i.unwrap()).is_err() {
return;
}
if cancellation_token.load(Ordering::SeqCst) {
return;
}
}
}))
}
fn read_sync(&self) -> SyncReader {
SyncReader {
bytes: Box::new(get_tty().unwrap().bytes().flatten()),
}
}
fn read_until_async(&self, delimiter: u8) -> AsyncReader {
AsyncReader::new(Box::new(move |event_tx, cancellation_token| {
for byte in get_tty().unwrap().bytes() {
let byte = byte.unwrap();
let end_of_stream = byte == delimiter;
let send_error = event_tx.send(byte).is_err();
if end_of_stream || send_error || cancellation_token.load(Ordering::SeqCst) {
return;
}
}
}))
}
fn enable_mouse_mode(&self, stdout: &Option<&Arc<TerminalOutput>>) -> io::Result<()> {
write(
stdout,
format!(
"{}h{}h{}h{}h",
csi!("?1000"),
csi!("?1002"),
csi!("?1015"),
csi!("?1006")
),
)?;
Ok(())
}
fn disable_mouse_mode(&self, stdout: &Option<&Arc<TerminalOutput>>) -> io::Result<()> {
write(
stdout,
format!(
"{}l{}l{}l{}l",
csi!("?1006"),
csi!("?1015"),
csi!("?1002"),
csi!("?1000")
),
)?;
Ok(())
}
}
/// This type allows you to read input synchronously, which means that reading call will be blocking ones.
///
/// This type is an iterator, and could be used to iterate over input events.
///
/// If you don't want to block your calls use [AsyncReader](./LINK), which will read input on the background and queue it for you to read.
pub struct SyncReader {
bytes: Box<Iterator<Item = u8>>,
}
impl Iterator for SyncReader {
type Item = InputEvent;
/// Read input from the user.
///
/// If there are no keys pressed this will be a blocking call until there are.
/// This will return `None` in case of a failure and `Some(InputEvent) in case of an occurred input event.`
fn next(&mut self) -> Option<Self::Item> {
let mut iterator = self.bytes.as_mut();
match iterator.next() {
Some(byte) => {
if let Ok(event) = parse_event(byte, &mut iterator) {
Some(event)
} else {
None
}
}
None => None,
}
}
}