est_render/
input.rs

1use std::collections::HashMap;
2
3use smol_str::SmolStr;
4
5use crate::{math::Point2, runner::{Event, Runner}, utils::ArcRef};
6
7pub type KeyboardEvent = Box<dyn Fn(&str, bool) + Send + Sync>;
8pub type MouseEvent = Box<dyn Fn(&str, Point2, bool) + Send + Sync>;
9pub type MouseMoveEvent = Box<dyn Fn(Point2) + Send + Sync>;
10
11#[derive(Debug, Clone)]
12pub struct Input {
13    pub(crate) inner: ArcRef<InputInner>,
14}
15
16impl Input {
17    pub(crate) fn new(runner: &mut Runner, window_id: Option<usize>) -> Self {
18        let mut inner = InputInner::default();
19        inner.window_id = window_id;
20
21        let inner = ArcRef::new(inner);
22        runner.input_events_attributes.push(ArcRef::clone(&inner));
23
24        Self {
25            inner
26        }
27    }
28
29    /// Returns the current mouse position in pixels.
30    pub fn mouse_position(&self) -> Point2 {
31        self.inner.borrow().mouse_position
32    }
33
34    /// Returns true if the mouse button is currently pressed down.
35    /// 
36    /// Expected button names are:
37    /// - "Left"
38    /// - "Right"
39    /// - "Middle"
40    /// - "Back"
41    /// - "Forward"
42    pub fn mouse_pressed(&self, button: &str) -> bool {
43        self.inner.borrow()
44            .mouse_buttons
45            .get(button)
46            .copied()
47            .unwrap_or(false)
48    }
49
50    /// Returns true if the mouse button was pressed once since the last call to this method.
51    /// 
52    /// See [`Input::mouse_pressed`] for expected button names.
53    pub fn mouse_pressed_once(&self, button: &str) -> bool {
54        let mut inner = self.inner.borrow_mut();
55        if let Some(pressed) = inner.mouse_buttons_once.get(button) {
56            if *pressed {
57                inner.mouse_buttons_once.insert(SmolStr::from(button), false);
58                return true;
59            }
60        }
61
62        false
63    }
64
65    /// Returns true if the key is currently pressed down.
66    /// 
67    /// The key should be a string representation of the key, such as "a", "Enter", "Space", etc.
68    /// 
69    /// The normal key names are used, such as:
70    /// - "a"
71    /// - "b"
72    /// - etc.
73    /// 
74    /// The modifier keys are also supported such as:
75    /// - "Shift"
76    /// - etc.
77    /// 
78    /// Which also can be combined with other keys, such as:
79    /// - "A" (Shift + "a")
80    /// - "B" (Shift + "b")
81    /// - etc.
82    /// 
83    /// This also supports unknown scancodes!
84    pub fn key_pressed(&self, key: &str) -> bool {
85        self.inner.borrow()
86            .keyboard_keys
87            .get(key)
88            .copied()
89            .unwrap_or(false)
90    }
91
92    /// Returns true if the key was pressed once since the last call to this method.
93    /// 
94    /// See [`Input::key_pressed`] for expected key names.
95    pub fn key_pressed_once(&self, key: &str) -> bool {
96        let mut inner = self.inner.borrow_mut();
97        if let Some(pressed) = inner.keyboard_keys_once.get(key) {
98            if *pressed {
99                inner.keyboard_keys_once.insert(SmolStr::from(key), false);
100                return true;
101            }
102        }
103
104        false
105    }
106
107    /// Listens for mouse events.
108    pub fn listen_mouse_event<F>(&mut self, event: F)
109    where
110        F: Fn(&str, Point2, bool) + Send + Sync + 'static,
111    {
112        self.inner.borrow_mut().mouse_events.push(Box::new(event));
113    }
114
115    /// Listens for mouse move events.
116    pub fn listen_mouse_move_event<F>(&mut self, event: F)
117    where
118        F: Fn(Point2) + Send + Sync + 'static,
119    {
120        self.inner.borrow_mut().mouse_move_events.push(Box::new(event));
121    }
122
123    /// Listens for keyboard events.
124    pub fn listen_keyboard_event<F>(&mut self, event: F)
125    where
126        F: Fn(&str, bool) + Send + Sync + 'static,
127    {
128        self.inner.borrow_mut().keyboard_events.push(Box::new(event));
129    }
130}
131
132#[derive(Default)]
133pub(crate) struct InputInner {
134    window_id: Option<usize>,
135
136    mouse_position: Point2,
137
138    mouse_buttons: HashMap<SmolStr, bool>,
139    mouse_buttons_once: HashMap<SmolStr, bool>,
140
141    keyboard_keys: HashMap<SmolStr, bool>,
142    keyboard_keys_once: HashMap<SmolStr, bool>,
143
144    mouse_events: Vec<MouseEvent>,
145    keyboard_events: Vec<KeyboardEvent>,
146    mouse_move_events: Vec<MouseMoveEvent>,
147}
148
149impl InputInner {
150    pub fn process_event(&mut self, event: &Event) {
151        match event {
152            Event::CursorMoved { pos, window_id } => {
153                if self.window_id.is_some() && self.window_id != Some(*window_id) {
154                    return;
155                }
156
157                self.mouse_position = Point2::new(pos.x as f32, pos.y as f32);
158
159                for mouse_move_event in &self.mouse_move_events {
160                    mouse_move_event(self.mouse_position);
161                }
162            }
163            Event::MouseInput { button, pressed, window_id } => {
164                if self.window_id.is_some() && self.window_id != Some(*window_id) {
165                    return;
166                }
167                let last_state = self.mouse_buttons.get(button).copied().unwrap_or(false);
168                self.mouse_buttons.insert(button.clone(), *pressed);
169                self.mouse_buttons_once.insert(button.clone(), *pressed);
170
171                if last_state != *pressed {
172                    for mouse_event in &self.mouse_events {
173                        mouse_event(button, self.mouse_position, *pressed);
174                    }
175                }
176            }
177            Event::KeyboardInput { key, pressed, window_id } => {
178                if self.window_id.is_some() && self.window_id != Some(*window_id) {
179                    return;
180                }
181
182                let last_state = self.keyboard_keys.get(key).copied().unwrap_or(false);
183                self.keyboard_keys.insert(key.clone(), *pressed);
184                self.keyboard_keys_once.insert(key.clone(), *pressed);
185
186                if last_state != *pressed {
187                    for keyboard_event in &self.keyboard_events {
188                        keyboard_event(key, *pressed);
189                    }
190                }
191            }
192            _ => {}
193        }
194    }
195}