aboutsummaryrefslogtreecommitdiff
path: root/src/input
diff options
context:
space:
mode:
authorArne Dußin2021-01-27 14:01:50 +0100
committerArne Dußin2021-02-02 22:16:15 +0100
commitf92e9f6f07b1e3834c2ca58ce3510734819d08e4 (patch)
tree20e3d3afce342a56ae98f6c20491482ccd2b5c6b /src/input
parentc60a6d07efb120724b308e29e8e70f27c87c952d (diff)
downloadgraf_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.rs123
-rw-r--r--src/input/button.rs177
-rw-r--r--src/input/mod.rs200
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)
- }
-}