Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_text/tests/annealer_corpus/crossterm_event.rs

57.6 KiB, 1 run

created by r1870400018:11714, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

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