crossterm/
event.rs

1//! # Event
2//!
3//! The `event` module provides the functionality to read keyboard, mouse and terminal resize events.
4//!
5//! * The [`read`](fn.read.html) function returns an [`Event`](enum.Event.html) immediately
6//! (if available) or blocks until an [`Event`](enum.Event.html) is available.
7//!
8//! * The [`poll`](fn.poll.html) function allows you to check if there is or isn't an [`Event`](enum.Event.html) available
9//! within the given period of time. In other words - if subsequent call to the [`read`](fn.read.html)
10//! function will block or not.
11//!
12//! It's **not allowed** to call these functions from different threads or combine them with the
13//! [`EventStream`](struct.EventStream.html). You're allowed to either:
14//!
15//! * use the [`read`](fn.read.html) & [`poll`](fn.poll.html) functions on any, but same, thread
16//! * or the [`EventStream`](struct.EventStream.html).
17//!
18//! **Make sure to enable [raw mode](../terminal/index.html#raw-mode) in order for keyboard events to work properly**
19//!
20//! ## Mouse Events
21//!
22//! Mouse events are not enabled by default. You have to enable them with the
23//! [`EnableMouseCapture`](struct.EnableMouseCapture.html) command. See [Command API](../index.html#command-api)
24//! for more information.
25//!
26//! ## Examples
27//!
28//! Blocking read:
29//!
30//! ```no_run
31//! use crossterm::event::{read, Event};
32//!
33//! fn print_events() -> crossterm::Result<()> {
34//!     loop {
35//!         // `read()` blocks until an `Event` is available
36//!         match read()? {
37//!             Event::FocusGained => println!("FocusGained"),
38//!             Event::FocusLost => println!("FocusLost"),
39//!             Event::Key(event) => println!("{:?}", event),
40//!             Event::Mouse(event) => println!("{:?}", event),
41//!             #[cfg(feature = "bracketed-paste")]
42//!             Event::Paste(data) => println!("{:?}", data),
43//!             Event::Resize(width, height) => println!("New size {}x{}", width, height),
44//!         }
45//!     }
46//!     Ok(())
47//! }
48//! ```
49//!
50//! Non-blocking read:
51//!
52//! ```no_run
53//! use std::time::Duration;
54//!
55//! use crossterm::event::{poll, read, Event};
56//!
57//! fn print_events() -> crossterm::Result<()> {
58//!     loop {
59//!         // `poll()` waits for an `Event` for a given time period
60//!         if poll(Duration::from_millis(500))? {
61//!             // It's guaranteed that the `read()` won't block when the `poll()`
62//!             // function returns `true`
63//!             match read()? {
64//!                 Event::FocusGained => println!("FocusGained"),
65//!                 Event::FocusLost => println!("FocusLost"),
66//!                 Event::Key(event) => println!("{:?}", event),
67//!                 Event::Mouse(event) => println!("{:?}", event),
68//!                 #[cfg(feature = "bracketed-paste")]
69//!                 Event::Paste(data) => println!("Pasted {:?}", data),
70//!                 Event::Resize(width, height) => println!("New size {}x{}", width, height),
71//!             }
72//!         } else {
73//!             // Timeout expired and no `Event` is available
74//!         }
75//!     }
76//!     Ok(())
77//! }
78//! ```
79//!
80//! Check the [examples](https://github.com/crossterm-rs/crossterm/tree/master/examples) folder for more of
81//! them (`event-*`).
82
83use std::fmt;
84use std::hash::{Hash, Hasher};
85#[cfg(windows)]
86use std::io;
87use std::time::Duration;
88
89use bitflags::bitflags;
90use parking_lot::{MappedMutexGuard, Mutex, MutexGuard};
91#[cfg(feature = "serde")]
92use serde::{Deserialize, Serialize};
93
94use crate::{csi, Command, Result};
95use filter::{EventFilter, Filter};
96use read::InternalEventReader;
97#[cfg(feature = "event-stream")]
98pub use stream::EventStream;
99use timeout::PollTimeout;
100
101pub(crate) mod filter;
102mod read;
103mod source;
104#[cfg(feature = "event-stream")]
105mod stream;
106pub(crate) mod sys;
107mod timeout;
108
109/// Static instance of `InternalEventReader`.
110/// This needs to be static because there can be one event reader.
111static INTERNAL_EVENT_READER: Mutex<Option<InternalEventReader>> = parking_lot::const_mutex(None);
112
113fn lock_internal_event_reader() -> MappedMutexGuard<'static, InternalEventReader> {
114    MutexGuard::map(INTERNAL_EVENT_READER.lock(), |reader| {
115        reader.get_or_insert_with(InternalEventReader::default)
116    })
117}
118fn try_lock_internal_event_reader_for(
119    duration: Duration,
120) -> Option<MappedMutexGuard<'static, InternalEventReader>> {
121    Some(MutexGuard::map(
122        INTERNAL_EVENT_READER.try_lock_for(duration)?,
123        |reader| reader.get_or_insert_with(InternalEventReader::default),
124    ))
125}
126
127/// Checks if there is an [`Event`](enum.Event.html) available.
128///
129/// Returns `Ok(true)` if an [`Event`](enum.Event.html) is available otherwise it returns `Ok(false)`.
130///
131/// `Ok(true)` guarantees that subsequent call to the [`read`](fn.read.html) function
132/// won't block.
133///
134/// # Arguments
135///
136/// * `timeout` - maximum waiting time for event availability
137///
138/// # Examples
139///
140/// Return immediately:
141///
142/// ```no_run
143/// use std::time::Duration;
144///
145/// use crossterm::{event::poll, Result};
146///
147/// fn is_event_available() -> Result<bool> {
148///     // Zero duration says that the `poll` function must return immediately
149///     // with an `Event` availability information
150///     poll(Duration::from_secs(0))
151/// }
152/// ```
153///
154/// Wait up to 100ms:
155///
156/// ```no_run
157/// use std::time::Duration;
158///
159/// use crossterm::{event::poll, Result};
160///
161/// fn is_event_available() -> Result<bool> {
162///     // Wait for an `Event` availability for 100ms. It returns immediately
163///     // if an `Event` is/becomes available.
164///     poll(Duration::from_millis(100))
165/// }
166/// ```
167pub fn poll(timeout: Duration) -> Result<bool> {
168    poll_internal(Some(timeout), &EventFilter)
169}
170
171/// Reads a single [`Event`](enum.Event.html).
172///
173/// This function blocks until an [`Event`](enum.Event.html) is available. Combine it with the
174/// [`poll`](fn.poll.html) function to get non-blocking reads.
175///
176/// # Examples
177///
178/// Blocking read:
179///
180/// ```no_run
181/// use crossterm::{event::read, Result};
182///
183/// fn print_events() -> Result<bool> {
184///     loop {
185///         // Blocks until an `Event` is available
186///         println!("{:?}", read()?);
187///     }
188/// }
189/// ```
190///
191/// Non-blocking read:
192///
193/// ```no_run
194/// use std::time::Duration;
195///
196/// use crossterm::{event::{read, poll}, Result};
197///
198/// fn print_events() -> Result<bool> {
199///     loop {
200///         if poll(Duration::from_millis(100))? {
201///             // It's guaranteed that `read` won't block, because `poll` returned
202///             // `Ok(true)`.
203///             println!("{:?}", read()?);
204///         } else {
205///             // Timeout expired, no `Event` is available
206///         }
207///     }
208/// }
209/// ```
210pub fn read() -> Result<Event> {
211    match read_internal(&EventFilter)? {
212        InternalEvent::Event(event) => Ok(event),
213        #[cfg(unix)]
214        _ => unreachable!(),
215    }
216}
217
218/// Polls to check if there are any `InternalEvent`s that can be read within the given duration.
219pub(crate) fn poll_internal<F>(timeout: Option<Duration>, filter: &F) -> Result<bool>
220where
221    F: Filter,
222{
223    let (mut reader, timeout) = if let Some(timeout) = timeout {
224        let poll_timeout = PollTimeout::new(Some(timeout));
225        if let Some(reader) = try_lock_internal_event_reader_for(timeout) {
226            (reader, poll_timeout.leftover())
227        } else {
228            return Ok(false);
229        }
230    } else {
231        (lock_internal_event_reader(), None)
232    };
233    reader.poll(timeout, filter)
234}
235
236/// Reads a single `InternalEvent`.
237pub(crate) fn read_internal<F>(filter: &F) -> Result<InternalEvent>
238where
239    F: Filter,
240{
241    let mut reader = lock_internal_event_reader();
242    reader.read(filter)
243}
244
245/// A command that enables mouse event capturing.
246///
247/// Mouse events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html).
248#[derive(Debug, Clone, Copy, PartialEq, Eq)]
249pub struct EnableMouseCapture;
250
251impl Command for EnableMouseCapture {
252    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
253        f.write_str(concat!(
254            // Normal tracking: Send mouse X & Y on button press and release
255            csi!("?1000h"),
256            // Button-event tracking: Report button motion events (dragging)
257            csi!("?1002h"),
258            // Any-event tracking: Report all motion events
259            csi!("?1003h"),
260            // RXVT mouse mode: Allows mouse coordinates of >223
261            csi!("?1015h"),
262            // SGR mouse mode: Allows mouse coordinates of >223, preferred over RXVT mode
263            csi!("?1006h"),
264        ))
265    }
266
267    #[cfg(windows)]
268    fn execute_winapi(&self) -> Result<()> {
269        sys::windows::enable_mouse_capture()
270    }
271
272    #[cfg(windows)]
273    fn is_ansi_code_supported(&self) -> bool {
274        false
275    }
276}
277
278/// A command that disables mouse event capturing.
279///
280/// Mouse events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html).
281#[derive(Debug, Clone, Copy, PartialEq, Eq)]
282pub struct DisableMouseCapture;
283
284impl Command for DisableMouseCapture {
285    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
286        f.write_str(concat!(
287            // The inverse commands of EnableMouseCapture, in reverse order.
288            csi!("?1006l"),
289            csi!("?1015l"),
290            csi!("?1003l"),
291            csi!("?1002l"),
292            csi!("?1000l"),
293        ))
294    }
295
296    #[cfg(windows)]
297    fn execute_winapi(&self) -> Result<()> {
298        sys::windows::disable_mouse_capture()
299    }
300
301    #[cfg(windows)]
302    fn is_ansi_code_supported(&self) -> bool {
303        false
304    }
305}
306
307bitflags! {
308    /// Represents special flags that tell compatible terminals to add extra information to keyboard events.
309    ///
310    /// See <https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement> for more information.
311    ///
312    /// Alternate keys and Unicode codepoints are not yet supported by crossterm.
313    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
314    pub struct KeyboardEnhancementFlags: u8 {
315        /// Represent Escape and modified keys using CSI-u sequences, so they can be unambiguously
316        /// read.
317        const DISAMBIGUATE_ESCAPE_CODES = 0b0000_0001;
318        /// Add extra events with [`KeyEvent.kind`] set to [`KeyEventKind::Repeat`] or
319        /// [`KeyEventKind::Release`] when keys are autorepeated or released.
320        const REPORT_EVENT_TYPES = 0b0000_0010;
321        // Send [alternate keycodes](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#key-codes)
322        // in addition to the base keycode.
323        //
324        // *Note*: these are not yet supported by crossterm.
325        // const REPORT_ALTERNATE_KEYS = 0b0000_0100;
326        /// Represent all keyboard events as CSI-u sequences. This is required to get repeat/release
327        /// events for plain-text keys.
328        const REPORT_ALL_KEYS_AS_ESCAPE_CODES = 0b0000_1000;
329        // Send the Unicode codepoint as well as the keycode.
330        //
331        // *Note*: this is not yet supported by crossterm.
332        // const REPORT_ASSOCIATED_TEXT = 0b0001_0000;
333    }
334}
335
336/// 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.
337///
338/// It should be paired with [`PopKeyboardEnhancementFlags`] at the end of execution.
339///
340/// Example usage:
341/// ```no_run
342/// use std::io::{Write, stdout};
343/// use crossterm::execute;
344/// use crossterm::event::{
345///     KeyboardEnhancementFlags,
346///     PushKeyboardEnhancementFlags,
347///     PopKeyboardEnhancementFlags
348/// };
349///
350/// let mut stdout = stdout();
351///
352/// execute!(
353///     stdout,
354///     PushKeyboardEnhancementFlags(
355///         KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
356///     )
357/// );
358///
359/// // ...
360///
361/// execute!(stdout, PopKeyboardEnhancementFlags);
362/// ```
363///
364/// Note that, currently, only the following support this protocol:
365/// * [kitty terminal](https://sw.kovidgoyal.net/kitty/)
366/// * [foot terminal](https://codeberg.org/dnkl/foot/issues/319)
367/// * [WezTerm terminal](https://wezfurlong.org/wezterm/config/lua/config/enable_kitty_keyboard.html)
368/// * [notcurses library](https://github.com/dankamongmen/notcurses/issues/2131)
369/// * [neovim text editor](https://github.com/neovim/neovim/pull/18181)
370/// * [kakoune text editor](https://github.com/mawww/kakoune/issues/4103)
371/// * [dte text editor](https://gitlab.com/craigbarnes/dte/-/issues/138)
372#[derive(Debug, Clone, Copy, PartialEq, Eq)]
373pub struct PushKeyboardEnhancementFlags(pub KeyboardEnhancementFlags);
374
375impl Command for PushKeyboardEnhancementFlags {
376    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
377        write!(f, "{}{}u", csi!(">"), self.0.bits())
378    }
379
380    #[cfg(windows)]
381    fn execute_winapi(&self) -> Result<()> {
382        Err(io::Error::new(
383            io::ErrorKind::Unsupported,
384            "Keyboard progressive enhancement not implemented for the legacy Windows API.",
385        ))
386    }
387
388    #[cfg(windows)]
389    fn is_ansi_code_supported(&self) -> bool {
390        false
391    }
392}
393
394/// A command that disables extra kinds of keyboard events.
395///
396/// Specifically, it pops one level of keyboard enhancement flags.
397///
398/// See [`PushKeyboardEnhancementFlags`] and <https://sw.kovidgoyal.net/kitty/keyboard-protocol/> for more information.
399#[derive(Debug, Clone, Copy, PartialEq, Eq)]
400pub struct PopKeyboardEnhancementFlags;
401
402impl Command for PopKeyboardEnhancementFlags {
403    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
404        f.write_str(csi!("<1u"))
405    }
406
407    #[cfg(windows)]
408    fn execute_winapi(&self) -> Result<()> {
409        Err(io::Error::new(
410            io::ErrorKind::Unsupported,
411            "Keyboard progressive enhancement not implemented for the legacy Windows API.",
412        ))
413    }
414
415    #[cfg(windows)]
416    fn is_ansi_code_supported(&self) -> bool {
417        false
418    }
419}
420
421/// A command that enables focus event emission.
422///
423/// It should be paired with [`DisableFocusChange`] at the end of execution.
424///
425/// Focus events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html).
426#[derive(Debug, Clone, Copy, PartialEq, Eq)]
427pub struct EnableFocusChange;
428
429impl Command for EnableFocusChange {
430    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
431        f.write_str(csi!("?1004h"))
432    }
433
434    #[cfg(windows)]
435    fn execute_winapi(&self) -> Result<()> {
436        // Focus events are always enabled on Windows
437        Ok(())
438    }
439}
440
441/// A command that disables focus event emission.
442#[derive(Debug, Clone, Copy, PartialEq, Eq)]
443pub struct DisableFocusChange;
444
445impl Command for DisableFocusChange {
446    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
447        f.write_str(csi!("?1004l"))
448    }
449
450    #[cfg(windows)]
451    fn execute_winapi(&self) -> Result<()> {
452        // Focus events can't be disabled on Windows
453        Ok(())
454    }
455}
456
457/// A command that enables [bracketed paste mode](https://en.wikipedia.org/wiki/Bracketed-paste).
458///
459/// It should be paired with [`DisableBracketedPaste`] at the end of execution.
460///
461/// This is not supported in older Windows terminals without
462/// [virtual terminal sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences).
463#[cfg(feature = "bracketed-paste")]
464#[derive(Debug, Clone, Copy, PartialEq, Eq)]
465pub struct EnableBracketedPaste;
466
467#[cfg(feature = "bracketed-paste")]
468impl Command for EnableBracketedPaste {
469    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
470        f.write_str(csi!("?2004h"))
471    }
472
473    #[cfg(windows)]
474    fn execute_winapi(&self) -> Result<()> {
475        Err(io::Error::new(
476            io::ErrorKind::Unsupported,
477            "Bracketed paste not implemented in the legacy Windows API.",
478        ))
479    }
480}
481
482/// A command that disables bracketed paste mode.
483#[cfg(feature = "bracketed-paste")]
484#[derive(Debug, Clone, Copy, PartialEq, Eq)]
485pub struct DisableBracketedPaste;
486
487#[cfg(feature = "bracketed-paste")]
488impl Command for DisableBracketedPaste {
489    fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
490        f.write_str(csi!("?2004l"))
491    }
492
493    #[cfg(windows)]
494    fn execute_winapi(&self) -> Result<()> {
495        Ok(())
496    }
497}
498
499/// Represents an event.
500#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
501#[cfg_attr(not(feature = "bracketed-paste"), derive(Copy))]
502#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Hash)]
503pub enum Event {
504    /// The terminal gained focus
505    FocusGained,
506    /// The terminal lost focus
507    FocusLost,
508    /// A single key event with additional pressed modifiers.
509    Key(KeyEvent),
510    /// A single mouse event with additional pressed modifiers.
511    Mouse(MouseEvent),
512    /// A string that was pasted into the terminal. Only emitted if bracketed paste has been
513    /// enabled.
514    #[cfg(feature = "bracketed-paste")]
515    Paste(String),
516    /// An resize event with new dimensions after resize (columns, rows).
517    /// **Note** that resize events can be occur in batches.
518    Resize(u16, u16),
519}
520
521/// Represents a mouse event.
522///
523/// # Platform-specific Notes
524///
525/// ## Mouse Buttons
526///
527/// Some platforms/terminals do not report mouse button for the
528/// `MouseEventKind::Up` and `MouseEventKind::Drag` events. `MouseButton::Left`
529/// is returned if we don't know which button was used.
530///
531/// ## Key Modifiers
532///
533/// Some platforms/terminals does not report all key modifiers
534/// combinations for all mouse event types. For example - macOS reports
535/// `Ctrl` + left mouse button click as a right mouse button click.
536#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
537#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
538pub struct MouseEvent {
539    /// The kind of mouse event that was caused.
540    pub kind: MouseEventKind,
541    /// The column that the event occurred on.
542    pub column: u16,
543    /// The row that the event occurred on.
544    pub row: u16,
545    /// The key modifiers active when the event occurred.
546    pub modifiers: KeyModifiers,
547}
548
549/// A mouse event kind.
550///
551/// # Platform-specific Notes
552///
553/// ## Mouse Buttons
554///
555/// Some platforms/terminals do not report mouse button for the
556/// `MouseEventKind::Up` and `MouseEventKind::Drag` events. `MouseButton::Left`
557/// is returned if we don't know which button was used.
558#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
559#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
560pub enum MouseEventKind {
561    /// Pressed mouse button. Contains the button that was pressed.
562    Down(MouseButton),
563    /// Released mouse button. Contains the button that was released.
564    Up(MouseButton),
565    /// Moved the mouse cursor while pressing the contained mouse button.
566    Drag(MouseButton),
567    /// Moved the mouse cursor while not pressing a mouse button.
568    Moved,
569    /// Scrolled mouse wheel downwards (towards the user).
570    ScrollDown,
571    /// Scrolled mouse wheel upwards (away from the user).
572    ScrollUp,
573}
574
575/// Represents a mouse button.
576#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
577#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
578pub enum MouseButton {
579    /// Left mouse button.
580    Left,
581    /// Right mouse button.
582    Right,
583    /// Middle mouse button.
584    Middle,
585}
586
587bitflags! {
588    /// Represents key modifiers (shift, control, alt, etc.).
589    ///
590    /// **Note:** `SUPER`, `HYPER`, and `META` can only be read if
591    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
592    /// [`PushKeyboardEnhancementFlags`].
593    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
594    pub struct KeyModifiers: u8 {
595        const SHIFT = 0b0000_0001;
596        const CONTROL = 0b0000_0010;
597        const ALT = 0b0000_0100;
598        const SUPER = 0b0000_1000;
599        const HYPER = 0b0001_0000;
600        const META = 0b0010_0000;
601        const NONE = 0b0000_0000;
602    }
603}
604
605/// Represents a keyboard event kind.
606#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
607#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
608pub enum KeyEventKind {
609    Press,
610    Repeat,
611    Release,
612}
613
614bitflags! {
615    /// Represents extra state about the key event.
616    ///
617    /// **Note:** This state can only be read if
618    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
619    /// [`PushKeyboardEnhancementFlags`].
620    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
621    pub struct KeyEventState: u8 {
622        /// The key event origins from the keypad.
623        const KEYPAD = 0b0000_0001;
624        /// Caps Lock was enabled for this key event.
625        ///
626        /// **Note:** this is set for the initial press of Num Lock itself.
627        const CAPS_LOCK = 0b0000_1000;
628        /// Num Lock was enabled for this key event.
629        ///
630        /// **Note:** this is set for the initial press of Num Lock itself.
631        const NUM_LOCK = 0b0000_1000;
632        const NONE = 0b0000_0000;
633    }
634}
635
636/// Represents a key event.
637#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
638#[derive(Debug, PartialOrd, Clone, Copy)]
639pub struct KeyEvent {
640    /// The key itself.
641    pub code: KeyCode,
642    /// Additional key modifiers.
643    pub modifiers: KeyModifiers,
644    /// Kind of event.
645    pub kind: KeyEventKind,
646    /// Keyboard state.
647    ///
648    /// Only set if [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
649    /// [`PushKeyboardEnhancementFlags`].
650    pub state: KeyEventState,
651}
652
653impl KeyEvent {
654    pub const fn new(code: KeyCode, modifiers: KeyModifiers) -> KeyEvent {
655        KeyEvent {
656            code,
657            modifiers,
658            kind: KeyEventKind::Press,
659            state: KeyEventState::empty(),
660        }
661    }
662
663    pub const fn new_with_kind(
664        code: KeyCode,
665        modifiers: KeyModifiers,
666        kind: KeyEventKind,
667    ) -> KeyEvent {
668        KeyEvent {
669            code,
670            modifiers,
671            kind,
672            state: KeyEventState::empty(),
673        }
674    }
675
676    pub const fn new_with_kind_and_state(
677        code: KeyCode,
678        modifiers: KeyModifiers,
679        kind: KeyEventKind,
680        state: KeyEventState,
681    ) -> KeyEvent {
682        KeyEvent {
683            code,
684            modifiers,
685            kind,
686            state,
687        }
688    }
689
690    // modifies the KeyEvent,
691    // so that KeyModifiers::SHIFT is present iff
692    // an uppercase char is present.
693    fn normalize_case(mut self) -> KeyEvent {
694        let c = match self.code {
695            KeyCode::Char(c) => c,
696            _ => return self,
697        };
698
699        if c.is_ascii_uppercase() {
700            self.modifiers.insert(KeyModifiers::SHIFT);
701        } else if self.modifiers.contains(KeyModifiers::SHIFT) {
702            self.code = KeyCode::Char(c.to_ascii_uppercase())
703        }
704        self
705    }
706}
707
708impl From<KeyCode> for KeyEvent {
709    fn from(code: KeyCode) -> Self {
710        KeyEvent {
711            code,
712            modifiers: KeyModifiers::empty(),
713            kind: KeyEventKind::Press,
714            state: KeyEventState::empty(),
715        }
716    }
717}
718
719impl PartialEq for KeyEvent {
720    fn eq(&self, other: &KeyEvent) -> bool {
721        let KeyEvent {
722            code: lhs_code,
723            modifiers: lhs_modifiers,
724            kind: lhs_kind,
725            state: lhs_state,
726        } = self.normalize_case();
727        let KeyEvent {
728            code: rhs_code,
729            modifiers: rhs_modifiers,
730            kind: rhs_kind,
731            state: rhs_state,
732        } = other.normalize_case();
733        (lhs_code == rhs_code)
734            && (lhs_modifiers == rhs_modifiers)
735            && (lhs_kind == rhs_kind)
736            && (lhs_state == rhs_state)
737    }
738}
739
740impl Eq for KeyEvent {}
741
742impl Hash for KeyEvent {
743    fn hash<H: Hasher>(&self, hash_state: &mut H) {
744        let KeyEvent {
745            code,
746            modifiers,
747            kind,
748            state,
749        } = self.normalize_case();
750        code.hash(hash_state);
751        modifiers.hash(hash_state);
752        kind.hash(hash_state);
753        state.hash(hash_state);
754    }
755}
756
757/// Represents a media key (as part of [`KeyCode::Media`]).
758#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
759#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
760pub enum MediaKeyCode {
761    /// Play media key.
762    Play,
763    /// Pause media key.
764    Pause,
765    /// Play/Pause media key.
766    PlayPause,
767    /// Reverse media key.
768    Reverse,
769    /// Stop media key.
770    Stop,
771    /// Fast-forward media key.
772    FastForward,
773    /// Rewind media key.
774    Rewind,
775    /// Next-track media key.
776    TrackNext,
777    /// Previous-track media key.
778    TrackPrevious,
779    /// Record media key.
780    Record,
781    /// Lower-volume media key.
782    LowerVolume,
783    /// Raise-volume media key.
784    RaiseVolume,
785    /// Mute media key.
786    MuteVolume,
787}
788
789/// Represents a modifier key (as part of [`KeyCode::Modifier`]).
790#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
791#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
792pub enum ModifierKeyCode {
793    /// Left Shift key.
794    LeftShift,
795    /// Left Control key.
796    LeftControl,
797    /// Left Alt key.
798    LeftAlt,
799    /// Left Super key.
800    LeftSuper,
801    /// Left Hyper key.
802    LeftHyper,
803    /// Left Meta key.
804    LeftMeta,
805    /// Right Shift key.
806    RightShift,
807    /// Right Control key.
808    RightControl,
809    /// Right Alt key.
810    RightAlt,
811    /// Right Super key.
812    RightSuper,
813    /// Right Hyper key.
814    RightHyper,
815    /// Right Meta key.
816    RightMeta,
817    /// Iso Level3 Shift key.
818    IsoLevel3Shift,
819    /// Iso Level5 Shift key.
820    IsoLevel5Shift,
821}
822
823/// Represents a key.
824#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
825#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
826pub enum KeyCode {
827    /// Backspace key.
828    Backspace,
829    /// Enter key.
830    Enter,
831    /// Left arrow key.
832    Left,
833    /// Right arrow key.
834    Right,
835    /// Up arrow key.
836    Up,
837    /// Down arrow key.
838    Down,
839    /// Home key.
840    Home,
841    /// End key.
842    End,
843    /// Page up key.
844    PageUp,
845    /// Page down key.
846    PageDown,
847    /// Tab key.
848    Tab,
849    /// Shift + Tab key.
850    BackTab,
851    /// Delete key.
852    Delete,
853    /// Insert key.
854    Insert,
855    /// F key.
856    ///
857    /// `KeyCode::F(1)` represents F1 key, etc.
858    F(u8),
859    /// A character.
860    ///
861    /// `KeyCode::Char('c')` represents `c` character, etc.
862    Char(char),
863    /// Null.
864    Null,
865    /// Escape key.
866    Esc,
867    /// Caps Lock key.
868    ///
869    /// **Note:** this key can only be read if
870    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
871    /// [`PushKeyboardEnhancementFlags`].
872    CapsLock,
873    /// Scroll Lock key.
874    ///
875    /// **Note:** this key can only be read if
876    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
877    /// [`PushKeyboardEnhancementFlags`].
878    ScrollLock,
879    /// Num Lock key.
880    ///
881    /// **Note:** this key can only be read if
882    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
883    /// [`PushKeyboardEnhancementFlags`].
884    NumLock,
885    /// Print Screen key.
886    ///
887    /// **Note:** this key can only be read if
888    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
889    /// [`PushKeyboardEnhancementFlags`].
890    PrintScreen,
891    /// Pause key.
892    ///
893    /// **Note:** this key can only be read if
894    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
895    /// [`PushKeyboardEnhancementFlags`].
896    Pause,
897    /// Menu key.
898    ///
899    /// **Note:** this key can only be read if
900    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
901    /// [`PushKeyboardEnhancementFlags`].
902    Menu,
903    /// The "Begin" key (often mapped to the 5 key when Num Lock is turned on).
904    ///
905    /// **Note:** this key can only be read if
906    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
907    /// [`PushKeyboardEnhancementFlags`].
908    KeypadBegin,
909    /// A media key.
910    ///
911    /// **Note:** these keys can only be read if
912    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
913    /// [`PushKeyboardEnhancementFlags`].
914    Media(MediaKeyCode),
915    /// A modifier key.
916    ///
917    /// **Note:** these keys can only be read if **both**
918    /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] and
919    /// [`KeyboardEnhancementFlags::REPORT_ALL_KEYS_AS_ESCAPE_CODES`] have been enabled with
920    /// [`PushKeyboardEnhancementFlags`].
921    Modifier(ModifierKeyCode),
922}
923
924/// An internal event.
925///
926/// Encapsulates publicly available `Event` with additional internal
927/// events that shouldn't be publicly available to the crate users.
928#[derive(Debug, PartialOrd, PartialEq, Hash, Clone, Eq)]
929pub(crate) enum InternalEvent {
930    /// An event.
931    Event(Event),
932    /// A cursor position (`col`, `row`).
933    #[cfg(unix)]
934    CursorPosition(u16, u16),
935}
936
937#[cfg(test)]
938mod tests {
939    use std::collections::hash_map::DefaultHasher;
940    use std::hash::{Hash, Hasher};
941
942    use super::{KeyCode, KeyEvent, KeyModifiers};
943
944    #[test]
945    fn test_equality() {
946        let lowercase_d_with_shift = KeyEvent::new(KeyCode::Char('d'), KeyModifiers::SHIFT);
947        let uppercase_d_with_shift = KeyEvent::new(KeyCode::Char('D'), KeyModifiers::SHIFT);
948        let uppercase_d = KeyEvent::new(KeyCode::Char('D'), KeyModifiers::NONE);
949        assert_eq!(lowercase_d_with_shift, uppercase_d_with_shift);
950        assert_eq!(uppercase_d, uppercase_d_with_shift);
951    }
952
953    #[test]
954    fn test_hash() {
955        let lowercase_d_with_shift_hash = {
956            let mut hasher = DefaultHasher::new();
957            KeyEvent::new(KeyCode::Char('d'), KeyModifiers::SHIFT).hash(&mut hasher);
958            hasher.finish()
959        };
960        let uppercase_d_with_shift_hash = {
961            let mut hasher = DefaultHasher::new();
962            KeyEvent::new(KeyCode::Char('D'), KeyModifiers::SHIFT).hash(&mut hasher);
963            hasher.finish()
964        };
965        let uppercase_d_hash = {
966            let mut hasher = DefaultHasher::new();
967            KeyEvent::new(KeyCode::Char('D'), KeyModifiers::NONE).hash(&mut hasher);
968            hasher.finish()
969        };
970        assert_eq!(lowercase_d_with_shift_hash, uppercase_d_with_shift_hash);
971        assert_eq!(uppercase_d_hash, uppercase_d_with_shift_hash);
972    }
973}