Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_input/src/button_input.rs
6595 views
1
//! The generic input type.
2
3
use bevy_ecs::resource::Resource;
4
use bevy_platform::collections::HashSet;
5
use core::hash::Hash;
6
#[cfg(feature = "bevy_reflect")]
7
use {
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::{IntoScheduleConfigs, Res, Resource, resource_changed}, schedule::SystemCondition};
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))]
125
pub struct ButtonInput<T: Clone + 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
134
impl<T: Clone + 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
144
impl<T> ButtonInput<T>
145
where
146
T: Clone + 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.clone()) {
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)]
278
mod 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
}
581
582