diff options
| author | Arne Dußin | 2021-01-27 14:01:50 +0100 |
|---|---|---|
| committer | Arne Dußin | 2021-02-02 22:16:15 +0100 |
| commit | f92e9f6f07b1e3834c2ca58ce3510734819d08e4 (patch) | |
| tree | 20e3d3afce342a56ae98f6c20491482ccd2b5c6b /src/input | |
| parent | c60a6d07efb120724b308e29e8e70f27c87c952d (diff) | |
| download | graf_karto-f92e9f6f07b1e3834c2ca58ce3510734819d08e4.tar.gz graf_karto-f92e9f6f07b1e3834c2ca58ce3510734819d08e4.zip | |
Rework graf karto to fit the client/server structure
Diffstat (limited to 'src/input')
| -rw-r--r-- | src/input/binding.rs | 123 | ||||
| -rw-r--r-- | src/input/button.rs | 177 | ||||
| -rw-r--r-- | src/input/mod.rs | 200 |
3 files changed, 0 insertions, 500 deletions
diff --git a/src/input/binding.rs b/src/input/binding.rs deleted file mode 100644 index 386fb66..0000000 --- a/src/input/binding.rs +++ /dev/null @@ -1,123 +0,0 @@ -//! Bindings module, which is a key combination that does something when pressed. - -use super::Button; -use raylib::RaylibHandle; -use serde::{Deserialize, Serialize}; - -/// Binding struct, which holds any number of buttons (keyboard and mouse may be mixed, if desired) -#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Binding { - buttons: Vec<Button>, -} - -impl Binding { - /// Create a new binding from a range of buttons. The button order does not matter, but at least - /// one button must be supplied. - pub fn new(buttons: Vec<Button>) -> Self { - if buttons.is_empty() { - panic!("Tried to create a binding without any keys."); - } - - Self { buttons } - } - - /// Returns `true` if only mouse buttons are present in this binding, otherwise false. - pub fn mouse_only(&self) -> bool { - for button in &self.buttons { - match button { - Button::Mouse(_) => continue, - _ => return false, - } - } - - true - } - - /// Returns `true` if only keyboard buttons are present in this binding, otherwise false. - pub fn keyboard_only(&self) -> bool { - for button in &self.buttons { - match button { - Button::Scancode(_) | Button::Text(_) => continue, - _ => return false, - } - } - - true - } - - /// Returns `true` if at least one mouse button is required for this binding to work. - pub fn has_mouse_component(&self) -> bool { - self.buttons.iter().any(|b| { - if let Button::Mouse(_) = b { - true - } else { - false - } - }) - } - - /// Returns `true` if at least one keyboard button is required for this binding to work. - pub fn has_keyboard_component(&self) -> bool { - self.buttons.iter().any(|b| match b { - Button::Scancode(_) | Button::Text(_) => true, - _ => false, - }) - } - - /// Checks if this binding was pressed this frame. Heavily dependent on input struct working - /// correctly. - pub(super) fn is_pressed( - &self, - allow_mouse: bool, - allow_keyboard: bool, - text: &str, - rl: &RaylibHandle, - ) -> bool { - let mut distinct_press = false; - for button in &self.buttons { - match *button { - Button::Mouse(mouse_button) => { - if !allow_mouse || !rl.is_mouse_button_down(mouse_button.into()) { - return false; - } - - /* Check if the button has been pressed in this frame exactly. - * This prevents activating the same keybinding every frame - * while the buttons are being held down. - */ - if rl.is_mouse_button_pressed(mouse_button.into()) { - distinct_press = true; - } - } - Button::Scancode(code) => { - if !allow_keyboard || !rl.is_key_down(code.into()) { - return false; - } - - // Check the same as with the mouse button. - if rl.is_key_pressed(code.into()) { - distinct_press = true; - } - } - Button::Text(c) => { - if !allow_keyboard || !text.contains(c) { - return false; - } - - // Always distinct, since on triggering, the text is cleared. - distinct_press = true; - } - } - } - - distinct_press - } -} - -impl From<Button> for Binding { - fn from(button: Button) -> Self { - Self { - buttons: vec![button], - } - } -} diff --git a/src/input/button.rs b/src/input/button.rs deleted file mode 100644 index e9ef45e..0000000 --- a/src/input/button.rs +++ /dev/null @@ -1,177 +0,0 @@ -//! Reimplementation crate of the KeyboardKey and MouseButton structs of raylib, because they do -//! not implement `serde::Serialize` and `serde::Deserialize`. If you have a better idea on how to -//! handle it, feel free. - -use raylib::ffi::{KeyboardKey as rlKeyboardKey, MouseButton as rlMouseButton}; -use serde::{Deserialize, Serialize}; -use std::mem; - -/// Abstraction over different key-types. A binding can be constructed from this button-type or -/// multiple button-presses can be chained together to create a binding. Just be careful to not -/// have bindings where one binding is included in another. This includes bindings where on your -/// keyboard you have Scancode(Shift) + Scancode(A) and another binding of Text(A) (Text(a) would -/// be okay) -#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum Button { - /// A button on the mouse (raylib supports just three :/ ) - Mouse(MouseButton), - /// Scancode that is sent by the OS. This can change between OSes, but stays the same between - /// runs and layout changes in the keyboard. - Scancode(Scancode), - /// The text input read from the operating system. This means even characters composed or - /// non-ASCII characters can be used. I mean, who doesn't want to bind the wall tool to 壁? - Text(char), -} - -#[allow(missing_docs)] -#[repr(u32)] -#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum MouseButton { - Left = 0, - Right = 1, - Middle = 2, -} - -#[allow(missing_docs)] -#[repr(u32)] -#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum Scancode { - Apostrophe = 39, - Comma = 44, - Minus = 45, - Period = 46, - Slash = 47, - Zero = 48, - One = 49, - Two = 50, - Three = 51, - Four = 52, - Five = 53, - Six = 54, - Seven = 55, - Eight = 56, - Nine = 57, - Semicolon = 59, - Equal = 61, - A = 65, - B = 66, - C = 67, - D = 68, - E = 69, - F = 70, - G = 71, - H = 72, - I = 73, - J = 74, - K = 75, - L = 76, - M = 77, - N = 78, - O = 79, - P = 80, - Q = 81, - R = 82, - S = 83, - T = 84, - U = 85, - V = 86, - W = 87, - X = 88, - Y = 89, - Z = 90, - Space = 32, - Escape = 256, - Enter = 257, - Tab = 258, - Backspace = 259, - Insert = 260, - Delete = 261, - Right = 262, - Left = 263, - Down = 264, - Up = 265, - PageUp = 266, - PageDown = 267, - Home = 268, - End = 269, - CapsLock = 280, - ScrollLock = 281, - NumLock = 282, - PrintScreen = 283, - Pause = 284, - F1 = 290, - F2 = 291, - F3 = 292, - F4 = 293, - F5 = 294, - F6 = 295, - F7 = 296, - F8 = 297, - F9 = 298, - F10 = 299, - F11 = 300, - F12 = 301, - LeftShift = 340, - LeftControl = 341, - LeftAlt = 342, - LeftSuper = 343, - RightShift = 344, - RightControl = 345, - RightAlt = 346, - RightSuper = 347, - Menu = 348, - LeftBracket = 91, - Backslash = 92, - RightBracket = 93, - Grave = 96, - Keypad0 = 320, - Keypad1 = 321, - Keypad2 = 322, - Keypad3 = 323, - Keypad4 = 324, - Keypad5 = 325, - Keypad6 = 326, - Keypad7 = 327, - Keypad8 = 328, - Keypad9 = 329, - KeypadDecimal = 330, - KeypadDivide = 331, - KeypadMultiply = 332, - KeypadSubtract = 333, - KeypadAdd = 334, - KeypadEnter = 335, - KeypadEqual = 336, -} - -impl From<rlMouseButton> for Button { - fn from(button: rlMouseButton) -> Self { - Self::Mouse(MouseButton::from(button)) - } -} -impl From<rlKeyboardKey> for Button { - fn from(key: rlKeyboardKey) -> Self { - Self::Scancode(Scancode::from(key)) - } -} - -impl From<rlMouseButton> for MouseButton { - fn from(button: rlMouseButton) -> Self { - unsafe { mem::transmute(button as u32) } - } -} -impl Into<rlMouseButton> for MouseButton { - fn into(self) -> rlMouseButton { - unsafe { mem::transmute(self as u32) } - } -} - -impl From<rlKeyboardKey> for Scancode { - fn from(key: rlKeyboardKey) -> Self { - unsafe { mem::transmute(key as u32) } - } -} -impl Into<rlKeyboardKey> for Scancode { - fn into(self) -> rlKeyboardKey { - unsafe { mem::transmute(self as u32) } - } -} diff --git a/src/input/mod.rs b/src/input/mod.rs deleted file mode 100644 index e8b1821..0000000 --- a/src/input/mod.rs +++ /dev/null @@ -1,200 +0,0 @@ -//! Input with binding abstraction -//! -//! Binding keys or combinations to specific actions with just raylib alone is difficult to handle in -//! input-heavy applications, as opposed to games. This is an optimisation effort. To understand how -//! it works, the first thing to know is that there are two main modes for bindings, which are local -//! and global. A local binding is specific to a certain area of the window and is used to block the -//! mouse from being sent to many different targets (think of a pop-up window over the editor, which -//! must capture the mouse). Global bindings will be processed as long as no local binding has -//! prevalence, but they do not have an area that needs to be managed by a handler. -//! -//! In summary, the local <-> global distinction is used to capture the mouse. -//! -//! Some elements want to capture the keyboard, for instance, when activating a text box, the text -//! input should only go to this box, but should a tool be bound to a character, it should not -//! activate when typing. For this purpose, any element may seize control as long as no other element -//! still has the focus. A channel is opened and no bindings will be processed. Instead the text -//! together with a few control characters is relayed directly to the channel, until the receiver -//! hangs up. -//! -//! In summary, a channel is used to seize control of the keyboard when typing into an element. - -pub mod binding; -pub mod button; - -pub use binding::*; -pub use button::*; - -use crate::math::{ExactSurface, Rect, Vec2}; -use crate::stable_vec::StableVec; -use raylib::ffi::KeyboardKey; -use raylib::RaylibHandle; -use std::collections::HashMap; -use std::sync::mpsc::{self, Receiver, Sender}; - -/// Input and binding handler this should only be created once per instance. -pub struct Input { - global_bindings: HashMap<Binding, bool>, - local_bindings: StableVec<(Rect<u16>, HashMap<Binding, bool>)>, - last_text: String, - text_pipe: Option<Sender<char>>, - mouse_pos: Vec2<u16>, -} - -impl Input { - /// Create a new Input and binding handler. - pub fn new(rl: &RaylibHandle) -> Self { - Self { - global_bindings: HashMap::new(), - local_bindings: StableVec::new(), - last_text: String::new(), - text_pipe: None, - mouse_pos: Vec2::new(rl.get_mouse_x() as u16, rl.get_mouse_y() as u16), - } - } - - /// Must be called on every frame of the program, since keypresses will be processed here. This - /// will not activate the binding function directly, since raylib is heavily polling focused. - pub fn update(&mut self, rl: &mut RaylibHandle) { - self.mouse_pos = Vec2::new(rl.get_mouse_x() as u16, rl.get_mouse_y() as u16); - /* Read the next character to be sent with some extra characters - * raylib doesn't recognize to be valid. - */ - let c = if rl.is_key_pressed(KeyboardKey::KEY_ENTER) { - Some('\n') - } else if rl.is_key_pressed(KeyboardKey::KEY_ESCAPE) { - Some('\x1B') - } else if rl.is_key_pressed(KeyboardKey::KEY_BACKSPACE) { - Some('\x7f') - } else { - rl.get_key_pressed_number().map(|c| c as u8 as char) - }; - - /* Send the character to the listening entity or push it to the text that - * is currently being read for the keybindings. - */ - if let Some(text_pipe) = self.text_pipe.as_mut() { - if let Some(c) = c { - if text_pipe.send(c).is_err() { - self.last_text.push(c); - self.text_pipe = None; - } - } - } else if let Some(c) = c { - self.last_text.push(c); - } - - /* Update the local parts. The local stack has priority over the global - * bindings, so it is processed first, with the priority going from the - * top of the stack to the bottom in that order (reversed vec order) - */ - let mut mouse_blocked = false; - for (_, (rect, bindings)) in self.local_bindings.id_iter_mut().rev() { - if rect.contains_point(&self.mouse_pos) { - for (binding, state) in &mut bindings.iter_mut() { - *state = binding.is_pressed( - !mouse_blocked, - self.text_pipe.is_none(), - &self.last_text, - rl, - ); - - if *state { - self.last_text.clear(); - } - } - - mouse_blocked = true; - break; - } - } - - /* Process the global bindings, as long as nothing prevents the bindings - * from being processed like a local binding or the text being captured. - */ - for (binding, state) in self.global_bindings.iter_mut() { - *state = binding.is_pressed( - !mouse_blocked, - self.text_pipe.is_none(), - &self.last_text, - rl, - ); - - if *state { - self.last_text.clear(); - } - } - } - - /// Add a global binding. This is necessary so the input knows which key presses to monitor. - pub fn add_global(&mut self, binding: Binding) -> bool { - self.global_bindings.insert(binding, false).is_none() - } - - /// Add a local binding handler for the given area. Returns a unique and unchanging handler id. - /// Handlers with higher ids (that have been added later) are preferred over old handlers. - pub fn add_local_handler(&mut self, area: Rect<u16>) -> usize { - self.local_bindings.push((area, HashMap::new())) - } - - /// Add a local binding for the given handler. - pub fn add_local(&mut self, handler_id: usize, binding: Binding) -> bool { - self.local_bindings - .get_mut(handler_id) - .expect("Handler does not exist") - .1 - .insert(binding, false) - .is_none() - } - - /// Update the binding rectangle of a handler. - pub fn set_binding_rect(&mut self, handler_id: usize, rect: Rect<u16>) { - self.local_bindings - .get_mut(handler_id) - .expect("Handler does not exist") - .0 = rect; - } - - /// Check if a global binding has been activated this frame. If so, it returns true. - /// This will only activate once, so there is no need to worry about multiple function calls - /// when the user keeps the button down. - pub fn poll_global(&mut self, binding: &Binding) -> bool { - let state = self.global_bindings.get_mut(&binding); - if state.is_none() { - error!("Tried to poll binding that isn't registered."); - return false; - } - - *state.unwrap() - } - - /// Like `poll_global` bun instead checks the bindings of the local handler with the given id. - pub fn poll_local(&mut self, handler_id: usize, binding: &Binding) -> bool { - let (_, bindings) = self - .local_bindings - .get_mut(handler_id) - .expect("Invalid binding handler id"); - - let state = bindings.get_mut(&binding); - if state.is_none() { - error!("Tried to poll binding that isn't registered."); - return false; - } - - *state.unwrap() - } - - /// Attempts to capture all keyboard input from here on. If no other component is currently - /// capturing, it returns a receiver that can be used. When the entity no longer wants to - /// capture the keyboard, control must be returned by dropping the receiver. - pub fn try_capture_keyboard(&mut self) -> Option<Receiver<char>> { - if self.text_pipe.is_some() { - return None; - } - - let (tx, rx) = mpsc::channel(); - self.text_pipe = Some(tx); - - Some(rx) - } -} |
