#![cfg(feature = "gamepad")]
use bevy::ecs::system::SystemState;
use bevy::input::InputPlugin;
use bevy::input::gamepad::{
GamepadConnection, GamepadConnectionEvent, RawGamepadAxisChangedEvent, RawGamepadEvent,
};
use bevy::prelude::*;
use leafwing_input_manager::input_processing::{
WithAxisProcessingPipelineExt, WithDualAxisProcessingPipelineExt,
};
use leafwing_input_manager::prelude::*;
#[derive(Actionlike, Clone, Copy, Debug, Reflect, PartialEq, Eq, Hash)]
enum ButtonlikeTestAction {
Up,
Down,
Left,
Right,
}
#[derive(Actionlike, Clone, Copy, Debug, Reflect, PartialEq, Eq, Hash)]
#[actionlike(Axis)]
enum AxislikeTestAction {
X,
Y,
#[actionlike(DualAxis)]
XY,
}
fn test_app() -> App {
let mut app = App::new();
app.add_plugins(MinimalPlugins)
.add_plugins(InputPlugin)
.add_plugins(InputManagerPlugin::<ButtonlikeTestAction>::default())
.add_plugins(InputManagerPlugin::<AxislikeTestAction>::default())
.init_resource::<ActionState<ButtonlikeTestAction>>()
.init_resource::<ActionState<AxislikeTestAction>>();
let gamepad = app.world_mut().spawn_empty().id();
let mut gamepad_connection_messages = app
.world_mut()
.resource_mut::<Messages<GamepadConnectionEvent>>();
gamepad_connection_messages.write(GamepadConnectionEvent {
gamepad,
connection: GamepadConnection::Connected {
name: "TestController".into(),
vendor_id: None,
product_id: None,
},
});
app.update();
app.update();
app
}
#[test]
fn gamepad_single_axis_mocking() {
let mut app = test_app();
let mut messages = app.world_mut().resource_mut::<Messages<RawGamepadEvent>>();
assert_eq!(messages.drain().count(), 0);
let input = GamepadControlAxis::LEFT_X;
input.set_value(app.world_mut(), -1.0);
let mut query_state = SystemState::<Query<Entity, With<Gamepad>>>::new(app.world_mut());
let query = query_state.get(app.world());
let gamepad = find_gamepad(Some(query));
let mut messages = app.world_mut().resource_mut::<Messages<RawGamepadEvent>>();
assert_eq!(
messages.drain().next().unwrap(),
RawGamepadEvent::Axis(RawGamepadAxisChangedEvent {
axis: GamepadAxis::LeftStickX,
gamepad: gamepad,
value: -1.0,
})
);
}
#[test]
fn gamepad_dual_axis_mocking() {
let mut app = test_app();
let mut messages = app.world_mut().resource_mut::<Messages<RawGamepadEvent>>();
assert_eq!(messages.drain().count(), 0);
let input = GamepadStick::LEFT;
input.set_axis_pair(app.world_mut(), Vec2::new(1.0, -1.0));
let mut query_state = SystemState::<Query<Entity, With<Gamepad>>>::new(app.world_mut());
let query = query_state.get(app.world());
let gamepad = find_gamepad(Some(query));
let mut messages = app.world_mut().resource_mut::<Messages<RawGamepadEvent>>();
let mut drain = messages.drain().into_iter();
let x = drain.next().unwrap();
assert_eq!(
x,
RawGamepadEvent::Axis(RawGamepadAxisChangedEvent {
axis: GamepadAxis::LeftStickX,
gamepad: gamepad,
value: 1.0,
})
);
let y = drain.next().unwrap();
assert_eq!(
y,
RawGamepadEvent::Axis(RawGamepadAxisChangedEvent {
axis: GamepadAxis::LeftStickY,
gamepad: gamepad,
value: -1.0,
})
);
}
#[test]
fn gamepad_single_axis() {
let mut app = test_app();
app.insert_resource(
InputMap::default()
.with_axis(
AxislikeTestAction::X,
GamepadControlAxis::LEFT_X.with_deadzone_symmetric(0.1),
)
.with_axis(
AxislikeTestAction::Y,
GamepadControlAxis::LEFT_Y.with_deadzone_symmetric(0.1),
),
);
let input = GamepadControlAxis::LEFT_X;
input.set_value(app.world_mut(), 1.0);
app.update();
let input = GamepadControlAxis::LEFT_X;
input.set_value(app.world_mut(), -1.0);
app.update();
let input = GamepadControlAxis::LEFT_Y;
input.set_value(app.world_mut(), 1.0);
app.update();
let input = GamepadControlAxis::LEFT_Y;
input.set_value(app.world_mut(), -1.0);
app.update();
let input = GamepadControlAxis::LEFT_Y;
input.set_value(app.world_mut(), 0.0);
app.update();
let input = GamepadControlAxis::LEFT_X;
input.set_value(app.world_mut(), 0.2);
app.update();
let action_state = app.world().resource::<ActionState<AxislikeTestAction>>();
assert_eq!(action_state.value(&AxislikeTestAction::X), 0.11111112);
}
#[test]
fn gamepad_single_axis_inverted() {
let mut app = test_app();
app.insert_resource(
InputMap::default()
.with_axis(
AxislikeTestAction::X,
GamepadControlAxis::LEFT_X
.with_deadzone_symmetric(0.1)
.inverted(),
)
.with_axis(
AxislikeTestAction::Y,
GamepadControlAxis::LEFT_Y
.with_deadzone_symmetric(0.1)
.inverted(),
),
);
let input = GamepadControlAxis::LEFT_X;
input.set_value(app.world_mut(), 1.0);
app.update();
let action_state = app.world().resource::<ActionState<AxislikeTestAction>>();
assert_eq!(action_state.value(&AxislikeTestAction::X), -1.0);
let input = GamepadControlAxis::LEFT_X;
input.set_value(app.world_mut(), -1.0);
app.update();
let action_state = app.world().resource::<ActionState<AxislikeTestAction>>();
assert_eq!(action_state.value(&AxislikeTestAction::X), 1.0);
let input = GamepadControlAxis::LEFT_Y;
input.set_value(app.world_mut(), 1.0);
app.update();
let action_state = app.world().resource::<ActionState<AxislikeTestAction>>();
assert_eq!(action_state.value(&AxislikeTestAction::Y), -1.0);
let input = GamepadControlAxis::LEFT_Y;
input.set_value(app.world_mut(), -1.0);
app.update();
let action_state = app.world().resource::<ActionState<AxislikeTestAction>>();
assert_eq!(action_state.value(&AxislikeTestAction::Y), 1.0);
}
#[test]
fn gamepad_dual_axis_deadzone() {
let mut app = test_app();
app.insert_resource(InputMap::default().with_dual_axis(
AxislikeTestAction::XY,
GamepadStick::LEFT.with_deadzone_symmetric(0.1),
));
let input = GamepadStick::LEFT;
input.set_axis_pair(app.world_mut(), Vec2::new(0.04, 0.1));
app.update();
let action_state = app.world().resource::<ActionState<AxislikeTestAction>>();
assert_eq!(
action_state.axis_pair(&AxislikeTestAction::XY),
Vec2::new(0.0, 0.0)
);
let input = GamepadStick::LEFT;
input.set_axis_pair(app.world_mut(), Vec2::new(1.0, 0.2));
app.update();
let action_state = app.world().resource::<ActionState<AxislikeTestAction>>();
assert_eq!(
action_state.axis_pair(&AxislikeTestAction::XY),
Vec2::new(1.0, 0.11111112)
);
let input = GamepadStick::LEFT;
input.set_axis_pair(app.world_mut(), Vec2::new(0.8, 0.1));
app.update();
let action_state = app.world().resource::<ActionState<AxislikeTestAction>>();
assert_eq!(
action_state.axis_pair(&AxislikeTestAction::XY),
Vec2::new(0.7777778, 0.0)
);
}
#[test]
fn gamepad_circle_deadzone() {
let mut app = test_app();
app.insert_resource(InputMap::default().with_dual_axis(
AxislikeTestAction::XY,
GamepadStick::LEFT.with_circle_deadzone(0.1),
));
let input = GamepadStick::LEFT;
input.set_axis_pair(app.world_mut(), Vec2::new(0.06, 0.06));
app.update();
let action_state = app.world().resource::<ActionState<AxislikeTestAction>>();
assert_eq!(
action_state.axis_pair(&AxislikeTestAction::XY),
Vec2::new(0.0, 0.0)
);
let input = GamepadStick::LEFT;
input.set_axis_pair(app.world_mut(), Vec2::new(0.2, 0.0));
app.update();
let action_state = app.world().resource::<ActionState<AxislikeTestAction>>();
assert_eq!(
action_state.axis_pair(&AxislikeTestAction::XY),
Vec2::new(0.11111112, 0.0)
);
}
#[test]
fn test_zero_dual_axis_deadzone() {
let mut app = test_app();
app.insert_resource(InputMap::default().with_dual_axis(
AxislikeTestAction::XY,
GamepadStick::LEFT.with_deadzone_symmetric(0.0),
));
let input = GamepadStick::LEFT;
input.set_axis_pair(app.world_mut(), Vec2::ZERO);
app.update();
let action_state = app.world().resource::<ActionState<AxislikeTestAction>>();
assert_eq!(
action_state.axis_pair(&AxislikeTestAction::XY),
Vec2::new(0.0, 0.0)
);
}
#[test]
fn test_zero_circle_deadzone() {
let mut app = test_app();
app.insert_resource(InputMap::default().with_dual_axis(
AxislikeTestAction::XY,
GamepadStick::LEFT.with_circle_deadzone(0.0),
));
let input = GamepadStick::LEFT;
input.set_axis_pair(app.world_mut(), Vec2::ZERO);
app.update();
let action_state = app.world().resource::<ActionState<AxislikeTestAction>>();
assert_eq!(
action_state.axis_pair(&AxislikeTestAction::XY),
Vec2::new(0.0, 0.0)
);
}
#[test]
fn gamepad_virtual_dpad() {
let mut app = test_app();
app.insert_resource(
InputMap::default().with_dual_axis(AxislikeTestAction::XY, VirtualDPad::dpad()),
);
GamepadButton::DPadLeft.press(app.world_mut());
app.update();
let action_state = app.world().resource::<ActionState<AxislikeTestAction>>();
assert_eq!(
action_state.axis_pair(&AxislikeTestAction::XY),
Vec2::new(-1.0, 0.0)
);
}