@@ -126,6 +126,7 @@ pub(crate) mod stream;
126126pub ( crate ) mod sys;
127127pub ( crate ) mod timeout;
128128
129+ use derive_more:: derive:: IsVariant ;
129130#[ cfg( feature = "event-stream" ) ]
130131pub use stream:: EventStream ;
131132
@@ -543,7 +544,7 @@ impl Command for PopKeyboardEnhancementFlags {
543544/// Represents an event.
544545#[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
545546#[ cfg_attr( not( feature = "bracketed-paste" ) , derive( Copy ) ) ]
546- #[ derive( Debug , PartialOrd , PartialEq , Eq , Clone , Hash ) ]
547+ #[ derive( Debug , PartialOrd , PartialEq , Eq , Clone , Hash , IsVariant ) ]
547548pub enum Event {
548549 /// The terminal gained focus
549550 FocusGained ,
@@ -562,6 +563,63 @@ pub enum Event {
562563 Resize ( u16 , u16 ) ,
563564}
564565
566+ impl Event {
567+ /// Returns `true` if the event is a key press event.
568+ ///
569+ /// This is useful for waiting for any key press event, regardless of the key that was pressed.
570+ ///
571+ /// Returns `false` for key release and repeat events (as well as for non-key events).
572+ ///
573+ /// # Examples
574+ ///
575+ /// The following code runs a loop that processes events until a key press event is encountered:
576+ ///
577+ /// ```no_run
578+ /// use crossterm::event;
579+ ///
580+ /// while !event::read()?.is_key_press() {
581+ /// // ...
582+ /// }
583+ /// ```
584+ #[ inline]
585+ pub fn is_key_press ( & self ) -> bool {
586+ matches ! (
587+ self ,
588+ Event :: Key ( KeyEvent {
589+ kind: KeyEventKind :: Press ,
590+ ..
591+ } )
592+ )
593+ }
594+
595+ /// Returns an Option containing the KeyEvent if the event is a key press event.
596+ ///
597+ /// This is a convenience method that makes apps that only care about key press events, and not
598+ /// key release or repeat events (or non-key events), easier to write.
599+ ///
600+ /// Returns `None` for key release and repeat events (as well as for non-key events).
601+ ///
602+ /// # Examples
603+ ///
604+ /// The following code runs a loop that only processes key press events:
605+ ///
606+ /// ```no_run
607+ /// use crossterm::event;
608+ ///
609+ /// while let Ok(event) = event::read() {
610+ /// if let Some(key) = event.as_key_press() {
611+ /// // ...
612+ /// }
613+ /// }
614+ #[ inline]
615+ pub fn as_key_press ( & self ) -> Option < & KeyEvent > {
616+ match self {
617+ Event :: Key ( event) if self . is_key_press ( ) => Some ( event) ,
618+ _ => None ,
619+ }
620+ }
621+ }
622+
565623/// Represents a mouse event.
566624///
567625/// # Platform-specific Notes
@@ -600,7 +658,7 @@ pub struct MouseEvent {
600658/// `MouseEventKind::Up` and `MouseEventKind::Drag` events. `MouseButton::Left`
601659/// is returned if we don't know which button was used.
602660#[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
603- #[ derive( Debug , PartialOrd , PartialEq , Eq , Clone , Copy , Hash ) ]
661+ #[ derive( Debug , PartialOrd , PartialEq , Eq , Clone , Copy , Hash , IsVariant ) ]
604662pub enum MouseEventKind {
605663 /// Pressed mouse button. Contains the button that was pressed.
606664 Down ( MouseButton ) ,
@@ -622,7 +680,7 @@ pub enum MouseEventKind {
622680
623681/// Represents a mouse button.
624682#[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
625- #[ derive( Debug , PartialOrd , PartialEq , Eq , Clone , Copy , Hash ) ]
683+ #[ derive( Debug , PartialOrd , PartialEq , Eq , Clone , Copy , Hash , IsVariant ) ]
626684pub enum MouseButton {
627685 /// Left mouse button.
628686 Left ,
@@ -702,7 +760,7 @@ impl Display for KeyModifiers {
702760
703761/// Represents a keyboard event kind.
704762#[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
705- #[ derive( Debug , PartialOrd , PartialEq , Eq , Clone , Copy , Hash ) ]
763+ #[ derive( Debug , PartialOrd , PartialEq , Eq , Clone , Copy , Hash , IsVariant ) ]
706764pub enum KeyEventKind {
707765 Press ,
708766 Repeat ,
@@ -806,6 +864,21 @@ impl KeyEvent {
806864 }
807865 self
808866 }
867+
868+ /// Returns whether the key event is a press event.
869+ pub fn is_press ( & self ) -> bool {
870+ self . kind . is_press ( )
871+ }
872+
873+ /// Returns whether the key event is a release event.
874+ pub fn is_release ( & self ) -> bool {
875+ self . kind . is_release ( )
876+ }
877+
878+ /// Returns whether the key event is a repeat event.
879+ pub fn is_repeat ( & self ) -> bool {
880+ self . kind . is_repeat ( )
881+ }
809882}
810883
811884impl From < KeyCode > for KeyEvent {
@@ -1006,7 +1079,7 @@ impl Display for ModifierKeyCode {
10061079}
10071080
10081081/// Represents a key.
1009- #[ derive( Debug , PartialOrd , PartialEq , Eq , Clone , Copy , Hash ) ]
1082+ #[ derive( Debug , PartialOrd , PartialEq , Eq , Clone , Copy , Hash , IsVariant ) ]
10101083#[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
10111084pub enum KeyCode {
10121085 /// Backspace key (Delete on macOS, Backspace on other platforms).
@@ -1040,10 +1113,12 @@ pub enum KeyCode {
10401113 /// F key.
10411114 ///
10421115 /// `KeyCode::F(1)` represents F1 key, etc.
1116+ #[ is_variant( ignore) ]
10431117 F ( u8 ) ,
10441118 /// A character.
10451119 ///
10461120 /// `KeyCode::Char('c')` represents `c` character, etc.
1121+ #[ is_variant( ignore) ]
10471122 Char ( char ) ,
10481123 /// Null.
10491124 Null ,
@@ -1096,16 +1171,100 @@ pub enum KeyCode {
10961171 /// **Note:** these keys can only be read if
10971172 /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] has been enabled with
10981173 /// [`PushKeyboardEnhancementFlags`].
1174+ #[ is_variant( ignore) ]
10991175 Media ( MediaKeyCode ) ,
11001176 /// A modifier key.
11011177 ///
11021178 /// **Note:** these keys can only be read if **both**
11031179 /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] and
11041180 /// [`KeyboardEnhancementFlags::REPORT_ALL_KEYS_AS_ESCAPE_CODES`] have been enabled with
11051181 /// [`PushKeyboardEnhancementFlags`].
1182+ #[ is_variant( ignore) ]
11061183 Modifier ( ModifierKeyCode ) ,
11071184}
11081185
1186+ impl KeyCode {
1187+ /// Returns `true` if the key code is the given function key.
1188+ ///
1189+ /// # Examples
1190+ ///
1191+ /// ```
1192+ /// # use crossterm::event::KeyCode;
1193+ /// assert!(KeyCode::F(1).is_function(1));
1194+ /// assert!(!KeyCode::F(1).is_function(2));
1195+ /// ```
1196+ pub fn is_function_key ( & self , n : u8 ) -> bool {
1197+ matches ! ( self , KeyCode :: F ( m) if * m == n)
1198+ }
1199+
1200+ /// Returns `true` if the key code is the given character.
1201+ ///
1202+ /// # Examples
1203+ ///
1204+ /// ```
1205+ /// # use crossterm::event::KeyCode;
1206+ /// assert!(KeyCode::Char('a').is_char('a'));
1207+ /// assert!(!KeyCode::Char('a').is_char('b'));
1208+ /// assert!(!KeyCode::F(1).is_char('a'));
1209+ /// ```
1210+ pub fn is_char ( & self , c : char ) -> bool {
1211+ matches ! ( self , KeyCode :: Char ( m) if * m == c)
1212+ }
1213+
1214+ /// Returns the character if the key code is a character key.
1215+ ///
1216+ /// Returns `None` if the key code is not a character key.
1217+ ///
1218+ /// # Examples
1219+ ///
1220+ /// ```
1221+ /// # use crossterm::event::KeyCode;
1222+ /// assert_eq!(KeyCode::Char('a').as_char(), Some('a'));
1223+ /// assert_eq!(KeyCode::F(1).as_char(), None);
1224+ /// ```
1225+ pub fn as_char ( & self ) -> Option < char > {
1226+ match self {
1227+ KeyCode :: Char ( c) => Some ( * c) ,
1228+ _ => None ,
1229+ }
1230+ }
1231+
1232+ /// Returns `true` if the key code is the given media key.
1233+ ///
1234+ /// **Note:** this method requires
1235+ /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] to be enabled with
1236+ /// [`PushKeyboardEnhancementFlags`].
1237+ ///
1238+ /// # Examples
1239+ ///
1240+ /// ```
1241+ /// # use crossterm::event::{KeyCode, MediaKeyCode};
1242+ /// assert!(KeyCode::Media(MediaKeyCode::Play).is_media(MediaKeyCode::Play));
1243+ /// assert!(!KeyCode::Media(MediaKeyCode::Play).is_media(MediaKeyCode::Pause));
1244+ /// ```
1245+ pub fn is_media_key ( & self , media : MediaKeyCode ) -> bool {
1246+ matches ! ( self , KeyCode :: Media ( m) if * m == media)
1247+ }
1248+
1249+ /// Returns `true` if the key code is the given modifier key.
1250+ ///
1251+ /// **Note:** this method requires both
1252+ /// [`KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES`] and
1253+ /// [`KeyboardEnhancementFlags::REPORT_ALL_KEYS_AS_ESCAPE_CODES`] to be enabled with
1254+ /// [`PushKeyboardEnhancementFlags`].
1255+ ///
1256+ /// # Examples
1257+ ///
1258+ /// ```
1259+ /// # use crossterm::event::{KeyCode, ModifierKeyCode};
1260+ /// assert!(KeyCode::Modifier(ModifierKeyCode::LeftShift).is_modifier(ModifierKeyCode::LeftShift));
1261+ /// assert!(!KeyCode::Modifier(ModifierKeyCode::LeftShift).is_modifier(ModifierKeyCode::RightShift));
1262+ /// ```
1263+ pub fn is_modifier ( & self , modifier : ModifierKeyCode ) -> bool {
1264+ matches ! ( self , KeyCode :: Modifier ( m) if * m == modifier)
1265+ }
1266+ }
1267+
11091268impl Display for KeyCode {
11101269 /// Formats the `KeyCode` using the given formatter.
11111270 ///
@@ -1324,4 +1483,87 @@ mod tests {
13241483 assert_eq ! ( format!( "{}" , Modifier ( RightAlt ) ) , "Right Alt" ) ;
13251484 assert_eq ! ( format!( "{}" , Modifier ( RightSuper ) ) , "Right Super" ) ;
13261485 }
1486+
1487+ #[ test]
1488+ fn test_event_is ( ) {
1489+ let event = Event :: FocusGained ;
1490+ assert ! ( event. is_focus_gained( ) ) ;
1491+ assert ! ( !event. is_key( ) ) ;
1492+
1493+ let event = Event :: FocusLost ;
1494+ assert ! ( event. is_focus_lost( ) ) ;
1495+ assert ! ( !event. is_key( ) ) ;
1496+
1497+ let event = Event :: Resize ( 1 , 1 ) ;
1498+ assert ! ( event. is_resize( ) ) ;
1499+ assert ! ( !event. is_key( ) ) ;
1500+
1501+ let event = Event :: Key ( KeyCode :: Esc . into ( ) ) ;
1502+ assert ! ( event. is_key( ) ) ;
1503+ assert ! ( !event. is_focus_gained( ) ) ;
1504+
1505+ let event = Event :: Mouse ( MouseEvent {
1506+ kind : MouseEventKind :: Down ( MouseButton :: Left ) ,
1507+ column : 1 ,
1508+ row : 1 ,
1509+ modifiers : KeyModifiers :: empty ( ) ,
1510+ } ) ;
1511+ assert ! ( event. is_mouse( ) ) ;
1512+ assert ! ( !event. is_key( ) ) ;
1513+ }
1514+
1515+ const ESC_PRESSED : KeyEvent =
1516+ KeyEvent :: new_with_kind ( KeyCode :: Esc , KeyModifiers :: empty ( ) , KeyEventKind :: Press ) ;
1517+ const ESC_RELEASED : KeyEvent =
1518+ KeyEvent :: new_with_kind ( KeyCode :: Esc , KeyModifiers :: empty ( ) , KeyEventKind :: Release ) ;
1519+ const ESC_REPEAT : KeyEvent =
1520+ KeyEvent :: new_with_kind ( KeyCode :: Esc , KeyModifiers :: empty ( ) , KeyEventKind :: Repeat ) ;
1521+
1522+ #[ test]
1523+ fn test_event_is_key_press ( ) {
1524+ let event = Event :: Key ( ESC_PRESSED ) ;
1525+ assert ! ( event. is_key_press( ) ) ;
1526+
1527+ let event = Event :: Key ( ESC_RELEASED ) ;
1528+ assert ! ( !event. is_key_press( ) ) ;
1529+
1530+ let event = Event :: Key ( ESC_REPEAT ) ;
1531+ assert ! ( !event. is_key_press( ) ) ;
1532+
1533+ let event = Event :: FocusGained ;
1534+ assert ! ( !event. is_key_press( ) ) ;
1535+ }
1536+
1537+ #[ test]
1538+ fn test_event_as_key_press ( ) {
1539+ let event = Event :: Key ( ESC_PRESSED ) ;
1540+ assert_eq ! ( event. as_key_press( ) , Some ( & ESC_PRESSED ) ) ;
1541+
1542+ let event = Event :: Key ( ESC_RELEASED ) ;
1543+ assert_eq ! ( event. as_key_press( ) , None ) ;
1544+
1545+ let event = Event :: Key ( ESC_REPEAT ) ;
1546+ assert_eq ! ( event. as_key_press( ) , None ) ;
1547+
1548+ let event = Event :: FocusGained ;
1549+ assert_eq ! ( event. as_key_press( ) , None ) ;
1550+ }
1551+
1552+ #[ test]
1553+ fn test_key_event_is ( ) {
1554+ let event = ESC_PRESSED ;
1555+ assert ! ( event. is_press( ) ) ;
1556+ assert ! ( !event. is_release( ) ) ;
1557+ assert ! ( !event. is_repeat( ) ) ;
1558+
1559+ let event = ESC_RELEASED ;
1560+ assert ! ( !event. is_press( ) ) ;
1561+ assert ! ( event. is_release( ) ) ;
1562+ assert ! ( !event. is_repeat( ) ) ;
1563+
1564+ let event = ESC_REPEAT ;
1565+ assert ! ( !event. is_press( ) ) ;
1566+ assert ! ( !event. is_release( ) ) ;
1567+ assert ! ( event. is_repeat( ) ) ;
1568+ }
13271569}
0 commit comments