use std::collections::HashMap;
use crossterm::event::{KeyCode, KeyModifiers};
use falling_tetromino_engine::Button;
use crate::tui_settings::SlotMachine;
#[derive(PartialEq, Eq, Clone, Debug)]
#[serde_with::serde_as] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(transparent)]
pub struct GameKeybinds {
keymap: HashMap<(KeyCode, KeyModifiers), Button>,
}
pub fn default_keybinds_slots() -> SlotMachine<GameKeybinds> {
let slots = vec![
("Default".to_owned(), GameKeybinds::default_tetro()),
("Control+".to_owned(), GameKeybinds::extra_control()),
("Guideline".to_owned(), GameKeybinds::guideline()),
("Terminal finesse".to_owned(), GameKeybinds::terminal_fin()),
("Vim".to_owned(), GameKeybinds::vim()),
("Blank slate".to_owned(), GameKeybinds::blank_slate()),
];
SlotMachine::with_unmodifiable_slots(slots, "Keybinds".to_owned())
}
impl GameKeybinds {
pub fn get(&self, (code, modifiers): (KeyCode, KeyModifiers)) -> Option<&Button> {
self.keymap.get(&Self::normalize((code, modifiers)))
}
pub fn iter(&self) -> impl Iterator<Item = (&(KeyCode, KeyModifiers), &Button)> {
self.keymap.iter()
}
pub fn unstable_access(&mut self) -> &mut HashMap<(KeyCode, KeyModifiers), Button> {
&mut self.keymap
}
pub fn normalize(
(mut code, mut modifiers): (KeyCode, KeyModifiers),
) -> (KeyCode, KeyModifiers) {
match code {
KeyCode::Modifier(modifier_key_code) => {
use crossterm::event::ModifierKeyCode as MKC;
let modifier = match modifier_key_code {
MKC::LeftShift | MKC::RightShift => KeyModifiers::SHIFT,
MKC::LeftControl | MKC::RightControl => KeyModifiers::CONTROL,
MKC::LeftAlt | MKC::RightAlt => KeyModifiers::ALT,
MKC::LeftSuper | MKC::RightSuper => KeyModifiers::SUPER,
MKC::LeftHyper | MKC::RightHyper => KeyModifiers::HYPER,
MKC::LeftMeta | MKC::RightMeta => KeyModifiers::META,
MKC::IsoLevel3Shift | MKC::IsoLevel5Shift => KeyModifiers::NONE,
};
modifiers.remove(modifier);
}
KeyCode::Char(ref mut char) => {
*char = char.to_ascii_lowercase();
}
_ => {}
}
(code, modifiers)
}
pub fn default_tetro() -> GameKeybinds {
let keys = [
(KeyCode::Left, Button::MoveLeft),
(KeyCode::Right, Button::MoveRight),
(KeyCode::Char('a'), Button::RotateLeft),
(KeyCode::Char('d'), Button::RotateRight),
(KeyCode::Down, Button::DropSoft),
(KeyCode::Up, Button::DropHard),
(KeyCode::Char(' '), Button::HoldPiece),
]
.map(|(k, b)| ((k, KeyModifiers::NONE), b));
GameKeybinds {
keymap: keys.into(),
}
}
pub fn extra_control() -> GameKeybinds {
let keys = [
(KeyCode::Left, Button::MoveLeft),
(KeyCode::Right, Button::MoveRight),
(KeyCode::Char('a'), Button::RotateLeft),
(KeyCode::Char('d'), Button::RotateRight),
(KeyCode::Char('s'), Button::Rotate180),
(KeyCode::Down, Button::DropSoft),
(KeyCode::Up, Button::DropHard),
(KeyCode::Char('w'), Button::TeleDown),
(KeyCode::Char('q'), Button::TeleLeft),
(KeyCode::Char('e'), Button::TeleRight),
(KeyCode::Char(' '), Button::HoldPiece),
]
.map(|(k, b)| ((k, KeyModifiers::NONE), b));
GameKeybinds {
keymap: keys.into(),
}
}
pub fn guideline() -> GameKeybinds {
use crossterm::event::ModifierKeyCode as M;
let keys = [
(KeyCode::Left, Button::MoveLeft),
(KeyCode::Right, Button::MoveRight),
(KeyCode::Char('z'), Button::RotateLeft),
(KeyCode::Char('y'), Button::RotateLeft), (KeyCode::Modifier(M::LeftControl), Button::RotateLeft),
(KeyCode::Modifier(M::RightControl), Button::RotateLeft),
(KeyCode::Char('x'), Button::RotateRight),
(KeyCode::Up, Button::RotateRight),
(KeyCode::Down, Button::DropSoft),
(KeyCode::Char(' '), Button::DropHard),
(KeyCode::Char('c'), Button::HoldPiece),
(KeyCode::Modifier(M::LeftShift), Button::HoldPiece),
(KeyCode::Modifier(M::RightShift), Button::HoldPiece),
]
.map(|(k, b)| ((k, KeyModifiers::NONE), b));
GameKeybinds {
keymap: keys.into(),
}
}
pub fn vim() -> GameKeybinds {
let keys = [
(KeyCode::Char('h'), Button::MoveLeft),
(KeyCode::Char('l'), Button::MoveRight),
(KeyCode::Char('a'), Button::RotateLeft),
(KeyCode::Char('d'), Button::RotateRight),
(KeyCode::Char('j'), Button::DropSoft),
(KeyCode::Char('k'), Button::DropHard),
(KeyCode::Char(' '), Button::HoldPiece),
]
.map(|(k, b)| ((k, KeyModifiers::NONE), b));
GameKeybinds {
keymap: keys.into(),
}
}
pub fn terminal_fin() -> GameKeybinds {
let keys = [
(KeyCode::Char('e'), Button::HoldPiece),
(KeyCode::Char('a'), Button::Rotate180),
(KeyCode::Char('s'), Button::TeleRight),
(KeyCode::Char('d'), Button::MoveLeft),
(KeyCode::Char('f'), Button::RotateLeft),
(KeyCode::Char(' '), Button::TeleDown),
(KeyCode::Char('j'), Button::DropHard),
(KeyCode::Char('k'), Button::RotateRight),
(KeyCode::Char('l'), Button::MoveRight),
(KeyCode::Char(';'), Button::TeleLeft),
(KeyCode::Char('รถ'), Button::TeleLeft),
(KeyCode::Char('i'), Button::DropSoft),
]
.map(|(k, b)| ((k, KeyModifiers::NONE), b));
GameKeybinds {
keymap: keys.into(),
}
}
pub fn blank_slate() -> GameKeybinds {
GameKeybinds { keymap: [].into() }
}
}