//! # Event //! //! The `event` module provides the functionality to read keyboard, mouse and terminal resize events. //! //! * The [`read`](fn.read.html) function returns an [`Event`](enum.Event.html) immediately //! (if available) or blocks until an [`Event`](enum.Event.html) is available. //! //! * The [`poll`](fn.poll.html) function allows you to check if there is or isn't an [`Event`](enum.Event.html) available //! within the given period of time. In other words - if subsequent call to the [`read`](fn.read.html) //! function will block or not. //! //! It's **not allowed** to call these functions from different threads or combine them with the //! [`EventStream`](struct.EventStream.html). You're allowed to either: //! //! * use the [`read`](fn.read.html) & [`poll`](fn.poll.html) functions on any, but same, thread //! * or the [`EventStream`](struct.EventStream.html). //! //! ## Mouse Events //! //! Mouse events are not enabled by default. You have to enable them with the //! [`EnableMouseCapture`](struct.EnableMouseCapture.html) command. See [Command API](../index.html#command-api) //! for more information. //! //! ## Examples //! //! Blocking read: //! //! ```no_run //! use crossterm::event::{read, Event}; //! //! fn print_events() -> crossterm::Result<()> { //! loop { //! // `read()` blocks until an `Event` is available //! match read()? { //! Event::Key(event) => println!("{:?}", event), //! Event::Mouse(event) => println!("{:?}", event), //! Event::Resize(width, height) => println!("New size {}x{}", width, height), //! } //! } //! Ok(()) //! } //! ``` //! //! Non-blocking read: //! //! ```no_run //! use std::time::Duration; //! //! use crossterm::event::{poll, read, Event}; //! //! fn print_events() -> crossterm::Result<()> { //! loop { //! // `poll()` waits for an `Event` for a given time period //! if poll(Duration::from_millis(500))? { //! // It's guaranteed that the `read()` won't block when the `poll()` //! // function returns `true` //! match read()? { //! Event::Key(event) => println!("{:?}", event), //! Event::Mouse(event) => println!("{:?}", event), //! Event::Resize(width, height) => println!("New size {}x{}", width, height), //! } //! } else { //! // Timeout expired and no `Event` is available //! } //! } //! Ok(()) //! } //! ``` //! //! Check the [examples](https://github.com/crossterm-rs/crossterm/tree/master/examples) folder for more of //! them (`event-*`). use std::fmt; use std::time::Duration; use parking_lot::RwLock; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use bitflags::bitflags; use filter::{EventFilter, Filter}; use lazy_static::lazy_static; #[cfg(feature = "event-stream")] pub use stream::EventStream; use timeout::PollTimeout; use crate::{Command, Result}; mod ansi; pub(crate) mod filter; mod read; mod source; #[cfg(feature = "event-stream")] mod stream; pub(crate) mod sys; mod timeout; lazy_static! { /// Static instance of `InternalEventReader`. /// This needs to be static because there can be one event reader. static ref INTERNAL_EVENT_READER: RwLock = RwLock::new(read::InternalEventReader::default()); } /// Checks if there is an [`Event`](enum.Event.html) available. /// /// Returns `Ok(true)` if an [`Event`](enum.Event.html) is available otherwise it returns `Ok(false)`. /// /// `Ok(true)` guarantees that subsequent call to the [`read`](fn.read.html) function /// wont block. /// /// # Arguments /// /// * `timeout` - maximum waiting time for event availability /// /// # Examples /// /// Return immediately: /// /// ```no_run /// use std::time::Duration; /// /// use crossterm::{event::poll, Result}; /// /// fn is_event_available() -> Result { /// // Zero duration says that the `poll` function must return immediately /// // with an `Event` availability information /// poll(Duration::from_secs(0)) /// } /// ``` /// /// Wait up to 100ms: /// /// ```no_run /// use std::time::Duration; /// /// use crossterm::{event::poll, Result}; /// /// fn is_event_available() -> Result { /// // Wait for an `Event` availability for 100ms. It returns immediately /// // if an `Event` is/becomes available. /// poll(Duration::from_millis(100)) /// } /// ``` pub fn poll(timeout: Duration) -> Result { poll_internal(Some(timeout), &EventFilter) } /// Reads a single [`Event`](enum.Event.html). /// /// This function blocks until an [`Event`](enum.Event.html) is available. Combine it with the /// [`poll`](fn.poll.html) function to get non-blocking reads. /// /// # Examples /// /// Blocking read: /// /// ```no_run /// use crossterm::{event::read, Result}; /// /// fn print_events() -> Result { /// loop { /// // Blocks until an `Event` is available /// println!("{:?}", read()?); /// } /// } /// ``` /// /// Non-blocking read: /// /// ```no_run /// use std::time::Duration; /// /// use crossterm::{event::{read, poll}, Result}; /// /// fn print_events() -> Result { /// loop { /// if poll(Duration::from_millis(100))? { /// // It's guaranteed that `read` wont block, because `poll` returned /// // `Ok(true)`. /// println!("{:?}", read()?); /// } else { /// // Timeout expired, no `Event` is available /// } /// } /// } /// ``` pub fn read() -> Result { match read_internal(&EventFilter)? { InternalEvent::Event(event) => Ok(event), #[cfg(unix)] _ => unreachable!(), } } /// Polls to check if there are any `InternalEvent`s that can be read within the given duration. pub(crate) fn poll_internal(timeout: Option, filter: &F) -> Result where F: Filter, { let (mut reader, timeout) = if let Some(timeout) = timeout { let poll_timeout = PollTimeout::new(Some(timeout)); if let Some(reader) = INTERNAL_EVENT_READER.try_write_for(timeout) { (reader, poll_timeout.leftover()) } else { return Ok(false); } } else { (INTERNAL_EVENT_READER.write(), None) }; reader.poll(timeout, filter) } /// Reads a single `InternalEvent`. pub(crate) fn read_internal(filter: &F) -> Result where F: Filter, { let mut reader = INTERNAL_EVENT_READER.write(); reader.read(filter) } /// A command that enables mouse event capturing. /// /// Mouse events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html). #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct EnableMouseCapture; impl Command for EnableMouseCapture { fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result { f.write_str(ansi::ENABLE_MOUSE_MODE_CSI_SEQUENCE) } #[cfg(windows)] fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> { sys::windows::enable_mouse_capture() } #[cfg(windows)] fn is_ansi_code_supported(&self) -> bool { false } } /// A command that disables mouse event capturing. /// /// Mouse events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html). #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DisableMouseCapture; impl Command for DisableMouseCapture { fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result { f.write_str(ansi::DISABLE_MOUSE_MODE_CSI_SEQUENCE) } #[cfg(windows)] fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> { sys::windows::disable_mouse_capture() } #[cfg(windows)] fn is_ansi_code_supported(&self) -> bool { false } } /// Represents an event. #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] pub enum Event { /// A single key event with additional pressed modifiers. Key(KeyEvent), /// A single mouse event with additional pressed modifiers. Mouse(MouseEvent), /// An resize event with new dimensions after resize (columns, rows). Resize(u16, u16), } /// Represents a mouse event. /// /// # Platform-specific Notes /// /// ## Mouse Buttons /// /// Some platforms/terminals do not report mouse button for the /// `MouseEventKind::Up` and `MouseEventKind::Drag` events. `MouseButton::Left` /// is returned if we don't know which button was used. /// /// ## Key Modifiers /// /// Some platforms/terminals does not report all key modifiers /// combinations for all mouse event types. For example - macOS reports /// `Ctrl` + left mouse button click as a right mouse button click. #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] pub struct MouseEvent { /// The kind of mouse event that was caused. pub kind: MouseEventKind, /// The column that the event occurred on. pub column: u16, /// The row that the event occurred on. pub row: u16, /// The key modifiers active when the event occurred. pub modifiers: KeyModifiers, } /// A mouse event kind. /// /// # Platform-specific Notes /// /// ## Mouse Buttons /// /// Some platforms/terminals do not report mouse button for the /// `MouseEventKind::Up` and `MouseEventKind::Drag` events. `MouseButton::Left` /// is returned if we don't know which button was used. #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] pub enum MouseEventKind { /// Pressed mouse button. Contains the button that was pressed. Down(MouseButton), /// Released mouse button. Contains the button that was released. Up(MouseButton), /// Moved the mouse cursor while pressing the contained mouse button. Drag(MouseButton), /// Moved the mouse cursor while not pressing a mouse button. Moved, /// Scrolled mouse wheel downwards (towards the user). ScrollDown, /// Scrolled mouse wheel upwards (away from the user). ScrollUp, } /// Represents a mouse button. #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] pub enum MouseButton { /// Left mouse button. Left, /// Right mouse button. Right, /// Middle mouse button. Middle, } bitflags! { /// Represents key modifiers (shift, control, alt). #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct KeyModifiers: u8 { const SHIFT = 0b0000_0001; const CONTROL = 0b0000_0010; const ALT = 0b0000_0100; const NONE = 0b0000_0000; } } /// Represents a key event. #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] pub struct KeyEvent { /// The key itself. pub code: KeyCode, /// Additional key modifiers. pub modifiers: KeyModifiers, } impl KeyEvent { pub fn new(code: KeyCode, modifiers: KeyModifiers) -> KeyEvent { KeyEvent { code, modifiers } } } impl From for KeyEvent { fn from(code: KeyCode) -> Self { KeyEvent { code, modifiers: KeyModifiers::empty(), } } } /// Represents a key. #[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum KeyCode { /// Backspace key. Backspace, /// Enter key. Enter, /// Left arrow key. Left, /// Right arrow key. Right, /// Up arrow key. Up, /// Down arrow key. Down, /// Home key. Home, /// End key. End, /// Page up key. PageUp, /// Page dow key. PageDown, /// Tab key. Tab, /// Shift + Tab key. BackTab, /// Delete key. Delete, /// Insert key. Insert, /// F key. /// /// `KeyEvent::F(1)` represents F1 key, etc. F(u8), /// A character. /// /// `KeyEvent::Char('c')` represents `c` character, etc. Char(char), /// Null. Null, /// Escape key. Esc, } /// An internal event. /// /// Encapsulates publicly available `Event` with additional internal /// events that shouldn't be publicly available to the crate users. #[derive(Debug, PartialOrd, PartialEq, Hash, Clone, Eq)] pub(crate) enum InternalEvent { /// An event. Event(Event), /// A cursor position (`col`, `row`). #[cfg(unix)] CursorPosition(u16, u16), }