use std::collections::HashMap;
use std::hash::Hash;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyState {
Up,
Down,
Pressed,
Released,
}
pub struct KeyStateMap<T>
where
T: Clone + Eq + Hash + PartialEq,
{
keys: HashMap<T, KeyState>,
}
impl<T> Default for KeyStateMap<T>
where
T: Clone + Eq + Hash + PartialEq,
{
fn default() -> Self {
Self {
keys: HashMap::default(),
}
}
}
impl<T> KeyStateMap<T>
where
T: Clone + Eq + Hash + PartialEq,
{
pub fn is_pressed(&self, key: &T) -> bool {
let state = self.state(key);
state == KeyState::Pressed
}
pub fn is_down(&self, key: &T) -> bool {
let state = self.state(key);
(state == KeyState::Pressed) || (state == KeyState::Down)
}
pub fn is_released(&self, key: &T) -> bool {
let state = self.state(key);
state == KeyState::Released
}
pub fn is_up(&self, key: &T) -> bool {
let state = self.state(key);
(state == KeyState::Released) || (state == KeyState::Up)
}
pub fn transition_states(&mut self) {
for (_, curr_state) in self.keys.iter_mut() {
let new_state = match curr_state {
KeyState::Pressed => KeyState::Down,
KeyState::Released => KeyState::Up,
_ => *curr_state,
};
*curr_state = new_state;
}
}
pub fn handle_key_down(&mut self, key: &T) {
self.keys.insert(key.clone(), KeyState::Pressed);
}
pub fn handle_key_up(&mut self, key: &T) {
self.keys.insert(key.clone(), KeyState::Released);
}
fn state(&self, key: &T) -> KeyState {
let state = self.keys.get(key);
match state {
Some(current_state) => *current_state,
None => KeyState::Up,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Clone, Eq, Hash, PartialEq)]
enum MouseButton {
Main,
Secondary,
}
#[test]
fn initial() {
let input = KeyStateMap::default();
assert_eq!(input.state(&MouseButton::Main), KeyState::Up);
}
#[test]
fn transition_noop() {
let mut input = KeyStateMap::default();
input.transition_states();
assert_eq!(input.state(&MouseButton::Main), KeyState::Up);
}
#[test]
fn transition_pressed_down() {
let mut input = KeyStateMap::default();
input.handle_key_down(&MouseButton::Main);
assert_eq!(input.state(&MouseButton::Main), KeyState::Pressed);
input.transition_states();
assert_eq!(input.state(&MouseButton::Main), KeyState::Down);
}
#[test]
fn transition_released_inactive() {
let mut input = KeyStateMap::default();
input.handle_key_down(&MouseButton::Main);
input.transition_states();
assert_eq!(input.state(&MouseButton::Main), KeyState::Down);
input.handle_key_up(&MouseButton::Main);
assert_eq!(input.state(&MouseButton::Main), KeyState::Released);
input.transition_states();
assert_eq!(input.state(&MouseButton::Main), KeyState::Up);
}
#[test]
fn independent() {
let mut input = KeyStateMap::default();
input.handle_key_down(&MouseButton::Main);
assert_eq!(input.state(&MouseButton::Main), KeyState::Pressed);
assert_eq!(input.state(&MouseButton::Secondary), KeyState::Up);
input.transition_states();
assert_eq!(input.state(&MouseButton::Main), KeyState::Down);
assert_eq!(input.state(&MouseButton::Secondary), KeyState::Up);
input.handle_key_up(&MouseButton::Main);
input.handle_key_down(&MouseButton::Secondary);
assert_eq!(input.state(&MouseButton::Main), KeyState::Released);
assert_eq!(input.state(&MouseButton::Secondary), KeyState::Pressed);
input.transition_states();
assert_eq!(input.state(&MouseButton::Main), KeyState::Up);
assert_eq!(input.state(&MouseButton::Secondary), KeyState::Down);
}
}