1use std::hash::{Hash, Hasher};
4
5use bevy::ecs::message::Messages;
6use bevy::ecs::system::lifetimeless::{Read, SQuery};
7use bevy::ecs::system::{StaticSystemParam, SystemParam, SystemState};
8use bevy::input::gamepad::{
9 GamepadInput, RawGamepadAxisChangedEvent, RawGamepadButtonChangedEvent, RawGamepadEvent,
10};
11use bevy::input::{Axis, ButtonInput};
12use bevy::math::FloatOrd;
13use bevy::prelude::{
14 Entity, Gamepad, GamepadAxis, GamepadButton, Query, Reflect, Res, ResMut, Vec2, With, World,
15};
16use leafwing_input_manager_macros::serde_typetag;
17use serde::{Deserialize, Serialize};
18
19use crate as leafwing_input_manager;
20use crate::axislike::AxisDirection;
21use crate::buttonlike::ButtonValue;
22use crate::clashing_inputs::BasicInputs;
23use crate::input_processing::{
24 AxisProcessor, DualAxisProcessor, WithAxisProcessingPipelineExt,
25 WithDualAxisProcessingPipelineExt,
26};
27use crate::user_input::UserInput;
28use crate::InputControlKind;
29
30use super::updating::{CentralInputStore, UpdatableInput};
31use super::{Axislike, Buttonlike, DualAxislike};
32
33#[must_use]
37pub fn find_gamepad(gamepads: Option<Query<Entity, With<Gamepad>>>) -> Entity {
38 match gamepads {
39 None => Entity::PLACEHOLDER,
40 Some(gamepads) => gamepads.iter().next().unwrap_or(Entity::PLACEHOLDER),
41 }
42}
43
44#[must_use]
46#[inline]
47fn read_axis_value(input_store: &CentralInputStore, gamepad: Entity, axis: GamepadAxis) -> f32 {
48 let axis = SpecificGamepadAxis::new(gamepad, axis);
49 input_store.value(&axis)
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
54pub struct SpecificGamepadAxis {
55 pub gamepad: Entity,
57 pub axis: GamepadAxis,
59}
60
61impl SpecificGamepadAxis {
62 pub fn new(gamepad: Entity, axis: GamepadAxis) -> Self {
64 Self { gamepad, axis }
65 }
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
70pub struct SpecificGamepadButton {
71 pub gamepad: Entity,
73 pub button: GamepadButton,
75}
76
77impl SpecificGamepadButton {
78 pub fn new(gamepad: Entity, button: GamepadButton) -> Self {
81 Self { gamepad, button }
82 }
83}
84
85#[derive(Debug, Clone, Copy, PartialEq, Reflect, Serialize, Deserialize)]
113#[must_use]
114pub struct GamepadControlDirection {
115 pub axis: GamepadAxis,
117
118 pub direction: AxisDirection,
120
121 pub threshold: f32,
124}
125
126impl GamepadControlDirection {
127 #[inline]
129 pub const fn negative(axis: GamepadAxis) -> Self {
130 Self {
131 axis,
132 direction: AxisDirection::Negative,
133 threshold: 0.0,
134 }
135 }
136
137 #[inline]
139 pub const fn positive(axis: GamepadAxis) -> Self {
140 Self {
141 axis,
142 direction: AxisDirection::Positive,
143 threshold: 0.0,
144 }
145 }
146
147 #[inline]
157 pub fn threshold(mut self, threshold: f32) -> Self {
158 assert!(threshold >= 0.0);
159 self.threshold = threshold;
160 self
161 }
162
163 pub const LEFT_UP: Self = Self::positive(GamepadAxis::LeftStickY);
165
166 pub const LEFT_DOWN: Self = Self::negative(GamepadAxis::LeftStickY);
168
169 pub const LEFT_LEFT: Self = Self::negative(GamepadAxis::LeftStickX);
171
172 pub const LEFT_RIGHT: Self = Self::positive(GamepadAxis::LeftStickX);
174
175 pub const RIGHT_UP: Self = Self::positive(GamepadAxis::RightStickY);
177
178 pub const RIGHT_DOWN: Self = Self::negative(GamepadAxis::RightStickY);
180
181 pub const RIGHT_LEFT: Self = Self::negative(GamepadAxis::RightStickX);
183
184 pub const RIGHT_RIGHT: Self = Self::positive(GamepadAxis::RightStickX);
186}
187
188impl UserInput for GamepadControlDirection {
189 #[inline]
191 fn kind(&self) -> InputControlKind {
192 InputControlKind::Button
193 }
194
195 #[inline]
197 fn decompose(&self) -> BasicInputs {
198 BasicInputs::Simple(Box::new((*self).threshold(0.0)))
199 }
200}
201
202#[serde_typetag]
203impl Buttonlike for GamepadControlDirection {
204 #[inline]
206 fn pressed(&self, input_store: &CentralInputStore, gamepad: Entity) -> bool {
207 let value = read_axis_value(input_store, gamepad, self.axis);
208 self.direction.is_active(value, self.threshold)
209 }
210
211 fn press_as_gamepad(&self, world: &mut World, gamepad: Option<Entity>) {
213 let mut query_state = SystemState::<Query<Entity, With<Gamepad>>>::new(world);
214 let query = query_state.get(world);
215 let gamepad = gamepad.unwrap_or(find_gamepad(Some(query)));
216
217 let message = RawGamepadEvent::Axis(RawGamepadAxisChangedEvent {
218 gamepad,
219 axis: self.axis,
220 value: self.direction.full_active_value(),
221 });
222 world
223 .resource_mut::<Messages<RawGamepadEvent>>()
224 .write(message);
225 }
226
227 fn release_as_gamepad(&self, world: &mut World, gamepad: Option<Entity>) {
229 let mut query_state = SystemState::<Query<Entity, With<Gamepad>>>::new(world);
230 let query = query_state.get(world);
231 let gamepad = gamepad.unwrap_or(find_gamepad(Some(query)));
232
233 let message = RawGamepadEvent::Axis(RawGamepadAxisChangedEvent {
234 gamepad,
235 axis: self.axis,
236 value: 0.0,
237 });
238 world
239 .resource_mut::<Messages<RawGamepadEvent>>()
240 .write(message);
241 }
242
243 fn set_value_as_gamepad(&self, world: &mut World, value: f32, gamepad: Option<Entity>) {
244 if value > 0.0 {
245 self.press_as_gamepad(world, gamepad);
246 } else {
247 self.release_as_gamepad(world, gamepad);
248 }
249 }
250}
251
252impl Eq for GamepadControlDirection {}
253
254impl Hash for GamepadControlDirection {
255 fn hash<H: Hasher>(&self, state: &mut H) {
256 self.axis.hash(state);
257 self.direction.hash(state);
258 FloatOrd(self.threshold).hash(state);
259 }
260}
261
262impl UpdatableInput for GamepadAxis {
263 type SourceData = SQuery<(Entity, Read<Gamepad>)>;
264
265 fn compute(
266 mut central_input_store: ResMut<CentralInputStore>,
267 source_data: StaticSystemParam<Self::SourceData>,
268 ) {
269 for (gamepad_entity, gamepad) in source_data.iter() {
270 for input in gamepad.get_analog_axes() {
271 let GamepadInput::Axis(axis) = input else {
272 continue;
273 };
274 let value = gamepad.get(*axis).unwrap_or_default();
275 central_input_store.update_axislike(
276 SpecificGamepadAxis {
277 gamepad: gamepad_entity,
278 axis: *axis,
279 },
280 value,
281 );
282 central_input_store.update_axislike(*axis, value);
283 }
284 }
285 }
286}
287
288impl UserInput for GamepadAxis {
289 fn kind(&self) -> InputControlKind {
290 InputControlKind::Axis
291 }
292
293 fn decompose(&self) -> BasicInputs {
294 BasicInputs::Composite(vec![
295 Box::new(GamepadControlDirection::negative(*self)),
296 Box::new(GamepadControlDirection::positive(*self)),
297 ])
298 }
299}
300
301#[serde_typetag]
302impl Axislike for GamepadAxis {
303 fn value(&self, input_store: &CentralInputStore, gamepad: Entity) -> f32 {
304 read_axis_value(input_store, gamepad, *self)
305 }
306}
307
308impl UserInput for SpecificGamepadAxis {
312 fn kind(&self) -> InputControlKind {
313 InputControlKind::Axis
314 }
315
316 fn decompose(&self) -> BasicInputs {
317 BasicInputs::Composite(vec![
318 Box::new(GamepadControlDirection::negative(self.axis)),
319 Box::new(GamepadControlDirection::positive(self.axis)),
320 ])
321 }
322}
323
324#[serde_typetag]
325impl Axislike for SpecificGamepadAxis {
326 fn value(&self, input_store: &CentralInputStore, gamepad: Entity) -> f32 {
327 read_axis_value(input_store, gamepad, self.axis)
328 }
329}
330
331#[derive(Debug, Clone, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
362#[must_use]
363pub struct GamepadControlAxis {
364 pub axis: GamepadAxis,
366
367 pub processors: Vec<AxisProcessor>,
369}
370
371impl GamepadControlAxis {
372 #[inline]
375 pub const fn new(axis: GamepadAxis) -> Self {
376 Self {
377 axis,
378 processors: Vec::new(),
379 }
380 }
381
382 pub const LEFT_X: Self = Self::new(GamepadAxis::LeftStickX);
385
386 pub const LEFT_Y: Self = Self::new(GamepadAxis::LeftStickY);
389
390 pub const LEFT_Z: Self = Self::new(GamepadAxis::LeftZ);
392
393 pub const RIGHT_X: Self = Self::new(GamepadAxis::RightStickX);
396
397 pub const RIGHT_Y: Self = Self::new(GamepadAxis::RightStickY);
400
401 pub const RIGHT_Z: Self = Self::new(GamepadAxis::RightZ);
403}
404
405impl UserInput for GamepadControlAxis {
406 #[inline]
408 fn kind(&self) -> InputControlKind {
409 InputControlKind::Axis
410 }
411
412 #[inline]
414 fn decompose(&self) -> BasicInputs {
415 BasicInputs::Composite(vec![
416 Box::new(GamepadControlDirection::negative(self.axis)),
417 Box::new(GamepadControlDirection::positive(self.axis)),
418 ])
419 }
420}
421
422#[serde_typetag]
423impl Axislike for GamepadControlAxis {
424 #[inline]
426 fn value(&self, input_store: &CentralInputStore, gamepad: Entity) -> f32 {
427 let value = read_axis_value(input_store, gamepad, self.axis);
428 self.processors
429 .iter()
430 .fold(value, |value, processor| processor.process(value))
431 }
432
433 fn set_value_as_gamepad(&self, world: &mut World, value: f32, gamepad: Option<Entity>) {
435 let mut query_state = SystemState::<Query<Entity, With<Gamepad>>>::new(world);
436 let query = query_state.get(world);
437 let gamepad = gamepad.unwrap_or(find_gamepad(Some(query)));
438
439 let message = RawGamepadEvent::Axis(RawGamepadAxisChangedEvent {
440 gamepad,
441 axis: self.axis,
442 value,
443 });
444 world
445 .resource_mut::<Messages<RawGamepadEvent>>()
446 .write(message);
447 }
448}
449
450impl WithAxisProcessingPipelineExt for GamepadControlAxis {
451 #[inline]
452 fn reset_processing_pipeline(mut self) -> Self {
453 self.processors.clear();
454 self
455 }
456
457 #[inline]
458 fn replace_processing_pipeline(
459 mut self,
460 processors: impl IntoIterator<Item = AxisProcessor>,
461 ) -> Self {
462 self.processors = processors.into_iter().collect();
463 self
464 }
465
466 #[inline]
467 fn with_processor(mut self, processor: impl Into<AxisProcessor>) -> Self {
468 self.processors.push(processor.into());
469 self
470 }
471}
472
473#[derive(Debug, Clone, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
504#[must_use]
505pub struct GamepadStick {
506 pub x: GamepadAxis,
508
509 pub y: GamepadAxis,
511
512 pub processors: Vec<DualAxisProcessor>,
514}
515
516impl GamepadStick {
517 pub const LEFT: Self = Self {
519 x: GamepadAxis::LeftStickX,
520 y: GamepadAxis::LeftStickY,
521 processors: Vec::new(),
522 };
523
524 pub const RIGHT: Self = Self {
526 x: GamepadAxis::RightStickX,
527 y: GamepadAxis::RightStickY,
528 processors: Vec::new(),
529 };
530}
531
532impl UserInput for GamepadStick {
533 #[inline]
535 fn kind(&self) -> InputControlKind {
536 InputControlKind::DualAxis
537 }
538
539 #[inline]
541 fn decompose(&self) -> BasicInputs {
542 BasicInputs::Composite(vec![
543 Box::new(GamepadControlDirection::negative(self.x)),
544 Box::new(GamepadControlDirection::positive(self.x)),
545 Box::new(GamepadControlDirection::negative(self.y)),
546 Box::new(GamepadControlDirection::positive(self.y)),
547 ])
548 }
549}
550
551#[serde_typetag]
552impl DualAxislike for GamepadStick {
553 #[inline]
555 fn axis_pair(&self, input_store: &CentralInputStore, gamepad: Entity) -> Vec2 {
556 let x = read_axis_value(input_store, gamepad, self.x);
557 let y = read_axis_value(input_store, gamepad, self.y);
558 self.processors
559 .iter()
560 .fold(Vec2::new(x, y), |value, processor| processor.process(value))
561 }
562
563 fn set_axis_pair_as_gamepad(&self, world: &mut World, value: Vec2, gamepad: Option<Entity>) {
565 let mut query_state = SystemState::<Query<Entity, With<Gamepad>>>::new(world);
566 let query = query_state.get(world);
567 let gamepad = gamepad.unwrap_or(find_gamepad(Some(query)));
568
569 let message = RawGamepadEvent::Axis(RawGamepadAxisChangedEvent {
570 gamepad,
571 axis: self.x,
572 value: value.x,
573 });
574 world
575 .resource_mut::<Messages<RawGamepadEvent>>()
576 .write(message);
577
578 let message = RawGamepadEvent::Axis(RawGamepadAxisChangedEvent {
579 gamepad,
580 axis: self.y,
581 value: value.y,
582 });
583 world
584 .resource_mut::<Messages<RawGamepadEvent>>()
585 .write(message);
586 }
587}
588
589impl WithDualAxisProcessingPipelineExt for GamepadStick {
590 #[inline]
591 fn reset_processing_pipeline(mut self) -> Self {
592 self.processors.clear();
593 self
594 }
595
596 #[inline]
597 fn replace_processing_pipeline(
598 mut self,
599 processor: impl IntoIterator<Item = DualAxisProcessor>,
600 ) -> Self {
601 self.processors = processor.into_iter().collect();
602 self
603 }
604
605 #[inline]
606 fn with_processor(mut self, processor: impl Into<DualAxisProcessor>) -> Self {
607 self.processors.push(processor.into());
608 self
609 }
610}
611
612#[must_use]
614#[inline]
615fn button_pressed(input_store: &CentralInputStore, gamepad: Entity, button: GamepadButton) -> bool {
616 let button = SpecificGamepadButton::new(gamepad, button);
617 input_store.pressed(&button)
618}
619
620#[must_use]
626#[inline]
627fn button_value(input_store: &CentralInputStore, gamepad: Entity, button: GamepadButton) -> f32 {
628 let button = SpecificGamepadButton::new(gamepad, button);
629 input_store.button_value(&button)
630}
631
632#[derive(SystemParam)]
634pub struct GamepadButtonInput<'w> {
635 pub buttons: Res<'w, ButtonInput<GamepadButton>>,
637
638 pub axes: Res<'w, Axis<GamepadButton>>,
640}
641
642impl UpdatableInput for GamepadButton {
643 type SourceData = SQuery<(Entity, Read<Gamepad>)>;
644
645 fn compute(
646 mut central_input_store: ResMut<CentralInputStore>,
647 source_data: StaticSystemParam<Self::SourceData>,
648 ) {
649 for (gamepad_entity, gamepad) in source_data.iter() {
650 for key in gamepad.get_pressed() {
651 let specific_button = SpecificGamepadButton {
652 gamepad: gamepad_entity,
653 button: *key,
654 };
655 let value = gamepad.get(*key).unwrap_or(1.0);
656 central_input_store
657 .update_buttonlike(specific_button, ButtonValue::new(true, value));
658 }
659
660 for key in gamepad.get_just_released() {
661 let specific_button = SpecificGamepadButton {
662 gamepad: gamepad_entity,
663 button: *key,
664 };
665 let value = gamepad.get(*key).unwrap_or(0.0);
666 central_input_store
667 .update_buttonlike(specific_button, ButtonValue::new(false, value));
668 }
669 }
670 }
671}
672
673impl UserInput for SpecificGamepadButton {
677 fn kind(&self) -> InputControlKind {
678 InputControlKind::Button
679 }
680
681 fn decompose(&self) -> BasicInputs {
682 BasicInputs::Simple(Box::new(*self))
683 }
684}
685
686#[serde_typetag]
687impl Buttonlike for SpecificGamepadButton {
688 fn pressed(&self, input_store: &CentralInputStore, _gamepad: Entity) -> bool {
690 button_pressed(input_store, self.gamepad, self.button)
691 }
692
693 fn value(&self, input_store: &CentralInputStore, _gamepad: Entity) -> f32 {
695 button_value(input_store, self.gamepad, self.button)
696 }
697
698 fn press(&self, world: &mut World) {
699 self.set_value(world, 1.0);
700 }
701
702 fn release(&self, world: &mut World) {
703 self.set_value(world, 0.0);
704 }
705
706 fn set_value(&self, world: &mut World, value: f32) {
707 let message = RawGamepadEvent::Button(RawGamepadButtonChangedEvent {
708 gamepad: self.gamepad,
709 button: self.button,
710 value,
711 });
712 world
713 .resource_mut::<Messages<RawGamepadEvent>>()
714 .write(message);
715 }
716}
717
718impl UserInput for GamepadButton {
720 #[inline]
722 fn kind(&self) -> InputControlKind {
723 InputControlKind::Button
724 }
725
726 #[inline]
729 fn decompose(&self) -> BasicInputs {
730 BasicInputs::Simple(Box::new(*self))
731 }
732}
733
734#[serde_typetag]
735impl Buttonlike for GamepadButton {
736 #[inline]
738 fn pressed(&self, input_store: &CentralInputStore, gamepad: Entity) -> bool {
739 button_pressed(input_store, gamepad, *self)
740 }
741
742 #[inline]
748 fn value(&self, input_store: &CentralInputStore, gamepad: Entity) -> f32 {
749 button_value(input_store, gamepad, *self)
750 }
751
752 fn press_as_gamepad(&self, world: &mut World, gamepad: Option<Entity>) {
754 self.set_value_as_gamepad(world, 1.0, gamepad);
755 }
756
757 fn release_as_gamepad(&self, world: &mut World, gamepad: Option<Entity>) {
759 self.set_value_as_gamepad(world, 0.0, gamepad);
760 }
761
762 #[inline]
764 fn set_value_as_gamepad(&self, world: &mut World, value: f32, gamepad: Option<Entity>) {
765 let mut query_state = SystemState::<Query<Entity, With<Gamepad>>>::new(world);
766 let query = query_state.get(world);
767 let gamepad = gamepad.unwrap_or(find_gamepad(Some(query)));
768
769 let message = RawGamepadEvent::Button(RawGamepadButtonChangedEvent {
770 gamepad,
771 button: *self,
772 value,
773 });
774 world
775 .resource_mut::<Messages<RawGamepadEvent>>()
776 .write(message);
777 }
778}
779
780#[cfg(test)]
781mod tests {
782 use super::*;
783 use crate::plugin::CentralInputStorePlugin;
784 use bevy::input::gamepad::{GamepadConnection, GamepadConnectionEvent};
785 use bevy::input::InputPlugin;
786 use bevy::prelude::*;
787
788 fn test_app() -> App {
789 let mut app = App::new();
790 app.add_plugins(MinimalPlugins);
791 app.add_plugins((InputPlugin, CentralInputStorePlugin));
792
793 let gamepad = app.world_mut().spawn(()).id();
796 let mut gamepad_connection_messages = app
797 .world_mut()
798 .resource_mut::<Messages<GamepadConnectionEvent>>();
799 gamepad_connection_messages.write(GamepadConnectionEvent {
800 gamepad,
802 connection: GamepadConnection::Connected {
803 name: "TestController".into(),
804 vendor_id: None,
805 product_id: None,
806 },
807 });
808
809 app.update();
811 app.update();
813
814 app
815 }
816
817 #[test]
818 fn test_gamepad_axes() {
819 let left_up = GamepadControlDirection::LEFT_UP;
820 assert_eq!(left_up.kind(), InputControlKind::Button);
821
822 let left_down = GamepadControlDirection::LEFT_DOWN;
824 assert_eq!(left_down.kind(), InputControlKind::Button);
825
826 let left_x = GamepadControlAxis::LEFT_X;
827 assert_eq!(left_x.kind(), InputControlKind::Axis);
828
829 let left_y = GamepadControlAxis::LEFT_Y;
830 assert_eq!(left_y.kind(), InputControlKind::Axis);
831
832 let left = GamepadStick::LEFT;
833 assert_eq!(left.kind(), InputControlKind::DualAxis);
834
835 let right_up = GamepadControlDirection::RIGHT_DOWN;
837 assert_eq!(right_up.kind(), InputControlKind::Button);
838
839 let right_y = GamepadControlAxis::RIGHT_Y;
840 assert_eq!(right_y.kind(), InputControlKind::Axis);
841
842 let right = GamepadStick::RIGHT;
843 assert_eq!(right.kind(), InputControlKind::DualAxis);
844
845 let mut app = test_app();
847 app.update();
848 let gamepad = app
849 .world_mut()
850 .query_filtered::<Entity, With<Gamepad>>()
851 .iter(app.world())
852 .next()
853 .unwrap();
854 let inputs = app.world().resource::<CentralInputStore>();
855
856 assert!(!left_up.pressed(inputs, gamepad));
857 assert!(!left_down.pressed(inputs, gamepad));
858 assert!(!right_up.pressed(inputs, gamepad));
859 assert_eq!(left_x.value(inputs, gamepad), 0.0);
860 assert_eq!(left_y.value(inputs, gamepad), 0.0);
861 assert_eq!(right_y.value(inputs, gamepad), 0.0);
862 assert_eq!(left.axis_pair(inputs, gamepad), Vec2::ZERO);
863 assert_eq!(right.axis_pair(inputs, gamepad), Vec2::ZERO);
864
865 let data = Vec2::new(0.0, 1.0);
867 let mut app = test_app();
868 let gamepad = app
869 .world_mut()
870 .query_filtered::<Entity, With<Gamepad>>()
871 .iter(app.world())
872 .next()
873 .unwrap();
874 GamepadControlDirection::LEFT_UP.press_as_gamepad(app.world_mut(), Some(gamepad));
875 app.update();
876 let inputs = app.world().resource::<CentralInputStore>();
877
878 assert!(left_up.pressed(inputs, gamepad));
879 assert!(!left_down.pressed(inputs, gamepad));
880 assert!(!right_up.pressed(inputs, gamepad));
881 assert_eq!(left_x.value(inputs, gamepad), 0.0);
882 assert_eq!(left_y.value(inputs, gamepad), 1.0);
883 assert_eq!(right_y.value(inputs, gamepad), 0.0);
884 assert_eq!(left.axis_pair(inputs, gamepad), data);
885 assert_eq!(right.axis_pair(inputs, gamepad), Vec2::ZERO);
886
887 let data = Vec2::new(0.0, 0.6);
889 let mut app = test_app();
890 let gamepad = app
891 .world_mut()
892 .query_filtered::<Entity, With<Gamepad>>()
893 .iter(app.world())
894 .next()
895 .unwrap();
896 GamepadControlAxis::LEFT_Y.set_value_as_gamepad(app.world_mut(), data.y, Some(gamepad));
897 app.update();
898 let inputs = app.world().resource::<CentralInputStore>();
899
900 assert!(left_up.pressed(inputs, gamepad));
901 assert!(!left_down.pressed(inputs, gamepad));
902 assert!(!right_up.pressed(inputs, gamepad));
903 assert_eq!(left_x.value(inputs, gamepad), 0.0);
904 assert_eq!(left_y.value(inputs, gamepad), 0.6);
905 assert_eq!(right_y.value(inputs, gamepad), 0.0);
906 assert_eq!(left.axis_pair(inputs, gamepad), data);
907 assert_eq!(right.axis_pair(inputs, gamepad), Vec2::ZERO);
908
909 let data = Vec2::new(0.6, 0.4);
911 let mut app = test_app();
912 let gamepad = app
913 .world_mut()
914 .query_filtered::<Entity, With<Gamepad>>()
915 .iter(app.world())
916 .next()
917 .unwrap();
918 GamepadStick::LEFT.set_axis_pair_as_gamepad(app.world_mut(), data, Some(gamepad));
919 app.update();
920 let inputs = app.world().resource::<CentralInputStore>();
921
922 assert!(left_up.pressed(inputs, gamepad));
923 assert!(!left_down.pressed(inputs, gamepad));
924 assert!(!right_up.pressed(inputs, gamepad));
925 assert_eq!(left_x.value(inputs, gamepad), data.x);
926 assert_eq!(left_y.value(inputs, gamepad), data.y);
927 assert_eq!(right_y.value(inputs, gamepad), 0.0);
928 assert_eq!(left.axis_pair(inputs, gamepad), data);
929 assert_eq!(right.axis_pair(inputs, gamepad), Vec2::ZERO);
930 }
931
932 #[test]
933 #[ignore = "Input mocking is subtly broken: https://github.com/Leafwing-Studios/leafwing-input-manager/issues/516"]
934 fn test_gamepad_buttons() {
935 let up = GamepadButton::DPadUp;
936 assert_eq!(up.kind(), InputControlKind::Button);
937
938 let left = GamepadButton::DPadLeft;
939 assert_eq!(left.kind(), InputControlKind::Button);
940
941 let down = GamepadButton::DPadDown;
942 assert_eq!(left.kind(), InputControlKind::Button);
943
944 let right = GamepadButton::DPadRight;
945 assert_eq!(left.kind(), InputControlKind::Button);
946
947 let mut app = test_app();
949 app.update();
950 let gamepad = app.world_mut().spawn(()).id();
951 let inputs = app.world().resource::<CentralInputStore>();
952
953 assert!(!up.pressed(inputs, gamepad));
954 assert!(!left.pressed(inputs, gamepad));
955 assert!(!down.pressed(inputs, gamepad));
956 assert!(!right.pressed(inputs, gamepad));
957
958 let mut app = test_app();
960 GamepadButton::DPadLeft.press(app.world_mut());
961 app.update();
962 let inputs = app.world().resource::<CentralInputStore>();
963
964 assert!(!up.pressed(inputs, gamepad));
965 assert!(left.pressed(inputs, gamepad));
966 assert!(!down.pressed(inputs, gamepad));
967 assert!(!right.pressed(inputs, gamepad));
968 }
969
970 #[test]
971 #[ignore = "Input mocking is subtly broken: https://github.com/Leafwing-Studios/leafwing-input-manager/issues/516"]
972 fn test_gamepad_button_values() {
973 let up = GamepadButton::DPadUp;
974 assert_eq!(up.kind(), InputControlKind::Button);
975
976 let left = GamepadButton::DPadLeft;
977 assert_eq!(left.kind(), InputControlKind::Button);
978
979 let down = GamepadButton::DPadDown;
980 assert_eq!(down.kind(), InputControlKind::Button);
981
982 let right = GamepadButton::DPadRight;
983 assert_eq!(right.kind(), InputControlKind::Button);
984
985 let mut app = test_app();
987 app.update();
988 let gamepad = app.world_mut().spawn(()).id();
989 let inputs = app.world().resource::<CentralInputStore>();
990
991 assert_eq!(up.value(inputs, gamepad), 0.0);
992 assert_eq!(left.value(inputs, gamepad), 0.0);
993 assert_eq!(down.value(inputs, gamepad), 0.0);
994 assert_eq!(right.value(inputs, gamepad), 0.0);
995
996 let mut app = test_app();
998 GamepadButton::DPadLeft.press(app.world_mut());
999 app.update();
1000 let inputs = app.world().resource::<CentralInputStore>();
1001
1002 assert_eq!(up.value(inputs, gamepad), 0.0);
1003 assert_eq!(left.value(inputs, gamepad), 1.0);
1004 assert_eq!(down.value(inputs, gamepad), 0.0);
1005 assert_eq!(right.value(inputs, gamepad), 0.0);
1006 }
1007}