use std::collections::HashSet;
use winit::event::{ElementState, KeyEvent, WindowEvent, MouseButton, MouseScrollDelta};
use winit::keyboard::{KeyCode, PhysicalKey};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MouseBtn {
Left,
Right,
Middle,
Other(u16),
}
impl From<MouseButton> for MouseBtn {
fn from(button: MouseButton) -> Self {
match button {
MouseButton::Left => MouseBtn::Left,
MouseButton::Right => MouseBtn::Right,
MouseButton::Middle => MouseBtn::Middle,
MouseButton::Back => MouseBtn::Other(3),
MouseButton::Forward => MouseBtn::Other(4),
MouseButton::Other(id) => MouseBtn::Other(id),
}
}
}
pub struct InputHandler {
keys_pressed: HashSet<KeyCode>,
keys_just_pressed: HashSet<KeyCode>,
keys_just_released: HashSet<KeyCode>,
pub mouse_delta: (f64, f64),
pub mouse_position: (f64, f64),
last_mouse_position: Option<(f64, f64)>,
mouse_buttons: HashSet<MouseBtn>,
mouse_buttons_just_pressed: HashSet<MouseBtn>,
mouse_buttons_just_released: HashSet<MouseBtn>,
pub mouse_wheel_delta: f32,
pub mouse_locked: bool,
pub mouse_visible: bool,
}
impl InputHandler {
pub fn new() -> Self {
Self {
keys_pressed: HashSet::new(),
keys_just_pressed: HashSet::new(),
keys_just_released: HashSet::new(),
mouse_delta: (0.0, 0.0),
mouse_position: (0.0, 0.0),
last_mouse_position: None,
mouse_buttons: HashSet::new(),
mouse_buttons_just_pressed: HashSet::new(),
mouse_buttons_just_released: HashSet::new(),
mouse_wheel_delta: 0.0,
mouse_locked: false,
mouse_visible: true,
}
}
pub fn begin_frame(&mut self) {
self.keys_just_pressed.clear();
self.keys_just_released.clear();
self.mouse_buttons_just_pressed.clear();
self.mouse_buttons_just_released.clear();
self.mouse_wheel_delta = 0.0;
self.mouse_delta = (0.0, 0.0);
}
pub fn update(&mut self, event: &WindowEvent) {
match event {
WindowEvent::KeyboardInput {
event:
KeyEvent {
physical_key: PhysicalKey::Code(keycode),
state,
..
},
..
} => {
match state {
ElementState::Pressed => {
if self.keys_pressed.insert(*keycode) {
self.keys_just_pressed.insert(*keycode);
}
}
ElementState::Released => {
self.keys_pressed.remove(keycode);
self.keys_just_released.insert(*keycode);
}
}
}
WindowEvent::CursorMoved { position, .. } => {
self.mouse_position = (position.x, position.y);
if let Some(last_pos) = self.last_mouse_position {
self.mouse_delta = (
position.x - last_pos.0,
position.y - last_pos.1,
);
} else {
self.mouse_delta = (0.0, 0.0);
}
self.last_mouse_position = Some((position.x, position.y));
}
WindowEvent::MouseInput { state, button, .. } => {
let btn = MouseBtn::from(*button);
match state {
ElementState::Pressed => {
if self.mouse_buttons.insert(btn) {
self.mouse_buttons_just_pressed.insert(btn);
}
}
ElementState::Released => {
self.mouse_buttons.remove(&btn);
self.mouse_buttons_just_released.insert(btn);
}
}
}
WindowEvent::MouseWheel { delta, .. } => {
match delta {
MouseScrollDelta::LineDelta(_x, y) => {
self.mouse_wheel_delta = *y;
}
MouseScrollDelta::PixelDelta(pos) => {
self.mouse_wheel_delta = pos.y as f32 / 100.0;
}
}
}
_ => {}
}
}
pub fn is_key_pressed(&self, keycode: KeyCode) -> bool {
self.keys_pressed.contains(&keycode)
}
pub fn is_key_just_pressed(&self, keycode: KeyCode) -> bool {
self.keys_just_pressed.contains(&keycode)
}
pub fn is_key_just_released(&self, keycode: KeyCode) -> bool {
self.keys_just_released.contains(&keycode)
}
pub fn any_key_pressed(&self) -> bool {
!self.keys_pressed.is_empty()
}
pub fn get_pressed_keys(&self) -> Vec<KeyCode> {
self.keys_pressed.iter().copied().collect()
}
pub fn reset_mouse_delta(&mut self) {
self.mouse_delta = (0.0, 0.0);
}
pub fn get_mouse_delta(&self) -> (f64, f64) {
self.mouse_delta
}
pub fn get_mouse_position(&self) -> (f64, f64) {
self.mouse_position
}
pub fn get_mouse_x(&self) -> f64 {
self.mouse_position.0
}
pub fn get_mouse_y(&self) -> f64 {
self.mouse_position.1
}
pub fn is_mouse_button_pressed(&self, button: MouseBtn) -> bool {
self.mouse_buttons.contains(&button)
}
pub fn is_mouse_button_just_pressed(&self, button: MouseBtn) -> bool {
self.mouse_buttons_just_pressed.contains(&button)
}
pub fn is_mouse_button_just_released(&self, button: MouseBtn) -> bool {
self.mouse_buttons_just_released.contains(&button)
}
pub fn is_left_mouse_just_released(&self) -> bool {
self.is_mouse_button_just_released(MouseBtn::Left)
}
pub fn is_right_mouse_just_released(&self) -> bool {
self.is_mouse_button_just_released(MouseBtn::Right)
}
pub fn is_left_mouse_pressed(&self) -> bool {
self.is_mouse_button_pressed(MouseBtn::Left)
}
pub fn is_right_mouse_pressed(&self) -> bool {
self.is_mouse_button_pressed(MouseBtn::Right)
}
pub fn is_middle_mouse_pressed(&self) -> bool {
self.is_mouse_button_pressed(MouseBtn::Middle)
}
pub fn is_left_mouse_just_pressed(&self) -> bool {
self.is_mouse_button_just_pressed(MouseBtn::Left)
}
pub fn is_right_mouse_just_pressed(&self) -> bool {
self.is_mouse_button_just_pressed(MouseBtn::Right)
}
pub fn get_mouse_wheel_delta(&self) -> f32 {
self.mouse_wheel_delta
}
pub fn is_scrolling_up(&self) -> bool {
self.mouse_wheel_delta > 0.0
}
pub fn is_scrolling_down(&self) -> bool {
self.mouse_wheel_delta < 0.0
}
pub fn is_ctrl_pressed(&self) -> bool {
self.is_key_pressed(KeyCode::ControlLeft) || self.is_key_pressed(KeyCode::ControlRight)
}
pub fn is_shift_pressed(&self) -> bool {
self.is_key_pressed(KeyCode::ShiftLeft) || self.is_key_pressed(KeyCode::ShiftRight)
}
pub fn is_alt_pressed(&self) -> bool {
self.is_key_pressed(KeyCode::AltLeft) || self.is_key_pressed(KeyCode::AltRight)
}
pub fn get_axis_horizontal(&self) -> f32 {
let mut axis = 0.0;
if self.is_key_pressed(KeyCode::KeyA) || self.is_key_pressed(KeyCode::ArrowLeft) {
axis -= 1.0;
}
if self.is_key_pressed(KeyCode::KeyD) || self.is_key_pressed(KeyCode::ArrowRight) {
axis += 1.0;
}
axis
}
pub fn get_axis_vertical(&self) -> f32 {
let mut axis = 0.0;
if self.is_key_pressed(KeyCode::KeyW) || self.is_key_pressed(KeyCode::ArrowUp) {
axis -= 1.0;
}
if self.is_key_pressed(KeyCode::KeyS) || self.is_key_pressed(KeyCode::ArrowDown) {
axis += 1.0;
}
axis
}
pub fn get_movement_vector(&self) -> (f32, f32) {
(self.get_axis_horizontal(), self.get_axis_vertical())
}
#[cfg(target_os = "android")]
pub fn process_touch(&mut self, event: &WindowEvent) {
use winit::event::Touch;
match event {
WindowEvent::Touch(Touch { phase, location, id, .. }) => {
use winit::event::TouchPhase;
let touch_point = crate::android::TouchPoint {
id: *id,
x: location.x as f32,
y: location.y as f32,
pressure: 1.0,
};
let touch_phase = match phase {
TouchPhase::Started => crate::android::TouchPhase::Started,
TouchPhase::Moved => crate::android::TouchPhase::Moved,
TouchPhase::Ended => crate::android::TouchPhase::Ended,
TouchPhase::Cancelled => crate::android::TouchPhase::Cancelled,
};
let touch_event = crate::android::TouchEvent {
point: touch_point,
phase: touch_phase,
};
}
_ => {}
}
}
}