From 0a1b53111627206cc7436589e5b7212e1b72edb8 Mon Sep 17 00:00:00 2001 From: Jack Wills <32690432+mrjackwills@users.noreply.github.com> Date: Thu, 2 Mar 2023 01:09:17 +0000 Subject: [PATCH] feat: Acutal fix the the mouse events output The EnableMouseCapture from Crossterm was too broad, by only enabling a subject of the events, 1) performance is improvedand 2) and intermittent bug where mouse events were output to stdout has been removed --- containerised/Dockerfile_dev | 2 +- src/docker_data/mod.rs | 4 ++-- src/input_handler/mod.rs | 23 ++++++++--------------- src/main.rs | 13 ------------- src/ui/mod.rs | 33 +++++++++++++++++++++------------ 5 files changed, 32 insertions(+), 43 deletions(-) diff --git a/containerised/Dockerfile_dev b/containerised/Dockerfile_dev index 88accee..6ff45ba 100644 --- a/containerised/Dockerfile_dev +++ b/containerised/Dockerfile_dev @@ -14,7 +14,7 @@ COPY ./target/x86_64-unknown-linux-musl/release/oxker /app/ ENTRYPOINT [ "/app/oxker"] # Dev build for testing -# docker build -t oxker_dev -f Dockerfile . && docker run --rm -it --volume /var/run/docker.sock:/var/run/docker.sock:ro oxker_dev +# docker build -t oxker_dev -f containerised/Dockerfile_dev . && docker run --rm -it --volume /var/run/docker.sock:/var/run/docker.sock:ro oxker_dev # Dev build one liner, x86 host # docker image prune -a; cargo build --release --target x86_64-unknown-linux-musl && docker build -t oxker_dev -f containerised/Dockerfile_dev . && docker run --rm -it --volume /var/run/docker.sock:/var/run/docker.sock:ro oxker_dev diff --git a/src/docker_data/mod.rs b/src/docker_data/mod.rs index 4e7923b..51b955e 100644 --- a/src/docker_data/mod.rs +++ b/src/docker_data/mod.rs @@ -16,7 +16,6 @@ use crate::{ app_data::{AppData, ContainerId, DockerControls}, app_error::AppError, parse_args::CliArgs, - stop_running, ui::{GuiState, Status}, ENTRY_POINT, }; @@ -405,7 +404,8 @@ impl DockerData { .values() .into_iter() .for_each(tokio::task::JoinHandle::abort); - stop_running(&self.is_running); + self.is_running + .store(false, std::sync::atomic::Ordering::SeqCst); } } } diff --git a/src/input_handler/mod.rs b/src/input_handler/mod.rs index cf3b91a..f1dd26c 100644 --- a/src/input_handler/mod.rs +++ b/src/input_handler/mod.rs @@ -4,9 +4,7 @@ use std::sync::{ }; use crossterm::{ - event::{ - DisableMouseCapture, EnableMouseCapture, KeyCode, MouseButton, MouseEvent, MouseEventKind, - }, + event::{DisableMouseCapture, KeyCode, MouseButton, MouseEvent, MouseEventKind}, execute, }; use parking_lot::Mutex; @@ -21,8 +19,7 @@ use crate::{ app_data::{AppData, DockerControls, Header}, app_error::AppError, docker_data::DockerMessage, - stop_running, - ui::{GuiState, SelectablePanel, Status}, + ui::{enable_mouse_capture, GuiState, SelectablePanel, Status}, }; pub use message::InputMessages; @@ -95,15 +92,10 @@ impl InputHandler { } } } else { - match execute!(std::io::stdout(), EnableMouseCapture) { - Ok(_) => self - .gui_state - .lock() - .set_info_box("✓ mouse capture enabled".to_owned()), - Err(_) => { - self.app_data.lock().set_error(AppError::MouseCapture(true)); - } - } + enable_mouse_capture(); + self.gui_state + .lock() + .set_info_box("✓ mouse capture enabled".to_owned()); }; // If the info box sleep handle is currently being executed, as in 'm' is pressed twice within a 4000ms window @@ -135,7 +127,8 @@ impl InputHandler { .lock() .status_contains(&[Status::Error, Status::Init]); if error_init || self.docker_sender.send(DockerMessage::Quit).await.is_err() { - stop_running(&self.is_running); + self.is_running + .store(false, std::sync::atomic::Ordering::SeqCst); } } diff --git a/src/main.rs b/src/main.rs index d2ee241..ec9eef4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,10 +19,6 @@ use app_data::AppData; use app_error::AppError; use bollard::Docker; -use crossterm::{ - event::{DisableMouseCapture, EnableMouseCapture}, - execute, -}; use docker_data::DockerData; use input_handler::InputMessages; use parking_lot::Mutex; @@ -67,15 +63,6 @@ fn check_if_containerised() -> bool { } } -/// Set is_running to false, disable mouse capture, due to weird bug on Linux & WSL terminals -/// where mouse movement will be piped to the stdout -fn stop_running(is_running: &AtomicBool) { - std::thread::spawn(|| { - execute!(std::io::stdout(), EnableMouseCapture).unwrap_or(()); - execute!(std::io::stdout(), DisableMouseCapture).unwrap_or(()); - }); - is_running.store(false, std::sync::atomic::Ordering::SeqCst); -} /// Create docker daemon handler, and only spawn up the docker data handler if a ping returns non-error async fn docker_init( app_data: &Arc>, diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 58dd9a0..9522b51 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,12 +1,12 @@ use anyhow::Result; use crossterm::{ - event::{self, DisableMouseCapture, EnableMouseCapture, Event}, + event::{self, DisableMouseCapture, Event}, execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; use parking_lot::Mutex; use std::{ - io::{self, Stdout}, + io::{self, Stdout, Write}, sync::{atomic::Ordering, Arc}, }; use std::{sync::atomic::AtomicBool, time::Instant}; @@ -39,6 +39,20 @@ pub struct Ui { terminal: Terminal>, } +/// Enable moust capture, but don't enable all the mouse movements, which improves performance, and fixes the weird mouse event output bug +pub fn enable_mouse_capture() { + io::stdout() + .write_all( + concat!( + crossterm::csi!("?1000h"), + crossterm::csi!("?1015h"), + crossterm::csi!("?1006h"), + ) + .as_bytes(), + ) + .unwrap_or(()); +} + impl Ui { /// Create a new Ui struct, and execute the drawing loop pub async fn create( @@ -73,7 +87,8 @@ impl Ui { fn setup_terminal() -> io::Result>> { enable_raw_mode()?; let mut stdout = io::stdout(); - execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?; + execute!(stdout, EnterAlternateScreen)?; + enable_mouse_capture(); let backend = CrosstermBackend::new(stdout); Terminal::new(backend) } @@ -96,12 +111,6 @@ impl Ui { fn err_loop(&mut self) -> Result<(), AppError> { let mut seconds = 5; loop { - // This is a fix for a weird bug on Linux + WSL which will output mouse movement to stdout - std::thread::spawn(|| { - execute!(io::stdout(), EnableMouseCapture).unwrap_or(()); - execute!(io::stdout(), DisableMouseCapture).unwrap_or(()); - }); - if self.now.elapsed() >= std::time::Duration::from_secs(1) { seconds -= 1; self.now = Instant::now(); @@ -124,14 +133,14 @@ impl Ui { /// The loop for drawing the main UI to the terminal async fn gui_loop(&mut self) -> Result<(), AppError> { - let input_poll_rate = std::time::Duration::from_millis(1); + let input_poll_rate = std::time::Duration::from_millis(100); let update_duration = std::time::Duration::from_millis(u64::from(self.app_data.lock().args.docker_interval)); while self.is_running.load(Ordering::SeqCst) { if self .terminal - .draw(|frame| ui_frame(frame, &self.app_data, &self.gui_state)) + .draw(|frame| draw_frame(frame, &self.app_data, &self.gui_state)) .is_err() { return Err(AppError::Terminal); @@ -183,7 +192,7 @@ impl Ui { } /// Draw the main ui to a frame of the terminal -fn ui_frame( +fn draw_frame( f: &mut Frame<'_, B>, app_data: &Arc>, gui_state: &Arc>,