1use std::hash::{Hash, Hasher};
4
5use bevy::ecs::system::lifetimeless::{Read, SQuery};
6use bevy::ecs::system::{StaticSystemParam, SystemParam, SystemState};
7use bevy::input::gamepad::{
8 GamepadInput, RawGamepadAxisChangedEvent, RawGamepadButtonChangedEvent, RawGamepadEvent,
9};
10use bevy::input::{Axis, ButtonInput};
11use bevy::math::FloatOrd;
12use bevy::prelude::{
13 Entity, Events, Gamepad, GamepadAxis, GamepadButton, Query, Reflect, Res, ResMut, Vec2, With,
14 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 event = RawGamepadEvent::Axis(RawGamepadAxisChangedEvent {
218 gamepad,
219 axis: self.axis,
220 value: self.direction.full_active_value(),
221 });
222 world.resource_mut::<Events<RawGamepadEvent>>().send(event);
223 }
224
225 fn release_as_gamepad(&self, world: &mut World, gamepad: Option<Entity>) {
227 let mut query_state = SystemState::<Query<Entity, With<Gamepad>>>::new(world);
228 let query = query_state.get(world);
229 let gamepad = gamepad.unwrap_or(find_gamepad(Some(query)));
230
231 let event = RawGamepadEvent::Axis(RawGamepadAxisChangedEvent {
232 gamepad,
233 axis: self.axis,
234 value: 0.0,
235 });
236 world.resource_mut::<Events<RawGamepadEvent>>().send(event);
237 }
238
239 fn set_value_as_gamepad(&self, world: &mut World, value: f32, gamepad: Option<Entity>) {
240 if value > 0.0 {
241 self.press_as_gamepad(world, gamepad);
242 } else {
243 self.release_as_gamepad(world, gamepad);
244 }
245 }
246}
247
248impl Eq for GamepadControlDirection {}
249
250impl Hash for GamepadControlDirection {
251 fn hash<H: Hasher>(&self, state: &mut H) {
252 self.axis.hash(state);
253 self.direction.hash(state);
254 FloatOrd(self.threshold).hash(state);
255 }
256}
257
258impl UpdatableInput for GamepadAxis {
259 type SourceData = SQuery<(Entity, Read<Gamepad>)>;
260
261 fn compute(
262 mut central_input_store: ResMut<CentralInputStore>,
263 source_data: StaticSystemParam<Self::SourceData>,
264 ) {
265 for (gamepad_entity, gamepad) in source_data.iter() {
266 for input in gamepad.get_analog_axes() {
267 let GamepadInput::Axis(axis) = input else {
268 continue;
269 };
270 let value = gamepad.get(*axis).unwrap_or_default();
271 central_input_store.update_axislike(
272 SpecificGamepadAxis {
273 gamepad: gamepad_entity,
274 axis: *axis,
275 },
276 value,
277 );
278 central_input_store.update_axislike(*axis, value);
279 }
280 }
281 }
282}
283
284impl UserInput for GamepadAxis {
285 fn kind(&self) -> InputControlKind {
286 InputControlKind::Axis
287 }
288
289 fn decompose(&self) -> BasicInputs {
290 BasicInputs::Composite(vec![
291 Box::new(GamepadControlDirection::negative(*self)),
292 Box::new(GamepadControlDirection::positive(*self)),
293 ])
294 }
295}
296
297#[serde_typetag]
298impl Axislike for GamepadAxis {
299 fn value(&self, input_store: &CentralInputStore, gamepad: Entity) -> f32 {
300 read_axis_value(input_store, gamepad, *self)
301 }
302}
303
304impl UserInput for SpecificGamepadAxis {
308 fn kind(&self) -> InputControlKind {
309 InputControlKind::Axis
310 }
311
312 fn decompose(&self) -> BasicInputs {
313 BasicInputs::Composite(vec![
314 Box::new(GamepadControlDirection::negative(self.axis)),
315 Box::new(GamepadControlDirection::positive(self.axis)),
316 ])
317 }
318}
319
320#[serde_typetag]
321impl Axislike for SpecificGamepadAxis {
322 fn value(&self, input_store: &CentralInputStore, gamepad: Entity) -> f32 {
323 read_axis_value(input_store, gamepad, self.axis)
324 }
325}
326
327#[derive(Debug, Clone, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
358#[must_use]
359pub struct GamepadControlAxis {
360 pub axis: GamepadAxis,
362
363 pub processors: Vec<AxisProcessor>,
365}
366
367impl GamepadControlAxis {
368 #[inline]
371 pub const fn new(axis: GamepadAxis) -> Self {
372 Self {
373 axis,
374 processors: Vec::new(),
375 }
376 }
377
378 pub const LEFT_X: Self = Self::new(GamepadAxis::LeftStickX);
381
382 pub const LEFT_Y: Self = Self::new(GamepadAxis::LeftStickY);
385
386 pub const LEFT_Z: Self = Self::new(GamepadAxis::LeftZ);
388
389 pub const RIGHT_X: Self = Self::new(GamepadAxis::RightStickX);
392
393 pub const RIGHT_Y: Self = Self::new(GamepadAxis::RightStickY);
396
397 pub const RIGHT_Z: Self = Self::new(GamepadAxis::RightZ);
399}
400
401impl UserInput for GamepadControlAxis {
402 #[inline]
404 fn kind(&self) -> InputControlKind {
405 InputControlKind::Axis
406 }
407
408 #[inline]
410 fn decompose(&self) -> BasicInputs {
411 BasicInputs::Composite(vec![
412 Box::new(GamepadControlDirection::negative(self.axis)),
413 Box::new(GamepadControlDirection::positive(self.axis)),
414 ])
415 }
416}
417
418#[serde_typetag]
419impl Axislike for GamepadControlAxis {
420 #[inline]
422 fn value(&self, input_store: &CentralInputStore, gamepad: Entity) -> f32 {
423 let value = read_axis_value(input_store, gamepad, self.axis);
424 self.processors
425 .iter()
426 .fold(value, |value, processor| processor.process(value))
427 }
428
429 fn set_value_as_gamepad(&self, world: &mut World, value: f32, gamepad: Option<Entity>) {
431 let mut query_state = SystemState::<Query<Entity, With<Gamepad>>>::new(world);
432 let query = query_state.get(world);
433 let gamepad = gamepad.unwrap_or(find_gamepad(Some(query)));
434
435 let event = RawGamepadEvent::Axis(RawGamepadAxisChangedEvent {
436 gamepad,
437 axis: self.axis,
438 value,
439 });
440 world.resource_mut::<Events<RawGamepadEvent>>().send(event);
441 }
442}
443
444impl WithAxisProcessingPipelineExt for GamepadControlAxis {
445 #[inline]
446 fn reset_processing_pipeline(mut self) -> Self {
447 self.processors.clear();
448 self
449 }
450
451 #[inline]
452 fn replace_processing_pipeline(
453 mut self,
454 processors: impl IntoIterator<Item = AxisProcessor>,
455 ) -> Self {
456 self.processors = processors.into_iter().collect();
457 self
458 }
459
460 #[inline]
461 fn with_processor(mut self, processor: impl Into<AxisProcessor>) -> Self {
462 self.processors.push(processor.into());
463 self
464 }
465}
466
467#[derive(Debug, Clone, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
498#[must_use]
499pub struct GamepadStick {
500 pub x: GamepadAxis,
502
503 pub y: GamepadAxis,
505
506 pub processors: Vec<DualAxisProcessor>,
508}
509
510impl GamepadStick {
511 pub const LEFT: Self = Self {
513 x: GamepadAxis::LeftStickX,
514 y: GamepadAxis::LeftStickY,
515 processors: Vec::new(),
516 };
517
518 pub const RIGHT: Self = Self {
520 x: GamepadAxis::RightStickX,
521 y: GamepadAxis::RightStickY,
522 processors: Vec::new(),
523 };
524}
525
526impl UserInput for GamepadStick {
527 #[inline]
529 fn kind(&self) -> InputControlKind {
530 InputControlKind::DualAxis
531 }
532
533 #[inline]
535 fn decompose(&self) -> BasicInputs {
536 BasicInputs::Composite(vec![
537 Box::new(GamepadControlDirection::negative(self.x)),
538 Box::new(GamepadControlDirection::positive(self.x)),
539 Box::new(GamepadControlDirection::negative(self.y)),
540 Box::new(GamepadControlDirection::positive(self.y)),
541 ])
542 }
543}
544
545#[serde_typetag]
546impl DualAxislike for GamepadStick {
547 #[inline]
549 fn axis_pair(&self, input_store: &CentralInputStore, gamepad: Entity) -> Vec2 {
550 let x = read_axis_value(input_store, gamepad, self.x);
551 let y = read_axis_value(input_store, gamepad, self.y);
552 self.processors
553 .iter()
554 .fold(Vec2::new(x, y), |value, processor| processor.process(value))
555 }
556
557 fn set_axis_pair_as_gamepad(&self, world: &mut World, value: Vec2, gamepad: Option<Entity>) {
559 let mut query_state = SystemState::<Query<Entity, With<Gamepad>>>::new(world);
560 let query = query_state.get(world);
561 let gamepad = gamepad.unwrap_or(find_gamepad(Some(query)));
562
563 let event = RawGamepadEvent::Axis(RawGamepadAxisChangedEvent {
564 gamepad,
565 axis: self.x,
566 value: value.x,
567 });
568 world.resource_mut::<Events<RawGamepadEvent>>().send(event);
569
570 let event = RawGamepadEvent::Axis(RawGamepadAxisChangedEvent {
571 gamepad,
572 axis: self.y,
573 value: value.y,
574 });
575 world.resource_mut::<Events<RawGamepadEvent>>().send(event);
576 }
577}
578
579impl WithDualAxisProcessingPipelineExt for GamepadStick {
580 #[inline]
581 fn reset_processing_pipeline(mut self) -> Self {
582 self.processors.clear();
583 self
584 }
585
586 #[inline]
587 fn replace_processing_pipeline(
588 mut self,
589 processor: impl IntoIterator<Item = DualAxisProcessor>,
590 ) -> Self {
591 self.processors = processor.into_iter().collect();
592 self
593 }
594
595 #[inline]
596 fn with_processor(mut self, processor: impl Into<DualAxisProcessor>) -> Self {
597 self.processors.push(processor.into());
598 self
599 }
600}
601
602#[must_use]
604#[inline]
605fn button_pressed(input_store: &CentralInputStore, gamepad: Entity, button: GamepadButton) -> bool {
606 let button = SpecificGamepadButton::new(gamepad, button);
607 input_store.pressed(&button)
608}
609
610#[must_use]
616#[inline]
617fn button_value(input_store: &CentralInputStore, gamepad: Entity, button: GamepadButton) -> f32 {
618 let button = SpecificGamepadButton::new(gamepad, button);
619 input_store.button_value(&button)
620}
621
622#[derive(SystemParam)]
624pub struct GamepadButtonInput<'w> {
625 pub buttons: Res<'w, ButtonInput<GamepadButton>>,
627
628 pub axes: Res<'w, Axis<GamepadButton>>,
630}
631
632impl UpdatableInput for GamepadButton {
633 type SourceData = SQuery<(Entity, Read<Gamepad>)>;
634
635 fn compute(
636 mut central_input_store: ResMut<CentralInputStore>,
637 source_data: StaticSystemParam<Self::SourceData>,
638 ) {
639 for (gamepad_entity, gamepad) in source_data.iter() {
640 for key in gamepad.get_pressed() {
641 let specific_button = SpecificGamepadButton {
642 gamepad: gamepad_entity,
643 button: *key,
644 };
645 let value = specific_button.value(¢ral_input_store, gamepad_entity);
646 central_input_store
647 .update_buttonlike(specific_button, ButtonValue::new(true, value));
648 }
649
650 for key in gamepad.get_just_released() {
651 let specific_button = SpecificGamepadButton {
652 gamepad: gamepad_entity,
653 button: *key,
654 };
655 let value = specific_button.value(¢ral_input_store, gamepad_entity);
656 central_input_store
657 .update_buttonlike(specific_button, ButtonValue::new(false, value));
658 }
659 }
660 }
661}
662
663impl UserInput for SpecificGamepadButton {
667 fn kind(&self) -> InputControlKind {
668 InputControlKind::Button
669 }
670
671 fn decompose(&self) -> BasicInputs {
672 BasicInputs::Simple(Box::new(*self))
673 }
674}
675
676#[serde_typetag]
677impl Buttonlike for SpecificGamepadButton {
678 fn pressed(&self, input_store: &CentralInputStore, _gamepad: Entity) -> bool {
680 button_pressed(input_store, self.gamepad, self.button)
681 }
682
683 fn value(&self, input_store: &CentralInputStore, _gamepad: Entity) -> f32 {
685 button_value(input_store, self.gamepad, self.button)
686 }
687
688 fn press(&self, world: &mut World) {
689 self.set_value(world, 1.0);
690 }
691
692 fn release(&self, world: &mut World) {
693 self.set_value(world, 0.0);
694 }
695
696 fn set_value(&self, world: &mut World, value: f32) {
697 let event = RawGamepadEvent::Button(RawGamepadButtonChangedEvent {
698 gamepad: self.gamepad,
699 button: self.button,
700 value,
701 });
702 world.resource_mut::<Events<RawGamepadEvent>>().send(event);
703 }
704}
705
706impl UserInput for GamepadButton {
708 #[inline]
710 fn kind(&self) -> InputControlKind {
711 InputControlKind::Button
712 }
713
714 #[inline]
717 fn decompose(&self) -> BasicInputs {
718 BasicInputs::Simple(Box::new(*self))
719 }
720}
721
722#[serde_typetag]
723impl Buttonlike for GamepadButton {
724 #[inline]
726 fn pressed(&self, input_store: &CentralInputStore, gamepad: Entity) -> bool {
727 button_pressed(input_store, gamepad, *self)
728 }
729
730 #[inline]
736 fn value(&self, input_store: &CentralInputStore, gamepad: Entity) -> f32 {
737 button_value(input_store, gamepad, *self)
738 }
739
740 fn press_as_gamepad(&self, world: &mut World, gamepad: Option<Entity>) {
742 self.set_value_as_gamepad(world, 1.0, gamepad);
743 }
744
745 fn release_as_gamepad(&self, world: &mut World, gamepad: Option<Entity>) {
747 self.set_value_as_gamepad(world, 0.0, gamepad);
748 }
749
750 #[inline]
752 fn set_value_as_gamepad(&self, world: &mut World, value: f32, gamepad: Option<Entity>) {
753 let mut query_state = SystemState::<Query<Entity, With<Gamepad>>>::new(world);
754 let query = query_state.get(world);
755 let gamepad = gamepad.unwrap_or(find_gamepad(Some(query)));
756
757 let event = RawGamepadEvent::Button(RawGamepadButtonChangedEvent {
758 gamepad,
759 button: *self,
760 value,
761 });
762 world.resource_mut::<Events<RawGamepadEvent>>().send(event);
763 }
764}
765
766#[cfg(test)]
767mod tests {
768 use super::*;
769 use crate::plugin::CentralInputStorePlugin;
770 use bevy::input::gamepad::{GamepadConnection, GamepadConnectionEvent};
771 use bevy::input::InputPlugin;
772 use bevy::prelude::*;
773
774 fn test_app() -> App {
775 let mut app = App::new();
776 app.add_plugins(MinimalPlugins);
777 app.add_plugins((InputPlugin, CentralInputStorePlugin));
778
779 let gamepad = app.world_mut().spawn(()).id();
782 let mut gamepad_connection_events = app
783 .world_mut()
784 .resource_mut::<Events<GamepadConnectionEvent>>();
785 gamepad_connection_events.send(GamepadConnectionEvent {
786 gamepad,
788 connection: GamepadConnection::Connected {
789 name: "TestController".into(),
790 vendor_id: None,
791 product_id: None,
792 },
793 });
794
795 app.update();
797 app.update();
799
800 app
801 }
802
803 #[test]
804 fn test_gamepad_axes() {
805 let left_up = GamepadControlDirection::LEFT_UP;
806 assert_eq!(left_up.kind(), InputControlKind::Button);
807
808 let left_down = GamepadControlDirection::LEFT_DOWN;
810 assert_eq!(left_down.kind(), InputControlKind::Button);
811
812 let left_x = GamepadControlAxis::LEFT_X;
813 assert_eq!(left_x.kind(), InputControlKind::Axis);
814
815 let left_y = GamepadControlAxis::LEFT_Y;
816 assert_eq!(left_y.kind(), InputControlKind::Axis);
817
818 let left = GamepadStick::LEFT;
819 assert_eq!(left.kind(), InputControlKind::DualAxis);
820
821 let right_up = GamepadControlDirection::RIGHT_DOWN;
823 assert_eq!(right_up.kind(), InputControlKind::Button);
824
825 let right_y = GamepadControlAxis::RIGHT_Y;
826 assert_eq!(right_y.kind(), InputControlKind::Axis);
827
828 let right = GamepadStick::RIGHT;
829 assert_eq!(right.kind(), InputControlKind::DualAxis);
830
831 let mut app = test_app();
833 app.update();
834 let gamepad = app
835 .world_mut()
836 .query_filtered::<Entity, With<Gamepad>>()
837 .iter(app.world())
838 .next()
839 .unwrap();
840 let inputs = app.world().resource::<CentralInputStore>();
841
842 assert!(!left_up.pressed(inputs, gamepad));
843 assert!(!left_down.pressed(inputs, gamepad));
844 assert!(!right_up.pressed(inputs, gamepad));
845 assert_eq!(left_x.value(inputs, gamepad), 0.0);
846 assert_eq!(left_y.value(inputs, gamepad), 0.0);
847 assert_eq!(right_y.value(inputs, gamepad), 0.0);
848 assert_eq!(left.axis_pair(inputs, gamepad), Vec2::ZERO);
849 assert_eq!(right.axis_pair(inputs, gamepad), Vec2::ZERO);
850
851 let data = Vec2::new(0.0, 1.0);
853 let mut app = test_app();
854 let gamepad = app
855 .world_mut()
856 .query_filtered::<Entity, With<Gamepad>>()
857 .iter(app.world())
858 .next()
859 .unwrap();
860 GamepadControlDirection::LEFT_UP.press_as_gamepad(app.world_mut(), Some(gamepad));
861 app.update();
862 let inputs = app.world().resource::<CentralInputStore>();
863
864 assert!(left_up.pressed(inputs, gamepad));
865 assert!(!left_down.pressed(inputs, gamepad));
866 assert!(!right_up.pressed(inputs, gamepad));
867 assert_eq!(left_x.value(inputs, gamepad), 0.0);
868 assert_eq!(left_y.value(inputs, gamepad), 1.0);
869 assert_eq!(right_y.value(inputs, gamepad), 0.0);
870 assert_eq!(left.axis_pair(inputs, gamepad), data);
871 assert_eq!(right.axis_pair(inputs, gamepad), Vec2::ZERO);
872
873 let data = Vec2::new(0.0, 0.6);
875 let mut app = test_app();
876 let gamepad = app
877 .world_mut()
878 .query_filtered::<Entity, With<Gamepad>>()
879 .iter(app.world())
880 .next()
881 .unwrap();
882 GamepadControlAxis::LEFT_Y.set_value_as_gamepad(app.world_mut(), data.y, Some(gamepad));
883 app.update();
884 let inputs = app.world().resource::<CentralInputStore>();
885
886 assert!(left_up.pressed(inputs, gamepad));
887 assert!(!left_down.pressed(inputs, gamepad));
888 assert!(!right_up.pressed(inputs, gamepad));
889 assert_eq!(left_x.value(inputs, gamepad), 0.0);
890 assert_eq!(left_y.value(inputs, gamepad), 0.6);
891 assert_eq!(right_y.value(inputs, gamepad), 0.0);
892 assert_eq!(left.axis_pair(inputs, gamepad), data);
893 assert_eq!(right.axis_pair(inputs, gamepad), Vec2::ZERO);
894
895 let data = Vec2::new(0.6, 0.4);
897 let mut app = test_app();
898 let gamepad = app
899 .world_mut()
900 .query_filtered::<Entity, With<Gamepad>>()
901 .iter(app.world())
902 .next()
903 .unwrap();
904 GamepadStick::LEFT.set_axis_pair_as_gamepad(app.world_mut(), data, Some(gamepad));
905 app.update();
906 let inputs = app.world().resource::<CentralInputStore>();
907
908 assert!(left_up.pressed(inputs, gamepad));
909 assert!(!left_down.pressed(inputs, gamepad));
910 assert!(!right_up.pressed(inputs, gamepad));
911 assert_eq!(left_x.value(inputs, gamepad), data.x);
912 assert_eq!(left_y.value(inputs, gamepad), data.y);
913 assert_eq!(right_y.value(inputs, gamepad), 0.0);
914 assert_eq!(left.axis_pair(inputs, gamepad), data);
915 assert_eq!(right.axis_pair(inputs, gamepad), Vec2::ZERO);
916 }
917
918 #[test]
919 #[ignore = "Input mocking is subtly broken: https://github.com/Leafwing-Studios/leafwing-input-manager/issues/516"]
920 fn test_gamepad_buttons() {
921 let up = GamepadButton::DPadUp;
922 assert_eq!(up.kind(), InputControlKind::Button);
923
924 let left = GamepadButton::DPadLeft;
925 assert_eq!(left.kind(), InputControlKind::Button);
926
927 let down = GamepadButton::DPadDown;
928 assert_eq!(left.kind(), InputControlKind::Button);
929
930 let right = GamepadButton::DPadRight;
931 assert_eq!(left.kind(), InputControlKind::Button);
932
933 let mut app = test_app();
935 app.update();
936 let gamepad = app.world_mut().spawn(()).id();
937 let inputs = app.world().resource::<CentralInputStore>();
938
939 assert!(!up.pressed(inputs, gamepad));
940 assert!(!left.pressed(inputs, gamepad));
941 assert!(!down.pressed(inputs, gamepad));
942 assert!(!right.pressed(inputs, gamepad));
943
944 let mut app = test_app();
946 GamepadButton::DPadLeft.press(app.world_mut());
947 app.update();
948 let inputs = app.world().resource::<CentralInputStore>();
949
950 assert!(!up.pressed(inputs, gamepad));
951 assert!(left.pressed(inputs, gamepad));
952 assert!(!down.pressed(inputs, gamepad));
953 assert!(!right.pressed(inputs, gamepad));
954 }
955}