1use std::fmt::Debug;
4use std::hash::Hash;
5
6#[cfg(feature = "asset")]
7use bevy::asset::Asset;
8use bevy::platform::collections::HashMap;
9use bevy::prelude::{Component, Deref, DerefMut, Entity, Gamepad, Query, Reflect, Resource, With};
10use bevy::{log::error, prelude::ReflectComponent};
11use bevy::{
12 math::{Vec2, Vec3},
13 prelude::ReflectResource,
14};
15use itertools::Itertools;
16use serde::{Deserialize, Serialize};
17
18use crate::clashing_inputs::ClashStrategy;
19use crate::prelude::updating::CentralInputStore;
20use crate::prelude::{ActionState, UserInputWrapper};
21use crate::user_input::{Axislike, Buttonlike, DualAxislike, TripleAxislike};
22use crate::{Actionlike, InputControlKind};
23
24#[cfg(feature = "gamepad")]
25use crate::user_input::gamepad::find_gamepad;
26
27#[cfg(not(feature = "gamepad"))]
28fn find_gamepad(_: Option<Query<Entity, With<Gamepad>>>) -> Entity {
29 Entity::PLACEHOLDER
30}
31
32#[derive(Resource, Component, Debug, Clone, PartialEq, Eq, Reflect, Serialize, Deserialize)]
105#[require(ActionState::<A>)]
106#[cfg_attr(feature = "asset", derive(Asset))]
107#[reflect(Resource, Component)]
108pub struct InputMap<A: Actionlike> {
109 buttonlike_map: HashMap<A, Vec<Box<dyn Buttonlike>>>,
111
112 axislike_map: HashMap<A, Vec<Box<dyn Axislike>>>,
114
115 dual_axislike_map: HashMap<A, Vec<Box<dyn DualAxislike>>>,
117
118 triple_axislike_map: HashMap<A, Vec<Box<dyn TripleAxislike>>>,
120
121 associated_gamepad: Option<Entity>,
123}
124
125impl<A: Actionlike> Default for InputMap<A> {
126 fn default() -> Self {
127 InputMap {
128 buttonlike_map: HashMap::default(),
129 axislike_map: HashMap::default(),
130 dual_axislike_map: HashMap::default(),
131 triple_axislike_map: HashMap::default(),
132 associated_gamepad: None,
133 }
134 }
135}
136
137impl<A: Actionlike> InputMap<A> {
139 #[inline(always)]
145 pub fn new(bindings: impl IntoIterator<Item = (A, impl Buttonlike)>) -> Self {
146 bindings
147 .into_iter()
148 .fold(Self::default(), |map, (action, input)| {
149 map.with(action, input)
150 })
151 }
152
153 #[inline(always)]
159 pub fn with(mut self, action: A, button: impl Buttonlike) -> Self {
160 self.insert(action, button);
161 self
162 }
163
164 #[inline(always)]
170 pub fn with_axis(mut self, action: A, axis: impl Axislike) -> Self {
171 self.insert_axis(action, axis);
172 self
173 }
174
175 #[inline(always)]
181 pub fn with_dual_axis(mut self, action: A, dual_axis: impl DualAxislike) -> Self {
182 self.insert_dual_axis(action, dual_axis);
183 self
184 }
185
186 #[inline(always)]
192 pub fn with_triple_axis(mut self, action: A, triple_axis: impl TripleAxislike) -> Self {
193 self.insert_triple_axis(action, triple_axis);
194 self
195 }
196
197 #[inline(always)]
203 pub fn with_one_to_many(
204 mut self,
205 action: A,
206 inputs: impl IntoIterator<Item = impl Buttonlike>,
207 ) -> Self {
208 self.insert_one_to_many(action, inputs);
209 self
210 }
211
212 #[inline(always)]
218 pub fn with_multiple(
219 mut self,
220 bindings: impl IntoIterator<Item = (A, impl Buttonlike)>,
221 ) -> Self {
222 self.insert_multiple(bindings);
223 self
224 }
225}
226
227#[inline(always)]
228fn insert_unique<K, V>(map: &mut HashMap<K, Vec<V>>, key: &K, value: V)
229where
230 K: Clone + Eq + Hash,
231 V: PartialEq,
232{
233 if let Some(list) = map.get_mut(key) {
234 if !list.contains(&value) {
235 list.push(value);
236 }
237 } else {
238 map.insert(key.clone(), vec![value]);
239 }
240}
241
242impl<A: Actionlike> InputMap<A> {
244 #[inline(always)]
250 #[track_caller]
251 pub fn insert(&mut self, action: A, button: impl Buttonlike) -> &mut Self {
252 self.insert_boxed(action, Box::new(button));
253 self
254 }
255
256 #[inline(always)]
261 #[track_caller]
262 pub fn insert_boxed(&mut self, action: A, button: Box<dyn Buttonlike>) -> &mut Self {
263 debug_assert!(
264 action.input_control_kind() == InputControlKind::Button,
265 "Cannot map a Buttonlike input for action {:?} of kind {:?}",
266 action,
267 action.input_control_kind()
268 );
269
270 if action.input_control_kind() != InputControlKind::Button {
271 error!(
272 "Cannot map a Buttonlike input for action {:?} of kind {:?}",
273 action,
274 action.input_control_kind()
275 );
276
277 return self;
278 }
279
280 insert_unique(&mut self.buttonlike_map, &action, button);
281 self
282 }
283
284 #[inline(always)]
290 #[track_caller]
291 pub fn insert_axis(&mut self, action: A, axis: impl Axislike) -> &mut Self {
292 self.insert_axis_boxed(action, Box::new(axis));
293 self
294 }
295
296 #[inline(always)]
301 #[track_caller]
302 pub fn insert_axis_boxed(&mut self, action: A, axis: Box<dyn Axislike>) -> &mut Self {
303 debug_assert!(
304 action.input_control_kind() == InputControlKind::Axis,
305 "Cannot map an Axislike input for action {:?} of kind {:?}",
306 action,
307 action.input_control_kind()
308 );
309
310 if action.input_control_kind() != InputControlKind::Axis {
311 error!(
312 "Cannot map an Axislike input for action {:?} of kind {:?}",
313 action,
314 action.input_control_kind()
315 );
316
317 return self;
318 }
319
320 insert_unique(&mut self.axislike_map, &action, axis);
321 self
322 }
323
324 #[inline(always)]
330 #[track_caller]
331 pub fn insert_dual_axis(&mut self, action: A, dual_axis: impl DualAxislike) -> &mut Self {
332 self.insert_dual_axis_boxed(action, Box::new(dual_axis));
333 self
334 }
335
336 #[inline(always)]
341 #[track_caller]
342 pub fn insert_dual_axis_boxed(&mut self, action: A, axis: Box<dyn DualAxislike>) -> &mut Self {
343 debug_assert!(
344 action.input_control_kind() == InputControlKind::DualAxis,
345 "Cannot map a DualAxislike input for action {:?} of kind {:?}",
346 action,
347 action.input_control_kind()
348 );
349
350 if action.input_control_kind() != InputControlKind::DualAxis {
351 error!(
352 "Cannot map a DualAxislike input for action {:?} of kind {:?}",
353 action,
354 action.input_control_kind()
355 );
356
357 return self;
358 }
359
360 insert_unique(&mut self.dual_axislike_map, &action, axis);
361 self
362 }
363
364 #[inline(always)]
370 #[track_caller]
371 pub fn insert_triple_axis(&mut self, action: A, triple_axis: impl TripleAxislike) -> &mut Self {
372 self.insert_triple_axis_boxed(action, Box::new(triple_axis));
373 self
374 }
375
376 #[inline(always)]
381 #[track_caller]
382 pub fn insert_triple_axis_boxed(
383 &mut self,
384 action: A,
385 triple_axis: Box<dyn TripleAxislike>,
386 ) -> &mut Self {
387 debug_assert!(
388 action.input_control_kind() == InputControlKind::TripleAxis,
389 "Cannot map a TripleAxislike input for action {:?} of kind {:?}",
390 action,
391 action.input_control_kind()
392 );
393
394 if action.input_control_kind() != InputControlKind::TripleAxis {
395 error!(
396 "Cannot map a TripleAxislike input for action {:?} of kind {:?}",
397 action,
398 action.input_control_kind()
399 );
400
401 return self;
402 }
403
404 insert_unique(&mut self.triple_axislike_map, &action, triple_axis);
405 self
406 }
407
408 #[inline(always)]
416 pub fn insert_one_to_many(
417 &mut self,
418 action: A,
419 inputs: impl IntoIterator<Item = impl Buttonlike>,
420 ) -> &mut Self {
421 let inputs = inputs
422 .into_iter()
423 .map(|input| Box::new(input) as Box<dyn Buttonlike>);
424 self.insert_one_to_many_boxed(action, inputs);
425 self
426 }
427
428 #[inline(always)]
433 pub fn insert_one_to_many_boxed(
434 &mut self,
435 action: A,
436 inputs: impl IntoIterator<Item = Box<dyn Buttonlike>>,
437 ) -> &mut Self {
438 let inputs = inputs.into_iter();
439 if let Some(bindings) = self.buttonlike_map.get_mut(&action) {
440 for input in inputs {
441 if !bindings.contains(&input) {
442 bindings.push(input);
443 }
444 }
445 } else {
446 self.buttonlike_map
447 .insert(action, inputs.unique().collect());
448 }
449 self
450 }
451
452 #[inline(always)]
458 pub fn insert_multiple(
459 &mut self,
460 bindings: impl IntoIterator<Item = (A, impl Buttonlike)>,
461 ) -> &mut Self {
462 for (action, input) in bindings.into_iter() {
463 self.insert(action, input);
464 }
465 self
466 }
467
468 #[inline(always)]
473 pub fn insert_multiple_boxed(
474 &mut self,
475 bindings: impl IntoIterator<Item = (A, Box<dyn Buttonlike>)>,
476 ) -> &mut Self {
477 for (action, input) in bindings.into_iter() {
478 self.insert_boxed(action, input);
479 }
480 self
481 }
482
483 pub fn merge(&mut self, other: &InputMap<A>) -> &mut Self {
488 if self.associated_gamepad != other.associated_gamepad {
489 self.clear_gamepad();
490 }
491
492 for (other_action, other_inputs) in other.iter_buttonlike() {
493 for other_input in other_inputs.iter().cloned() {
494 insert_unique(&mut self.buttonlike_map, other_action, other_input);
495 }
496 }
497
498 for (other_action, other_inputs) in other.iter_axislike() {
499 for other_input in other_inputs.iter().cloned() {
500 insert_unique(&mut self.axislike_map, other_action, other_input);
501 }
502 }
503
504 for (other_action, other_inputs) in other.iter_dual_axislike() {
505 for other_input in other_inputs.iter().cloned() {
506 insert_unique(&mut self.dual_axislike_map, other_action, other_input);
507 }
508 }
509
510 for (other_action, other_inputs) in other.iter_triple_axislike() {
511 for other_input in other_inputs.iter().cloned() {
512 insert_unique(&mut self.triple_axislike_map, other_action, other_input);
513 }
514 }
515
516 self
517 }
518}
519
520impl<A: Actionlike> InputMap<A> {
522 #[must_use]
526 #[inline]
527 pub const fn gamepad(&self) -> Option<Entity> {
528 self.associated_gamepad
529 }
530
531 #[inline]
543 pub fn with_gamepad(mut self, gamepad: Entity) -> Self {
544 self.set_gamepad(gamepad);
545 self
546 }
547
548 #[inline]
560 pub fn set_gamepad(&mut self, gamepad: Entity) -> &mut Self {
561 self.associated_gamepad = Some(gamepad);
562 self
563 }
564
565 #[inline]
567 pub fn clear_gamepad(&mut self) -> &mut Self {
568 self.associated_gamepad = None;
569 self
570 }
571}
572
573impl<A: Actionlike> InputMap<A> {
575 #[must_use]
579 pub fn pressed(
580 &self,
581 action: &A,
582 input_store: &CentralInputStore,
583 clash_strategy: ClashStrategy,
584 ) -> bool {
585 let processed_actions = self.process_actions(None, input_store, clash_strategy);
586
587 let Some(updated_value) = processed_actions.get(action) else {
588 return false;
589 };
590
591 match updated_value {
592 UpdatedValue::Button(state) => *state,
593 _ => false,
594 }
595 }
596
597 #[must_use]
608 pub fn process_actions(
609 &self,
610 gamepads: Option<Query<Entity, With<Gamepad>>>,
611 input_store: &CentralInputStore,
612 clash_strategy: ClashStrategy,
613 ) -> UpdatedActions<A> {
614 let mut updated_actions = UpdatedActions::default();
615 let gamepad = self.associated_gamepad.unwrap_or(find_gamepad(gamepads));
616
617 for (action, _input_bindings) in self.iter_buttonlike() {
619 let mut final_state = false;
620 for binding in _input_bindings {
621 if binding.pressed(input_store, gamepad) {
622 final_state = true;
623 break;
624 }
625 }
626
627 updated_actions.insert(action.clone(), UpdatedValue::Button(final_state));
628 }
629
630 for (action, _input_bindings) in self.iter_axislike() {
631 let mut final_value = 0.0;
632 for binding in _input_bindings {
633 final_value += binding.value(input_store, gamepad);
634 }
635
636 updated_actions.insert(action.clone(), UpdatedValue::Axis(final_value));
637 }
638
639 for (action, _input_bindings) in self.iter_dual_axislike() {
640 let mut final_value = Vec2::ZERO;
641 for binding in _input_bindings {
642 final_value += binding.axis_pair(input_store, gamepad);
643 }
644
645 updated_actions.insert(action.clone(), UpdatedValue::DualAxis(final_value));
646 }
647
648 for (action, _input_bindings) in self.iter_triple_axislike() {
649 let mut final_value = Vec3::ZERO;
650 for binding in _input_bindings {
651 final_value += binding.axis_triple(input_store, gamepad);
652 }
653
654 updated_actions.insert(action.clone(), UpdatedValue::TripleAxis(final_value));
655 }
656
657 self.handle_clashes(&mut updated_actions, input_store, clash_strategy, gamepad);
659
660 updated_actions
661 }
662}
663
664#[derive(Debug, Clone, PartialEq, Deref, DerefMut)]
667pub struct UpdatedActions<A: Actionlike>(pub HashMap<A, UpdatedValue>);
668
669impl<A: Actionlike> UpdatedActions<A> {
670 pub fn pressed(&self, action: &A) -> bool {
672 match self.0.get(action) {
673 Some(UpdatedValue::Button(state)) => *state,
674 _ => false,
675 }
676 }
677}
678
679#[derive(Debug, Clone, Copy, PartialEq)]
683pub enum UpdatedValue {
684 Button(bool),
686 Axis(f32),
688 DualAxis(Vec2),
690 TripleAxis(Vec3),
692}
693
694impl<A: Actionlike> Default for UpdatedActions<A> {
695 fn default() -> Self {
696 Self(HashMap::default())
697 }
698}
699
700impl<A: Actionlike> InputMap<A> {
702 pub fn iter_buttonlike(&self) -> impl Iterator<Item = (&A, &Vec<Box<dyn Buttonlike>>)> {
704 self.buttonlike_map.iter()
705 }
706
707 pub fn iter_axislike(&self) -> impl Iterator<Item = (&A, &Vec<Box<dyn Axislike>>)> {
709 self.axislike_map.iter()
710 }
711
712 pub fn iter_dual_axislike(&self) -> impl Iterator<Item = (&A, &Vec<Box<dyn DualAxislike>>)> {
714 self.dual_axislike_map.iter()
715 }
716
717 pub fn iter_triple_axislike(
719 &self,
720 ) -> impl Iterator<Item = (&A, &Vec<Box<dyn TripleAxislike>>)> {
721 self.triple_axislike_map.iter()
722 }
723
724 pub fn buttonlike_bindings(&self) -> impl Iterator<Item = (&A, &dyn Buttonlike)> {
726 self.buttonlike_map
727 .iter()
728 .flat_map(|(action, inputs)| inputs.iter().map(move |input| (action, input.as_ref())))
729 }
730
731 pub fn axislike_bindings(&self) -> impl Iterator<Item = (&A, &dyn Axislike)> {
733 self.axislike_map
734 .iter()
735 .flat_map(|(action, inputs)| inputs.iter().map(move |input| (action, input.as_ref())))
736 }
737
738 pub fn dual_axislike_bindings(&self) -> impl Iterator<Item = (&A, &dyn DualAxislike)> {
740 self.dual_axislike_map
741 .iter()
742 .flat_map(|(action, inputs)| inputs.iter().map(move |input| (action, input.as_ref())))
743 }
744
745 pub fn triple_axislike_bindings(&self) -> impl Iterator<Item = (&A, &dyn TripleAxislike)> {
747 self.triple_axislike_map
748 .iter()
749 .flat_map(|(action, inputs)| inputs.iter().map(move |input| (action, input.as_ref())))
750 }
751
752 pub fn buttonlike_actions(&self) -> impl Iterator<Item = &A> {
754 self.buttonlike_map.keys()
755 }
756
757 pub fn axislike_actions(&self) -> impl Iterator<Item = &A> {
759 self.axislike_map.keys()
760 }
761
762 pub fn dual_axislike_actions(&self) -> impl Iterator<Item = &A> {
764 self.dual_axislike_map.keys()
765 }
766
767 pub fn triple_axislike_actions(&self) -> impl Iterator<Item = &A> {
769 self.triple_axislike_map.keys()
770 }
771
772 #[must_use]
781 pub fn get(&self, action: &A) -> Option<Vec<UserInputWrapper>> {
782 match action.input_control_kind() {
783 InputControlKind::Button => {
784 let buttonlike = self.buttonlike_map.get(action)?;
785 Some(
786 buttonlike
787 .iter()
788 .map(|input| UserInputWrapper::Button(input.clone()))
789 .collect(),
790 )
791 }
792 InputControlKind::Axis => {
793 let axislike = self.axislike_map.get(action)?;
794 Some(
795 axislike
796 .iter()
797 .map(|input| UserInputWrapper::Axis(input.clone()))
798 .collect(),
799 )
800 }
801 InputControlKind::DualAxis => {
802 let dual_axislike = self.dual_axislike_map.get(action)?;
803 Some(
804 dual_axislike
805 .iter()
806 .map(|input| UserInputWrapper::DualAxis(input.clone()))
807 .collect(),
808 )
809 }
810 InputControlKind::TripleAxis => {
811 let triple_axislike = self.triple_axislike_map.get(action)?;
812 Some(
813 triple_axislike
814 .iter()
815 .map(|input| UserInputWrapper::TripleAxis(input.clone()))
816 .collect(),
817 )
818 }
819 }
820 }
821
822 #[must_use]
824 pub fn get_buttonlike(&self, action: &A) -> Option<&Vec<Box<dyn Buttonlike>>> {
825 self.buttonlike_map.get(action)
826 }
827
828 #[must_use]
830 pub fn get_buttonlike_mut(&mut self, action: &A) -> Option<&mut Vec<Box<dyn Buttonlike>>> {
831 self.buttonlike_map.get_mut(action)
832 }
833
834 #[must_use]
836 pub fn get_axislike(&self, action: &A) -> Option<&Vec<Box<dyn Axislike>>> {
837 self.axislike_map.get(action)
838 }
839
840 #[must_use]
842 pub fn get_axislike_mut(&mut self, action: &A) -> Option<&mut Vec<Box<dyn Axislike>>> {
843 self.axislike_map.get_mut(action)
844 }
845
846 #[must_use]
848 pub fn get_dual_axislike(&self, action: &A) -> Option<&Vec<Box<dyn DualAxislike>>> {
849 self.dual_axislike_map.get(action)
850 }
851
852 #[must_use]
854 pub fn get_dual_axislike_mut(&mut self, action: &A) -> Option<&mut Vec<Box<dyn DualAxislike>>> {
855 self.dual_axislike_map.get_mut(action)
856 }
857
858 #[must_use]
860 pub fn get_triple_axislike(&self, action: &A) -> Option<&Vec<Box<dyn TripleAxislike>>> {
861 self.triple_axislike_map.get(action)
862 }
863
864 #[must_use]
866 pub fn get_triple_axislike_mut(
867 &mut self,
868 action: &A,
869 ) -> Option<&mut Vec<Box<dyn TripleAxislike>>> {
870 self.triple_axislike_map.get_mut(action)
871 }
872
873 #[must_use]
875 pub fn len(&self) -> usize {
876 self.buttonlike_map.values().map(Vec::len).sum::<usize>()
877 + self.axislike_map.values().map(Vec::len).sum::<usize>()
878 + self.dual_axislike_map.values().map(Vec::len).sum::<usize>()
879 + self
880 .triple_axislike_map
881 .values()
882 .map(Vec::len)
883 .sum::<usize>()
884 }
885
886 #[inline]
888 #[must_use]
889 pub fn is_empty(&self) -> bool {
890 self.len() == 0
891 }
892
893 pub fn clear(&mut self) {
895 self.buttonlike_map.clear();
896 self.axislike_map.clear();
897 self.dual_axislike_map.clear();
898 self.triple_axislike_map.clear();
899 }
900}
901
902impl<A: Actionlike> InputMap<A> {
904 pub fn clear_action(&mut self, action: &A) {
906 match action.input_control_kind() {
907 InputControlKind::Button => {
908 self.buttonlike_map.remove(action);
909 }
910 InputControlKind::Axis => {
911 self.axislike_map.remove(action);
912 }
913 InputControlKind::DualAxis => {
914 self.dual_axislike_map.remove(action);
915 }
916 InputControlKind::TripleAxis => {
917 self.triple_axislike_map.remove(action);
918 }
919 }
920 }
921
922 pub fn remove_at(&mut self, action: &A, index: usize) -> Option<()> {
930 match action.input_control_kind() {
931 InputControlKind::Button => {
932 let input_bindings = self.buttonlike_map.get_mut(action)?;
933 if input_bindings.len() > index {
934 input_bindings.remove(index);
935 Some(())
936 } else {
937 None
938 }
939 }
940 InputControlKind::Axis => {
941 let input_bindings = self.axislike_map.get_mut(action)?;
942 if input_bindings.len() > index {
943 input_bindings.remove(index);
944 Some(())
945 } else {
946 None
947 }
948 }
949 InputControlKind::DualAxis => {
950 let input_bindings = self.dual_axislike_map.get_mut(action)?;
951 if input_bindings.len() > index {
952 input_bindings.remove(index);
953 Some(())
954 } else {
955 None
956 }
957 }
958 InputControlKind::TripleAxis => {
959 let input_bindings = self.triple_axislike_map.get_mut(action)?;
960 if input_bindings.len() > index {
961 input_bindings.remove(index);
962 Some(())
963 } else {
964 None
965 }
966 }
967 }
968 }
969
970 pub fn remove(&mut self, action: &A, input: impl Buttonlike) -> Option<usize> {
974 let bindings = self.buttonlike_map.get_mut(action)?;
975 let boxed_input: Box<dyn Buttonlike> = Box::new(input);
976 let index = bindings.iter().position(|input| input == &boxed_input)?;
977 bindings.remove(index);
978 Some(index)
979 }
980}
981
982impl<A: Actionlike, U: Buttonlike> From<HashMap<A, Vec<U>>> for InputMap<A> {
983 fn from(raw_map: HashMap<A, Vec<U>>) -> Self {
1010 let mut input_map = Self::default();
1011 for (action, inputs) in raw_map.into_iter() {
1012 input_map.insert_one_to_many(action, inputs);
1013 }
1014 input_map
1015 }
1016}
1017
1018impl<A: Actionlike, U: Buttonlike> FromIterator<(A, U)> for InputMap<A> {
1019 fn from_iter<T: IntoIterator<Item = (A, U)>>(iter: T) -> Self {
1020 let mut input_map = Self::default();
1021 for (action, input) in iter.into_iter() {
1022 input_map.insert(action, input);
1023 }
1024 input_map
1025 }
1026}
1027
1028#[cfg(feature = "keyboard")]
1029mod tests {
1030 use bevy::prelude::Reflect;
1031 use serde::{Deserialize, Serialize};
1032
1033 use super::*;
1034 use crate as leafwing_input_manager;
1035 use crate::prelude::*;
1036
1037 #[derive(Actionlike, Serialize, Deserialize, Clone, PartialEq, Eq, Hash, Debug, Reflect)]
1038 enum Action {
1039 Run,
1040 Jump,
1041 Hide,
1042 #[actionlike(Axis)]
1043 Axis,
1044 #[actionlike(DualAxis)]
1045 DualAxis,
1046 #[actionlike(TripleAxis)]
1047 TripleAxis,
1048 }
1049
1050 #[test]
1051 fn creation() {
1052 use bevy::input::keyboard::KeyCode;
1053
1054 let input_map = InputMap::default()
1055 .with(Action::Run, KeyCode::KeyW)
1056 .with(Action::Run, KeyCode::ShiftLeft)
1057 .with(Action::Run, KeyCode::ShiftLeft)
1059 .with_one_to_many(Action::Run, [KeyCode::KeyR, KeyCode::ShiftRight])
1060 .with_multiple([
1061 (Action::Jump, KeyCode::Space),
1062 (Action::Hide, KeyCode::ControlLeft),
1063 (Action::Hide, KeyCode::ControlRight),
1064 ]);
1065
1066 let expected_bindings: HashMap<Box<dyn Buttonlike>, Action> = [
1067 (Box::new(KeyCode::KeyW) as Box<dyn Buttonlike>, Action::Run),
1068 (
1069 Box::new(KeyCode::ShiftLeft) as Box<dyn Buttonlike>,
1070 Action::Run,
1071 ),
1072 (Box::new(KeyCode::KeyR) as Box<dyn Buttonlike>, Action::Run),
1073 (
1074 Box::new(KeyCode::ShiftRight) as Box<dyn Buttonlike>,
1075 Action::Run,
1076 ),
1077 (
1078 Box::new(KeyCode::Space) as Box<dyn Buttonlike>,
1079 Action::Jump,
1080 ),
1081 (
1082 Box::new(KeyCode::ControlLeft) as Box<dyn Buttonlike>,
1083 Action::Hide,
1084 ),
1085 (
1086 Box::new(KeyCode::ControlRight) as Box<dyn Buttonlike>,
1087 Action::Hide,
1088 ),
1089 ]
1090 .into_iter()
1091 .collect();
1092
1093 for (action, input) in input_map.buttonlike_bindings() {
1094 let expected_action = expected_bindings.get(input).unwrap();
1095 assert_eq!(expected_action, action);
1096 }
1097 }
1098
1099 #[test]
1100 fn insertion_idempotency() {
1101 use bevy::input::keyboard::KeyCode;
1102
1103 let mut input_map = InputMap::default();
1104 input_map.insert(Action::Run, KeyCode::Space);
1105
1106 let expected: Vec<Box<dyn Buttonlike>> = vec![Box::new(KeyCode::Space)];
1107 assert_eq!(input_map.get_buttonlike(&Action::Run), Some(&expected));
1108
1109 input_map.insert(Action::Run, KeyCode::Space);
1111 assert_eq!(input_map.get_buttonlike(&Action::Run), Some(&expected));
1112 }
1113
1114 #[test]
1115 fn multiple_insertion() {
1116 use bevy::input::keyboard::KeyCode;
1117
1118 let mut input_map = InputMap::default();
1119 input_map.insert(Action::Run, KeyCode::Space);
1120 input_map.insert(Action::Run, KeyCode::Enter);
1121
1122 let expected: Vec<Box<dyn Buttonlike>> =
1123 vec![Box::new(KeyCode::Space), Box::new(KeyCode::Enter)];
1124 assert_eq!(input_map.get_buttonlike(&Action::Run), Some(&expected));
1125 }
1126
1127 #[test]
1128 fn input_clearing() {
1129 use bevy::input::keyboard::KeyCode;
1130
1131 let mut input_map = InputMap::default();
1132 input_map.insert(Action::Run, KeyCode::Space);
1133
1134 input_map.clear_action(&Action::Run);
1136 assert_eq!(input_map, InputMap::default());
1137
1138 input_map.insert(Action::Run, KeyCode::Space);
1140 input_map.insert(Action::Run, KeyCode::ShiftLeft);
1141 assert!(input_map.remove_at(&Action::Run, 1).is_some());
1142 assert!(
1143 input_map.remove_at(&Action::Run, 1).is_none(),
1144 "Should return None on second removal at the same index"
1145 );
1146 assert!(input_map.remove_at(&Action::Run, 0).is_some());
1147 assert!(
1148 input_map.remove_at(&Action::Run, 0).is_none(),
1149 "Should return None on second removal at the same index"
1150 );
1151 }
1152
1153 #[test]
1154 fn merging() {
1155 use bevy::input::keyboard::KeyCode;
1156
1157 let mut input_map = InputMap::default();
1158 let mut default_keyboard_map = InputMap::default();
1159 default_keyboard_map.insert(Action::Run, KeyCode::ShiftLeft);
1160 default_keyboard_map.insert(
1161 Action::Hide,
1162 ButtonlikeChord::new([KeyCode::ControlLeft, KeyCode::KeyH]),
1163 );
1164
1165 let mut default_gamepad_map = InputMap::default();
1166 default_gamepad_map.insert(Action::Run, KeyCode::Numpad0);
1167 default_gamepad_map.insert(Action::Hide, KeyCode::Numpad7);
1168
1169 input_map.merge(&default_keyboard_map);
1171 assert_eq!(input_map, default_keyboard_map);
1172
1173 input_map.merge(&default_keyboard_map);
1175 assert_eq!(input_map, default_keyboard_map);
1176 }
1177
1178 #[cfg(feature = "gamepad")]
1179 #[test]
1180 fn gamepad_swapping() {
1181 let mut input_map = InputMap::<Action>::default();
1182 assert_eq!(input_map.gamepad(), None);
1183
1184 input_map.set_gamepad(Entity::from_raw(123));
1185 assert_eq!(input_map.gamepad(), Some(Entity::from_raw(123)));
1186
1187 input_map.clear_gamepad();
1188 assert_eq!(input_map.gamepad(), None);
1189 }
1190
1191 #[cfg(feature = "keyboard")]
1192 #[test]
1193 fn input_map_serde() {
1194 use bevy::prelude::{App, KeyCode};
1195 use serde_test::{assert_tokens, Token};
1196
1197 let mut app = App::new();
1198
1199 app.add_plugins(InputManagerPlugin::<Action>::default());
1201
1202 let input_map = InputMap::new([(Action::Hide, KeyCode::ControlLeft)]);
1203 assert_tokens(
1204 &input_map,
1205 &[
1206 Token::Struct {
1207 name: "InputMap",
1208 len: 5,
1209 },
1210 Token::Str("buttonlike_map"),
1211 Token::Map { len: Some(1) },
1212 Token::UnitVariant {
1213 name: "Action",
1214 variant: "Hide",
1215 },
1216 Token::Seq { len: Some(1) },
1217 Token::Map { len: Some(1) },
1218 Token::BorrowedStr("KeyCode"),
1219 Token::UnitVariant {
1220 name: "KeyCode",
1221 variant: "ControlLeft",
1222 },
1223 Token::MapEnd,
1224 Token::SeqEnd,
1225 Token::MapEnd,
1226 Token::Str("axislike_map"),
1227 Token::Map { len: Some(0) },
1228 Token::MapEnd,
1229 Token::Str("dual_axislike_map"),
1230 Token::Map { len: Some(0) },
1231 Token::MapEnd,
1232 Token::Str("triple_axislike_map"),
1233 Token::Map { len: Some(0) },
1234 Token::MapEnd,
1235 Token::Str("associated_gamepad"),
1236 Token::None,
1237 Token::StructEnd,
1238 ],
1239 );
1240 }
1241}