use glam as math;
use std::{collections::HashSet, sync::Arc};
use winit::{
event::{DeviceEvent, ElementState, WindowEvent},
keyboard::PhysicalKey,
window::Window,
};
pub use winit::event::MouseButton;
pub use winit::keyboard::KeyCode;
use crate::context::Resource;
impl Resource for Input {}
pub struct Input {
window: Arc<Window>, events: Vec<WindowEvent>,
pub keys: HashSet<KeyCode>,
pub key_just_pressed: HashSet<KeyCode>,
pub mouse_buttons: HashSet<MouseButton>,
pub mouse_button_just_pressed: HashSet<MouseButton>,
pub cursor_position: math::Vec2,
pub mouse_delta: math::Vec2,
cursor_locked: bool,
cursor_lock_applied: bool,
}
impl Input {
pub fn new(window: Arc<Window>) -> Self {
let mut input_manager = Self {
window: window.clone(),
events: Vec::new(),
keys: HashSet::new(),
key_just_pressed: HashSet::new(),
mouse_buttons: HashSet::new(),
mouse_button_just_pressed: HashSet::new(),
cursor_position: math::vec2(0.0, 0.0),
mouse_delta: math::vec2(0.0, 0.0),
cursor_locked: false,
cursor_lock_applied: false,
};
input_manager.apply_cursor_lock();
input_manager
}
fn apply_cursor_lock(&mut self) {
if self.cursor_locked && !self.cursor_lock_applied {
match self
.window
.set_cursor_grab(winit::window::CursorGrabMode::Locked)
{
Ok(_) => {
self.cursor_lock_applied = true;
self.window.set_cursor_visible(false);
}
Err(e) => {
log::error!("Failed to lock cursor: {:?}", e);
}
}
} else if !self.cursor_locked && self.cursor_lock_applied {
match self
.window
.set_cursor_grab(winit::window::CursorGrabMode::None)
{
Ok(_) => {
self.cursor_lock_applied = false;
self.window.set_cursor_visible(true);
}
Err(e) => {
log::error!("Failed to unlock cursor: {:?}", e);
}
}
}
}
pub fn handle_device_event(&mut self, event: &DeviceEvent) {
#[allow(clippy::single_match)]
match event {
DeviceEvent::MouseMotion { delta } => {
let delta_vec = math::vec2(delta.0 as f32, delta.1 as f32);
self.mouse_delta += delta_vec;
}
_ => {}
}
}
pub fn handle_event(&mut self, event: &WindowEvent) {
self.events.push(event.clone());
match event {
WindowEvent::KeyboardInput { event, .. } => {
if let PhysicalKey::Code(keycode) = event.physical_key {
match event.state {
ElementState::Pressed => {
if !self.keys.contains(&keycode) {
self.key_just_pressed.insert(keycode);
}
self.keys.insert(keycode);
}
ElementState::Released => {
self.keys.remove(&keycode);
}
}
}
}
WindowEvent::MouseInput { state, button, .. } => match state {
ElementState::Pressed => {
if !self.mouse_button_just_pressed.contains(button) {
self.mouse_button_just_pressed.insert(*button);
}
self.mouse_buttons.insert(*button);
}
ElementState::Released => {
self.mouse_buttons.remove(button);
}
},
WindowEvent::CursorMoved { position, .. } => {
let new_position = math::vec2(position.x as f32, position.y as f32);
self.cursor_position = new_position;
}
_ => {}
}
}
pub fn end_frame(&mut self) {
self.key_just_pressed.clear();
self.mouse_button_just_pressed.clear();
self.mouse_delta = math::vec2(0.0, 0.0);
self.events.clear();
}
pub fn set_cursor_locked(&mut self, locked: bool) {
if self.cursor_locked != locked {
self.cursor_locked = locked;
self.apply_cursor_lock(); }
}
pub fn is_cursor_locked(&self) -> bool {
self.cursor_locked
}
}