From 632326387b56da217fceb7b16a5aabd61b89e0e9 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Mon, 25 Nov 2024 18:04:53 -0800 Subject: [PATCH 1/3] Add is_ and as_ methods to the event enums Often application code only cares about a small subset of possible events. These methods make it simpler to write code which checks whether an event is a particular event type or converts events into the specific type (returning an Option). This can help simplify some nested match blocks. E.g.: ```rust match event { Event::Key(key) if key.kind == KeyEventKind::Press => { ... } } ``` becomes: ```rust if let Some(key) = event.as_key_press() { ... } ``` Similar flexible methods are aded across all the event enums: - `Event::is_focus_gained()` - `Event::is_focus_lost()` - `Event::is_key()` - `Event::is_mouse()` - `Event::is_paste()` - `Event::is_resize()` - `Event::is_key_press()` - `Event::as_key_press() -> Option<&KeyEvent>` - `MouseEventKind::is_*()` - `MouseButton::is_*()` - `KeyEventKind::is_*()` - `KeyEvent::is_press()` - `KeyEvent::is_release()` - `KeyEvent::is_repeat()` - `KeyCode::is_*()` - `KeyCode::is_function_key(n)` - `KeyCode::is_char(c)` - `KeyCode::as_char() -> Option` - `KeyCode::is_media_key(media)` - `KeyCode::is_modifier(modifier)` --- Cargo.toml | 1 + src/event.rs | 252 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 248 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d3b026e7..34d44e8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ use-dev-tty = ["filedescriptor", "rustix/process"] [dependencies] bitflags = { version = "2.3" } +derive_more = { version = "1.0.0", features = ["is_variant"] } document-features = "0.2.10" futures-core = { version = "0.3", optional = true, default-features = false } parking_lot = "0.12" diff --git a/src/event.rs b/src/event.rs index 4d28dc15..ece2658b 100644 --- a/src/event.rs +++ b/src/event.rs @@ -126,6 +126,7 @@ pub(crate) mod stream; pub(crate) mod sys; pub(crate) mod timeout; +use derive_more::derive::IsVariant; #[cfg(feature = "event-stream")] pub use stream::EventStream; @@ -543,7 +544,7 @@ impl Command for PopKeyboardEnhancementFlags { /// Represents an event. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(not(feature = "bracketed-paste"), derive(Copy))] -#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Hash)] +#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Hash, IsVariant)] pub enum Event { /// The terminal gained focus FocusGained, @@ -562,6 +563,63 @@ pub enum Event { Resize(u16, u16), } +impl Event { + /// Returns `true` if the event is a key press event. + /// + /// This is useful for waiting for any key press event, regardless of the key that was pressed. + /// + /// Returns `false` for key release and repeat events (as well as for non-key events). + /// + /// # Examples + /// + /// The following code runs a loop that processes events until a key press event is encountered: + /// + /// ```no_run + /// use crossterm::event; + /// + /// while !event::read()?.is_key_press() { + /// // ... + /// } + /// ``` + #[inline] + pub fn is_key_press(&self) -> bool { + matches!( + self, + Event::Key(KeyEvent { + kind: KeyEventKind::Press, + .. + }) + ) + } + + /// Returns an Option containing the KeyEvent if the event is a key press event. + /// + /// This is a convenience method that makes apps that only care about key press events, and not + /// key release or repeat events (or non-key events), easier to write. + /// + /// Returns `None` for key release and repeat events (as well as for non-key events). + /// + /// # Examples + /// + /// The following code runs a loop that only processes key press events: + /// + /// ```no_run + /// use crossterm::event; + /// + /// while let Ok(event) = event::read() { + /// if let Some(key) = event.as_key_press() { + /// // ... + /// } + /// } + #[inline] + pub fn as_key_press(&self) -> Option<&KeyEvent> { + match self { + Event::Key(event) if self.is_key_press() => Some(event), + _ => None, + } + } +} + /// Represents a mouse event. /// /// # Platform-specific Notes @@ -600,7 +658,7 @@ pub struct MouseEvent { /// `MouseEventKind::Up` and `MouseEventKind::Drag` events. `MouseButton::Left` /// is returned if we don't know which button was used. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] +#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash, IsVariant)] pub enum MouseEventKind { /// Pressed mouse button. Contains the button that was pressed. Down(MouseButton), @@ -622,7 +680,7 @@ pub enum MouseEventKind { /// Represents a mouse button. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] +#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash, IsVariant)] pub enum MouseButton { /// Left mouse button. Left, @@ -702,7 +760,7 @@ impl Display for KeyModifiers { /// Represents a keyboard event kind. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] +#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash, IsVariant)] pub enum KeyEventKind { Press, Repeat, @@ -806,6 +864,21 @@ impl KeyEvent { } self } + + /// Returns whether the key event is a press event. + pub fn is_press(&self) -> bool { + self.kind.is_press() + } + + /// Returns whether the key event is a release event. + pub fn is_release(&self) -> bool { + self.kind.is_release() + } + + /// Returns whether the key event is a repeat event. + pub fn is_repeat(&self) -> bool { + self.kind.is_repeat() + } } impl From for KeyEvent { @@ -1006,7 +1079,7 @@ impl Display for ModifierKeyCode { } /// Represents a key. -#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] +#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash, IsVariant)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum KeyCode { /// Backspace key (Delete on macOS, Backspace on other platforms). @@ -1040,10 +1113,12 @@ pub enum KeyCode { /// F key. /// /// `KeyCode::F(1)` represents F1 key, etc. + #[is_variant(ignore)] F(u8), /// A character. /// /// `KeyCode::Char('c')` represents `c` character, etc. + #[is_variant(ignore)] Char(char), /// Null. Null, @@ -1096,6 +1171,7 @@ pub enum KeyCode { /// **Note:** these keys can only be read if /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with /// [`PushKeyboardEnhancementFlags`]. + #[is_variant(ignore)] Media(MediaKeyCode), /// A modifier key. /// @@ -1103,9 +1179,92 @@ pub enum KeyCode { /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] and /// [`KeyboardEnhancementFlags::REPORT_ALL_KEYS_AS_ESCAPE_CODES`] have been enabled with /// [`PushKeyboardEnhancementFlags`]. + #[is_variant(ignore)] Modifier(ModifierKeyCode), } +impl KeyCode { + /// Returns `true` if the key code is the given function key. + /// + /// # Examples + /// + /// ``` + /// # use crossterm::event::KeyCode; + /// assert!(KeyCode::F(1).is_function_key(1)); + /// assert!(!KeyCode::F(1).is_function_key(2)); + /// ``` + pub fn is_function_key(&self, n: u8) -> bool { + matches!(self, KeyCode::F(m) if *m == n) + } + + /// Returns `true` if the key code is the given character. + /// + /// # Examples + /// + /// ``` + /// # use crossterm::event::KeyCode; + /// assert!(KeyCode::Char('a').is_char('a')); + /// assert!(!KeyCode::Char('a').is_char('b')); + /// assert!(!KeyCode::F(1).is_char('a')); + /// ``` + pub fn is_char(&self, c: char) -> bool { + matches!(self, KeyCode::Char(m) if *m == c) + } + + /// Returns the character if the key code is a character key. + /// + /// Returns `None` if the key code is not a character key. + /// + /// # Examples + /// + /// ``` + /// # use crossterm::event::KeyCode; + /// assert_eq!(KeyCode::Char('a').as_char(), Some('a')); + /// assert_eq!(KeyCode::F(1).as_char(), None); + /// ``` + pub fn as_char(&self) -> Option { + match self { + KeyCode::Char(c) => Some(*c), + _ => None, + } + } + + /// Returns `true` if the key code is the given media key. + /// + /// **Note:** this method requires + /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] to be enabled with + /// [`PushKeyboardEnhancementFlags`]. + /// + /// # Examples + /// + /// ``` + /// # use crossterm::event::{KeyCode, MediaKeyCode}; + /// assert!(KeyCode::Media(MediaKeyCode::Play).is_media_key(MediaKeyCode::Play)); + /// assert!(!KeyCode::Media(MediaKeyCode::Play).is_media_key(MediaKeyCode::Pause)); + /// ``` + pub fn is_media_key(&self, media: MediaKeyCode) -> bool { + matches!(self, KeyCode::Media(m) if *m == media) + } + + /// Returns `true` if the key code is the given modifier key. + /// + /// **Note:** this method requires both + /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] and + /// [`KeyboardEnhancementFlags::REPORT_ALL_KEYS_AS_ESCAPE_CODES`] to be enabled with + /// [`PushKeyboardEnhancementFlags`]. + /// + /// # Examples + /// + /// ``` + /// # use crossterm::event::{KeyCode, ModifierKeyCode}; + /// assert!(KeyCode::Modifier(ModifierKeyCode::LeftShift).is_modifier(ModifierKeyCode::LeftShift)); + /// assert!(!KeyCode::Modifier(ModifierKeyCode::LeftShift).is_modifier(ModifierKeyCode::RightShift)); + /// ``` + pub fn is_modifier(&self, modifier: ModifierKeyCode) -> bool { + matches!(self, KeyCode::Modifier(m) if *m == modifier) + } +} + impl Display for KeyCode { /// Formats the `KeyCode` using the given formatter. /// @@ -1324,4 +1483,87 @@ mod tests { assert_eq!(format!("{}", Modifier(RightAlt)), "Right Alt"); assert_eq!(format!("{}", Modifier(RightSuper)), "Right Super"); } + + #[test] + fn test_event_is() { + let event = Event::FocusGained; + assert!(event.is_focus_gained()); + assert!(!event.is_key()); + + let event = Event::FocusLost; + assert!(event.is_focus_lost()); + assert!(!event.is_key()); + + let event = Event::Resize(1, 1); + assert!(event.is_resize()); + assert!(!event.is_key()); + + let event = Event::Key(KeyCode::Esc.into()); + assert!(event.is_key()); + assert!(!event.is_focus_gained()); + + let event = Event::Mouse(MouseEvent { + kind: MouseEventKind::Down(MouseButton::Left), + column: 1, + row: 1, + modifiers: KeyModifiers::empty(), + }); + assert!(event.is_mouse()); + assert!(!event.is_key()); + } + + const ESC_PRESSED: KeyEvent = + KeyEvent::new_with_kind(KeyCode::Esc, KeyModifiers::empty(), KeyEventKind::Press); + const ESC_RELEASED: KeyEvent = + KeyEvent::new_with_kind(KeyCode::Esc, KeyModifiers::empty(), KeyEventKind::Release); + const ESC_REPEAT: KeyEvent = + KeyEvent::new_with_kind(KeyCode::Esc, KeyModifiers::empty(), KeyEventKind::Repeat); + + #[test] + fn test_event_is_key_press() { + let event = Event::Key(ESC_PRESSED); + assert!(event.is_key_press()); + + let event = Event::Key(ESC_RELEASED); + assert!(!event.is_key_press()); + + let event = Event::Key(ESC_REPEAT); + assert!(!event.is_key_press()); + + let event = Event::FocusGained; + assert!(!event.is_key_press()); + } + + #[test] + fn test_event_as_key_press() { + let event = Event::Key(ESC_PRESSED); + assert_eq!(event.as_key_press(), Some(&ESC_PRESSED)); + + let event = Event::Key(ESC_RELEASED); + assert_eq!(event.as_key_press(), None); + + let event = Event::Key(ESC_REPEAT); + assert_eq!(event.as_key_press(), None); + + let event = Event::FocusGained; + assert_eq!(event.as_key_press(), None); + } + + #[test] + fn test_key_event_is() { + let event = ESC_PRESSED; + assert!(event.is_press()); + assert!(!event.is_release()); + assert!(!event.is_repeat()); + + let event = ESC_RELEASED; + assert!(!event.is_press()); + assert!(event.is_release()); + assert!(!event.is_repeat()); + + let event = ESC_REPEAT; + assert!(!event.is_press()); + assert!(!event.is_release()); + assert!(event.is_repeat()); + } } From 5dea800b6890a54c4af0e33ecc6f2a3f63170045 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Mon, 25 Nov 2024 18:29:03 -0800 Subject: [PATCH 2/3] Use as_key_press() in example --- examples/event-match-modifiers.rs | 67 +++++++++++++++---------------- src/event.rs | 1 + 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/examples/event-match-modifiers.rs b/examples/event-match-modifiers.rs index c3f75e95..ac9daefd 100644 --- a/examples/event-match-modifiers.rs +++ b/examples/event-match-modifiers.rs @@ -4,43 +4,42 @@ use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; -fn match_event(read_event: Event) { - match read_event { - // Match one one modifier: - Event::Key(KeyEvent { - modifiers: KeyModifiers::CONTROL, - code, - .. - }) => { - println!("Control + {:?}", code); - } - Event::Key(KeyEvent { - modifiers: KeyModifiers::SHIFT, - code, - .. - }) => { - println!("Shift + {:?}", code); - } - Event::Key(KeyEvent { - modifiers: KeyModifiers::ALT, - code, - .. - }) => { - println!("Alt + {:?}", code); - } +fn match_event(event: Event) { + if let Some(key) = event.as_key_press() { + match key { + KeyEvent { + modifiers: KeyModifiers::CONTROL, + code, + .. + } => { + println!("Control + {:?}", code); + } + KeyEvent { + modifiers: KeyModifiers::SHIFT, + code, + .. + } => { + println!("Shift + {:?}", code); + } + KeyEvent { + modifiers: KeyModifiers::ALT, + code, + .. + } => { + println!("Alt + {:?}", code); + } - // Match on multiple modifiers: - Event::Key(KeyEvent { - code, modifiers, .. - }) => { - if modifiers == (KeyModifiers::ALT | KeyModifiers::SHIFT) { - println!("Alt + Shift {:?}", code); - } else { - println!("({:?}) with key: {:?}", modifiers, code) + // Match on multiple modifiers: + KeyEvent { + code, modifiers, .. + } => { + if *modifiers == (KeyModifiers::ALT | KeyModifiers::SHIFT) { + println!("Alt + Shift {:?}", code); + } else { + println!("({:?}) with key: {:?}", modifiers, code) + } } } - - _ => {} } } diff --git a/src/event.rs b/src/event.rs index ece2658b..c36f740e 100644 --- a/src/event.rs +++ b/src/event.rs @@ -580,6 +580,7 @@ impl Event { /// while !event::read()?.is_key_press() { /// // ... /// } + /// # Ok::<(), std::io::Error>(()) /// ``` #[inline] pub fn is_key_press(&self) -> bool { From 5ee493105b9102381fb416a5d070303b808190f5 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Thu, 26 Dec 2024 00:03:52 -0800 Subject: [PATCH 3/3] Add several more methods relating event ergonomics - add is_key_release() and is_key_repeat() checks - add as_key_event() - rename as_key_press() to as_key_press_event() - add as_key_repeat_event() - add as_key_release_event() - add as_mouse_event() - add as_paste_event() - more tests - update event-match and key-display examples --- examples/event-match-modifiers.rs | 4 +- examples/key-display.rs | 29 ++-- src/event.rs | 259 ++++++++++++++++++++++++------ 3 files changed, 222 insertions(+), 70 deletions(-) diff --git a/examples/event-match-modifiers.rs b/examples/event-match-modifiers.rs index ac9daefd..20b6405f 100644 --- a/examples/event-match-modifiers.rs +++ b/examples/event-match-modifiers.rs @@ -5,7 +5,7 @@ use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; fn match_event(event: Event) { - if let Some(key) = event.as_key_press() { + if let Some(key) = event.as_key_press_event() { match key { KeyEvent { modifiers: KeyModifiers::CONTROL, @@ -33,7 +33,7 @@ fn match_event(event: Event) { KeyEvent { code, modifiers, .. } => { - if *modifiers == (KeyModifiers::ALT | KeyModifiers::SHIFT) { + if modifiers == (KeyModifiers::ALT | KeyModifiers::SHIFT) { println!("Alt + Shift {:?}", code); } else { println!("({:?}) with key: {:?}", modifiers, code) diff --git a/examples/key-display.rs b/examples/key-display.rs index c5ea7b8d..ed60c9d8 100644 --- a/examples/key-display.rs +++ b/examples/key-display.rs @@ -7,9 +7,9 @@ use std::io; -use crossterm::event::{KeyEventKind, KeyModifiers}; +use crossterm::event::KeyModifiers; use crossterm::{ - event::{read, Event, KeyCode}, + event::{read, KeyCode}, terminal::{disable_raw_mode, enable_raw_mode}, }; @@ -29,20 +29,17 @@ fn main() -> io::Result<()> { } fn print_events() -> io::Result<()> { - loop { - let event = read()?; - match event { - Event::Key(event) if event.kind == KeyEventKind::Press => { - print!("Key pressed: "); - if event.modifiers != KeyModifiers::NONE { - print!("{}+", event.modifiers); - } - println!("{}\r", event.code); - if event.code == KeyCode::Esc { - break; - } - } - _ => {} + while let Ok(event) = read() { + let Some(event) = event.as_key_press_event() else { + continue; + }; + let modifier = match event.modifiers { + KeyModifiers::NONE => "".to_string(), + _ => format!("{:}+", event.modifiers), + }; + println!("Key pressed: {modifier}{code}\r", code = event.code); + if event.code == KeyCode::Esc { + break; } } Ok(()) diff --git a/src/event.rs b/src/event.rs index c36f740e..5e809bd2 100644 --- a/src/event.rs +++ b/src/event.rs @@ -593,6 +593,54 @@ impl Event { ) } + /// Returns `true` if the event is a key release event. + #[inline] + pub fn is_key_release(&self) -> bool { + matches!( + self, + Event::Key(KeyEvent { + kind: KeyEventKind::Release, + .. + }) + ) + } + + /// Returns `true` if the event is a key repeat event. + #[inline] + pub fn is_key_repeat(&self) -> bool { + matches!( + self, + Event::Key(KeyEvent { + kind: KeyEventKind::Repeat, + .. + }) + ) + } + + /// Returns the key event if the event is a key event, otherwise `None`. + /// + /// This is a convenience method that makes apps that only care about key events easier to write. + /// + /// # Examples + /// + /// The following code runs a loop that only processes key events: + /// + /// ```no_run + /// use crossterm::event; + /// + /// while let Some(key_event) = event::read()?.as_key_event() { + /// // ... + /// } + /// # std::io::Result::Ok(()) + /// ``` + #[inline] + pub fn as_key_event(&self) -> Option { + match self { + Event::Key(event) => Some(*event), + _ => None, + } + } + /// Returns an Option containing the KeyEvent if the event is a key press event. /// /// This is a convenience method that makes apps that only care about key press events, and not @@ -608,14 +656,100 @@ impl Event { /// use crossterm::event; /// /// while let Ok(event) = event::read() { - /// if let Some(key) = event.as_key_press() { + /// if let Some(key) = event.as_key_press_event() { /// // ... /// } /// } #[inline] - pub fn as_key_press(&self) -> Option<&KeyEvent> { + pub fn as_key_press_event(&self) -> Option { + match self { + Event::Key(event) if self.is_key_press() => Some(*event), + _ => None, + } + } + + /// Returns an Option containing the KeyEvent if the event is a key release event. + #[inline] + pub fn as_key_release_event(&self) -> Option { + match self { + Event::Key(event) if event.kind == KeyEventKind::Release => Some(*event), + _ => None, + } + } + + /// Returns an Option containing the KeyEvent if the event is a key repeat event. + #[inline] + pub fn as_key_repeat_event(&self) -> Option { + match self { + Event::Key(event) if event.kind == KeyEventKind::Repeat => Some(*event), + _ => None, + } + } + + /// Returns the mouse event if the event is a mouse event, otherwise `None`. + /// + /// This is a convenience method that makes code which only cares about mouse events easier to + /// write. + /// + /// # Examples + /// + /// ```no_run + /// use crossterm::event; + /// + /// while let Some(mouse_event) = event::read()?.as_mouse_event() { + /// // ... + /// } + /// # std::io::Result::Ok(()) + /// ``` + #[inline] + pub fn as_mouse_event(&self) -> Option { + match self { + Event::Mouse(event) => Some(*event), + _ => None, + } + } + + /// Returns the pasted string if the event is a paste event, otherwise `None`. + /// + /// This is a convenience method that makes code which only cares about paste events easier to write. + /// + /// # Examples + /// + /// ```no_run + /// use crossterm::event; + /// + /// while let Some(paste) = event::read()?.as_paste_event() { + /// // ... + /// } + /// # std::io::Result::Ok(()) + /// ``` + #[cfg(feature = "bracketed-paste")] + #[inline] + pub fn as_paste_event(&self) -> Option<&str> { + match self { + Event::Paste(paste) => Some(paste), + _ => None, + } + } + + /// Returns the size as a tuple if the event is a resize event, otherwise `None`. + /// + /// This is a convenience method that makes code which only cares about resize events easier to write. + /// + /// # Examples + /// + /// ```no_run + /// use crossterm::event; + /// + /// while let Some((columns, rows)) = event::read()?.as_resize_event() { + /// // ... + /// } + /// # std::io::Result::Ok(()) + /// ``` + #[inline] + pub fn as_resize_event(&self) -> Option<(u16, u16)> { match self { - Event::Key(event) if self.is_key_press() => Some(event), + Event::Resize(columns, rows) => Some((*columns, *rows)), _ => None, } } @@ -1485,86 +1619,107 @@ mod tests { assert_eq!(format!("{}", Modifier(RightSuper)), "Right Super"); } + const ESC_PRESSED: KeyEvent = + KeyEvent::new_with_kind(KeyCode::Esc, KeyModifiers::empty(), KeyEventKind::Press); + const ESC_RELEASED: KeyEvent = + KeyEvent::new_with_kind(KeyCode::Esc, KeyModifiers::empty(), KeyEventKind::Release); + const ESC_REPEAT: KeyEvent = + KeyEvent::new_with_kind(KeyCode::Esc, KeyModifiers::empty(), KeyEventKind::Repeat); + const MOUSE_CLICK: MouseEvent = MouseEvent { + kind: MouseEventKind::Down(MouseButton::Left), + column: 1, + row: 1, + modifiers: KeyModifiers::empty(), + }; + #[test] - fn test_event_is() { + fn event_is() { let event = Event::FocusGained; assert!(event.is_focus_gained()); + assert!(event.is_focus_gained()); assert!(!event.is_key()); let event = Event::FocusLost; assert!(event.is_focus_lost()); + assert!(!event.is_focus_gained()); assert!(!event.is_key()); let event = Event::Resize(1, 1); assert!(event.is_resize()); assert!(!event.is_key()); - let event = Event::Key(KeyCode::Esc.into()); - assert!(event.is_key()); - assert!(!event.is_focus_gained()); - - let event = Event::Mouse(MouseEvent { - kind: MouseEventKind::Down(MouseButton::Left), - column: 1, - row: 1, - modifiers: KeyModifiers::empty(), - }); - assert!(event.is_mouse()); - assert!(!event.is_key()); - } - - const ESC_PRESSED: KeyEvent = - KeyEvent::new_with_kind(KeyCode::Esc, KeyModifiers::empty(), KeyEventKind::Press); - const ESC_RELEASED: KeyEvent = - KeyEvent::new_with_kind(KeyCode::Esc, KeyModifiers::empty(), KeyEventKind::Release); - const ESC_REPEAT: KeyEvent = - KeyEvent::new_with_kind(KeyCode::Esc, KeyModifiers::empty(), KeyEventKind::Repeat); - - #[test] - fn test_event_is_key_press() { let event = Event::Key(ESC_PRESSED); + assert!(event.is_key()); assert!(event.is_key_press()); + assert!(!event.is_key_release()); + assert!(!event.is_key_repeat()); + assert!(!event.is_focus_gained()); let event = Event::Key(ESC_RELEASED); + assert!(event.is_key()); assert!(!event.is_key_press()); + assert!(event.is_key_release()); + assert!(!event.is_key_repeat()); + assert!(!event.is_focus_gained()); let event = Event::Key(ESC_REPEAT); + assert!(event.is_key()); assert!(!event.is_key_press()); + assert!(!event.is_key_release()); + assert!(event.is_key_repeat()); + assert!(!event.is_focus_gained()); - let event = Event::FocusGained; - assert!(!event.is_key_press()); + let event = Event::Mouse(MOUSE_CLICK); + assert!(event.is_mouse()); + assert!(!event.is_key()); + + #[cfg(feature = "bracketed-paste")] + { + let event = Event::Paste("".to_string()); + assert!(event.is_paste()); + assert!(!event.is_key()); + } } #[test] - fn test_event_as_key_press() { + fn event_as() { + let event = Event::FocusGained; + assert_eq!(event.as_key_event(), None); + let event = Event::Key(ESC_PRESSED); - assert_eq!(event.as_key_press(), Some(&ESC_PRESSED)); + assert_eq!(event.as_key_event(), Some(ESC_PRESSED)); + assert_eq!(event.as_key_press_event(), Some(ESC_PRESSED)); + assert_eq!(event.as_key_release_event(), None); + assert_eq!(event.as_key_repeat_event(), None); + assert_eq!(event.as_resize_event(), None); let event = Event::Key(ESC_RELEASED); - assert_eq!(event.as_key_press(), None); + assert_eq!(event.as_key_event(), Some(ESC_RELEASED)); + assert_eq!(event.as_key_release_event(), Some(ESC_RELEASED)); + assert_eq!(event.as_key_press_event(), None); + assert_eq!(event.as_key_repeat_event(), None); + assert_eq!(event.as_resize_event(), None); let event = Event::Key(ESC_REPEAT); - assert_eq!(event.as_key_press(), None); + assert_eq!(event.as_key_event(), Some(ESC_REPEAT)); + assert_eq!(event.as_key_repeat_event(), Some(ESC_REPEAT)); + assert_eq!(event.as_key_press_event(), None); + assert_eq!(event.as_key_release_event(), None); + assert_eq!(event.as_resize_event(), None); - let event = Event::FocusGained; - assert_eq!(event.as_key_press(), None); - } + let event = Event::Resize(1, 1); + assert_eq!(event.as_resize_event(), Some((1, 1))); + assert_eq!(event.as_key_event(), None); - #[test] - fn test_key_event_is() { - let event = ESC_PRESSED; - assert!(event.is_press()); - assert!(!event.is_release()); - assert!(!event.is_repeat()); - - let event = ESC_RELEASED; - assert!(!event.is_press()); - assert!(event.is_release()); - assert!(!event.is_repeat()); - - let event = ESC_REPEAT; - assert!(!event.is_press()); - assert!(!event.is_release()); - assert!(event.is_repeat()); + let event = Event::Mouse(MOUSE_CLICK); + assert_eq!(event.as_mouse_event(), Some(MOUSE_CLICK)); + assert_eq!(event.as_key_event(), None); + + #[cfg(feature = "bracketed-paste")] + { + let event = Event::Paste("".to_string()); + assert_eq!(event.as_paste_event(), Some("")); + assert_eq!(event.as_key_event(), None); + } } }