rsnaker/controls/
input.rs1use crate::controls::direction::Direction;
2use crate::game_logic::state::{GameState, GameStatus};
3use crossterm::event;
4use crossterm::event::{KeyCode, KeyEventKind};
5use std::sync::{Arc, RwLock};
6
7const QUIT_KEYS: [KeyCode; 2] = [KeyCode::Char('q'), KeyCode::Char('Q')];
8const PARAMETERS_KEYS: [KeyCode; 2] = [KeyCode::Char('e'), KeyCode::Char('E')];
9const FRUITS_KEYS: [KeyCode; 2] = [KeyCode::Char('f'), KeyCode::Char('F')];
10const VELOCITY_KEYS: [KeyCode; 2] = [KeyCode::Char('s'), KeyCode::Char('P')];
11const HELP_KEYS: [KeyCode; 2] = [KeyCode::Char('h'), KeyCode::Char('H')];
12const MAIN_MENU_KEYS: [KeyCode; 2] = [KeyCode::Char('m'), KeyCode::Char('M')];
13const START_KEYS: [KeyCode; 2] = [KeyCode::Char('r'), KeyCode::Char('R')];
15pub(crate) const PAUSE_KEYS: [KeyCode; 4] = [
16 KeyCode::Char('p'),
17 KeyCode::Char('P'),
18 KeyCode::Char(' '),
19 KeyCode::Home,
20];
21const RESET_KEYS: [KeyCode; 2] = [KeyCode::Char('r'), KeyCode::Char('R')];
22const NEXT_KEYS: [KeyCode; 2] = [KeyCode::Right, KeyCode::Up];
23const PREVIOUS_KEYS: [KeyCode; 3] = [KeyCode::Left, KeyCode::Backspace, KeyCode::Down];
24const ENTER_KEYS: [KeyCode; 2] = [KeyCode::Enter, KeyCode::End];
25
26pub fn playing_input_loop(direction: &Arc<RwLock<Direction>>, gs: &Arc<RwLock<GameState>>) {
33 loop {
34 if let Ok(event::Event::Key(key)) = event::read() {
35 if key.kind == KeyEventKind::Press {
36 if PAUSE_KEYS.contains(&key.code) {
38 let mut gs_guard = gs.write().unwrap();
39 if gs_guard.status == GameStatus::Playing {
41 gs_guard.status = GameStatus::Paused;
42 } else if gs_guard.status == GameStatus::Paused {
43 gs_guard.status = GameStatus::Playing;
44 }
45 } else if QUIT_KEYS.contains(&key.code) {
47 gs.write().unwrap().status = GameStatus::ByeBye;
48 break;
49 } else if MAIN_MENU_KEYS.contains(&key.code) {
51 gs.write().unwrap().status = GameStatus::Menu;
52 break;
53 } else if RESET_KEYS.contains(&key.code) {
55 gs.write().unwrap().status = GameStatus::Restarting;
56 } else {
58 let direction_input = match key.code {
59 KeyCode::Left => Some(Direction::Left),
60 KeyCode::Right => Some(Direction::Right),
61 KeyCode::Down => Some(Direction::Down),
62 KeyCode::Up => Some(Direction::Up),
63 _ => None,
64 };
65 if let Some(dir) = direction_input {
66 *direction.write().unwrap() = dir;
67 }
68 }
69 }
70 }
71 }
72}
73
74#[derive(PartialEq, Clone, Debug)]
75pub enum GreetingOption {
76 StartGame,
77 Parameters,
78 Fruits,
79 Velocity,
80 Help,
81 MainMenu,
82 QuitGame,
83 Next,
84 Previous,
85 Enter,
86}
87#[must_use]
92pub fn greeting_screen_manage_input() -> Option<GreetingOption> {
93 if let event::Event::Key(key) = event::read().expect("Error reading key event") {
95 match key.kind {
96 KeyEventKind::Press => {
98 flush_input_buffer();
99 if START_KEYS.contains(&key.code) {
101 Some(GreetingOption::StartGame)
102 } else if QUIT_KEYS.contains(&key.code) {
104 Some(GreetingOption::QuitGame)
105 } else if PARAMETERS_KEYS.contains(&key.code) {
106 Some(GreetingOption::Parameters)
107 } else if FRUITS_KEYS.contains(&key.code) {
108 Some(GreetingOption::Fruits)
109 } else if VELOCITY_KEYS.contains(&key.code) {
110 Some(GreetingOption::Velocity)
111 } else if HELP_KEYS.contains(&key.code) {
112 Some(GreetingOption::Help)
113 } else if MAIN_MENU_KEYS.contains(&key.code) {
114 Some(GreetingOption::MainMenu)
115 } else if NEXT_KEYS.contains(&key.code) {
116 Some(GreetingOption::Next)
117 } else if PREVIOUS_KEYS.contains(&key.code) {
118 Some(GreetingOption::Previous)
119 } else if ENTER_KEYS.contains(&key.code) {
120 Some(GreetingOption::Enter)
121 } else {
122 None
123 }
124 }
125 _ => None,
126 }
127 } else {
128 None
129 }
130}
131fn flush_input_buffer() {
132 while crossterm::event::poll(std::time::Duration::from_secs(0)).unwrap_or(false) {
133 let _ = crossterm::event::read(); }
135}