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 pub fn mouse_position(&self) -> Point2 {
31 self.inner.borrow().mouse_position
32 }
33
34 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 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 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 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 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 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 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}