use alloc::vec::Vec;
use core::{any::TypeId, hash::Hash, iter, mem};
use bevy::{
ecs::{schedule::ScheduleLabel, system::SystemParam},
input::mouse::{AccumulatedMouseMotion, AccumulatedMouseScroll},
platform::collections::HashSet,
prelude::*,
utils::TypeIdMap,
};
use log::{debug, trace};
use crate::prelude::*;
pub(crate) fn update_pending(mut reader: InputReader) {
reader.update_pending();
}
#[derive(SystemParam)]
pub(crate) struct InputReader<'w, 's> {
keys: Option<Res<'w, ButtonInput<KeyCode>>>,
mouse_buttons: Option<Res<'w, ButtonInput<MouseButton>>>,
mouse_motion: Option<Res<'w, AccumulatedMouseMotion>>,
mouse_scroll: Option<Res<'w, AccumulatedMouseScroll>>,
gamepads: Query<'w, 's, &'static Gamepad>,
action_sources: Res<'w, ActionSources>,
consumed: ResMut<'w, ConsumedInputs>,
pending: ResMut<'w, PendingBindings>,
gamepad_device: Local<'s, GamepadDevice>,
skip_ignore_check: Local<'s, bool>,
}
impl InputReader<'_, '_> {
pub(crate) fn update_pending(&mut self) {
*self.skip_ignore_check = true;
let mut pending = mem::take(&mut *self.pending);
pending.ignored.clear();
pending.bindings.retain(|&binding| {
if self.value(binding).as_bool() {
pending.ignored.add(binding, *self.gamepad_device);
true
} else {
trace!("'{binding}' reset and no longer ignored");
false
}
});
*self.pending = pending;
*self.skip_ignore_check = false
}
pub(crate) fn clear_consumed<S: ScheduleLabel>(&mut self) {
self.consumed.entry(TypeId::of::<S>()).or_default().clear();
}
pub(crate) fn set_gamepad(&mut self, gamepad: impl Into<GamepadDevice>) {
*self.gamepad_device = gamepad.into();
}
pub(crate) fn value(&self, binding: impl Into<Binding>) -> ActionValue {
let binding = binding.into();
match binding {
Binding::Keyboard { key, mod_keys } => {
let pressed = self.action_sources.keyboard
&& self.keys.as_ref().is_some_and(|k| k.pressed(key))
&& self.mod_keys_pressed(mod_keys)
&& !self.ignored(binding);
pressed.into()
}
Binding::MouseButton { button, mod_keys } => {
let pressed = self.action_sources.mouse_buttons
&& self
.mouse_buttons
.as_ref()
.is_some_and(|b| b.pressed(button))
&& self.mod_keys_pressed(mod_keys)
&& !self.ignored(binding);
pressed.into()
}
Binding::MouseMotion { mod_keys } => {
if !self.action_sources.mouse_motion
|| !self.mod_keys_pressed(mod_keys)
|| self.ignored(binding)
{
return Vec2::ZERO.into();
}
self.mouse_motion
.as_ref()
.map(|m| m.delta)
.unwrap_or_default()
.into()
}
Binding::MouseWheel { mod_keys } => {
if !self.action_sources.mouse_wheel
|| !self.mod_keys_pressed(mod_keys)
|| self.ignored(binding)
{
return Vec2::ZERO.into();
}
self.mouse_scroll
.as_ref()
.map(|s| s.delta)
.unwrap_or_default()
.into()
}
Binding::GamepadButton(button) => {
if !self.action_sources.gamepad_button || self.ignored(binding) {
return 0.0.into();
}
let value = match *self.gamepad_device {
GamepadDevice::Any => self
.gamepads
.iter()
.filter_map(|gamepad| gamepad.get(button))
.find(|&value| value != 0.0),
GamepadDevice::Single(entity) => self
.gamepads
.get(entity)
.ok()
.and_then(|gamepad| gamepad.get(button)),
GamepadDevice::None => return 0.0.into(),
};
value.unwrap_or_default().into()
}
Binding::GamepadAxis(axis) => {
if !self.action_sources.gamepad_axis || self.ignored(binding) {
return 0.0.into();
}
let value = match *self.gamepad_device {
GamepadDevice::Any => self
.gamepads
.iter()
.filter_map(|gamepad| gamepad.get_unclamped(axis))
.reduce(|acc, v| acc + v),
GamepadDevice::Single(entity) => self
.gamepads
.get(entity)
.ok()
.and_then(|gamepad| gamepad.get(axis)),
GamepadDevice::None => return 0.0.into(),
};
let value = value.unwrap_or_default();
value.into()
}
Binding::AnyKey => {
if self.ignored(Binding::AnyKey) {
return false.into();
}
if self.action_sources.keyboard
&& self
.keys
.iter()
.flat_map(|k| k.get_pressed())
.any(|&k| !self.ignored(k))
{
return true.into();
}
if self.action_sources.mouse_buttons
&& self
.mouse_buttons
.iter()
.flat_map(|b| b.get_pressed())
.any(|&b| !self.ignored(b))
{
return true.into();
}
if self.action_sources.gamepad_button {
match *self.gamepad_device {
GamepadDevice::Single(entity) => {
if let Ok(gamepad) = self.gamepads.get(entity)
&& gamepad.get_pressed().any(|&b| !self.ignored(b))
{
return true.into();
}
}
GamepadDevice::Any => {
for gamepad in &self.gamepads {
if gamepad.get_pressed().any(|&b| !self.ignored(b)) {
return true.into();
}
}
}
GamepadDevice::None => (),
};
}
false.into()
}
Binding::None => false.into(),
}
}
fn mod_keys_pressed(&self, mod_keys: ModKeys) -> bool {
if !mod_keys.is_empty() && !self.action_sources.keyboard {
return false;
}
for keys in mod_keys.iter_keys() {
if self.keys.as_ref().is_none_or(|k| !k.any_pressed(keys)) {
return false;
}
}
true
}
fn ignored(&self, binding: impl Into<Binding>) -> bool {
if *self.skip_ignore_check {
return false;
}
let keys_ignored =
self.pending.ignored.any_key || self.consumed.values().any(|ignored| ignored.any_key);
let mut iter = iter::once(&self.pending.ignored).chain(self.consumed.values());
match binding.into() {
Binding::Keyboard { key, mod_keys } => {
iter.any(|i| i.keys.contains(&key) || i.mod_keys.intersects(mod_keys))
|| keys_ignored
}
Binding::MouseButton { button, mod_keys } => {
iter.any(|i| i.mouse_buttons.contains(&button) || i.mod_keys.intersects(mod_keys))
|| keys_ignored
}
Binding::MouseMotion { mod_keys } => {
iter.any(|inputs| inputs.mouse_motion || inputs.mod_keys.intersects(mod_keys))
}
Binding::MouseWheel { mod_keys } => {
iter.any(|inputs| inputs.mouse_wheel || inputs.mod_keys.intersects(mod_keys))
}
Binding::GamepadButton(button) => {
let input = GamepadInput {
gamepad: *self.gamepad_device,
input: button,
};
iter.any(|inputs| inputs.gamepad_buttons.contains(&input)) || keys_ignored
}
Binding::GamepadAxis(axis) => {
let input = GamepadInput {
gamepad: *self.gamepad_device,
input: axis,
};
iter.any(|inputs| inputs.gamepad_axes.contains(&input))
}
Binding::AnyKey => keys_ignored,
Binding::None => false,
}
}
pub(crate) fn consume<S: ScheduleLabel>(&mut self, binding: impl Into<Binding>) {
self.consumed
.entry(TypeId::of::<S>())
.or_default()
.add(binding.into(), *self.gamepad_device);
}
}
#[derive(Resource)]
#[cfg_attr(feature = "reflect", derive(Reflect), reflect(Default, Resource))]
pub struct ActionSources {
pub keyboard: bool,
pub mouse_buttons: bool,
pub mouse_motion: bool,
pub mouse_wheel: bool,
pub gamepad_button: bool,
pub gamepad_axis: bool,
}
impl Default for ActionSources {
fn default() -> Self {
Self {
keyboard: true,
mouse_buttons: true,
mouse_motion: true,
mouse_wheel: true,
gamepad_button: true,
gamepad_axis: true,
}
}
}
#[derive(Resource, Default, Deref, DerefMut)]
pub(crate) struct ConsumedInputs(TypeIdMap<IgnoredInputs>);
#[derive(Resource, Default)]
pub(crate) struct PendingBindings {
bindings: Vec<Binding>,
ignored: IgnoredInputs,
}
impl PendingBindings {
pub(crate) fn extend(&mut self, iter: impl Iterator<Item = Binding>) {
self.bindings
.extend(iter.inspect(|binding| debug!("ignoring '{binding}' until reset")));
}
}
#[derive(Default)]
pub(crate) struct IgnoredInputs {
keys: HashSet<KeyCode>,
mod_keys: ModKeys,
mouse_buttons: HashSet<MouseButton>,
mouse_motion: bool,
mouse_wheel: bool,
gamepad_buttons: HashSet<GamepadInput<GamepadButton>>,
gamepad_axes: HashSet<GamepadInput<GamepadAxis>>,
any_key: bool,
}
impl IgnoredInputs {
fn add(&mut self, binding: Binding, gamepad: GamepadDevice) {
match binding {
Binding::Keyboard { key, mod_keys } => {
self.keys.insert(key);
self.mod_keys.insert(mod_keys);
}
Binding::MouseButton { button, mod_keys } => {
self.mouse_buttons.insert(button);
self.mod_keys.insert(mod_keys);
}
Binding::MouseMotion { mod_keys } => {
self.mouse_motion = true;
self.mod_keys.insert(mod_keys);
}
Binding::MouseWheel { mod_keys } => {
self.mouse_wheel = true;
self.mod_keys.insert(mod_keys);
}
Binding::GamepadButton(button) => {
let input = GamepadInput {
gamepad,
input: button,
};
self.gamepad_buttons.insert(input);
}
Binding::GamepadAxis(axis) => {
let input = GamepadInput {
gamepad,
input: axis,
};
self.gamepad_axes.insert(input);
}
Binding::AnyKey => self.any_key = true,
Binding::None => (),
}
}
fn clear(&mut self) {
self.keys.clear();
self.mod_keys = ModKeys::empty();
self.mouse_buttons.clear();
self.mouse_motion = false;
self.mouse_wheel = false;
self.gamepad_buttons.clear();
self.gamepad_axes.clear();
self.any_key = false;
}
}
#[derive(Hash, PartialEq, Eq)]
struct GamepadInput<T: Hash + Eq> {
gamepad: GamepadDevice,
input: T,
}
#[cfg(test)]
mod tests {
use bevy::{
ecs::system::SystemState,
input::mouse::{MouseMotion, MouseScrollUnit, MouseWheel},
};
use super::*;
#[test]
fn keyboard() {
let (mut world, mut state) = init_world();
let key = KeyCode::Space;
world.resource_mut::<ButtonInput<KeyCode>>().press(key);
let mut reader = state.get_mut(&mut world);
assert_eq!(reader.value(key), true.into());
assert_eq!(reader.value(Binding::AnyKey), true.into());
assert_eq!(reader.value(KeyCode::Escape), false.into());
assert_eq!(reader.value(key.with_mod_keys(ModKeys::ALT)), false.into());
reader.consume::<PreUpdate>(key);
assert_eq!(reader.value(key), false.into());
assert_eq!(reader.value(Binding::AnyKey), false.into());
}
#[test]
fn mouse_button() {
let (mut world, mut state) = init_world();
let button = MouseButton::Left;
world
.resource_mut::<ButtonInput<MouseButton>>()
.press(button);
let mut reader = state.get_mut(&mut world);
assert_eq!(reader.value(button), true.into());
assert_eq!(reader.value(Binding::AnyKey), true.into());
assert_eq!(reader.value(MouseButton::Right), false.into());
assert_eq!(
reader.value(button.with_mod_keys(ModKeys::CONTROL)),
false.into()
);
reader.consume::<PreUpdate>(button);
assert_eq!(reader.value(button), false.into());
assert_eq!(reader.value(Binding::AnyKey), false.into());
}
#[test]
fn mouse_motion() {
let (mut world, mut state) = init_world();
let value = Vec2::ONE;
world.insert_resource(AccumulatedMouseMotion { delta: value });
let binding = Binding::mouse_motion();
let mut reader = state.get_mut(&mut world);
reader.clear_consumed::<PreUpdate>();
assert_eq!(reader.value(binding), value.into());
assert_eq!(
reader.value(binding.with_mod_keys(ModKeys::SHIFT)),
Vec2::ZERO.into()
);
reader.consume::<PreUpdate>(binding);
assert_eq!(reader.value(binding), Vec2::ZERO.into());
}
#[test]
fn mouse_wheel() {
let (mut world, mut state) = init_world();
let value = Vec2::ONE;
world.insert_resource(AccumulatedMouseScroll {
unit: MouseScrollUnit::Line,
delta: value,
});
let binding = Binding::mouse_wheel();
let mut reader = state.get_mut(&mut world);
reader.clear_consumed::<PreUpdate>();
assert_eq!(reader.value(binding), value.into());
assert_eq!(
reader.value(binding.with_mod_keys(ModKeys::SUPER)),
Vec2::ZERO.into()
);
reader.consume::<PreUpdate>(binding);
assert_eq!(reader.value(binding), Vec2::ZERO.into());
}
#[test]
fn gamepad_button() {
let (mut world, mut state) = init_world();
let value = 1.0;
let button1 = GamepadButton::South;
let mut gamepad1 = Gamepad::default();
gamepad1.analog_mut().set(button1, value);
gamepad1.digital_mut().press(button1);
let gamepad_entity = world.spawn(gamepad1).id();
let button2 = GamepadButton::East;
let mut gamepad2 = Gamepad::default();
gamepad2.analog_mut().set(button2, value);
gamepad2.digital_mut().press(button2);
world.spawn(gamepad2);
let mut reader = state.get_mut(&mut world);
reader.set_gamepad(gamepad_entity);
assert_eq!(reader.value(button1), value.into());
assert_eq!(
reader.value(button2),
0.0.into(),
"should read only from `{gamepad_entity:?}`"
);
assert_eq!(reader.value(Binding::AnyKey), true.into());
assert_eq!(reader.value(GamepadButton::North), 0.0.into());
reader.consume::<PreUpdate>(button1);
assert_eq!(reader.value(button1), 0.0.into());
assert_eq!(reader.value(Binding::AnyKey), false.into());
}
#[test]
fn any_gamepad_button() {
let (mut world, mut state) = init_world();
let value = 1.0;
let button1 = GamepadButton::South;
let mut gamepad1 = Gamepad::default();
gamepad1.analog_mut().set(button1, value);
gamepad1.digital_mut().press(button1);
world.spawn(gamepad1);
let button2 = GamepadButton::East;
let mut gamepad2 = Gamepad::default();
gamepad2.analog_mut().set(button2, value);
gamepad2.digital_mut().press(button2);
world.spawn(gamepad2);
let mut reader = state.get_mut(&mut world);
assert_eq!(reader.value(button1), value.into());
assert_eq!(reader.value(button2), value.into());
assert_eq!(reader.value(Binding::AnyKey), true.into());
assert_eq!(reader.value(GamepadButton::North), 0.0.into());
reader.consume::<PreUpdate>(button1);
assert_eq!(reader.value(button1), 0.0.into());
assert_eq!(reader.value(Binding::AnyKey), true.into());
reader.consume::<PreUpdate>(button2);
assert_eq!(reader.value(button2), 0.0.into());
assert_eq!(reader.value(Binding::AnyKey), false.into());
}
#[test]
fn gamepad_axis() {
let (mut world, mut state) = init_world();
let value = 1.0;
let axis1 = GamepadAxis::LeftStickX;
let mut gamepad1 = Gamepad::default();
gamepad1.analog_mut().set(axis1, value);
let gamepad_entity = world.spawn(gamepad1).id();
let axis2 = GamepadAxis::LeftStickY;
let mut gamepad2 = Gamepad::default();
gamepad2.analog_mut().set(axis2, value);
world.spawn(gamepad2);
let mut reader = state.get_mut(&mut world);
reader.set_gamepad(gamepad_entity);
assert_eq!(reader.value(axis1), value.into());
assert_eq!(
reader.value(axis2),
0.0.into(),
"should read only from `{gamepad_entity:?}`"
);
assert_eq!(reader.value(GamepadAxis::RightStickX), 0.0.into());
reader.consume::<PreUpdate>(axis1);
assert_eq!(reader.value(axis1), 0.0.into());
}
#[test]
fn any_gamepad_axis() {
let (mut world, mut state) = init_world();
let value = 1.0;
let axis1 = GamepadAxis::LeftStickX;
let mut gamepad1 = Gamepad::default();
gamepad1.analog_mut().set(axis1, value);
world.spawn(gamepad1);
let axis2 = GamepadAxis::LeftStickY;
let mut gamepad2 = Gamepad::default();
gamepad2.analog_mut().set(axis2, value);
world.spawn(gamepad2);
let mut reader = state.get_mut(&mut world);
assert_eq!(reader.value(axis1), value.into());
assert_eq!(reader.value(axis2), value.into());
assert_eq!(reader.value(GamepadAxis::RightStickX), 0.0.into());
reader.consume::<PreUpdate>(axis1);
assert_eq!(reader.value(axis1), 0.0.into());
reader.consume::<PreUpdate>(axis2);
assert_eq!(reader.value(axis2), 0.0.into());
}
#[test]
fn no_gamepad() {
let (mut world, mut state) = init_world();
let value = 1.0;
let axis = GamepadAxis::LeftStickX;
let button = GamepadButton::South;
let mut gamepad = Gamepad::default();
gamepad.analog_mut().set(axis, value);
gamepad.analog_mut().set(button, value);
gamepad.digital_mut().press(button);
world.spawn(gamepad);
let mut reader = state.get_mut(&mut world);
reader.set_gamepad(None);
assert_eq!(reader.value(button), 0.0.into());
assert_eq!(reader.value(axis), 0.0.into());
assert_eq!(reader.value(Binding::AnyKey), false.into());
}
#[test]
fn any_gamepad_axis_sum() {
let (mut world, mut state) = init_world();
let axis = GamepadAxis::LeftStickX;
let mut gamepad1 = Gamepad::default();
gamepad1.analog_mut().set(axis, 0.001);
world.spawn(gamepad1);
let mut gamepad2 = Gamepad::default();
gamepad2.analog_mut().set(axis, 0.002);
world.spawn(gamepad2);
let mut reader = state.get_mut(&mut world);
assert_eq!(reader.value(axis), 0.003.into());
assert_eq!(reader.value(GamepadAxis::RightStickX), 0.0.into());
reader.consume::<PreUpdate>(axis);
assert_eq!(reader.value(axis), 0.0.into());
}
#[test]
fn keyboard_with_modifier() {
let (mut world, mut state) = init_world();
let key = KeyCode::Space;
let modifier = KeyCode::ControlLeft;
let mut keys = world.resource_mut::<ButtonInput<KeyCode>>();
keys.press(modifier);
keys.press(key);
let binding = key.with_mod_keys(modifier.into());
let mut reader = state.get_mut(&mut world);
assert_eq!(reader.value(binding), true.into());
assert_eq!(reader.value(key), true.into());
assert_eq!(reader.value(Binding::AnyKey), true.into());
assert_eq!(
reader.value(binding.with_mod_keys(ModKeys::ALT)),
false.into()
);
assert_eq!(
reader.value(binding.with_mod_keys(ModKeys::CONTROL | ModKeys::ALT)),
false.into()
);
reader.consume::<PreUpdate>(binding);
assert_eq!(reader.value(binding), false.into());
assert_eq!(
reader.value(Binding::AnyKey),
true.into(),
"should still be pressed due to modifier"
);
let other_key = KeyCode::Enter;
world
.resource_mut::<ButtonInput<KeyCode>>()
.press(other_key);
let other_input = other_key.with_mod_keys(modifier.into());
let reader = state.get_mut(&mut world);
assert_eq!(reader.value(other_input), false.into());
assert_eq!(reader.value(other_key), true.into());
}
#[test]
fn mouse_button_with_modifier() {
let (mut world, mut state) = init_world();
let button = MouseButton::Left;
let modifier = KeyCode::AltLeft;
world.resource_mut::<ButtonInput<KeyCode>>().press(modifier);
world
.resource_mut::<ButtonInput<MouseButton>>()
.press(button);
let binding = button.with_mod_keys(modifier.into());
let mut reader = state.get_mut(&mut world);
assert_eq!(reader.value(binding), true.into());
assert_eq!(reader.value(button), true.into());
assert_eq!(reader.value(Binding::AnyKey), true.into());
assert_eq!(
reader.value(binding.with_mod_keys(ModKeys::CONTROL)),
false.into()
);
assert_eq!(
reader.value(binding.with_mod_keys(ModKeys::CONTROL | ModKeys::ALT)),
false.into()
);
reader.consume::<PreUpdate>(binding);
assert_eq!(reader.value(binding), false.into());
assert_eq!(
reader.value(Binding::AnyKey),
true.into(),
"should still be pressed due to modifier"
);
}
#[test]
fn mouse_motion_with_modifier() {
let (mut world, mut state) = init_world();
let value = Vec2::ONE;
let modifier = KeyCode::ShiftLeft;
world.resource_mut::<ButtonInput<KeyCode>>().press(modifier);
world.insert_resource(AccumulatedMouseMotion { delta: value });
let binding = Binding::mouse_motion().with_mod_keys(modifier.into());
let mut reader = state.get_mut(&mut world);
reader.clear_consumed::<PreUpdate>();
assert_eq!(reader.value(binding), value.into());
assert_eq!(reader.value(binding.without_mod_keys()), value.into());
assert_eq!(
reader.value(binding.with_mod_keys(ModKeys::SUPER)),
Vec2::ZERO.into()
);
assert_eq!(
reader.value(binding.with_mod_keys(ModKeys::SHIFT | ModKeys::SUPER)),
Vec2::ZERO.into()
);
reader.consume::<PreUpdate>(binding);
assert_eq!(reader.value(binding), Vec2::ZERO.into());
}
#[test]
fn mouse_wheel_with_modifier() {
let (mut world, mut state) = init_world();
let value = Vec2::ONE;
let modifier = KeyCode::SuperLeft;
world.resource_mut::<ButtonInput<KeyCode>>().press(modifier);
world.insert_resource(AccumulatedMouseScroll {
unit: MouseScrollUnit::Line,
delta: value,
});
let binding = Binding::mouse_wheel().with_mod_keys(modifier.into());
let mut reader = state.get_mut(&mut world);
reader.clear_consumed::<PreUpdate>();
assert_eq!(reader.value(binding), value.into());
assert_eq!(reader.value(binding.without_mod_keys()), value.into());
assert_eq!(
reader.value(binding.with_mod_keys(ModKeys::SHIFT)),
Vec2::ZERO.into()
);
assert_eq!(
reader.value(binding.with_mod_keys(ModKeys::SHIFT | ModKeys::SUPER)),
Vec2::ZERO.into()
);
reader.consume::<PreUpdate>(binding);
assert_eq!(reader.value(binding), Vec2::ZERO.into());
}
#[test]
fn sources() {
let (mut world, mut state) = init_world();
let key = KeyCode::Space;
let mouse_button = MouseButton::Left;
let gamepad_button = GamepadButton::South;
let axis = GamepadAxis::LeftStickX;
world.resource_mut::<ButtonInput<KeyCode>>().press(key);
world
.resource_mut::<ButtonInput<MouseButton>>()
.press(mouse_button);
world.insert_resource(AccumulatedMouseMotion { delta: Vec2::ONE });
world.insert_resource(AccumulatedMouseScroll {
unit: MouseScrollUnit::Line,
delta: Vec2::ONE,
});
let mut gamepad = Gamepad::default();
gamepad.analog_mut().set(axis, 1.0);
gamepad.analog_mut().set(gamepad_button, 1.0);
world.spawn(gamepad);
let mut action_sources = world.resource_mut::<ActionSources>();
action_sources.keyboard = false;
action_sources.mouse_buttons = false;
action_sources.mouse_motion = false;
action_sources.mouse_wheel = false;
action_sources.gamepad_button = false;
action_sources.gamepad_axis = false;
let mut reader = state.get_mut(&mut world);
reader.clear_consumed::<PreUpdate>();
assert_eq!(reader.value(key), false.into());
assert_eq!(reader.value(mouse_button), false.into());
assert_eq!(reader.value(Binding::mouse_motion()), Vec2::ZERO.into());
assert_eq!(reader.value(Binding::mouse_wheel()), Vec2::ZERO.into());
assert_eq!(reader.value(gamepad_button), 0.0.into());
assert_eq!(reader.value(axis), 0.0.into());
}
fn init_world<'w, 's>() -> (World, SystemState<InputReader<'w, 's>>) {
let mut world = World::new();
world.init_resource::<ButtonInput<KeyCode>>();
world.init_resource::<ButtonInput<MouseButton>>();
world.init_resource::<Messages<MouseMotion>>();
world.init_resource::<Messages<MouseWheel>>();
world.init_resource::<ButtonInput<GamepadButton>>();
world.init_resource::<Axis<GamepadAxis>>();
world.init_resource::<AccumulatedMouseMotion>();
world.init_resource::<AccumulatedMouseScroll>();
world.init_resource::<ConsumedInputs>();
world.init_resource::<PendingBindings>();
world.init_resource::<ActionSources>();
let state = SystemState::<InputReader>::new(&mut world);
(world, state)
}
}