leafwing_input_manager/user_input/
keyboard.rs

1//! Keyboard inputs
2
3use bevy::ecs::system::lifetimeless::SRes;
4use bevy::ecs::system::StaticSystemParam;
5use bevy::input::keyboard::{Key, KeyboardInput, NativeKey};
6use bevy::input::{ButtonInput, ButtonState};
7use bevy::prelude::{Entity, Events, KeyCode, Reflect, ResMut, World};
8use leafwing_input_manager_macros::serde_typetag;
9use serde::{Deserialize, Serialize};
10
11use crate as leafwing_input_manager;
12use crate::buttonlike::ButtonValue;
13use crate::clashing_inputs::BasicInputs;
14use crate::user_input::{ButtonlikeChord, UserInput};
15use crate::InputControlKind;
16
17use super::updating::{CentralInputStore, UpdatableInput};
18use super::Buttonlike;
19
20// Built-in support for Bevy's KeyCode
21impl UserInput for KeyCode {
22    /// [`KeyCode`] acts as a button.
23    #[inline]
24    fn kind(&self) -> InputControlKind {
25        InputControlKind::Button
26    }
27
28    /// Returns a [`BasicInputs`] that only contains the [`KeyCode`] itself,
29    /// as it represents a simple physical button.
30    #[inline]
31    fn decompose(&self) -> BasicInputs {
32        BasicInputs::Simple(Box::new(*self))
33    }
34}
35
36impl UpdatableInput for KeyCode {
37    type SourceData = SRes<ButtonInput<KeyCode>>;
38
39    fn compute(
40        mut central_input_store: ResMut<CentralInputStore>,
41        source_data: StaticSystemParam<Self::SourceData>,
42    ) {
43        for key in source_data.get_pressed() {
44            central_input_store.update_buttonlike(*key, ButtonValue::from_pressed(true));
45        }
46
47        for key in source_data.get_just_released() {
48            central_input_store.update_buttonlike(*key, ButtonValue::from_pressed(false));
49        }
50    }
51}
52
53#[serde_typetag]
54impl Buttonlike for KeyCode {
55    /// Checks if the specified key is currently pressed down.
56    #[inline]
57    fn pressed(&self, input_store: &CentralInputStore, _gamepad: Entity) -> bool {
58        input_store.pressed(self)
59    }
60
61    /// Sends a fake [`KeyboardInput`] event to the world with [`ButtonState::Pressed`].
62    ///
63    /// # Note
64    ///
65    /// The `logical_key` and `window` fields will be filled with placeholder values.
66    fn press(&self, world: &mut World) {
67        let mut events = world.resource_mut::<Events<KeyboardInput>>();
68        events.send(KeyboardInput {
69            key_code: *self,
70            logical_key: Key::Unidentified(NativeKey::Unidentified),
71            state: ButtonState::Pressed,
72            repeat: false,
73            window: Entity::PLACEHOLDER,
74            text: None,
75        });
76    }
77
78    /// Sends a fake [`KeyboardInput`] event to the world with [`ButtonState::Released`].
79    ///
80    /// # Note
81    ///
82    /// The `logical_key` and `window` fields will be filled with placeholder values.
83    fn release(&self, world: &mut World) {
84        let mut events = world.resource_mut::<Events<KeyboardInput>>();
85        events.send(KeyboardInput {
86            key_code: *self,
87            logical_key: Key::Unidentified(NativeKey::Unidentified),
88            state: ButtonState::Released,
89            repeat: false,
90            window: Entity::PLACEHOLDER,
91            text: None,
92        });
93    }
94
95    /// If the value is greater than `0.0`, press the key; otherwise release it.
96    fn set_value(&self, world: &mut World, value: f32) {
97        if value > 0.0 {
98            self.press(world);
99        } else {
100            self.release(world);
101        }
102    }
103}
104
105/// Keyboard modifiers like Alt, Control, Shift, and Super (OS symbol key).
106///
107/// Each variant represents a pair of [`KeyCode`]s, the left and right version of the modifier key,
108/// allowing for handling modifiers regardless of which side is pressed.
109#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
110#[must_use]
111pub enum ModifierKey {
112    /// The Alt key, representing either [`KeyCode::AltLeft`] or [`KeyCode::AltRight`].
113    Alt,
114
115    /// The Control key, representing either [`KeyCode::ControlLeft`] or [`KeyCode::ControlRight`].
116    Control,
117
118    /// The Shift key, representing either [`KeyCode::ShiftLeft`] or [`KeyCode::ShiftRight`].
119    Shift,
120
121    /// The Super (OS symbol) key, representing either [`KeyCode::SuperLeft`] or [`KeyCode::SuperRight`].
122    Super,
123}
124
125impl ModifierKey {
126    /// Returns a pair of [`KeyCode`]s corresponding to both modifier keys.
127    #[must_use]
128    #[inline]
129    pub const fn keycodes(&self) -> [KeyCode; 2] {
130        [self.left(), self.right()]
131    }
132
133    /// Returns the [`KeyCode`] corresponding to the left modifier key.
134    #[must_use]
135    #[inline]
136    pub const fn left(&self) -> KeyCode {
137        match self {
138            ModifierKey::Alt => KeyCode::AltLeft,
139            ModifierKey::Control => KeyCode::ControlLeft,
140            ModifierKey::Shift => KeyCode::ShiftLeft,
141            ModifierKey::Super => KeyCode::SuperLeft,
142        }
143    }
144
145    /// Returns the [`KeyCode`] corresponding to the right modifier key.
146    #[must_use]
147    #[inline]
148    pub const fn right(&self) -> KeyCode {
149        match self {
150            ModifierKey::Alt => KeyCode::AltRight,
151            ModifierKey::Control => KeyCode::ControlRight,
152            ModifierKey::Shift => KeyCode::ShiftRight,
153            ModifierKey::Super => KeyCode::SuperRight,
154        }
155    }
156
157    /// Create an [`ButtonlikeChord`] that includes this [`ModifierKey`] and the given `input`.
158    #[inline]
159    pub fn with(&self, other: impl Buttonlike) -> ButtonlikeChord {
160        ButtonlikeChord::from_single(*self).with(other)
161    }
162}
163
164impl UserInput for ModifierKey {
165    /// [`ModifierKey`] acts as a button.
166    #[inline]
167    fn kind(&self) -> InputControlKind {
168        InputControlKind::Button
169    }
170
171    /// Returns the two [`KeyCode`]s used by this [`ModifierKey`].
172    #[inline]
173    fn decompose(&self) -> BasicInputs {
174        BasicInputs::Composite(vec![Box::new(self.left()), Box::new(self.right())])
175    }
176}
177
178#[serde_typetag]
179impl Buttonlike for ModifierKey {
180    /// Checks if the specified modifier key is currently pressed down.
181    #[inline]
182    fn pressed(&self, input_store: &CentralInputStore, _gamepad: Entity) -> bool {
183        input_store.pressed(&self.left()) || input_store.pressed(&self.right())
184    }
185
186    /// Sends a fake [`KeyboardInput`] event to the world with [`ButtonState::Pressed`].
187    ///
188    /// The left and right keys will be pressed simultaneously.
189    ///
190    /// # Note
191    ///
192    /// The `logical_key` and `window` fields will be filled with placeholder values.
193    fn press(&self, world: &mut World) {
194        self.left().press(world);
195        self.right().press(world);
196    }
197
198    /// Sends a fake [`KeyboardInput`] event to the world with [`ButtonState::Released`].
199    ///
200    /// The left and right keys will be released simultaneously.
201    ///
202    /// # Note
203    ///
204    /// The `logical_key` and `window` fields will be filled with placeholder values.
205    fn release(&self, world: &mut World) {
206        self.left().release(world);
207        self.right().release(world);
208    }
209
210    /// If the value is greater than `0.0`, press the keys; otherwise release it.
211    fn set_value(&self, world: &mut World, value: f32) {
212        if value > 0.0 {
213            self.press(world);
214        } else {
215            self.release(world);
216        }
217    }
218}
219
220#[cfg(test)]
221mod tests {
222    use super::*;
223    use crate::plugin::CentralInputStorePlugin;
224    use bevy::input::InputPlugin;
225    use bevy::prelude::*;
226
227    fn test_app() -> App {
228        let mut app = App::new();
229        app.add_plugins(InputPlugin)
230            .add_plugins(CentralInputStorePlugin);
231        app
232    }
233
234    #[test]
235    fn test_keyboard_input() {
236        let up = KeyCode::ArrowUp;
237        assert_eq!(up.kind(), InputControlKind::Button);
238
239        let left = KeyCode::ArrowLeft;
240        assert_eq!(left.kind(), InputControlKind::Button);
241
242        let alt = ModifierKey::Alt;
243        assert_eq!(alt.kind(), InputControlKind::Button);
244
245        // No inputs
246        let mut app = test_app();
247        app.update();
248        let gamepad = app.world_mut().spawn(()).id();
249        let inputs = app.world().resource::<CentralInputStore>();
250
251        assert!(!up.pressed(inputs, gamepad));
252        assert!(!left.pressed(inputs, gamepad));
253        assert!(!alt.pressed(inputs, gamepad));
254
255        // Press arrow up
256        let mut app = test_app();
257        KeyCode::ArrowUp.press(app.world_mut());
258        app.update();
259        let inputs = app.world().resource::<CentralInputStore>();
260
261        assert!(up.pressed(inputs, gamepad));
262        assert!(!left.pressed(inputs, gamepad));
263        assert!(!alt.pressed(inputs, gamepad));
264
265        // Press arrow down
266        let mut app = test_app();
267        KeyCode::ArrowDown.press(app.world_mut());
268        app.update();
269        let inputs = app.world().resource::<CentralInputStore>();
270
271        assert!(!up.pressed(inputs, gamepad));
272        assert!(!left.pressed(inputs, gamepad));
273        assert!(!alt.pressed(inputs, gamepad));
274
275        // Press arrow left
276        let mut app = test_app();
277        KeyCode::ArrowLeft.press(app.world_mut());
278        app.update();
279        let inputs = app.world().resource::<CentralInputStore>();
280
281        assert!(!up.pressed(inputs, gamepad));
282        assert!(left.pressed(inputs, gamepad));
283        assert!(!alt.pressed(inputs, gamepad));
284
285        // Press arrow down and arrow up
286        let mut app = test_app();
287        KeyCode::ArrowDown.press(app.world_mut());
288        KeyCode::ArrowUp.press(app.world_mut());
289        app.update();
290        let inputs = app.world().resource::<CentralInputStore>();
291
292        assert!(up.pressed(inputs, gamepad));
293        assert!(!left.pressed(inputs, gamepad));
294        assert!(!alt.pressed(inputs, gamepad));
295
296        // Press arrow left and arrow up
297        let mut app = test_app();
298        KeyCode::ArrowLeft.press(app.world_mut());
299        KeyCode::ArrowUp.press(app.world_mut());
300        app.update();
301        let inputs = app.world().resource::<CentralInputStore>();
302
303        assert!(up.pressed(inputs, gamepad));
304        assert!(left.pressed(inputs, gamepad));
305        assert!(!alt.pressed(inputs, gamepad));
306
307        // Press left Alt
308        let mut app = test_app();
309        KeyCode::AltLeft.press(app.world_mut());
310        app.update();
311        let inputs = app.world().resource::<CentralInputStore>();
312
313        assert!(!up.pressed(inputs, gamepad));
314        assert!(!left.pressed(inputs, gamepad));
315        assert!(alt.pressed(inputs, gamepad));
316
317        // Press right Alt
318        let mut app = test_app();
319        KeyCode::AltRight.press(app.world_mut());
320        app.update();
321        let inputs = app.world().resource::<CentralInputStore>();
322
323        assert!(!up.pressed(inputs, gamepad));
324        assert!(!left.pressed(inputs, gamepad));
325        assert!(alt.pressed(inputs, gamepad));
326    }
327}