leafwing_input_manager/action_state/mod.rs
1//! This module contains [`ActionState`] and its supporting methods and impls.
2
3use crate::input_map::UpdatedValue;
4use crate::{action_diff::ActionDiff, input_map::UpdatedActions};
5use crate::{Actionlike, InputControlKind};
6
7use bevy::platform::{collections::HashMap, time::Instant};
8use bevy::prelude::Resource;
9use bevy::reflect::Reflect;
10use bevy::{ecs::component::Component, prelude::ReflectComponent};
11use bevy::{
12 math::{Vec2, Vec3},
13 prelude::ReflectResource,
14};
15#[cfg(feature = "timing")]
16use core::time::Duration;
17use serde::{Deserialize, Serialize};
18
19mod action_data;
20pub use action_data::*;
21
22/// Stores the canonical input-method-agnostic representation of the inputs received
23///
24/// Can be used as either a resource or as a [`Component`] on entities that you wish to control directly from player input.
25///
26/// # Disabling actions
27///
28/// Actions can be disabled in four different ways, with increasing granularity:
29///
30/// 1. By disabling updates to all actions using a run condition on [`InputManagerSystem::Update`](crate::plugin::InputManagerSystem::Update).
31/// 2. By disabling updates to all actions of type `A` using a run condition on [`TickActionStateSystem::<A>`](crate::plugin::TickActionStateSystem).
32/// 3. By setting a specific action state to disabled using [`ActionState::disable`].
33/// 4. By disabling a specific action using [`ActionState::disable_action`].
34///
35/// More general mechanisms of disabling actions will cause specific mechanisms to be ignored.
36/// For example, if an entire action state is disabled, then enabling or disabling individual actions will have no effect.
37///
38/// Actions that are disabled will report as released (but not just released), and their values will be zero.
39/// Under the hood, their values are still updated to avoid surprising behavior when re-enabled,
40/// but they are not reported to the user using standard methods like [`ActionState::pressed`].
41/// To check the underlying values, access their [`ActionData`] directly.
42///
43/// # Example
44///
45/// ```rust
46/// use bevy::reflect::Reflect;
47/// use leafwing_input_manager::prelude::*;
48/// use bevy::platform::time::Instant;
49///
50/// #[derive(Actionlike, PartialEq, Eq, Hash, Clone, Copy, Debug, Reflect)]
51/// enum Action {
52/// Left,
53/// Right,
54/// Jump,
55/// }
56///
57/// let mut action_state = ActionState::<Action>::default();
58///
59/// // Typically, this is done automatically by the `InputManagerPlugin` from user inputs
60/// // using the `ActionState::update` method
61/// action_state.press(&Action::Jump);
62///
63/// assert!(action_state.pressed(&Action::Jump));
64/// assert!(action_state.just_pressed(&Action::Jump));
65/// assert!(action_state.released(&Action::Left));
66///
67/// // Resets just_pressed and just_released
68/// let t0 = Instant::now();
69/// let t1 = Instant::now();
70///
71/// action_state.tick(t1, t0);
72/// assert!(action_state.pressed(&Action::Jump));
73/// assert!(!action_state.just_pressed(&Action::Jump));
74///
75/// action_state.release(&Action::Jump);
76/// assert!(!action_state.pressed(&Action::Jump));
77/// assert!(action_state.released(&Action::Jump));
78/// assert!(action_state.just_released(&Action::Jump));
79///
80/// let t2 = Instant::now();
81/// action_state.tick(t2, t1);
82/// assert!(action_state.released(&Action::Jump));
83/// assert!(!action_state.just_released(&Action::Jump));
84/// ```
85#[derive(Resource, Component, Clone, Debug, PartialEq, Serialize, Deserialize, Reflect)]
86#[reflect(Resource, Component)]
87pub struct ActionState<A: Actionlike> {
88 /// Whether or not all of the actions are disabled.
89 disabled: bool,
90 /// The shared action data for each action
91 action_data: HashMap<A, ActionData>,
92}
93
94// The derive does not work unless A: Default,
95// so we have to implement it manually
96impl<A: Actionlike> Default for ActionState<A> {
97 fn default() -> Self {
98 Self {
99 disabled: false,
100 action_data: HashMap::default(),
101 }
102 }
103}
104
105impl<A: Actionlike> ActionState<A> {
106 /// Returns a reference to the complete [`ActionData`] for all actions.
107 #[inline]
108 #[must_use]
109 pub fn all_action_data(&self) -> &HashMap<A, ActionData> {
110 &self.action_data
111 }
112
113 /// We are about to enter the `Main` schedule, so we:
114 /// - save all the changes applied to `state` into the `fixed_update_state`
115 /// - switch to loading the `update_state`
116 pub(crate) fn swap_to_update_state(&mut self) {
117 for action_datum in self.action_data.values_mut() {
118 action_datum.kind_data.swap_to_update_state();
119 }
120 }
121
122 /// We are about to enter the `FixedMain` schedule, so we:
123 /// - save all the changes applied to `state` into the `update_state`
124 /// - switch to loading the `fixed_update_state`
125 pub(crate) fn swap_to_fixed_update_state(&mut self) {
126 for action_datum in self.action_data.values_mut() {
127 action_datum.kind_data.swap_to_fixed_update_state();
128 }
129 }
130
131 /// Function for advanced users to override the `state` from the `update_state`
132 pub fn set_update_state_from_state(&mut self) {
133 for action_datum in self.action_data.values_mut() {
134 action_datum.kind_data.set_update_state_from_state();
135 }
136 }
137
138 /// Function for advanced users to override the `state` from the `fixed_update_state`
139 pub fn set_fixed_update_state_from_state(&mut self) {
140 for action_datum in self.action_data.values_mut() {
141 action_datum.kind_data.set_fixed_update_state_from_state();
142 }
143 }
144
145 /// Updates the [`ActionState`] based on the provided [`UpdatedActions`].
146 ///
147 /// The `action_data` is typically constructed from [`InputMap::process_actions`](crate::input_map::InputMap::process_actions),
148 /// which reads from the assorted [`ButtonInput`](bevy::input::ButtonInput) resources.
149 ///
150 /// Actions that are disabled will still be updated: instead, their values will be read as released / zero.
151 /// You can see their underlying values by checking their [`ActionData`] directly.
152 pub fn update(&mut self, updated_actions: UpdatedActions<A>) {
153 for (action, updated_value) in updated_actions.iter() {
154 match updated_value {
155 UpdatedValue::Button(pressed) => {
156 if *pressed {
157 self.press(action);
158 } else {
159 self.release(action);
160 }
161 }
162 UpdatedValue::Axis(value) => {
163 self.set_value(action, *value);
164 }
165 UpdatedValue::DualAxis(pair) => {
166 self.set_axis_pair(action, *pair);
167 }
168 UpdatedValue::TripleAxis(triple) => {
169 self.set_axis_triple(action, *triple);
170 }
171 }
172 }
173 }
174
175 /// Advances the time for all actions,
176 /// transitioning them from `just_pressed` to `pressed`, and `just_released` to `released`.
177 ///
178 /// If the `timing` feature flag is enabled, the underlying timing and action data will be advanced according to the `current_instant`.
179 /// - if no [`Instant`] is set, the `current_instant` will be set as the initial time at which the button was pressed / released
180 /// - the [`Duration`] will advance to reflect elapsed time
181 ///
182 ///
183 /// # Example
184 /// ```rust
185 /// use bevy::prelude::Reflect;
186 /// use leafwing_input_manager::prelude::*;
187 /// use leafwing_input_manager::buttonlike::ButtonState;
188 /// use bevy::platform::time::Instant;
189 ///
190 /// #[derive(Actionlike, Clone, Copy, PartialEq, Eq, Hash, Debug, Reflect)]
191 /// enum Action {
192 /// Run,
193 /// Jump,
194 /// }
195 ///
196 /// let mut action_state = ActionState::<Action>::default();
197 ///
198 /// // Actions start released
199 /// assert!(action_state.released(&Action::Jump));
200 /// assert!(!action_state.just_released(&Action::Run));
201 ///
202 /// // Ticking time moves causes buttons just released to no longer be just released
203 /// let t0 = Instant::now();
204 /// let t1 = Instant::now();
205 ///
206 /// action_state.tick(t1, t0);
207 /// assert!(action_state.released(&Action::Jump));
208 /// assert!(!action_state.just_released(&Action::Jump));
209 ///
210 /// action_state.press(&Action::Jump);
211 /// assert!(action_state.just_pressed(&Action::Jump));
212 ///
213 /// // Ticking time moves causes buttons just pressed to no longer be just pressed
214 /// let t2 = Instant::now();
215 ///
216 /// action_state.tick(t2, t1);
217 /// assert!(action_state.pressed(&Action::Jump));
218 /// assert!(!action_state.just_pressed(&Action::Jump));
219 /// ```
220 pub fn tick(&mut self, _current_instant: Instant, _previous_instant: Instant) {
221 // Advanced the action states
222 self.action_data
223 .values_mut()
224 .for_each(|action_datum| action_datum.tick(_current_instant, _previous_instant));
225 }
226
227 /// A reference to the [`ActionData`] corresponding to the `action`.
228 #[inline]
229 #[must_use]
230 pub fn action_data(&self, action: &A) -> Option<&ActionData> {
231 self.action_data.get(action)
232 }
233
234 /// A mutable reference to the [`ActionData`] corresponding to the `action`.
235 ///
236 /// To initialize the [`ActionData`] if it has not yet been triggered,
237 /// use [`action_data_mut_or_default`](Self::action_data_mut_or_default) method.
238 #[inline]
239 #[must_use]
240 pub fn action_data_mut(&mut self, action: &A) -> Option<&mut ActionData> {
241 self.action_data.get_mut(action)
242 }
243
244 /// A mutable reference to the [`ActionData`] corresponding to the `action`, initializing it if needed.
245 ///
246 /// If the `action` has no data yet (because the `action` has not been triggered),
247 /// this method will create and insert a default [`ActionData`] for you,
248 /// avoiding potential errors from unwrapping [`None`].
249 pub fn action_data_mut_or_default(&mut self, action: &A) -> &mut ActionData {
250 if self.action_data.contains_key(action) {
251 // Safe to unwrap because we just checked
252 self.action_data.get_mut(action).unwrap()
253 } else {
254 self.action_data.insert(
255 action.clone(),
256 ActionData::from_kind(action.input_control_kind()),
257 );
258 // Safe to unwrap because we just inserted
259 self.action_data_mut(action).unwrap()
260 }
261 }
262
263 /// A reference of the [`ButtonData`] corresponding to the `action`.
264 ///
265 /// Generally, it'll be clearer to call `pressed` or so on directly on the [`ActionState`].
266 /// However, accessing the raw data directly allows you to examine detailed metadata holistically.
267 ///
268 /// # Caution
269 ///
270 /// To access the [`ButtonData`] regardless of whether the `action` has been triggered,
271 /// use [`unwrap_or_default`](Option::unwrap_or_default) on the returned [`Option`].
272 ///
273 /// # Returns
274 ///
275 /// - `Some(ButtonData)` if it exists.
276 /// - `None` if the `action` has never been triggered (pressed, clicked, etc.).
277 #[inline]
278 #[must_use]
279 pub fn button_data(&self, action: &A) -> Option<&ButtonData> {
280 match self.action_data(action) {
281 Some(action_data) => match action_data.kind_data {
282 ActionKindData::Button(ref button_data) => Some(button_data),
283 _ => None,
284 },
285 None => None,
286 }
287 }
288
289 /// A mutable reference of the [`ButtonData`] corresponding to the `action`.
290 ///
291 /// Generally, it'll be clearer to call `pressed` or so on directly on the [`ActionState`].
292 /// However, accessing the raw data directly allows you to examine detailed metadata holistically.
293 ///
294 /// # Caution
295 ///
296 /// To access the [`ButtonData`] regardless of whether the `action` has been triggered,
297 /// use [`unwrap_or_default`](Option::unwrap_or_default) on the returned [`Option`].
298 ///
299 /// To insert a default [`ButtonData`] if it doesn't exist,
300 /// use [`button_data_mut_or_default`](Self::button_data_mut_or_default) method.
301 ///
302 /// # Returns
303 ///
304 /// - `Some(ButtonData)` if it exists.
305 /// - `None` if the `action` has never been triggered (pressed, clicked, etc.).
306 #[inline]
307 #[must_use]
308 pub fn button_data_mut(&mut self, action: &A) -> Option<&mut ButtonData> {
309 match self.action_data_mut(action) {
310 Some(action_data) => match &mut action_data.kind_data {
311 ActionKindData::Button(ref mut button_data) => Some(button_data),
312 _ => None,
313 },
314 None => None,
315 }
316 }
317
318 /// A mutable reference of the [`ButtonData`] corresponding to the `action`, initializing it if needed.
319 ///
320 /// If the `action` has no data yet (because the `action` has not been triggered),
321 /// this method will create and insert a default [`ButtonData`] for you,
322 /// avoiding potential errors from unwrapping [`None`].
323 ///
324 /// Generally, it'll be clearer to call `pressed` or so on directly on the [`ActionState`].
325 /// However, accessing the raw data directly allows you to examine detailed metadata holistically.
326 #[inline]
327 #[must_use]
328 #[track_caller]
329 pub fn button_data_mut_or_default(&mut self, action: &A) -> &mut ButtonData {
330 debug_assert_eq!(action.input_control_kind(), InputControlKind::Button);
331
332 let action_data = self.action_data_mut_or_default(action);
333 let ActionKindData::Button(ref mut button_data) = action_data.kind_data else {
334 panic!("{action:?} is not a Button");
335 };
336 button_data
337 }
338
339 /// A reference of the [`AxisData`] corresponding to the `action`.
340 ///
341 /// # Caution
342 ///
343 /// To access the [`AxisData`] regardless of whether the `action` has been triggered,
344 /// use [`unwrap_or_default`](Option::unwrap_or_default) on the returned [`Option`].
345 ///
346 /// # Returns
347 ///
348 /// - `Some(AxisData)` if it exists.
349 /// - `None` if the `action` has never been triggered (pressed, clicked, etc.).
350 #[inline]
351 #[must_use]
352 #[track_caller]
353 pub fn axis_data(&self, action: &A) -> Option<&AxisData> {
354 debug_assert_eq!(action.input_control_kind(), InputControlKind::Axis);
355
356 match self.action_data(action) {
357 Some(action_data) => match action_data.kind_data {
358 ActionKindData::Axis(ref axis_data) => Some(axis_data),
359 _ => None,
360 },
361 None => None,
362 }
363 }
364
365 /// A mutable reference of the [`AxisData`] corresponding to the `action`.
366 ///
367 /// # Caution
368 ///
369 /// To insert a default [`AxisData`] if it doesn't exist,
370 /// use [`axis_data_mut_or_default`](Self::axis_data_mut_or_default) method.
371 ///
372 /// # Returns
373 ///
374 /// - `Some(AxisData)` if it exists.
375 /// - `None` if the `action` has never been triggered (pressed, clicked, etc.).
376 #[inline]
377 #[must_use]
378 pub fn axis_data_mut(&mut self, action: &A) -> Option<&mut AxisData> {
379 match self.action_data_mut(action) {
380 Some(action_data) => match &mut action_data.kind_data {
381 ActionKindData::Axis(ref mut axis_data) => Some(axis_data),
382 _ => None,
383 },
384 None => None,
385 }
386 }
387
388 /// A mutable reference of the [`AxisData`] corresponding to the `action`, initializing it if needed..
389 ///
390 /// If the `action` has no data yet (because the `action` has not been triggered),
391 /// this method will create and insert a default [`AxisData`] for you,
392 /// avoiding potential errors from unwrapping [`None`].
393 ///
394 /// Generally, it'll be clearer to call `pressed` or so on directly on the [`ActionState`].
395 /// However, accessing the raw data directly allows you to examine detailed metadata holistically.
396 #[inline]
397 #[must_use]
398 #[track_caller]
399 pub fn axis_data_mut_or_default(&mut self, action: &A) -> &mut AxisData {
400 debug_assert_eq!(action.input_control_kind(), InputControlKind::Axis);
401
402 let action_data = self.action_data_mut_or_default(action);
403 let ActionKindData::Axis(ref mut axis_data) = action_data.kind_data else {
404 panic!("{action:?} is not an Axis");
405 };
406 axis_data
407 }
408
409 /// A reference of the [`DualAxisData`] corresponding to the `action`.
410 ///
411 /// # Caution
412 ///
413 /// To access the [`DualAxisData`] regardless of whether the `action` has been triggered,
414 /// use [`unwrap_or_default`](Option::unwrap_or_default) on the returned [`Option`].
415 ///
416 /// # Returns
417 ///
418 /// - `Some(DualAxisData)` if it exists.
419 /// - `None` if the `action` has never been triggered (pressed, clicked, etc.).
420 #[inline]
421 #[must_use]
422 #[track_caller]
423 pub fn dual_axis_data(&self, action: &A) -> Option<&DualAxisData> {
424 debug_assert_eq!(action.input_control_kind(), InputControlKind::DualAxis);
425
426 match self.action_data(action) {
427 Some(action_data) => match action_data.kind_data {
428 ActionKindData::DualAxis(ref dual_axis_data) => Some(dual_axis_data),
429 _ => None,
430 },
431 None => None,
432 }
433 }
434
435 /// A mutable reference of the [`DualAxisData`] corresponding to the `action`.
436 ///
437 /// # Caution
438 ///
439 /// To insert a default [`DualAxisData`] if it doesn't exist,
440 /// use [`dual_axis_data_mut_or_default`](Self::dual_axis_data_mut_or_default) method.
441 ///
442 /// # Returns
443 ///
444 /// - `Some(DualAxisData)` if it exists.
445 /// - `None` if the `action` has never been triggered (pressed, clicked, etc.).
446 #[inline]
447 #[must_use]
448 #[track_caller]
449 pub fn dual_axis_data_mut(&mut self, action: &A) -> Option<&mut DualAxisData> {
450 debug_assert_eq!(action.input_control_kind(), InputControlKind::DualAxis);
451
452 match self.action_data_mut(action) {
453 Some(action_data) => match &mut action_data.kind_data {
454 ActionKindData::DualAxis(ref mut dual_axis_data) => Some(dual_axis_data),
455 _ => None,
456 },
457 None => None,
458 }
459 }
460
461 /// A mutable reference of the [`DualAxisData`] corresponding to the `action` initializing it if needed.
462 ///
463 /// If the `action` has no data yet (because the `action` has not been triggered),
464 /// this method will create and insert a default [`DualAxisData`] for you,
465 /// avoiding potential errors from unwrapping [`None`].
466 ///
467 /// Generally, it'll be clearer to call `pressed` or so on directly on the [`ActionState`].
468 /// However, accessing the raw data directly allows you to examine detailed metadata holistically.
469 #[inline]
470 #[must_use]
471 #[track_caller]
472 pub fn dual_axis_data_mut_or_default(&mut self, action: &A) -> &mut DualAxisData {
473 debug_assert_eq!(action.input_control_kind(), InputControlKind::DualAxis);
474
475 let action_data = self.action_data_mut_or_default(action);
476 let ActionKindData::DualAxis(ref mut dual_axis_data) = action_data.kind_data else {
477 panic!("{action:?} is not a DualAxis");
478 };
479 dual_axis_data
480 }
481
482 /// A reference of the [`TripleAxisData`] corresponding to the `action`.
483 ///
484 /// # Caution
485 ///
486 /// To access the [`TripleAxisData`] regardless of whether the `action` has been triggered,
487 /// use [`unwrap_or_default`](Option::unwrap_or_default) on the returned [`Option`].
488 ///
489 /// # Returns
490 ///
491 /// - `Some(TripleAxisData)` if it exists.
492 /// - `None` if the `action` has never been triggered (pressed, clicked, etc.).
493 #[inline]
494 #[must_use]
495 #[track_caller]
496 pub fn triple_axis_data(&self, action: &A) -> Option<&TripleAxisData> {
497 debug_assert_eq!(action.input_control_kind(), InputControlKind::TripleAxis);
498
499 match self.action_data(action) {
500 Some(action_data) => match action_data.kind_data {
501 ActionKindData::TripleAxis(ref triple_axis_data) => Some(triple_axis_data),
502 _ => None,
503 },
504 None => None,
505 }
506 }
507
508 /// A mutable reference of the [`TripleAxisData`] corresponding to the `action`.
509 ///
510 /// # Caution
511 ///
512 /// To insert a default [`TripleAxisData`] if it doesn't exist,
513 /// use [`triple_axis_data_mut_or_default`](Self::dual_axis_data_mut_or_default) method.
514 ///
515 /// # Returns
516 ///
517 /// - `Some(ButtonData)` if it exists.
518 /// - `None` if the `action` has never been triggered (pressed, clicked, etc.).
519 #[inline]
520 #[must_use]
521 #[track_caller]
522 pub fn triple_axis_data_mut(&mut self, action: &A) -> Option<&mut TripleAxisData> {
523 debug_assert_eq!(action.input_control_kind(), InputControlKind::TripleAxis);
524
525 match self.action_data_mut(action) {
526 Some(action_data) => match &mut action_data.kind_data {
527 ActionKindData::TripleAxis(ref mut triple_axis_data) => Some(triple_axis_data),
528 _ => None,
529 },
530 None => None,
531 }
532 }
533
534 /// A mutable reference of the [`TripleAxisData`] corresponding to the `action` initializing it if needed.
535 ///
536 /// If the `action` has no data yet (because the `action` has not been triggered),
537 /// this method will create and insert a default [`TripleAxisData`] for you,
538 /// avoiding potential errors from unwrapping [`None`].
539 ///
540 /// Generally, it'll be clearer to call `pressed` or so on directly on the [`ActionState`].
541 /// However, accessing the raw data directly allows you to examine detailed metadata holistically.
542 #[inline]
543 #[must_use]
544 #[track_caller]
545 pub fn triple_axis_data_mut_or_default(&mut self, action: &A) -> &mut TripleAxisData {
546 debug_assert_eq!(action.input_control_kind(), InputControlKind::TripleAxis);
547
548 let action_data = self.action_data_mut_or_default(action);
549 let ActionKindData::TripleAxis(ref mut triple_axis_data) = action_data.kind_data else {
550 panic!("{action:?} is not a TripleAxis");
551 };
552 triple_axis_data
553 }
554
555 /// Get the value associated with the corresponding buttonlike `action` if present.
556 ///
557 /// # Warnings
558 ///
559 /// This value may not be bounded as you might expect.
560 /// Consider clamping this to account for multiple triggering inputs,
561 /// typically using the [`clamped_button_value`](Self::clamped_button_value) method instead.
562 #[inline]
563 #[must_use]
564 #[track_caller]
565 pub fn button_value(&self, action: &A) -> f32 {
566 debug_assert_eq!(action.input_control_kind(), InputControlKind::Button);
567
568 if self.action_disabled(action) {
569 return 0.0;
570 }
571
572 let action_data = self.button_data(action);
573 action_data.map_or(0.0, |action_data| action_data.value)
574 }
575
576 /// Sets the value of the buttonlike `action` to the provided `value`.
577 ///
578 /// Also updates the state of the button based on the `value`:
579 /// - If `value > 0.0`, the button will be pressed.
580 /// - If `value <= 0.0`, the button will be released.
581 #[track_caller]
582 pub fn set_button_value(&mut self, action: &A, value: f32) {
583 debug_assert_eq!(action.input_control_kind(), InputControlKind::Button);
584
585 let button_data = self.button_data_mut_or_default(action);
586 button_data.value = value;
587
588 if value > 0.0 {
589 #[cfg(feature = "timing")]
590 if button_data.state.released() {
591 button_data.timing.flip();
592 }
593
594 button_data.state.press();
595 } else {
596 #[cfg(feature = "timing")]
597 if button_data.state.pressed() {
598 button_data.timing.flip();
599 }
600
601 button_data.state.release();
602 }
603 }
604
605 /// Get the value associated with the corresponding `action`, clamped to `[0.0, 1.0]`.
606 ///
607 /// # Warning
608 ///
609 /// This value will be 0. by default,
610 /// even if the action is not a buttonlike action.
611 pub fn clamped_button_value(&self, action: &A) -> f32 {
612 self.button_value(action).clamp(0., 1.)
613 }
614
615 /// Get the value associated with the corresponding axislike `action` if present.
616 ///
617 /// # Warnings
618 ///
619 /// This value may not be bounded as you might expect.
620 /// Consider clamping this to account for multiple triggering inputs,
621 /// typically using the [`clamped_value`](Self::clamped_value) method instead.
622 #[inline]
623 #[must_use]
624 #[track_caller]
625 pub fn value(&self, action: &A) -> f32 {
626 debug_assert_eq!(action.input_control_kind(), InputControlKind::Axis);
627
628 if self.action_disabled(action) {
629 return 0.0;
630 }
631
632 let action_data = self.axis_data(action);
633 action_data.map_or(0.0, |action_data| action_data.value)
634 }
635
636 /// Sets the value of the axislike `action` to the provided `value`.
637 #[track_caller]
638 pub fn set_value(&mut self, action: &A, value: f32) {
639 debug_assert_eq!(action.input_control_kind(), InputControlKind::Axis);
640
641 let axis_data = self.axis_data_mut_or_default(action);
642 axis_data.value = value;
643 }
644
645 /// Get the value associated with the corresponding `action`, clamped to `[-1.0, 1.0]`.
646 ///
647 /// # Warning
648 ///
649 /// This value will be 0. by default,
650 /// even if the action is not an axislike action.
651 pub fn clamped_value(&self, action: &A) -> f32 {
652 self.value(action).clamp(-1., 1.)
653 }
654
655 /// Get the [`Vec2`] from the binding that triggered the corresponding `action`.
656 ///
657 /// Only events that represent dual-axis control provide a [`Vec2`],
658 /// and this will return [`None`] for other events.
659 ///
660 /// If multiple inputs with an axis pair trigger the same game action at the same time, the
661 /// value of each axis pair will be added together.
662 ///
663 /// # Warning
664 ///
665 /// This value will be [`Vec2::ZERO`] by default,
666 /// even if the action is not a dual-axislike action.
667 ///
668 /// These values may not be bounded as you might expect.
669 /// Consider clamping this to account for multiple triggering inputs,
670 /// typically using the [`clamped_axis_pair`](Self::clamped_axis_pair) method instead.
671 #[must_use]
672 #[track_caller]
673 pub fn axis_pair(&self, action: &A) -> Vec2 {
674 debug_assert_eq!(action.input_control_kind(), InputControlKind::DualAxis);
675
676 if self.action_disabled(action) {
677 return Vec2::ZERO;
678 }
679
680 let action_data = self.dual_axis_data(action);
681 action_data.map_or(Vec2::ZERO, |action_data| action_data.pair)
682 }
683
684 /// Sets the [`Vec2`] of the `action` to the provided `pair`.
685 #[track_caller]
686 pub fn set_axis_pair(&mut self, action: &A, pair: Vec2) {
687 debug_assert_eq!(action.input_control_kind(), InputControlKind::DualAxis);
688
689 let dual_axis_data = self.dual_axis_data_mut_or_default(action);
690 dual_axis_data.pair = pair;
691 }
692
693 /// Get the [`Vec2`] associated with the corresponding `action`, clamped to `[-1.0, 1.0]`.
694 ///
695 /// # Warning
696 ///
697 /// This value will be [`Vec2::ZERO`] by default,
698 /// even if the action is not a dual-axislike action.
699 pub fn clamped_axis_pair(&self, action: &A) -> Vec2 {
700 let pair = self.axis_pair(action);
701 pair.clamp(Vec2::NEG_ONE, Vec2::ONE)
702 }
703
704 /// Get the [`Vec3`] from the binding that triggered the corresponding `action`.
705 ///
706 /// Only events that represent triple-axis control provide a [`Vec3`],
707 /// and this will return [`None`] for other events.
708 ///
709 /// If multiple inputs with an axis triple trigger the same game action at the same time, the
710 /// value of each axis triple will be added together.
711 ///
712 /// # Warning
713 ///
714 /// This value will be [`Vec3::ZERO`] by default,
715 /// even if the action is not a triple-axislike action.
716 ///
717 /// These values may not be bounded as you might expect.
718 /// Consider clamping this to account for multiple triggering inputs,
719 /// typically using the [`clamped_axis_triple`](Self::clamped_axis_triple) method instead.
720 #[must_use]
721 #[track_caller]
722 pub fn axis_triple(&self, action: &A) -> Vec3 {
723 debug_assert_eq!(action.input_control_kind(), InputControlKind::TripleAxis);
724
725 if self.action_disabled(action) {
726 return Vec3::ZERO;
727 }
728
729 let action_data = self.triple_axis_data(action);
730 action_data.map_or(Vec3::ZERO, |action_data| action_data.triple)
731 }
732
733 /// Sets the [`Vec2`] of the `action` to the provided `pair`.
734 #[track_caller]
735 pub fn set_axis_triple(&mut self, action: &A, triple: Vec3) {
736 debug_assert_eq!(action.input_control_kind(), InputControlKind::TripleAxis);
737
738 let triple_axis_data = self.triple_axis_data_mut_or_default(action);
739 triple_axis_data.triple = triple;
740 }
741
742 /// Get the [`Vec3`] associated with the corresponding `action`, clamped to the cube of values bounded by -1 and 1 on all axes.
743 ///
744 /// # Warning
745 ///
746 /// This value will be [`Vec3::ZERO`] by default,
747 /// even if the action is not a dual-axislike action.
748 pub fn clamped_axis_triple(&self, action: &A) -> Vec3 {
749 let triple = self.axis_triple(action);
750 triple.clamp(Vec3::NEG_ONE, Vec3::ONE)
751 }
752
753 /// Manually sets the [`ButtonData`] of the corresponding `action`
754 ///
755 /// You should almost always use more direct methods, as they are simpler and less error-prone.
756 ///
757 /// However, this method can be useful for testing,
758 /// or when transferring [`ButtonData`] between action states.
759 ///
760 /// # Example
761 /// ```rust
762 /// use bevy::prelude::Reflect;
763 /// use leafwing_input_manager::prelude::*;
764 ///
765 /// #[derive(Actionlike, Clone, Copy, PartialEq, Eq, Hash, Debug, Reflect)]
766 /// enum AbilitySlot {
767 /// Slot1,
768 /// Slot2,
769 /// }
770 ///
771 /// #[derive(Actionlike, Clone, Copy, PartialEq, Eq, Hash, Debug, Reflect)]
772 /// enum Action {
773 /// Run,
774 /// Jump,
775 /// }
776 ///
777 /// let mut ability_slot_state = ActionState::<AbilitySlot>::default();
778 /// let mut action_state = ActionState::<Action>::default();
779 ///
780 /// // Extract the state from the ability slot
781 /// let slot_1_state = ability_slot_state.button_data(&AbilitySlot::Slot1);
782 ///
783 /// // And transfer it to the actual ability that we care about
784 /// // without losing timing information
785 /// if let Some(state) = slot_1_state {
786 /// action_state.set_button_data(Action::Run, state.clone());
787 /// }
788 /// ```
789 #[inline]
790 #[track_caller]
791 pub fn set_button_data(&mut self, action: A, data: ButtonData) {
792 debug_assert_eq!(action.input_control_kind(), InputControlKind::Button);
793
794 let button_data = self.button_data_mut_or_default(&action);
795 *button_data = data;
796 }
797
798 /// Press the `action`
799 ///
800 /// No initial instant or reasons why the button was pressed will be recorded.
801 /// Instead, this is set through [`ActionState::tick()`]
802 #[inline]
803 #[track_caller]
804 pub fn press(&mut self, action: &A) {
805 debug_assert_eq!(action.input_control_kind(), InputControlKind::Button);
806
807 let action_data = self.button_data_mut_or_default(action);
808
809 #[cfg(feature = "timing")]
810 if action_data.update_state.released() {
811 action_data.timing.flip();
812 }
813
814 action_data.state.press();
815 action_data.value = 1.0;
816 }
817
818 /// Release the `action`
819 ///
820 /// No initial instant will be recorded.
821 /// Instead, this is set through [`ActionState::tick()`]
822 #[inline]
823 pub fn release(&mut self, action: &A) {
824 debug_assert_eq!(action.input_control_kind(), InputControlKind::Button);
825
826 let action_data = self.button_data_mut_or_default(action);
827
828 #[cfg(feature = "timing")]
829 if action_data.update_state.pressed() {
830 action_data.timing.flip();
831 }
832
833 action_data.state.release();
834 action_data.value = 0.0;
835 }
836
837 /// Resets an action to its default state.
838 ///
839 /// Buttons will be released, and axes will be set to 0.
840 pub fn reset(&mut self, action: &A) {
841 match action.input_control_kind() {
842 InputControlKind::Button => self.release(action),
843 InputControlKind::Axis => {
844 self.set_value(action, 0.0);
845 }
846 InputControlKind::DualAxis => {
847 self.set_axis_pair(action, Vec2::ZERO);
848 }
849 InputControlKind::TripleAxis => {
850 self.set_axis_triple(action, Vec3::ZERO);
851 }
852 }
853 }
854
855 /// Releases all [`Buttonlike`](crate::user_input::Buttonlike) actions,
856 /// sets all [`Axislike`](crate::user_input::Axislike) actions to 0,
857 /// sets all [`DualAxislike`](crate::user_input::DualAxislike) actions to [`Vec2::ZERO`],
858 /// and sets all [`TripleAxislike`](crate::user_input::TripleAxislike) actions to [`Vec3::ZERO`].
859 pub fn reset_all(&mut self) {
860 // Collect out to avoid angering the borrow checker
861 let all_actions = self.action_data.keys().cloned().collect::<Vec<A>>();
862 for action in all_actions.into_iter() {
863 self.reset(&action);
864 }
865 }
866
867 /// Is the entire [`ActionState`] currently disabled?
868 pub fn disabled(&self) -> bool {
869 self.disabled
870 }
871
872 /// Is this `action` currently disabled?
873 #[inline]
874 #[must_use]
875 pub fn action_disabled(&self, action: &A) -> bool {
876 if self.disabled {
877 return true;
878 }
879
880 match self.action_data(action) {
881 Some(action_data) => action_data.disabled,
882 None => false,
883 }
884 }
885
886 /// Disables the entire [`ActionState`].
887 ///
888 /// All values will be reset to their default state.
889 #[inline]
890 pub fn disable(&mut self) {
891 self.disabled = true;
892 self.reset_all();
893 }
894
895 /// Disables the `action`.
896 ///
897 /// The action's value will be reset to its default state.
898 #[inline]
899 pub fn disable_action(&mut self, action: &A) {
900 let action_data = self.action_data_mut_or_default(action);
901
902 action_data.disabled = true;
903 self.reset(action);
904 }
905
906 /// Disables all actions
907 #[inline]
908 pub fn disable_all_actions(&mut self) {
909 for action in self.keys() {
910 self.disable_action(&action);
911 }
912 }
913
914 /// Enables the entire [`ActionState`]
915 #[inline]
916 pub fn enable(&mut self) {
917 self.disabled = false;
918 }
919
920 /// Enables the `action`
921 #[inline]
922 pub fn enable_action(&mut self, action: &A) {
923 let action_data = self.action_data_mut_or_default(action);
924
925 action_data.disabled = false;
926 }
927
928 /// Enables all actions
929 #[inline]
930 pub fn enable_all_actions(&mut self) {
931 for action in self.keys() {
932 self.enable_action(&action);
933 }
934 }
935
936 /// Is this `action` currently pressed?
937 ///
938 /// # Warning
939 ///
940 /// This value will be `false` by default,
941 /// even if the action is not a buttonlike action.
942 #[inline]
943 #[must_use]
944 #[track_caller]
945 pub fn pressed(&self, action: &A) -> bool {
946 debug_assert_eq!(action.input_control_kind(), InputControlKind::Button);
947
948 if self.action_disabled(action) {
949 return false;
950 }
951
952 match self.button_data(action) {
953 Some(button_data) => button_data.pressed(),
954 None => false,
955 }
956 }
957
958 /// Was this `action` pressed since the last time [tick](ActionState::tick) was called?
959 ///
960 /// # Warning
961 ///
962 /// This value will be `false` by default,
963 /// even if the action is not a buttonlike action.
964 #[inline]
965 #[must_use]
966 #[track_caller]
967 pub fn just_pressed(&self, action: &A) -> bool {
968 debug_assert_eq!(action.input_control_kind(), InputControlKind::Button);
969
970 if self.action_disabled(action) {
971 return false;
972 }
973
974 match self.button_data(action) {
975 Some(button_data) => button_data.just_pressed(),
976 None => false,
977 }
978 }
979
980 /// Is this `action` currently released?
981 ///
982 /// This is always the logical negation of [pressed](ActionState::pressed)
983 ///
984 /// # Warning
985 ///
986 /// This value will be `true` by default,
987 /// even if the action is not a buttonlike action.
988 #[inline]
989 #[must_use]
990 #[track_caller]
991 pub fn released(&self, action: &A) -> bool {
992 debug_assert_eq!(action.input_control_kind(), InputControlKind::Button);
993
994 if self.action_disabled(action) {
995 return true;
996 }
997
998 match self.button_data(action) {
999 Some(button_data) => button_data.released(),
1000 None => true,
1001 }
1002 }
1003
1004 /// Was this `action` released since the last time [tick](ActionState::tick) was called?
1005 ///
1006 /// # Warning
1007 ///
1008 /// This value will be `false` by default,
1009 /// even if the action is not a buttonlike action.
1010 #[inline]
1011 #[must_use]
1012 #[track_caller]
1013 pub fn just_released(&self, action: &A) -> bool {
1014 debug_assert_eq!(action.input_control_kind(), InputControlKind::Button);
1015
1016 if self.action_disabled(action) {
1017 return false;
1018 }
1019
1020 match self.button_data(action) {
1021 Some(button_data) => button_data.just_released(),
1022 None => false,
1023 }
1024 }
1025
1026 #[must_use]
1027 /// Which actions are currently pressed?
1028 pub fn get_pressed(&self) -> Vec<A> {
1029 let all_actions = self.action_data.keys().cloned();
1030
1031 all_actions
1032 .into_iter()
1033 .filter(|action| action.input_control_kind() == InputControlKind::Button)
1034 .filter(|action| self.pressed(action))
1035 .collect()
1036 }
1037
1038 #[must_use]
1039 /// Which actions were just pressed?
1040 pub fn get_just_pressed(&self) -> Vec<A> {
1041 let all_actions = self.action_data.keys().cloned();
1042
1043 all_actions
1044 .into_iter()
1045 .filter(|action| action.input_control_kind() == InputControlKind::Button)
1046 .filter(|action| self.just_pressed(action))
1047 .collect()
1048 }
1049
1050 #[must_use]
1051 /// Which actions are currently released?
1052 pub fn get_released(&self) -> Vec<A> {
1053 let all_actions = self.action_data.keys().cloned();
1054
1055 all_actions
1056 .into_iter()
1057 .filter(|action| action.input_control_kind() == InputControlKind::Button)
1058 .filter(|action| self.released(action))
1059 .collect()
1060 }
1061
1062 #[must_use]
1063 /// Which actions were just released?
1064 pub fn get_just_released(&self) -> Vec<A> {
1065 let all_actions = self.action_data.keys().cloned();
1066
1067 all_actions
1068 .into_iter()
1069 .filter(|action| action.input_control_kind() == InputControlKind::Button)
1070 .filter(|action| self.just_released(action))
1071 .collect()
1072 }
1073
1074 /// The [`Instant`] that the action was last pressed or released
1075 ///
1076 ///
1077 ///
1078 /// If the action was pressed or released since the last time [`ActionState::tick`] was called
1079 /// the value will be [`None`].
1080 /// This ensures that all our actions are assigned a timing and duration
1081 /// that corresponds exactly to the start of a frame, rather than relying on idiosyncratic timing.
1082 ///
1083 /// This will also be [`None`] if the action was never pressed or released.
1084 #[cfg(feature = "timing")]
1085 #[must_use]
1086 #[track_caller]
1087 pub fn instant_started(&self, action: &A) -> Option<Instant> {
1088 debug_assert_eq!(action.input_control_kind(), InputControlKind::Button);
1089
1090 let button_data = self.button_data(action)?;
1091 button_data.timing.instant_started
1092 }
1093
1094 /// The [`Duration`] for which the action has been held or released
1095 ///
1096 /// This will be [`Duration::ZERO`] if the action was never pressed or released.
1097 #[cfg(feature = "timing")]
1098 #[must_use]
1099 #[track_caller]
1100 pub fn current_duration(&self, action: &A) -> Duration {
1101 debug_assert_eq!(action.input_control_kind(), InputControlKind::Button);
1102
1103 self.button_data(action)
1104 .map(|data| data.timing.current_duration)
1105 .unwrap_or_default()
1106 }
1107
1108 /// The [`Duration`] for which the action was last held or released
1109 ///
1110 /// This is a snapshot of the [`ActionState::current_duration`] state at the time
1111 /// the action was last pressed or released.
1112 ///
1113 /// This will be [`Duration::ZERO`] if the action was never pressed or released.
1114 #[cfg(feature = "timing")]
1115 #[must_use]
1116 #[track_caller]
1117 pub fn previous_duration(&self, action: &A) -> Duration {
1118 debug_assert_eq!(action.input_control_kind(), InputControlKind::Button);
1119
1120 self.button_data(action)
1121 .map(|data| data.timing.previous_duration)
1122 .unwrap_or_default()
1123 }
1124
1125 /// Applies an [`ActionDiff`] (usually received over the network) to the [`ActionState`].
1126 ///
1127 /// This lets you reconstruct an [`ActionState`] from a stream of [`ActionDiff`]s
1128 pub fn apply_diff(&mut self, action_diff: &ActionDiff<A>) {
1129 match action_diff {
1130 ActionDiff::Pressed { action, value } => {
1131 self.set_button_value(action, *value);
1132 }
1133 ActionDiff::Released { action } => {
1134 self.release(action);
1135 }
1136 ActionDiff::AxisChanged { action, value } => {
1137 self.set_value(action, *value);
1138 }
1139 ActionDiff::DualAxisChanged { action, axis_pair } => {
1140 self.set_axis_pair(action, *axis_pair);
1141 }
1142 ActionDiff::TripleAxisChanged {
1143 action,
1144 axis_triple,
1145 } => {
1146 self.set_axis_triple(action, *axis_triple);
1147 }
1148 };
1149 }
1150
1151 /// Returns an owned list of the [`Actionlike`] keys in this [`ActionState`].
1152 #[inline]
1153 #[must_use]
1154 pub fn keys(&self) -> Vec<A> {
1155 self.action_data.keys().cloned().collect()
1156 }
1157}
1158
1159#[cfg(test)]
1160mod tests {
1161 use crate as leafwing_input_manager;
1162 use crate::action_state::ActionState;
1163 use bevy::prelude::*;
1164 use leafwing_input_manager_macros::Actionlike;
1165
1166 #[cfg(feature = "keyboard")]
1167 #[test]
1168 fn press_lifecycle() {
1169 use std::time::{Duration, Instant};
1170
1171 use crate::input_map::InputMap;
1172 use crate::plugin::CentralInputStorePlugin;
1173 use crate::prelude::updating::CentralInputStore;
1174 use crate::prelude::ClashStrategy;
1175 use crate::user_input::Buttonlike;
1176 use bevy::input::InputPlugin;
1177
1178 let mut app = App::new();
1179 app.add_plugins((InputPlugin, CentralInputStorePlugin));
1180
1181 #[derive(Actionlike, Clone, Copy, PartialEq, Eq, Hash, Debug, bevy::prelude::Reflect)]
1182 enum Action {
1183 Run,
1184 Jump,
1185 Hide,
1186 }
1187
1188 // Action state
1189 let mut action_state = ActionState::<Action>::default();
1190 println!(
1191 "Default button data: {:?}",
1192 action_state.button_data(&Action::Run)
1193 );
1194
1195 // Input map
1196 let mut input_map = InputMap::default();
1197 input_map.insert(Action::Run, KeyCode::KeyR);
1198
1199 // Starting state
1200 let input_store = app.world().resource::<CentralInputStore>();
1201 action_state.update(input_map.process_actions(None, input_store, ClashStrategy::PressAll));
1202
1203 println!(
1204 "Initialized button data: {:?}",
1205 action_state.button_data(&Action::Run)
1206 );
1207
1208 assert!(!action_state.pressed(&Action::Run));
1209 assert!(!action_state.just_pressed(&Action::Run));
1210 assert!(action_state.released(&Action::Run));
1211 assert!(!action_state.just_released(&Action::Run));
1212
1213 // Pressing
1214 KeyCode::KeyR.press(app.world_mut());
1215 // Process the input events into Input<KeyCode> data
1216 app.update();
1217 let input_store = app.world().resource::<CentralInputStore>();
1218
1219 action_state.update(input_map.process_actions(None, input_store, ClashStrategy::PressAll));
1220
1221 assert!(action_state.pressed(&Action::Run));
1222 assert!(action_state.just_pressed(&Action::Run));
1223 assert!(!action_state.released(&Action::Run));
1224 assert!(!action_state.just_released(&Action::Run));
1225
1226 // Waiting
1227 action_state.tick(Instant::now(), Instant::now() - Duration::from_micros(1));
1228 action_state.update(input_map.process_actions(None, input_store, ClashStrategy::PressAll));
1229
1230 assert!(action_state.pressed(&Action::Run));
1231 assert!(!action_state.just_pressed(&Action::Run));
1232 assert!(!action_state.released(&Action::Run));
1233 assert!(!action_state.just_released(&Action::Run));
1234
1235 // Releasing
1236 KeyCode::KeyR.release(app.world_mut());
1237 app.update();
1238 let input_store = app.world().resource::<CentralInputStore>();
1239
1240 action_state.update(input_map.process_actions(None, input_store, ClashStrategy::PressAll));
1241
1242 assert!(!action_state.pressed(&Action::Run));
1243 assert!(!action_state.just_pressed(&Action::Run));
1244 assert!(action_state.released(&Action::Run));
1245 assert!(action_state.just_released(&Action::Run));
1246
1247 // Waiting
1248 action_state.tick(Instant::now(), Instant::now() - Duration::from_micros(1));
1249 action_state.update(input_map.process_actions(None, input_store, ClashStrategy::PressAll));
1250
1251 assert!(!action_state.pressed(&Action::Run));
1252 assert!(!action_state.just_pressed(&Action::Run));
1253 assert!(action_state.released(&Action::Run));
1254 assert!(!action_state.just_released(&Action::Run));
1255 }
1256
1257 #[test]
1258 fn synthetic_press() {
1259 #[derive(Actionlike, Clone, Copy, PartialEq, Eq, Hash, Debug, Reflect)]
1260 enum Action {
1261 One,
1262 Two,
1263 }
1264
1265 let mut action_state = ActionState::<Action>::default();
1266 action_state.press(&Action::One);
1267 dbg!(&action_state);
1268
1269 assert!(action_state.pressed(&Action::One));
1270 assert!(action_state.just_pressed(&Action::One));
1271 assert!(!action_state.released(&Action::One));
1272 assert!(!action_state.just_released(&Action::One));
1273
1274 assert!(!action_state.pressed(&Action::Two));
1275 assert!(!action_state.just_pressed(&Action::Two));
1276 assert!(action_state.released(&Action::Two));
1277 assert!(!action_state.just_released(&Action::Two));
1278 }
1279
1280 #[cfg(feature = "keyboard")]
1281 #[test]
1282 #[ignore = "Clashing inputs for non-buttonlike inputs is broken."]
1283 fn update_with_clashes_prioritizing_longest() {
1284 use std::time::{Duration, Instant};
1285
1286 use crate::input_map::InputMap;
1287 use crate::plugin::CentralInputStorePlugin;
1288 use crate::prelude::updating::CentralInputStore;
1289 use crate::prelude::ClashStrategy;
1290 use crate::user_input::chord::ButtonlikeChord;
1291 use crate::user_input::Buttonlike;
1292 use bevy::input::InputPlugin;
1293 use bevy::prelude::KeyCode::*;
1294 use bevy::prelude::*;
1295
1296 #[derive(Actionlike, Clone, Copy, PartialEq, Eq, Hash, Debug, Reflect)]
1297 enum Action {
1298 One,
1299 Two,
1300 OneAndTwo,
1301 }
1302
1303 // Input map
1304 let mut input_map = InputMap::default();
1305 input_map.insert(Action::One, Digit1);
1306 input_map.insert(Action::Two, Digit2);
1307 input_map.insert(Action::OneAndTwo, ButtonlikeChord::new([Digit1, Digit2]));
1308
1309 let mut app = App::new();
1310 app.add_plugins(InputPlugin)
1311 .add_plugins(CentralInputStorePlugin);
1312
1313 // Action state
1314 let mut action_state = ActionState::<Action>::default();
1315
1316 // Starting state
1317 let input_store = app.world().resource::<CentralInputStore>();
1318 action_state.update(input_map.process_actions(
1319 None,
1320 input_store,
1321 ClashStrategy::PrioritizeLongest,
1322 ));
1323 assert!(action_state.released(&Action::One));
1324 assert!(action_state.released(&Action::Two));
1325 assert!(action_state.released(&Action::OneAndTwo));
1326
1327 // Pressing One
1328 Digit1.press(app.world_mut());
1329 app.update();
1330 let input_store = app.world().resource::<CentralInputStore>();
1331
1332 action_state.update(input_map.process_actions(
1333 None,
1334 input_store,
1335 ClashStrategy::PrioritizeLongest,
1336 ));
1337
1338 assert!(action_state.pressed(&Action::One));
1339 assert!(action_state.released(&Action::Two));
1340 assert!(action_state.released(&Action::OneAndTwo));
1341
1342 // Waiting
1343 action_state.tick(Instant::now(), Instant::now() - Duration::from_micros(1));
1344 action_state.update(input_map.process_actions(
1345 None,
1346 input_store,
1347 ClashStrategy::PrioritizeLongest,
1348 ));
1349
1350 assert!(action_state.pressed(&Action::One));
1351 assert!(action_state.released(&Action::Two));
1352 assert!(action_state.released(&Action::OneAndTwo));
1353
1354 // Pressing Two
1355 Digit2.press(app.world_mut());
1356 app.update();
1357 let input_store = app.world().resource::<CentralInputStore>();
1358
1359 action_state.update(input_map.process_actions(
1360 None,
1361 input_store,
1362 ClashStrategy::PrioritizeLongest,
1363 ));
1364
1365 // Now only the longest OneAndTwo has been pressed,
1366 // while both One and Two have been released
1367 assert!(action_state.released(&Action::One));
1368 assert!(action_state.released(&Action::Two));
1369 assert!(action_state.pressed(&Action::OneAndTwo));
1370
1371 // Waiting
1372 action_state.tick(Instant::now(), Instant::now() - Duration::from_micros(1));
1373 action_state.update(input_map.process_actions(
1374 None,
1375 input_store,
1376 ClashStrategy::PrioritizeLongest,
1377 ));
1378
1379 assert!(action_state.released(&Action::One));
1380 assert!(action_state.released(&Action::Two));
1381 assert!(action_state.pressed(&Action::OneAndTwo));
1382 }
1383}