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
///
/// The main difference between the [`KeyboardInput`] event and the [`Input<KeyCode>`] resource is that
/// the latter has convenient functions like [`Input::pressed`], [`Input::just_pressed`] and [`Input::just_released`].
/// The main difference between the [`KeyboardInput`] event and the [`Input<KeyCode>`] or [`Input<ScanCode>`] resources is that
/// the latter have convenient functions such as [`Input::pressed`], [`Input::just_pressed`] and [`Input::just_released`].
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>,
) {
keyboard_input.clear();
scan_input.clear();
key_input.clear();
for event in keyboard_input_events.iter() {
if let KeyboardInput {
key_code: Some(key_code),
state,
..
} = event
{
let KeyboardInput {
scan_code, state, ..
} = event;
if let Some(key_code) = event.key_code {
match state {
ButtonState::Pressed => keyboard_input.press(*key_code),
ButtonState::Released => keyboard_input.release(*key_code),
ButtonState::Pressed => key_input.press(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
///
/// 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
///
@ -407,3 +411,17 @@ pub enum KeyCode {
/// The `Cut` key.
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,
GamepadEventType, Gamepads,
},
keyboard::KeyCode,
keyboard::{KeyCode, ScanCode},
mouse::MouseButton,
touch::{TouchInput, Touches},
Axis, Input,
@ -24,7 +24,7 @@ pub mod 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 prelude::Gamepads;
use touch::{touch_screen_input_system, TouchInput, Touches};
@ -47,6 +47,7 @@ impl Plugin for InputPlugin {
// keyboard
.add_event::<KeyboardInput>()
.init_resource::<Input<KeyCode>>()
.init_resource::<Input<ScanCode>>()
.add_system_to_stage(
CoreStage::PreUpdate,
keyboard_input_system.label(InputSystem),