Skip to main content

volition/
lib.rs

1/*!
2    Minimalist input lib based on [winit](https://github.com/tomaka/winit).
3*/
4
5#![deny(missing_docs)]
6
7use winit::dpi::PhysicalPosition;
8use winit::event::DeviceEvent::MouseMotion;
9use winit::event::ElementState::{Pressed, Released};
10use winit::event::Event::{self, DeviceEvent, WindowEvent};
11use winit::event::KeyboardInput;
12pub use winit::event::MouseButton;
13use winit::event::MouseScrollDelta;
14pub use winit::event::VirtualKeyCode as Key;
15use winit::event::WindowEvent::KeyboardInput as WKeyboardInput;
16use winit::event::WindowEvent::{
17    AxisMotion, CursorMoved, MouseInput, MouseWheel, ReceivedCharacter,
18};
19use winit::window::Window;
20
21/// struct for abstracting the state for all the inputs
22pub struct Input {
23    /// The position of the mouse
24    pub mouse_pos: (f32, f32),
25    /// The difference in mouse position from the last frame
26    pub mouse_delta: (f32, f32),
27    /// The raw difference in mouse position from the last frame
28    pub raw_mouse_delta: (f32, f32),
29    /// The mouse axis motion for the last frame
30    pub mouse_axis_motion: (f32, f32),
31    /// The difference in position of the mouse when from the previous frame
32    pub mouse_wheel_delta: (f32, f32),
33    /// The keys that are currently pressed down
34    pub keys_down: Vec<Key>,
35    /// The keys that have been pressed on this frame
36    pub keys_pressed: Vec<Key>,
37    /// The keys that have been released on this frame
38    pub keys_released: Vec<Key>,
39    /// Characters received that are pressed down
40    pub characters_down: Vec<char>,
41    /// The mouse buttons that are currently pressed down
42    pub mouse_btns_down: Vec<MouseButton>,
43    /// The mouse buttons that have been pressed down on this frame
44    pub mouse_btns_pressed: Vec<MouseButton>,
45    /// The mouse buttons that have been release on this frame
46    pub mouse_btns_released: Vec<MouseButton>,
47    /// Whether to show or hide the mouse
48    pub hide_mouse: bool,
49}
50
51impl Default for Input {
52    /// Create a default instance of Input
53    fn default() -> Self {
54        Self::new()
55    }
56}
57
58impl Input {
59    /// Creates a new Input instance
60    pub fn new() -> Input {
61        Input {
62            mouse_pos: (0f32, 0f32),
63            mouse_delta: (0f32, 0f32),
64            raw_mouse_delta: (0f32, 0f32),
65            mouse_axis_motion: (0f32, 0f32),
66            mouse_wheel_delta: (0f32, 0f32),
67            keys_down: Vec::new(),
68            keys_pressed: Vec::new(),
69            keys_released: Vec::new(),
70            characters_down: Vec::new(),
71            mouse_btns_down: Vec::new(),
72            mouse_btns_pressed: Vec::new(),
73            mouse_btns_released: Vec::new(),
74            hide_mouse: true,
75        }
76    }
77
78    /// This method updates the state of the inputs
79    pub fn update_inputs(&mut self, window: &Window, events: &Vec<Event<()>>) {
80        let (width, height): (u32, u32) = window.inner_size().into();
81        let h_width = (width as u32 / 2u32) as f32;
82        let h_height = (height / 2u32) as f32;
83
84        // reset properties
85        {
86            // reset the delta in case the mouse does not move
87            self.mouse_delta = (0f32, 0f32);
88            self.mouse_wheel_delta = (0f32, 0f32);
89
90           // keys pressed is only for a single frame so clear
91            self.keys_pressed.clear();
92            self.keys_released.clear();
93            self.mouse_btns_pressed.clear();
94            self.mouse_btns_released.clear();
95            self.characters_down.clear();
96        }
97
98        let keys_down = &mut self.keys_down;
99        let keys_pressed = &mut self.keys_pressed;
100        let keys_released = &mut self.keys_released;
101        let mouse_delta = &mut self.mouse_delta;
102        let raw_mouse_delta = &mut self.raw_mouse_delta;
103        let mouse_axis_motion = &mut self.mouse_axis_motion;
104        let mouse_pos = &mut self.mouse_pos;
105        let mouse_btns_down = &mut self.mouse_btns_down;
106        let mouse_btns_pressed = &mut self.mouse_btns_pressed;
107        let mouse_btns_released = &mut self.mouse_btns_released;
108        let mouse_wheel_delta = &mut self.mouse_wheel_delta;
109        let characters_down = &mut self.characters_down;
110
111        // polling and handling the events received by the display
112        for event in events {
113            match event {
114                WindowEvent { event, .. } => match event {
115                    WKeyboardInput {
116                        input:
117                            KeyboardInput {
118                                state: Pressed,
119                                virtual_keycode: vkey,
120                                ..
121                            },
122                        ..
123                    } => {
124                        if let Some(key) = vkey {
125                            keys_down.push(*key);
126                            keys_pressed.push(*key);
127                        }
128                    }
129                    WKeyboardInput {
130                        input:
131                            KeyboardInput {
132                                state: Released,
133                                virtual_keycode: vkey,
134                                ..
135                            },
136                        ..
137                    } => {
138                        if let Some(key) = vkey {
139                            keys_down.retain(|&k| k != *key);
140                            keys_released.push(*key);
141                        }
142                    }
143                    CursorMoved { position: pos, .. } => {
144                        let (x, y): (i32, i32) = (*pos).into();
145                        mouse_delta.0 = (h_width - x as f32) / width as f32;
146                        mouse_delta.1 = (h_height - y as f32) / height as f32;
147                        (*mouse_pos) = (x as f32, y as f32);
148                    }
149                    AxisMotion { axis, value, .. } => match axis {
150                        0 => mouse_axis_motion.0 = *value as f32,
151                        1 => mouse_axis_motion.1 = *value as f32,
152                        _ => {}
153                    },
154                    MouseInput {
155                        state: Pressed,
156                        button: btn,
157                        ..
158                    } => {
159                        mouse_btns_down.push(*btn);
160                        mouse_btns_pressed.push(*btn);
161                    }
162                    MouseInput {
163                        state: Released,
164                        button: btn,
165                        ..
166                    } => {
167                        mouse_btns_down.retain(|&mb| mb != *btn);
168                        mouse_btns_released.push(*btn);
169                    }
170                    MouseWheel { delta, .. } => {
171                        (*mouse_wheel_delta) = match delta {
172                            MouseScrollDelta::LineDelta(x, y) => (*x, *y),
173                            MouseScrollDelta::PixelDelta(pos) => {
174                                let (x, y): (i32, i32) = (*pos).into();
175                                (x as f32, y as f32)
176                            }
177                        };
178                    }
179                    ReceivedCharacter(c) => characters_down.push(*c),
180                    _ => (),
181                },
182                DeviceEvent { event, .. } => {
183                    if let MouseMotion { delta } = event {
184                        (*raw_mouse_delta) = (delta.0 as f32, delta.1 as f32);
185                    }
186                }
187                _ => (),
188            }
189        }
190
191        if self.hide_mouse {
192            window.set_cursor_visible(false);
193            window.set_cursor_grab(true).unwrap();
194            let _ = window.set_cursor_position(PhysicalPosition::new(h_width, h_height));
195        } else {
196            window.set_cursor_visible(true);
197            window.set_cursor_grab(false).unwrap();
198        }
199    }
200}