frenderer/
input.rs

1//! A wrapper for a current and previous input button/mouse state.
2
3pub use winit::dpi::PhysicalPosition as MousePos;
4use winit::event::{ElementState, Event, MouseButton, WindowEvent};
5pub use winit::keyboard::KeyCode as Key;
6
7/// `Input` wraps a current and previous input state.  When window
8/// events arrive from [`winit`], you should call
9/// [`Input::process_input_event()`]; later (e.g. when handling
10/// [`winit::event::Event::AboutToWait`] and simulating a single game
11/// step), you can make queries like [`Input::is_key_down()`], and
12/// when you've finished processing events for a frame you can call
13/// [`Input::next_frame()`] to cycle the new state to the old state.
14pub struct Input {
15    now_keys: Vec<Key>,
16    prev_keys: Vec<Key>,
17    now_mouse: Vec<MouseButton>,
18    prev_mouse: Vec<MouseButton>,
19    now_mouse_pos: MousePos<f64>,
20    prev_mouse_pos: MousePos<f64>,
21}
22impl Default for Input {
23    fn default() -> Self {
24        Self {
25            now_keys: vec![],
26            prev_keys: vec![],
27            now_mouse: vec![],
28            prev_mouse: vec![],
29            now_mouse_pos: MousePos { x: 0.0, y: 0.0 },
30            prev_mouse_pos: MousePos { x: 0.0, y: 0.0 },
31        }
32    }
33}
34#[allow(dead_code)]
35impl Input {
36    /// Process a [`winit`] event and update the current keys/mouse position.
37    pub fn process_input_event<T>(&mut self, ev: &Event<T>) {
38        match ev {
39            // WindowEvent->KeyboardInput: Keyboard input!
40            Event::WindowEvent {
41                // Note this deeply nested pattern match
42                event: WindowEvent::KeyboardInput { event: key_ev, .. },
43                ..
44            } => {
45                self.handle_key_event(key_ev);
46            }
47            Event::WindowEvent {
48                event: WindowEvent::MouseInput { state, button, .. },
49                ..
50            } => {
51                self.handle_mouse_button(*state, *button);
52            }
53            Event::WindowEvent {
54                event: WindowEvent::CursorMoved { position, .. },
55                ..
56            } => {
57                self.handle_mouse_move(*position);
58            }
59            _ => (),
60        }
61    }
62    /// Is this key currently down?
63    pub fn is_key_down(&self, kc: Key) -> bool {
64        self.now_keys.contains(&kc)
65    }
66    /// Is this key currently up?
67    pub fn is_key_up(&self, kc: Key) -> bool {
68        !self.now_keys.contains(&kc)
69    }
70    /// Was this key just pressed on this frame?
71    pub fn is_key_pressed(&self, kc: Key) -> bool {
72        self.now_keys.contains(&kc) && !self.prev_keys.contains(&kc)
73    }
74    /// Was this key just released on this frame?
75    pub fn is_key_released(&self, kc: Key) -> bool {
76        !self.now_keys.contains(&kc) && self.prev_keys.contains(&kc)
77    }
78    /// Is this mouse button currently held?
79    pub fn is_mouse_down(&self, button: MouseButton) -> bool {
80        self.now_mouse.contains(&button)
81    }
82    /// Is this mouse button currently up?
83    pub fn is_mouse_up(&self, mb: MouseButton) -> bool {
84        !self.now_mouse.contains(&mb)
85    }
86    /// Was this mouse button just pressed this frame?
87    pub fn is_mouse_pressed(&self, mb: MouseButton) -> bool {
88        self.now_mouse.contains(&mb) && !self.prev_mouse.contains(&mb)
89    }
90    /// Was this mouse button just released this frame?
91    pub fn is_mouse_released(&self, mb: MouseButton) -> bool {
92        !self.now_mouse.contains(&mb) && self.prev_mouse.contains(&mb)
93    }
94    /// Where is the mouse right now?
95    pub fn mouse_pos(&self) -> MousePos<f64> {
96        self.now_mouse_pos
97    }
98    /// How much has the mouse moved this frame?
99    pub fn mouse_delta(&self) -> MousePos<f64> {
100        MousePos {
101            x: self.now_mouse_pos.x - self.prev_mouse_pos.x,
102            y: self.now_mouse_pos.y - self.prev_mouse_pos.y,
103        }
104    }
105    /// Given two keys (a negative and positive direction), produce a
106    /// value between -1 and 1 based on which are currently held.
107    pub fn key_axis(&self, down: Key, up: Key) -> f32 {
108        (if self.is_key_down(down) { -1.0 } else { 0.0 })
109            + (if self.is_key_down(up) { 1.0 } else { 0.0 })
110    }
111    /// Cycle current state to previous state.
112    pub fn next_frame(&mut self) {
113        self.prev_keys.clear();
114        self.prev_keys.extend_from_slice(&self.now_keys);
115        self.prev_mouse.clear();
116        self.prev_mouse.extend_from_slice(&self.now_mouse);
117
118        self.prev_mouse_pos = self.now_mouse_pos;
119    }
120    fn handle_key_event(&mut self, ke: &winit::event::KeyEvent) {
121        if let winit::event::KeyEvent {
122            physical_key: winit::keyboard::PhysicalKey::Code(keycode),
123            state,
124            ..
125        } = ke
126        {
127            match state {
128                winit::event::ElementState::Pressed => {
129                    if !self.now_keys.contains(keycode) {
130                        self.now_keys.push(*keycode);
131                    }
132                }
133                winit::event::ElementState::Released => {
134                    if let Some(idx) = self.now_keys.iter().position(|k| k == keycode) {
135                        self.now_keys.swap_remove(idx);
136                    }
137                }
138            }
139        }
140    }
141    fn handle_mouse_button(&mut self, state: ElementState, button: MouseButton) {
142        match state {
143            ElementState::Pressed => {
144                if !self.now_mouse.contains(&button) {
145                    self.now_mouse.push(button);
146                }
147            }
148            ElementState::Released => {
149                if let Some(idx) = self.now_mouse.iter().position(|m| *m == button) {
150                    self.now_mouse.swap_remove(idx);
151                }
152            }
153        }
154    }
155    fn handle_mouse_move(&mut self, position: MousePos<f64>) {
156        self.now_mouse_pos = position;
157    }
158}