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 #[inline(always)]
87 pub const fn is_key(&self) -> bool {
88 matches!(self, Event::Key(_))
89 }
90
91 #[inline(always)]
102 pub fn is_key_press(&self, key: Key) -> bool {
103 matches!(self, Event::Key(k) if k.key == key)
104 }
105
106 pub fn is_key_with_modifiers(&self, key: Key, modifiers: KeyModifiers) -> bool {
117 matches!(self, Event::Key(k) if k.key == key && k.modifiers == modifiers)
118 }
119
120 #[inline(always)]
122 pub const fn as_key(&self) -> Option<&KeyEvent> {
123 match self {
124 Event::Key(k) => Some(k),
125 _ => None,
126 }
127 }
128
129 #[inline(always)]
131 pub const fn is_mouse(&self) -> bool {
132 matches!(self, Event::Mouse(_))
133 }
134
135 #[inline(always)]
137 pub const fn as_mouse(&self) -> Option<&MouseEvent> {
138 match self {
139 Event::Mouse(m) => Some(m),
140 _ => None,
141 }
142 }
143
144 pub fn is_click(&self) -> bool {
146 matches!(self, Event::Mouse(m) if m.is_click())
147 }
148
149 pub fn as_click(&self) -> Option<(u16, u16)> {
160 match self {
161 Event::Mouse(m) if m.is_click() => Some(m.position()),
162 _ => None,
163 }
164 }
165
166 pub fn is_resize(&self) -> bool {
168 matches!(self, Event::Resize { .. })
169 }
170
171 pub fn as_resize(&self) -> Option<(u16, u16)> {
182 match self {
183 Event::Resize { width, height } => Some((*width, *height)),
184 _ => None,
185 }
186 }
187
188 #[inline(always)]
190 pub const fn is_user(&self) -> bool {
191 matches!(self, Event::User(_))
192 }
193
194 #[inline(always)]
196 pub const fn as_user(&self) -> Option<&M> {
197 match self {
198 Event::User(msg) => Some(msg),
199 _ => None,
200 }
201 }
202
203 pub fn into_user(self) -> Option<M> {
205 match self {
206 Event::User(msg) => Some(msg),
207 _ => None,
208 }
209 }
210
211 #[inline(always)]
213 pub const fn is_quit(&self) -> bool {
214 matches!(self, Event::Quit)
215 }
216
217 #[inline(always)]
219 pub const fn is_tick(&self) -> bool {
220 matches!(self, Event::Tick)
221 }
222
223 pub fn is_paste(&self) -> bool {
225 matches!(self, Event::Paste(_))
226 }
227
228 pub fn as_paste(&self) -> Option<&str> {
230 match self {
231 Event::Paste(text) => Some(text.as_str()),
232 _ => None,
233 }
234 }
235
236 pub fn is_focus(&self) -> bool {
238 matches!(self, Event::Focus)
239 }
240
241 pub fn is_blur(&self) -> bool {
243 matches!(self, Event::Blur)
244 }
245
246 pub fn is_suspend(&self) -> bool {
248 matches!(self, Event::Suspend)
249 }
250
251 pub fn is_resume(&self) -> bool {
253 matches!(self, Event::Resume)
254 }
255}
256
257#[derive(Debug, Clone, Copy, PartialEq, Eq)]
259pub struct WindowSize {
260 pub width: u16,
262 pub height: u16,
264}
265
266#[derive(Debug, Clone, Copy, PartialEq, Eq)]
268pub struct KeyEvent {
269 pub key: Key,
271 pub modifiers: KeyModifiers,
273}
274
275impl KeyEvent {
276 pub fn new(key: Key, modifiers: KeyModifiers) -> Self {
278 Self { key, modifiers }
279 }
280
281 pub fn is_char(&self) -> bool {
283 matches!(self.key, Key::Char(_))
284 }
285
286 pub fn char(&self) -> Option<char> {
288 match self.key {
289 Key::Char(c) => Some(c),
290 _ => None,
291 }
292 }
293
294 pub fn is(&self, key: Key) -> bool {
305 self.key == key
306 }
307
308 pub fn is_with_modifiers(&self, key: Key, modifiers: KeyModifiers) -> bool {
319 self.key == key && self.modifiers == modifiers
320 }
321
322 pub fn is_ctrl(&self) -> bool {
324 self.modifiers.contains(KeyModifiers::CONTROL)
325 }
326
327 pub fn is_alt(&self) -> bool {
329 self.modifiers.contains(KeyModifiers::ALT)
330 }
331
332 pub fn is_shift(&self) -> bool {
334 self.modifiers.contains(KeyModifiers::SHIFT)
335 }
336
337 pub fn is_super(&self) -> bool {
339 self.modifiers.contains(KeyModifiers::SUPER)
340 }
341
342 pub fn is_navigation(&self) -> bool {
344 matches!(
345 self.key,
346 Key::Up
347 | Key::Down
348 | Key::Left
349 | Key::Right
350 | Key::Home
351 | Key::End
352 | Key::PageUp
353 | Key::PageDown
354 )
355 }
356
357 pub fn is_function_key(&self) -> bool {
359 matches!(self.key, Key::F(_))
360 }
361
362 pub fn is_media_key(&self) -> bool {
364 matches!(
365 self.key,
366 Key::MediaPlay
367 | Key::MediaPause
368 | Key::MediaPlayPause
369 | Key::MediaStop
370 | Key::MediaNext
371 | Key::MediaPrevious
372 | Key::MediaFastForward
373 | Key::MediaRewind
374 | Key::MediaVolumeUp
375 | Key::MediaVolumeDown
376 | Key::MediaMute
377 )
378 }
379
380 pub fn has_modifiers(&self) -> bool {
382 !self.modifiers.is_empty()
383 }
384
385 pub fn no_modifiers(&self) -> bool {
387 self.modifiers.is_empty()
388 }
389}
390
391#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
393pub enum ModifierKey {
394 Shift,
396 Control,
398 Alt,
400 Super,
402 Meta,
404 Hyper,
406}
407
408#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
410pub enum Key {
411 Char(char),
413 Backspace,
415 Enter,
417 Left,
419 Right,
421 Up,
423 Down,
425 Home,
427 End,
429 PageUp,
431 PageDown,
433 Tab,
435 Delete,
437 Insert,
439 Esc,
441 F(u8),
443 Null,
445 CapsLock,
447 ScrollLock,
449 NumLock,
451 PrintScreen,
453 Pause,
455 Menu,
457 KeypadBegin,
459 MediaPlay,
461 MediaPause,
463 MediaPlayPause,
465 MediaStop,
467 MediaNext,
469 MediaPrevious,
471 MediaFastForward,
473 MediaRewind,
475 MediaVolumeUp,
477 MediaVolumeDown,
479 MediaMute,
481 Modifier(ModifierKey),
483}
484
485impl From<crossterm::event::KeyEvent> for KeyEvent {
486 fn from(event: crossterm::event::KeyEvent) -> Self {
487 let key = match event.code {
488 KeyCode::Char(c) => Key::Char(c),
489 KeyCode::Backspace => Key::Backspace,
490 KeyCode::Enter => Key::Enter,
491 KeyCode::Left => Key::Left,
492 KeyCode::Right => Key::Right,
493 KeyCode::Up => Key::Up,
494 KeyCode::Down => Key::Down,
495 KeyCode::Home => Key::Home,
496 KeyCode::End => Key::End,
497 KeyCode::PageUp => Key::PageUp,
498 KeyCode::PageDown => Key::PageDown,
499 KeyCode::Tab => Key::Tab,
500 KeyCode::BackTab => Key::Tab, KeyCode::Delete => Key::Delete,
502 KeyCode::Insert => Key::Insert,
503 KeyCode::Esc => Key::Esc,
504 KeyCode::F(n) => Key::F(n),
505 KeyCode::Null => Key::Null,
506 KeyCode::CapsLock => Key::CapsLock,
507 KeyCode::ScrollLock => Key::ScrollLock,
508 KeyCode::NumLock => Key::NumLock,
509 KeyCode::PrintScreen => Key::PrintScreen,
510 KeyCode::Pause => Key::Pause,
511 KeyCode::Menu => Key::Menu,
512 KeyCode::KeypadBegin => Key::KeypadBegin,
513 KeyCode::Media(crossterm::event::MediaKeyCode::Play) => Key::MediaPlay,
515 KeyCode::Media(crossterm::event::MediaKeyCode::Pause) => Key::MediaPause,
516 KeyCode::Media(crossterm::event::MediaKeyCode::PlayPause) => Key::MediaPlayPause,
517 KeyCode::Media(crossterm::event::MediaKeyCode::Stop) => Key::MediaStop,
518 KeyCode::Media(crossterm::event::MediaKeyCode::FastForward) => Key::MediaFastForward,
519 KeyCode::Media(crossterm::event::MediaKeyCode::Rewind) => Key::MediaRewind,
520 KeyCode::Media(crossterm::event::MediaKeyCode::TrackNext) => Key::MediaNext,
521 KeyCode::Media(crossterm::event::MediaKeyCode::TrackPrevious) => Key::MediaPrevious,
522 KeyCode::Media(crossterm::event::MediaKeyCode::LowerVolume) => Key::MediaVolumeDown,
523 KeyCode::Media(crossterm::event::MediaKeyCode::RaiseVolume) => Key::MediaVolumeUp,
524 KeyCode::Media(crossterm::event::MediaKeyCode::MuteVolume) => Key::MediaMute,
525 KeyCode::Modifier(
527 crossterm::event::ModifierKeyCode::LeftShift
528 | crossterm::event::ModifierKeyCode::RightShift,
529 ) => Key::Modifier(ModifierKey::Shift),
530 KeyCode::Modifier(
531 crossterm::event::ModifierKeyCode::LeftControl
532 | crossterm::event::ModifierKeyCode::RightControl,
533 ) => Key::Modifier(ModifierKey::Control),
534 KeyCode::Modifier(
535 crossterm::event::ModifierKeyCode::LeftAlt
536 | crossterm::event::ModifierKeyCode::RightAlt,
537 ) => Key::Modifier(ModifierKey::Alt),
538 KeyCode::Modifier(
539 crossterm::event::ModifierKeyCode::LeftSuper
540 | crossterm::event::ModifierKeyCode::RightSuper,
541 ) => Key::Modifier(ModifierKey::Super),
542 KeyCode::Modifier(
543 crossterm::event::ModifierKeyCode::LeftMeta
544 | crossterm::event::ModifierKeyCode::RightMeta,
545 ) => Key::Modifier(ModifierKey::Meta),
546 KeyCode::Modifier(
547 crossterm::event::ModifierKeyCode::LeftHyper
548 | crossterm::event::ModifierKeyCode::RightHyper,
549 ) => Key::Modifier(ModifierKey::Hyper),
550 _ => Key::Null, };
552
553 Self {
554 key,
555 modifiers: event.modifiers,
556 }
557 }
558}
559
560#[derive(Debug, Clone, Copy, PartialEq)]
578pub struct MouseEvent {
579 pub kind: MouseEventKind,
581 pub column: u16,
583 pub row: u16,
585 pub modifiers: KeyModifiers,
587}
588
589impl MouseEvent {
590 pub fn new(kind: MouseEventKind, column: u16, row: u16, modifiers: KeyModifiers) -> Self {
592 Self {
593 kind,
594 column,
595 row,
596 modifiers,
597 }
598 }
599
600 pub fn is_left_click(&self) -> bool {
602 matches!(self.kind, MouseEventKind::Down(MouseButton::Left))
603 }
604
605 pub fn is_right_click(&self) -> bool {
607 matches!(self.kind, MouseEventKind::Down(MouseButton::Right))
608 }
609
610 pub fn is_middle_click(&self) -> bool {
612 matches!(self.kind, MouseEventKind::Down(MouseButton::Middle))
613 }
614
615 pub fn is_click(&self) -> bool {
617 matches!(self.kind, MouseEventKind::Down(_))
618 }
619
620 pub fn is_release(&self) -> bool {
622 matches!(self.kind, MouseEventKind::Up(_))
623 }
624
625 pub fn is_drag(&self) -> bool {
627 matches!(self.kind, MouseEventKind::Drag(_))
628 }
629
630 pub fn is_left_drag(&self) -> bool {
632 matches!(self.kind, MouseEventKind::Drag(MouseButton::Left))
633 }
634
635 pub fn is_right_drag(&self) -> bool {
637 matches!(self.kind, MouseEventKind::Drag(MouseButton::Right))
638 }
639
640 pub fn is_middle_drag(&self) -> bool {
642 matches!(self.kind, MouseEventKind::Drag(MouseButton::Middle))
643 }
644
645 pub fn is_scroll_up(&self) -> bool {
647 matches!(self.kind, MouseEventKind::ScrollUp)
648 }
649
650 pub fn is_scroll_down(&self) -> bool {
652 matches!(self.kind, MouseEventKind::ScrollDown)
653 }
654
655 pub fn is_scroll_left(&self) -> bool {
657 matches!(self.kind, MouseEventKind::ScrollLeft)
658 }
659
660 pub fn is_scroll_right(&self) -> bool {
662 matches!(self.kind, MouseEventKind::ScrollRight)
663 }
664
665 pub fn is_scroll(&self) -> bool {
667 matches!(
668 self.kind,
669 MouseEventKind::ScrollUp
670 | MouseEventKind::ScrollDown
671 | MouseEventKind::ScrollLeft
672 | MouseEventKind::ScrollRight
673 )
674 }
675
676 pub fn is_move(&self) -> bool {
678 matches!(self.kind, MouseEventKind::Moved)
679 }
680
681 pub fn button(&self) -> Option<MouseButton> {
683 match self.kind {
684 MouseEventKind::Down(btn) | MouseEventKind::Up(btn) | MouseEventKind::Drag(btn) => {
685 Some(btn)
686 }
687 _ => None,
688 }
689 }
690
691 pub fn position(&self) -> (u16, u16) {
693 (self.column, self.row)
694 }
695
696 pub fn is_within(&self, x: u16, y: u16, width: u16, height: u16) -> bool {
708 self.column >= x && self.column < x + width && self.row >= y && self.row < y + height
709 }
710
711 pub fn is_at(&self, column: u16, row: u16) -> bool {
713 self.column == column && self.row == row
714 }
715
716 pub fn has_modifier(&self, modifier: KeyModifiers) -> bool {
718 self.modifiers.contains(modifier)
719 }
720
721 pub fn is_ctrl(&self) -> bool {
723 self.modifiers.contains(KeyModifiers::CONTROL)
724 }
725
726 pub fn is_alt(&self) -> bool {
728 self.modifiers.contains(KeyModifiers::ALT)
729 }
730
731 pub fn is_shift(&self) -> bool {
733 self.modifiers.contains(KeyModifiers::SHIFT)
734 }
735
736 pub fn has_modifiers(&self) -> bool {
738 !self.modifiers.is_empty()
739 }
740
741 pub fn no_modifiers(&self) -> bool {
743 self.modifiers.is_empty()
744 }
745}
746
747impl From<crossterm::event::MouseEvent> for MouseEvent {
748 fn from(event: crossterm::event::MouseEvent) -> Self {
749 Self {
750 kind: event.kind,
751 column: event.column,
752 row: event.row,
753 modifiers: event.modifiers,
754 }
755 }
756}
757
758#[cfg(test)]
759mod tests {
760 use super::*;
761 use proptest::prelude::*;
762
763 #[test]
764 fn test_key_event_creation() {
765 let event = KeyEvent::new(Key::Char('a'), KeyModifiers::empty());
766 assert_eq!(event.key, Key::Char('a'));
767 assert!(event.is_char());
768 assert_eq!(event.char(), Some('a'));
769 }
770
771 #[test]
772 fn test_key_event_modifiers() {
773 let event = KeyEvent::new(Key::Char('c'), KeyModifiers::CONTROL);
774 assert_eq!(event.key, Key::Char('c'));
775 assert_eq!(event.modifiers, KeyModifiers::CONTROL);
776 }
777
778 #[test]
779 fn test_non_char_keys() {
780 let event = KeyEvent::new(Key::Enter, KeyModifiers::empty());
781 assert!(!event.is_char());
782 assert_eq!(event.char(), None);
783 }
784
785 #[test]
786 fn test_window_size_creation() {
787 let size = WindowSize {
788 width: 80,
789 height: 24,
790 };
791 assert_eq!(size.width, 80);
792 assert_eq!(size.height, 24);
793 }
794
795 #[test]
796 fn test_mouse_event_creation() {
797 let event = MouseEvent {
798 kind: MouseEventKind::Down(MouseButton::Left),
799 column: 10,
800 row: 5,
801 modifiers: KeyModifiers::empty(),
802 };
803 assert_eq!(event.column, 10);
804 assert_eq!(event.row, 5);
805 }
806
807 #[test]
808 fn test_event_variants() {
809 let key_event = Event::<String>::Key(KeyEvent::new(Key::Char('a'), KeyModifiers::empty()));
810 let mouse_event = Event::<String>::Mouse(MouseEvent {
811 kind: MouseEventKind::Down(MouseButton::Left),
812 column: 0,
813 row: 0,
814 modifiers: KeyModifiers::empty(),
815 });
816 let resize_event = Event::<String>::Resize {
817 width: 80,
818 height: 24,
819 };
820 let tick_event = Event::<String>::Tick;
821 let user_event = Event::User("test".to_string());
822 let quit_event = Event::<String>::Quit;
823 let focus_event = Event::<String>::Focus;
824 let blur_event = Event::<String>::Blur;
825 let suspend_event = Event::<String>::Suspend;
826 let resume_event = Event::<String>::Resume;
827 let paste_event = Event::<String>::Paste("pasted text".to_string());
828
829 assert!(key_event.is_key());
831 assert!(key_event.as_key().is_some());
832
833 assert!(mouse_event.is_mouse());
834 assert!(mouse_event.as_mouse().is_some());
835
836 assert!(resize_event.is_resize());
837 assert_eq!(resize_event.as_resize(), Some((80, 24)));
838
839 assert!(tick_event.is_tick());
840
841 assert!(user_event.is_user());
842 assert_eq!(user_event.as_user(), Some(&"test".to_string()));
843
844 assert!(quit_event.is_quit());
845 assert!(focus_event.is_focus());
846 assert!(blur_event.is_blur());
847 assert!(suspend_event.is_suspend());
848 assert!(resume_event.is_resume());
849
850 assert!(paste_event.is_paste());
851 assert_eq!(paste_event.as_paste(), Some("pasted text"));
852 }
853
854 #[test]
855 fn test_key_variants() {
856 let keys = vec![
857 Key::Char('a'),
858 Key::Backspace,
859 Key::Enter,
860 Key::Left,
861 Key::Right,
862 Key::Up,
863 Key::Down,
864 Key::Home,
865 Key::End,
866 Key::PageUp,
867 Key::PageDown,
868 Key::Tab,
869 Key::Delete,
870 Key::Insert,
871 Key::Esc,
872 Key::F(1),
873 Key::Null,
874 ];
875
876 for key in keys {
877 let event = KeyEvent::new(key, KeyModifiers::empty());
878 assert_eq!(event.key, key);
879
880 match key {
882 Key::Char(c) => {
883 assert!(event.is_char());
884 assert_eq!(event.char(), Some(c));
885 }
886 _ => {
887 assert!(!event.is_char());
888 assert_eq!(event.char(), None);
889 }
890 }
891 }
892 }
893
894 #[test]
895 fn test_crossterm_key_conversion() {
896 let crossterm_event = crossterm::event::KeyEvent::new(
897 KeyCode::Char('x'),
898 KeyModifiers::CONTROL | KeyModifiers::SHIFT,
899 );
900
901 let key_event: KeyEvent = crossterm_event.into();
902 assert_eq!(key_event.key, Key::Char('x'));
903 assert_eq!(
904 key_event.modifiers,
905 KeyModifiers::CONTROL | KeyModifiers::SHIFT
906 );
907 }
908
909 #[test]
910 fn test_enhanced_keys() {
911 use crossterm::event::{KeyCode, KeyModifiers};
912
913 let caps_lock = crossterm::event::KeyEvent::new(KeyCode::CapsLock, KeyModifiers::empty());
915 let key_event = KeyEvent::from(caps_lock);
916 assert_eq!(key_event.key, Key::CapsLock);
917
918 let scroll_lock =
919 crossterm::event::KeyEvent::new(KeyCode::ScrollLock, KeyModifiers::empty());
920 let key_event = KeyEvent::from(scroll_lock);
921 assert_eq!(key_event.key, Key::ScrollLock);
922
923 let print_screen =
924 crossterm::event::KeyEvent::new(KeyCode::PrintScreen, KeyModifiers::empty());
925 let key_event = KeyEvent::from(print_screen);
926 assert_eq!(key_event.key, Key::PrintScreen);
927
928 let play = crossterm::event::KeyEvent::new(
930 KeyCode::Media(crossterm::event::MediaKeyCode::Play),
931 KeyModifiers::empty(),
932 );
933 let key_event = KeyEvent::from(play);
934 assert_eq!(key_event.key, Key::MediaPlay);
935
936 let volume_up = crossterm::event::KeyEvent::new(
937 KeyCode::Media(crossterm::event::MediaKeyCode::RaiseVolume),
938 KeyModifiers::empty(),
939 );
940 let key_event = KeyEvent::from(volume_up);
941 assert_eq!(key_event.key, Key::MediaVolumeUp);
942
943 let left_shift = crossterm::event::KeyEvent::new(
945 KeyCode::Modifier(crossterm::event::ModifierKeyCode::LeftShift),
946 KeyModifiers::empty(),
947 );
948 let key_event = KeyEvent::from(left_shift);
949 assert_eq!(key_event.key, Key::Modifier(ModifierKey::Shift));
950
951 let right_alt = crossterm::event::KeyEvent::new(
952 KeyCode::Modifier(crossterm::event::ModifierKeyCode::RightAlt),
953 KeyModifiers::empty(),
954 );
955 let key_event = KeyEvent::from(right_alt);
956 assert_eq!(key_event.key, Key::Modifier(ModifierKey::Alt));
957 }
958
959 #[test]
960 fn test_crossterm_key_conversion_all_keys() {
961 let test_cases = vec![
963 (KeyCode::Backspace, Key::Backspace),
964 (KeyCode::Enter, Key::Enter),
965 (KeyCode::Left, Key::Left),
966 (KeyCode::Right, Key::Right),
967 (KeyCode::Up, Key::Up),
968 (KeyCode::Down, Key::Down),
969 (KeyCode::Home, Key::Home),
970 (KeyCode::End, Key::End),
971 (KeyCode::PageUp, Key::PageUp),
972 (KeyCode::PageDown, Key::PageDown),
973 (KeyCode::Tab, Key::Tab),
974 (KeyCode::Delete, Key::Delete),
975 (KeyCode::Insert, Key::Insert),
976 (KeyCode::Esc, Key::Esc),
977 (KeyCode::F(1), Key::F(1)),
978 (KeyCode::F(12), Key::F(12)),
979 (KeyCode::Null, Key::Null),
980 (KeyCode::BackTab, Key::Tab), ];
982
983 for (crossterm_code, expected_key) in test_cases {
984 let crossterm_event =
985 crossterm::event::KeyEvent::new(crossterm_code, KeyModifiers::empty());
986 let key_event: KeyEvent = crossterm_event.into();
987 assert_eq!(key_event.key, expected_key);
988 }
989 }
990
991 #[test]
992 fn test_crossterm_mouse_conversion() {
993 let crossterm_event = crossterm::event::MouseEvent {
994 kind: MouseEventKind::Down(MouseButton::Right),
995 column: 42,
996 row: 24,
997 modifiers: KeyModifiers::ALT,
998 };
999
1000 let mouse_event: MouseEvent = crossterm_event.into();
1001 assert_eq!(mouse_event.kind, MouseEventKind::Down(MouseButton::Right));
1002 assert_eq!(mouse_event.column, 42);
1003 assert_eq!(mouse_event.row, 24);
1004 assert_eq!(mouse_event.modifiers, KeyModifiers::ALT);
1005 }
1006
1007 proptest! {
1009 #[test]
1010 fn test_key_event_properties(
1011 c in any::<char>(),
1012 ctrl in any::<bool>(),
1013 alt in any::<bool>(),
1014 shift in any::<bool>()
1015 ) {
1016 let mut modifiers = KeyModifiers::empty();
1017 if ctrl { modifiers |= KeyModifiers::CONTROL; }
1018 if alt { modifiers |= KeyModifiers::ALT; }
1019 if shift { modifiers |= KeyModifiers::SHIFT; }
1020
1021 let event = KeyEvent::new(Key::Char(c), modifiers);
1022
1023 prop_assert_eq!(event.key, Key::Char(c));
1024 prop_assert_eq!(event.modifiers, modifiers);
1025 prop_assert!(event.is_char());
1026 prop_assert_eq!(event.char(), Some(c));
1027 }
1028
1029 #[test]
1030 fn test_window_size_properties(
1031 width in 1u16..1000u16,
1032 height in 1u16..1000u16
1033 ) {
1034 let size = WindowSize { width, height };
1035
1036 prop_assert_eq!(size.width, width);
1037 prop_assert_eq!(size.height, height);
1038
1039 let size2 = size;
1041 prop_assert_eq!(size, size2);
1042 }
1043
1044 #[test]
1045 fn test_mouse_event_properties(
1046 column in 0u16..1000u16,
1047 row in 0u16..1000u16,
1048 button_idx in 0..3usize
1049 ) {
1050 let button = match button_idx {
1051 0 => MouseButton::Left,
1052 1 => MouseButton::Right,
1053 2 => MouseButton::Middle,
1054 _ => unreachable!(),
1055 };
1056
1057 let event = MouseEvent {
1058 kind: MouseEventKind::Down(button),
1059 column,
1060 row,
1061 modifiers: KeyModifiers::empty(),
1062 };
1063
1064 prop_assert_eq!(event.column, column);
1065 prop_assert_eq!(event.row, row);
1066 prop_assert_eq!(event.kind, MouseEventKind::Down(button));
1067 }
1068
1069 #[test]
1070 fn test_event_user_message_properties(
1071 message in ".*"
1072 ) {
1073 let event = Event::User(message.clone());
1074
1075 prop_assert!(event.is_user());
1076 prop_assert_eq!(event.as_user(), Some(&message));
1077 }
1078
1079 #[test]
1080 fn test_event_resize_properties(
1081 width in 1u16..1000u16,
1082 height in 1u16..1000u16
1083 ) {
1084 let event = Event::<String>::Resize { width, height };
1085
1086 prop_assert!(event.is_resize());
1087 prop_assert_eq!(event.as_resize(), Some((width, height)));
1088 }
1089
1090 #[test]
1091 fn test_event_paste_properties(
1092 paste_text in ".*"
1093 ) {
1094 let event = Event::<String>::Paste(paste_text.clone());
1095
1096 prop_assert!(event.is_paste());
1097 prop_assert_eq!(event.as_paste(), Some(paste_text.as_str()));
1098 }
1099
1100 #[test]
1101 fn test_function_key_properties(
1102 key_num in 1u8..25u8
1103 ) {
1104 let key = Key::F(key_num);
1105 let event = KeyEvent::new(key, KeyModifiers::empty());
1106
1107 prop_assert_eq!(event.key, Key::F(key_num));
1108 prop_assert!(!event.is_char());
1109 prop_assert_eq!(event.char(), None);
1110 }
1111
1112 #[test]
1113 fn test_key_modifier_combinations(
1114 ctrl in any::<bool>(),
1115 alt in any::<bool>(),
1116 shift in any::<bool>(),
1117 super_key in any::<bool>()
1118 ) {
1119 let mut modifiers = KeyModifiers::empty();
1120 if ctrl { modifiers |= KeyModifiers::CONTROL; }
1121 if alt { modifiers |= KeyModifiers::ALT; }
1122 if shift { modifiers |= KeyModifiers::SHIFT; }
1123 if super_key { modifiers |= KeyModifiers::SUPER; }
1124
1125 let event = KeyEvent::new(Key::Char('a'), modifiers);
1126
1127 prop_assert_eq!(event.modifiers.contains(KeyModifiers::CONTROL), ctrl);
1128 prop_assert_eq!(event.modifiers.contains(KeyModifiers::ALT), alt);
1129 prop_assert_eq!(event.modifiers.contains(KeyModifiers::SHIFT), shift);
1130 prop_assert_eq!(event.modifiers.contains(KeyModifiers::SUPER), super_key);
1131 }
1132 }
1133}