use crate::Component;
use std::collections::HashMap;
use device_query::{DeviceQuery, DeviceState, Keycode};
#[derive(Clone, PartialEq)]
enum KeyState {
Up,
Down,
}
#[derive(Clone)]
struct KeyStateData {
prev_state: KeyState,
current_state: KeyState,
}
#[derive(Component)]
pub struct Input {
keylogger: HashMap<Keycode, KeyStateData>,
device_state: DeviceState,
}
impl Input {
pub fn new() -> Self {
Input {
keylogger: HashMap::new(),
device_state: DeviceState::new(),
}
}
pub fn is_key_down(&self, keycode: &Keycode) -> bool {
if let Some(key_state_data) = self.keylogger.get(keycode) {
return key_state_data.current_state == KeyState::Down
&& key_state_data.prev_state == KeyState::Up;
}
false
}
pub fn is_key_up(&self, keycode: &Keycode) -> bool {
if let Some(key_state_data) = self.keylogger.get(keycode) {
return key_state_data.current_state == KeyState::Up
&& key_state_data.prev_state == KeyState::Down;
}
false
}
pub fn is_key_pressed(&self, keycode: &Keycode) -> bool {
if let Some(key_state_data) = self.keylogger.get(keycode) {
return key_state_data.current_state == KeyState::Down;
}
false
}
pub fn is_any_key_down(&self) -> bool {
self.keylogger.values().any(|key_state_data| {
return key_state_data.current_state == KeyState::Down
&& key_state_data.prev_state == KeyState::Up;
})
}
pub fn is_any_key_up(&self) -> bool {
self.keylogger.values().any(|key_state_data| {
return key_state_data.current_state == KeyState::Up
&& key_state_data.prev_state == KeyState::Down;
})
}
pub fn is_any_key_pressed(&self) -> bool {
self.keylogger.values().any(|key_state_data| {
return key_state_data.current_state == KeyState::Down;
})
}
pub fn is_chord_pressed(&self, keycodes: &[&Keycode]) -> bool {
keycodes
.into_iter()
.all(|keycode| self.is_key_pressed(keycode))
}
pub fn is_chord_pressed_exclusively(&self, keycodes: &[&Keycode]) -> bool {
self.keylogger
.iter()
.filter_map(|(keycode, key_state)| {
if key_state.current_state == KeyState::Down {
return Some(keycode);
}
None
})
.all(|pressed_key| keycodes.contains(&pressed_key))
&& self.is_chord_pressed(keycodes)
}
pub(crate) fn update(&mut self) {
let current_keys = self.device_state.get_keys();
self.keylogger.iter_mut().for_each(|(_, key_state_data)| {
key_state_data.prev_state = key_state_data.current_state.clone();
key_state_data.current_state = KeyState::Up;
});
current_keys.iter().for_each(|keycode| {
if let Some(key_state_data) = self.keylogger.get(keycode) {
let mut new_key_state_data = key_state_data.clone();
new_key_state_data.current_state = KeyState::Down;
self.keylogger.insert(keycode.clone(), new_key_state_data);
} else {
self.keylogger.insert(
keycode.clone(),
KeyStateData {
prev_state: KeyState::Up,
current_state: KeyState::Down,
},
);
}
});
}
}
#[cfg(test)]
mod tests {
use super::*;
mod key_state {
use super::*;
#[test]
fn equality_works() {
assert!(KeyState::Up == KeyState::Up);
assert!(KeyState::Down == KeyState::Down);
}
#[test]
fn inequality_works() {
assert!(KeyState::Up != KeyState::Down);
}
}
}