use crate::{input::*, EmeraldError};
#[cfg(feature = "gamepads")]
use gamepad::{Button, GamepadEngine, GamepadState};
use winit::event::{ElementState, VirtualKeyCode};
use std::collections::{HashMap, HashSet};
use super::touch_state::TouchState;
pub(crate) struct Action {
pub key_bindings: HashSet<KeyCode>,
#[cfg(feature = "gamepads")]
pub button_bindings: HashMap<usize, HashSet<Button>>,
}
impl Action {
pub fn new() -> Self {
Self {
key_bindings: HashSet::new(),
#[cfg(feature = "gamepads")]
button_bindings: HashMap::new(),
}
}
}
pub type ActionId = String;
pub(crate) struct InputEngine {
#[cfg(feature = "gamepads")]
gamepad_engine: GamepadEngine,
#[cfg(feature = "gamepads")]
pub(crate) gamepads: Vec<GamepadState>,
pub(crate) keys: HashMap<KeyCode, ButtonState>,
pub(crate) mouse: MouseState,
pub(crate) touches: HashMap<u64, TouchState>,
pub(crate) touches_to_mouse: bool,
pub(crate) mouse_to_touch: bool,
pub(crate) actions: HashMap<ActionId, Action>,
}
impl InputEngine {
pub(crate) fn new() -> Self {
InputEngine {
#[cfg(feature = "gamepads")]
gamepad_engine: GamepadEngine::new(),
#[cfg(feature = "gamepads")]
gamepads: Vec::new(),
keys: HashMap::new(),
mouse: MouseState::new(),
touches: HashMap::new(),
touches_to_mouse: false,
mouse_to_touch: false,
actions: HashMap::new(),
}
}
pub fn handle_virtual_keycode(&mut self, virtual_keycode: VirtualKeyCode, state: ElementState) {
let keycode = virtual_keycode_to_keycode(virtual_keycode);
match state {
ElementState::Pressed => self.set_key_pressed(keycode, true),
ElementState::Released => self.set_key_pressed(keycode, false),
}
}
pub fn handle_cursor_move(&mut self, position: &winit::dpi::PhysicalPosition<f64>) {
self.mouse.translation = Translation::new(position.x as f32, position.y as f32);
}
pub fn handle_mouse_input(&mut self, button: &winit::event::MouseButton, state: &ElementState) {
let is_pressed = match state {
ElementState::Pressed => true,
ElementState::Released => false,
};
match button {
winit::event::MouseButton::Left => {
self.mouse.left.is_pressed = is_pressed;
}
winit::event::MouseButton::Right => {
self.mouse.right.is_pressed = is_pressed;
}
winit::event::MouseButton::Middle => {
self.mouse.middle.is_pressed = is_pressed;
}
_ => {}
}
}
fn rollover_touches(&mut self) {
self.touches.retain(|_id, touch| !touch.is_outdated());
for touch in self.touches.values_mut() {
touch.rollover();
}
}
#[inline]
#[cfg(feature = "gamepads")]
pub fn update_and_rollover(&mut self) -> Result<(), EmeraldError> {
self.gamepad_engine.update()?;
self.gamepads = self.gamepad_engine.gamepads().clone();
for state in self.keys.values_mut() {
state.rollover();
}
self.rollover_touches();
self.mouse.rollover();
Ok(())
}
#[inline]
#[cfg(not(feature = "gamepads"))]
pub fn update_and_rollover(&mut self) -> Result<(), EmeraldError> {
for (_key, state) in &mut self.keys {
state.rollover();
}
self.rollover_touches();
self.mouse.rollover();
Ok(())
}
fn add_action_if_not_exists(&mut self, action_id: &ActionId) {
if self.actions.contains_key(action_id) {
return;
}
self.actions.insert(action_id.clone(), Action::new());
}
#[inline]
pub fn add_action_binding_key(&mut self, action_id: &ActionId, key_code: KeyCode) {
self.add_action_if_not_exists(action_id);
if let Some(action) = self.actions.get_mut(action_id) {
action.key_bindings.insert(key_code);
}
}
#[inline]
#[cfg(feature = "gamepads")]
pub fn add_action_binding_button(
&mut self,
action_id: &ActionId,
button: Button,
gamepad_index: usize,
) {
self.add_action_if_not_exists(action_id);
if let Some(action) = self.actions.get_mut(action_id) {
if !action.button_bindings.contains_key(&gamepad_index) {
action.button_bindings.insert(gamepad_index, HashSet::new());
}
if let Some(set) = action.button_bindings.get_mut(&gamepad_index) {
set.insert(button);
}
}
}
#[inline]
pub fn remove_action_binding_key(&mut self, action_id: &ActionId, key_code: &KeyCode) {
if let Some(action) = self.actions.get_mut(action_id) {
action.key_bindings.remove(key_code);
}
}
#[inline]
#[cfg(feature = "gamepads")]
pub fn remove_action_binding_button(
&mut self,
action_id: &ActionId,
button: &Button,
gamepad_index: usize,
) {
if let Some(action) = self.actions.get_mut(action_id) {
if let Some(set) = action.button_bindings.get_mut(&gamepad_index) {
set.remove(button);
if set.len() == 0 {
action.button_bindings.remove(&gamepad_index);
}
}
}
}
#[inline]
pub fn set_key_down(&mut self, keycode: KeyCode, _repeat: bool) {
self.set_key_pressed(keycode, true)
}
#[inline]
pub fn set_key_up(&mut self, keycode: KeyCode) {
self.set_key_pressed(keycode, false)
}
#[inline]
fn set_key_pressed(&mut self, keycode: KeyCode, is_pressed: bool) {
if let Some(mut key) = self.keys.get_mut(&keycode) {
key.is_pressed = is_pressed;
} else {
self.keys.insert(keycode, ButtonState::new());
self.set_key_pressed(keycode, is_pressed);
}
}
#[inline]
pub fn set_mouse_translation(&mut self, x: f32, y: f32) {
self.mouse.translation = Translation::new(x, y);
}
#[inline]
pub fn set_mouse_down(&mut self, button: MouseButton, x: f32, y: f32) {
self.set_mouse_translation(x, y);
self.set_mouse_pressed(button, true);
}
#[inline]
pub fn set_mouse_up(&mut self, button: MouseButton, x: f32, y: f32) {
self.set_mouse_translation(x, y);
self.set_mouse_pressed(button, false);
}
#[inline]
fn set_mouse_pressed(&mut self, button: MouseButton, is_pressed: bool) {
let state = match button {
MouseButton::Right => &mut self.mouse.right,
MouseButton::Left => &mut self.mouse.left,
MouseButton::Middle => &mut self.mouse.middle,
MouseButton::Unknown => return,
};
state.is_pressed = is_pressed;
}
#[inline]
pub fn touch_event(&mut self, phase: TouchPhase, id: u64, x: f32, y: f32) {
let touch = self.touches.entry(id).or_default();
touch.translation = Translation::new(x, y);
touch.phase = phase;
}
}
pub(crate) fn virtual_keycode_to_keycode(virtual_keycode: VirtualKeyCode) -> KeyCode {
match virtual_keycode {
VirtualKeyCode::A => KeyCode::A,
VirtualKeyCode::B => KeyCode::B,
VirtualKeyCode::C => KeyCode::C,
VirtualKeyCode::D => KeyCode::D,
VirtualKeyCode::E => KeyCode::E,
VirtualKeyCode::F => KeyCode::F,
VirtualKeyCode::G => KeyCode::G,
VirtualKeyCode::H => KeyCode::H,
VirtualKeyCode::I => KeyCode::I,
VirtualKeyCode::J => KeyCode::J,
VirtualKeyCode::K => KeyCode::K,
VirtualKeyCode::L => KeyCode::L,
VirtualKeyCode::M => KeyCode::M,
VirtualKeyCode::N => KeyCode::N,
VirtualKeyCode::O => KeyCode::O,
VirtualKeyCode::P => KeyCode::P,
VirtualKeyCode::Q => KeyCode::Q,
VirtualKeyCode::R => KeyCode::R,
VirtualKeyCode::S => KeyCode::S,
VirtualKeyCode::T => KeyCode::T,
VirtualKeyCode::U => KeyCode::U,
VirtualKeyCode::V => KeyCode::V,
VirtualKeyCode::W => KeyCode::W,
VirtualKeyCode::X => KeyCode::X,
VirtualKeyCode::Y => KeyCode::Y,
VirtualKeyCode::Z => KeyCode::Z,
VirtualKeyCode::Down => KeyCode::Down,
VirtualKeyCode::Up => KeyCode::Up,
VirtualKeyCode::Left => KeyCode::Left,
VirtualKeyCode::Right => KeyCode::Right,
VirtualKeyCode::Space => KeyCode::Space,
VirtualKeyCode::Escape => KeyCode::Escape,
VirtualKeyCode::Delete => KeyCode::Delete,
VirtualKeyCode::Apostrophe => KeyCode::Apostrophe,
VirtualKeyCode::Comma => KeyCode::Comma,
VirtualKeyCode::Minus => KeyCode::Minus,
VirtualKeyCode::Period => KeyCode::Period,
VirtualKeyCode::Slash => KeyCode::Slash,
VirtualKeyCode::Key0 => KeyCode::Key0,
VirtualKeyCode::Key1 => KeyCode::Key1,
VirtualKeyCode::Key2 => KeyCode::Key2,
VirtualKeyCode::Key3 => KeyCode::Key3,
VirtualKeyCode::Key4 => KeyCode::Key4,
VirtualKeyCode::Key5 => KeyCode::Key5,
VirtualKeyCode::Key6 => KeyCode::Key6,
VirtualKeyCode::Key7 => KeyCode::Key7,
VirtualKeyCode::Key8 => KeyCode::Key8,
VirtualKeyCode::Key9 => KeyCode::Key9,
VirtualKeyCode::Semicolon => KeyCode::Semicolon,
VirtualKeyCode::Equals => KeyCode::Equal,
VirtualKeyCode::LBracket => KeyCode::LeftBracket,
VirtualKeyCode::Backslash => KeyCode::Backslash,
VirtualKeyCode::RBracket => KeyCode::RightBracket,
VirtualKeyCode::Grave => KeyCode::GraveAccent,
VirtualKeyCode::NumpadEnter => KeyCode::KpEnter,
VirtualKeyCode::Return => KeyCode::Enter,
VirtualKeyCode::Tab => KeyCode::Tab,
VirtualKeyCode::Back => KeyCode::Backspace,
VirtualKeyCode::Insert => KeyCode::Insert,
VirtualKeyCode::PageUp => KeyCode::PageUp,
VirtualKeyCode::PageDown => KeyCode::PageDown,
VirtualKeyCode::Home => KeyCode::Home,
VirtualKeyCode::End => KeyCode::End,
VirtualKeyCode::Capital => KeyCode::CapsLock,
VirtualKeyCode::Scroll => KeyCode::ScrollLock,
VirtualKeyCode::Numlock => KeyCode::NumLock,
VirtualKeyCode::Pause => KeyCode::Pause,
VirtualKeyCode::F1 => KeyCode::F1,
VirtualKeyCode::F2 => KeyCode::F2,
VirtualKeyCode::F3 => KeyCode::F3,
VirtualKeyCode::F4 => KeyCode::F4,
VirtualKeyCode::F5 => KeyCode::F5,
VirtualKeyCode::F6 => KeyCode::F6,
VirtualKeyCode::F7 => KeyCode::F7,
VirtualKeyCode::F8 => KeyCode::F8,
VirtualKeyCode::F9 => KeyCode::F9,
VirtualKeyCode::F10 => KeyCode::F10,
VirtualKeyCode::F11 => KeyCode::F11,
VirtualKeyCode::F12 => KeyCode::F12,
VirtualKeyCode::F13 => KeyCode::F13,
VirtualKeyCode::F14 => KeyCode::F14,
VirtualKeyCode::F15 => KeyCode::F15,
VirtualKeyCode::F16 => KeyCode::F16,
VirtualKeyCode::F17 => KeyCode::F17,
VirtualKeyCode::F18 => KeyCode::F18,
VirtualKeyCode::F19 => KeyCode::F19,
VirtualKeyCode::F20 => KeyCode::F20,
VirtualKeyCode::F21 => KeyCode::F21,
VirtualKeyCode::F22 => KeyCode::F22,
VirtualKeyCode::F23 => KeyCode::F23,
VirtualKeyCode::F24 => KeyCode::F24,
VirtualKeyCode::Numpad0 => KeyCode::Kp0,
VirtualKeyCode::Numpad1 => KeyCode::Kp1,
VirtualKeyCode::Numpad2 => KeyCode::Kp2,
VirtualKeyCode::Numpad3 => KeyCode::Kp3,
VirtualKeyCode::Numpad4 => KeyCode::Kp4,
VirtualKeyCode::Numpad5 => KeyCode::Kp5,
VirtualKeyCode::Numpad6 => KeyCode::Kp6,
VirtualKeyCode::Numpad7 => KeyCode::Kp7,
VirtualKeyCode::Numpad8 => KeyCode::Kp8,
VirtualKeyCode::Numpad9 => KeyCode::Kp9,
VirtualKeyCode::NumpadDecimal => KeyCode::KpDecimal,
VirtualKeyCode::NumpadDivide => KeyCode::KpDivide,
VirtualKeyCode::NumpadMultiply => KeyCode::KpMultiply,
VirtualKeyCode::NumpadSubtract => KeyCode::KpSubtract,
VirtualKeyCode::NumpadAdd => KeyCode::KpAdd,
VirtualKeyCode::NumpadEquals => KeyCode::KpEqual,
VirtualKeyCode::LShift => KeyCode::LeftShift,
VirtualKeyCode::LControl => KeyCode::LeftControl,
VirtualKeyCode::LAlt => KeyCode::LeftAlt,
VirtualKeyCode::RShift => KeyCode::RightShift,
VirtualKeyCode::RControl => KeyCode::RightControl,
VirtualKeyCode::RAlt => KeyCode::RightAlt,
_ => KeyCode::Unknown,
}
}