use super::*;
use crate::sys::unix::{get_tty, read_char_raw};
use crossterm_utils::{csi, write_cout, Result, ErrorKind};
use std::char;
use std::sync::atomic::{AtomicBool, Ordering};
use std::{
io::{Read, Write},
str,
};
use std::{sync::mpsc, thread};
pub struct UnixInput;
impl UnixInput {
pub fn new() -> UnixInput {
UnixInput {}
}
}
impl ITerminalInput for UnixInput {
fn read_char(&self) -> io::Result<char> {
read_char_raw()
}
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_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 read_sync(&self) -> SyncReader {
SyncReader {
source: Box::from(get_tty().unwrap()),
leftover: None,
}
}
fn enable_mouse_mode(&self) -> Result<()> {
write_cout!(&format!(
"{}h{}h{}h{}h",
csi!("?1000"),
csi!("?1002"),
csi!("?1015"),
csi!("?1006")
))?;
Ok(())
}
fn disable_mouse_mode(&self) -> Result<()> {
write_cout!(&format!(
"{}l{}l{}l{}l",
csi!("?1006"),
csi!("?1015"),
csi!("?1002"),
csi!("?1000")
))?;
Ok(())
}
}
pub struct AsyncReader {
event_rx: Receiver<u8>,
shutdown: Arc<AtomicBool>,
}
impl AsyncReader {
pub fn new(function: Box<Fn(&Sender<u8>, &Arc<AtomicBool>) + Send>) -> AsyncReader {
let shutdown_handle = Arc::new(AtomicBool::new(false));
let (event_tx, event_rx) = mpsc::channel();
let thread_shutdown = shutdown_handle.clone();
thread::spawn(move || loop {
function(&event_tx, &thread_shutdown);
});
AsyncReader {
event_rx,
shutdown: shutdown_handle,
}
}
pub fn stop_reading(&mut self) {
self.shutdown.store(true, Ordering::SeqCst);
}
}
impl Iterator for AsyncReader {
type Item = InputEvent;
fn next(&mut self) -> Option<Self::Item> {
let mut iterator = self.event_rx.try_iter();
match iterator.next() {
Some(char_value) => {
if let Ok(char_value) = parse_event(char_value, &mut iterator) {
Some(char_value)
} else {
None
}
}
None => None,
}
}
}
impl Drop for AsyncReader {
fn drop(&mut self) {
self.stop_reading();
}
}
pub struct SyncReader {
source: Box<std::fs::File>,
leftover: Option<u8>,
}
impl Iterator for SyncReader {
type Item = InputEvent;
fn next(&mut self) -> Option<Self::Item> {
let source = &mut self.source;
if let Some(c) = self.leftover {
self.leftover = None;
if let Ok(e) = parse_event(c, &mut source.bytes().flatten()) {
return Some(e);
} else {
return None;
}
}
let mut buf = [0u8; 2];
let res = match source.read(&mut buf) {
Ok(0) => return None,
Ok(1) => match buf[0] {
b'\x1B' => return Some(InputEvent::Keyboard(KeyEvent::Esc)),
c => {
if let Ok(e) = parse_event(c, &mut source.bytes().flatten()) {
return Some(e);
} else {
return None;
}
}
},
Ok(2) => {
let option_iter = &mut Some(buf[1]).into_iter();
let iter = option_iter.map(|c| Ok(c)).chain(source.bytes());
if let Ok(e) = parse_event(buf[0], &mut iter.flatten()) {
self.leftover = option_iter.next();
Some(e)
} else {
None
}
}
Ok(_) => unreachable!(),
Err(_) => return None,
};
res
}
}
pub(crate) fn parse_event<I>(item: u8, iter: &mut I) -> Result<InputEvent>
where
I: Iterator<Item = u8>,
{
let error = ErrorKind::IoError(io::Error::new(
io::ErrorKind::Other,
"Could not parse an event",
));
let input_event = match item {
b'\x1B' => {
let a = iter.next();
match a {
Some(b'O') => {
match iter.next() {
Some(val @ b'P'...b'S') => {
InputEvent::Keyboard(KeyEvent::F(1 + val - b'P'))
}
_ => return Err(error),
}
}
Some(b'[') => {
parse_csi(iter)
}
Some(b'\x1B') => InputEvent::Keyboard(KeyEvent::Esc),
Some(c) => {
let ch = parse_utf8_char(c, iter);
InputEvent::Keyboard(KeyEvent::Alt(ch?))
}
None => InputEvent::Keyboard(KeyEvent::Esc),
}
}
b'\n' | b'\r' => InputEvent::Keyboard(KeyEvent::Char('\n')),
b'\t' => InputEvent::Keyboard(KeyEvent::Char('\t')),
b'\x7F' => InputEvent::Keyboard(KeyEvent::Backspace),
c @ b'\x01'...b'\x1A' => {
InputEvent::Keyboard(KeyEvent::Ctrl((c as u8 - 0x1 + b'a') as char))
}
c @ b'\x1C'...b'\x1F' => {
InputEvent::Keyboard(KeyEvent::Ctrl((c as u8 - 0x1C + b'4') as char))
}
b'\0' => InputEvent::Keyboard(KeyEvent::Null),
c => {
let ch = parse_utf8_char(c, iter);
InputEvent::Keyboard(KeyEvent::Char(ch?))
}
};
Ok(input_event)
}
fn parse_csi<I>(iter: &mut I) -> InputEvent
where
I: Iterator<Item = u8>,
{
match iter.next() {
Some(b'[') => match iter.next() {
Some(val @ b'A'...b'E') => InputEvent::Keyboard(KeyEvent::F(1 + val - b'A')),
_ => InputEvent::Unknown,
},
Some(b'D') => InputEvent::Keyboard(KeyEvent::Left),
Some(b'C') => InputEvent::Keyboard(KeyEvent::Right),
Some(b'A') => InputEvent::Keyboard(KeyEvent::Up),
Some(b'B') => InputEvent::Keyboard(KeyEvent::Down),
Some(b'H') => InputEvent::Keyboard(KeyEvent::Home),
Some(b'F') => InputEvent::Keyboard(KeyEvent::End),
Some(b'Z') => InputEvent::Keyboard(KeyEvent::BackTab),
Some(b'M') => {
let mut next = || iter.next().unwrap();
let cb = next() as i8 - 32;
let cx = next().saturating_sub(32) as u16;
let cy = next().saturating_sub(32) as u16;
InputEvent::Mouse(match cb & 0b11 {
0 => {
if cb & 0x40 != 0 {
MouseEvent::Press(MouseButton::WheelUp, cx, cy)
} else {
MouseEvent::Press(MouseButton::Left, cx, cy)
}
}
1 => {
if cb & 0x40 != 0 {
MouseEvent::Press(MouseButton::WheelDown, cx, cy)
} else {
MouseEvent::Press(MouseButton::Middle, cx, cy)
}
}
2 => MouseEvent::Press(MouseButton::Right, cx, cy),
3 => MouseEvent::Release(cx, cy),
_ => MouseEvent::Unknown,
})
}
Some(b'<') => {
let mut buf = Vec::new();
let mut c = iter.next().unwrap();
while match c {
b'm' | b'M' => false,
_ => true,
} {
buf.push(c);
c = iter.next().unwrap();
}
let str_buf = String::from_utf8(buf).unwrap();
let nums = &mut str_buf.split(';');
let cb = nums.next().unwrap().parse::<u16>().unwrap();
let cx = nums.next().unwrap().parse::<u16>().unwrap();
let cy = nums.next().unwrap().parse::<u16>().unwrap();
match cb {
0...2 | 64...65 => {
let button = match cb {
0 => MouseButton::Left,
1 => MouseButton::Middle,
2 => MouseButton::Right,
64 => MouseButton::WheelUp,
65 => MouseButton::WheelDown,
_ => unreachable!(),
};
match c {
b'M' => InputEvent::Mouse(MouseEvent::Press(button, cx, cy)),
b'm' => InputEvent::Mouse(MouseEvent::Release(cx, cy)),
_ => InputEvent::Unknown,
}
}
32 => InputEvent::Mouse(MouseEvent::Hold(cx, cy)),
3 => InputEvent::Mouse(MouseEvent::Release(cx, cy)),
_ => InputEvent::Unknown,
}
}
Some(c @ b'0'...b'9') => {
let mut buf = Vec::new();
buf.push(c);
let mut character = iter.next().unwrap();
while character < 64 || character > 126 {
buf.push(character);
character = iter.next().unwrap();
}
match character {
b'M' => {
let str_buf = String::from_utf8(buf).unwrap();
let nums: Vec<u16> = str_buf.split(';').map(|n| n.parse().unwrap()).collect();
let cb = nums[0];
let cx = nums[1];
let cy = nums[2];
let event = match cb {
32 => MouseEvent::Press(MouseButton::Left, cx, cy),
33 => MouseEvent::Press(MouseButton::Middle, cx, cy),
34 => MouseEvent::Press(MouseButton::Right, cx, cy),
35 => MouseEvent::Release(cx, cy),
64 => MouseEvent::Hold(cx, cy),
96 | 97 => MouseEvent::Press(MouseButton::WheelUp, cx, cy),
_ => MouseEvent::Unknown,
};
InputEvent::Mouse(event)
}
b'~' => {
let str_buf = String::from_utf8(buf).unwrap();
let nums: Vec<u8> = str_buf.split(';').map(|n| n.parse().unwrap()).collect();
if nums.is_empty() {
return InputEvent::Unknown;
}
if nums.len() > 1 {
return InputEvent::Unknown;
}
match nums[0] {
1 | 7 => InputEvent::Keyboard(KeyEvent::Home),
2 => InputEvent::Keyboard(KeyEvent::Insert),
3 => InputEvent::Keyboard(KeyEvent::Delete),
4 | 8 => InputEvent::Keyboard(KeyEvent::End),
5 => InputEvent::Keyboard(KeyEvent::PageUp),
6 => InputEvent::Keyboard(KeyEvent::PageDown),
v @ 11...15 => InputEvent::Keyboard(KeyEvent::F(v - 10)),
v @ 17...21 => InputEvent::Keyboard(KeyEvent::F(v - 11)),
v @ 23...24 => InputEvent::Keyboard(KeyEvent::F(v - 12)),
_ => InputEvent::Unknown,
}
}
e => match (buf.last().unwrap(), e) {
(53, 65) => InputEvent::Keyboard(KeyEvent::CtrlUp),
(53, 66) => InputEvent::Keyboard(KeyEvent::CtrlDown),
(53, 67) => InputEvent::Keyboard(KeyEvent::CtrlRight),
(53, 68) => InputEvent::Keyboard(KeyEvent::CtrlLeft),
(50, 65) => InputEvent::Keyboard(KeyEvent::ShiftUp),
(50, 66) => InputEvent::Keyboard(KeyEvent::ShiftDown),
(50, 67) => InputEvent::Keyboard(KeyEvent::ShiftRight),
(50, 68) => InputEvent::Keyboard(KeyEvent::ShiftLeft),
_ => InputEvent::Unknown,
},
}
}
_ => InputEvent::Unknown,
}
}
fn parse_utf8_char<I>(c: u8, iter: &mut I) -> Result<char>
where
I: Iterator<Item = u8>,
{
let error = Err(ErrorKind::IoError(io::Error::new(
io::ErrorKind::Other,
"Input character is not valid UTF-8",
)));
if c.is_ascii() {
Ok(c as char)
} else {
let mut bytes = Vec::new();
bytes.push(c);
while let Some(next) = iter.next() {
bytes.push(next);
if let Ok(st) = str::from_utf8(&bytes) {
return Ok(st.chars().next().unwrap());
}
if bytes.len() >= 4 {
return error;
}
}
return error;
}
}
#[cfg(test)]
#[test]
fn test_parse_utf8() {
let st = "abcéŷ¤£€ù%323";
let ref mut bytes = st.bytes().map(|x| Ok(x));
let chars = st.chars();
for c in chars {
let b = bytes.next().unwrap().unwrap();
assert_eq!(c, parse_utf8_char(b, bytes).unwrap());
}
}