leafwing_input_manager/user_input/
keyboard.rs

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