Skip to content

Commit

Permalink
removed dynamic key mapping; resulting in wrongly always pressed 'A' …
Browse files Browse the repository at this point in the history
…when releasing shift (see #3)
  • Loading branch information
Vrixyz committed Oct 25, 2023
1 parent b0ce1ff commit 87bad37
Show file tree
Hide file tree
Showing 52 changed files with 97 additions and 171 deletions.
2 changes: 1 addition & 1 deletion crates/bevy_input/src/common_conditions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use std::hash::Hash;
/// .run();
/// }
///
/// fn update_pause_state(mut paused: ResMut<Paused>, input: Input<KeyLogic>) {
/// fn update_pause_state(mut paused: ResMut<Paused>, input: Input<KeyCode>) {
/// if input.just_pressed(KeyCode::Escape) {
/// paused.0 = !paused.0;
/// }
Expand Down
40 changes: 6 additions & 34 deletions crates/bevy_input/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

use bevy_ecs::system::Resource;

use bevy_reflect::{std_traits::ReflectDefault, FromReflect, Reflect};
use bevy_utils::{HashMap, HashSet};
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_utils::HashSet;
use std::hash::Hash;

// unused import, but needed for intra doc link to work
Expand Down Expand Up @@ -46,46 +46,29 @@ use bevy_ecs::schedule::State;
///[`DetectChangesMut::bypass_change_detection`]: bevy_ecs::change_detection::DetectChangesMut::bypass_change_detection
#[derive(Debug, Clone, Resource, Reflect)]
#[reflect(Default)]
pub struct Input<T: FromReflect + Clone + Eq + Hash + Send + Sync + 'static> {
pub struct Input<T: Clone + Eq + Hash + Send + Sync + 'static> {
/// A collection of every button that is currently being pressed.
pressed: HashSet<T>,
/// A collection of every button that has just been pressed.
just_pressed: HashSet<T>,
/// A collection of every button that has just been released.
just_released: HashSet<T>,
/// To map logical keys with their respecting physical keys for reliability.
dynamic_map_value: HashMap<T, T>,
}

impl<T: FromReflect + Clone + Eq + Hash + Send + Sync + 'static> Default for Input<T> {
impl<T: Clone + Eq + Hash + Send + Sync + 'static> Default for Input<T> {
fn default() -> Self {
Self {
pressed: Default::default(),
just_pressed: Default::default(),
just_released: Default::default(),
dynamic_map_value: HashMap::default(),
}
}
}

impl<T> Input<T>
where
T: FromReflect + Clone + Eq + Hash + Send + Sync + 'static,
T: Clone + Eq + Hash + Send + Sync + 'static,
{
/// When user adds modifiers to a keypress, the underlying Logical key might change.<br />
/// Use this to store a reference to the original `LogicalKey`.
pub fn add_dynamic_mapping<V: Into<T>, S: Into<T>>(&mut self, user_visible: V, stored: S) {
self.dynamic_map_value
.insert(user_visible.into(), stored.into());
}

/// To call when a dynamic key mapping is not longer needed.
pub fn release_dynamic_mapping<I: Into<T>>(&mut self, key: I) {
let to_remove = key.into();
self.dynamic_map_value
.retain(|k, v| k != &to_remove && v != &to_remove);
}

/// Registers a press for the given `input`.
pub fn press<I: Into<T>>(&mut self, input: I) {
let input = input.into();
Expand All @@ -98,7 +81,6 @@ where
/// Returns `true` if the `input` has been pressed.
pub fn pressed<I: Into<T>>(&self, input: I) -> bool {
let input = input.into();
let input = self.dynamic_map_value.get(&input).unwrap_or(&input).clone();
self.pressed.contains(&input)
}

Expand All @@ -110,7 +92,6 @@ where
/// Registers a release for the given `input`.
pub fn release<I: Into<T>>(&mut self, input: I) {
let input = input.into();
let input = self.dynamic_map_value.get(&input).unwrap_or(&input).clone();
// Returns `true` if the `input` was pressed.
if self.pressed.remove(&input) {
self.just_released.insert(input.clone());
Expand All @@ -126,7 +107,6 @@ where
/// Returns `true` if the `input` has just been pressed.
pub fn just_pressed<I: Into<T>>(&self, input: I) -> bool {
let input = input.into();
let input = self.dynamic_map_value.get(&input).unwrap_or(&input).clone();
self.just_pressed.contains(&input)
}

Expand All @@ -145,7 +125,6 @@ where
/// Returns `true` if the `input` has just been released.
pub fn just_released<I: Into<T>>(&self, input: I) -> bool {
let input = input.into();
let input = self.dynamic_map_value.get(&input).unwrap_or(&input).clone();
self.just_released.contains(&input)
}

Expand All @@ -159,8 +138,6 @@ where
/// Future calls to [`Input::just_released`] for the given input will return false until a new release event occurs.
pub fn clear_just_released<I: Into<T>>(&mut self, input: I) -> bool {
let input = input.into();
let input = self.dynamic_map_value.get(&input).unwrap_or(&input).clone();
self.release_dynamic_mapping(input.clone());
self.just_released.remove(&input)
}

Expand All @@ -170,7 +147,6 @@ where
self.pressed.remove(&input);
self.just_pressed.remove(&input);
self.just_released.remove(&input);
self.dynamic_map_value.clear();
}

/// Clears the `pressed`, `just_pressed`, and `just_released` data for every input.
Expand All @@ -180,18 +156,14 @@ where
self.pressed.clear();
self.just_pressed.clear();
self.just_released.clear();
self.dynamic_map_value.clear();
}

/// Clears the `just pressed` and `just released` data for every input.
///
/// See also [`Input::reset_all`] for a full reset.
pub fn clear(&mut self) {
self.just_pressed.clear();
let inputs_to_release = self.just_released.drain().collect::<Vec<_>>();
for r in inputs_to_release {
self.release_dynamic_mapping(r);
}
self.just_released.clear();
}

/// An iterator visiting every pressed input in arbitrary order.
Expand Down
66 changes: 13 additions & 53 deletions crates/bevy_input/src/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use serde::{Deserialize, Serialize};
/// ## Usage
///
/// The event is consumed inside of the [`keyboard_input_system`]
/// to update the [`Input<KeyLogic>`] resource.
/// to update the [`Input<KeyCode>`] and [`Input<Key>`] resources.
#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect)]
#[reflect(Debug, PartialEq)]
#[cfg_attr(
Expand All @@ -43,61 +43,19 @@ pub struct KeyboardInput {
pub window: Entity,
}

/// The stored logical key code for `Res<Input<KeyLogic>>`
///
/// We need to store the corresponding `KeyCode` because when modifiers are applied,
/// the released logical key might be different from the pressed.
/// For example, the sequence of physical keys:
/// - Press shift
/// - Press 'a'
/// - Release shift
/// - Release 'a',
///
/// Leads to the following underlying logical events:
/// - Press shift
/// - Press logic character key 'A'
/// - Release shift
/// - Release logic character key 'a'
/// Note the different capitalization.
#[derive(Debug, Clone, Eq, PartialEq, Hash, Reflect)]
#[cfg_attr(
feature = "serialize",
derive(serde::Serialize, serde::Deserialize),
reflect(Serialize, Deserialize)
)]
pub enum KeyLogic {
/// Represents the logical key, typically what's visible on the keyboard.
Logic(Key),
/// Represents the ScanCode
Physical(KeyCode),
}

impl<I> From<I> for KeyLogic
where
I: Into<Key>,
{
fn from(value: I) -> Self {
KeyLogic::Logic(value.into())
}
}

impl From<KeyCode> for KeyLogic {
fn from(value: KeyCode) -> Self {
KeyLogic::Physical(value)
}
}

/// Updates the [`Input<KeyLogic>`] resource with the latest [`KeyboardInput`] events.
/// Updates the [`Input<KeyCode>`] and [`Input<Key>`] resources with the latest [`KeyboardInput`] events.
///
/// ## Differences
///
/// The main difference between the [`KeyboardInput`] event and the [`Input<KeyLogic>`] resources is that
/// The main difference between the [`KeyboardInput`] event and the [`Input<KeyCode>`] or [`Input<Key>`] 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 key_input: ResMut<Input<KeyLogic>>,
mut key_code_input: ResMut<Input<KeyCode>>,
mut key_input: ResMut<Input<Key>>,
mut keyboard_input_events: EventReader<KeyboardInput>,
) {
// Avoid clearing if it's not empty to ensure change detection is not triggered.
key_code_input.bypass_change_detection().clear();
key_input.bypass_change_detection().clear();
for event in keyboard_input_events.read() {
let KeyboardInput {
Expand All @@ -108,10 +66,13 @@ pub fn keyboard_input_system(
} = event;
match state {
ButtonState::Pressed => {
key_input.add_dynamic_mapping(logical_key.clone(), *key_code);
key_input.press(*key_code);
key_code_input.press(*key_code);
key_input.press(logical_key.clone());
}
ButtonState::Released => {
key_code_input.release(*key_code);
key_input.release(logical_key.clone());
}
ButtonState::Released => key_input.release(*key_code),
}
}
}
Expand Down Expand Up @@ -667,8 +628,7 @@ pub enum NativeKey {
///
/// ## Usage
///
/// It is used as the generic `T` value of an [`Input`](crate::Input) to create a `Res<Input<KeyLogic>>`,
/// storing a `Key` and its corresponding `KeyCode`.
/// It is used as the generic `T` value of an [`Input`](crate::Input) to create a `Res<Input<KeyCode>>` and `Res<Input<Key>>`.
///
/// The resource values are mapped to the current layout of the keyboard and correlate to a [`KeyCode`](KeyCode).
///
Expand Down
8 changes: 4 additions & 4 deletions crates/bevy_input/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub mod prelude {
gamepad::{
Gamepad, GamepadAxis, GamepadAxisType, GamepadButton, GamepadButtonType, Gamepads,
},
keyboard::{Key, KeyCode, KeyLogic},
keyboard::{Key, KeyCode},
mouse::MouseButton,
touch::{TouchInput, Touches},
Axis, Input,
Expand All @@ -38,7 +38,7 @@ use bevy_app::prelude::*;
use bevy_ecs::prelude::*;

use bevy_reflect::Reflect;
use keyboard::{keyboard_input_system, Key, KeyCode, KeyLogic, KeyboardInput, NativeKey};
use keyboard::{keyboard_input_system, Key, KeyCode, KeyboardInput, NativeKey};
use mouse::{
mouse_button_input_system, MouseButton, MouseButtonInput, MouseMotion, MouseScrollUnit,
MouseWheel,
Expand Down Expand Up @@ -70,7 +70,8 @@ impl Plugin for InputPlugin {
app
// keyboard
.add_event::<KeyboardInput>()
.init_resource::<Input<KeyLogic>>()
.init_resource::<Input<KeyCode>>()
.init_resource::<Input<Key>>()
.add_systems(PreUpdate, keyboard_input_system.in_set(InputSystem))
// mouse
.add_event::<MouseButtonInput>()
Expand Down Expand Up @@ -116,7 +117,6 @@ impl Plugin for InputPlugin {

// Register keyboard types
app.register_type::<KeyboardInput>()
.register_type::<KeyLogic>()
.register_type::<KeyCode>()
.register_type::<Key>()
.register_type::<NativeKey>();
Expand Down
7 changes: 2 additions & 5 deletions crates/bevy_window/src/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ use crate::{PrimaryWindow, Window, WindowCloseRequested};

use bevy_app::AppExit;
use bevy_ecs::prelude::*;
use bevy_input::{
keyboard::{KeyCode, KeyLogic},
Input,
};
use bevy_input::{keyboard::KeyCode, Input};

/// Exit the application when there are no open windows.
///
Expand Down Expand Up @@ -55,7 +52,7 @@ pub fn close_when_requested(mut commands: Commands, mut closed: EventReader<Wind
pub fn close_on_esc(
mut commands: Commands,
focused_windows: Query<(Entity, &Window)>,
input: Res<Input<KeyLogic>>,
input: Res<Input<KeyCode>>,
) {
for (window, focus) in focused_windows.iter() {
if !focus.focused {
Expand Down
2 changes: 1 addition & 1 deletion examples/2d/2d_gizmos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ fn system(mut gizmos: Gizmos, time: Res<Time>) {
gizmos.arc_2d(Vec2::ZERO, sin / 10., PI / 2., 350., Color::ORANGE_RED);
}

fn update_config(mut config: ResMut<GizmoConfig>, keyboard: Res<Input<KeyLogic>>, time: Res<Time>) {
fn update_config(mut config: ResMut<GizmoConfig>, keyboard: Res<Input<KeyCode>>, time: Res<Time>) {
if keyboard.pressed(KeyCode::ArrowRight) {
config.line_width += 5. * time.delta_seconds();
}
Expand Down
2 changes: 1 addition & 1 deletion examples/2d/bloom_2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ fn update_bloom_settings(
mut camera: Query<(Entity, Option<&mut BloomSettings>), With<Camera>>,
mut text: Query<&mut Text>,
mut commands: Commands,
keycode: Res<Input<KeyLogic>>,
keycode: Res<Input<KeyCode>>,
time: Res<Time>,
) {
let bloom_settings = camera.single_mut();
Expand Down
2 changes: 1 addition & 1 deletion examples/2d/rotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
/// Demonstrates applying rotation and movement based on keyboard input.
fn player_movement_system(
time: Res<Time>,
keyboard_input: Res<Input<KeyLogic>>,
keyboard_input: Res<Input<KeyCode>>,
mut query: Query<(&Player, &mut Transform)>,
) {
let (ship, mut transform) = query.single_mut();
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/3d_gizmos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ fn rotate_camera(mut query: Query<&mut Transform, With<Camera>>, time: Res<Time>
transform.rotate_around(Vec3::ZERO, Quat::from_rotation_y(time.delta_seconds() / 2.));
}

fn update_config(mut config: ResMut<GizmoConfig>, keyboard: Res<Input<KeyLogic>>, time: Res<Time>) {
fn update_config(mut config: ResMut<GizmoConfig>, keyboard: Res<Input<KeyCode>>, time: Res<Time>) {
if keyboard.just_pressed(KeyCode::KeyD) {
config.depth_bias = if config.depth_bias == 0. { -1. } else { 0. };
}
Expand Down
4 changes: 2 additions & 2 deletions examples/3d/anti_aliasing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fn main() {
}

fn modify_aa(
keys: Res<Input<KeyLogic>>,
keys: Res<Input<KeyCode>>,
mut camera: Query<
(
Entity,
Expand Down Expand Up @@ -117,7 +117,7 @@ fn modify_aa(
}

fn modify_sharpening(
keys: Res<Input<KeyLogic>>,
keys: Res<Input<KeyCode>>,
mut query: Query<&mut ContrastAdaptiveSharpeningSettings>,
) {
for mut cas in &mut query {
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/atmospheric_fog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ fn setup_instructions(mut commands: Commands) {
);
}

fn toggle_system(keycode: Res<Input<KeyLogic>>, mut fog: Query<&mut FogSettings>) {
fn toggle_system(keycode: Res<Input<KeyCode>>, mut fog: Query<&mut FogSettings>) {
let mut fog_settings = fog.single_mut();

if keycode.just_pressed(KeyCode::Space) {
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/blend_modes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ fn example_control_system(
labelled: Query<&GlobalTransform>,
mut state: Local<ExampleState>,
time: Res<Time>,
input: Res<Input<KeyLogic>>,
input: Res<Input<KeyCode>>,
) {
if input.pressed(KeyCode::ArrowUp) {
state.alpha = (state.alpha + time.delta_seconds()).min(1.0);
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/bloom_3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ fn update_bloom_settings(
mut camera: Query<(Entity, Option<&mut BloomSettings>), With<Camera>>,
mut text: Query<&mut Text>,
mut commands: Commands,
keycode: Res<Input<KeyLogic>>,
keycode: Res<Input<KeyCode>>,
time: Res<Time>,
) {
let bloom_settings = camera.single_mut();
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/fog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ fn update_system(
mut camera: Query<(&mut FogSettings, &mut Transform)>,
mut text: Query<&mut Text>,
time: Res<Time>,
keycode: Res<Input<KeyLogic>>,
keycode: Res<Input<KeyCode>>,
) {
let now = time.elapsed_seconds();
let delta = time.delta_seconds();
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/generate_custom_mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ fn setup(
// System to receive input from the user,
// check out examples/input/ for more examples about user input.
fn input_handler(
keyboard_input: Res<Input<KeyLogic>>,
keyboard_input: Res<Input<KeyCode>>,
mesh_query: Query<&Handle<Mesh>, With<CustomUV>>,
mut meshes: ResMut<Assets<Mesh>>,
mut query: Query<&mut Transform, With<CustomUV>>,
Expand Down
Loading

0 comments on commit 87bad37

Please sign in to comment.