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