On Web, implement DeviceEvents (#2871)
This commit is contained in:
parent
9a9c9b15ba
commit
6300cf915e
8 changed files with 405 additions and 85 deletions
|
|
@ -1,17 +1,24 @@
|
|||
use super::super::DeviceId;
|
||||
use super::{backend, state::State};
|
||||
use crate::dpi::PhysicalSize;
|
||||
use crate::event::{Event, StartCause};
|
||||
use crate::event_loop::ControlFlow;
|
||||
use crate::event::{
|
||||
DeviceEvent, DeviceId as RootDeviceId, ElementState, Event, RawKeyEvent, StartCause,
|
||||
};
|
||||
use crate::event_loop::{ControlFlow, DeviceEvents};
|
||||
use crate::platform_impl::platform::backend::EventListenerHandle;
|
||||
use crate::window::WindowId;
|
||||
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
cell::{Cell, RefCell},
|
||||
clone::Clone,
|
||||
collections::{HashSet, VecDeque},
|
||||
iter,
|
||||
ops::Deref,
|
||||
rc::{Rc, Weak},
|
||||
};
|
||||
use wasm_bindgen::prelude::Closure;
|
||||
use web_sys::{KeyboardEvent, PointerEvent, WheelEvent};
|
||||
use web_time::{Duration, Instant};
|
||||
|
||||
pub struct Shared<T: 'static>(Rc<Execution<T>>);
|
||||
|
|
@ -24,6 +31,8 @@ impl<T> Clone for Shared<T> {
|
|||
}
|
||||
}
|
||||
|
||||
type OnEventHandle<T> = RefCell<Option<EventListenerHandle<dyn FnMut(T)>>>;
|
||||
|
||||
pub struct Execution<T: 'static> {
|
||||
runner: RefCell<RunnerEnum<T>>,
|
||||
events: RefCell<VecDeque<EventWrapper<T>>>,
|
||||
|
|
@ -33,6 +42,13 @@ pub struct Execution<T: 'static> {
|
|||
redraw_pending: RefCell<HashSet<WindowId>>,
|
||||
destroy_pending: RefCell<VecDeque<WindowId>>,
|
||||
unload_event_handle: RefCell<Option<backend::UnloadEventHandle>>,
|
||||
device_events: Cell<DeviceEvents>,
|
||||
on_mouse_move: OnEventHandle<PointerEvent>,
|
||||
on_wheel: OnEventHandle<WheelEvent>,
|
||||
on_mouse_press: OnEventHandle<PointerEvent>,
|
||||
on_mouse_release: OnEventHandle<PointerEvent>,
|
||||
on_key_press: OnEventHandle<KeyboardEvent>,
|
||||
on_key_release: OnEventHandle<KeyboardEvent>,
|
||||
}
|
||||
|
||||
enum RunnerEnum<T: 'static> {
|
||||
|
|
@ -131,6 +147,13 @@ impl<T: 'static> Shared<T> {
|
|||
redraw_pending: RefCell::new(HashSet::new()),
|
||||
destroy_pending: RefCell::new(VecDeque::new()),
|
||||
unload_event_handle: RefCell::new(None),
|
||||
device_events: Cell::default(),
|
||||
on_mouse_move: RefCell::new(None),
|
||||
on_wheel: RefCell::new(None),
|
||||
on_mouse_press: RefCell::new(None),
|
||||
on_mouse_release: RefCell::new(None),
|
||||
on_key_press: RefCell::new(None),
|
||||
on_key_release: RefCell::new(None),
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
@ -165,6 +188,184 @@ impl<T: 'static> Shared<T> {
|
|||
Some(backend::on_unload(self.window(), move || {
|
||||
close_instance.handle_unload()
|
||||
}));
|
||||
|
||||
let runner = self.clone();
|
||||
let window = self.window().clone();
|
||||
*self.0.on_mouse_move.borrow_mut() = Some(EventListenerHandle::new(
|
||||
self.window(),
|
||||
"pointermove",
|
||||
Closure::new(move |event: PointerEvent| {
|
||||
if !runner.device_events() {
|
||||
return;
|
||||
}
|
||||
|
||||
let pointer_type = event.pointer_type();
|
||||
|
||||
if pointer_type != "mouse" {
|
||||
return;
|
||||
}
|
||||
|
||||
// chorded button event
|
||||
let device_id = RootDeviceId(DeviceId(event.pointer_id()));
|
||||
|
||||
if let Some(button) = backend::event::mouse_button(&event) {
|
||||
debug_assert_eq!(
|
||||
pointer_type, "mouse",
|
||||
"expect pointer type of a chorded button event to be a mouse"
|
||||
);
|
||||
|
||||
let state = if backend::event::mouse_buttons(&event).contains(button.into()) {
|
||||
ElementState::Pressed
|
||||
} else {
|
||||
ElementState::Released
|
||||
};
|
||||
|
||||
runner.send_event(Event::DeviceEvent {
|
||||
device_id,
|
||||
event: DeviceEvent::Button {
|
||||
button: button.to_id(),
|
||||
state,
|
||||
},
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// pointer move event
|
||||
let mut delta = backend::event::MouseDelta::init(&window, &event);
|
||||
runner.send_events(backend::event::pointer_move_event(event).flat_map(|event| {
|
||||
let delta = delta
|
||||
.delta(&event)
|
||||
.to_physical(backend::scale_factor(&window));
|
||||
|
||||
let x_motion = (delta.x != 0.0).then_some(Event::DeviceEvent {
|
||||
device_id,
|
||||
event: DeviceEvent::Motion {
|
||||
axis: 0,
|
||||
value: delta.x,
|
||||
},
|
||||
});
|
||||
|
||||
let y_motion = (delta.y != 0.0).then_some(Event::DeviceEvent {
|
||||
device_id,
|
||||
event: DeviceEvent::Motion {
|
||||
axis: 1,
|
||||
value: delta.y,
|
||||
},
|
||||
});
|
||||
|
||||
x_motion
|
||||
.into_iter()
|
||||
.chain(y_motion)
|
||||
.chain(iter::once(Event::DeviceEvent {
|
||||
device_id,
|
||||
event: DeviceEvent::MouseMotion {
|
||||
delta: (delta.x, delta.y),
|
||||
},
|
||||
}))
|
||||
}));
|
||||
}),
|
||||
));
|
||||
let runner = self.clone();
|
||||
let window = self.window().clone();
|
||||
*self.0.on_wheel.borrow_mut() = Some(EventListenerHandle::new(
|
||||
self.window(),
|
||||
"wheel",
|
||||
Closure::new(move |event: WheelEvent| {
|
||||
if !runner.device_events() {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(delta) = backend::event::mouse_scroll_delta(&window, &event) {
|
||||
runner.send_event(Event::DeviceEvent {
|
||||
device_id: RootDeviceId(DeviceId(0)),
|
||||
event: DeviceEvent::MouseWheel { delta },
|
||||
});
|
||||
}
|
||||
}),
|
||||
));
|
||||
let runner = self.clone();
|
||||
*self.0.on_mouse_press.borrow_mut() = Some(EventListenerHandle::new(
|
||||
self.window(),
|
||||
"pointerdown",
|
||||
Closure::new(move |event: PointerEvent| {
|
||||
if !runner.device_events() {
|
||||
return;
|
||||
}
|
||||
|
||||
if event.pointer_type() != "mouse" {
|
||||
return;
|
||||
}
|
||||
|
||||
let button = backend::event::mouse_button(&event).expect("no mouse button pressed");
|
||||
runner.send_event(Event::DeviceEvent {
|
||||
device_id: RootDeviceId(DeviceId(event.pointer_id())),
|
||||
event: DeviceEvent::Button {
|
||||
button: button.to_id(),
|
||||
state: ElementState::Pressed,
|
||||
},
|
||||
});
|
||||
}),
|
||||
));
|
||||
let runner = self.clone();
|
||||
*self.0.on_mouse_release.borrow_mut() = Some(EventListenerHandle::new(
|
||||
self.window(),
|
||||
"pointerup",
|
||||
Closure::new(move |event: PointerEvent| {
|
||||
if !runner.device_events() {
|
||||
return;
|
||||
}
|
||||
|
||||
if event.pointer_type() != "mouse" {
|
||||
return;
|
||||
}
|
||||
|
||||
let button = backend::event::mouse_button(&event).expect("no mouse button pressed");
|
||||
runner.send_event(Event::DeviceEvent {
|
||||
device_id: RootDeviceId(DeviceId(event.pointer_id())),
|
||||
event: DeviceEvent::Button {
|
||||
button: button.to_id(),
|
||||
state: ElementState::Released,
|
||||
},
|
||||
});
|
||||
}),
|
||||
));
|
||||
let runner = self.clone();
|
||||
*self.0.on_key_press.borrow_mut() = Some(EventListenerHandle::new(
|
||||
self.window(),
|
||||
"keydown",
|
||||
Closure::new(move |event: KeyboardEvent| {
|
||||
if !runner.device_events() {
|
||||
return;
|
||||
}
|
||||
|
||||
runner.send_event(Event::DeviceEvent {
|
||||
device_id: RootDeviceId(unsafe { DeviceId::dummy() }),
|
||||
event: DeviceEvent::Key(RawKeyEvent {
|
||||
physical_key: backend::event::key_code(&event),
|
||||
state: ElementState::Pressed,
|
||||
}),
|
||||
});
|
||||
}),
|
||||
));
|
||||
let runner = self.clone();
|
||||
*self.0.on_key_release.borrow_mut() = Some(EventListenerHandle::new(
|
||||
self.window(),
|
||||
"keyup",
|
||||
Closure::new(move |event: KeyboardEvent| {
|
||||
if !runner.device_events() {
|
||||
return;
|
||||
}
|
||||
|
||||
runner.send_event(Event::DeviceEvent {
|
||||
device_id: RootDeviceId(unsafe { DeviceId::dummy() }),
|
||||
event: DeviceEvent::Key(RawKeyEvent {
|
||||
physical_key: backend::event::key_code(&event),
|
||||
state: ElementState::Released,
|
||||
}),
|
||||
});
|
||||
}),
|
||||
));
|
||||
}
|
||||
|
||||
// Generate a strictly increasing ID
|
||||
|
|
@ -405,6 +606,12 @@ impl<T: 'static> Shared<T> {
|
|||
self.handle_event(Event::LoopDestroyed, control);
|
||||
let all_canvases = std::mem::take(&mut *self.0.all_canvases.borrow_mut());
|
||||
*self.0.unload_event_handle.borrow_mut() = None;
|
||||
*self.0.on_mouse_move.borrow_mut() = None;
|
||||
*self.0.on_wheel.borrow_mut() = None;
|
||||
*self.0.on_mouse_press.borrow_mut() = None;
|
||||
*self.0.on_mouse_release.borrow_mut() = None;
|
||||
*self.0.on_key_press.borrow_mut() = None;
|
||||
*self.0.on_key_release.borrow_mut() = None;
|
||||
// Dropping the `Runner` drops the event handler closure, which will in
|
||||
// turn drop all `Window`s moved into the closure.
|
||||
*self.0.runner.borrow_mut() = RunnerEnum::Destroyed;
|
||||
|
|
@ -450,6 +657,24 @@ impl<T: 'static> Shared<T> {
|
|||
RunnerEnum::Destroyed => ControlFlow::Exit,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listen_device_events(&self, allowed: DeviceEvents) {
|
||||
self.0.device_events.set(allowed)
|
||||
}
|
||||
|
||||
pub fn device_events(&self) -> bool {
|
||||
match self.0.device_events.get() {
|
||||
DeviceEvents::Always => true,
|
||||
DeviceEvents::WhenFocused => self.0.all_canvases.borrow().iter().any(|(_, canvas)| {
|
||||
if let Some(canvas) = canvas.upgrade() {
|
||||
canvas.borrow().has_focus.load(Ordering::Relaxed)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}),
|
||||
DeviceEvents::Never => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum EventWrapper<T: 'static> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue