diff options
Diffstat (limited to 'src/input')
-rw-r--r-- | src/input/events.rs | 6 | ||||
-rw-r--r-- | src/input/mod.rs | 8 | ||||
-rw-r--r-- | src/input/resources.rs | 48 | ||||
-rw-r--r-- | src/input/systems.rs | 46 |
4 files changed, 108 insertions, 0 deletions
diff --git a/src/input/events.rs b/src/input/events.rs new file mode 100644 index 0000000..cf46445 --- /dev/null +++ b/src/input/events.rs @@ -0,0 +1,6 @@ +use bevy::prelude::*; +use crossterm::event::Event; + +/// An event triggered when a crossterm input event is received +#[derive(Event)] +pub struct TerminalInputEvent(pub Event); diff --git a/src/input/mod.rs b/src/input/mod.rs new file mode 100644 index 0000000..80c36bc --- /dev/null +++ b/src/input/mod.rs @@ -0,0 +1,8 @@ +/// Events for this module +pub mod events; + +/// Resources for this module +pub mod resources; + +/// Systems for this module +pub(crate) mod systems; diff --git a/src/input/resources.rs b/src/input/resources.rs new file mode 100644 index 0000000..afe6353 --- /dev/null +++ b/src/input/resources.rs @@ -0,0 +1,48 @@ +use bevy::{prelude::*, utils::HashSet}; +use crossterm::event::{Event, KeyCode}; +use std::sync::{Arc, Mutex}; + +/// Resource containing currently pressed and released keys +#[derive(Resource, Default)] +pub struct TerminalInput { + pressed_keys: HashSet<KeyCode>, + released_keys: HashSet<KeyCode>, +} + +impl TerminalInput { + /// Gets whether the given key is pressed + pub fn is_pressed(&self, code: KeyCode) -> bool { + self.pressed_keys.contains(&code) + } + + /// Gets whether the given key is released + pub fn is_released(&self, code: KeyCode) -> bool { + self.released_keys.contains(&code) + } + + /// Sets given key to pressed + pub(super) fn press(&mut self, code: KeyCode) { + if !self.is_pressed(code) { + self.pressed_keys.insert(code); + } + } + + /// Sets given key to released and removes pressed state + pub(super) fn release(&mut self, code: KeyCode) { + if self.is_pressed(code) { + self.pressed_keys.remove(&code); + } + if !self.is_released(code) { + self.released_keys.insert(code); + } + } + + /// Clears all released keys + pub(super) fn clear_released(&mut self) { + self.released_keys.clear(); + } +} + +/// Event queue for crossterm input event thread +#[derive(Resource, Default)] +pub(crate) struct EventQueue(pub(super) Arc<Mutex<Vec<Event>>>); diff --git a/src/input/systems.rs b/src/input/systems.rs new file mode 100644 index 0000000..3b7f11d --- /dev/null +++ b/src/input/systems.rs @@ -0,0 +1,46 @@ +use bevy::prelude::*; +use crossterm::event::{read, Event, KeyEventKind}; + +use super::{events::TerminalInputEvent, resources::{EventQueue, TerminalInput}}; + +/// Initializes event queue and thread +pub fn setup_input(event_queue: Res<EventQueue>) { + let event_queue = event_queue.0.clone(); + std::thread::spawn(move || { + loop { + // `read()` blocks until an `Event` is available + match read() { + Ok(event) => { + event_queue.lock().unwrap().push(event); + } + Err(err) => { + panic!("Error reading input events: {:?}", err); + } + } + } + }); +} + +/// Reads events from queue and broadcasts corresponding `TerminalInputEvent`s +pub fn input_handling( + event_queue: Res<EventQueue>, + mut input: ResMut<TerminalInput>, + mut event_writer: EventWriter<TerminalInputEvent>, +) { + input.clear_released(); + let mut event_queue = event_queue.0.lock().unwrap(); + while let Some(event) = event_queue.pop() { + if let Event::Key(event) = event { + match event.kind { + KeyEventKind::Press => { + input.press(event.code); + } + KeyEventKind::Release => { + input.release(event.code); + } + _ => (), + } + } + event_writer.send(TerminalInputEvent(event)); + } +} |