use std::collections::HashMap;
use super::action::InputAction;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum VirtualKey {
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
Num0,
Num1,
Num2,
Num3,
Num4,
Num5,
Num6,
Num7,
Num8,
Num9,
ArrowUp,
ArrowDown,
ArrowLeft,
ArrowRight,
ShiftLeft,
ShiftRight,
CtrlLeft,
CtrlRight,
AltLeft,
AltRight,
Space,
Enter,
Escape,
Tab,
Backspace,
Delete,
Home,
End,
PageUp,
PageDown,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
MouseLeft,
MouseRight,
MouseMiddle,
MouseButton4,
MouseButton5,
GamepadA,
GamepadB,
GamepadX,
GamepadY,
GamepadLB,
GamepadRB,
GamepadLT,
GamepadRT,
GamepadStart,
GamepadSelect,
GamepadDpadUp,
GamepadDpadDown,
GamepadDpadLeft,
GamepadDpadRight,
GamepadLeftStickPress,
GamepadRightStickPress,
}
pub struct InputBindingMap {
bindings: HashMap<VirtualKey, InputAction>,
}
impl InputBindingMap {
pub fn new() -> Self {
Self {
bindings: HashMap::new(),
}
}
pub fn default_bindings() -> Self {
let mut map = Self::new();
map.bind(VirtualKey::W, InputAction::MoveForward);
map.bind(VirtualKey::S, InputAction::MoveBackward);
map.bind(VirtualKey::A, InputAction::MoveLeft);
map.bind(VirtualKey::D, InputAction::MoveRight);
map.bind(VirtualKey::ArrowUp, InputAction::MoveForward);
map.bind(VirtualKey::ArrowDown, InputAction::MoveBackward);
map.bind(VirtualKey::ArrowLeft, InputAction::MoveLeft);
map.bind(VirtualKey::ArrowRight, InputAction::MoveRight);
map.bind(VirtualKey::Space, InputAction::Jump);
map.bind(VirtualKey::ShiftLeft, InputAction::Sprint);
map.bind(VirtualKey::MouseRight, InputAction::CameraRotate);
map.bind(VirtualKey::MouseMiddle, InputAction::CameraPan);
map.bind(VirtualKey::MouseLeft, InputAction::PrimaryAction);
map.bind(VirtualKey::E, InputAction::Interact);
map.bind(VirtualKey::Escape, InputAction::Cancel);
map.bind(VirtualKey::Enter, InputAction::Confirm);
map.bind(VirtualKey::Q, InputAction::Block);
map.bind(VirtualKey::I, InputAction::OpenInventory);
map.bind(VirtualKey::M, InputAction::OpenMap);
map.bind(VirtualKey::T, InputAction::OpenChat);
map.bind(VirtualKey::Num1, InputAction::QuickSlot(0));
map.bind(VirtualKey::Num2, InputAction::QuickSlot(1));
map.bind(VirtualKey::Num3, InputAction::QuickSlot(2));
map.bind(VirtualKey::Num4, InputAction::QuickSlot(3));
map.bind(VirtualKey::Num5, InputAction::QuickSlot(4));
map.bind(VirtualKey::Num6, InputAction::QuickSlot(5));
map.bind(VirtualKey::Num7, InputAction::QuickSlot(6));
map.bind(VirtualKey::Num8, InputAction::QuickSlot(7));
map.bind(VirtualKey::Num9, InputAction::QuickSlot(8));
map.bind(VirtualKey::F11, InputAction::ToggleFullscreen);
map.bind(VirtualKey::F12, InputAction::Screenshot);
map.bind(VirtualKey::GamepadA, InputAction::Confirm);
map.bind(VirtualKey::GamepadB, InputAction::Cancel);
map.bind(VirtualKey::GamepadX, InputAction::Interact);
map.bind(VirtualKey::GamepadY, InputAction::OpenInventory);
map.bind(VirtualKey::GamepadRB, InputAction::Attack);
map.bind(VirtualKey::GamepadLB, InputAction::Block);
map.bind(VirtualKey::GamepadStart, InputAction::Pause);
map
}
pub fn bind(&mut self, key: VirtualKey, action: InputAction) {
self.bindings.insert(key, action);
}
pub fn unbind(&mut self, key: VirtualKey) {
self.bindings.remove(&key);
}
pub fn action_for(&self, key: VirtualKey) -> Option<InputAction> {
self.bindings.get(&key).copied()
}
pub fn len(&self) -> usize {
self.bindings.len()
}
pub fn is_empty(&self) -> bool {
self.bindings.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (&VirtualKey, &InputAction)> {
self.bindings.iter()
}
}
impl Default for InputBindingMap {
fn default() -> Self {
Self::default_bindings()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_bindings_has_wasd() {
let map = InputBindingMap::default_bindings();
assert_eq!(map.action_for(VirtualKey::W), Some(InputAction::MoveForward));
assert_eq!(map.action_for(VirtualKey::S), Some(InputAction::MoveBackward));
assert_eq!(map.action_for(VirtualKey::A), Some(InputAction::MoveLeft));
assert_eq!(map.action_for(VirtualKey::D), Some(InputAction::MoveRight));
}
#[test]
fn bind_and_unbind() {
let mut map = InputBindingMap::new();
map.bind(VirtualKey::X, InputAction::Attack);
assert_eq!(map.action_for(VirtualKey::X), Some(InputAction::Attack));
map.unbind(VirtualKey::X);
assert_eq!(map.action_for(VirtualKey::X), None);
}
#[test]
fn rebind_overwrites() {
let mut map = InputBindingMap::new();
map.bind(VirtualKey::Space, InputAction::Jump);
map.bind(VirtualKey::Space, InputAction::Dodge);
assert_eq!(map.action_for(VirtualKey::Space), Some(InputAction::Dodge));
}
#[test]
fn default_bindings_nonempty() {
let map = InputBindingMap::default_bindings();
assert!(!map.is_empty());
assert!(map.len() > 20);
}
#[test]
fn arrow_keys_bound() {
let map = InputBindingMap::default_bindings();
assert_eq!(map.action_for(VirtualKey::ArrowUp), Some(InputAction::MoveForward));
assert_eq!(map.action_for(VirtualKey::ArrowDown), Some(InputAction::MoveBackward));
assert_eq!(map.action_for(VirtualKey::ArrowLeft), Some(InputAction::MoveLeft));
assert_eq!(map.action_for(VirtualKey::ArrowRight), Some(InputAction::MoveRight));
}
#[test]
fn quick_slots_bound() {
let map = InputBindingMap::default_bindings();
assert_eq!(map.action_for(VirtualKey::Num1), Some(InputAction::QuickSlot(0)));
assert_eq!(map.action_for(VirtualKey::Num9), Some(InputAction::QuickSlot(8)));
}
#[test]
fn mouse_left_maps_to_primary_action() {
let map = InputBindingMap::default_bindings();
assert_eq!(map.action_for(VirtualKey::MouseLeft), Some(InputAction::PrimaryAction));
}
#[test]
fn gamepad_bindings() {
let map = InputBindingMap::default_bindings();
assert_eq!(map.action_for(VirtualKey::GamepadA), Some(InputAction::Confirm));
assert_eq!(map.action_for(VirtualKey::GamepadB), Some(InputAction::Cancel));
assert_eq!(map.action_for(VirtualKey::GamepadStart), Some(InputAction::Pause));
}
}