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