From 1dfca5a395dda90968809a562e87f5488ebc545b Mon Sep 17 00:00:00 2001 From: daxpedda Date: Mon, 28 Aug 2023 19:18:10 +0200 Subject: [PATCH] Enable event propagation (#3062) --- CHANGELOG.md | 1 + src/platform_impl/web/event_loop/runner.rs | 16 +- .../web/event_loop/window_target.rs | 179 +++++------------- src/platform_impl/web/web_sys/canvas.rs | 15 +- src/platform_impl/web/web_sys/event_handle.rs | 6 +- src/platform_impl/web/web_sys/mod.rs | 5 +- src/platform_impl/web/web_sys/pointer.rs | 29 +-- 7 files changed, 75 insertions(+), 176 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f386d4ee..a33d97dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ And please only add new entries to the top of this list, right below the `# Unre - On Web, never return a `MonitorHandle`. - **Breaking:** Move `Event::RedrawRequested` to `WindowEvent::RedrawRequested`. - On macOS, fix crash in `window.set_minimized(false)`. +- On Web, enable event propagation and let `DeviceEvent`s appear after `WindowEvent`s. # 0.29.1-beta diff --git a/src/platform_impl/web/event_loop/runner.rs b/src/platform_impl/web/event_loop/runner.rs index b5eeda41..bea6b281 100644 --- a/src/platform_impl/web/event_loop/runner.rs +++ b/src/platform_impl/web/event_loop/runner.rs @@ -201,7 +201,7 @@ impl Shared { self.init(); *self.0.page_transition_event_handle.borrow_mut() = Some(backend::on_page_transition( - self.window(), + self.window().clone(), { let runner = self.clone(); move |event: PageTransitionEvent| { @@ -227,7 +227,7 @@ impl Shared { let runner = self.clone(); let window = self.window().clone(); *self.0.on_mouse_move.borrow_mut() = Some(EventListenerHandle::new( - self.window(), + self.window().clone(), "pointermove", Closure::new(move |event: PointerEvent| { if !runner.device_events() { @@ -304,7 +304,7 @@ impl Shared { let runner = self.clone(); let window = self.window().clone(); *self.0.on_wheel.borrow_mut() = Some(EventListenerHandle::new( - self.window(), + self.window().clone(), "wheel", Closure::new(move |event: WheelEvent| { if !runner.device_events() { @@ -321,7 +321,7 @@ impl Shared { )); let runner = self.clone(); *self.0.on_mouse_press.borrow_mut() = Some(EventListenerHandle::new( - self.window(), + self.window().clone(), "pointerdown", Closure::new(move |event: PointerEvent| { if !runner.device_events() { @@ -344,7 +344,7 @@ impl Shared { )); let runner = self.clone(); *self.0.on_mouse_release.borrow_mut() = Some(EventListenerHandle::new( - self.window(), + self.window().clone(), "pointerup", Closure::new(move |event: PointerEvent| { if !runner.device_events() { @@ -367,7 +367,7 @@ impl Shared { )); let runner = self.clone(); *self.0.on_key_press.borrow_mut() = Some(EventListenerHandle::new( - self.window(), + self.window().clone(), "keydown", Closure::new(move |event: KeyboardEvent| { if !runner.device_events() { @@ -385,7 +385,7 @@ impl Shared { )); let runner = self.clone(); *self.0.on_key_release.borrow_mut() = Some(EventListenerHandle::new( - self.window(), + self.window().clone(), "keyup", Closure::new(move |event: KeyboardEvent| { if !runner.device_events() { @@ -404,7 +404,7 @@ impl Shared { let runner = self.clone(); *self.0.on_visibility_change.borrow_mut() = Some(EventListenerHandle::new( // Safari <14 doesn't support the `visibilitychange` event on `Window`. - self.document(), + self.document().clone(), "visibilitychange", Closure::new(move |_| { if !runner.0.suspended.get() { diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 7429e98f..e0901a35 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -17,8 +17,7 @@ use super::{ window::WindowId, }; use crate::event::{ - DeviceEvent, DeviceId as RootDeviceId, ElementState, Event, KeyEvent, RawKeyEvent, Touch, - TouchPhase, WindowEvent, + DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase, WindowEvent, }; use crate::event_loop::DeviceEvents; use crate::keyboard::ModifiersState; @@ -140,34 +139,24 @@ impl EventLoopWindowTarget { let device_id = RootDeviceId(unsafe { DeviceId::dummy() }); - let device_event = runner.device_events().then_some(Event::DeviceEvent { - device_id, - event: DeviceEvent::Key(RawKeyEvent { - physical_key, - state: ElementState::Pressed, - }), - }); - runner.send_events( - device_event - .into_iter() - .chain(iter::once(Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::KeyboardInput { - device_id, - event: KeyEvent { - physical_key, - logical_key, - text, - location, - state: ElementState::Pressed, - repeat, - platform_specific: KeyEventExtra, - }, - is_synthetic: false, + iter::once(Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::KeyboardInput { + device_id, + event: KeyEvent { + physical_key, + logical_key, + text, + location, + state: ElementState::Pressed, + repeat, + platform_specific: KeyEventExtra, }, - })) - .chain(modifiers_changed), + is_synthetic: false, + }, + }) + .chain(modifiers_changed), ); }, prevent_default, @@ -187,34 +176,24 @@ impl EventLoopWindowTarget { let device_id = RootDeviceId(unsafe { DeviceId::dummy() }); - let device_event = runner.device_events().then_some(Event::DeviceEvent { - device_id, - event: DeviceEvent::Key(RawKeyEvent { - physical_key, - state: ElementState::Pressed, - }), - }); - runner.send_events( - device_event - .into_iter() - .chain(iter::once(Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::KeyboardInput { - device_id, - event: KeyEvent { - physical_key, - logical_key, - text, - location, - state: ElementState::Released, - repeat, - platform_specific: KeyEventExtra, - }, - is_synthetic: false, + iter::once(Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::KeyboardInput { + device_id, + event: KeyEvent { + physical_key, + logical_key, + text, + location, + state: ElementState::Released, + repeat, + platform_specific: KeyEventExtra, }, - })) - .chain(modifiers_changed), + is_synthetic: false, + }, + }) + .chain(modifiers_changed), ) }, prevent_default, @@ -311,48 +290,17 @@ impl EventLoopWindowTarget { } }); - runner.send_events(modifiers.into_iter().chain(events.flat_map( - |(position, delta)| { - let device_id = RootDeviceId(DeviceId(pointer_id)); + runner.send_events(modifiers.into_iter().chain(events.flat_map(|position| { + let device_id = RootDeviceId(DeviceId(pointer_id)); - let device_events = runner.device_events().then(|| { - 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), - }, - }, - )) - }); - - device_events.into_iter().flatten().chain(iter::once( - Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::CursorMoved { - device_id, - position, - }, - }, - )) - }, - ))); + iter::once(Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::CursorMoved { + device_id, + position, + }, + }) + }))); } }, { @@ -413,18 +361,10 @@ impl EventLoopWindowTarget { ElementState::Released }; - let device_event = runner.device_events().then(|| Event::DeviceEvent { - device_id, - event: DeviceEvent::Button { - button: button.to_id(), - state, - }, - }); - // A chorded button event may come in without any prior CursorMoved events, // therefore we should send a CursorMoved event to make sure that the // user code has the correct cursor position. - runner.send_events(modifiers.into_iter().chain(device_event).chain([ + runner.send_events(modifiers.into_iter().chain([ Event::WindowEvent { window_id: RootWindowId(id), event: WindowEvent::CursorMoved { @@ -475,18 +415,11 @@ impl EventLoopWindowTarget { }); let device_id: RootDeviceId = RootDeviceId(DeviceId(pointer_id)); - let device_event = runner.device_events().then(|| Event::DeviceEvent { - device_id, - event: DeviceEvent::Button { - button: button.to_id(), - state: ElementState::Pressed, - }, - }); // A mouse down event may come in without any prior CursorMoved events, // therefore we should send a CursorMoved event to make sure that the // user code has the correct cursor position. - runner.send_events(modifiers.into_iter().chain(device_event).chain([ + runner.send_events(modifiers.into_iter().chain([ Event::WindowEvent { window_id: RootWindowId(id), event: WindowEvent::CursorMoved { @@ -568,18 +501,11 @@ impl EventLoopWindowTarget { }); let device_id: RootDeviceId = RootDeviceId(DeviceId(pointer_id)); - let device_event = runner.device_events().then(|| Event::DeviceEvent { - device_id, - event: DeviceEvent::Button { - button: button.to_id(), - state: ElementState::Pressed, - }, - }); // A mouse up event may come in without any prior CursorMoved events, // therefore we should send a CursorMoved event to make sure that the // user code has the correct cursor position. - runner.send_events(modifiers.into_iter().chain(device_event).chain([ + runner.send_events(modifiers.into_iter().chain([ Event::WindowEvent { window_id: RootWindowId(id), event: WindowEvent::CursorMoved { @@ -644,21 +570,16 @@ impl EventLoopWindowTarget { } }); - let device_event = runner.device_events().then_some(Event::DeviceEvent { - device_id: RootDeviceId(DeviceId(pointer_id)), - event: DeviceEvent::MouseWheel { delta }, - }); - - runner.send_events(modifiers_changed.into_iter().chain(device_event).chain( - iter::once(Event::WindowEvent { + runner.send_events(modifiers_changed.into_iter().chain(iter::once( + Event::WindowEvent { window_id: RootWindowId(id), event: WindowEvent::MouseWheel { device_id: RootDeviceId(DeviceId(pointer_id)), delta, phase: TouchPhase::Moved, }, - }), - )); + }, + ))); }, prevent_default, ); diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index 0303a0bd..2cb0ec9a 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -367,12 +367,7 @@ impl Canvas { prevent_default: bool, ) where MOD: 'static + FnMut(ModifiersState), - M: 'static - + FnMut( - ModifiersState, - i32, - &mut dyn Iterator, PhysicalPosition)>, - ), + M: 'static + FnMut(ModifiersState, i32, &mut dyn Iterator>), T: 'static + FnMut(ModifiersState, i32, &mut dyn Iterator, Force)>), B: 'static + FnMut(ModifiersState, i32, PhysicalPosition, ButtonsState, MouseButton), @@ -524,17 +519,13 @@ impl Common { pub fn add_event( &self, event_name: &'static str, - mut handler: F, + handler: F, ) -> EventListenerHandle where E: 'static + AsRef + wasm_bindgen::convert::FromWasmAbi, F: 'static + FnMut(E), { - let closure = Closure::new(move |event: E| { - event.as_ref().stop_propagation(); - handler(event); - }); - EventListenerHandle::new(&self.raw, event_name, closure) + EventListenerHandle::new(self.raw.clone(), event_name, Closure::new(handler)) } // The difference between add_event and add_user_event is that the latter has a special meaning diff --git a/src/platform_impl/web/web_sys/event_handle.rs b/src/platform_impl/web/web_sys/event_handle.rs index 505d58a2..bf2c3471 100644 --- a/src/platform_impl/web/web_sys/event_handle.rs +++ b/src/platform_impl/web/web_sys/event_handle.rs @@ -8,11 +8,11 @@ pub struct EventListenerHandle { } impl EventListenerHandle { - pub fn new(target: &U, event_type: &'static str, listener: Closure) -> Self + pub fn new(target: U, event_type: &'static str, listener: Closure) -> Self where - U: Clone + Into, + U: Into, { - let target = target.clone().into(); + let target = target.into(); target .add_event_listener_with_callback(event_type, listener.as_ref().unchecked_ref()) .expect("Failed to add event listener"); diff --git a/src/platform_impl/web/web_sys/mod.rs b/src/platform_impl/web/web_sys/mod.rs index 752dc2f7..3d961e48 100644 --- a/src/platform_impl/web/web_sys/mod.rs +++ b/src/platform_impl/web/web_sys/mod.rs @@ -35,14 +35,15 @@ pub struct PageTransitionEventHandle { } pub fn on_page_transition( - window: &web_sys::Window, + window: web_sys::Window, show_handler: impl FnMut(PageTransitionEvent) + 'static, hide_handler: impl FnMut(PageTransitionEvent) + 'static, ) -> PageTransitionEventHandle { let show_closure = Closure::new(show_handler); let hide_closure = Closure::new(hide_handler); - let show_listener = event_handle::EventListenerHandle::new(window, "pageshow", show_closure); + let show_listener = + event_handle::EventListenerHandle::new(window.clone(), "pageshow", show_closure); let hide_listener = event_handle::EventListenerHandle::new(window, "pagehide", hide_closure); PageTransitionEventHandle { _show_listener: show_listener, diff --git a/src/platform_impl/web/web_sys/pointer.rs b/src/platform_impl/web/web_sys/pointer.rs index d8f28d78..b0c52b58 100644 --- a/src/platform_impl/web/web_sys/pointer.rs +++ b/src/platform_impl/web/web_sys/pointer.rs @@ -168,12 +168,7 @@ impl PointerHandler { prevent_default: bool, ) where MOD: 'static + FnMut(ModifiersState), - M: 'static - + FnMut( - ModifiersState, - i32, - &mut dyn Iterator, PhysicalPosition)>, - ), + M: 'static + FnMut(ModifiersState, i32, &mut dyn Iterator>), T: 'static + FnMut(ModifiersState, i32, &mut dyn Iterator, Force)>), B: 'static + FnMut(ModifiersState, i32, PhysicalPosition, ButtonsState, MouseButton), @@ -223,22 +218,12 @@ impl PointerHandler { // pointer move event let scale = super::scale_factor(&window); match pointer_type.as_str() { - "mouse" => { - let mut delta = event::MouseDelta::init(&window, &event); - - mouse_handler( - modifiers, - id, - &mut event::pointer_move_event(event).map(|event| { - let position = event::mouse_position(&event).to_physical(scale); - let delta = delta - .delta(&event) - .to_physical(super::scale_factor(&window)); - - (position, delta) - }), - ) - } + "mouse" => mouse_handler( + modifiers, + id, + &mut event::pointer_move_event(event) + .map(|event| event::mouse_position(&event).to_physical(scale)), + ), "touch" => touch_handler( modifiers, id,