1use crossterm::event::KeyCode;
47pub use crossterm::event::{KeyModifiers, MouseButton, MouseEventKind};
48
49#[derive(Debug, Clone, PartialEq)]
51pub enum Event<M> {
52 Key(KeyEvent),
54 Mouse(MouseEvent),
56 Resize {
58 width: u16,
60 height: u16,
62 },
63 Tick,
65 User(M),
67 Quit,
69 Focus,
71 Blur,
73 Suspend,
75 Resume,
77 Paste(String),
79 #[doc(hidden)]
81 ExecProcess,
82}
83
84impl<M> Event<M> {
85 pub fn is_key(&self) -> bool {
87 matches!(self, Event::Key(_))
88 }
89
90 pub fn is_key_press(&self, key: Key) -> bool {
101 matches!(self, Event::Key(k) if k.key == key)
102 }
103
104 pub fn is_key_with_modifiers(&self, key: Key, modifiers: KeyModifiers) -> bool {
115 matches!(self, Event::Key(k) if k.key == key && k.modifiers == modifiers)
116 }
117
118 pub fn as_key(&self) -> Option<&KeyEvent> {
120 match self {
121 Event::Key(k) => Some(k),
122 _ => None,
123 }
124 }
125
126 pub fn is_mouse(&self) -> bool {
128 matches!(self, Event::Mouse(_))
129 }
130
131 pub fn as_mouse(&self) -> Option<&MouseEvent> {
133 match self {
134 Event::Mouse(m) => Some(m),
135 _ => None,
136 }
137 }
138
139 pub fn is_click(&self) -> bool {
141 matches!(self, Event::Mouse(m) if m.is_click())
142 }
143
144 pub fn as_click(&self) -> Option<(u16, u16)> {
155 match self {
156 Event::Mouse(m) if m.is_click() => Some(m.position()),
157 _ => None,
158 }
159 }
160
161 pub fn is_resize(&self) -> bool {
163 matches!(self, Event::Resize { .. })
164 }
165
166 pub fn as_resize(&self) -> Option<(u16, u16)> {
177 match self {
178 Event::Resize { width, height } => Some((*width, *height)),
179 _ => None,
180 }
181 }
182
183 pub fn is_user(&self) -> bool {
185 matches!(self, Event::User(_))
186 }
187
188 pub fn as_user(&self) -> Option<&M> {
190 match self {
191 Event::User(msg) => Some(msg),
192 _ => None,
193 }
194 }
195
196 pub fn into_user(self) -> Option<M> {
198 match self {
199 Event::User(msg) => Some(msg),
200 _ => None,
201 }
202 }
203
204 pub fn is_quit(&self) -> bool {
206 matches!(self, Event::Quit)
207 }
208
209 pub fn is_tick(&self) -> bool {
211 matches!(self, Event::Tick)
212 }
213
214 pub fn is_paste(&self) -> bool {
216 matches!(self, Event::Paste(_))
217 }
218
219 pub fn as_paste(&self) -> Option<&str> {
221 match self {
222 Event::Paste(text) => Some(text.as_str()),
223 _ => None,
224 }
225 }
226
227 pub fn is_focus(&self) -> bool {
229 matches!(self, Event::Focus)
230 }
231
232 pub fn is_blur(&self) -> bool {
234 matches!(self, Event::Blur)
235 }
236
237 pub fn is_suspend(&self) -> bool {
239 matches!(self, Event::Suspend)
240 }
241
242 pub fn is_resume(&self) -> bool {
244 matches!(self, Event::Resume)
245 }
246}
247
248#[derive(Debug, Clone, Copy, PartialEq, Eq)]
250pub struct WindowSize {
251 pub width: u16,
253 pub height: u16,
255}
256
257#[derive(Debug, Clone, Copy, PartialEq, Eq)]
259pub struct KeyEvent {
260 pub key: Key,
262 pub modifiers: KeyModifiers,
264}
265
266impl KeyEvent {
267 pub fn new(key: Key, modifiers: KeyModifiers) -> Self {
269 Self { key, modifiers }
270 }
271
272 pub fn is_char(&self) -> bool {
274 matches!(self.key, Key::Char(_))
275 }
276
277 pub fn char(&self) -> Option<char> {
279 match self.key {
280 Key::Char(c) => Some(c),
281 _ => None,
282 }
283 }
284
285 pub fn is(&self, key: Key) -> bool {
296 self.key == key
297 }
298
299 pub fn is_with_modifiers(&self, key: Key, modifiers: KeyModifiers) -> bool {
310 self.key == key && self.modifiers == modifiers
311 }
312
313 pub fn is_ctrl(&self) -> bool {
315 self.modifiers.contains(KeyModifiers::CONTROL)
316 }
317
318 pub fn is_alt(&self) -> bool {
320 self.modifiers.contains(KeyModifiers::ALT)
321 }
322
323 pub fn is_shift(&self) -> bool {
325 self.modifiers.contains(KeyModifiers::SHIFT)
326 }
327
328 pub fn is_super(&self) -> bool {
330 self.modifiers.contains(KeyModifiers::SUPER)
331 }
332
333 pub fn is_navigation(&self) -> bool {
335 matches!(
336 self.key,
337 Key::Up | Key::Down | Key::Left | Key::Right |
338 Key::Home | Key::End | Key::PageUp | Key::PageDown
339 )
340 }
341
342 pub fn is_function_key(&self) -> bool {
344 matches!(self.key, Key::F(_))
345 }
346
347 pub fn is_media_key(&self) -> bool {
349 matches!(
350 self.key,
351 Key::MediaPlay | Key::MediaPause | Key::MediaPlayPause |
352 Key::MediaStop | Key::MediaNext | Key::MediaPrevious |
353 Key::MediaFastForward | Key::MediaRewind |
354 Key::MediaVolumeUp | Key::MediaVolumeDown | Key::MediaMute
355 )
356 }
357
358 pub fn has_modifiers(&self) -> bool {
360 !self.modifiers.is_empty()
361 }
362
363 pub fn no_modifiers(&self) -> bool {
365 self.modifiers.is_empty()
366 }
367}
368
369#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
371pub enum ModifierKey {
372 Shift,
374 Control,
376 Alt,
378 Super,
380 Meta,
382 Hyper,
384}
385
386#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
388pub enum Key {
389 Char(char),
391 Backspace,
393 Enter,
395 Left,
397 Right,
399 Up,
401 Down,
403 Home,
405 End,
407 PageUp,
409 PageDown,
411 Tab,
413 Delete,
415 Insert,
417 Esc,
419 F(u8),
421 Null,
423 CapsLock,
425 ScrollLock,
427 NumLock,
429 PrintScreen,
431 Pause,
433 Menu,
435 KeypadBegin,
437 MediaPlay,
439 MediaPause,
441 MediaPlayPause,
443 MediaStop,
445 MediaNext,
447 MediaPrevious,
449 MediaFastForward,
451 MediaRewind,
453 MediaVolumeUp,
455 MediaVolumeDown,
457 MediaMute,
459 Modifier(ModifierKey),
461}
462
463impl From<crossterm::event::KeyEvent> for KeyEvent {
464 fn from(event: crossterm::event::KeyEvent) -> Self {
465 let key = match event.code {
466 KeyCode::Char(c) => Key::Char(c),
467 KeyCode::Backspace => Key::Backspace,
468 KeyCode::Enter => Key::Enter,
469 KeyCode::Left => Key::Left,
470 KeyCode::Right => Key::Right,
471 KeyCode::Up => Key::Up,
472 KeyCode::Down => Key::Down,
473 KeyCode::Home => Key::Home,
474 KeyCode::End => Key::End,
475 KeyCode::PageUp => Key::PageUp,
476 KeyCode::PageDown => Key::PageDown,
477 KeyCode::Tab => Key::Tab,
478 KeyCode::BackTab => Key::Tab, KeyCode::Delete => Key::Delete,
480 KeyCode::Insert => Key::Insert,
481 KeyCode::Esc => Key::Esc,
482 KeyCode::F(n) => Key::F(n),
483 KeyCode::Null => Key::Null,
484 KeyCode::CapsLock => Key::CapsLock,
485 KeyCode::ScrollLock => Key::ScrollLock,
486 KeyCode::NumLock => Key::NumLock,
487 KeyCode::PrintScreen => Key::PrintScreen,
488 KeyCode::Pause => Key::Pause,
489 KeyCode::Menu => Key::Menu,
490 KeyCode::KeypadBegin => Key::KeypadBegin,
491 KeyCode::Media(crossterm::event::MediaKeyCode::Play) => Key::MediaPlay,
493 KeyCode::Media(crossterm::event::MediaKeyCode::Pause) => Key::MediaPause,
494 KeyCode::Media(crossterm::event::MediaKeyCode::PlayPause) => Key::MediaPlayPause,
495 KeyCode::Media(crossterm::event::MediaKeyCode::Stop) => Key::MediaStop,
496 KeyCode::Media(crossterm::event::MediaKeyCode::FastForward) => Key::MediaFastForward,
497 KeyCode::Media(crossterm::event::MediaKeyCode::Rewind) => Key::MediaRewind,
498 KeyCode::Media(crossterm::event::MediaKeyCode::TrackNext) => Key::MediaNext,
499 KeyCode::Media(crossterm::event::MediaKeyCode::TrackPrevious) => Key::MediaPrevious,
500 KeyCode::Media(crossterm::event::MediaKeyCode::LowerVolume) => Key::MediaVolumeDown,
501 KeyCode::Media(crossterm::event::MediaKeyCode::RaiseVolume) => Key::MediaVolumeUp,
502 KeyCode::Media(crossterm::event::MediaKeyCode::MuteVolume) => Key::MediaMute,
503 KeyCode::Modifier(crossterm::event::ModifierKeyCode::LeftShift)
505 | KeyCode::Modifier(crossterm::event::ModifierKeyCode::RightShift) => {
506 Key::Modifier(ModifierKey::Shift)
507 }
508 KeyCode::Modifier(crossterm::event::ModifierKeyCode::LeftControl)
509 | KeyCode::Modifier(crossterm::event::ModifierKeyCode::RightControl) => {
510 Key::Modifier(ModifierKey::Control)
511 }
512 KeyCode::Modifier(crossterm::event::ModifierKeyCode::LeftAlt)
513 | KeyCode::Modifier(crossterm::event::ModifierKeyCode::RightAlt) => {
514 Key::Modifier(ModifierKey::Alt)
515 }
516 KeyCode::Modifier(crossterm::event::ModifierKeyCode::LeftSuper)
517 | KeyCode::Modifier(crossterm::event::ModifierKeyCode::RightSuper) => {
518 Key::Modifier(ModifierKey::Super)
519 }
520 KeyCode::Modifier(crossterm::event::ModifierKeyCode::LeftMeta)
521 | KeyCode::Modifier(crossterm::event::ModifierKeyCode::RightMeta) => {
522 Key::Modifier(ModifierKey::Meta)
523 }
524 KeyCode::Modifier(crossterm::event::ModifierKeyCode::LeftHyper)
525 | KeyCode::Modifier(crossterm::event::ModifierKeyCode::RightHyper) => {
526 Key::Modifier(ModifierKey::Hyper)
527 }
528 _ => Key::Null, };
530
531 Self {
532 key,
533 modifiers: event.modifiers,
534 }
535 }
536}
537
538#[derive(Debug, Clone, Copy, PartialEq)]
556pub struct MouseEvent {
557 pub kind: MouseEventKind,
559 pub column: u16,
561 pub row: u16,
563 pub modifiers: KeyModifiers,
565}
566
567impl MouseEvent {
568 pub fn new(kind: MouseEventKind, column: u16, row: u16, modifiers: KeyModifiers) -> Self {
570 Self { kind, column, row, modifiers }
571 }
572
573 pub fn is_left_click(&self) -> bool {
575 matches!(self.kind, MouseEventKind::Down(MouseButton::Left))
576 }
577
578 pub fn is_right_click(&self) -> bool {
580 matches!(self.kind, MouseEventKind::Down(MouseButton::Right))
581 }
582
583 pub fn is_middle_click(&self) -> bool {
585 matches!(self.kind, MouseEventKind::Down(MouseButton::Middle))
586 }
587
588 pub fn is_click(&self) -> bool {
590 matches!(self.kind, MouseEventKind::Down(_))
591 }
592
593 pub fn is_release(&self) -> bool {
595 matches!(self.kind, MouseEventKind::Up(_))
596 }
597
598 pub fn is_drag(&self) -> bool {
600 matches!(self.kind, MouseEventKind::Drag(_))
601 }
602
603 pub fn is_left_drag(&self) -> bool {
605 matches!(self.kind, MouseEventKind::Drag(MouseButton::Left))
606 }
607
608 pub fn is_right_drag(&self) -> bool {
610 matches!(self.kind, MouseEventKind::Drag(MouseButton::Right))
611 }
612
613 pub fn is_middle_drag(&self) -> bool {
615 matches!(self.kind, MouseEventKind::Drag(MouseButton::Middle))
616 }
617
618 pub fn is_scroll_up(&self) -> bool {
620 matches!(self.kind, MouseEventKind::ScrollUp)
621 }
622
623 pub fn is_scroll_down(&self) -> bool {
625 matches!(self.kind, MouseEventKind::ScrollDown)
626 }
627
628 pub fn is_scroll_left(&self) -> bool {
630 matches!(self.kind, MouseEventKind::ScrollLeft)
631 }
632
633 pub fn is_scroll_right(&self) -> bool {
635 matches!(self.kind, MouseEventKind::ScrollRight)
636 }
637
638 pub fn is_scroll(&self) -> bool {
640 matches!(
641 self.kind,
642 MouseEventKind::ScrollUp
643 | MouseEventKind::ScrollDown
644 | MouseEventKind::ScrollLeft
645 | MouseEventKind::ScrollRight
646 )
647 }
648
649 pub fn is_move(&self) -> bool {
651 matches!(self.kind, MouseEventKind::Moved)
652 }
653
654 pub fn button(&self) -> Option<MouseButton> {
656 match self.kind {
657 MouseEventKind::Down(btn) | MouseEventKind::Up(btn) | MouseEventKind::Drag(btn) => Some(btn),
658 _ => None,
659 }
660 }
661
662 pub fn position(&self) -> (u16, u16) {
664 (self.column, self.row)
665 }
666
667 pub fn is_within(&self, x: u16, y: u16, width: u16, height: u16) -> bool {
679 self.column >= x && self.column < x + width &&
680 self.row >= y && self.row < y + height
681 }
682
683 pub fn is_at(&self, column: u16, row: u16) -> bool {
685 self.column == column && self.row == row
686 }
687
688 pub fn has_modifier(&self, modifier: KeyModifiers) -> bool {
690 self.modifiers.contains(modifier)
691 }
692
693 pub fn is_ctrl(&self) -> bool {
695 self.modifiers.contains(KeyModifiers::CONTROL)
696 }
697
698 pub fn is_alt(&self) -> bool {
700 self.modifiers.contains(KeyModifiers::ALT)
701 }
702
703 pub fn is_shift(&self) -> bool {
705 self.modifiers.contains(KeyModifiers::SHIFT)
706 }
707
708 pub fn has_modifiers(&self) -> bool {
710 !self.modifiers.is_empty()
711 }
712
713 pub fn no_modifiers(&self) -> bool {
715 self.modifiers.is_empty()
716 }
717}
718
719impl From<crossterm::event::MouseEvent> for MouseEvent {
720 fn from(event: crossterm::event::MouseEvent) -> Self {
721 Self {
722 kind: event.kind,
723 column: event.column,
724 row: event.row,
725 modifiers: event.modifiers,
726 }
727 }
728}
729
730#[cfg(test)]
731mod tests {
732 use super::*;
733 use proptest::prelude::*;
734
735 #[test]
736 fn test_key_event_creation() {
737 let event = KeyEvent::new(Key::Char('a'), KeyModifiers::empty());
738 assert_eq!(event.key, Key::Char('a'));
739 assert!(event.is_char());
740 assert_eq!(event.char(), Some('a'));
741 }
742
743 #[test]
744 fn test_key_event_modifiers() {
745 let event = KeyEvent::new(Key::Char('c'), KeyModifiers::CONTROL);
746 assert_eq!(event.key, Key::Char('c'));
747 assert_eq!(event.modifiers, KeyModifiers::CONTROL);
748 }
749
750 #[test]
751 fn test_non_char_keys() {
752 let event = KeyEvent::new(Key::Enter, KeyModifiers::empty());
753 assert!(!event.is_char());
754 assert_eq!(event.char(), None);
755 }
756
757 #[test]
758 fn test_window_size_creation() {
759 let size = WindowSize {
760 width: 80,
761 height: 24,
762 };
763 assert_eq!(size.width, 80);
764 assert_eq!(size.height, 24);
765 }
766
767 #[test]
768 fn test_mouse_event_creation() {
769 let event = MouseEvent {
770 kind: MouseEventKind::Down(MouseButton::Left),
771 column: 10,
772 row: 5,
773 modifiers: KeyModifiers::empty(),
774 };
775 assert_eq!(event.column, 10);
776 assert_eq!(event.row, 5);
777 }
778
779 #[test]
780 fn test_event_variants() {
781 let key_event = Event::<String>::Key(KeyEvent::new(Key::Char('a'), KeyModifiers::empty()));
782 let mouse_event = Event::<String>::Mouse(MouseEvent {
783 kind: MouseEventKind::Down(MouseButton::Left),
784 column: 0,
785 row: 0,
786 modifiers: KeyModifiers::empty(),
787 });
788 let resize_event = Event::<String>::Resize {
789 width: 80,
790 height: 24,
791 };
792 let tick_event = Event::<String>::Tick;
793 let user_event = Event::User("test".to_string());
794 let quit_event = Event::<String>::Quit;
795 let focus_event = Event::<String>::Focus;
796 let blur_event = Event::<String>::Blur;
797 let suspend_event = Event::<String>::Suspend;
798 let resume_event = Event::<String>::Resume;
799 let paste_event = Event::<String>::Paste("pasted text".to_string());
800
801 assert!(key_event.is_key());
803 assert!(key_event.as_key().is_some());
804
805 assert!(mouse_event.is_mouse());
806 assert!(mouse_event.as_mouse().is_some());
807
808 assert!(resize_event.is_resize());
809 assert_eq!(resize_event.as_resize(), Some((80, 24)));
810
811 assert!(tick_event.is_tick());
812
813 assert!(user_event.is_user());
814 assert_eq!(user_event.as_user(), Some(&"test".to_string()));
815
816 assert!(quit_event.is_quit());
817 assert!(focus_event.is_focus());
818 assert!(blur_event.is_blur());
819 assert!(suspend_event.is_suspend());
820 assert!(resume_event.is_resume());
821
822 assert!(paste_event.is_paste());
823 assert_eq!(paste_event.as_paste(), Some("pasted text"));
824 }
825
826 #[test]
827 fn test_key_variants() {
828 let keys = vec![
829 Key::Char('a'),
830 Key::Backspace,
831 Key::Enter,
832 Key::Left,
833 Key::Right,
834 Key::Up,
835 Key::Down,
836 Key::Home,
837 Key::End,
838 Key::PageUp,
839 Key::PageDown,
840 Key::Tab,
841 Key::Delete,
842 Key::Insert,
843 Key::Esc,
844 Key::F(1),
845 Key::Null,
846 ];
847
848 for key in keys {
849 let event = KeyEvent::new(key, KeyModifiers::empty());
850 assert_eq!(event.key, key);
851
852 match key {
854 Key::Char(c) => {
855 assert!(event.is_char());
856 assert_eq!(event.char(), Some(c));
857 }
858 _ => {
859 assert!(!event.is_char());
860 assert_eq!(event.char(), None);
861 }
862 }
863 }
864 }
865
866 #[test]
867 fn test_crossterm_key_conversion() {
868 let crossterm_event = crossterm::event::KeyEvent::new(
869 KeyCode::Char('x'),
870 KeyModifiers::CONTROL | KeyModifiers::SHIFT,
871 );
872
873 let key_event: KeyEvent = crossterm_event.into();
874 assert_eq!(key_event.key, Key::Char('x'));
875 assert_eq!(
876 key_event.modifiers,
877 KeyModifiers::CONTROL | KeyModifiers::SHIFT
878 );
879 }
880
881 #[test]
882 fn test_enhanced_keys() {
883 use crossterm::event::{KeyCode, KeyModifiers};
884
885 let caps_lock = crossterm::event::KeyEvent::new(KeyCode::CapsLock, KeyModifiers::empty());
887 let key_event = KeyEvent::from(caps_lock);
888 assert_eq!(key_event.key, Key::CapsLock);
889
890 let scroll_lock =
891 crossterm::event::KeyEvent::new(KeyCode::ScrollLock, KeyModifiers::empty());
892 let key_event = KeyEvent::from(scroll_lock);
893 assert_eq!(key_event.key, Key::ScrollLock);
894
895 let print_screen =
896 crossterm::event::KeyEvent::new(KeyCode::PrintScreen, KeyModifiers::empty());
897 let key_event = KeyEvent::from(print_screen);
898 assert_eq!(key_event.key, Key::PrintScreen);
899
900 let play = crossterm::event::KeyEvent::new(
902 KeyCode::Media(crossterm::event::MediaKeyCode::Play),
903 KeyModifiers::empty(),
904 );
905 let key_event = KeyEvent::from(play);
906 assert_eq!(key_event.key, Key::MediaPlay);
907
908 let volume_up = crossterm::event::KeyEvent::new(
909 KeyCode::Media(crossterm::event::MediaKeyCode::RaiseVolume),
910 KeyModifiers::empty(),
911 );
912 let key_event = KeyEvent::from(volume_up);
913 assert_eq!(key_event.key, Key::MediaVolumeUp);
914
915 let left_shift = crossterm::event::KeyEvent::new(
917 KeyCode::Modifier(crossterm::event::ModifierKeyCode::LeftShift),
918 KeyModifiers::empty(),
919 );
920 let key_event = KeyEvent::from(left_shift);
921 assert_eq!(key_event.key, Key::Modifier(ModifierKey::Shift));
922
923 let right_alt = crossterm::event::KeyEvent::new(
924 KeyCode::Modifier(crossterm::event::ModifierKeyCode::RightAlt),
925 KeyModifiers::empty(),
926 );
927 let key_event = KeyEvent::from(right_alt);
928 assert_eq!(key_event.key, Key::Modifier(ModifierKey::Alt));
929 }
930
931 #[test]
932 fn test_crossterm_key_conversion_all_keys() {
933 let test_cases = vec![
935 (KeyCode::Backspace, Key::Backspace),
936 (KeyCode::Enter, Key::Enter),
937 (KeyCode::Left, Key::Left),
938 (KeyCode::Right, Key::Right),
939 (KeyCode::Up, Key::Up),
940 (KeyCode::Down, Key::Down),
941 (KeyCode::Home, Key::Home),
942 (KeyCode::End, Key::End),
943 (KeyCode::PageUp, Key::PageUp),
944 (KeyCode::PageDown, Key::PageDown),
945 (KeyCode::Tab, Key::Tab),
946 (KeyCode::Delete, Key::Delete),
947 (KeyCode::Insert, Key::Insert),
948 (KeyCode::Esc, Key::Esc),
949 (KeyCode::F(1), Key::F(1)),
950 (KeyCode::F(12), Key::F(12)),
951 (KeyCode::Null, Key::Null),
952 (KeyCode::BackTab, Key::Tab), ];
954
955 for (crossterm_code, expected_key) in test_cases {
956 let crossterm_event =
957 crossterm::event::KeyEvent::new(crossterm_code, KeyModifiers::empty());
958 let key_event: KeyEvent = crossterm_event.into();
959 assert_eq!(key_event.key, expected_key);
960 }
961 }
962
963 #[test]
964 fn test_crossterm_mouse_conversion() {
965 let crossterm_event = crossterm::event::MouseEvent {
966 kind: MouseEventKind::Down(MouseButton::Right),
967 column: 42,
968 row: 24,
969 modifiers: KeyModifiers::ALT,
970 };
971
972 let mouse_event: MouseEvent = crossterm_event.into();
973 assert_eq!(mouse_event.kind, MouseEventKind::Down(MouseButton::Right));
974 assert_eq!(mouse_event.column, 42);
975 assert_eq!(mouse_event.row, 24);
976 assert_eq!(mouse_event.modifiers, KeyModifiers::ALT);
977 }
978
979 proptest! {
981 #[test]
982 fn test_key_event_properties(
983 c in any::<char>(),
984 ctrl in any::<bool>(),
985 alt in any::<bool>(),
986 shift in any::<bool>()
987 ) {
988 let mut modifiers = KeyModifiers::empty();
989 if ctrl { modifiers |= KeyModifiers::CONTROL; }
990 if alt { modifiers |= KeyModifiers::ALT; }
991 if shift { modifiers |= KeyModifiers::SHIFT; }
992
993 let event = KeyEvent::new(Key::Char(c), modifiers);
994
995 prop_assert_eq!(event.key, Key::Char(c));
996 prop_assert_eq!(event.modifiers, modifiers);
997 prop_assert!(event.is_char());
998 prop_assert_eq!(event.char(), Some(c));
999 }
1000
1001 #[test]
1002 fn test_window_size_properties(
1003 width in 1u16..1000u16,
1004 height in 1u16..1000u16
1005 ) {
1006 let size = WindowSize { width, height };
1007
1008 prop_assert_eq!(size.width, width);
1009 prop_assert_eq!(size.height, height);
1010
1011 let size2 = size;
1013 prop_assert_eq!(size, size2);
1014 }
1015
1016 #[test]
1017 fn test_mouse_event_properties(
1018 column in 0u16..1000u16,
1019 row in 0u16..1000u16,
1020 button_idx in 0..3usize
1021 ) {
1022 let button = match button_idx {
1023 0 => MouseButton::Left,
1024 1 => MouseButton::Right,
1025 2 => MouseButton::Middle,
1026 _ => unreachable!(),
1027 };
1028
1029 let event = MouseEvent {
1030 kind: MouseEventKind::Down(button),
1031 column,
1032 row,
1033 modifiers: KeyModifiers::empty(),
1034 };
1035
1036 prop_assert_eq!(event.column, column);
1037 prop_assert_eq!(event.row, row);
1038 prop_assert_eq!(event.kind, MouseEventKind::Down(button));
1039 }
1040
1041 #[test]
1042 fn test_event_user_message_properties(
1043 message in ".*"
1044 ) {
1045 let event = Event::User(message.clone());
1046
1047 prop_assert!(event.is_user());
1048 prop_assert_eq!(event.as_user(), Some(&message));
1049 }
1050
1051 #[test]
1052 fn test_event_resize_properties(
1053 width in 1u16..1000u16,
1054 height in 1u16..1000u16
1055 ) {
1056 let event = Event::<String>::Resize { width, height };
1057
1058 prop_assert!(event.is_resize());
1059 prop_assert_eq!(event.as_resize(), Some((width, height)));
1060 }
1061
1062 #[test]
1063 fn test_event_paste_properties(
1064 paste_text in ".*"
1065 ) {
1066 let event = Event::<String>::Paste(paste_text.clone());
1067
1068 prop_assert!(event.is_paste());
1069 prop_assert_eq!(event.as_paste(), Some(paste_text.as_str()));
1070 }
1071
1072 #[test]
1073 fn test_function_key_properties(
1074 key_num in 1u8..25u8
1075 ) {
1076 let key = Key::F(key_num);
1077 let event = KeyEvent::new(key, KeyModifiers::empty());
1078
1079 prop_assert_eq!(event.key, Key::F(key_num));
1080 prop_assert!(!event.is_char());
1081 prop_assert_eq!(event.char(), None);
1082 }
1083
1084 #[test]
1085 fn test_key_modifier_combinations(
1086 ctrl in any::<bool>(),
1087 alt in any::<bool>(),
1088 shift in any::<bool>(),
1089 super_key in any::<bool>()
1090 ) {
1091 let mut modifiers = KeyModifiers::empty();
1092 if ctrl { modifiers |= KeyModifiers::CONTROL; }
1093 if alt { modifiers |= KeyModifiers::ALT; }
1094 if shift { modifiers |= KeyModifiers::SHIFT; }
1095 if super_key { modifiers |= KeyModifiers::SUPER; }
1096
1097 let event = KeyEvent::new(Key::Char('a'), modifiers);
1098
1099 prop_assert_eq!(event.modifiers.contains(KeyModifiers::CONTROL), ctrl);
1100 prop_assert_eq!(event.modifiers.contains(KeyModifiers::ALT), alt);
1101 prop_assert_eq!(event.modifiers.contains(KeyModifiers::SHIFT), shift);
1102 prop_assert_eq!(event.modifiers.contains(KeyModifiers::SUPER), super_key);
1103 }
1104 }
1105}