bevy_input/
button_input.rs

1//! The generic input type.
2
3use bevy_ecs::system::Resource;
4use bevy_utils::HashSet;
5use core::hash::Hash;
6#[cfg(feature = "bevy_reflect")]
7use {
8    bevy_ecs::reflect::ReflectResource,
9    bevy_reflect::{std_traits::ReflectDefault, Reflect},
10};
11
12/// A "press-able" input of type `T`.
13///
14/// ## Usage
15///
16/// This type can be used as a resource to keep the current state of an input, by reacting to
17/// events from the input. For a given input value:
18///
19/// * [`ButtonInput::pressed`] will return `true` between a press and a release event.
20/// * [`ButtonInput::just_pressed`] will return `true` for one frame after a press event.
21/// * [`ButtonInput::just_released`] will return `true` for one frame after a release event.
22///
23/// ## Multiple systems
24///
25/// In case multiple systems are checking for [`ButtonInput::just_pressed`] or [`ButtonInput::just_released`]
26/// but only one should react, for example when modifying a
27/// [`Resource`], you should consider clearing the input state, either by:
28///
29/// * Using [`ButtonInput::clear_just_pressed`] or [`ButtonInput::clear_just_released`] instead.
30/// * Calling [`ButtonInput::clear`] or [`ButtonInput::reset`] immediately after the state change.
31///
32/// ## Performance
33///
34/// For all operations, the following conventions are used:
35/// - **n** is the number of stored inputs.
36/// - **m** is the number of input arguments passed to the method.
37/// - **\***-suffix denotes an amortized cost.
38/// - **~**-suffix denotes an expected cost.
39///
40/// See Rust's [std::collections doc on performance](https://doc.rust-lang.org/std/collections/index.html#performance) for more details on the conventions used here.
41///
42/// | **[`ButtonInput`] operations**          | **Computational complexity** |
43/// |-----------------------------------|------------------------------------|
44/// | [`ButtonInput::any_just_pressed`]       | *O*(m)~                      |
45/// | [`ButtonInput::any_just_released`]      | *O*(m)~                      |
46/// | [`ButtonInput::any_pressed`]            | *O*(m)~                      |
47/// | [`ButtonInput::get_just_pressed`]       | *O*(n)                       |
48/// | [`ButtonInput::get_just_released`]      | *O*(n)                       |
49/// | [`ButtonInput::get_pressed`]            | *O*(n)                       |
50/// | [`ButtonInput::just_pressed`]           | *O*(1)~                      |
51/// | [`ButtonInput::just_released`]          | *O*(1)~                      |
52/// | [`ButtonInput::pressed`]                | *O*(1)~                      |
53/// | [`ButtonInput::press`]                  | *O*(1)~*                     |
54/// | [`ButtonInput::release`]                | *O*(1)~*                     |
55/// | [`ButtonInput::release_all`]            | *O*(n)~*                     |
56/// | [`ButtonInput::clear_just_pressed`]     | *O*(1)~                      |
57/// | [`ButtonInput::clear_just_released`]    | *O*(1)~                      |
58/// | [`ButtonInput::reset_all`]              | *O*(n)                       |
59/// | [`ButtonInput::clear`]                  | *O*(n)                       |
60///
61/// ## Window focus
62///
63/// `ButtonInput<KeyCode>` is tied to window focus. For example, if the user holds a button
64/// while the window loses focus, [`ButtonInput::just_released`] will be triggered. Similarly if the window
65/// regains focus, [`ButtonInput::just_pressed`] will be triggered.
66///
67/// `ButtonInput<GamepadButton>` is independent of window focus.
68///
69/// ## Examples
70///
71/// Reading and checking against the current set of pressed buttons:
72/// ```no_run
73/// # use bevy_app::{App, NoopPluginGroup as DefaultPlugins, Update};
74/// # use bevy_ecs::{prelude::{IntoSystemConfigs, Res, Resource, resource_changed}, schedule::Condition};
75/// # use bevy_input::{ButtonInput, prelude::{KeyCode, MouseButton}};
76///
77/// fn main() {
78///     App::new()
79///         .add_plugins(DefaultPlugins)
80///         .add_systems(
81///             Update,
82///             print_mouse.run_if(resource_changed::<ButtonInput<MouseButton>>),
83///         )
84///         .add_systems(
85///             Update,
86///             print_keyboard.run_if(resource_changed::<ButtonInput<KeyCode>>),
87///         )
88///         .run();
89/// }
90///
91/// fn print_mouse(mouse: Res<ButtonInput<MouseButton>>) {
92///     println!("Mouse: {:?}", mouse.get_pressed().collect::<Vec<_>>());
93/// }
94///
95/// fn print_keyboard(keyboard: Res<ButtonInput<KeyCode>>) {
96///     if keyboard.any_pressed([KeyCode::ControlLeft, KeyCode::ControlRight])
97///         && keyboard.any_pressed([KeyCode::AltLeft, KeyCode::AltRight])
98///         && keyboard.any_pressed([KeyCode::ShiftLeft, KeyCode::ShiftRight])
99///         && keyboard.any_pressed([KeyCode::SuperLeft, KeyCode::SuperRight])
100///         && keyboard.pressed(KeyCode::KeyL)
101///     {
102///         println!("On Windows this opens LinkedIn.");
103///     } else {
104///         println!("keyboard: {:?}", keyboard.get_pressed().collect::<Vec<_>>());
105///     }
106/// }
107/// ```
108///
109/// ## Note
110///
111/// When adding this resource for a new input type, you should:
112///
113/// * Call the [`ButtonInput::press`] method for each press event.
114/// * Call the [`ButtonInput::release`] method for each release event.
115/// * Call the [`ButtonInput::clear`] method at each frame start, before processing events.
116///
117/// Note: Calling `clear` from a [`ResMut`] will trigger change detection.
118/// It may be preferable to use [`DetectChangesMut::bypass_change_detection`]
119/// to avoid causing the resource to always be marked as changed.
120///
121/// [`ResMut`]: bevy_ecs::system::ResMut
122/// [`DetectChangesMut::bypass_change_detection`]: bevy_ecs::change_detection::DetectChangesMut::bypass_change_detection
123#[derive(Debug, Clone, Resource)]
124#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Default, Resource))]
125pub struct ButtonInput<T: Copy + Eq + Hash + Send + Sync + 'static> {
126    /// A collection of every button that is currently being pressed.
127    pressed: HashSet<T>,
128    /// A collection of every button that has just been pressed.
129    just_pressed: HashSet<T>,
130    /// A collection of every button that has just been released.
131    just_released: HashSet<T>,
132}
133
134impl<T: Copy + Eq + Hash + Send + Sync + 'static> Default for ButtonInput<T> {
135    fn default() -> Self {
136        Self {
137            pressed: Default::default(),
138            just_pressed: Default::default(),
139            just_released: Default::default(),
140        }
141    }
142}
143
144impl<T> ButtonInput<T>
145where
146    T: Copy + Eq + Hash + Send + Sync + 'static,
147{
148    /// Registers a press for the given `input`.
149    pub fn press(&mut self, input: T) {
150        // Returns `true` if the `input` wasn't pressed.
151        if self.pressed.insert(input) {
152            self.just_pressed.insert(input);
153        }
154    }
155
156    /// Returns `true` if the `input` has been pressed.
157    pub fn pressed(&self, input: T) -> bool {
158        self.pressed.contains(&input)
159    }
160
161    /// Returns `true` if any item in `inputs` has been pressed.
162    pub fn any_pressed(&self, inputs: impl IntoIterator<Item = T>) -> bool {
163        inputs.into_iter().any(|it| self.pressed(it))
164    }
165
166    /// Returns `true` if all items in `inputs` have been pressed.
167    pub fn all_pressed(&self, inputs: impl IntoIterator<Item = T>) -> bool {
168        inputs.into_iter().all(|it| self.pressed(it))
169    }
170
171    /// Registers a release for the given `input`.
172    pub fn release(&mut self, input: T) {
173        // Returns `true` if the `input` was pressed.
174        if self.pressed.remove(&input) {
175            self.just_released.insert(input);
176        }
177    }
178
179    /// Registers a release for all currently pressed inputs.
180    pub fn release_all(&mut self) {
181        // Move all items from pressed into just_released
182        self.just_released.extend(self.pressed.drain());
183    }
184
185    /// Returns `true` if the `input` has been pressed during the current frame.
186    ///
187    /// Note: This function does not imply information regarding the current state of [`ButtonInput::pressed`] or [`ButtonInput::just_released`].
188    pub fn just_pressed(&self, input: T) -> bool {
189        self.just_pressed.contains(&input)
190    }
191
192    /// Returns `true` if any item in `inputs` has been pressed during the current frame.
193    pub fn any_just_pressed(&self, inputs: impl IntoIterator<Item = T>) -> bool {
194        inputs.into_iter().any(|it| self.just_pressed(it))
195    }
196
197    /// Clears the `just_pressed` state of the `input` and returns `true` if the `input` has just been pressed.
198    ///
199    /// Future calls to [`ButtonInput::just_pressed`] for the given input will return false until a new press event occurs.
200    pub fn clear_just_pressed(&mut self, input: T) -> bool {
201        self.just_pressed.remove(&input)
202    }
203
204    /// Returns `true` if the `input` has been released during the current frame.
205    ///
206    /// Note: This function does not imply information regarding the current state of [`ButtonInput::pressed`] or [`ButtonInput::just_pressed`].
207    pub fn just_released(&self, input: T) -> bool {
208        self.just_released.contains(&input)
209    }
210
211    /// Returns `true` if any item in `inputs` has just been released.
212    pub fn any_just_released(&self, inputs: impl IntoIterator<Item = T>) -> bool {
213        inputs.into_iter().any(|input| self.just_released(input))
214    }
215
216    /// Returns `true` if all items in `inputs` have just been released.
217    pub fn all_just_released(&self, inputs: impl IntoIterator<Item = T>) -> bool {
218        inputs.into_iter().all(|input| self.just_released(input))
219    }
220
221    /// Returns `true` if all items in `inputs` have been just pressed.
222    pub fn all_just_pressed(&self, inputs: impl IntoIterator<Item = T>) -> bool {
223        inputs.into_iter().all(|input| self.just_pressed(input))
224    }
225
226    /// Clears the `just_released` state of the `input` and returns `true` if the `input` has just been released.
227    ///
228    /// Future calls to [`ButtonInput::just_released`] for the given input will return false until a new release event occurs.
229    pub fn clear_just_released(&mut self, input: T) -> bool {
230        self.just_released.remove(&input)
231    }
232
233    /// Clears the `pressed`, `just_pressed` and `just_released` data of the `input`.
234    pub fn reset(&mut self, input: T) {
235        self.pressed.remove(&input);
236        self.just_pressed.remove(&input);
237        self.just_released.remove(&input);
238    }
239
240    /// Clears the `pressed`, `just_pressed`, and `just_released` data for every input.
241    ///
242    /// See also [`ButtonInput::clear`] for simulating elapsed time steps.
243    pub fn reset_all(&mut self) {
244        self.pressed.clear();
245        self.just_pressed.clear();
246        self.just_released.clear();
247    }
248
249    /// Clears the `just pressed` and `just released` data for every input.
250    ///
251    /// See also [`ButtonInput::reset_all`] for a full reset.
252    pub fn clear(&mut self) {
253        self.just_pressed.clear();
254        self.just_released.clear();
255    }
256
257    /// An iterator visiting every pressed input in arbitrary order.
258    pub fn get_pressed(&self) -> impl ExactSizeIterator<Item = &T> {
259        self.pressed.iter()
260    }
261
262    /// An iterator visiting every just pressed input in arbitrary order.
263    ///
264    /// Note: Returned elements do not imply information regarding the current state of [`ButtonInput::pressed`] or [`ButtonInput::just_released`].
265    pub fn get_just_pressed(&self) -> impl ExactSizeIterator<Item = &T> {
266        self.just_pressed.iter()
267    }
268
269    /// An iterator visiting every just released input in arbitrary order.
270    ///
271    /// Note: Returned elements do not imply information regarding the current state of [`ButtonInput::pressed`] or [`ButtonInput::just_pressed`].
272    pub fn get_just_released(&self) -> impl ExactSizeIterator<Item = &T> {
273        self.just_released.iter()
274    }
275}
276
277#[cfg(test)]
278mod test {
279    use crate::ButtonInput;
280
281    /// Used for testing the functionality of [`ButtonInput`].
282    #[derive(Copy, Clone, Eq, PartialEq, Hash)]
283    enum DummyInput {
284        Input1,
285        Input2,
286    }
287
288    #[test]
289    fn test_press() {
290        let mut input = ButtonInput::default();
291        assert!(!input.pressed.contains(&DummyInput::Input1));
292        assert!(!input.just_pressed.contains(&DummyInput::Input1));
293        input.press(DummyInput::Input1);
294        assert!(input.just_pressed.contains(&DummyInput::Input1));
295        assert!(input.pressed.contains(&DummyInput::Input1));
296    }
297
298    #[test]
299    fn test_pressed() {
300        let mut input = ButtonInput::default();
301        assert!(!input.pressed(DummyInput::Input1));
302        input.press(DummyInput::Input1);
303        assert!(input.pressed(DummyInput::Input1));
304    }
305
306    #[test]
307    fn test_any_pressed() {
308        let mut input = ButtonInput::default();
309        assert!(!input.any_pressed([DummyInput::Input1]));
310        assert!(!input.any_pressed([DummyInput::Input2]));
311        assert!(!input.any_pressed([DummyInput::Input1, DummyInput::Input2]));
312        input.press(DummyInput::Input1);
313        assert!(input.any_pressed([DummyInput::Input1]));
314        assert!(!input.any_pressed([DummyInput::Input2]));
315        assert!(input.any_pressed([DummyInput::Input1, DummyInput::Input2]));
316    }
317
318    #[test]
319    fn test_all_pressed() {
320        let mut input = ButtonInput::default();
321        assert!(!input.all_pressed([DummyInput::Input1]));
322        assert!(!input.all_pressed([DummyInput::Input2]));
323        assert!(!input.all_pressed([DummyInput::Input1, DummyInput::Input2]));
324        input.press(DummyInput::Input1);
325        assert!(input.all_pressed([DummyInput::Input1]));
326        assert!(!input.all_pressed([DummyInput::Input1, DummyInput::Input2]));
327        input.press(DummyInput::Input2);
328        assert!(input.all_pressed([DummyInput::Input1, DummyInput::Input2]));
329    }
330
331    #[test]
332    fn test_release() {
333        let mut input = ButtonInput::default();
334        input.press(DummyInput::Input1);
335        assert!(input.pressed.contains(&DummyInput::Input1));
336        assert!(!input.just_released.contains(&DummyInput::Input1));
337        input.release(DummyInput::Input1);
338        assert!(!input.pressed.contains(&DummyInput::Input1));
339        assert!(input.just_released.contains(&DummyInput::Input1));
340    }
341
342    #[test]
343    fn test_release_all() {
344        let mut input = ButtonInput::default();
345        input.press(DummyInput::Input1);
346        input.press(DummyInput::Input2);
347        input.release_all();
348        assert!(input.pressed.is_empty());
349        assert!(input.just_released.contains(&DummyInput::Input1));
350        assert!(input.just_released.contains(&DummyInput::Input2));
351    }
352
353    #[test]
354    fn test_just_pressed() {
355        let mut input = ButtonInput::default();
356        assert!(!input.just_pressed(DummyInput::Input1));
357        input.press(DummyInput::Input1);
358        assert!(input.just_pressed(DummyInput::Input1));
359    }
360
361    #[test]
362    fn test_any_just_pressed() {
363        let mut input = ButtonInput::default();
364        assert!(!input.any_just_pressed([DummyInput::Input1]));
365        assert!(!input.any_just_pressed([DummyInput::Input2]));
366        assert!(!input.any_just_pressed([DummyInput::Input1, DummyInput::Input2]));
367        input.press(DummyInput::Input1);
368        assert!(input.any_just_pressed([DummyInput::Input1]));
369        assert!(!input.any_just_pressed([DummyInput::Input2]));
370        assert!(input.any_just_pressed([DummyInput::Input1, DummyInput::Input2]));
371    }
372
373    #[test]
374    fn test_clear_just_pressed() {
375        let mut input = ButtonInput::default();
376        input.press(DummyInput::Input1);
377        assert!(input.just_pressed(DummyInput::Input1));
378        input.clear_just_pressed(DummyInput::Input1);
379        assert!(!input.just_pressed(DummyInput::Input1));
380    }
381
382    #[test]
383    fn test_just_released() {
384        let mut input = ButtonInput::default();
385        input.press(DummyInput::Input1);
386        assert!(!input.just_released(DummyInput::Input1));
387        input.release(DummyInput::Input1);
388        assert!(input.just_released(DummyInput::Input1));
389    }
390
391    #[test]
392    fn test_any_just_released() {
393        let mut input = ButtonInput::default();
394        input.press(DummyInput::Input1);
395        assert!(!input.any_just_released([DummyInput::Input1]));
396        assert!(!input.any_just_released([DummyInput::Input2]));
397        assert!(!input.any_just_released([DummyInput::Input1, DummyInput::Input2]));
398        input.release(DummyInput::Input1);
399        assert!(input.any_just_released([DummyInput::Input1]));
400        assert!(!input.any_just_released([DummyInput::Input2]));
401        assert!(input.any_just_released([DummyInput::Input1, DummyInput::Input2]));
402    }
403
404    #[test]
405    fn test_clear_just_released() {
406        let mut input = ButtonInput::default();
407        input.press(DummyInput::Input1);
408        input.release(DummyInput::Input1);
409        assert!(input.just_released(DummyInput::Input1));
410        input.clear_just_released(DummyInput::Input1);
411        assert!(!input.just_released(DummyInput::Input1));
412    }
413
414    #[test]
415    fn test_reset() {
416        let mut input = ButtonInput::default();
417
418        // Pressed
419        input.press(DummyInput::Input1);
420        assert!(input.pressed(DummyInput::Input1));
421        assert!(input.just_pressed(DummyInput::Input1));
422        assert!(!input.just_released(DummyInput::Input1));
423        input.reset(DummyInput::Input1);
424        assert!(!input.pressed(DummyInput::Input1));
425        assert!(!input.just_pressed(DummyInput::Input1));
426        assert!(!input.just_released(DummyInput::Input1));
427
428        // Released
429        input.press(DummyInput::Input1);
430        input.release(DummyInput::Input1);
431        assert!(!input.pressed(DummyInput::Input1));
432        assert!(input.just_pressed(DummyInput::Input1));
433        assert!(input.just_released(DummyInput::Input1));
434        input.reset(DummyInput::Input1);
435        assert!(!input.pressed(DummyInput::Input1));
436        assert!(!input.just_pressed(DummyInput::Input1));
437        assert!(!input.just_released(DummyInput::Input1));
438    }
439
440    #[test]
441    fn test_reset_all() {
442        let mut input = ButtonInput::default();
443
444        input.press(DummyInput::Input1);
445        input.press(DummyInput::Input2);
446        input.release(DummyInput::Input2);
447        assert!(input.pressed.contains(&DummyInput::Input1));
448        assert!(input.just_pressed.contains(&DummyInput::Input1));
449        assert!(input.just_released.contains(&DummyInput::Input2));
450        input.reset_all();
451        assert!(input.pressed.is_empty());
452        assert!(input.just_pressed.is_empty());
453        assert!(input.just_released.is_empty());
454    }
455
456    #[test]
457    fn test_clear() {
458        let mut input = ButtonInput::default();
459
460        // Pressed
461        input.press(DummyInput::Input1);
462        assert!(input.pressed(DummyInput::Input1));
463        assert!(input.just_pressed(DummyInput::Input1));
464        assert!(!input.just_released(DummyInput::Input1));
465        input.clear();
466        assert!(input.pressed(DummyInput::Input1));
467        assert!(!input.just_pressed(DummyInput::Input1));
468        assert!(!input.just_released(DummyInput::Input1));
469
470        // Released
471        input.press(DummyInput::Input1);
472        input.release(DummyInput::Input1);
473        assert!(!input.pressed(DummyInput::Input1));
474        assert!(!input.just_pressed(DummyInput::Input1));
475        assert!(input.just_released(DummyInput::Input1));
476        input.clear();
477        assert!(!input.pressed(DummyInput::Input1));
478        assert!(!input.just_pressed(DummyInput::Input1));
479        assert!(!input.just_released(DummyInput::Input1));
480    }
481
482    #[test]
483    fn test_get_pressed() {
484        let mut input = ButtonInput::default();
485        input.press(DummyInput::Input1);
486        input.press(DummyInput::Input2);
487        let pressed = input.get_pressed();
488        assert_eq!(pressed.len(), 2);
489        for pressed_input in pressed {
490            assert!(input.pressed.contains(pressed_input));
491        }
492    }
493
494    #[test]
495    fn test_get_just_pressed() {
496        let mut input = ButtonInput::default();
497        input.press(DummyInput::Input1);
498        input.press(DummyInput::Input2);
499        let just_pressed = input.get_just_pressed();
500        assert_eq!(just_pressed.len(), 2);
501        for just_pressed_input in just_pressed {
502            assert!(input.just_pressed.contains(just_pressed_input));
503        }
504    }
505
506    #[test]
507    fn test_get_just_released() {
508        let mut input = ButtonInput::default();
509        input.press(DummyInput::Input1);
510        input.press(DummyInput::Input2);
511        input.release(DummyInput::Input1);
512        input.release(DummyInput::Input2);
513        let just_released = input.get_just_released();
514        assert_eq!(just_released.len(), 2);
515        for just_released_input in just_released {
516            assert!(input.just_released.contains(just_released_input));
517        }
518    }
519
520    #[test]
521    fn test_general_input_handling() {
522        let mut input = ButtonInput::default();
523
524        // Test pressing
525        input.press(DummyInput::Input1);
526        input.press(DummyInput::Input2);
527
528        // Check if they were `just_pressed` (pressed on this update)
529        assert!(input.just_pressed(DummyInput::Input1));
530        assert!(input.just_pressed(DummyInput::Input2));
531
532        // Check if they are also marked as pressed
533        assert!(input.pressed(DummyInput::Input1));
534        assert!(input.pressed(DummyInput::Input2));
535
536        // Clear the `input`, removing `just_pressed` and `just_released`
537        input.clear();
538
539        // Check if they're marked `just_pressed`
540        assert!(!input.just_pressed(DummyInput::Input1));
541        assert!(!input.just_pressed(DummyInput::Input2));
542
543        // Check if they're marked as pressed
544        assert!(input.pressed(DummyInput::Input1));
545        assert!(input.pressed(DummyInput::Input2));
546
547        // Release the inputs and check state
548        input.release(DummyInput::Input1);
549        input.release(DummyInput::Input2);
550
551        // Check if they're marked as `just_released` (released on this update)
552        assert!(input.just_released(DummyInput::Input1));
553        assert!(input.just_released(DummyInput::Input2));
554
555        // Check that they're not incorrectly marked as pressed
556        assert!(!input.pressed(DummyInput::Input1));
557        assert!(!input.pressed(DummyInput::Input2));
558
559        // Clear the `Input` and check for removal from `just_released`
560        input.clear();
561
562        // Check that they're not incorrectly marked as just released
563        assert!(!input.just_released(DummyInput::Input1));
564        assert!(!input.just_released(DummyInput::Input2));
565
566        // Set up an `Input` to test resetting
567        let mut input = ButtonInput::default();
568
569        input.press(DummyInput::Input1);
570        input.release(DummyInput::Input2);
571
572        // Reset the `Input` and test if it was reset correctly
573        input.reset(DummyInput::Input1);
574        input.reset(DummyInput::Input2);
575
576        assert!(!input.just_pressed(DummyInput::Input1));
577        assert!(!input.pressed(DummyInput::Input1));
578        assert!(!input.just_released(DummyInput::Input2));
579    }
580}