From 1db74c81ebf20847b90d585b86ed1314496c7aec Mon Sep 17 00:00:00 2001 From: remgodow Date: Thu, 3 Sep 2020 18:17:18 +0200 Subject: feat(infra): replace termion with Windows compatible crossterm (#179) * Replace termion backend with crossterm, which works on Windows as well. * Remove tui default-features (termion), update unit tests for crossterm. * Fix formatting. --- src/main.rs | 36 ++++++++++++++++++++++++++---------- src/os/shared.rs | 12 ++++++------ src/tests/cases/test_utils.rs | 7 +++++-- src/tests/cases/ui.rs | 27 +++++++++++++++++++++------ src/tests/fakes/fake_input.rs | 2 +- 5 files changed, 59 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 586b9d0..966e871 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,21 +13,20 @@ use network::{ }; use os::OnSigWinch; +use ::crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; +use ::crossterm::terminal; use ::pnet::datalink::{DataLinkReceiver, NetworkInterface}; use ::std::collections::HashMap; use ::std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use ::std::sync::{Arc, Mutex}; use ::std::thread; use ::std::thread::park_timeout; -use ::termion::event::{Event, Key}; use ::tui::backend::Backend; use std::process; -use ::std::io; use ::std::time::{Duration, Instant}; -use ::termion::raw::IntoRawMode; -use ::tui::backend::TermionBackend; +use ::tui::backend::CrosstermBackend; use std::sync::RwLock; use structopt::StructOpt; @@ -87,9 +86,9 @@ fn try_main() -> Result<(), failure::Error> { let terminal_backend = RawTerminalBackend {}; start(terminal_backend, os_input, opts); } else { - match io::stdout().into_raw_mode() { - Ok(stdout) => { - let terminal_backend = TermionBackend::new(stdout); + match terminal::enable_raw_mode() { + Ok(()) => { + let terminal_backend = CrosstermBackend::new(); start(terminal_backend, os_input, opts); } Err(_) => failure::bail!( @@ -250,13 +249,27 @@ where let mut ui = ui.lock().unwrap(); match evt { - Event::Key(Key::Ctrl('c')) | Event::Key(Key::Char('q')) => { + Event::Key(KeyEvent { + modifiers: KeyModifiers::CONTROL, + code: KeyCode::Char('c'), + }) + | Event::Key(KeyEvent { + modifiers: KeyModifiers::NONE, + code: KeyCode::Char('q'), + }) => { running.store(false, Ordering::Release); cleanup(); display_handler.unpark(); + match terminal::disable_raw_mode() { + Ok(_) => {} + Err(_) => println!("Error could not disable raw input"), + } break; } - Event::Key(Key::Char(' ')) => { + Event::Key(KeyEvent { + modifiers: KeyModifiers::NONE, + code: KeyCode::Char(' '), + }) => { let restarting = paused.fetch_xor(true, Ordering::SeqCst); if restarting { *last_start_time.write().unwrap() = Instant::now(); @@ -271,7 +284,10 @@ where display_handler.unpark(); } - Event::Key(Key::Char('\t')) => { + Event::Key(KeyEvent { + modifiers: KeyModifiers::NONE, + code: KeyCode::Tab, + }) => { let paused = paused.load(Ordering::SeqCst); let elapsed_time = elapsed_time( *last_start_time.read().unwrap(), diff --git a/src/os/shared.rs b/src/os/shared.rs index 462f269..7c252bf 100644 --- a/src/os/shared.rs +++ b/src/os/shared.rs @@ -1,9 +1,9 @@ +use ::crossterm::event::read; +use ::crossterm::event::Event; use ::pnet::datalink::Channel::Ethernet; use ::pnet::datalink::DataLinkReceiver; use ::pnet::datalink::{self, Config, NetworkInterface}; -use ::std::io::{self, stdin, ErrorKind, Write}; -use ::termion::event::Event; -use ::termion::input::TermRead; +use ::std::io::{self, ErrorKind, Write}; use ::tokio::runtime::Runtime; use ::std::time; @@ -25,9 +25,9 @@ pub struct KeyboardEvents; impl Iterator for KeyboardEvents { type Item = Event; fn next(&mut self) -> Option { - match stdin().events().next() { - Some(Ok(ev)) => Some(ev), - _ => None, + match read() { + Ok(ev) => Some(ev), + Err(_) => None, } } } diff --git a/src/tests/cases/test_utils.rs b/src/tests/cases/test_utils.rs index 50cd30e..7982a2d 100644 --- a/src/tests/cases/test_utils.rs +++ b/src/tests/cases/test_utils.rs @@ -6,7 +6,7 @@ use std::iter; use crate::network::dns::Client; use crate::{Opt, OsInputOutput, RenderOpts}; -use ::termion::event::{Event, Key}; +use ::crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; use packet_builder::*; use pnet::datalink::DataLinkReceiver; use std::collections::HashMap; @@ -19,7 +19,10 @@ use pnet_base::MacAddr; pub fn sleep_and_quit_events(sleep_num: usize) -> Box { let mut events: Vec> = iter::repeat(None).take(sleep_num).collect(); - events.push(Some(Event::Key(Key::Ctrl('c')))); + events.push(Some(Event::Key(KeyEvent { + modifiers: KeyModifiers::CONTROL, + code: KeyCode::Char('c'), + }))); Box::new(KeyboardEvents::new(events)) } diff --git a/src/tests/cases/ui.rs b/src/tests/cases/ui.rs index d3df052..1037a67 100644 --- a/src/tests/cases/ui.rs +++ b/src/tests/cases/ui.rs @@ -12,7 +12,7 @@ use crate::tests::cases::test_utils::{ build_tcp_packet, opts_ui, os_input_output, os_input_output_factory, sample_frames, sleep_and_quit_events, test_backend_factory, }; -use ::termion::event::{Event, Key}; +use ::crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; use pnet::datalink::DataLinkReceiver; use std::iter; @@ -66,11 +66,20 @@ fn pause_by_space() { // sleep for 1s, then press space, sleep for 2s, then quit let mut events: Vec> = iter::repeat(None).take(1).collect(); - events.push(Some(Event::Key(Key::Char(' ')))); + events.push(Some(Event::Key(KeyEvent { + modifiers: KeyModifiers::NONE, + code: KeyCode::Char(' '), + }))); events.push(None); events.push(None); - events.push(Some(Event::Key(Key::Char(' ')))); - events.push(Some(Event::Key(Key::Ctrl('c')))); + events.push(Some(Event::Key(KeyEvent { + modifiers: KeyModifiers::NONE, + code: KeyCode::Char(' '), + }))); + events.push(Some(Event::Key(KeyEvent { + modifiers: KeyModifiers::CONTROL, + code: KeyCode::Char('c'), + }))); let events = Box::new(KeyboardEvents::new(events)); let os_input = os_input_output_factory(network_frames, None, None, events); @@ -116,10 +125,16 @@ fn rearranged_by_tab() { // sleep for 1s, then press tab, sleep for 2s, then quit let mut events: Vec> = iter::repeat(None).take(1).collect(); events.push(None); - events.push(Some(Event::Key(Key::Char('\t')))); + events.push(Some(Event::Key(KeyEvent { + modifiers: KeyModifiers::NONE, + code: KeyCode::Tab, + }))); events.push(None); events.push(None); - events.push(Some(Event::Key(Key::Ctrl('c')))); + events.push(Some(Event::Key(KeyEvent { + modifiers: KeyModifiers::CONTROL, + code: KeyCode::Char('c'), + }))); let events = Box::new(KeyboardEvents::new(events)); let os_input = os_input_output_factory(network_frames, None, None, events); diff --git a/src/tests/fakes/fake_input.rs b/src/tests/fakes/fake_input.rs index b0f7d19..ac6c246 100644 --- a/src/tests/fakes/fake_input.rs +++ b/src/tests/fakes/fake_input.rs @@ -1,11 +1,11 @@ use ::async_trait::async_trait; +use ::crossterm::event::Event; use ::ipnetwork::IpNetwork; use ::pnet::datalink::DataLinkReceiver; use ::pnet::datalink::NetworkInterface; use ::std::collections::HashMap; use ::std::net::{IpAddr, Ipv4Addr, SocketAddr}; use ::std::{thread, time}; -use ::termion::event::Event; use ::tokio::runtime::Runtime; use crate::{ -- cgit v1.2.3