# Objective While `KeyCode` is very often the correct way to interact with keyboard input there are a bunch of cases where it isn't, notably most of the symbols (e.g. plus, minus, different parentheses). Currently the only way to get these is to read from `EventReader<KeyboardInput>`, but then you'd have to redo the `ButtonInput` logic for pressed/released to e.g. make zoom functionality that depends on plus/minus keys. This has led to confusion previously, like https://github.com/bevyengine/bevy/issues/3278 ## Solution Add a `ButtonInput<Key>` resource. ## Testing Modified the `keyboard_input` example to test it. ## Open questions I'm not 100% sure this is the right way forward, since it duplicates the key processing logic and might make people use the shorter `ButtonInput<Key>` even when it's not appropriate. Another option is to add a new struct with both `Key` and `KeyCode`, and use `ButtonInput` with that instead. That would make it more explanatory, but that is a lot of churn. The third alternative is to not do this because it's too niche. I'll add more documentation and take it out of draft if we want to move forward with it.
192 lines
6.4 KiB
Rust
192 lines
6.4 KiB
Rust
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
|
#![forbid(unsafe_code)]
|
|
#![doc(
|
|
html_logo_url = "https://bevy.org/assets/icon.png",
|
|
html_favicon_url = "https://bevy.org/assets/icon.png"
|
|
)]
|
|
#![no_std]
|
|
|
|
//! Input functionality for the [Bevy game engine](https://bevy.org/).
|
|
//!
|
|
//! # Supported input devices
|
|
//!
|
|
//! `bevy` currently supports keyboard, mouse, gamepad, and touch inputs.
|
|
|
|
#[cfg(feature = "std")]
|
|
extern crate std;
|
|
|
|
extern crate alloc;
|
|
|
|
mod axis;
|
|
mod button_input;
|
|
/// Common run conditions
|
|
pub mod common_conditions;
|
|
pub mod gamepad;
|
|
pub mod gestures;
|
|
pub mod keyboard;
|
|
pub mod mouse;
|
|
pub mod touch;
|
|
|
|
pub use axis::*;
|
|
pub use button_input::*;
|
|
|
|
/// The input prelude.
|
|
///
|
|
/// This includes the most common types in this crate, re-exported for your convenience.
|
|
pub mod prelude {
|
|
#[doc(hidden)]
|
|
pub use crate::{
|
|
gamepad::{Gamepad, GamepadAxis, GamepadButton, GamepadSettings},
|
|
keyboard::KeyCode,
|
|
mouse::MouseButton,
|
|
touch::{TouchInput, Touches},
|
|
Axis, ButtonInput,
|
|
};
|
|
}
|
|
|
|
use bevy_app::prelude::*;
|
|
use bevy_ecs::prelude::*;
|
|
#[cfg(feature = "bevy_reflect")]
|
|
use bevy_reflect::Reflect;
|
|
use gestures::*;
|
|
use keyboard::{keyboard_input_system, Key, KeyCode, KeyboardFocusLost, KeyboardInput};
|
|
use mouse::{
|
|
accumulate_mouse_motion_system, accumulate_mouse_scroll_system, mouse_button_input_system,
|
|
AccumulatedMouseMotion, AccumulatedMouseScroll, MouseButton, MouseButtonInput, MouseMotion,
|
|
MouseWheel,
|
|
};
|
|
use touch::{touch_screen_input_system, TouchInput, Touches};
|
|
|
|
#[cfg(feature = "bevy_reflect")]
|
|
use gamepad::Gamepad;
|
|
use gamepad::{
|
|
gamepad_connection_system, gamepad_event_processing_system, GamepadAxis,
|
|
GamepadAxisChangedEvent, GamepadButton, GamepadButtonChangedEvent,
|
|
GamepadButtonStateChangedEvent, GamepadConnection, GamepadConnectionEvent, GamepadEvent,
|
|
GamepadInput, GamepadRumbleRequest, GamepadSettings, RawGamepadAxisChangedEvent,
|
|
RawGamepadButtonChangedEvent, RawGamepadEvent,
|
|
};
|
|
|
|
#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
|
|
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
|
|
|
|
/// Adds keyboard and mouse input to an App
|
|
#[derive(Default)]
|
|
pub struct InputPlugin;
|
|
|
|
/// Label for systems that update the input data.
|
|
#[derive(Debug, PartialEq, Eq, Clone, Hash, SystemSet)]
|
|
pub struct InputSystems;
|
|
|
|
/// Deprecated alias for [`InputSystems`].
|
|
#[deprecated(since = "0.17.0", note = "Renamed to `InputSystems`.")]
|
|
pub type InputSystem = InputSystems;
|
|
|
|
impl Plugin for InputPlugin {
|
|
fn build(&self, app: &mut App) {
|
|
app
|
|
// keyboard
|
|
.add_event::<KeyboardInput>()
|
|
.add_event::<KeyboardFocusLost>()
|
|
.init_resource::<ButtonInput<KeyCode>>()
|
|
.init_resource::<ButtonInput<Key>>()
|
|
.add_systems(PreUpdate, keyboard_input_system.in_set(InputSystems))
|
|
// mouse
|
|
.add_event::<MouseButtonInput>()
|
|
.add_event::<MouseMotion>()
|
|
.add_event::<MouseWheel>()
|
|
.init_resource::<ButtonInput<MouseButton>>()
|
|
.add_systems(
|
|
PreUpdate,
|
|
(
|
|
mouse_button_input_system,
|
|
accumulate_mouse_motion_system,
|
|
accumulate_mouse_scroll_system,
|
|
)
|
|
.in_set(InputSystems),
|
|
)
|
|
.add_event::<PinchGesture>()
|
|
.add_event::<RotationGesture>()
|
|
.add_event::<DoubleTapGesture>()
|
|
.add_event::<PanGesture>()
|
|
// gamepad
|
|
.add_event::<GamepadEvent>()
|
|
.add_event::<GamepadConnectionEvent>()
|
|
.add_event::<GamepadButtonChangedEvent>()
|
|
.add_event::<GamepadButtonStateChangedEvent>()
|
|
.add_event::<GamepadAxisChangedEvent>()
|
|
.add_event::<RawGamepadEvent>()
|
|
.add_event::<RawGamepadAxisChangedEvent>()
|
|
.add_event::<RawGamepadButtonChangedEvent>()
|
|
.add_event::<GamepadRumbleRequest>()
|
|
.init_resource::<AccumulatedMouseMotion>()
|
|
.init_resource::<AccumulatedMouseScroll>()
|
|
.add_systems(
|
|
PreUpdate,
|
|
(
|
|
gamepad_connection_system,
|
|
gamepad_event_processing_system.after(gamepad_connection_system),
|
|
)
|
|
.in_set(InputSystems),
|
|
)
|
|
// touch
|
|
.add_event::<TouchInput>()
|
|
.init_resource::<Touches>()
|
|
.add_systems(PreUpdate, touch_screen_input_system.in_set(InputSystems));
|
|
|
|
#[cfg(feature = "bevy_reflect")]
|
|
{
|
|
// Register common types
|
|
app.register_type::<ButtonState>()
|
|
.register_type::<KeyboardInput>()
|
|
.register_type::<MouseButtonInput>()
|
|
.register_type::<PinchGesture>()
|
|
.register_type::<RotationGesture>()
|
|
.register_type::<DoubleTapGesture>()
|
|
.register_type::<PanGesture>()
|
|
.register_type::<TouchInput>()
|
|
.register_type::<RawGamepadEvent>()
|
|
.register_type::<RawGamepadAxisChangedEvent>()
|
|
.register_type::<RawGamepadButtonChangedEvent>()
|
|
.register_type::<Gamepad>()
|
|
.register_type::<GamepadConnectionEvent>()
|
|
.register_type::<GamepadButtonChangedEvent>()
|
|
.register_type::<GamepadAxisChangedEvent>()
|
|
.register_type::<GamepadButtonStateChangedEvent>()
|
|
.register_type::<GamepadConnection>()
|
|
.register_type::<GamepadSettings>()
|
|
.register_type::<GamepadAxis>()
|
|
.register_type::<GamepadButton>()
|
|
.register_type::<GamepadInput>()
|
|
.register_type::<AccumulatedMouseMotion>()
|
|
.register_type::<AccumulatedMouseScroll>();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The current "press" state of an element
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
|
#[cfg_attr(
|
|
feature = "bevy_reflect",
|
|
derive(Reflect),
|
|
reflect(Debug, Hash, PartialEq, Clone)
|
|
)]
|
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
|
#[cfg_attr(
|
|
all(feature = "serialize", feature = "bevy_reflect"),
|
|
reflect(Serialize, Deserialize)
|
|
)]
|
|
pub enum ButtonState {
|
|
/// The button is pressed.
|
|
Pressed,
|
|
/// The button is not pressed.
|
|
Released,
|
|
}
|
|
|
|
impl ButtonState {
|
|
/// Is this button pressed?
|
|
pub fn is_pressed(&self) -> bool {
|
|
matches!(self, ButtonState::Pressed)
|
|
}
|
|
}
|