rsnaker/controls/
playing_input.rs

1use crate::controls::direction::Direction;
2use crate::controls::main_menu::{ENTER_KEYS, NEXT_KEYS, PREVIOUS_KEYS};
3use crate::game_logic::state::{GameOverMenu, GameState, GameStatus};
4use crossterm::event;
5use crossterm::event::{KeyCode, KeyEventKind};
6use std::sync::{Arc, RwLock};
7
8pub const QUIT_KEYS: [KeyCode; 2] = [KeyCode::Char('q'), KeyCode::Char('Q')];
9pub const START_KEYS: [KeyCode; 2] = [KeyCode::Char('r'), KeyCode::Char('R')];
10pub const MAIN_MENU_KEYS: [KeyCode; 2] = [KeyCode::Char('m'), KeyCode::Char('M')];
11//const DIRECTIONAL_KEYS: [KeyCode; 4] = [KeyCode::Down, KeyCode::Up, KeyCode::Left, KeyCode::Right];
12pub const PAUSE_KEYS: [KeyCode; 4] = [
13    KeyCode::Char('p'),
14    KeyCode::Char('P'),
15    KeyCode::Char(' '),
16    KeyCode::Home,
17];
18pub const RESET_KEYS: [KeyCode; 2] = [KeyCode::Char('r'), KeyCode::Char('R')];
19
20/// You cannot block middle-click paste/scroll behavior from inside your Rust TUI app.
21/// If you really want to disable it, you would have to modify user system settings or terminal emulator config
22/// (e.g., in alacrity, kitty, gnome-terminal, etc.)
23/// That is outside the app's control
24/// # Panics
25/// if Arc panics while holding the resources (poisoning), no recovery mechanism implemented better crash
26pub fn playing_input_loop(direction: &Arc<RwLock<Direction>>, gs: &Arc<RwLock<GameState>>) {
27    loop {
28        if let Ok(event::Event::Key(key)) = event::read() {
29            if key.kind == KeyEventKind::Press {
30                let mut gs_guard = gs.write().unwrap();
31                // Handle GameOver navigation separately
32                if let GameStatus::GameOver(selection) = gs_guard.status {
33                    if NEXT_KEYS.contains(&key.code) {
34                        gs_guard.status = GameStatus::GameOver(selection.next());
35                    } else if PREVIOUS_KEYS.contains(&key.code) {
36                        gs_guard.status = GameStatus::GameOver(selection.previous());
37                    } else if ENTER_KEYS.contains(&key.code) {
38                        match selection {
39                            GameOverMenu::Restart => gs_guard.status = GameStatus::Restarting,
40                            GameOverMenu::Menu => {
41                                gs_guard.status = GameStatus::Menu;
42                                break;
43                            }
44                            GameOverMenu::Quit => {
45                                gs_guard.status = GameStatus::ByeBye;
46                                break;
47                            }
48                        }
49                    }
50                }
51                //We keep an if and not an else if, to keep keyboard shortcut working on game over screen
52                //PAUSE
53                if PAUSE_KEYS.contains(&key.code) {
54                    //in others state does nothing to not break game_logic logic
55                    if gs_guard.status == GameStatus::Playing {
56                        gs_guard.status = GameStatus::Paused;
57                    } else if gs_guard.status == GameStatus::Paused {
58                        gs_guard.status = GameStatus::Playing;
59                    }
60                //QUIT
61                } else if QUIT_KEYS.contains(&key.code) {
62                    gs_guard.status = GameStatus::ByeBye;
63                    break;
64                //MENU
65                } else if MAIN_MENU_KEYS.contains(&key.code) {
66                    gs_guard.status = GameStatus::Menu;
67                    break;
68                //RESTART
69                } else if RESET_KEYS.contains(&key.code) {
70                    gs_guard.status = GameStatus::Restarting;
71                //Arrow input
72                } else {
73                    let direction_input = match key.code {
74                        KeyCode::Left => Some(Direction::Left),
75                        KeyCode::Right => Some(Direction::Right),
76                        KeyCode::Down => Some(Direction::Down),
77                        KeyCode::Up => Some(Direction::Up),
78                        _ => None,
79                    };
80                    if let Some(dir) = direction_input {
81                        *direction.write().unwrap() = dir;
82                    }
83                }
84            }
85        }
86    }
87}