Added keyboard scan input event (#5495)

# Objective

- I wanted to have controls independent from keyboard layout and found that bevy doesn't have a proper implementation for that

## Solution

- I created a `ScanCode` enum with two hundreds scan codes and updated `keyboard_input_system` to include and update `ResMut<Input<ScanCode>>`
- closes both https://github.com/bevyengine/bevy/issues/2052 and https://github.com/bevyengine/bevy/issues/862

Co-authored-by: Bleb1k <91003089+Bleb1k@users.noreply.github.com>
This commit is contained in:
Bleb1k 2022-08-05 04:19:53 +00:00
parent c37939d322
commit 115211161b
2 changed files with 34 additions and 15 deletions

View File

@ -24,25 +24,29 @@ pub struct KeyboardInput {
/// ///
/// ## Differences /// ## Differences
/// ///
/// The main difference between the [`KeyboardInput`] event and the [`Input<KeyCode>`] resource is that /// The main difference between the [`KeyboardInput`] event and the [`Input<KeyCode>`] or [`Input<ScanCode>`] resources is that
/// the latter has convenient functions like [`Input::pressed`], [`Input::just_pressed`] and [`Input::just_released`]. /// the latter have convenient functions such as [`Input::pressed`], [`Input::just_pressed`] and [`Input::just_released`].
pub fn keyboard_input_system( pub fn keyboard_input_system(
mut keyboard_input: ResMut<Input<KeyCode>>, mut scan_input: ResMut<Input<ScanCode>>,
mut key_input: ResMut<Input<KeyCode>>,
mut keyboard_input_events: EventReader<KeyboardInput>, mut keyboard_input_events: EventReader<KeyboardInput>,
) { ) {
keyboard_input.clear(); scan_input.clear();
key_input.clear();
for event in keyboard_input_events.iter() { for event in keyboard_input_events.iter() {
if let KeyboardInput { let KeyboardInput {
key_code: Some(key_code), scan_code, state, ..
state, } = event;
.. if let Some(key_code) = event.key_code {
} = event
{
match state { match state {
ButtonState::Pressed => keyboard_input.press(*key_code), ButtonState::Pressed => key_input.press(key_code),
ButtonState::Released => keyboard_input.release(*key_code), ButtonState::Released => key_input.release(key_code),
} }
} }
match state {
ButtonState::Pressed => scan_input.press(ScanCode(*scan_code)),
ButtonState::Released => scan_input.release(ScanCode(*scan_code)),
}
} }
} }
@ -51,7 +55,7 @@ pub fn keyboard_input_system(
/// ## Usage /// ## Usage
/// ///
/// It is used as the generic `T` value of an [`Input`](crate::Input) to create a `Res<Input<KeyCode>>`. /// It is used as the generic `T` value of an [`Input`](crate::Input) to create a `Res<Input<KeyCode>>`.
/// The resource stores the data of the buttons of a keyboard and can be accessed inside of a system. /// The resource values are mapped to the current layout of the keyboard and correlate to an [`ScanCode`](ScanCode).
/// ///
/// ## Updating /// ## Updating
/// ///
@ -407,3 +411,17 @@ pub enum KeyCode {
/// The `Cut` key. /// The `Cut` key.
Cut, Cut,
} }
/// The scan code of a [`KeyboardInput`](crate::keyboard::KeyboardInput).
///
/// ## Usage
///
/// It is used as the generic <T> value of an [`Input`](crate::Input) to create a `Res<Input<ScanCode>>`.
/// The resource values are mapped to the physical location of a key on the keyboard and correlate to an [`KeyCode`](KeyCode)
///
/// ## Updating
///
/// The resource is updated inside of the [`keyboard_input_system`](crate::keyboard::keyboard_input_system).
#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub struct ScanCode(pub u32);

View File

@ -16,7 +16,7 @@ pub mod prelude {
Gamepad, GamepadAxis, GamepadAxisType, GamepadButton, GamepadButtonType, GamepadEvent, Gamepad, GamepadAxis, GamepadAxisType, GamepadButton, GamepadButtonType, GamepadEvent,
GamepadEventType, Gamepads, GamepadEventType, Gamepads,
}, },
keyboard::KeyCode, keyboard::{KeyCode, ScanCode},
mouse::MouseButton, mouse::MouseButton,
touch::{TouchInput, Touches}, touch::{TouchInput, Touches},
Axis, Input, Axis, Input,
@ -24,7 +24,7 @@ pub mod prelude {
} }
use bevy_app::prelude::*; use bevy_app::prelude::*;
use keyboard::{keyboard_input_system, KeyCode, KeyboardInput}; use keyboard::{keyboard_input_system, KeyCode, KeyboardInput, ScanCode};
use mouse::{mouse_button_input_system, MouseButton, MouseButtonInput, MouseMotion, MouseWheel}; use mouse::{mouse_button_input_system, MouseButton, MouseButtonInput, MouseMotion, MouseWheel};
use prelude::Gamepads; use prelude::Gamepads;
use touch::{touch_screen_input_system, TouchInput, Touches}; use touch::{touch_screen_input_system, TouchInput, Touches};
@ -47,6 +47,7 @@ impl Plugin for InputPlugin {
// keyboard // keyboard
.add_event::<KeyboardInput>() .add_event::<KeyboardInput>()
.init_resource::<Input<KeyCode>>() .init_resource::<Input<KeyCode>>()
.init_resource::<Input<ScanCode>>()
.add_system_to_stage( .add_system_to_stage(
CoreStage::PreUpdate, CoreStage::PreUpdate,
keyboard_input_system.label(InputSystem), keyboard_input_system.label(InputSystem),