use bevy_ecs::change_detection::DetectChangesMut;
use bevy_ecs::event::Event;
use bevy_ecs::event::EventReader;
use bevy_ecs::event::EventWriter;
use bevy_ecs::system::Res;
use bevy_ecs::system::ResMut;
use bevy_input::gamepad::GamepadButton;
use bevy_input::gamepad::GamepadButtonChangedEvent;
use bevy_input::gamepad::GamepadButtonInput;
use bevy_input::gamepad::GamepadButtonType;
use bevy_input::gamepad::GamepadSettings;
use bevy_input::keyboard::KeyCode;
use bevy_input::keyboard::KeyboardInput;
use bevy_input::keyboard::ScanCode;
use bevy_input::mouse::MouseButton;
use bevy_input::mouse::MouseButtonInput;
use bevy_input::ButtonState;
use bevy_log::warn;
use bevy_reflect::Enum;
use crate::actions::MultiInput;
use crate::controls::MultiScheme;
use crate::get_key;
use crate::get_scan_code;
use crate::prelude::ActionInput;
use crate::prelude::ControlScheme;
pub fn universal_input_system(
mut keyboard_events: EventReader<KeyboardInput>,
mut gamepad_events: EventReader<GamepadButtonChangedEvent>,
mut button_input_events: EventWriter<GamepadButtonInput>,
mut mouse_button_events: EventReader<MouseButtonInput>,
mut action_input: ResMut<ActionInput>,
control_scheme: Res<ControlScheme>,
settings: Res<GamepadSettings>,
) {
action_input.bypass_change_detection().clear();
let keyboard_events: Vec<&KeyboardInput> = keyboard_events.read().collect();
let gamepad_events: Vec<&GamepadButtonChangedEvent> =
gamepad_events.read().collect();
let mouse_button_events: Vec<&MouseButtonInput> =
mouse_button_events.read().collect();
update_inputs(
&keyboard_events,
&gamepad_events,
&mut button_input_events,
&mouse_button_events,
&mut action_input,
&control_scheme,
&settings,
);
}
pub fn multi_universal_input_system(
mut keyboard_events: EventReader<KeyboardInput>,
mut gamepad_events: EventReader<GamepadButtonChangedEvent>,
mut button_input_writer: EventWriter<GamepadButtonInput>,
mut mouse_button_events: EventReader<MouseButtonInput>,
mut multi_input: ResMut<MultiInput>,
multi_scheme: Res<MultiScheme>,
settings: Res<GamepadSettings>,
) {
multi_input.bypass_change_detection();
let keyboard_events: Vec<&KeyboardInput> = keyboard_events.read().collect();
let gamepad_events: Vec<&GamepadButtonChangedEvent> =
gamepad_events.read().collect();
let mouse_button_events: Vec<&MouseButtonInput> =
mouse_button_events.read().collect();
for i in 0..multi_input.keys().len() {
let action_input = multi_input.get_mut(i).unwrap();
let control_scheme = multi_scheme.get(i).unwrap();
action_input.clear();
update_inputs(
&keyboard_events,
&gamepad_events,
&mut button_input_writer,
&mouse_button_events,
action_input,
control_scheme,
&settings,
);
}
}
fn update_inputs(
keyboard_events: &Vec<&KeyboardInput>,
gamepad_events: &Vec<&GamepadButtonChangedEvent>,
button_input_events: &mut EventWriter<GamepadButtonInput>,
mouse_button_events: &Vec<&MouseButtonInput>,
action_input: &mut ActionInput,
control_scheme: &ControlScheme,
settings: &Res<GamepadSettings>,
) {
for event in keyboard_events {
let KeyboardInput {
scan_code, state, ..
} = event;
let key: UniversalInput = ScanCode(*scan_code).into();
if let Some(action) = control_scheme.get(key) {
match state {
ButtonState::Pressed => action_input.press(*action),
ButtonState::Released => action_input.release(*action),
}
}
}
for event in gamepad_events {
let button = GamepadButton::new(event.gamepad, event.button_type);
let value = event.value;
let button_settings = settings.get_button_settings(button);
let input: UniversalInput = button.into();
let Some(action) = control_scheme.get(input) else {
return;
};
if value <= button_settings.release_threshold() {
if action_input.pressed(*action) {
button_input_events.send(GamepadButtonInput {
button,
state: ButtonState::Released,
});
}
action_input.release(*action);
} else if value >= button_settings.press_threshold() {
button_input_events.send(GamepadButtonInput {
button,
state: ButtonState::Pressed,
});
action_input.press(*action);
}
}
for event in mouse_button_events {
let button: UniversalInput = event.button.into();
if let Some(action) = control_scheme.get(button) {
match event.state {
ButtonState::Pressed => action_input.press(*action),
ButtonState::Released => action_input.release(*action),
}
}
}
}
#[derive(Event)]
pub struct UniversalInputEvent(UniversalInput);
#[repr(u32)]
#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum UniversalInput {
Key1,
Key2,
Key3,
Key4,
Key5,
Key6,
Key7,
Key8,
Key9,
Key0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
Escape,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
F13,
F14,
F15,
F16,
F17,
F18,
F19,
F20,
F21,
F22,
F23,
F24,
Snapshot,
Scroll,
Pause,
Insert,
Home,
Delete,
End,
PageDown,
PageUp,
Left,
Up,
Right,
Down,
Back,
Return,
Space,
Compose,
Caret,
Numlock,
Numpad0,
Numpad1,
Numpad2,
Numpad3,
Numpad4,
Numpad5,
Numpad6,
Numpad7,
Numpad8,
Numpad9,
AbntC1,
AbntC2,
NumpadAdd,
Apostrophe,
Apps,
Asterisk,
Plus,
At,
Ax,
Backslash,
Calculator,
Capital,
Colon,
Comma,
Convert,
NumpadDecimal,
NumpadDivide,
Equals,
Grave,
Kana,
Kanji,
AltLeft,
BracketLeft,
ControlLeft,
ShiftLeft,
#[doc(alias("LWin", "LMeta", "LLogo"))]
SuperLeft,
Mail,
MediaSelect,
MediaStop,
Minus,
NumpadMultiply,
Mute,
MyComputer,
NavigateForward,
NavigateBackward,
NextTrack,
NoConvert,
NumpadComma,
NumpadEnter,
NumpadEquals,
Oem102,
Period,
PlayPause,
Power,
PrevTrack,
AltRight,
BracketRight,
ControlRight,
ShiftRight,
#[doc(alias("RWin", "RMeta", "RLogo"))]
SuperRight,
Semicolon,
Slash,
Sleep,
Stop,
NumpadSubtract,
Sysrq,
Tab,
Underline,
Unlabeled,
VolumeDown,
VolumeUp,
Wake,
WebBack,
WebFavorites,
WebForward,
WebHome,
WebRefresh,
WebSearch,
WebStop,
Yen,
Copy,
Paste,
Cut,
GamepadSouth(usize),
GamepadEast(usize),
GamepadNorth(usize),
GamepadWest(usize),
GamepadC(usize),
GamepadZ(usize),
GamepadLeftTrigger(usize),
GamepadLeftTrigger2(usize),
GamepadRightTrigger(usize),
GamepadRightTrigger2(usize),
GamepadSelect(usize),
GamepadStart(usize),
GamepadMode(usize),
GamepadLeftThumb(usize),
GamepadRightThumb(usize),
GamepadDPadUp(usize),
GamepadDPadDown(usize),
GamepadDPadLeft(usize),
GamepadDPadRight(usize),
GamepadOther(u8, usize),
MouseLeft,
MouseRight,
MouseMiddle,
MouseOther(u16),
Unknown(u32),
}
impl From<KeyCode> for UniversalInput {
fn from(value: KeyCode) -> Self {
let key_str = value.variant_name();
let Ok(scan_code) = get_scan_code(key_str) else {
warn!("Error KeyCode -> UniversalInput");
return UniversalInput::Unknown(0);
};
let Ok(scan_code) = get_key(scan_code) else {
warn!("Error KeyCode -> UniversalInput");
return UniversalInput::Unknown(scan_code);
};
scan_code
}
}
impl From<ScanCode> for UniversalInput {
fn from(value: ScanCode) -> Self {
let Ok(scan_code) = get_key(value.0) else {
warn!("Error ScanCode -> UniversalInput");
return UniversalInput::Unknown(value.0);
};
scan_code
}
}
impl From<GamepadButton> for UniversalInput {
fn from(value: GamepadButton) -> Self {
let button_type = value.button_type;
let id = value.gamepad.id;
match button_type {
GamepadButtonType::South => UniversalInput::GamepadSouth(id),
GamepadButtonType::East => UniversalInput::GamepadEast(id),
GamepadButtonType::North => UniversalInput::GamepadNorth(id),
GamepadButtonType::West => UniversalInput::GamepadWest(id),
GamepadButtonType::C => UniversalInput::GamepadC(id),
GamepadButtonType::Z => UniversalInput::GamepadZ(id),
GamepadButtonType::LeftTrigger => UniversalInput::GamepadLeftTrigger(id),
GamepadButtonType::LeftTrigger2 => UniversalInput::GamepadLeftTrigger2(id),
GamepadButtonType::RightTrigger => UniversalInput::GamepadRightTrigger(id),
GamepadButtonType::RightTrigger2 => {
UniversalInput::GamepadRightTrigger2(id)
}
GamepadButtonType::Select => UniversalInput::GamepadSelect(id),
GamepadButtonType::Start => UniversalInput::GamepadStart(id),
GamepadButtonType::Mode => UniversalInput::GamepadMode(id),
GamepadButtonType::LeftThumb => UniversalInput::GamepadLeftThumb(id),
GamepadButtonType::RightThumb => UniversalInput::GamepadRightThumb(id),
GamepadButtonType::DPadUp => UniversalInput::GamepadDPadUp(id),
GamepadButtonType::DPadDown => UniversalInput::GamepadDPadDown(id),
GamepadButtonType::DPadLeft => UniversalInput::GamepadDPadLeft(id),
GamepadButtonType::DPadRight => UniversalInput::GamepadDPadRight(id),
GamepadButtonType::Other(c) => UniversalInput::GamepadOther(c, id),
}
}
}
impl From<MouseButton> for UniversalInput {
fn from(value: MouseButton) -> Self {
match value {
MouseButton::Left => UniversalInput::MouseLeft,
MouseButton::Right => UniversalInput::MouseRight,
MouseButton::Middle => UniversalInput::MouseMiddle,
MouseButton::Other(id) => UniversalInput::MouseOther(id),
}
}
}