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}