From fe6ddb90f166ebe98d9b1269ce5a50af412b1e4b Mon Sep 17 00:00:00 2001 From: Canop Date: Tue, 29 Oct 2019 19:47:22 +0100 Subject: [PATCH] Introduce the EnableMouseCapture and DisableMouseCapture commands (#296) --- CHANGELOG.md | 5 +++-- src/input.rs | 40 +++++++++++++++++++++++++++++++++++++++- src/input/ansi.rs | 23 +++++++++++++++++++++++ src/input/input/unix.rs | 26 +++++++++----------------- src/lib.rs | 3 ++- 5 files changed, 76 insertions(+), 21 deletions(-) create mode 100644 src/input/ansi.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a39860..9cd4106 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - `input` module - Derive 'Copy' for 'KeyEvent' + - Add the `EnableMouseCapture` and `EnableMouseCapture` commands - `cursor` module - Remove `TerminalCursor`, `cursor`, `Crossterm::cursor()` - Introduce static function `crossterm::cursor::position` in place of `TerminalCursor::pos` @@ -21,10 +22,10 @@ - Remove re-export terminal module types at root level, are move those to `crossterm::terminal` - `style module` - Rename `ObjectStyle` to `ContentStyle`. Now full names are used for methods. - - Rename `StyledObject` to `StyledContent` and made members private. + - Rename `StyledObject` to `StyledContent` and made members private. - Rename `attr` method to `attribute`. - Rename `Attribute::NoInverse` to `NoReverse` - + # Version 0.12.1 - All the `crossterm_` crates code was moved to the `crossterm` crate diff --git a/src/input.rs b/src/input.rs index 9278435..0bb842c 100644 --- a/src/input.rs +++ b/src/input.rs @@ -38,7 +38,7 @@ #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use crate::utils::Result; +use crate::utils::{Command, Result}; #[cfg(unix)] use self::input::unix::UnixInput; @@ -47,6 +47,7 @@ use self::input::windows::WindowsInput; use self::input::Input; pub use self::input::{AsyncReader, SyncReader}; +mod ansi; mod input; mod sys; @@ -423,3 +424,40 @@ impl TerminalInput { pub fn input() -> TerminalInput { TerminalInput::new() } + +/// A command that enables mouse mode +/// +pub struct EnableMouseCapture; + +impl Command for EnableMouseCapture { + type AnsiType = String; + + fn ansi_code(&self) -> Self::AnsiType { + ansi::enable_mouse_mode_csi_sequence() + } + + #[cfg(windows)] + fn execute_winapi(&self) -> Result<()> { + input().enable_mouse_mode() + } +} + +/// A command that disables mouse event monitoring. +/// +/// Mouse events will be produced by the +/// [`AsyncReader`](struct.AsyncReader.html)/[`SyncReader`](struct.SyncReader.html). +/// +pub struct DisableMouseCapture; + +impl Command for DisableMouseCapture { + type AnsiType = String; + + fn ansi_code(&self) -> Self::AnsiType { + ansi::disable_mouse_mode_csi_sequence() + } + + #[cfg(windows)] + fn execute_winapi(&self) -> Result<()> { + input().disable_mouse_mode() + } +} diff --git a/src/input/ansi.rs b/src/input/ansi.rs new file mode 100644 index 0000000..9f39b5b --- /dev/null +++ b/src/input/ansi.rs @@ -0,0 +1,23 @@ +//! This module provides input related ANSI escape codes. + +use crate::csi; + +pub(crate) fn enable_mouse_mode_csi_sequence() -> String { + format!( + "{}h{}h{}h{}h", + csi!("?1000"), + csi!("?1002"), + csi!("?1015"), + csi!("?1006") + ) +} + +pub(crate) fn disable_mouse_mode_csi_sequence() -> String { + format!( + "{}l{}l{}l{}l", + csi!("?1006"), + csi!("?1015"), + csi!("?1002"), + csi!("?1000") + ) +} diff --git a/src/input/input/unix.rs b/src/input/input/unix.rs index 4136cfa..9d16160 100644 --- a/src/input/input/unix.rs +++ b/src/input/input/unix.rs @@ -4,10 +4,14 @@ use std::sync::mpsc::Receiver; use std::{char, sync::mpsc}; use crate::utils::Result; -use crate::{csi, write_cout}; +use crate::write_cout; use super::{ - super::{sys::unix::internal_event_receiver, InputEvent, InternalEvent, KeyEvent}, + super::{ + ansi::{disable_mouse_mode_csi_sequence, enable_mouse_mode_csi_sequence}, + sys::unix::internal_event_receiver, + InputEvent, InternalEvent, KeyEvent, + }, Input, }; @@ -50,24 +54,12 @@ impl Input for UnixInput { } fn enable_mouse_mode(&self) -> Result<()> { - write_cout!(&format!( - "{}h{}h{}h{}h", - csi!("?1000"), - csi!("?1002"), - csi!("?1015"), - csi!("?1006") - ))?; + write_cout!(enable_mouse_mode_csi_sequence())?; Ok(()) } fn disable_mouse_mode(&self) -> Result<()> { - write_cout!(&format!( - "{}l{}l{}l{}l", - csi!("?1006"), - csi!("?1015"), - csi!("?1002"), - csi!("?1000") - ))?; + write_cout!(disable_mouse_mode_csi_sequence())?; Ok(()) } } @@ -216,7 +208,7 @@ impl Iterator for AsyncReader { /// `SyncReader` is an individual iterator and it doesn't use `None` to indicate that the iteration is /// finished. You can expect additional `Some(InputEvent)` after calling `next` even if you have already /// received `None`. Unfortunately, `None` means that an error occurred, but you're free to call `next` -/// again. This behavior will be changed in the future to avoid errors consumption. +/// again. This behavior will be changed in the future to avoid errors consumption. /// /// # Notes /// diff --git a/src/lib.rs b/src/lib.rs index 82135db..3b3b807 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -169,7 +169,8 @@ #[cfg(feature = "input")] pub use input::{ - input, AsyncReader, InputEvent, KeyEvent, MouseButton, MouseEvent, SyncReader, TerminalInput, + input, AsyncReader, DisableMouseCapture, EnableMouseCapture, InputEvent, KeyEvent, MouseButton, + MouseEvent, SyncReader, TerminalInput, }; #[cfg(feature = "screen")] pub use screen::{