use std::{hash::{Hash, Hasher}, collections::{HashMap, hash_map::DefaultHasher}}; use winit::event::ElementState; //pub trait Button : Clone + Hash + Eq + PartialEq + 'static {} /* pub trait Button {} impl Button for T {} */ pub trait Button = Clone + Hash + Eq + PartialEq + 'static; #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] pub enum ButtonEvent { Pressed(T), Released(T), JustPressed(T), } impl ButtonEvent { fn take_val(self) -> T { match self { ButtonEvent::Pressed(t) => t, ButtonEvent::JustPressed(t) => t, ButtonEvent::Released(t) => t, } } fn clone_val(&self) -> T { self.clone().take_val() } } #[derive(Clone)] pub struct InputButtons { // the u64 as the key is the hashed value of T. this makes it easier to // search for a button and see its state button_events: HashMap>, } impl Default for InputButtons { fn default() -> Self { Self::new() } } impl InputButtons { pub fn new() -> Self { Self { button_events: HashMap::new(), } } fn get_button_hash(button: &T) -> u64 { let mut hasher = DefaultHasher::new(); button.hash(&mut hasher); hasher.finish() } /// Add a button event to this input type pub fn add_input(&mut self, button: ButtonEvent) { let hash = Self::get_button_hash(&button.clone_val()); self.button_events.insert(hash, button); } pub(crate) fn add_input_from_winit(&mut self, button: T, state: ElementState) { let event = match state { // TODO: there is a pause between pressed events of a key when holding down, so it stays in a just pressed state for too long // When a button is held down, this would change a just pressed button into a pressed button. ElementState::Pressed if self.is_pressed(button.clone()) => ButtonEvent::Pressed(button), ElementState::Pressed => ButtonEvent::JustPressed(button), ElementState::Released => ButtonEvent::Released(button), }; self.add_input(event); } /// Returns true if the button is pressed (or was just pressed) pub fn is_pressed(&self, button: T) -> bool { let hash = Self::get_button_hash(&button); match self.button_events.get(&hash) { Some(button_event) => match button_event { // this if statement should always be true, but just in case ;) ButtonEvent::Pressed(b) | ButtonEvent::JustPressed(b) if button == *b => true, _ => false, }, None => false } } /// Returns true if the button was just pressed this tick pub fn was_just_pressed(&self, button: T) -> bool { let hash = Self::get_button_hash(&button); match self.button_events.get(&hash) { Some(button_event) => match button_event { // this if statement should always be true, but just in case ;) ButtonEvent::JustPressed(b) if button == *b => true, _ => false, }, None => false } } }