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 debug_assert!(
253 action.input_control_kind() == InputControlKind::Button,
254 "Cannot map a Buttonlike input for action {:?} of kind {:?}",
255 action,
256 action.input_control_kind()
257 );
258
259 if action.input_control_kind() != InputControlKind::Button {
260 error!(
261 "Cannot map a Buttonlike input for action {:?} of kind {:?}",
262 action,
263 action.input_control_kind()
264 );
265
266 return self;
267 }
268
269 insert_unique(&mut self.buttonlike_map, &action, Box::new(button));
270 self
271 }
272
273 #[inline(always)]
279 #[track_caller]
280 pub fn insert_axis(&mut self, action: A, axis: impl Axislike) -> &mut Self {
281 debug_assert!(
282 action.input_control_kind() == InputControlKind::Axis,
283 "Cannot map an Axislike input for action {:?} of kind {:?}",
284 action,
285 action.input_control_kind()
286 );
287
288 if action.input_control_kind() != InputControlKind::Axis {
289 error!(
290 "Cannot map an Axislike input for action {:?} of kind {:?}",
291 action,
292 action.input_control_kind()
293 );
294
295 return self;
296 }
297
298 insert_unique(&mut self.axislike_map, &action, Box::new(axis));
299 self
300 }
301
302 #[inline(always)]
308 #[track_caller]
309 pub fn insert_dual_axis(&mut self, action: A, dual_axis: impl DualAxislike) -> &mut Self {
310 debug_assert!(
311 action.input_control_kind() == InputControlKind::DualAxis,
312 "Cannot map a DualAxislike input for action {:?} of kind {:?}",
313 action,
314 action.input_control_kind()
315 );
316
317 if action.input_control_kind() != InputControlKind::DualAxis {
318 error!(
319 "Cannot map a DualAxislike input for action {:?} of kind {:?}",
320 action,
321 action.input_control_kind()
322 );
323
324 return self;
325 }
326
327 insert_unique(&mut self.dual_axislike_map, &action, Box::new(dual_axis));
328 self
329 }
330
331 #[inline(always)]
337 #[track_caller]
338 pub fn insert_triple_axis(&mut self, action: A, triple_axis: impl TripleAxislike) -> &mut Self {
339 debug_assert!(
340 action.input_control_kind() == InputControlKind::TripleAxis,
341 "Cannot map a TripleAxislike input for action {:?} of kind {:?}",
342 action,
343 action.input_control_kind()
344 );
345
346 if action.input_control_kind() != InputControlKind::TripleAxis {
347 error!(
348 "Cannot map a TripleAxislike input for action {:?} of kind {:?}",
349 action,
350 action.input_control_kind()
351 );
352
353 return self;
354 }
355
356 let boxed = Box::new(triple_axis);
357 insert_unique(&mut self.triple_axislike_map, &action, boxed);
358 self
359 }
360
361 #[inline(always)]
369 pub fn insert_one_to_many(
370 &mut self,
371 action: A,
372 inputs: impl IntoIterator<Item = impl Buttonlike>,
373 ) -> &mut Self {
374 let inputs = inputs
375 .into_iter()
376 .map(|input| Box::new(input) as Box<dyn Buttonlike>);
377 if let Some(bindings) = self.buttonlike_map.get_mut(&action) {
378 for input in inputs {
379 if !bindings.contains(&input) {
380 bindings.push(input);
381 }
382 }
383 } else {
384 self.buttonlike_map
385 .insert(action, inputs.unique().collect());
386 }
387 self
388 }
389
390 #[inline(always)]
396 pub fn insert_multiple(
397 &mut self,
398 bindings: impl IntoIterator<Item = (A, impl Buttonlike)>,
399 ) -> &mut Self {
400 for (action, input) in bindings.into_iter() {
401 self.insert(action, input);
402 }
403 self
404 }
405
406 pub fn merge(&mut self, other: &InputMap<A>) -> &mut Self {
411 if self.associated_gamepad != other.associated_gamepad {
412 self.clear_gamepad();
413 }
414
415 for (other_action, other_inputs) in other.iter_buttonlike() {
416 for other_input in other_inputs.iter().cloned() {
417 insert_unique(&mut self.buttonlike_map, other_action, other_input);
418 }
419 }
420
421 for (other_action, other_inputs) in other.iter_axislike() {
422 for other_input in other_inputs.iter().cloned() {
423 insert_unique(&mut self.axislike_map, other_action, other_input);
424 }
425 }
426
427 for (other_action, other_inputs) in other.iter_dual_axislike() {
428 for other_input in other_inputs.iter().cloned() {
429 insert_unique(&mut self.dual_axislike_map, other_action, other_input);
430 }
431 }
432
433 for (other_action, other_inputs) in other.iter_triple_axislike() {
434 for other_input in other_inputs.iter().cloned() {
435 insert_unique(&mut self.triple_axislike_map, other_action, other_input);
436 }
437 }
438
439 self
440 }
441}
442
443impl<A: Actionlike> InputMap<A> {
445 #[must_use]
449 #[inline]
450 pub const fn gamepad(&self) -> Option<Entity> {
451 self.associated_gamepad
452 }
453
454 #[inline]
466 pub fn with_gamepad(mut self, gamepad: Entity) -> Self {
467 self.set_gamepad(gamepad);
468 self
469 }
470
471 #[inline]
483 pub fn set_gamepad(&mut self, gamepad: Entity) -> &mut Self {
484 self.associated_gamepad = Some(gamepad);
485 self
486 }
487
488 #[inline]
490 pub fn clear_gamepad(&mut self) -> &mut Self {
491 self.associated_gamepad = None;
492 self
493 }
494}
495
496impl<A: Actionlike> InputMap<A> {
498 #[must_use]
502 pub fn pressed(
503 &self,
504 action: &A,
505 input_store: &CentralInputStore,
506 clash_strategy: ClashStrategy,
507 ) -> bool {
508 let processed_actions = self.process_actions(None, input_store, clash_strategy);
509
510 let Some(updated_value) = processed_actions.get(action) else {
511 return false;
512 };
513
514 match updated_value {
515 UpdatedValue::Button(state) => *state,
516 _ => false,
517 }
518 }
519
520 #[must_use]
531 pub fn process_actions(
532 &self,
533 gamepads: Option<Query<Entity, With<Gamepad>>>,
534 input_store: &CentralInputStore,
535 clash_strategy: ClashStrategy,
536 ) -> UpdatedActions<A> {
537 let mut updated_actions = UpdatedActions::default();
538 let gamepad = self.associated_gamepad.unwrap_or(find_gamepad(gamepads));
539
540 for (action, _input_bindings) in self.iter_buttonlike() {
542 let mut final_state = false;
543 for binding in _input_bindings {
544 if binding.pressed(input_store, gamepad) {
545 final_state = true;
546 break;
547 }
548 }
549
550 updated_actions.insert(action.clone(), UpdatedValue::Button(final_state));
551 }
552
553 for (action, _input_bindings) in self.iter_axislike() {
554 let mut final_value = 0.0;
555 for binding in _input_bindings {
556 final_value += binding.value(input_store, gamepad);
557 }
558
559 updated_actions.insert(action.clone(), UpdatedValue::Axis(final_value));
560 }
561
562 for (action, _input_bindings) in self.iter_dual_axislike() {
563 let mut final_value = Vec2::ZERO;
564 for binding in _input_bindings {
565 final_value += binding.axis_pair(input_store, gamepad);
566 }
567
568 updated_actions.insert(action.clone(), UpdatedValue::DualAxis(final_value));
569 }
570
571 for (action, _input_bindings) in self.iter_triple_axislike() {
572 let mut final_value = Vec3::ZERO;
573 for binding in _input_bindings {
574 final_value += binding.axis_triple(input_store, gamepad);
575 }
576
577 updated_actions.insert(action.clone(), UpdatedValue::TripleAxis(final_value));
578 }
579
580 self.handle_clashes(&mut updated_actions, input_store, clash_strategy, gamepad);
582
583 updated_actions
584 }
585}
586
587#[derive(Debug, Clone, PartialEq, Deref, DerefMut)]
590pub struct UpdatedActions<A: Actionlike>(pub HashMap<A, UpdatedValue>);
591
592impl<A: Actionlike> UpdatedActions<A> {
593 pub fn pressed(&self, action: &A) -> bool {
595 match self.0.get(action) {
596 Some(UpdatedValue::Button(state)) => *state,
597 _ => false,
598 }
599 }
600}
601
602#[derive(Debug, Clone, Copy, PartialEq)]
606pub enum UpdatedValue {
607 Button(bool),
609 Axis(f32),
611 DualAxis(Vec2),
613 TripleAxis(Vec3),
615}
616
617impl<A: Actionlike> Default for UpdatedActions<A> {
618 fn default() -> Self {
619 Self(HashMap::default())
620 }
621}
622
623impl<A: Actionlike> InputMap<A> {
625 pub fn iter_buttonlike(&self) -> impl Iterator<Item = (&A, &Vec<Box<dyn Buttonlike>>)> {
627 self.buttonlike_map.iter()
628 }
629
630 pub fn iter_axislike(&self) -> impl Iterator<Item = (&A, &Vec<Box<dyn Axislike>>)> {
632 self.axislike_map.iter()
633 }
634
635 pub fn iter_dual_axislike(&self) -> impl Iterator<Item = (&A, &Vec<Box<dyn DualAxislike>>)> {
637 self.dual_axislike_map.iter()
638 }
639
640 pub fn iter_triple_axislike(
642 &self,
643 ) -> impl Iterator<Item = (&A, &Vec<Box<dyn TripleAxislike>>)> {
644 self.triple_axislike_map.iter()
645 }
646
647 pub fn buttonlike_bindings(&self) -> impl Iterator<Item = (&A, &dyn Buttonlike)> {
649 self.buttonlike_map
650 .iter()
651 .flat_map(|(action, inputs)| inputs.iter().map(move |input| (action, input.as_ref())))
652 }
653
654 pub fn axislike_bindings(&self) -> impl Iterator<Item = (&A, &dyn Axislike)> {
656 self.axislike_map
657 .iter()
658 .flat_map(|(action, inputs)| inputs.iter().map(move |input| (action, input.as_ref())))
659 }
660
661 pub fn dual_axislike_bindings(&self) -> impl Iterator<Item = (&A, &dyn DualAxislike)> {
663 self.dual_axislike_map
664 .iter()
665 .flat_map(|(action, inputs)| inputs.iter().map(move |input| (action, input.as_ref())))
666 }
667
668 pub fn triple_axislike_bindings(&self) -> impl Iterator<Item = (&A, &dyn TripleAxislike)> {
670 self.triple_axislike_map
671 .iter()
672 .flat_map(|(action, inputs)| inputs.iter().map(move |input| (action, input.as_ref())))
673 }
674
675 pub fn buttonlike_actions(&self) -> impl Iterator<Item = &A> {
677 self.buttonlike_map.keys()
678 }
679
680 pub fn axislike_actions(&self) -> impl Iterator<Item = &A> {
682 self.axislike_map.keys()
683 }
684
685 pub fn dual_axislike_actions(&self) -> impl Iterator<Item = &A> {
687 self.dual_axislike_map.keys()
688 }
689
690 pub fn triple_axislike_actions(&self) -> impl Iterator<Item = &A> {
692 self.triple_axislike_map.keys()
693 }
694
695 #[must_use]
704 pub fn get(&self, action: &A) -> Option<Vec<UserInputWrapper>> {
705 match action.input_control_kind() {
706 InputControlKind::Button => {
707 let buttonlike = self.buttonlike_map.get(action)?;
708 Some(
709 buttonlike
710 .iter()
711 .map(|input| UserInputWrapper::Button(input.clone()))
712 .collect(),
713 )
714 }
715 InputControlKind::Axis => {
716 let axislike = self.axislike_map.get(action)?;
717 Some(
718 axislike
719 .iter()
720 .map(|input| UserInputWrapper::Axis(input.clone()))
721 .collect(),
722 )
723 }
724 InputControlKind::DualAxis => {
725 let dual_axislike = self.dual_axislike_map.get(action)?;
726 Some(
727 dual_axislike
728 .iter()
729 .map(|input| UserInputWrapper::DualAxis(input.clone()))
730 .collect(),
731 )
732 }
733 InputControlKind::TripleAxis => {
734 let triple_axislike = self.triple_axislike_map.get(action)?;
735 Some(
736 triple_axislike
737 .iter()
738 .map(|input| UserInputWrapper::TripleAxis(input.clone()))
739 .collect(),
740 )
741 }
742 }
743 }
744
745 #[must_use]
747 pub fn get_buttonlike(&self, action: &A) -> Option<&Vec<Box<dyn Buttonlike>>> {
748 self.buttonlike_map.get(action)
749 }
750
751 #[must_use]
753 pub fn get_buttonlike_mut(&mut self, action: &A) -> Option<&mut Vec<Box<dyn Buttonlike>>> {
754 self.buttonlike_map.get_mut(action)
755 }
756
757 #[must_use]
759 pub fn get_axislike(&self, action: &A) -> Option<&Vec<Box<dyn Axislike>>> {
760 self.axislike_map.get(action)
761 }
762
763 #[must_use]
765 pub fn get_axislike_mut(&mut self, action: &A) -> Option<&mut Vec<Box<dyn Axislike>>> {
766 self.axislike_map.get_mut(action)
767 }
768
769 #[must_use]
771 pub fn get_dual_axislike(&self, action: &A) -> Option<&Vec<Box<dyn DualAxislike>>> {
772 self.dual_axislike_map.get(action)
773 }
774
775 #[must_use]
777 pub fn get_dual_axislike_mut(&mut self, action: &A) -> Option<&mut Vec<Box<dyn DualAxislike>>> {
778 self.dual_axislike_map.get_mut(action)
779 }
780
781 #[must_use]
783 pub fn get_triple_axislike(&self, action: &A) -> Option<&Vec<Box<dyn TripleAxislike>>> {
784 self.triple_axislike_map.get(action)
785 }
786
787 #[must_use]
789 pub fn get_triple_axislike_mut(
790 &mut self,
791 action: &A,
792 ) -> Option<&mut Vec<Box<dyn TripleAxislike>>> {
793 self.triple_axislike_map.get_mut(action)
794 }
795
796 #[must_use]
798 pub fn len(&self) -> usize {
799 self.buttonlike_map.values().map(Vec::len).sum::<usize>()
800 + self.axislike_map.values().map(Vec::len).sum::<usize>()
801 + self.dual_axislike_map.values().map(Vec::len).sum::<usize>()
802 + self
803 .triple_axislike_map
804 .values()
805 .map(Vec::len)
806 .sum::<usize>()
807 }
808
809 #[inline]
811 #[must_use]
812 pub fn is_empty(&self) -> bool {
813 self.len() == 0
814 }
815
816 pub fn clear(&mut self) {
818 self.buttonlike_map.clear();
819 self.axislike_map.clear();
820 self.dual_axislike_map.clear();
821 self.triple_axislike_map.clear();
822 }
823}
824
825impl<A: Actionlike> InputMap<A> {
827 pub fn clear_action(&mut self, action: &A) {
829 match action.input_control_kind() {
830 InputControlKind::Button => {
831 self.buttonlike_map.remove(action);
832 }
833 InputControlKind::Axis => {
834 self.axislike_map.remove(action);
835 }
836 InputControlKind::DualAxis => {
837 self.dual_axislike_map.remove(action);
838 }
839 InputControlKind::TripleAxis => {
840 self.triple_axislike_map.remove(action);
841 }
842 }
843 }
844
845 pub fn remove_at(&mut self, action: &A, index: usize) -> Option<()> {
853 match action.input_control_kind() {
854 InputControlKind::Button => {
855 let input_bindings = self.buttonlike_map.get_mut(action)?;
856 if input_bindings.len() > index {
857 input_bindings.remove(index);
858 Some(())
859 } else {
860 None
861 }
862 }
863 InputControlKind::Axis => {
864 let input_bindings = self.axislike_map.get_mut(action)?;
865 if input_bindings.len() > index {
866 input_bindings.remove(index);
867 Some(())
868 } else {
869 None
870 }
871 }
872 InputControlKind::DualAxis => {
873 let input_bindings = self.dual_axislike_map.get_mut(action)?;
874 if input_bindings.len() > index {
875 input_bindings.remove(index);
876 Some(())
877 } else {
878 None
879 }
880 }
881 InputControlKind::TripleAxis => {
882 let input_bindings = self.triple_axislike_map.get_mut(action)?;
883 if input_bindings.len() > index {
884 input_bindings.remove(index);
885 Some(())
886 } else {
887 None
888 }
889 }
890 }
891 }
892
893 pub fn remove(&mut self, action: &A, input: impl Buttonlike) -> Option<usize> {
897 let bindings = self.buttonlike_map.get_mut(action)?;
898 let boxed_input: Box<dyn Buttonlike> = Box::new(input);
899 let index = bindings.iter().position(|input| input == &boxed_input)?;
900 bindings.remove(index);
901 Some(index)
902 }
903}
904
905impl<A: Actionlike, U: Buttonlike> From<HashMap<A, Vec<U>>> for InputMap<A> {
906 fn from(raw_map: HashMap<A, Vec<U>>) -> Self {
933 let mut input_map = Self::default();
934 for (action, inputs) in raw_map.into_iter() {
935 input_map.insert_one_to_many(action, inputs);
936 }
937 input_map
938 }
939}
940
941impl<A: Actionlike, U: Buttonlike> FromIterator<(A, U)> for InputMap<A> {
942 fn from_iter<T: IntoIterator<Item = (A, U)>>(iter: T) -> Self {
943 let mut input_map = Self::default();
944 for (action, input) in iter.into_iter() {
945 input_map.insert(action, input);
946 }
947 input_map
948 }
949}
950
951#[cfg(feature = "keyboard")]
952mod tests {
953 use bevy::prelude::Reflect;
954 use serde::{Deserialize, Serialize};
955
956 use super::*;
957 use crate as leafwing_input_manager;
958 use crate::prelude::*;
959
960 #[derive(Actionlike, Serialize, Deserialize, Clone, PartialEq, Eq, Hash, Debug, Reflect)]
961 enum Action {
962 Run,
963 Jump,
964 Hide,
965 #[actionlike(Axis)]
966 Axis,
967 #[actionlike(DualAxis)]
968 DualAxis,
969 #[actionlike(TripleAxis)]
970 TripleAxis,
971 }
972
973 #[test]
974 fn creation() {
975 use bevy::input::keyboard::KeyCode;
976
977 let input_map = InputMap::default()
978 .with(Action::Run, KeyCode::KeyW)
979 .with(Action::Run, KeyCode::ShiftLeft)
980 .with(Action::Run, KeyCode::ShiftLeft)
982 .with_one_to_many(Action::Run, [KeyCode::KeyR, KeyCode::ShiftRight])
983 .with_multiple([
984 (Action::Jump, KeyCode::Space),
985 (Action::Hide, KeyCode::ControlLeft),
986 (Action::Hide, KeyCode::ControlRight),
987 ]);
988
989 let expected_bindings: HashMap<Box<dyn Buttonlike>, Action> = [
990 (Box::new(KeyCode::KeyW) as Box<dyn Buttonlike>, Action::Run),
991 (
992 Box::new(KeyCode::ShiftLeft) as Box<dyn Buttonlike>,
993 Action::Run,
994 ),
995 (Box::new(KeyCode::KeyR) as Box<dyn Buttonlike>, Action::Run),
996 (
997 Box::new(KeyCode::ShiftRight) as Box<dyn Buttonlike>,
998 Action::Run,
999 ),
1000 (
1001 Box::new(KeyCode::Space) as Box<dyn Buttonlike>,
1002 Action::Jump,
1003 ),
1004 (
1005 Box::new(KeyCode::ControlLeft) as Box<dyn Buttonlike>,
1006 Action::Hide,
1007 ),
1008 (
1009 Box::new(KeyCode::ControlRight) as Box<dyn Buttonlike>,
1010 Action::Hide,
1011 ),
1012 ]
1013 .into_iter()
1014 .collect();
1015
1016 for (action, input) in input_map.buttonlike_bindings() {
1017 let expected_action = expected_bindings.get(input).unwrap();
1018 assert_eq!(expected_action, action);
1019 }
1020 }
1021
1022 #[test]
1023 fn insertion_idempotency() {
1024 use bevy::input::keyboard::KeyCode;
1025
1026 let mut input_map = InputMap::default();
1027 input_map.insert(Action::Run, KeyCode::Space);
1028
1029 let expected: Vec<Box<dyn Buttonlike>> = vec![Box::new(KeyCode::Space)];
1030 assert_eq!(input_map.get_buttonlike(&Action::Run), Some(&expected));
1031
1032 input_map.insert(Action::Run, KeyCode::Space);
1034 assert_eq!(input_map.get_buttonlike(&Action::Run), Some(&expected));
1035 }
1036
1037 #[test]
1038 fn multiple_insertion() {
1039 use bevy::input::keyboard::KeyCode;
1040
1041 let mut input_map = InputMap::default();
1042 input_map.insert(Action::Run, KeyCode::Space);
1043 input_map.insert(Action::Run, KeyCode::Enter);
1044
1045 let expected: Vec<Box<dyn Buttonlike>> =
1046 vec![Box::new(KeyCode::Space), Box::new(KeyCode::Enter)];
1047 assert_eq!(input_map.get_buttonlike(&Action::Run), Some(&expected));
1048 }
1049
1050 #[test]
1051 fn input_clearing() {
1052 use bevy::input::keyboard::KeyCode;
1053
1054 let mut input_map = InputMap::default();
1055 input_map.insert(Action::Run, KeyCode::Space);
1056
1057 input_map.clear_action(&Action::Run);
1059 assert_eq!(input_map, InputMap::default());
1060
1061 input_map.insert(Action::Run, KeyCode::Space);
1063 input_map.insert(Action::Run, KeyCode::ShiftLeft);
1064 assert!(input_map.remove_at(&Action::Run, 1).is_some());
1065 assert!(
1066 input_map.remove_at(&Action::Run, 1).is_none(),
1067 "Should return None on second removal at the same index"
1068 );
1069 assert!(input_map.remove_at(&Action::Run, 0).is_some());
1070 assert!(
1071 input_map.remove_at(&Action::Run, 0).is_none(),
1072 "Should return None on second removal at the same index"
1073 );
1074 }
1075
1076 #[test]
1077 fn merging() {
1078 use bevy::input::keyboard::KeyCode;
1079
1080 let mut input_map = InputMap::default();
1081 let mut default_keyboard_map = InputMap::default();
1082 default_keyboard_map.insert(Action::Run, KeyCode::ShiftLeft);
1083 default_keyboard_map.insert(
1084 Action::Hide,
1085 ButtonlikeChord::new([KeyCode::ControlLeft, KeyCode::KeyH]),
1086 );
1087
1088 let mut default_gamepad_map = InputMap::default();
1089 default_gamepad_map.insert(Action::Run, KeyCode::Numpad0);
1090 default_gamepad_map.insert(Action::Hide, KeyCode::Numpad7);
1091
1092 input_map.merge(&default_keyboard_map);
1094 assert_eq!(input_map, default_keyboard_map);
1095
1096 input_map.merge(&default_keyboard_map);
1098 assert_eq!(input_map, default_keyboard_map);
1099 }
1100
1101 #[cfg(feature = "gamepad")]
1102 #[test]
1103 fn gamepad_swapping() {
1104 let mut input_map = InputMap::<Action>::default();
1105 assert_eq!(input_map.gamepad(), None);
1106
1107 input_map.set_gamepad(Entity::from_raw(123));
1108 assert_eq!(input_map.gamepad(), Some(Entity::from_raw(123)));
1109
1110 input_map.clear_gamepad();
1111 assert_eq!(input_map.gamepad(), None);
1112 }
1113
1114 #[cfg(feature = "keyboard")]
1115 #[test]
1116 fn input_map_serde() {
1117 use bevy::prelude::{App, KeyCode};
1118 use serde_test::{assert_tokens, Token};
1119
1120 let mut app = App::new();
1121
1122 app.add_plugins(InputManagerPlugin::<Action>::default());
1124
1125 let input_map = InputMap::new([(Action::Hide, KeyCode::ControlLeft)]);
1126 assert_tokens(
1127 &input_map,
1128 &[
1129 Token::Struct {
1130 name: "InputMap",
1131 len: 5,
1132 },
1133 Token::Str("buttonlike_map"),
1134 Token::Map { len: Some(1) },
1135 Token::UnitVariant {
1136 name: "Action",
1137 variant: "Hide",
1138 },
1139 Token::Seq { len: Some(1) },
1140 Token::Map { len: Some(1) },
1141 Token::BorrowedStr("KeyCode"),
1142 Token::UnitVariant {
1143 name: "KeyCode",
1144 variant: "ControlLeft",
1145 },
1146 Token::MapEnd,
1147 Token::SeqEnd,
1148 Token::MapEnd,
1149 Token::Str("axislike_map"),
1150 Token::Map { len: Some(0) },
1151 Token::MapEnd,
1152 Token::Str("dual_axislike_map"),
1153 Token::Map { len: Some(0) },
1154 Token::MapEnd,
1155 Token::Str("triple_axislike_map"),
1156 Token::Map { len: Some(0) },
1157 Token::MapEnd,
1158 Token::Str("associated_gamepad"),
1159 Token::None,
1160 Token::StructEnd,
1161 ],
1162 );
1163 }
1164}