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

Provided by KDAB

Privacy Policy