Skip to main content

crossterm/
event.rs

1//! # Event
2//!
3//! The `event` module provides the functionality to read keyboard, mouse and terminal resize events.
4//!
5//! * The [`read`](fn.read.html) function returns an [`Event`](enum.Event.html) immediately
6//! (if available) or blocks until an [`Event`](enum.Event.html) is available.
7//!
8//! * The [`poll`](fn.poll.html) function allows you to check if there is or isn't an [`Event`](enum.Event.html) available
9//! within the given period of time. In other words - if subsequent call to the [`read`](fn.read.html)
10//! function will block or not.
11//!
12//! It's **not allowed** to call these functions from different threads or combine them with the
13//! [`EventStream`](struct.EventStream.html). You're allowed to either:
14//!
15//! * use the [`read`](fn.read.html) & [`poll`](fn.poll.html) functions on any, but same, thread
16//! * or the [`EventStream`](struct.EventStream.html).
17//!
18//! **Make sure to enable [raw mode](../terminal/index.html#raw-mode) in order for keyboard events to work properly**
19//!
20//! ## Mouse and Focus Events
21//!
22//! Mouse and focus events are not enabled by default. You have to enable them with the
23//! [`EnableMouseCapture`](struct.EnableMouseCapture.html) / [`EnableFocusChange`](struct.EnableFocusChange.html) command.
24//! See [Command API](../index.html#command-api) for more information.
25//!
26//! ## Examples
27//!
28//! Blocking read:
29//!
30//! ```no_run
31//! #![cfg(feature = "bracketed-paste")]
32//! use crossterm::{
33//!     event::{
34//!         read, DisableBracketedPaste, DisableFocusChange, DisableMouseCapture, EnableBracketedPaste,
35//!         EnableFocusChange, EnableMouseCapture, Event,
36//!     },
37//!     execute,
38//! };
39//!
40//! fn print_events() -> std::io::Result<()> {
41//!     execute!(
42//!          std::io::stdout(),
43//!          EnableBracketedPaste,
44//!          EnableFocusChange,
45//!          EnableMouseCapture
46//!     )?;
47//!     loop {
48//!         // `read()` blocks until an `Event` is available
49//!         match read()? {
50//!             Event::FocusGained => println!("FocusGained"),
51//!             Event::FocusLost => println!("FocusLost"),
52//!             Event::Key(event) => println!("{:?}", event),
53//!             Event::Mouse(event) => println!("{:?}", event),
54//!             #[cfg(feature = "bracketed-paste")]
55//!             Event::Paste(data) => println!("{:?}", data),
56//!             Event::Resize(width, height) => println!("New size {}x{}", width, height),
57//!             Event::ThemeModeChanged(mode) => println!("New theme mode {:?}", mode),
58//!         }
59//!     }
60//!     execute!(
61//!         std::io::stdout(),
62//!         DisableBracketedPaste,
63//!         DisableFocusChange,
64//!         DisableMouseCapture
65//!     )?;
66//!     Ok(())
67//! }
68//! ```
69//!
70//! Non-blocking read:
71//!
72//! ```no_run
73//! #![cfg(feature = "bracketed-paste")]
74//! use std::{time::Duration, io};
75//!
76//! use crossterm::{
77//!     event::{
78//!         poll, read, DisableBracketedPaste, DisableFocusChange, DisableMouseCapture,
79//!         EnableBracketedPaste, EnableFocusChange, EnableMouseCapture, Event,
80//!     },
81//!     execute,
82//! };
83//!
84//! fn print_events() -> io::Result<()> {
85//!     execute!(
86//!          std::io::stdout(),
87//!          EnableBracketedPaste,
88//!          EnableFocusChange,
89//!          EnableMouseCapture
90//!     )?;
91//!     loop {
92//!         // `poll()` waits for an `Event` for a given time period
93//!         if poll(Duration::from_millis(500))? {
94//!             // It's guaranteed that the `read()` won't block when the `poll()`
95//!             // function returns `true`
96//!             match read()? {
97//!                 Event::FocusGained => println!("FocusGained"),
98//!                 Event::FocusLost => println!("FocusLost"),
99//!                 Event::Key(event) => println!("{:?}", event),
100//!                 Event::Mouse(event) => println!("{:?}", event),
101//!                 #[cfg(feature = "bracketed-paste")]
102//!                 Event::Paste(data) => println!("Pasted {:?}", data),
103//!                 Event::Resize(width, height) => println!("New size {}x{}", width, height),
104//!                 Event::ThemeModeChanged(mode) => println!("New theme mode {:?}", mode),
105//!             }
106//!         } else {
107//!             // Timeout expired and no `Event` is available
108//!         }
109//!     }
110//!     execute!(
111//!         std::io::stdout(),
112//!         DisableBracketedPaste,
113//!         DisableFocusChange,
114//!         DisableMouseCapture
115//!     )?;
116//!     Ok(())
117//! }
118//! ```
119//!
120//! Check the [examples](https://github.com/crossterm-rs/crossterm/tree/master/examples) folder for more of
121//! them (`event-*`).
122
123pub(crate) mod filter;
124pub(crate) mod read;
125pub(crate) mod source;
126#[cfg(feature = "event-stream")]
127pub(crate) mod stream;
128pub(crate) mod sys;
129pub(crate) mod timeout;
130
131#[cfg(feature = "derive-more")]
132use derive_more::derive::IsVariant;
133#[cfg(feature = "event-stream")]
134pub use stream::EventStream;
135
136use crate::event::{
137    filter::{EventFilter, Filter},
138    read::InternalEventReader,
139    timeout::PollTimeout,
140};
141use crate::{csi, Command};
142use parking_lot::{MappedMutexGuard, Mutex, MutexGuard};
143use std::fmt::{self, Display};
144use std::time::Duration;
145
146use bitflags::bitflags;
147use std::hash::{Hash, Hasher};
148
149/// Static instance of `InternalEventReader`.
150/// This needs to be static because there can be one event reader.
151static INTERNAL_EVENT_READER: Mutex<Option<InternalEventReader>> = parking_lot::const_mutex(None);
152
153pub(crate) fn lock_internal_event_reader() -> MappedMutexGuard<'static, InternalEventReader> {
154    MutexGuard::map(INTERNAL_EVENT_READER.lock(), |reader| {
155        reader.get_or_insert_with(InternalEventReader::default)
156    })
157}
158fn try_lock_internal_event_reader_for(
159    duration: Duration,
160) -> Option<MappedMutexGuard<'static, InternalEventReader>> {
161    Some(MutexGuard::map(
162        INTERNAL_EVENT_READER.try_lock_for(duration)?,
163        |reader| reader.get_or_insert_with(InternalEventReader::default),
164    ))
165}
166
167/// Checks if there is an [`Event`](enum.Event.html) available.
168///
169/// Returns `Ok(true)` if an [`Event`](enum.Event.html) is available otherwise it returns `Ok(false)`.
170///
171/// `Ok(true)` guarantees that subsequent call to the [`read`](fn.read.html) function
172/// won't block.
173///
174/// # Arguments
175///
176/// * `timeout` - maximum waiting time for event availability
177///
178/// # Examples
179///
180/// Return immediately:
181///
182/// ```no_run
183/// use std::{time::Duration, io};
184/// use crossterm::{event::poll};
185///
186/// fn is_event_available() -> io::Result<bool> {
187///     // Zero duration says that the `poll` function must return immediately
188///     // with an `Event` availability information
189///     poll(Duration::from_secs(0))
190/// }
191/// ```
192///
193/// Wait up to 100ms:
194///
195/// ```no_run
196/// use std::{time::Duration, io};
197///
198/// use crossterm::event::poll;
199///
200/// fn is_event_available() -> io::Result<bool> {
201///     // Wait for an `Event` availability for 100ms. It returns immediately
202///     // if an `Event` is/becomes available.
203///     poll(Duration::from_millis(100))
204/// }
205/// ```
206pub fn poll(timeout: Duration) -> std::io::Result<bool> {
207    poll_internal(Some(timeout), &EventFilter)
208}
209
210/// Reads a single [`Event`](enum.Event.html).
211///
212/// This function blocks until an [`Event`](enum.Event.html) is available. Combine it with the
213/// [`poll`](fn.poll.html) function to get non-blocking reads.
214///
215/// # Examples
216///
217/// Blocking read:
218///
219/// ```no_run
220/// use crossterm::event::read;
221/// use std::io;
222///
223/// fn print_events() -> io::Result<bool> {
224///     loop {
225///         // Blocks until an `Event` is available
226///         println!("{:?}", read()?);
227///     }
228/// }
229/// ```
230///
231/// Non-blocking read:
232///
233/// ```no_run
234/// use std::time::Duration;
235/// use std::io;
236///
237/// use crossterm::event::{read, poll};
238///
239/// fn print_events() -> io::Result<bool> {
240///     loop {
241///         if poll(Duration::from_millis(100))? {
242///             // It's guaranteed that `read` won't block, because `poll` returned
243///             // `Ok(true)`.
244///             println!("{:?}", read()?);
245///         } else {
246///             // Timeout expired, no `Event` is available
247///         }
248///     }
249/// }
250/// ```
251pub fn read() -> std::io::Result<Event> {
252    match read_internal(&EventFilter)? {
253        InternalEvent::Event(event) => Ok(event),
254        #[cfg(unix)]
255        _ => unreachable!(),
256    }
257}
258
259/// Polls to check if there are any `InternalEvent`s that can be read within the given duration.
260pub(crate) fn poll_internal<F>(timeout: Option<Duration>, filter: &F) -> std::io::Result<bool>
261where
262    F: Filter,
263{
264    let (mut reader, timeout) = if let Some(timeout) = timeout {
265        let poll_timeout = PollTimeout::new(Some(timeout));
266        if let Some(reader) = try_lock_internal_event_reader_for(timeout) {
267            (reader, poll_timeout.leftover())
268        } else {
269            return Ok(false);
270        }
271    } else {
272        (lock_internal_event_reader(), None)
273    };
274    reader.poll(timeout, filter)
275}
276
277/// Reads a single `InternalEvent`.
278pub(crate) fn read_internal<F>(filter: &F) -> std::io::Result<InternalEvent>
279where
280    F: Filter,
281{
282    let mut reader = lock_internal_event_reader();
283    reader.read(filter)
284}
285
286bitflags! {
287    /// Represents special flags that tell compatible terminals to add extra information to keyboard events.
288    ///
289    /// See <https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement> for more information.
290    ///
291    /// Alternate keys and Unicode codepoints are not yet supported by crossterm.
292    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(transparent))]
293    #[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
294    pub struct KeyboardEnhancementFlags: u8 {
295        /// Represent Escape and modified keys using CSI-u sequences, so they can be unambiguously
296        /// read.
297        const DISAMBIGUATE_ESCAPE_CODES = 0b0000_0001;
298        /// Add extra events with [`KeyEvent.kind`] set to [`KeyEventKind::Repeat`] or
299        /// [`KeyEventKind::Release`] when keys are autorepeated or released.
300        const REPORT_EVENT_TYPES = 0b0000_0010;
301        /// Send [alternate keycodes](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#key-codes)
302        /// in addition to the base keycode. The alternate keycode overrides the base keycode in
303        /// resulting `KeyEvent`s.
304        const REPORT_ALTERNATE_KEYS = 0b0000_0100;
305        /// Represent all keyboard events as CSI-u sequences. This is required to get repeat/release
306        /// events for plain-text keys.
307        const REPORT_ALL_KEYS_AS_ESCAPE_CODES = 0b0000_1000;
308        // Send the Unicode codepoint as well as the keycode.
309        //
310        // *Note*: this is not yet supported by crossterm.
311        // const REPORT_ASSOCIATED_TEXT = 0b0001_0000;
312    }
313}
314
315/// The terminal's current mode of the synchronized output feature.
316///
317/// <https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036#feature-detection>
318#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
319#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
320pub enum SynchronizedOutputMode {
321    /// Screen updates are not shown to the user until mode is disabled.
322    Set,
323    /// Screen updates are shown as usual (e.g. as soon as they arrive).
324    Reset,
325    /// The terminal does not support synchronized output sequences.
326    NotSupported,
327}
328
329impl Default for SynchronizedOutputMode {
330    fn default() -> Self {
331        Self::NotSupported
332    }
333}
334
335/// A command that enables mouse event capturing.
336///
337/// Mouse events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html).
338#[cfg(feature = "events")]
339#[derive(Debug, Clone, Copy, PartialEq, Eq)]
340pub struct EnableMouseCapture;
341
342#[cfg(feature = "events")]
343impl Command for EnableMouseCapture {
344    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
345        f.write_str(concat!(
346            // Normal tracking: Send mouse X & Y on button press and release
347            csi!("?1000h"),
348            // Button-event tracking: Report button motion events (dragging)
349            csi!("?1002h"),
350            // Any-event tracking: Report all motion events
351            csi!("?1003h"),
352            // RXVT mouse mode: Allows mouse coordinates of >223
353            csi!("?1015h"),
354            // SGR mouse mode: Allows mouse coordinates of >223, preferred over RXVT mode
355            csi!("?1006h"),
356        ))
357    }
358
359    #[cfg(windows)]
360    fn execute_winapi(&self) -> std::io::Result<()> {
361        sys::windows::enable_mouse_capture()
362    }
363
364    #[cfg(windows)]
365    fn is_ansi_code_supported(&self) -> bool {
366        false
367    }
368}
369
370/// A command that disables mouse event capturing.
371///
372/// Mouse events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html).
373#[derive(Debug, Clone, Copy, PartialEq, Eq)]
374pub struct DisableMouseCapture;
375
376impl Command for DisableMouseCapture {
377    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
378        f.write_str(concat!(
379            // The inverse commands of EnableMouseCapture, in reverse order.
380            csi!("?1006l"),
381            csi!("?1015l"),
382            csi!("?1003l"),
383            csi!("?1002l"),
384            csi!("?1000l"),
385        ))
386    }
387
388    #[cfg(windows)]
389    fn execute_winapi(&self) -> std::io::Result<()> {
390        sys::windows::disable_mouse_capture()
391    }
392
393    #[cfg(windows)]
394    fn is_ansi_code_supported(&self) -> bool {
395        false
396    }
397}
398
399/// A command that enables focus event emission.
400///
401/// It should be paired with [`DisableFocusChange`] at the end of execution.
402///
403/// Focus events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html).
404#[derive(Debug, Clone, Copy, PartialEq, Eq)]
405pub struct EnableFocusChange;
406
407impl Command for EnableFocusChange {
408    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
409        f.write_str(csi!("?1004h"))
410    }
411
412    #[cfg(windows)]
413    fn execute_winapi(&self) -> std::io::Result<()> {
414        // Focus events are always enabled on Windows
415        Ok(())
416    }
417}
418
419/// A command that disables focus event emission.
420#[derive(Debug, Clone, Copy, PartialEq, Eq)]
421pub struct DisableFocusChange;
422
423impl Command for DisableFocusChange {
424    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
425        f.write_str(csi!("?1004l"))
426    }
427
428    #[cfg(windows)]
429    fn execute_winapi(&self) -> std::io::Result<()> {
430        // Focus events can't be disabled on Windows
431        Ok(())
432    }
433}
434
435/// A command that enables [bracketed paste mode](https://en.wikipedia.org/wiki/Bracketed-paste).
436///
437/// It should be paired with [`DisableBracketedPaste`] at the end of execution.
438///
439/// This is not supported in older Windows terminals without
440/// [virtual terminal sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences).
441#[cfg(feature = "bracketed-paste")]
442#[derive(Debug, Clone, Copy, PartialEq, Eq)]
443pub struct EnableBracketedPaste;
444
445#[cfg(feature = "bracketed-paste")]
446impl Command for EnableBracketedPaste {
447    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
448        f.write_str(csi!("?2004h"))
449    }
450
451    #[cfg(windows)]
452    fn execute_winapi(&self) -> std::io::Result<()> {
453        Err(std::io::Error::new(
454            std::io::ErrorKind::Unsupported,
455            "Bracketed paste not implemented in the legacy Windows API.",
456        ))
457    }
458}
459
460/// A command that disables bracketed paste mode.
461#[cfg(feature = "bracketed-paste")]
462#[derive(Debug, Clone, Copy, PartialEq, Eq)]
463pub struct DisableBracketedPaste;
464
465#[cfg(feature = "bracketed-paste")]
466impl Command for DisableBracketedPaste {
467    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
468        f.write_str(csi!("?2004l"))
469    }
470
471    #[cfg(windows)]
472    fn execute_winapi(&self) -> std::io::Result<()> {
473        Ok(())
474    }
475}
476
477/// A command that enables the [kitty keyboard protocol](https://sw.kovidgoyal.net/kitty/keyboard-protocol/), which adds extra information to keyboard events and removes ambiguity for modifier keys.
478///
479/// It should be paired with [`PopKeyboardEnhancementFlags`] at the end of execution.
480///
481/// Example usage:
482/// ```no_run
483/// use std::io::{Write, stdout};
484/// use crossterm::execute;
485/// use crossterm::event::{
486///     KeyboardEnhancementFlags,
487///     PushKeyboardEnhancementFlags,
488///     PopKeyboardEnhancementFlags
489/// };
490///
491/// let mut stdout = stdout();
492///
493/// execute!(
494///     stdout,
495///     PushKeyboardEnhancementFlags(
496///         KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
497///     )
498/// );
499///
500/// // ...
501///
502/// execute!(stdout, PopKeyboardEnhancementFlags);
503/// ```
504///
505/// Note that, currently, only the following support this protocol:
506/// * [kitty terminal](https://sw.kovidgoyal.net/kitty/)
507/// * [foot terminal](https://codeberg.org/dnkl/foot/issues/319)
508/// * [WezTerm terminal](https://wezfurlong.org/wezterm/config/lua/config/enable_kitty_keyboard.html)
509/// * [alacritty terminal](https://github.com/alacritty/alacritty/issues/6378)
510/// * [notcurses library](https://github.com/dankamongmen/notcurses/issues/2131)
511/// * [neovim text editor](https://github.com/neovim/neovim/pull/18181)
512/// * [kakoune text editor](https://github.com/mawww/kakoune/issues/4103)
513/// * [dte text editor](https://gitlab.com/craigbarnes/dte/-/issues/138)
514#[derive(Debug, Clone, Copy, PartialEq, Eq)]
515pub struct PushKeyboardEnhancementFlags(pub KeyboardEnhancementFlags);
516
517impl Command for PushKeyboardEnhancementFlags {
518    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
519        write!(f, "{}{}u", csi!(">"), self.0.bits())
520    }
521
522    #[cfg(windows)]
523    fn execute_winapi(&self) -> std::io::Result<()> {
524        use std::io;
525
526        Err(io::Error::new(
527            io::ErrorKind::Unsupported,
528            "Keyboard progressive enhancement not implemented for the legacy Windows API.",
529        ))
530    }
531
532    #[cfg(windows)]
533    fn is_ansi_code_supported(&self) -> bool {
534        false
535    }
536}
537
538/// A command that disables extra kinds of keyboard events.
539///
540/// Specifically, it pops one level of keyboard enhancement flags.
541///
542/// See [`PushKeyboardEnhancementFlags`] and <https://sw.kovidgoyal.net/kitty/keyboard-protocol/> for more information.
543#[derive(Debug, Clone, Copy, PartialEq, Eq)]
544pub struct PopKeyboardEnhancementFlags;
545
546impl Command for PopKeyboardEnhancementFlags {
547    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
548        f.write_str(csi!("<1u"))
549    }
550
551    #[cfg(windows)]
552    fn execute_winapi(&self) -> std::io::Result<()> {
553        use std::io;
554
555        Err(io::Error::new(
556            io::ErrorKind::Unsupported,
557            "Keyboard progressive enhancement not implemented for the legacy Windows API.",
558        ))
559    }
560
561    #[cfg(windows)]
562    fn is_ansi_code_supported(&self) -> bool {
563        false
564    }
565}
566
567/// A command which subscribes to updates of the terminal's selected theme mode (dark/light).
568///
569/// See [`ThemeMode`] for more information.
570#[derive(Debug, Clone, Copy, PartialEq, Eq)]
571pub struct EnableThemeModeUpdates;
572
573impl Command for EnableThemeModeUpdates {
574    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
575        f.write_str(csi!("?2031h"))
576    }
577
578    #[cfg(windows)]
579    fn execute_winapi(&self) -> std::io::Result<()> {
580        use std::io;
581
582        Err(io::Error::new(
583            io::ErrorKind::Unsupported,
584            "Theme mode updates are not implemented for the legacy Windows API",
585        ))
586    }
587
588    #[cfg(windows)]
589    fn is_ansi_code_supported(&self) -> bool {
590        false
591    }
592}
593
594/// A command which unsubscribes to updates of the terminal's selected theme mode (dark/light).
595///
596/// See [ThemeMode] and [EnableThemeModeUpdates] for more information.
597#[derive(Debug, Clone, Copy, PartialEq, Eq)]
598pub struct DisableThemeModeUpdates;
599
600impl Command for DisableThemeModeUpdates {
601    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
602        f.write_str(csi!("?2031l"))
603    }
604
605    #[cfg(windows)]
606    fn execute_winapi(&self) -> std::io::Result<()> {
607        use std::io;
608
609        Err(io::Error::new(
610            io::ErrorKind::Unsupported,
611            "Theme mode updates are not implemented for the legacy Windows API",
612        ))
613    }
614
615    #[cfg(windows)]
616    fn is_ansi_code_supported(&self) -> bool {
617        false
618    }
619}
620
621/// Represents an event.
622#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
623#[cfg_attr(feature = "derive-more", derive(IsVariant))]
624#[cfg_attr(not(feature = "bracketed-paste"), derive(Copy))]
625#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Hash)]
626pub enum Event {
627    /// The terminal gained focus
628    FocusGained,
629    /// The terminal lost focus
630    FocusLost,
631    /// A single key event with additional pressed modifiers.
632    Key(KeyEvent),
633    /// A single mouse event with additional pressed modifiers.
634    Mouse(MouseEvent),
635    /// A string that was pasted into the terminal. Only emitted if bracketed paste has been
636    /// enabled.
637    #[cfg(feature = "bracketed-paste")]
638    Paste(String),
639    /// An resize event with new dimensions after resize (columns, rows).
640    /// **Note** that resize events can occur in batches.
641    Resize(u16, u16),
642    ThemeModeChanged(ThemeMode),
643}
644
645impl Event {
646    /// Returns `true` if the event is a key press event.
647    ///
648    /// This is useful for waiting for any key press event, regardless of the key that was pressed.
649    ///
650    /// Returns `false` for key release and repeat events (as well as for non-key events).
651    ///
652    /// # Examples
653    ///
654    /// The following code runs a loop that processes events until a key press event is encountered:
655    ///
656    /// ```no_run
657    /// use crossterm::event;
658    ///
659    /// while !event::read()?.is_key_press() {
660    ///     // ...
661    /// }
662    /// # Ok::<(), std::io::Error>(())
663    /// ```
664    #[inline]
665    pub fn is_key_press(&self) -> bool {
666        matches!(
667            self,
668            Event::Key(KeyEvent {
669                kind: KeyEventKind::Press,
670                ..
671            })
672        )
673    }
674
675    /// Returns `true` if the event is a key release event.
676    #[inline]
677    pub fn is_key_release(&self) -> bool {
678        matches!(
679            self,
680            Event::Key(KeyEvent {
681                kind: KeyEventKind::Release,
682                ..
683            })
684        )
685    }
686
687    /// Returns `true` if the event is a key repeat event.
688    #[inline]
689    pub fn is_key_repeat(&self) -> bool {
690        matches!(
691            self,
692            Event::Key(KeyEvent {
693                kind: KeyEventKind::Repeat,
694                ..
695            })
696        )
697    }
698
699    /// Returns the key event if the event is a key event, otherwise `None`.
700    ///
701    /// This is a convenience method that makes apps that only care about key events easier to write.
702    ///
703    /// # Examples
704    ///
705    /// The following code runs a loop that only processes key events:
706    ///
707    /// ```no_run
708    /// use crossterm::event;
709    ///
710    /// while let Some(key_event) = event::read()?.as_key_event() {
711    ///     // ...
712    /// }
713    /// # std::io::Result::Ok(())
714    /// ```
715    #[inline]
716    pub fn as_key_event(&self) -> Option<KeyEvent> {
717        match self {
718            Event::Key(event) => Some(*event),
719            _ => None,
720        }
721    }
722
723    /// Returns an Option containing the KeyEvent if the event is a key press event.
724    ///
725    /// This is a convenience method that makes apps that only care about key press events, and not
726    /// key release or repeat events (or non-key events), easier to write.
727    ///
728    /// Returns `None` for key release and repeat events (as well as for non-key events).
729    ///
730    /// # Examples
731    ///
732    /// The following code runs a loop that only processes key press events:
733    ///
734    /// ```no_run
735    /// use crossterm::event;
736    ///
737    /// while let Ok(event) = event::read() {
738    ///     if let Some(key) = event.as_key_press_event() {
739    ///         // ...
740    ///     }
741    /// }
742    #[inline]
743    pub fn as_key_press_event(&self) -> Option<KeyEvent> {
744        match self {
745            Event::Key(event) if self.is_key_press() => Some(*event),
746            _ => None,
747        }
748    }
749
750    /// Returns an Option containing the `KeyEvent` if the event is a key release event.
751    #[inline]
752    pub fn as_key_release_event(&self) -> Option<KeyEvent> {
753        match self {
754            Event::Key(event) if self.is_key_release() => Some(*event),
755            _ => None,
756        }
757    }
758
759    /// Returns an Option containing the `KeyEvent` if the event is a key repeat event.
760    #[inline]
761    pub fn as_key_repeat_event(&self) -> Option<KeyEvent> {
762        match self {
763            Event::Key(event) if self.is_key_repeat() => Some(*event),
764            _ => None,
765        }
766    }
767
768    /// Returns the mouse event if the event is a mouse event, otherwise `None`.
769    ///
770    /// This is a convenience method that makes code which only cares about mouse events easier to
771    /// write.
772    ///
773    /// # Examples
774    ///
775    /// ```no_run
776    /// use crossterm::event;
777    ///
778    /// while let Some(mouse_event) = event::read()?.as_mouse_event() {
779    ///     // ...
780    /// }
781    /// # std::io::Result::Ok(())
782    /// ```
783    #[inline]
784    pub fn as_mouse_event(&self) -> Option<MouseEvent> {
785        match self {
786            Event::Mouse(event) => Some(*event),
787            _ => None,
788        }
789    }
790
791    /// Returns the pasted string if the event is a paste event, otherwise `None`.
792    ///
793    /// This is a convenience method that makes code which only cares about paste events easier to write.
794    ///
795    /// # Examples
796    ///
797    /// ```no_run
798    /// use crossterm::event;
799    ///
800    /// while let Some(paste) = event::read()?.as_paste_event() {
801    ///     // ...
802    /// }
803    /// # std::io::Result::Ok(())
804    /// ```
805    #[cfg(feature = "bracketed-paste")]
806    #[inline]
807    pub fn as_paste_event(&self) -> Option<&str> {
808        match self {
809            Event::Paste(paste) => Some(paste),
810            _ => None,
811        }
812    }
813
814    /// Returns the size as a tuple if the event is a resize event, otherwise `None`.
815    ///
816    /// This is a convenience method that makes code which only cares about resize events easier to write.
817    ///
818    /// # Examples
819    ///
820    /// ```no_run
821    /// use crossterm::event;
822    ///
823    /// while let Some((columns, rows)) = event::read()?.as_resize_event() {
824    ///     // ...
825    /// }
826    /// # std::io::Result::Ok(())
827    /// ```
828    #[inline]
829    pub fn as_resize_event(&self) -> Option<(u16, u16)> {
830        match self {
831            Event::Resize(columns, rows) => Some((*columns, *rows)),
832            _ => None,
833        }
834    }
835}
836
837/// Represents a mouse event.
838///
839/// # Platform-specific Notes
840///
841/// ## Mouse Buttons
842///
843/// Some platforms/terminals do not report mouse button for the
844/// `MouseEventKind::Up` and `MouseEventKind::Drag` events. `MouseButton::Left`
845/// is returned if we don't know which button was used.
846///
847/// ## Key Modifiers
848///
849/// Some platforms/terminals does not report all key modifiers
850/// combinations for all mouse event types. For example - macOS reports
851/// `Ctrl` + left mouse button click as a right mouse button click.
852#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
853#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
854pub struct MouseEvent {
855    /// The kind of mouse event that was caused.
856    pub kind: MouseEventKind,
857    /// The column that the event occurred on.
858    pub column: u16,
859    /// The row that the event occurred on.
860    pub row: u16,
861    /// The key modifiers active when the event occurred.
862    pub modifiers: KeyModifiers,
863}
864
865/// A mouse event kind.
866///
867/// # Platform-specific Notes
868///
869/// ## Mouse Buttons
870///
871/// Some platforms/terminals do not report mouse button for the
872/// `MouseEventKind::Up` and `MouseEventKind::Drag` events. `MouseButton::Left`
873/// is returned if we don't know which button was used.
874#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
875#[cfg_attr(feature = "derive-more", derive(IsVariant))]
876#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
877pub enum MouseEventKind {
878    /// Pressed mouse button. Contains the button that was pressed.
879    Down(MouseButton),
880    /// Released mouse button. Contains the button that was released.
881    Up(MouseButton),
882    /// Moved the mouse cursor while pressing the contained mouse button.
883    Drag(MouseButton),
884    /// Moved the mouse cursor while not pressing a mouse button.
885    Moved,
886    /// Scrolled mouse wheel downwards (towards the user).
887    ScrollDown,
888    /// Scrolled mouse wheel upwards (away from the user).
889    ScrollUp,
890    /// Scrolled mouse wheel left (mostly on a laptop touchpad).
891    ScrollLeft,
892    /// Scrolled mouse wheel right (mostly on a laptop touchpad).
893    ScrollRight,
894}
895
896/// Represents a mouse button.
897#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
898#[cfg_attr(feature = "derive-more", derive(IsVariant))]
899#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
900pub enum MouseButton {
901    /// Left mouse button.
902    Left,
903    /// Right mouse button.
904    Right,
905    /// Middle mouse button.
906    Middle,
907}
908
909bitflags! {
910    /// Represents key modifiers (shift, control, alt, etc.).
911    ///
912    /// **Note:** `SUPER`, `HYPER`, and `META` can only be read if
913    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
914    /// [`PushKeyboardEnhancementFlags`].
915    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(transparent))]
916    #[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
917    pub struct KeyModifiers: u8 {
918        const SHIFT = 0b0000_0001;
919        const CONTROL = 0b0000_0010;
920        const ALT = 0b0000_0100;
921        const SUPER = 0b0000_1000;
922        const HYPER = 0b0001_0000;
923        const META = 0b0010_0000;
924        const NONE = 0b0000_0000;
925    }
926}
927
928impl Display for KeyModifiers {
929    /// Formats the key modifiers using the given formatter.
930    ///
931    /// The key modifiers are joined by a `+` character.
932    ///
933    /// # Platform-specific Notes
934    ///
935    /// On macOS, the control, alt, and super keys is displayed as "Control", "Option", and
936    /// "Command" respectively. See
937    /// <https://support.apple.com/guide/applestyleguide/welcome/1.0/web>.
938    ///
939    /// On Windows, the super key is displayed as "Windows" and the control key is displayed as
940    /// "Ctrl". See
941    /// <https://learn.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/term-collections/keys-keyboard-shortcuts>.
942    ///
943    /// On other platforms, the super key is referred to as "Super" and the control key is
944    /// displayed as "Ctrl".
945    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
946        let mut first = true;
947        for modifier in self.iter() {
948            if !first {
949                f.write_str("+")?;
950            }
951
952            first = false;
953            match modifier {
954                KeyModifiers::SHIFT => f.write_str("Shift")?,
955                #[cfg(unix)]
956                KeyModifiers::CONTROL => f.write_str("Control")?,
957                #[cfg(windows)]
958                KeyModifiers::CONTROL => f.write_str("Ctrl")?,
959                #[cfg(target_os = "macos")]
960                KeyModifiers::ALT => f.write_str("Option")?,
961                #[cfg(not(target_os = "macos"))]
962                KeyModifiers::ALT => f.write_str("Alt")?,
963                #[cfg(target_os = "macos")]
964                KeyModifiers::SUPER => f.write_str("Command")?,
965                #[cfg(target_os = "windows")]
966                KeyModifiers::SUPER => f.write_str("Windows")?,
967                #[cfg(not(any(target_os = "macos", target_os = "windows")))]
968                KeyModifiers::SUPER => f.write_str("Super")?,
969                KeyModifiers::HYPER => f.write_str("Hyper")?,
970                KeyModifiers::META => f.write_str("Meta")?,
971                _ => unreachable!(),
972            }
973        }
974        Ok(())
975    }
976}
977
978/// Represents a keyboard event kind.
979#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
980#[cfg_attr(feature = "derive-more", derive(IsVariant))]
981#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
982pub enum KeyEventKind {
983    Press,
984    Repeat,
985    Release,
986}
987
988bitflags! {
989    /// Represents extra state about the key event.
990    ///
991    /// **Note:** This state can only be read if
992    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
993    /// [`PushKeyboardEnhancementFlags`].
994    #[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
995    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(transparent))]
996    pub struct KeyEventState: u8 {
997        /// The key event origins from the keypad.
998        const KEYPAD = 0b0000_0001;
999        /// Caps Lock was enabled for this key event.
1000        ///
1001        /// **Note:** this is set for the initial press of Caps Lock itself.
1002        const CAPS_LOCK = 0b0000_0010;
1003        /// Num Lock was enabled for this key event.
1004        ///
1005        /// **Note:** this is set for the initial press of Num Lock itself.
1006        const NUM_LOCK = 0b0000_0100;
1007        const NONE = 0b0000_0000;
1008    }
1009}
1010
1011/// Represents a key event.
1012#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1013#[derive(Debug, PartialOrd, Clone, Copy)]
1014pub struct KeyEvent {
1015    /// The key itself.
1016    pub code: KeyCode,
1017    /// Additional key modifiers.
1018    pub modifiers: KeyModifiers,
1019    /// Kind of event.
1020    ///
1021    /// Only set if:
1022    /// - Unix: [`KeyboardEnhancementFlags::REPORT_EVENT_TYPES`] has been enabled with [`PushKeyboardEnhancementFlags`].
1023    /// - Windows: always
1024    pub kind: KeyEventKind,
1025    /// Keyboard state.
1026    ///
1027    /// Only set if [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
1028    /// [`PushKeyboardEnhancementFlags`].
1029    pub state: KeyEventState,
1030}
1031
1032impl KeyEvent {
1033    pub const fn new(code: KeyCode, modifiers: KeyModifiers) -> KeyEvent {
1034        KeyEvent {
1035            code,
1036            modifiers,
1037            kind: KeyEventKind::Press,
1038            state: KeyEventState::empty(),
1039        }
1040    }
1041
1042    pub const fn new_with_kind(
1043        code: KeyCode,
1044        modifiers: KeyModifiers,
1045        kind: KeyEventKind,
1046    ) -> KeyEvent {
1047        KeyEvent {
1048            code,
1049            modifiers,
1050            kind,
1051            state: KeyEventState::empty(),
1052        }
1053    }
1054
1055    pub const fn new_with_kind_and_state(
1056        code: KeyCode,
1057        modifiers: KeyModifiers,
1058        kind: KeyEventKind,
1059        state: KeyEventState,
1060    ) -> KeyEvent {
1061        KeyEvent {
1062            code,
1063            modifiers,
1064            kind,
1065            state,
1066        }
1067    }
1068
1069    // modifies the KeyEvent,
1070    // so that KeyModifiers::SHIFT is present iff
1071    // an uppercase char is present.
1072    fn normalize_case(mut self) -> KeyEvent {
1073        let c = match self.code {
1074            KeyCode::Char(c) => c,
1075            _ => return self,
1076        };
1077
1078        if c.is_ascii_uppercase() {
1079            self.modifiers.insert(KeyModifiers::SHIFT);
1080        } else if self.modifiers.contains(KeyModifiers::SHIFT) {
1081            self.code = KeyCode::Char(c.to_ascii_uppercase())
1082        }
1083        self
1084    }
1085
1086    /// Returns whether the key event is a press event.
1087    pub fn is_press(&self) -> bool {
1088        matches!(self.kind, KeyEventKind::Press)
1089    }
1090
1091    /// Returns whether the key event is a release event.
1092    pub fn is_release(&self) -> bool {
1093        matches!(self.kind, KeyEventKind::Release)
1094    }
1095
1096    /// Returns whether the key event is a repeat event.
1097    pub fn is_repeat(&self) -> bool {
1098        matches!(self.kind, KeyEventKind::Repeat)
1099    }
1100}
1101
1102impl From<KeyCode> for KeyEvent {
1103    fn from(code: KeyCode) -> Self {
1104        KeyEvent {
1105            code,
1106            modifiers: KeyModifiers::empty(),
1107            kind: KeyEventKind::Press,
1108            state: KeyEventState::empty(),
1109        }
1110    }
1111}
1112
1113impl PartialEq for KeyEvent {
1114    fn eq(&self, other: &KeyEvent) -> bool {
1115        let KeyEvent {
1116            code: lhs_code,
1117            modifiers: lhs_modifiers,
1118            kind: lhs_kind,
1119            state: lhs_state,
1120        } = self.normalize_case();
1121        let KeyEvent {
1122            code: rhs_code,
1123            modifiers: rhs_modifiers,
1124            kind: rhs_kind,
1125            state: rhs_state,
1126        } = other.normalize_case();
1127        (lhs_code == rhs_code)
1128            && (lhs_modifiers == rhs_modifiers)
1129            && (lhs_kind == rhs_kind)
1130            && (lhs_state == rhs_state)
1131    }
1132}
1133
1134impl Eq for KeyEvent {}
1135
1136impl Hash for KeyEvent {
1137    fn hash<H: Hasher>(&self, hash_state: &mut H) {
1138        let KeyEvent {
1139            code,
1140            modifiers,
1141            kind,
1142            state,
1143        } = self.normalize_case();
1144        code.hash(hash_state);
1145        modifiers.hash(hash_state);
1146        kind.hash(hash_state);
1147        state.hash(hash_state);
1148    }
1149}
1150
1151/// Represents a media key (as part of [`KeyCode::Media`]).
1152#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
1153#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1154pub enum MediaKeyCode {
1155    /// Play media key.
1156    Play,
1157    /// Pause media key.
1158    Pause,
1159    /// Play/Pause media key.
1160    PlayPause,
1161    /// Reverse media key.
1162    Reverse,
1163    /// Stop media key.
1164    Stop,
1165    /// Fast-forward media key.
1166    FastForward,
1167    /// Rewind media key.
1168    Rewind,
1169    /// Next-track media key.
1170    TrackNext,
1171    /// Previous-track media key.
1172    TrackPrevious,
1173    /// Record media key.
1174    Record,
1175    /// Lower-volume media key.
1176    LowerVolume,
1177    /// Raise-volume media key.
1178    RaiseVolume,
1179    /// Mute media key.
1180    MuteVolume,
1181}
1182
1183impl Display for MediaKeyCode {
1184    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1185        match self {
1186            MediaKeyCode::Play => write!(f, "Play"),
1187            MediaKeyCode::Pause => write!(f, "Pause"),
1188            MediaKeyCode::PlayPause => write!(f, "Play/Pause"),
1189            MediaKeyCode::Reverse => write!(f, "Reverse"),
1190            MediaKeyCode::Stop => write!(f, "Stop"),
1191            MediaKeyCode::FastForward => write!(f, "Fast Forward"),
1192            MediaKeyCode::Rewind => write!(f, "Rewind"),
1193            MediaKeyCode::TrackNext => write!(f, "Next Track"),
1194            MediaKeyCode::TrackPrevious => write!(f, "Previous Track"),
1195            MediaKeyCode::Record => write!(f, "Record"),
1196            MediaKeyCode::LowerVolume => write!(f, "Lower Volume"),
1197            MediaKeyCode::RaiseVolume => write!(f, "Raise Volume"),
1198            MediaKeyCode::MuteVolume => write!(f, "Mute Volume"),
1199        }
1200    }
1201}
1202
1203/// Represents a modifier key (as part of [`KeyCode::Modifier`]).
1204#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
1205#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1206pub enum ModifierKeyCode {
1207    /// Left Shift key.
1208    LeftShift,
1209    /// Left Control key. (Control on macOS, Ctrl on other platforms)
1210    LeftControl,
1211    /// Left Alt key. (Option on macOS, Alt on other platforms)
1212    LeftAlt,
1213    /// Left Super key. (Command on macOS, Windows on Windows, Super on other platforms)
1214    LeftSuper,
1215    /// Left Hyper key.
1216    LeftHyper,
1217    /// Left Meta key.
1218    LeftMeta,
1219    /// Right Shift key.
1220    RightShift,
1221    /// Right Control key. (Control on macOS, Ctrl on other platforms)
1222    RightControl,
1223    /// Right Alt key. (Option on macOS, Alt on other platforms)
1224    RightAlt,
1225    /// Right Super key. (Command on macOS, Windows on Windows, Super on other platforms)
1226    RightSuper,
1227    /// Right Hyper key.
1228    RightHyper,
1229    /// Right Meta key.
1230    RightMeta,
1231    /// Iso Level3 Shift key.
1232    IsoLevel3Shift,
1233    /// Iso Level5 Shift key.
1234    IsoLevel5Shift,
1235}
1236
1237impl Display for ModifierKeyCode {
1238    /// Formats the modifier key using the given formatter.
1239    ///
1240    /// # Platform-specific Notes
1241    ///
1242    /// On macOS, the control, alt, and super keys are displayed as "Control", "Option", and
1243    /// "Command" respectively. See
1244    /// <https://support.apple.com/guide/applestyleguide/welcome/1.0/web>.
1245    ///
1246    /// On Windows, the super key is displayed as "Windows" and the control key is displayed as
1247    /// "Ctrl". See
1248    /// <https://learn.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/term-collections/keys-keyboard-shortcuts>.
1249    ///
1250    /// On other platforms, the super key is referred to as "Super".
1251    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1252        match self {
1253            ModifierKeyCode::LeftShift => write!(f, "Left Shift"),
1254            ModifierKeyCode::LeftHyper => write!(f, "Left Hyper"),
1255            ModifierKeyCode::LeftMeta => write!(f, "Left Meta"),
1256            ModifierKeyCode::RightShift => write!(f, "Right Shift"),
1257            ModifierKeyCode::RightHyper => write!(f, "Right Hyper"),
1258            ModifierKeyCode::RightMeta => write!(f, "Right Meta"),
1259            ModifierKeyCode::IsoLevel3Shift => write!(f, "Iso Level 3 Shift"),
1260            ModifierKeyCode::IsoLevel5Shift => write!(f, "Iso Level 5 Shift"),
1261
1262            #[cfg(target_os = "macos")]
1263            ModifierKeyCode::LeftControl => write!(f, "Left Control"),
1264            #[cfg(not(target_os = "macos"))]
1265            ModifierKeyCode::LeftControl => write!(f, "Left Ctrl"),
1266
1267            #[cfg(target_os = "macos")]
1268            ModifierKeyCode::LeftAlt => write!(f, "Left Option"),
1269            #[cfg(not(target_os = "macos"))]
1270            ModifierKeyCode::LeftAlt => write!(f, "Left Alt"),
1271
1272            #[cfg(target_os = "macos")]
1273            ModifierKeyCode::LeftSuper => write!(f, "Left Command"),
1274            #[cfg(target_os = "windows")]
1275            ModifierKeyCode::LeftSuper => write!(f, "Left Windows"),
1276            #[cfg(not(any(target_os = "macos", target_os = "windows")))]
1277            ModifierKeyCode::LeftSuper => write!(f, "Left Super"),
1278
1279            #[cfg(target_os = "macos")]
1280            ModifierKeyCode::RightControl => write!(f, "Right Control"),
1281            #[cfg(not(target_os = "macos"))]
1282            ModifierKeyCode::RightControl => write!(f, "Right Ctrl"),
1283
1284            #[cfg(target_os = "macos")]
1285            ModifierKeyCode::RightAlt => write!(f, "Right Option"),
1286            #[cfg(not(target_os = "macos"))]
1287            ModifierKeyCode::RightAlt => write!(f, "Right Alt"),
1288
1289            #[cfg(target_os = "macos")]
1290            ModifierKeyCode::RightSuper => write!(f, "Right Command"),
1291            #[cfg(target_os = "windows")]
1292            ModifierKeyCode::RightSuper => write!(f, "Right Windows"),
1293            #[cfg(not(any(target_os = "macos", target_os = "windows")))]
1294            ModifierKeyCode::RightSuper => write!(f, "Right Super"),
1295        }
1296    }
1297}
1298
1299/// Represents a key.
1300#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
1301#[cfg_attr(feature = "derive-more", derive(IsVariant))]
1302#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1303pub enum KeyCode {
1304    /// Backspace key (Delete on macOS, Backspace on other platforms).
1305    Backspace,
1306    /// Enter key.
1307    Enter,
1308    /// Left arrow key.
1309    Left,
1310    /// Right arrow key.
1311    Right,
1312    /// Up arrow key.
1313    Up,
1314    /// Down arrow key.
1315    Down,
1316    /// Home key.
1317    Home,
1318    /// End key.
1319    End,
1320    /// Page up key.
1321    PageUp,
1322    /// Page down key.
1323    PageDown,
1324    /// Tab key.
1325    Tab,
1326    /// Shift + Tab key.
1327    BackTab,
1328    /// Delete key. (Fn+Delete on macOS, Delete on other platforms)
1329    Delete,
1330    /// Insert key.
1331    Insert,
1332    /// F key.
1333    ///
1334    /// `KeyCode::F(1)` represents F1 key, etc.
1335    #[cfg_attr(feature = "derive-more", is_variant(ignore))]
1336    F(u8),
1337    /// A character.
1338    ///
1339    /// `KeyCode::Char('c')` represents `c` character, etc.
1340    #[cfg_attr(feature = "derive-more", is_variant(ignore))]
1341    Char(char),
1342    /// Null.
1343    Null,
1344    /// Escape key.
1345    Esc,
1346    /// Caps Lock key.
1347    ///
1348    /// **Note:** this key can only be read if
1349    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
1350    /// [`PushKeyboardEnhancementFlags`].
1351    CapsLock,
1352    /// Scroll Lock key.
1353    ///
1354    /// **Note:** this key can only be read if
1355    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
1356    /// [`PushKeyboardEnhancementFlags`].
1357    ScrollLock,
1358    /// Num Lock key.
1359    ///
1360    /// **Note:** this key can only be read if
1361    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
1362    /// [`PushKeyboardEnhancementFlags`].
1363    NumLock,
1364    /// Print Screen key.
1365    ///
1366    /// **Note:** this key can only be read if
1367    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
1368    /// [`PushKeyboardEnhancementFlags`].
1369    PrintScreen,
1370    /// Pause key.
1371    ///
1372    /// **Note:** this key can only be read if
1373    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
1374    /// [`PushKeyboardEnhancementFlags`].
1375    Pause,
1376    /// Menu key.
1377    ///
1378    /// **Note:** this key can only be read if
1379    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
1380    /// [`PushKeyboardEnhancementFlags`].
1381    Menu,
1382    /// The "Begin" key (often mapped to the 5 key when Num Lock is turned on).
1383    ///
1384    /// **Note:** this key can only be read if
1385    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
1386    /// [`PushKeyboardEnhancementFlags`].
1387    KeypadBegin,
1388    /// A media key.
1389    ///
1390    /// **Note:** these keys can only be read if
1391    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
1392    /// [`PushKeyboardEnhancementFlags`].
1393    #[cfg_attr(feature = "derive-more", is_variant(ignore))]
1394    Media(MediaKeyCode),
1395    /// A modifier key.
1396    ///
1397    /// **Note:** these keys can only be read if **both**
1398    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] and
1399    /// [`KeyboardEnhancementFlags::REPORT_ALL_KEYS_AS_ESCAPE_CODES`] have been enabled with
1400    /// [`PushKeyboardEnhancementFlags`].
1401    #[cfg_attr(feature = "derive-more", is_variant(ignore))]
1402    Modifier(ModifierKeyCode),
1403}
1404
1405impl KeyCode {
1406    /// Returns `true` if the key code is the given function key.
1407    ///
1408    /// # Examples
1409    ///
1410    /// ```
1411    /// # use crossterm::event::KeyCode;
1412    /// assert!(KeyCode::F(1).is_function_key(1));
1413    /// assert!(!KeyCode::F(1).is_function_key(2));
1414    /// ```
1415    pub fn is_function_key(&self, n: u8) -> bool {
1416        matches!(self, KeyCode::F(m) if *m == n)
1417    }
1418
1419    /// Returns `true` if the key code is the given character.
1420    ///
1421    /// # Examples
1422    ///
1423    /// ```
1424    /// # use crossterm::event::KeyCode;
1425    /// assert!(KeyCode::Char('a').is_char('a'));
1426    /// assert!(!KeyCode::Char('a').is_char('b'));
1427    /// assert!(!KeyCode::F(1).is_char('a'));
1428    /// ```
1429    pub fn is_char(&self, c: char) -> bool {
1430        matches!(self, KeyCode::Char(m) if *m == c)
1431    }
1432
1433    /// Returns the character if the key code is a character key.
1434    ///
1435    /// Returns `None` if the key code is not a character key.
1436    ///
1437    /// # Examples
1438    ///
1439    /// ```
1440    /// # use crossterm::event::KeyCode;
1441    /// assert_eq!(KeyCode::Char('a').as_char(), Some('a'));
1442    /// assert_eq!(KeyCode::F(1).as_char(), None);
1443    /// ```
1444    pub fn as_char(&self) -> Option<char> {
1445        match self {
1446            KeyCode::Char(c) => Some(*c),
1447            _ => None,
1448        }
1449    }
1450
1451    /// Returns `true` if the key code is the given media key.
1452    ///
1453    /// **Note:** this method requires
1454    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] to be enabled with
1455    /// [`PushKeyboardEnhancementFlags`].
1456    ///
1457    /// # Examples
1458    ///
1459    /// ```
1460    /// # use crossterm::event::{KeyCode, MediaKeyCode};
1461    /// assert!(KeyCode::Media(MediaKeyCode::Play).is_media_key(MediaKeyCode::Play));
1462    /// assert!(!KeyCode::Media(MediaKeyCode::Play).is_media_key(MediaKeyCode::Pause));
1463    /// ```
1464    pub fn is_media_key(&self, media: MediaKeyCode) -> bool {
1465        matches!(self, KeyCode::Media(m) if *m == media)
1466    }
1467
1468    /// Returns `true` if the key code is the given modifier key.
1469    ///
1470    /// **Note:** this method requires both
1471    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] and
1472    /// [`KeyboardEnhancementFlags::REPORT_ALL_KEYS_AS_ESCAPE_CODES`] to be enabled with
1473    /// [`PushKeyboardEnhancementFlags`].
1474    ///
1475    /// # Examples
1476    ///
1477    /// ```
1478    /// # use crossterm::event::{KeyCode, ModifierKeyCode};
1479    /// assert!(KeyCode::Modifier(ModifierKeyCode::LeftShift).is_modifier(ModifierKeyCode::LeftShift));
1480    /// assert!(!KeyCode::Modifier(ModifierKeyCode::LeftShift).is_modifier(ModifierKeyCode::RightShift));
1481    /// ```
1482    pub fn is_modifier(&self, modifier: ModifierKeyCode) -> bool {
1483        matches!(self, KeyCode::Modifier(m) if *m == modifier)
1484    }
1485}
1486
1487impl Display for KeyCode {
1488    /// Formats the `KeyCode` using the given formatter.
1489    ///
1490    /// # Platform-specific Notes
1491    ///
1492    /// On macOS, the Backspace key is displayed as "Delete", the Delete key is displayed as "Fwd
1493    /// Del", and the Enter key is displayed as "Return". See
1494    /// <https://support.apple.com/guide/applestyleguide/welcome/1.0/web>.
1495    ///
1496    /// On other platforms, the Backspace key is displayed as "Backspace", the Delete key is
1497    /// displayed as "Del", and the Enter key is displayed as "Enter".
1498    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1499        match self {
1500            // On macOS, the Backspace key is called "Delete" and the Delete key is called "Fwd Del".
1501            #[cfg(target_os = "macos")]
1502            KeyCode::Backspace => write!(f, "Delete"),
1503            #[cfg(target_os = "macos")]
1504            KeyCode::Delete => write!(f, "Fwd Del"),
1505
1506            #[cfg(not(target_os = "macos"))]
1507            KeyCode::Backspace => write!(f, "Backspace"),
1508            #[cfg(not(target_os = "macos"))]
1509            KeyCode::Delete => write!(f, "Del"),
1510
1511            #[cfg(target_os = "macos")]
1512            KeyCode::Enter => write!(f, "Return"),
1513            #[cfg(not(target_os = "macos"))]
1514            KeyCode::Enter => write!(f, "Enter"),
1515            KeyCode::Left => write!(f, "Left"),
1516            KeyCode::Right => write!(f, "Right"),
1517            KeyCode::Up => write!(f, "Up"),
1518            KeyCode::Down => write!(f, "Down"),
1519            KeyCode::Home => write!(f, "Home"),
1520            KeyCode::End => write!(f, "End"),
1521            KeyCode::PageUp => write!(f, "Page Up"),
1522            KeyCode::PageDown => write!(f, "Page Down"),
1523            KeyCode::Tab => write!(f, "Tab"),
1524            KeyCode::BackTab => write!(f, "Back Tab"),
1525            KeyCode::Insert => write!(f, "Insert"),
1526            KeyCode::F(n) => write!(f, "F{}", n),
1527            KeyCode::Char(c) => match c {
1528                // special case for non-visible characters
1529                ' ' => write!(f, "Space"),
1530                c => write!(f, "{}", c),
1531            },
1532            KeyCode::Null => write!(f, "Null"),
1533            KeyCode::Esc => write!(f, "Esc"),
1534            KeyCode::CapsLock => write!(f, "Caps Lock"),
1535            KeyCode::ScrollLock => write!(f, "Scroll Lock"),
1536            KeyCode::NumLock => write!(f, "Num Lock"),
1537            KeyCode::PrintScreen => write!(f, "Print Screen"),
1538            KeyCode::Pause => write!(f, "Pause"),
1539            KeyCode::Menu => write!(f, "Menu"),
1540            KeyCode::KeypadBegin => write!(f, "Begin"),
1541            KeyCode::Media(media) => write!(f, "{}", media),
1542            KeyCode::Modifier(modifier) => write!(f, "{}", modifier),
1543        }
1544    }
1545}
1546
1547/// An internal event.
1548///
1549/// Encapsulates publicly available `Event` with additional internal
1550/// events that shouldn't be publicly available to the crate users.
1551#[derive(Debug, PartialOrd, PartialEq, Hash, Clone, Eq)]
1552pub(crate) enum InternalEvent {
1553    /// An event.
1554    Event(Event),
1555    /// A cursor position (`col`, `row`).
1556    #[cfg(unix)]
1557    CursorPosition(u16, u16),
1558    /// The progressive keyboard enhancement flags enabled by the terminal.
1559    #[cfg(unix)]
1560    KeyboardEnhancementFlags(KeyboardEnhancementFlags),
1561    /// The terminal's current mode of the synchronized output feature.
1562    #[cfg(unix)]
1563    SynchronizedOutputMode(SynchronizedOutputMode),
1564    /// Attributes and architectural class of the terminal.
1565    #[cfg(unix)]
1566    PrimaryDeviceAttributes,
1567}
1568
1569/// The selected color scheme of the terminal.
1570///
1571/// This information can be queried from terminals implementing Contour's [VT extension for theme
1572/// mode updates](https://github.com/contour-terminal/contour/blob/master/docs/vt-extensions/color-palette-update-notifications.md).
1573/// Applications can subscribe to updates to the theme mode with [EnableThemeModeUpdates] and
1574/// unsubscribe with [DisableThemeModeUpdates].
1575#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1576#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1577pub enum ThemeMode {
1578    Light,
1579    Dark,
1580}
1581
1582/// The current state of features supported by the terminal.
1583///
1584/// This can be queried with [terminal::terminal_features].
1585#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
1586#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1587pub struct TerminalFeatures {
1588    pub keyboard_enhancement_flags: Option<KeyboardEnhancementFlags>,
1589    pub synchronized_output_mode: SynchronizedOutputMode,
1590    pub theme_mode: Option<ThemeMode>,
1591}
1592
1593#[cfg(test)]
1594mod tests {
1595    use std::collections::hash_map::DefaultHasher;
1596    use std::hash::{Hash, Hasher};
1597
1598    use super::*;
1599    use KeyCode::*;
1600    use MediaKeyCode::*;
1601    use ModifierKeyCode::*;
1602
1603    #[test]
1604    fn test_equality() {
1605        let lowercase_d_with_shift = KeyEvent::new(KeyCode::Char('d'), KeyModifiers::SHIFT);
1606        let uppercase_d_with_shift = KeyEvent::new(KeyCode::Char('D'), KeyModifiers::SHIFT);
1607        let uppercase_d = KeyEvent::new(KeyCode::Char('D'), KeyModifiers::NONE);
1608        assert_eq!(lowercase_d_with_shift, uppercase_d_with_shift);
1609        assert_eq!(uppercase_d, uppercase_d_with_shift);
1610    }
1611
1612    #[test]
1613    fn test_hash() {
1614        let lowercase_d_with_shift_hash = {
1615            let mut hasher = DefaultHasher::new();
1616            KeyEvent::new(KeyCode::Char('d'), KeyModifiers::SHIFT).hash(&mut hasher);
1617            hasher.finish()
1618        };
1619        let uppercase_d_with_shift_hash = {
1620            let mut hasher = DefaultHasher::new();
1621            KeyEvent::new(KeyCode::Char('D'), KeyModifiers::SHIFT).hash(&mut hasher);
1622            hasher.finish()
1623        };
1624        let uppercase_d_hash = {
1625            let mut hasher = DefaultHasher::new();
1626            KeyEvent::new(KeyCode::Char('D'), KeyModifiers::NONE).hash(&mut hasher);
1627            hasher.finish()
1628        };
1629        assert_eq!(lowercase_d_with_shift_hash, uppercase_d_with_shift_hash);
1630        assert_eq!(uppercase_d_hash, uppercase_d_with_shift_hash);
1631    }
1632
1633    #[test]
1634    fn keycode_display() {
1635        #[cfg(target_os = "macos")]
1636        {
1637            assert_eq!(format!("{}", Backspace), "Delete");
1638            assert_eq!(format!("{}", Delete), "Fwd Del");
1639            assert_eq!(format!("{}", Enter), "Return");
1640        }
1641        #[cfg(not(target_os = "macos"))]
1642        {
1643            assert_eq!(format!("{}", Backspace), "Backspace");
1644            assert_eq!(format!("{}", Delete), "Del");
1645            assert_eq!(format!("{}", Enter), "Enter");
1646        }
1647        assert_eq!(format!("{}", Left), "Left");
1648        assert_eq!(format!("{}", Right), "Right");
1649        assert_eq!(format!("{}", Up), "Up");
1650        assert_eq!(format!("{}", Down), "Down");
1651        assert_eq!(format!("{}", Home), "Home");
1652        assert_eq!(format!("{}", End), "End");
1653        assert_eq!(format!("{}", PageUp), "Page Up");
1654        assert_eq!(format!("{}", PageDown), "Page Down");
1655        assert_eq!(format!("{}", Tab), "Tab");
1656        assert_eq!(format!("{}", BackTab), "Back Tab");
1657        assert_eq!(format!("{}", Insert), "Insert");
1658        assert_eq!(format!("{}", F(1)), "F1");
1659        assert_eq!(format!("{}", Char('a')), "a");
1660        assert_eq!(format!("{}", Null), "Null");
1661        assert_eq!(format!("{}", Esc), "Esc");
1662        assert_eq!(format!("{}", CapsLock), "Caps Lock");
1663        assert_eq!(format!("{}", ScrollLock), "Scroll Lock");
1664        assert_eq!(format!("{}", NumLock), "Num Lock");
1665        assert_eq!(format!("{}", PrintScreen), "Print Screen");
1666        assert_eq!(format!("{}", KeyCode::Pause), "Pause");
1667        assert_eq!(format!("{}", Menu), "Menu");
1668        assert_eq!(format!("{}", KeypadBegin), "Begin");
1669    }
1670
1671    #[test]
1672    fn media_keycode_display() {
1673        assert_eq!(format!("{}", Media(Play)), "Play");
1674        assert_eq!(format!("{}", Media(MediaKeyCode::Pause)), "Pause");
1675        assert_eq!(format!("{}", Media(PlayPause)), "Play/Pause");
1676        assert_eq!(format!("{}", Media(Reverse)), "Reverse");
1677        assert_eq!(format!("{}", Media(Stop)), "Stop");
1678        assert_eq!(format!("{}", Media(FastForward)), "Fast Forward");
1679        assert_eq!(format!("{}", Media(Rewind)), "Rewind");
1680        assert_eq!(format!("{}", Media(TrackNext)), "Next Track");
1681        assert_eq!(format!("{}", Media(TrackPrevious)), "Previous Track");
1682        assert_eq!(format!("{}", Media(Record)), "Record");
1683        assert_eq!(format!("{}", Media(LowerVolume)), "Lower Volume");
1684        assert_eq!(format!("{}", Media(RaiseVolume)), "Raise Volume");
1685        assert_eq!(format!("{}", Media(MuteVolume)), "Mute Volume");
1686    }
1687
1688    #[test]
1689    fn modifier_keycode_display() {
1690        assert_eq!(format!("{}", Modifier(LeftShift)), "Left Shift");
1691        assert_eq!(format!("{}", Modifier(LeftHyper)), "Left Hyper");
1692        assert_eq!(format!("{}", Modifier(LeftMeta)), "Left Meta");
1693        assert_eq!(format!("{}", Modifier(RightShift)), "Right Shift");
1694        assert_eq!(format!("{}", Modifier(RightHyper)), "Right Hyper");
1695        assert_eq!(format!("{}", Modifier(RightMeta)), "Right Meta");
1696        assert_eq!(format!("{}", Modifier(IsoLevel3Shift)), "Iso Level 3 Shift");
1697        assert_eq!(format!("{}", Modifier(IsoLevel5Shift)), "Iso Level 5 Shift");
1698    }
1699
1700    #[cfg(target_os = "macos")]
1701    #[test]
1702    fn modifier_keycode_display_macos() {
1703        assert_eq!(format!("{}", Modifier(LeftControl)), "Left Control");
1704        assert_eq!(format!("{}", Modifier(LeftAlt)), "Left Option");
1705        assert_eq!(format!("{}", Modifier(LeftSuper)), "Left Command");
1706        assert_eq!(format!("{}", Modifier(RightControl)), "Right Control");
1707        assert_eq!(format!("{}", Modifier(RightAlt)), "Right Option");
1708        assert_eq!(format!("{}", Modifier(RightSuper)), "Right Command");
1709    }
1710
1711    #[cfg(target_os = "windows")]
1712    #[test]
1713    fn modifier_keycode_display_windows() {
1714        assert_eq!(format!("{}", Modifier(LeftControl)), "Left Ctrl");
1715        assert_eq!(format!("{}", Modifier(LeftAlt)), "Left Alt");
1716        assert_eq!(format!("{}", Modifier(LeftSuper)), "Left Windows");
1717        assert_eq!(format!("{}", Modifier(RightControl)), "Right Ctrl");
1718        assert_eq!(format!("{}", Modifier(RightAlt)), "Right Alt");
1719        assert_eq!(format!("{}", Modifier(RightSuper)), "Right Windows");
1720    }
1721
1722    #[cfg(not(any(target_os = "macos", target_os = "windows")))]
1723    #[test]
1724    fn modifier_keycode_display_other() {
1725        assert_eq!(format!("{}", Modifier(LeftControl)), "Left Ctrl");
1726        assert_eq!(format!("{}", Modifier(LeftAlt)), "Left Alt");
1727        assert_eq!(format!("{}", Modifier(LeftSuper)), "Left Super");
1728        assert_eq!(format!("{}", Modifier(RightControl)), "Right Ctrl");
1729        assert_eq!(format!("{}", Modifier(RightAlt)), "Right Alt");
1730        assert_eq!(format!("{}", Modifier(RightSuper)), "Right Super");
1731    }
1732
1733    #[test]
1734    fn key_modifiers_display() {
1735        let modifiers = KeyModifiers::SHIFT | KeyModifiers::CONTROL | KeyModifiers::ALT;
1736
1737        #[cfg(target_os = "macos")]
1738        assert_eq!(modifiers.to_string(), "Shift+Control+Option");
1739
1740        #[cfg(target_os = "windows")]
1741        assert_eq!(modifiers.to_string(), "Shift+Ctrl+Alt");
1742
1743        #[cfg(not(any(target_os = "macos", target_os = "windows")))]
1744        assert_eq!(modifiers.to_string(), "Shift+Control+Alt");
1745    }
1746
1747    const ESC_PRESSED: KeyEvent =
1748        KeyEvent::new_with_kind(KeyCode::Esc, KeyModifiers::empty(), KeyEventKind::Press);
1749    const ESC_RELEASED: KeyEvent =
1750        KeyEvent::new_with_kind(KeyCode::Esc, KeyModifiers::empty(), KeyEventKind::Release);
1751    const ESC_REPEAT: KeyEvent =
1752        KeyEvent::new_with_kind(KeyCode::Esc, KeyModifiers::empty(), KeyEventKind::Repeat);
1753    const MOUSE_CLICK: MouseEvent = MouseEvent {
1754        kind: MouseEventKind::Down(MouseButton::Left),
1755        column: 1,
1756        row: 1,
1757        modifiers: KeyModifiers::empty(),
1758    };
1759
1760    #[cfg(feature = "derive-more")]
1761    #[test]
1762    fn event_is() {
1763        let event = Event::FocusGained;
1764        assert!(event.is_focus_gained());
1765        assert!(event.is_focus_gained());
1766        assert!(!event.is_key());
1767
1768        let event = Event::FocusLost;
1769        assert!(event.is_focus_lost());
1770        assert!(!event.is_focus_gained());
1771        assert!(!event.is_key());
1772
1773        let event = Event::Resize(1, 1);
1774        assert!(event.is_resize());
1775        assert!(!event.is_key());
1776
1777        let event = Event::Key(ESC_PRESSED);
1778        assert!(event.is_key());
1779        assert!(event.is_key_press());
1780        assert!(!event.is_key_release());
1781        assert!(!event.is_key_repeat());
1782        assert!(!event.is_focus_gained());
1783
1784        let event = Event::Key(ESC_RELEASED);
1785        assert!(event.is_key());
1786        assert!(!event.is_key_press());
1787        assert!(event.is_key_release());
1788        assert!(!event.is_key_repeat());
1789        assert!(!event.is_focus_gained());
1790
1791        let event = Event::Key(ESC_REPEAT);
1792        assert!(event.is_key());
1793        assert!(!event.is_key_press());
1794        assert!(!event.is_key_release());
1795        assert!(event.is_key_repeat());
1796        assert!(!event.is_focus_gained());
1797
1798        let event = Event::Mouse(MOUSE_CLICK);
1799        assert!(event.is_mouse());
1800        assert!(!event.is_key());
1801
1802        #[cfg(feature = "bracketed-paste")]
1803        {
1804            let event = Event::Paste("".to_string());
1805            assert!(event.is_paste());
1806            assert!(!event.is_key());
1807        }
1808    }
1809
1810    #[test]
1811    fn event_as() {
1812        let event = Event::FocusGained;
1813        assert_eq!(event.as_key_event(), None);
1814
1815        let event = Event::Key(ESC_PRESSED);
1816        assert_eq!(event.as_key_event(), Some(ESC_PRESSED));
1817        assert_eq!(event.as_key_press_event(), Some(ESC_PRESSED));
1818        assert_eq!(event.as_key_release_event(), None);
1819        assert_eq!(event.as_key_repeat_event(), None);
1820        assert_eq!(event.as_resize_event(), None);
1821
1822        let event = Event::Key(ESC_RELEASED);
1823        assert_eq!(event.as_key_event(), Some(ESC_RELEASED));
1824        assert_eq!(event.as_key_release_event(), Some(ESC_RELEASED));
1825        assert_eq!(event.as_key_press_event(), None);
1826        assert_eq!(event.as_key_repeat_event(), None);
1827        assert_eq!(event.as_resize_event(), None);
1828
1829        let event = Event::Key(ESC_REPEAT);
1830        assert_eq!(event.as_key_event(), Some(ESC_REPEAT));
1831        assert_eq!(event.as_key_repeat_event(), Some(ESC_REPEAT));
1832        assert_eq!(event.as_key_press_event(), None);
1833        assert_eq!(event.as_key_release_event(), None);
1834        assert_eq!(event.as_resize_event(), None);
1835
1836        let event = Event::Resize(1, 1);
1837        assert_eq!(event.as_resize_event(), Some((1, 1)));
1838        assert_eq!(event.as_key_event(), None);
1839
1840        let event = Event::Mouse(MOUSE_CLICK);
1841        assert_eq!(event.as_mouse_event(), Some(MOUSE_CLICK));
1842        assert_eq!(event.as_key_event(), None);
1843
1844        #[cfg(feature = "bracketed-paste")]
1845        {
1846            let event = Event::Paste("".to_string());
1847            assert_eq!(event.as_paste_event(), Some(""));
1848            assert_eq!(event.as_key_event(), None);
1849        }
1850    }
1851}