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}