Skip to main content

fyrox_impl/engine/
input.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! This module contains a set of "shortcuts" that allows getting the state of a mouse and a keyboard
22//! in a simplified manner (read - without using "verbose" event-based approach). It may be useful
23//! in simple scenarios where you just need to know if a button (on keyboard, mouse) was pressed
24//! and do something. You should always prefer the event-based approach when possible.
25
26use fxhash::{FxHashMap, FxHashSet};
27use fyrox_core::algebra::Vector2;
28use winit::event::{ButtonId, ElementState};
29use winit::keyboard::{KeyCode, PhysicalKey};
30
31/// Represents the mouse state in the current frame. The contents of this structure is a simplified
32/// version of event-based approach. **Important:** this structure does not track from which mouse the
33/// corresponding event has come from, if you have more than one mouse use event-based approach
34/// instead!
35#[derive(Default, Clone)]
36pub struct Mouse {
37    /// Coordinates in pixels relative to the top-left corner of the window.
38    pub position: Vector2<f32>,
39    /// Speed of the mouse in some units.
40    pub speed: Vector2<f32>,
41    /// Physical state of mouse buttons. Usually, the button indices are the following:
42    ///
43    /// - 0 - left mouse button
44    /// - 1 - right mouse button
45    /// - 2 - middle mouse button
46    /// - 3 - additional mouse button (could back or forward)
47    /// - 4 - additional mouse button (could back or forward)
48    /// - 5 and higher - device-specific buttons
49    ///
50    /// There are named constants for the tree most used ones - [`Mouse::LEFT_BUTTON`],
51    /// [`Mouse::RIGHT_BUTTON`], [`Mouse::MIDDLE_BUTTON`].
52    pub buttons_state: FxHashMap<ButtonId, ElementState>,
53    /// A hash set that contains all the buttons that were pressed in the current frame. If a button
54    /// is still pressed in the next frame, this hash map will not contain it. This is useful
55    /// to check if a button was pressed and some action, but do not repeat the same action over and
56    /// over until the button is released.
57    pub pressed_buttons: FxHashSet<ButtonId>,
58    /// A hash set that contains all the buttons that were released in the current frame. If a button
59    /// is still released in the next frame, this hash map will not contain it. This is useful
60    /// to check if a button was released and some action, but do not repeat the same action over and
61    /// over until the button is pressed.
62    pub released_buttons: FxHashSet<ButtonId>,
63}
64
65impl Mouse {
66    /// Index of the left button.
67    pub const LEFT_BUTTON: ButtonId = 0;
68    /// Index of the right button.
69    pub const RIGHT_BUTTON: ButtonId = 1;
70    /// Index of the middle button.
71    pub const MIDDLE_BUTTON: ButtonId = 2;
72}
73
74/// Represents the keyboard state in the current frame. The contents of this structure is a simplified
75/// version of event-based approach. **Important:** this structure does not track from which keyboard the
76/// corresponding event has come from, if you have more than one keyboard use event-based approach
77/// instead!
78#[derive(Default, Clone)]
79pub struct Keyboard {
80    /// Represents the keyboard state in the current frame.
81    pub keys: FxHashMap<PhysicalKey, ElementState>,
82    /// A hash set that contains all the keys that were pressed in the current frame. If a key
83    /// is still pressed in the next frame, this hash map will not contain it. This is useful
84    /// to check if a key was pressed and some action, but do not repeat the same action over and
85    /// over until the key is released.
86    pub pressed_keys: FxHashSet<PhysicalKey>,
87    /// A hash set that contains all the keys that were released in the current frame. If a key
88    /// is still released in the next frame, this hash map will not contain it. This is useful
89    /// to check if a key was released and some action, but do not repeat the same action over and
90    /// over until the key is pressed.
91    pub released_keys: FxHashSet<PhysicalKey>,
92}
93
94/// A stored state of most common input events. It is used a "shortcut" in cases where event-based
95/// approach is too verbose. **Important:** this structure does not track from which device the
96/// corresponding event has come from, if you have more than one keyboard and/or mouse, use
97/// event-based approach instead! You should always prefer the event-based approach when possible.
98#[derive(Default, Clone)]
99pub struct InputState {
100    /// Represents the mouse state in the current frame.
101    pub mouse: Mouse,
102    /// Represents the keyboard state in the current frame.
103    pub keyboard: Keyboard,
104}
105
106impl InputState {
107    /// Returns `true` if the specified key is pressed, `false` - otherwise.
108    #[inline]
109    pub fn is_key_down(&self, key: KeyCode) -> bool {
110        self.keyboard
111            .keys
112            .get(&PhysicalKey::Code(key))
113            .is_some_and(|state| *state == ElementState::Pressed)
114    }
115
116    /// Returns `true` if the specified key was pressed in the current frame, `false` - otherwise.
117    /// This method will return `false` if the key is still pressed in the next frame. This is
118    /// useful to check if a key was pressed and some action, but do not repeat the same action
119    /// over and over until the key is released.
120    #[inline]
121    pub fn is_key_pressed(&self, key: KeyCode) -> bool {
122        self.keyboard.pressed_keys.contains(&PhysicalKey::Code(key))
123    }
124
125    /// Returns `true` if the specified key was released in the current frame, `false` - otherwise.
126    /// This method will return `false` if the key is still released in the next frame. This is
127    /// useful to check if a key was released and some action, but do not repeat the same action
128    /// over and over until the key is pressed.
129    #[inline]
130    pub fn is_key_released(&self, key: KeyCode) -> bool {
131        self.keyboard
132            .released_keys
133            .contains(&PhysicalKey::Code(key))
134    }
135
136    /// Returns `true` if the specified mouse button is pressed, `false` - otherwise. Usually,
137    /// the button indices are the following:
138    ///
139    /// - 0 - left mouse button
140    /// - 1 - right mouse button
141    /// - 2 - middle mouse button
142    /// - 3 - additional mouse button (could back or forward)
143    /// - 4 - additional mouse button (could back or forward)
144    /// - 5 and higher - device-specific buttons
145    ///
146    /// There are named constants for the tree most used ones - [`Mouse::LEFT_BUTTON`],
147    /// [`Mouse::RIGHT_BUTTON`], [`Mouse::MIDDLE_BUTTON`].
148    #[inline]
149    pub fn is_mouse_button_down(&self, button_id: ButtonId) -> bool {
150        self.mouse
151            .buttons_state
152            .get(&button_id)
153            .is_some_and(|state| *state == ElementState::Pressed)
154    }
155
156    /// Returns `true` if the specified button was pressed in the current frame, `false` - otherwise.
157    /// This method will return `false` if the button is still pressed in the next frame. This is
158    /// useful to check if a button was pressed and some action, but do not repeat the same action
159    /// over and over until the button is released. See the docs of [`Self::is_mouse_button_down`]
160    /// for button ids.
161    #[inline]
162    pub fn is_mouse_button_pressed(&self, button_id: ButtonId) -> bool {
163        self.mouse.pressed_buttons.contains(&button_id)
164    }
165
166    /// Returns `true` if the specified button was released in the current frame, `false` - otherwise.
167    /// This method will return `false` if the button is still released in the next frame. This is
168    /// useful to check if a button was released and some action, but do not repeat the same action
169    /// over and over until the button is pressed. See the docs of [`Self::is_mouse_button_down`]
170    /// for button ids.
171    #[inline]
172    pub fn is_mouse_button_released(&self, button_id: ButtonId) -> bool {
173        self.mouse.released_buttons.contains(&button_id)
174    }
175
176    /// Returns `true` if the left mouse button is pressed, `false` - otherwise.
177    #[inline]
178    pub fn is_left_mouse_button_down(&self) -> bool {
179        self.is_mouse_button_down(Mouse::LEFT_BUTTON)
180    }
181
182    /// Returns `true` if the right mouse button is pressed, `false` - otherwise.
183    #[inline]
184    pub fn is_right_mouse_button_down(&self) -> bool {
185        self.is_mouse_button_down(Mouse::RIGHT_BUTTON)
186    }
187
188    /// Returns `true` if the middle mouse button pressed is pressed, `false` - otherwise.
189    #[inline]
190    pub fn is_middle_mouse_button_down(&self) -> bool {
191        self.is_mouse_button_down(Mouse::MIDDLE_BUTTON)
192    }
193
194    /// Returns `true` if the left mouse button was pressed on the current frame,
195    /// `false` - otherwise.
196    #[inline]
197    pub fn is_left_mouse_button_pressed(&self) -> bool {
198        self.is_mouse_button_pressed(Mouse::LEFT_BUTTON)
199    }
200
201    /// Returns `true` if the right mouse button was pressed on the current frame,
202    /// `false` - otherwise.
203    #[inline]
204    pub fn is_right_mouse_button_pressed(&self) -> bool {
205        self.is_mouse_button_pressed(Mouse::RIGHT_BUTTON)
206    }
207
208    /// Returns `true` if the middle mouse button was pressed on the current frame,
209    /// `false` - otherwise.
210    #[inline]
211    pub fn is_middle_mouse_button_pressed(&self) -> bool {
212        self.is_mouse_button_pressed(Mouse::MIDDLE_BUTTON)
213    }
214
215    /// Returns `true` if the left mouse button was released on the current frame,
216    /// `false` - otherwise.
217    #[inline]
218    pub fn is_left_mouse_button_released(&self) -> bool {
219        self.is_mouse_button_released(Mouse::LEFT_BUTTON)
220    }
221
222    /// Returns `true` if the right mouse button was released on the current frame,
223    /// `false` - otherwise.
224    #[inline]
225    pub fn is_right_mouse_button_released(&self) -> bool {
226        self.is_mouse_button_released(Mouse::RIGHT_BUTTON)
227    }
228
229    /// Returns `true` if the middle mouse button was released on the current frame,
230    /// `false` - otherwise.
231    #[inline]
232    pub fn is_middle_mouse_button_released(&self) -> bool {
233        self.is_mouse_button_released(Mouse::MIDDLE_BUTTON)
234    }
235
236    /// Returns mouse speed in the current frame, the speed expressed in some arbitrary units.
237    #[inline]
238    pub fn mouse_speed(&self) -> Vector2<f32> {
239        self.mouse.speed
240    }
241
242    /// Returns mouse position in pixels relative to the top-left corner of the main window.
243    #[inline]
244    pub fn mouse_position(&self) -> Vector2<f32> {
245        self.mouse.position
246    }
247}