use std::collections::HashSet;
#[derive(Debug, Clone)]
pub enum InputEvent {
KeyPressed(KeyCode),
KeyReleased(KeyCode),
MousePressed(MouseButton),
MouseReleased(MouseButton),
MouseMoved {
x: f64,
y: f64,
},
MouseWheel {
delta_x: f64,
delta_y: f64,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
pub enum KeyCode {
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,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
Escape,
Enter,
Space,
Tab,
Backspace,
Shift,
Control,
Alt,
Up,
Down,
Left,
Right,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MouseButton {
Left,
Right,
Middle,
Back,
Forward,
Other(u16),
}
#[derive(Debug, Default)]
pub struct InputState {
pressed_keys: HashSet<KeyCode>,
pressed_mouse_buttons: HashSet<MouseButton>,
mouse_position: (f64, f64),
scroll_delta: (f64, f64),
}
impl InputState {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn process_event(&mut self, event: &InputEvent) {
match event {
InputEvent::KeyPressed(key) => {
self.pressed_keys.insert(*key);
}
InputEvent::KeyReleased(key) => {
self.pressed_keys.remove(key);
}
InputEvent::MousePressed(button) => {
self.pressed_mouse_buttons.insert(*button);
}
InputEvent::MouseReleased(button) => {
self.pressed_mouse_buttons.remove(button);
}
InputEvent::MouseMoved { x, y } => {
self.mouse_position = (*x, *y);
}
InputEvent::MouseWheel { delta_x, delta_y } => {
self.scroll_delta.0 += delta_x;
self.scroll_delta.1 += delta_y;
}
}
}
#[must_use]
pub fn is_key_pressed(&self, key: KeyCode) -> bool {
self.pressed_keys.contains(&key)
}
#[must_use]
pub fn is_mouse_button_pressed(&self, button: MouseButton) -> bool {
self.pressed_mouse_buttons.contains(&button)
}
#[must_use]
pub fn mouse_position(&self) -> (f64, f64) {
self.mouse_position
}
pub fn take_scroll_delta(&mut self) -> (f64, f64) {
let delta = self.scroll_delta;
self.scroll_delta = (0.0, 0.0);
delta
}
pub fn clear(&mut self) {
self.pressed_keys.clear();
self.pressed_mouse_buttons.clear();
self.scroll_delta = (0.0, 0.0);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_input_state_default() {
let state = InputState::new();
assert!(!state.is_key_pressed(KeyCode::A));
assert!(!state.is_mouse_button_pressed(MouseButton::Left));
assert_eq!(state.mouse_position(), (0.0, 0.0));
}
#[test]
fn test_key_press_release() {
let mut state = InputState::new();
state.process_event(&InputEvent::KeyPressed(KeyCode::W));
assert!(state.is_key_pressed(KeyCode::W));
assert!(!state.is_key_pressed(KeyCode::A));
state.process_event(&InputEvent::KeyPressed(KeyCode::A));
assert!(state.is_key_pressed(KeyCode::W));
assert!(state.is_key_pressed(KeyCode::A));
state.process_event(&InputEvent::KeyReleased(KeyCode::W));
assert!(!state.is_key_pressed(KeyCode::W));
assert!(state.is_key_pressed(KeyCode::A));
}
#[test]
fn test_mouse_button_press_release() {
let mut state = InputState::new();
state.process_event(&InputEvent::MousePressed(MouseButton::Left));
assert!(state.is_mouse_button_pressed(MouseButton::Left));
assert!(!state.is_mouse_button_pressed(MouseButton::Right));
state.process_event(&InputEvent::MouseReleased(MouseButton::Left));
assert!(!state.is_mouse_button_pressed(MouseButton::Left));
}
#[test]
fn test_mouse_movement() {
let mut state = InputState::new();
state.process_event(&InputEvent::MouseMoved { x: 100.0, y: 200.0 });
assert_eq!(state.mouse_position(), (100.0, 200.0));
state.process_event(&InputEvent::MouseMoved { x: 150.0, y: 250.0 });
assert_eq!(state.mouse_position(), (150.0, 250.0));
}
#[test]
fn test_scroll_accumulation() {
let mut state = InputState::new();
state.process_event(&InputEvent::MouseWheel {
delta_x: 1.0,
delta_y: 2.0,
});
state.process_event(&InputEvent::MouseWheel {
delta_x: 0.5,
delta_y: 1.0,
});
let delta = state.take_scroll_delta();
assert!((delta.0 - 1.5).abs() < f64::EPSILON);
assert!((delta.1 - 3.0).abs() < f64::EPSILON);
let delta = state.take_scroll_delta();
assert!((delta.0).abs() < f64::EPSILON);
assert!((delta.1).abs() < f64::EPSILON);
}
#[test]
fn test_clear() {
let mut state = InputState::new();
state.process_event(&InputEvent::KeyPressed(KeyCode::Space));
state.process_event(&InputEvent::MousePressed(MouseButton::Left));
state.process_event(&InputEvent::MouseWheel {
delta_x: 1.0,
delta_y: 1.0,
});
assert!(state.is_key_pressed(KeyCode::Space));
assert!(state.is_mouse_button_pressed(MouseButton::Left));
state.clear();
assert!(!state.is_key_pressed(KeyCode::Space));
assert!(!state.is_mouse_button_pressed(MouseButton::Left));
let delta = state.take_scroll_delta();
assert!((delta.0).abs() < f64::EPSILON);
}
#[test]
fn test_mouse_button_other() {
let mut state = InputState::new();
state.process_event(&InputEvent::MousePressed(MouseButton::Other(5)));
assert!(state.is_mouse_button_pressed(MouseButton::Other(5)));
assert!(!state.is_mouse_button_pressed(MouseButton::Other(6)));
}
}