1use super::*;
2
3impl Input {
5 pub fn extract_key_code(event: &Event) -> String {
15 Reflect::get(event.as_ref(), &JsValue::from_str(INPUT_KEY_CODE_PROPERTY))
16 .ok()
17 .and_then(|value: JsValue| value.as_string())
18 .unwrap_or_default()
19 }
20
21 pub fn extract_mouse_button(event: &Event) -> MouseButton {
31 let button_value: i32 = Reflect::get(
32 event.as_ref(),
33 &JsValue::from_str(INPUT_MOUSE_BUTTON_PROPERTY),
34 )
35 .ok()
36 .and_then(|value: JsValue| value.as_f64())
37 .map(|float: f64| float as i32)
38 .unwrap_or(0);
39 match button_value {
40 0 => MouseButton::Left,
41 1 => MouseButton::Middle,
42 2 => MouseButton::Right,
43 3 => MouseButton::Button4,
44 4 => MouseButton::Button5,
45 _ => MouseButton::Left,
46 }
47 }
48
49 pub fn extract_mouse_position(event: &Event) -> Vector2D {
59 let client_x: f64 =
60 Reflect::get(event.as_ref(), &JsValue::from_str(INPUT_CLIENT_X_PROPERTY))
61 .ok()
62 .and_then(|value: JsValue| value.as_f64())
63 .unwrap_or(0.0);
64 let client_y: f64 =
65 Reflect::get(event.as_ref(), &JsValue::from_str(INPUT_CLIENT_Y_PROPERTY))
66 .ok()
67 .and_then(|value: JsValue| value.as_f64())
68 .unwrap_or(0.0);
69 Vector2D::new(client_x, client_y)
70 }
71}
72
73impl Input {
82 pub fn attach(
94 state_cell: InputStateCell,
95 window: &Window,
96 pointer_target: &EventTarget,
97 ) -> InputStateCell {
98 Self::attach_keyboard(&state_cell, window);
99 Self::attach_pointer(&state_cell, pointer_target);
100 state_cell
101 }
102
103 pub fn attach_keyboard(state_cell: &InputStateCell, window: &Window) {
114 let state_keydown: InputStateCell = state_cell.clone();
115 let keydown_closure: Closure<dyn FnMut(Event)> =
116 Closure::wrap(Box::new(move |event: Event| {
117 let code: String = Input::extract_key_code(&event);
118 if code.is_empty() {
119 return;
120 }
121 let state: &mut InputState = state_keydown.get_mut();
122 state.press_key(code);
123 }));
124 Self::register_listener(window, INPUT_EVENT_KEYDOWN, keydown_closure);
125 let state_keyup: InputStateCell = state_cell.clone();
126 let keyup_closure: Closure<dyn FnMut(Event)> =
127 Closure::wrap(Box::new(move |event: Event| {
128 let code: String = Input::extract_key_code(&event);
129 if code.is_empty() {
130 return;
131 }
132 let state: &mut InputState = state_keyup.get_mut();
133 state.release_key(code);
134 }));
135 Self::register_listener(window, INPUT_EVENT_KEYUP, keyup_closure);
136 }
137
138 pub fn attach_pointer(state_cell: &InputStateCell, target: &EventTarget) {
150 let state_mousedown: InputStateCell = state_cell.clone();
151 let mousedown_closure: Closure<dyn FnMut(Event)> =
152 Closure::wrap(Box::new(move |event: Event| {
153 let button: MouseButton = Input::extract_mouse_button(&event);
154 let position: Vector2D = Input::extract_mouse_position(&event);
155 let state: &mut InputState = state_mousedown.get_mut();
156 state.press_mouse_button(button, position);
157 }));
158 Self::register_listener(target, INPUT_EVENT_MOUSEDOWN, mousedown_closure);
159 let state_mouseup: InputStateCell = state_cell.clone();
160 let mouseup_closure: Closure<dyn FnMut(Event)> =
161 Closure::wrap(Box::new(move |event: Event| {
162 let button: MouseButton = Input::extract_mouse_button(&event);
163 let state: &mut InputState = state_mouseup.get_mut();
164 state.release_mouse_button(button);
165 }));
166 Self::register_listener(target, INPUT_EVENT_MOUSEUP, mouseup_closure);
167 let state_mousemove: InputStateCell = state_cell.clone();
168 let mousemove_closure: Closure<dyn FnMut(Event)> =
169 Closure::wrap(Box::new(move |event: Event| {
170 let position: Vector2D = Input::extract_mouse_position(&event);
171 let state: &mut InputState = state_mousemove.get_mut();
172 state.update_mouse_position(position);
173 }));
174 Self::register_listener(target, INPUT_EVENT_MOUSEMOVE, mousemove_closure);
175 let state_mouseleave: InputStateCell = state_cell.clone();
176 let mouseleave_closure: Closure<dyn FnMut(Event)> =
177 Closure::wrap(Box::new(move |_: Event| {
178 let state: &mut InputState = state_mouseleave.get_mut();
179 state.set_mouse_moved(false);
180 state.set_mouse_delta(Vector2D::zero());
181 }));
182 Self::register_listener(target, INPUT_EVENT_MOUSELEAVE, mouseleave_closure);
183 let state_touchstart: InputStateCell = state_cell.clone();
184 let touchstart_closure: Closure<dyn FnMut(Event)> =
185 Closure::wrap(Box::new(move |event: Event| {
186 event.prevent_default();
187 let state: &mut InputState = state_touchstart.get_mut();
188 for (identifier, position) in Input::extract_touch_positions(&event) {
189 state.start_touch(identifier, position);
190 }
191 }));
192 Self::register_listener(target, INPUT_EVENT_TOUCHSTART, touchstart_closure);
193 let state_touchmove: InputStateCell = state_cell.clone();
194 let touchmove_closure: Closure<dyn FnMut(Event)> =
195 Closure::wrap(Box::new(move |event: Event| {
196 event.prevent_default();
197 let state: &mut InputState = state_touchmove.get_mut();
198 for (identifier, position) in Input::extract_touch_positions(&event) {
199 state.update_touch(identifier, position);
200 }
201 }));
202 Self::register_listener(target, INPUT_EVENT_TOUCHMOVE, touchmove_closure);
203 let state_touchend: InputStateCell = state_cell.clone();
204 let touchend_closure: Closure<dyn FnMut(Event)> =
205 Closure::wrap(Box::new(move |event: Event| {
206 let state: &mut InputState = state_touchend.get_mut();
207 for identifier in Input::extract_touch_identifiers(&event) {
208 state.end_touch(identifier);
209 }
210 }));
211 Self::register_listener(target, INPUT_EVENT_TOUCHEND, touchend_closure);
212 let contextmenu_closure: Closure<dyn FnMut(Event)> =
213 Closure::wrap(Box::new(move |event: Event| {
214 event.prevent_default();
215 }));
216 Self::register_listener(target, INPUT_EVENT_CONTEXTMENU, contextmenu_closure);
217 }
218
219 fn extract_touch_positions(event: &Event) -> Vec<(i32, Vector2D)> {
232 let touch_event: &TouchEvent = event.unchecked_ref();
233 let touches: TouchList = touch_event.changed_touches();
234 let length: u32 = touches.length();
235 let mut out: Vec<(i32, Vector2D)> = Vec::with_capacity(length as usize);
236 for index in 0..length {
237 let Some(touch) = touches.get(index) else {
238 continue;
239 };
240 let identifier: i32 = touch.identifier();
241 let position: Vector2D =
242 Vector2D::new(f64::from(touch.client_x()), f64::from(touch.client_y()));
243 out.push((identifier, position));
244 }
245 out
246 }
247
248 fn extract_touch_identifiers(event: &Event) -> Vec<i32> {
258 let touch_event: &TouchEvent = event.unchecked_ref();
259 let touches: TouchList = touch_event.changed_touches();
260 let length: u32 = touches.length();
261 let mut out: Vec<i32> = Vec::with_capacity(length as usize);
262 for index in 0..length {
263 let Some(touch) = touches.get(index) else {
264 continue;
265 };
266 out.push(touch.identifier());
267 }
268 out
269 }
270
271 fn register_listener(
284 target: &EventTarget,
285 event_name: &str,
286 closure: Closure<dyn FnMut(Event)>,
287 ) {
288 let _: Result<(), JsValue> =
289 target.add_event_listener_with_callback(event_name, closure.as_ref().unchecked_ref());
290 closure.forget();
291 }
292}
293
294impl InputState {
296 pub fn press_key(&mut self, key_code: String) {
302 if !self.get_keys_held().contains(&key_code) {
303 self.get_mut_keys_pressed().insert(key_code.clone());
304 }
305 self.get_mut_keys_held().insert(key_code);
306 }
307
308 pub fn release_key(&mut self, key_code: String) {
314 self.get_mut_keys_held().remove(&key_code);
315 self.get_mut_keys_released().insert(key_code);
316 }
317
318 pub fn is_key_pressed<K>(&self, key_code: K) -> bool
328 where
329 K: AsRef<str>,
330 {
331 self.get_keys_pressed().contains(key_code.as_ref())
332 }
333
334 pub fn is_key_held<K>(&self, key_code: K) -> bool
344 where
345 K: AsRef<str>,
346 {
347 self.get_keys_held().contains(key_code.as_ref())
348 }
349
350 pub fn is_key_released<K>(&self, key_code: K) -> bool
360 where
361 K: AsRef<str>,
362 {
363 self.get_keys_released().contains(key_code.as_ref())
364 }
365
366 pub fn press_mouse_button(&mut self, button: MouseButton, position: Vector2D) {
373 if !self.get_mouse_buttons_held().contains(&button) {
374 self.get_mut_mouse_buttons_pressed().insert(button);
375 }
376 self.get_mut_mouse_buttons_held().insert(button);
377 self.set_mouse_position(position);
378 }
379
380 pub fn release_mouse_button(&mut self, button: MouseButton) {
386 self.get_mut_mouse_buttons_held().remove(&button);
387 self.get_mut_mouse_buttons_released().insert(button);
388 }
389
390 pub fn update_mouse_position(&mut self, position: Vector2D) {
396 self.set_mouse_delta(position - self.get_mouse_position());
397 self.set_mouse_position(position);
398 self.set_mouse_moved(true);
399 }
400
401 pub fn is_mouse_button_pressed(&self, button: MouseButton) -> bool {
411 self.get_mouse_buttons_pressed().contains(&button)
412 }
413
414 pub fn is_mouse_button_held(&self, button: MouseButton) -> bool {
424 self.get_mouse_buttons_held().contains(&button)
425 }
426
427 pub fn update_touch(&mut self, identifier: i32, position: Vector2D) {
434 self.get_mut_touch_points().insert(identifier, position);
435 }
436
437 pub fn start_touch(&mut self, identifier: i32, position: Vector2D) {
444 self.get_mut_touch_points().insert(identifier, position);
445 self.get_mut_touch_started().insert(identifier);
446 }
447
448 pub fn end_touch(&mut self, identifier: i32) {
454 self.get_mut_touch_points().remove(&identifier);
455 self.get_mut_touch_ended().insert(identifier);
456 }
457
458 pub fn primary_touch_position(&self) -> Option<Vector2D> {
470 self.touch_points
471 .iter()
472 .min_by_key(|(identifier, _)| **identifier)
473 .map(|(_, position)| *position)
474 }
475
476 pub fn end_frame(&mut self) {
480 self.get_mut_keys_pressed().clear();
481 self.get_mut_keys_released().clear();
482 self.get_mut_mouse_buttons_pressed().clear();
483 self.get_mut_mouse_buttons_released().clear();
484 self.set_mouse_delta(Vector2D::zero());
485 self.set_mouse_moved(false);
486 self.get_mut_touch_started().clear();
487 self.get_mut_touch_ended().clear();
488 }
489}
490
491impl Default for InputState {
493 fn default() -> InputState {
494 InputState::new()
495 }
496}