use glam::{dvec2, DVec2, Vec2};
use rustc_hash::FxHashSet;
use winit::{
event::{MouseButton, MouseScrollDelta, WindowEvent},
keyboard::{KeyCode, PhysicalKey},
};
#[derive(Default)]
pub struct InputState {
pub event_buffers: Vec<WindowEvent>,
pub pressed_keys: FxHashSet<KeyCode>,
pub just_pressed_keys: FxHashSet<KeyCode>,
pub just_released_keys: FxHashSet<KeyCode>,
pub cursor_position: Option<DVec2>,
pub cursor_position_on_click: Option<DVec2>,
pub pressed_mouse_buttons: FxHashSet<MouseButton>,
pub clicked_mouse_buttons: FxHashSet<MouseButton>,
pub mouse_wheel_delta: Option<Vec2>,
pub mouse_drag_delta: Option<DVec2>,
}
impl InputState {
pub fn push_event(&mut self, event: WindowEvent) {
self.event_buffers.push(event);
}
pub fn update(&mut self) {
self.just_pressed_keys.clear();
self.just_released_keys.clear();
self.clicked_mouse_buttons.clear();
self.mouse_wheel_delta = None;
self.mouse_drag_delta = None;
for event in &self.event_buffers {
match event {
WindowEvent::KeyboardInput { event, .. } => {
if !event.repeat {
if let PhysicalKey::Code(keycode) = event.physical_key {
if event.state.is_pressed() {
self.pressed_keys.insert(keycode);
self.just_pressed_keys.insert(keycode);
} else {
self.pressed_keys.remove(&keycode);
self.just_released_keys.insert(keycode);
}
}
}
}
WindowEvent::CursorMoved { position, .. } => {
let previous_position = self.cursor_position;
let current_position = dvec2(position.x, position.y);
self.cursor_position = Some(current_position);
if let Some(previous_position) = previous_position {
if !self.pressed_mouse_buttons.is_empty() {
self.mouse_drag_delta = Some(current_position - previous_position);
}
}
}
WindowEvent::CursorLeft { .. } => {
self.cursor_position = None;
}
WindowEvent::MouseInput { state, button, .. } => {
if state.is_pressed() {
self.pressed_mouse_buttons.insert(*button);
self.cursor_position_on_click = self.cursor_position;
} else {
self.pressed_mouse_buttons.remove(button);
if self.cursor_position == self.cursor_position_on_click {
self.clicked_mouse_buttons.insert(*button);
}
self.cursor_position_on_click = None;
}
}
WindowEvent::MouseWheel { delta, .. } => match delta {
MouseScrollDelta::LineDelta(horizontal, vertical) => {
*self.mouse_wheel_delta.get_or_insert(Vec2::ZERO) +=
Vec2::new(*horizontal, *vertical);
}
_ => {}
},
_ => {}
}
}
self.event_buffers.clear();
}
}