oxygengine_input_device_web/
mouse.rs

1use backend::closure::WebClosure;
2use core::{ecs::Universe, Scalar};
3use input::device::InputDevice;
4use std::{any::Any, cell::Cell, rc::Rc};
5use wasm_bindgen::{prelude::*, JsCast};
6use web_sys::*;
7
8pub struct WebMouseInputDevice {
9    element: EventTarget,
10    position: Rc<Cell<(Scalar, Scalar)>>,
11    left_button: Rc<Cell<bool>>,
12    right_button: Rc<Cell<bool>>,
13    middle_button: Rc<Cell<bool>>,
14    mouse_down_closure: WebClosure,
15    mouse_up_closure: WebClosure,
16    mouse_move_closure: WebClosure,
17}
18
19unsafe impl Send for WebMouseInputDevice {}
20unsafe impl Sync for WebMouseInputDevice {}
21
22impl WebMouseInputDevice {
23    pub fn new(element: EventTarget) -> Self {
24        Self {
25            element,
26            position: Default::default(),
27            left_button: Default::default(),
28            right_button: Default::default(),
29            middle_button: Default::default(),
30            mouse_down_closure: Default::default(),
31            mouse_up_closure: Default::default(),
32            mouse_move_closure: Default::default(),
33        }
34    }
35}
36
37impl InputDevice for WebMouseInputDevice {
38    fn name(&self) -> &str {
39        "mouse"
40    }
41
42    fn on_register(&mut self) {
43        {
44            let left_button = self.left_button.clone();
45            let right_button = self.right_button.clone();
46            let middle_button = self.middle_button.clone();
47            let closure = Closure::wrap(Box::new(move |event: MouseEvent| match event.button() {
48                0 => left_button.set(true),
49                2 => right_button.set(true),
50                1 => middle_button.set(true),
51                _ => {}
52            }) as Box<dyn FnMut(_)>);
53            self.element
54                .add_event_listener_with_callback("mousedown", closure.as_ref().unchecked_ref())
55                .unwrap();
56            self.mouse_down_closure = WebClosure::acquire(closure);
57        }
58        {
59            let left_button = self.left_button.clone();
60            let right_button = self.right_button.clone();
61            let middle_button = self.middle_button.clone();
62            let closure = Closure::wrap(Box::new(move |event: MouseEvent| match event.button() {
63                0 => left_button.set(false),
64                2 => right_button.set(false),
65                1 => middle_button.set(false),
66                _ => {}
67            }) as Box<dyn FnMut(_)>);
68            self.element
69                .add_event_listener_with_callback("mouseup", closure.as_ref().unchecked_ref())
70                .unwrap();
71            self.mouse_up_closure = WebClosure::acquire(closure);
72        }
73        {
74            let position = self.position.clone();
75            let closure = Closure::wrap(Box::new(move |event: MouseEvent| {
76                position.set((event.client_x() as Scalar, event.client_y() as Scalar));
77            }) as Box<dyn FnMut(_)>);
78            self.element
79                .add_event_listener_with_callback("mousemove", closure.as_ref().unchecked_ref())
80                .unwrap();
81            self.mouse_move_closure = WebClosure::acquire(closure);
82        }
83    }
84
85    fn on_unregister(&mut self) {
86        self.mouse_down_closure.release();
87        self.mouse_up_closure.release();
88        self.mouse_move_closure.release();
89    }
90
91    fn process(&mut self, _: &mut Universe) {}
92
93    fn query_axis(&self, name: &str) -> Option<Scalar> {
94        match name {
95            "x" => Some(self.position.get().0),
96            "y" => Some(self.position.get().1),
97            _ => None,
98        }
99    }
100
101    fn query_trigger(&self, name: &str) -> Option<bool> {
102        match name {
103            "left" => Some(self.left_button.get()),
104            "right" => Some(self.right_button.get()),
105            "middle" => Some(self.middle_button.get()),
106            _ => None,
107        }
108    }
109
110    fn query_text(&self) -> Option<String> {
111        None
112    }
113
114    fn as_any(&self) -> &dyn Any {
115        self
116    }
117}