Skip to content

Commit

Permalink
Added keyboard scan input event (bevyengine#5495)
Browse files Browse the repository at this point in the history
# 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 bevyengine#2052 and bevyengine#862

Co-authored-by: Bleb1k <91003089+Bleb1k@users.noreply.github.com>
  • Loading branch information
2 people authored and james7132 committed Oct 28, 2022
1 parent 637800c commit a4779b2
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 15 deletions.
44 changes: 31 additions & 13 deletions crates/bevy_input/src/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
}
}
}

Expand All @@ -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
///
Expand Down Expand Up @@ -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);
5 changes: 3 additions & 2 deletions crates/bevy_input/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ pub mod prelude {
Gamepad, GamepadAxis, GamepadAxisType, GamepadButton, GamepadButtonType, GamepadEvent,
GamepadEventType, Gamepads,
},
keyboard::KeyCode,
keyboard::{KeyCode, ScanCode},
mouse::MouseButton,
touch::{TouchInput, Touches},
Axis, Input,
};
}

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};
Expand All @@ -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),
Expand Down

0 comments on commit a4779b2

Please sign in to comment.