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