153 lines
3.7 KiB
Rust
153 lines
3.7 KiB
Rust
//! This module helps us deal with controls and events.
|
|
|
|
use std::cell::RefCell;
|
|
use std::collections::{HashMap, VecDeque};
|
|
use std::rc::Rc;
|
|
|
|
use wasm_bindgen::prelude::*;
|
|
use wasm_bindgen::JsCast;
|
|
|
|
use crate::Result;
|
|
|
|
/// The state of the keyboard.
|
|
pub struct Keyboard {
|
|
/// The inner keyboard.
|
|
inner: Rc<RefCell<InnerKeyboard>>,
|
|
}
|
|
|
|
impl Keyboard {
|
|
/// Checks wether a key is pressed or not.
|
|
pub fn is_key_pressed(&self, key: Key) -> bool {
|
|
let mut b = self.inner.borrow_mut();
|
|
*b.keys.entry(key).or_insert(false)
|
|
}
|
|
|
|
/// Receives and treats an event.
|
|
pub fn manage_event(&self, event: Event) {
|
|
let mut b = self.inner.borrow_mut();
|
|
match event {
|
|
Event::KeyPressed(x) => *b.keys.entry(x).or_insert(true) = true,
|
|
Event::KeyReleased(x) => *b.keys.entry(x).or_insert(false) = false,
|
|
}
|
|
|
|
b.events.push_back(event);
|
|
}
|
|
|
|
/// Gets an event from the event stack.
|
|
pub fn pop(&self) -> Option<Event> {
|
|
self.inner.borrow_mut().events.pop_front()
|
|
}
|
|
}
|
|
|
|
impl Keyboard {
|
|
/// Initializes the keyboard.
|
|
pub fn new(document: &web_sys::Document) -> Result<Keyboard> {
|
|
let inner = Rc::new(RefCell::new(InnerKeyboard::new()));
|
|
|
|
let clone = Keyboard {
|
|
inner: inner.clone(),
|
|
};
|
|
|
|
let down_cb = Closure::<dyn FnMut(_)>::new(move |event: web_sys::KeyboardEvent| {
|
|
if let Some(event) = Event::from_js(true, event) {
|
|
clone.manage_event(event);
|
|
}
|
|
});
|
|
|
|
document.set_onkeydown(Some(down_cb.as_ref().unchecked_ref()));
|
|
down_cb.forget();
|
|
|
|
let clone = Keyboard {
|
|
inner: inner.clone(),
|
|
};
|
|
|
|
let up_cb = Closure::<dyn FnMut(_)>::new(move |event: web_sys::KeyboardEvent| {
|
|
if let Some(event) = Event::from_js(false, event) {
|
|
clone.manage_event(event);
|
|
}
|
|
});
|
|
|
|
document.set_onkeyup(Some(up_cb.as_ref().unchecked_ref()));
|
|
up_cb.forget();
|
|
|
|
Ok(Keyboard { inner })
|
|
}
|
|
}
|
|
|
|
/// The state of the keyboard.
|
|
pub struct InnerKeyboard {
|
|
/// Holds the state of the keys.
|
|
keys: HashMap<Key, bool>,
|
|
|
|
/// The list of events to be processed.
|
|
events: VecDeque<Event>,
|
|
}
|
|
|
|
impl InnerKeyboard {
|
|
/// Creates a new inner arrowboard.
|
|
pub fn new() -> InnerKeyboard {
|
|
InnerKeyboard {
|
|
keys: HashMap::new(),
|
|
events: VecDeque::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The different events that can occur.
|
|
#[derive(Copy, Clone)]
|
|
pub enum Event {
|
|
/// A key was pressed down.
|
|
KeyPressed(Key),
|
|
|
|
/// A key was released.
|
|
KeyReleased(Key),
|
|
}
|
|
|
|
/// The different key we cant to support.
|
|
#[derive(Hash, PartialEq, Eq, Copy, Clone)]
|
|
pub enum Key {
|
|
/// The left arrow key.
|
|
ArrowLeft,
|
|
|
|
/// The right arrow key.
|
|
ArrowRight,
|
|
|
|
/// The up arrow key.
|
|
ArrowUp,
|
|
|
|
/// The bottom arrow key.
|
|
ArrowDown,
|
|
|
|
/// The space key.
|
|
Space,
|
|
}
|
|
|
|
impl Key {
|
|
/// Tries and converts a javascript key to our key type.
|
|
pub fn from_str(string: &str) -> Option<Key> {
|
|
match string {
|
|
"ArrowLeft" => Some(Key::ArrowLeft),
|
|
"ArrowRight" => Some(Key::ArrowRight),
|
|
"ArrowUp" => Some(Key::ArrowUp),
|
|
"ArrowDown" => Some(Key::ArrowDown),
|
|
"Space" => Some(Key::Space),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Event {
|
|
/// Tries and converts a javacript event to our event type.
|
|
pub fn from_js(down: bool, event: web_sys::KeyboardEvent) -> Option<Event> {
|
|
let key = Key::from_str(&event.code())?;
|
|
|
|
let event = if down {
|
|
Some(Event::KeyPressed(key))
|
|
} else {
|
|
Some(Event::KeyReleased(key))
|
|
};
|
|
|
|
event
|
|
}
|
|
}
|