Enable event propagation (#3062)

This commit is contained in:
daxpedda 2023-08-28 19:18:10 +02:00 committed by GitHub
parent 7541220a41
commit 1dfca5a395
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 75 additions and 176 deletions

View file

@ -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`. - On Web, never return a `MonitorHandle`.
- **Breaking:** Move `Event::RedrawRequested` to `WindowEvent::RedrawRequested`. - **Breaking:** Move `Event::RedrawRequested` to `WindowEvent::RedrawRequested`.
- On macOS, fix crash in `window.set_minimized(false)`. - 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 # 0.29.1-beta

View file

@ -201,7 +201,7 @@ impl<T: 'static> Shared<T> {
self.init(); self.init();
*self.0.page_transition_event_handle.borrow_mut() = Some(backend::on_page_transition( *self.0.page_transition_event_handle.borrow_mut() = Some(backend::on_page_transition(
self.window(), self.window().clone(),
{ {
let runner = self.clone(); let runner = self.clone();
move |event: PageTransitionEvent| { move |event: PageTransitionEvent| {
@ -227,7 +227,7 @@ impl<T: 'static> Shared<T> {
let runner = self.clone(); let runner = self.clone();
let window = self.window().clone(); let window = self.window().clone();
*self.0.on_mouse_move.borrow_mut() = Some(EventListenerHandle::new( *self.0.on_mouse_move.borrow_mut() = Some(EventListenerHandle::new(
self.window(), self.window().clone(),
"pointermove", "pointermove",
Closure::new(move |event: PointerEvent| { Closure::new(move |event: PointerEvent| {
if !runner.device_events() { if !runner.device_events() {
@ -304,7 +304,7 @@ impl<T: 'static> Shared<T> {
let runner = self.clone(); let runner = self.clone();
let window = self.window().clone(); let window = self.window().clone();
*self.0.on_wheel.borrow_mut() = Some(EventListenerHandle::new( *self.0.on_wheel.borrow_mut() = Some(EventListenerHandle::new(
self.window(), self.window().clone(),
"wheel", "wheel",
Closure::new(move |event: WheelEvent| { Closure::new(move |event: WheelEvent| {
if !runner.device_events() { if !runner.device_events() {
@ -321,7 +321,7 @@ impl<T: 'static> Shared<T> {
)); ));
let runner = self.clone(); let runner = self.clone();
*self.0.on_mouse_press.borrow_mut() = Some(EventListenerHandle::new( *self.0.on_mouse_press.borrow_mut() = Some(EventListenerHandle::new(
self.window(), self.window().clone(),
"pointerdown", "pointerdown",
Closure::new(move |event: PointerEvent| { Closure::new(move |event: PointerEvent| {
if !runner.device_events() { if !runner.device_events() {
@ -344,7 +344,7 @@ impl<T: 'static> Shared<T> {
)); ));
let runner = self.clone(); let runner = self.clone();
*self.0.on_mouse_release.borrow_mut() = Some(EventListenerHandle::new( *self.0.on_mouse_release.borrow_mut() = Some(EventListenerHandle::new(
self.window(), self.window().clone(),
"pointerup", "pointerup",
Closure::new(move |event: PointerEvent| { Closure::new(move |event: PointerEvent| {
if !runner.device_events() { if !runner.device_events() {
@ -367,7 +367,7 @@ impl<T: 'static> Shared<T> {
)); ));
let runner = self.clone(); let runner = self.clone();
*self.0.on_key_press.borrow_mut() = Some(EventListenerHandle::new( *self.0.on_key_press.borrow_mut() = Some(EventListenerHandle::new(
self.window(), self.window().clone(),
"keydown", "keydown",
Closure::new(move |event: KeyboardEvent| { Closure::new(move |event: KeyboardEvent| {
if !runner.device_events() { if !runner.device_events() {
@ -385,7 +385,7 @@ impl<T: 'static> Shared<T> {
)); ));
let runner = self.clone(); let runner = self.clone();
*self.0.on_key_release.borrow_mut() = Some(EventListenerHandle::new( *self.0.on_key_release.borrow_mut() = Some(EventListenerHandle::new(
self.window(), self.window().clone(),
"keyup", "keyup",
Closure::new(move |event: KeyboardEvent| { Closure::new(move |event: KeyboardEvent| {
if !runner.device_events() { if !runner.device_events() {
@ -404,7 +404,7 @@ impl<T: 'static> Shared<T> {
let runner = self.clone(); let runner = self.clone();
*self.0.on_visibility_change.borrow_mut() = Some(EventListenerHandle::new( *self.0.on_visibility_change.borrow_mut() = Some(EventListenerHandle::new(
// Safari <14 doesn't support the `visibilitychange` event on `Window`. // Safari <14 doesn't support the `visibilitychange` event on `Window`.
self.document(), self.document().clone(),
"visibilitychange", "visibilitychange",
Closure::new(move |_| { Closure::new(move |_| {
if !runner.0.suspended.get() { if !runner.0.suspended.get() {

View file

@ -17,8 +17,7 @@ use super::{
window::WindowId, window::WindowId,
}; };
use crate::event::{ use crate::event::{
DeviceEvent, DeviceId as RootDeviceId, ElementState, Event, KeyEvent, RawKeyEvent, Touch, DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase, WindowEvent,
TouchPhase, WindowEvent,
}; };
use crate::event_loop::DeviceEvents; use crate::event_loop::DeviceEvents;
use crate::keyboard::ModifiersState; use crate::keyboard::ModifiersState;
@ -140,34 +139,24 @@ impl<T> EventLoopWindowTarget<T> {
let device_id = RootDeviceId(unsafe { DeviceId::dummy() }); 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( runner.send_events(
device_event iter::once(Event::WindowEvent {
.into_iter() window_id: RootWindowId(id),
.chain(iter::once(Event::WindowEvent { event: WindowEvent::KeyboardInput {
window_id: RootWindowId(id), device_id,
event: WindowEvent::KeyboardInput { event: KeyEvent {
device_id, physical_key,
event: KeyEvent { logical_key,
physical_key, text,
logical_key, location,
text, state: ElementState::Pressed,
location, repeat,
state: ElementState::Pressed, platform_specific: KeyEventExtra,
repeat,
platform_specific: KeyEventExtra,
},
is_synthetic: false,
}, },
})) is_synthetic: false,
.chain(modifiers_changed), },
})
.chain(modifiers_changed),
); );
}, },
prevent_default, prevent_default,
@ -187,34 +176,24 @@ impl<T> EventLoopWindowTarget<T> {
let device_id = RootDeviceId(unsafe { DeviceId::dummy() }); 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( runner.send_events(
device_event iter::once(Event::WindowEvent {
.into_iter() window_id: RootWindowId(id),
.chain(iter::once(Event::WindowEvent { event: WindowEvent::KeyboardInput {
window_id: RootWindowId(id), device_id,
event: WindowEvent::KeyboardInput { event: KeyEvent {
device_id, physical_key,
event: KeyEvent { logical_key,
physical_key, text,
logical_key, location,
text, state: ElementState::Released,
location, repeat,
state: ElementState::Released, platform_specific: KeyEventExtra,
repeat,
platform_specific: KeyEventExtra,
},
is_synthetic: false,
}, },
})) is_synthetic: false,
.chain(modifiers_changed), },
})
.chain(modifiers_changed),
) )
}, },
prevent_default, prevent_default,
@ -311,48 +290,17 @@ impl<T> EventLoopWindowTarget<T> {
} }
}); });
runner.send_events(modifiers.into_iter().chain(events.flat_map( runner.send_events(modifiers.into_iter().chain(events.flat_map(|position| {
|(position, delta)| { let device_id = RootDeviceId(DeviceId(pointer_id));
let device_id = RootDeviceId(DeviceId(pointer_id));
let device_events = runner.device_events().then(|| { iter::once(Event::WindowEvent {
let x_motion = (delta.x != 0.0).then_some(Event::DeviceEvent { window_id: RootWindowId(id),
device_id, event: WindowEvent::CursorMoved {
event: DeviceEvent::Motion { device_id,
axis: 0, position,
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,
},
},
))
},
)));
} }
}, },
{ {
@ -413,18 +361,10 @@ impl<T> EventLoopWindowTarget<T> {
ElementState::Released 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, // A chorded button event may come in without any prior CursorMoved events,
// therefore we should send a CursorMoved event to make sure that the // therefore we should send a CursorMoved event to make sure that the
// user code has the correct cursor position. // 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 { Event::WindowEvent {
window_id: RootWindowId(id), window_id: RootWindowId(id),
event: WindowEvent::CursorMoved { event: WindowEvent::CursorMoved {
@ -475,18 +415,11 @@ impl<T> EventLoopWindowTarget<T> {
}); });
let device_id: RootDeviceId = RootDeviceId(DeviceId(pointer_id)); 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, // A mouse down event may come in without any prior CursorMoved events,
// therefore we should send a CursorMoved event to make sure that the // therefore we should send a CursorMoved event to make sure that the
// user code has the correct cursor position. // 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 { Event::WindowEvent {
window_id: RootWindowId(id), window_id: RootWindowId(id),
event: WindowEvent::CursorMoved { event: WindowEvent::CursorMoved {
@ -568,18 +501,11 @@ impl<T> EventLoopWindowTarget<T> {
}); });
let device_id: RootDeviceId = RootDeviceId(DeviceId(pointer_id)); 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, // A mouse up event may come in without any prior CursorMoved events,
// therefore we should send a CursorMoved event to make sure that the // therefore we should send a CursorMoved event to make sure that the
// user code has the correct cursor position. // 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 { Event::WindowEvent {
window_id: RootWindowId(id), window_id: RootWindowId(id),
event: WindowEvent::CursorMoved { event: WindowEvent::CursorMoved {
@ -644,21 +570,16 @@ impl<T> EventLoopWindowTarget<T> {
} }
}); });
let device_event = runner.device_events().then_some(Event::DeviceEvent { runner.send_events(modifiers_changed.into_iter().chain(iter::once(
device_id: RootDeviceId(DeviceId(pointer_id)), Event::WindowEvent {
event: DeviceEvent::MouseWheel { delta },
});
runner.send_events(modifiers_changed.into_iter().chain(device_event).chain(
iter::once(Event::WindowEvent {
window_id: RootWindowId(id), window_id: RootWindowId(id),
event: WindowEvent::MouseWheel { event: WindowEvent::MouseWheel {
device_id: RootDeviceId(DeviceId(pointer_id)), device_id: RootDeviceId(DeviceId(pointer_id)),
delta, delta,
phase: TouchPhase::Moved, phase: TouchPhase::Moved,
}, },
}), },
)); )));
}, },
prevent_default, prevent_default,
); );

View file

@ -367,12 +367,7 @@ impl Canvas {
prevent_default: bool, prevent_default: bool,
) where ) where
MOD: 'static + FnMut(ModifiersState), MOD: 'static + FnMut(ModifiersState),
M: 'static M: 'static + FnMut(ModifiersState, i32, &mut dyn Iterator<Item = PhysicalPosition<f64>>),
+ FnMut(
ModifiersState,
i32,
&mut dyn Iterator<Item = (PhysicalPosition<f64>, PhysicalPosition<f64>)>,
),
T: 'static T: 'static
+ FnMut(ModifiersState, i32, &mut dyn Iterator<Item = (PhysicalPosition<f64>, Force)>), + FnMut(ModifiersState, i32, &mut dyn Iterator<Item = (PhysicalPosition<f64>, Force)>),
B: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, ButtonsState, MouseButton), B: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, ButtonsState, MouseButton),
@ -524,17 +519,13 @@ impl Common {
pub fn add_event<E, F>( pub fn add_event<E, F>(
&self, &self,
event_name: &'static str, event_name: &'static str,
mut handler: F, handler: F,
) -> EventListenerHandle<dyn FnMut(E)> ) -> EventListenerHandle<dyn FnMut(E)>
where where
E: 'static + AsRef<web_sys::Event> + wasm_bindgen::convert::FromWasmAbi, E: 'static + AsRef<web_sys::Event> + wasm_bindgen::convert::FromWasmAbi,
F: 'static + FnMut(E), F: 'static + FnMut(E),
{ {
let closure = Closure::new(move |event: E| { EventListenerHandle::new(self.raw.clone(), event_name, Closure::new(handler))
event.as_ref().stop_propagation();
handler(event);
});
EventListenerHandle::new(&self.raw, event_name, closure)
} }
// The difference between add_event and add_user_event is that the latter has a special meaning // The difference between add_event and add_user_event is that the latter has a special meaning

View file

@ -8,11 +8,11 @@ pub struct EventListenerHandle<T: ?Sized> {
} }
impl<T: ?Sized> EventListenerHandle<T> { impl<T: ?Sized> EventListenerHandle<T> {
pub fn new<U>(target: &U, event_type: &'static str, listener: Closure<T>) -> Self pub fn new<U>(target: U, event_type: &'static str, listener: Closure<T>) -> Self
where where
U: Clone + Into<EventTarget>, U: Into<EventTarget>,
{ {
let target = target.clone().into(); let target = target.into();
target target
.add_event_listener_with_callback(event_type, listener.as_ref().unchecked_ref()) .add_event_listener_with_callback(event_type, listener.as_ref().unchecked_ref())
.expect("Failed to add event listener"); .expect("Failed to add event listener");

View file

@ -35,14 +35,15 @@ pub struct PageTransitionEventHandle {
} }
pub fn on_page_transition( pub fn on_page_transition(
window: &web_sys::Window, window: web_sys::Window,
show_handler: impl FnMut(PageTransitionEvent) + 'static, show_handler: impl FnMut(PageTransitionEvent) + 'static,
hide_handler: impl FnMut(PageTransitionEvent) + 'static, hide_handler: impl FnMut(PageTransitionEvent) + 'static,
) -> PageTransitionEventHandle { ) -> PageTransitionEventHandle {
let show_closure = Closure::new(show_handler); let show_closure = Closure::new(show_handler);
let hide_closure = Closure::new(hide_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); let hide_listener = event_handle::EventListenerHandle::new(window, "pagehide", hide_closure);
PageTransitionEventHandle { PageTransitionEventHandle {
_show_listener: show_listener, _show_listener: show_listener,

View file

@ -168,12 +168,7 @@ impl PointerHandler {
prevent_default: bool, prevent_default: bool,
) where ) where
MOD: 'static + FnMut(ModifiersState), MOD: 'static + FnMut(ModifiersState),
M: 'static M: 'static + FnMut(ModifiersState, i32, &mut dyn Iterator<Item = PhysicalPosition<f64>>),
+ FnMut(
ModifiersState,
i32,
&mut dyn Iterator<Item = (PhysicalPosition<f64>, PhysicalPosition<f64>)>,
),
T: 'static T: 'static
+ FnMut(ModifiersState, i32, &mut dyn Iterator<Item = (PhysicalPosition<f64>, Force)>), + FnMut(ModifiersState, i32, &mut dyn Iterator<Item = (PhysicalPosition<f64>, Force)>),
B: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, ButtonsState, MouseButton), B: 'static + FnMut(ModifiersState, i32, PhysicalPosition<f64>, ButtonsState, MouseButton),
@ -223,22 +218,12 @@ impl PointerHandler {
// pointer move event // pointer move event
let scale = super::scale_factor(&window); let scale = super::scale_factor(&window);
match pointer_type.as_str() { match pointer_type.as_str() {
"mouse" => { "mouse" => mouse_handler(
let mut delta = event::MouseDelta::init(&window, &event); modifiers,
id,
mouse_handler( &mut event::pointer_move_event(event)
modifiers, .map(|event| event::mouse_position(&event).to_physical(scale)),
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)
}),
)
}
"touch" => touch_handler( "touch" => touch_handler(
modifiers, modifiers,
id, id,