@@ -122,6 +122,15 @@ fn check_auto_reset(
122122 }
123123}
124124
125+ /// Returns `true` when a key event should immediately exit the application
126+ /// in screensaver mode.
127+ ///
128+ /// Any key press exits; key release/repeat events (emitted on some platforms,
129+ /// e.g. Windows) are ignored so a single keystroke does not double-fire.
130+ fn screensaver_exit_on_key ( mode : & Mode , key_event : & crossterm:: event:: KeyEvent ) -> bool {
131+ * mode == Mode :: Screensaver && key_event. kind == crossterm:: event:: KeyEventKind :: Press
132+ }
133+
125134/// Runs the interactive simulation loop (Live or Screensaver mode).
126135///
127136/// Handles terminal setup, input processing, simulation updates, and rendering
@@ -130,7 +139,7 @@ fn check_auto_reset(
130139pub fn run_simulation (
131140 sim : & mut Simulation ,
132141 args : & Args ,
133- _mode : Mode ,
142+ mode : Mode ,
134143 palette : cli:: Palette ,
135144 charset : Charset ,
136145) -> io:: Result < ( ) > {
@@ -1169,6 +1178,14 @@ pub fn run_simulation(
11691178 key_event. modifiers . contains ( KeyModifiers :: SHIFT ) ;
11701179 }
11711180
1181+ // Screensaver mode: any key press exits (mouse events and
1182+ // resizes do not). Checked before overlay/control dispatch so
1183+ // no other handler can swallow the event.
1184+ if screensaver_exit_on_key ( & mode, & key_event) {
1185+ should_exit = true ;
1186+ break ;
1187+ }
1188+
11721189 // GLOBAL EXIT HANDLING -- always allow 'q' to quit regardless of overlay
11731190 if InputPoller :: is_exit_key ( & key_event) {
11741191 should_exit = true ;
@@ -2365,3 +2382,52 @@ pub fn get_terminal_size() -> (usize, usize) {
23652382 Err ( _) => ( 80 , 24 ) ,
23662383 }
23672384}
2385+
2386+ #[ cfg( test) ]
2387+ mod tests {
2388+ use super :: * ;
2389+ use crossterm:: event:: { KeyCode , KeyEvent , KeyEventKind , KeyEventState , KeyModifiers } ;
2390+
2391+ fn key ( code : KeyCode , kind : KeyEventKind ) -> KeyEvent {
2392+ KeyEvent {
2393+ code,
2394+ modifiers : KeyModifiers :: NONE ,
2395+ kind,
2396+ state : KeyEventState :: NONE ,
2397+ }
2398+ }
2399+
2400+ #[ test]
2401+ fn screensaver_exits_on_any_key_press ( ) {
2402+ for code in [
2403+ KeyCode :: Char ( 'a' ) ,
2404+ KeyCode :: Char ( ' ' ) ,
2405+ KeyCode :: Enter ,
2406+ KeyCode :: Esc ,
2407+ KeyCode :: Up ,
2408+ KeyCode :: F ( 1 ) ,
2409+ ] {
2410+ assert ! (
2411+ screensaver_exit_on_key( & Mode :: Screensaver , & key( code, KeyEventKind :: Press ) ) ,
2412+ "expected screensaver exit for {:?}" ,
2413+ code
2414+ ) ;
2415+ }
2416+ }
2417+
2418+ #[ test]
2419+ fn screensaver_ignores_key_release_and_repeat ( ) {
2420+ let release = key ( KeyCode :: Char ( 'a' ) , KeyEventKind :: Release ) ;
2421+ let repeat = key ( KeyCode :: Char ( 'a' ) , KeyEventKind :: Repeat ) ;
2422+ assert ! ( !screensaver_exit_on_key( & Mode :: Screensaver , & release) ) ;
2423+ assert ! ( !screensaver_exit_on_key( & Mode :: Screensaver , & repeat) ) ;
2424+ }
2425+
2426+ #[ test]
2427+ fn non_screensaver_modes_never_exit_on_key ( ) {
2428+ let press = key ( KeyCode :: Char ( 'a' ) , KeyEventKind :: Press ) ;
2429+ for mode in [ Mode :: Default , Mode :: Live , Mode :: Print ] {
2430+ assert ! ( !screensaver_exit_on_key( & mode, & press) ) ;
2431+ }
2432+ }
2433+ }
0 commit comments