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