use crate::math::Vec2;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
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,
Key1, Key2, Key3, Key4, Key5, Key6, Key7, Key8, Key9, Key0,
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
Space, Enter, Escape, Tab, Backspace, Delete, Insert,
Home, End, PageUp, PageDown,
Up, Down, Left, Right,
LeftShift, RightShift, LeftCtrl, RightCtrl,
LeftAlt, RightAlt, LeftSuper, RightSuper,
Semicolon, Comma, Period, Slash, Backslash,
LeftBracket, RightBracket, Equals, Minus,
Apostrophe, Backquote,
CapsLock, ScrollLock, NumLock, PrintScreen,
Pause, ContextMenu,
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MouseButton {
Left,
Right,
Middle,
Button4,
Button5,
}
#[derive(Debug, Clone)]
pub struct MouseState {
pub position: Vec2,
pub drag_start: Option<Vec2>,
pub delta: Vec2,
pub scroll: Vec2,
pub held: std::collections::HashSet<MouseButton>,
pub pressed_this_frame: Vec<MouseButton>,
pub released_this_frame: Vec<MouseButton>,
pub cursor_visible: bool,
pub cursor_grabbed: bool,
}
impl Default for MouseState {
fn default() -> Self {
Self {
position: Vec2::ZERO,
drag_start: None,
delta: Vec2::ZERO,
scroll: Vec2::ZERO,
held: std::collections::HashSet::new(),
pressed_this_frame: Vec::new(),
released_this_frame: Vec::new(),
cursor_visible: true,
cursor_grabbed: false,
}
}
}
impl MouseState {
pub fn is_down(&self, button: MouseButton) -> bool {
self.held.contains(&button)
}
pub fn is_pressed(&self, button: MouseButton) -> bool {
self.pressed_this_frame.contains(&button)
}
pub fn is_released(&self, button: MouseButton) -> bool {
self.released_this_frame.contains(&button)
}
pub fn is_any_down(&self) -> bool {
!self.held.is_empty()
}
pub fn is_dragging(&self) -> bool {
self.held.contains(&MouseButton::Left) && self.drag_start.is_some()
}
pub fn drag_vector(&self) -> Option<Vec2> {
self.drag_start.map(|start| self.position - start)
}
pub fn set_cursor_visible(&mut self, visible: bool) {
self.cursor_visible = visible;
}
pub fn set_cursor_grabbed(&mut self, grabbed: bool) {
self.cursor_grabbed = grabbed;
}
}
#[derive(Debug, Clone)]
pub struct KeyboardState {
held: std::collections::HashSet<KeyCode>,
pub pressed_this_frame: Vec<KeyCode>,
pub released_this_frame: Vec<KeyCode>,
text_buffer: String,
}
impl Default for KeyboardState {
fn default() -> Self {
Self {
held: std::collections::HashSet::new(),
pressed_this_frame: Vec::new(),
released_this_frame: Vec::new(),
text_buffer: String::new(),
}
}
}
impl KeyboardState {
#[inline]
pub fn is_down(&self, key: KeyCode) -> bool {
self.held.contains(&key)
}
#[inline]
pub fn is_pressed(&self, key: KeyCode) -> bool {
self.pressed_this_frame.contains(&key)
}
#[inline]
pub fn is_released(&self, key: KeyCode) -> bool {
self.released_this_frame.contains(&key)
}
pub fn are_all_down(&self, keys: &[KeyCode]) -> bool {
keys.iter().all(|k| self.held.contains(k))
}
pub fn is_any_down(&self, keys: &[KeyCode]) -> bool {
keys.iter().any(|k| self.held.contains(k))
}
pub fn take_text(&mut self) -> String {
std::mem::take(&mut self.text_buffer)
}
pub fn text(&self) -> &str {
&self.text_buffer
}
}
#[derive(Debug, Clone)]
pub struct InputAction {
pub name: String,
pub keys: Vec<KeyCode>,
pub mouse_buttons: Vec<MouseButton>,
pub positive_axis: Vec<(u32, f32)>,
pub negative_axis: Vec<(u32, f32)>,
pub gamepad_buttons: Vec<u32>,
}
impl InputAction {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
keys: Vec::new(),
mouse_buttons: Vec::new(),
positive_axis: Vec::new(),
negative_axis: Vec::new(),
gamepad_buttons: Vec::new(),
}
}
pub fn bind_key(&mut self, key: KeyCode) -> &mut Self {
self.keys.push(key);
self
}
pub fn bind_mouse(&mut self, button: MouseButton) -> &mut Self {
self.mouse_buttons.push(button);
self
}
pub fn is_down(&self, input: &InputState) -> bool {
for key in &self.keys {
if input.keyboard.is_down(*key) {
return true;
}
}
for btn in &self.mouse_buttons {
if input.mouse.is_down(*btn) {
return true;
}
}
false
}
pub fn is_pressed(&self, input: &InputState) -> bool {
for key in &self.keys {
if input.keyboard.is_pressed(*key) {
return true;
}
}
for btn in &self.mouse_buttons {
if input.mouse.is_pressed(*btn) {
return true;
}
}
false
}
}
#[derive(Debug, Clone, Default)]
pub struct InputState {
pub keyboard: KeyboardState,
pub mouse: MouseState,
actions: Vec<InputAction>,
}
impl InputState {
pub fn register_action(&mut self, action: InputAction) {
self.actions.push(action);
}
pub fn action(&self, name: &str) -> Option<&InputAction> {
self.actions.iter().find(|a| a.name == name)
}
pub fn is_action_down(&self, name: &str) -> bool {
self.actions.iter().any(|a| a.name == name && a.is_down(self))
}
pub fn is_action_pressed(&self, name: &str) -> bool {
self.actions.iter().any(|a| a.name == name && a.is_pressed(self))
}
}