diff --git a/Cargo.toml b/Cargo.toml index 859ba837..9ff849e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -129,7 +129,7 @@ redox_syscall = "0.3" [target.'cfg(target_family = "wasm")'.dependencies.web_sys] package = "web-sys" -version = "0.3.22" +version = "0.3" features = [ 'console', 'CssStyleDeclaration', @@ -151,8 +151,8 @@ features = [ [target.'cfg(target_family = "wasm")'.dependencies] atomic-waker = "1" -js-sys = "0.3" -wasm-bindgen = "0.2.45" +js-sys = "0.3.64" +wasm-bindgen = "0.2" wasm-bindgen-futures = "0.4" web-time = "0.2" diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 734b7027..c3c91076 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -194,65 +194,63 @@ impl EventLoopWindowTarget { prevent_default, ); - canvas.on_cursor_leave( - { - let runner = self.runner.clone(); - let has_focus = has_focus.clone(); - let modifiers = self.modifiers.clone(); + canvas.on_cursor_leave({ + let runner = self.runner.clone(); + let has_focus = has_focus.clone(); + let modifiers = self.modifiers.clone(); - move |active_modifiers| { - if has_focus.load(Ordering::Relaxed) && modifiers.get() != active_modifiers { + move |active_modifiers, pointer_id| { + let focus = (has_focus.load(Ordering::Relaxed) + && modifiers.get() != active_modifiers) + .then(|| { modifiers.set(active_modifiers); - runner.send_event(Event::WindowEvent { + Event::WindowEvent { window_id: RootWindowId(id), event: WindowEvent::ModifiersChanged(active_modifiers.into()), - }); - } - } - }, - { - let runner = self.runner.clone(); - - move |pointer_id| { - runner.send_event(Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::CursorLeft { - device_id: RootDeviceId(DeviceId(pointer_id)), - }, + } }); + + let pointer = pointer_id.map(|pointer_id| Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::CursorLeft { + device_id: RootDeviceId(DeviceId(pointer_id)), + }, + }); + + if focus.is_some() || pointer.is_some() { + runner.send_events(focus.into_iter().chain(pointer)) } - }, - ); + } + }); - canvas.on_cursor_enter( - { - let runner = self.runner.clone(); - let has_focus = has_focus.clone(); - let modifiers = self.modifiers.clone(); + canvas.on_cursor_enter({ + let runner = self.runner.clone(); + let has_focus = has_focus.clone(); + let modifiers = self.modifiers.clone(); - move |active_modifiers| { - if has_focus.load(Ordering::Relaxed) && modifiers.get() != active_modifiers { + move |active_modifiers, pointer_id| { + let focus = (has_focus.load(Ordering::Relaxed) + && modifiers.get() != active_modifiers) + .then(|| { modifiers.set(active_modifiers); - runner.send_event(Event::WindowEvent { + Event::WindowEvent { window_id: RootWindowId(id), event: WindowEvent::ModifiersChanged(active_modifiers.into()), - }); - } - } - }, - { - let runner = self.runner.clone(); - - move |pointer_id| { - runner.send_event(Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::CursorEntered { - device_id: RootDeviceId(DeviceId(pointer_id)), - }, + } }); + + let pointer = pointer_id.map(|pointer_id| Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::CursorEntered { + device_id: RootDeviceId(DeviceId(pointer_id)), + }, + }); + + if focus.is_some() || pointer.is_some() { + runner.send_events(focus.into_iter().chain(pointer)) } - }, - ); + } + }); canvas.on_cursor_move( { @@ -272,45 +270,93 @@ impl EventLoopWindowTarget { }, { let runner = self.runner.clone(); + let has_focus = has_focus.clone(); + let modifiers = self.modifiers.clone(); - move |pointer_id, position, delta| { - runner.send_events([ - Event::WindowEvent { + move |active_modifiers, pointer_id, events| { + let modifiers = (has_focus.load(Ordering::Relaxed) + && modifiers.get() != active_modifiers) + .then(|| { + modifiers.set(active_modifiers); + Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::ModifiersChanged(active_modifiers.into()), + } + }); + + runner.send_events(modifiers.into_iter().chain(events.flat_map( + |(position, delta)| { + let device_id = RootDeviceId(DeviceId(pointer_id)); + + [ + Event::DeviceEvent { + device_id, + event: DeviceEvent::MouseMotion { + delta: (delta.x, delta.y), + }, + }, + Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::CursorMoved { + device_id, + position, + }, + }, + ] + }, + ))); + } + }, + { + let runner = self.runner.clone(); + let has_focus = has_focus.clone(); + let modifiers = self.modifiers.clone(); + + move |active_modifiers, device_id, events| { + let modifiers = (has_focus.load(Ordering::Relaxed) + && modifiers.get() != active_modifiers) + .then(|| { + modifiers.set(active_modifiers); + Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::ModifiersChanged(active_modifiers.into()), + } + }); + + runner.send_events(modifiers.into_iter().chain(events.map( + |(location, force)| Event::WindowEvent { window_id: RootWindowId(id), - event: WindowEvent::CursorMoved { - device_id: RootDeviceId(DeviceId(pointer_id)), - position, - }, + event: WindowEvent::Touch(Touch { + id: device_id as u64, + device_id: RootDeviceId(DeviceId(device_id)), + phase: TouchPhase::Moved, + force: Some(force), + location, + }), }, - Event::DeviceEvent { - device_id: RootDeviceId(DeviceId(pointer_id)), - event: DeviceEvent::MouseMotion { - delta: (delta.x, delta.y), - }, - }, - ]); + ))); } }, { let runner = self.runner.clone(); + let has_focus = has_focus.clone(); + let modifiers = self.modifiers.clone(); - move |device_id, location, force| { - runner.send_event(Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::Touch(Touch { - id: device_id as u64, - device_id: RootDeviceId(DeviceId(device_id)), - phase: TouchPhase::Moved, - force: Some(force), - location, - }), - }); - } - }, - { - let runner = self.runner.clone(); + move |active_modifiers, + pointer_id, + position: crate::dpi::PhysicalPosition, + buttons, + button| { + let modifiers = (has_focus.load(Ordering::Relaxed) + && modifiers.get() != active_modifiers) + .then(|| { + modifiers.set(active_modifiers); + Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::ModifiersChanged(active_modifiers.into()), + } + }); - move |pointer_id, position: crate::dpi::PhysicalPosition, buttons, button| { let button_event = if buttons.contains(button.into()) { Event::WindowEvent { window_id: RootWindowId(id), @@ -334,7 +380,7 @@ impl EventLoopWindowTarget { // 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([ + runner.send_events(modifiers.into_iter().chain([ Event::WindowEvent { window_id: RootWindowId(id), event: WindowEvent::CursorMoved { @@ -343,7 +389,7 @@ impl EventLoopWindowTarget { }, }, button_event, - ]); + ])); } }, prevent_default, @@ -366,12 +412,21 @@ impl EventLoopWindowTarget { }, { let runner = self.runner.clone(); + let modifiers = self.modifiers.clone(); + + move |active_modifiers, pointer_id, position, button| { + let modifiers = (modifiers.get() != active_modifiers).then(|| { + modifiers.set(active_modifiers); + Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::ModifiersChanged(active_modifiers.into()), + } + }); - move |pointer_id, position, button| { // 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([ + runner.send_events(modifiers.into_iter().chain([ Event::WindowEvent { window_id: RootWindowId(id), event: WindowEvent::CursorMoved { @@ -387,23 +442,34 @@ impl EventLoopWindowTarget { button, }, }, - ]); + ])); } }, { let runner = self.runner.clone(); + let modifiers = self.modifiers.clone(); - move |device_id, location, force| { - runner.send_event(Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::Touch(Touch { - id: device_id as u64, - device_id: RootDeviceId(DeviceId(device_id)), - phase: TouchPhase::Started, - force: Some(force), - location, - }), - }) + move |active_modifiers, device_id, location, force| { + let modifiers = (modifiers.get() != active_modifiers).then(|| { + modifiers.set(active_modifiers); + Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::ModifiersChanged(active_modifiers.into()), + } + }); + + runner.send_events(modifiers.into_iter().chain(iter::once( + Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::Touch(Touch { + id: device_id as u64, + device_id: RootDeviceId(DeviceId(device_id)), + phase: TouchPhase::Started, + force: Some(force), + location, + }), + }, + ))) } }, prevent_default, @@ -427,12 +493,24 @@ impl EventLoopWindowTarget { }, { let runner = self.runner.clone(); + let has_focus = has_focus.clone(); + let modifiers = self.modifiers.clone(); + + move |active_modifiers, pointer_id, position, button| { + let modifiers = (has_focus.load(Ordering::Relaxed) + && modifiers.get() != active_modifiers) + .then(|| { + modifiers.set(active_modifiers); + Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::ModifiersChanged(active_modifiers.into()), + } + }); - move |pointer_id, position, button| { // 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([ + runner.send_events(modifiers.into_iter().chain([ Event::WindowEvent { window_id: RootWindowId(id), event: WindowEvent::CursorMoved { @@ -448,23 +526,37 @@ impl EventLoopWindowTarget { button, }, }, - ]); + ])); } }, { let runner_touch = self.runner.clone(); + let has_focus = has_focus.clone(); + let modifiers = self.modifiers.clone(); - move |device_id, location, force| { - runner_touch.send_event(Event::WindowEvent { - window_id: RootWindowId(id), - event: WindowEvent::Touch(Touch { - id: device_id as u64, - device_id: RootDeviceId(DeviceId(device_id)), - phase: TouchPhase::Ended, - force: Some(force), - location, - }), - }); + move |active_modifiers, device_id, location, force| { + let modifiers = (has_focus.load(Ordering::Relaxed) + && modifiers.get() != active_modifiers) + .then(|| { + modifiers.set(active_modifiers); + Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::ModifiersChanged(active_modifiers.into()), + } + }); + + runner_touch.send_events(modifiers.into_iter().chain(iter::once( + Event::WindowEvent { + window_id: RootWindowId(id), + event: WindowEvent::Touch(Touch { + id: device_id as u64, + device_id: RootDeviceId(DeviceId(device_id)), + phase: TouchPhase::Ended, + force: Some(force), + location, + }), + }, + ))); } }, ); diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index ea724822..273c7c6e 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -224,22 +224,18 @@ impl Canvas { )); } - pub fn on_cursor_leave(&mut self, modifier_handler: MOD, mouse_handler: M) + pub fn on_cursor_leave(&mut self, handler: F) where - MOD: 'static + FnMut(ModifiersState), - M: 'static + FnMut(i32), + F: 'static + FnMut(ModifiersState, Option), { - self.pointer_handler - .on_cursor_leave(&self.common, modifier_handler, mouse_handler) + self.pointer_handler.on_cursor_leave(&self.common, handler) } - pub fn on_cursor_enter(&mut self, modifier_handler: MOD, mouse_handler: M) + pub fn on_cursor_enter(&mut self, handler: F) where - MOD: 'static + FnMut(ModifiersState), - M: 'static + FnMut(i32), + F: 'static + FnMut(ModifiersState, Option), { - self.pointer_handler - .on_cursor_enter(&self.common, modifier_handler, mouse_handler) + self.pointer_handler.on_cursor_enter(&self.common, handler) } pub fn on_mouse_release( @@ -249,8 +245,8 @@ impl Canvas { touch_handler: T, ) where MOD: 'static + FnMut(ModifiersState), - M: 'static + FnMut(i32, PhysicalPosition, MouseButton), - T: 'static + FnMut(i32, PhysicalPosition, Force), + M: 'static + FnMut(ModifiersState, i32, PhysicalPosition, MouseButton), + T: 'static + FnMut(ModifiersState, i32, PhysicalPosition, Force), { self.pointer_handler.on_mouse_release( &self.common, @@ -268,8 +264,8 @@ impl Canvas { prevent_default: bool, ) where MOD: 'static + FnMut(ModifiersState), - M: 'static + FnMut(i32, PhysicalPosition, MouseButton), - T: 'static + FnMut(i32, PhysicalPosition, Force), + M: 'static + FnMut(ModifiersState, i32, PhysicalPosition, MouseButton), + T: 'static + FnMut(ModifiersState, i32, PhysicalPosition, Force), { self.pointer_handler.on_mouse_press( &self.common, @@ -289,9 +285,15 @@ impl Canvas { prevent_default: bool, ) where MOD: 'static + FnMut(ModifiersState), - M: 'static + FnMut(i32, PhysicalPosition, PhysicalPosition), - T: 'static + FnMut(i32, PhysicalPosition, Force), - B: 'static + FnMut(i32, PhysicalPosition, ButtonsState, MouseButton), + M: 'static + + FnMut( + ModifiersState, + i32, + &mut dyn Iterator, PhysicalPosition)>, + ), + T: 'static + + FnMut(ModifiersState, i32, &mut dyn Iterator, Force)>), + B: 'static + FnMut(ModifiersState, i32, PhysicalPosition, ButtonsState, MouseButton), { self.pointer_handler.on_cursor_move( &self.common, diff --git a/src/platform_impl/web/web_sys/event.rs b/src/platform_impl/web/web_sys/event.rs index 56618844..4d42a68a 100644 --- a/src/platform_impl/web/web_sys/event.rs +++ b/src/platform_impl/web/web_sys/event.rs @@ -2,8 +2,11 @@ use crate::dpi::LogicalPosition; use crate::event::{MouseButton, MouseScrollDelta}; use crate::keyboard::{Key, KeyCode, KeyLocation, ModifiersState}; +use once_cell::unsync::OnceCell; use smol_str::SmolStr; use std::convert::TryInto; +use wasm_bindgen::prelude::wasm_bindgen; +use wasm_bindgen::{JsCast, JsValue}; use web_sys::{HtmlCanvasElement, KeyboardEvent, MouseEvent, PointerEvent, WheelEvent}; bitflags! { @@ -61,10 +64,48 @@ pub fn mouse_position(event: &MouseEvent) -> LogicalPosition { } } -pub fn mouse_delta(event: &MouseEvent) -> LogicalPosition { - LogicalPosition { - x: event.movement_x() as f64, - y: event.movement_y() as f64, +// TODO: Remove this when Firefox supports correct movement values in coalesced events. +// See . +pub struct MouseDelta(Option); + +pub struct MouseDeltaInner { + old_position: LogicalPosition, + old_delta: LogicalPosition, +} + +impl MouseDelta { + pub fn init(window: &web_sys::Window, event: &PointerEvent) -> Self { + // Firefox has wrong movement values in coalesced events, we will detect that by checking + // for `pointerrawupdate` support. Presumably an implementation of `pointerrawupdate` + // should require correct movement values, otherwise uncoalesced events might be broken as + // well. + Self( + (!has_pointer_raw_support(window) && has_coalesced_events_support(event)).then(|| { + MouseDeltaInner { + old_position: mouse_position(event), + old_delta: LogicalPosition { + x: event.movement_x() as f64, + y: event.movement_y() as f64, + }, + } + }), + ) + } + + pub fn delta(&mut self, event: &MouseEvent) -> LogicalPosition { + if let Some(inner) = &mut self.0 { + let new_position = mouse_position(event); + let x = new_position.x - inner.old_position.x + inner.old_delta.x; + let y = new_position.y - inner.old_position.y + inner.old_delta.y; + inner.old_position = new_position; + inner.old_delta = LogicalPosition::new(0., 0.); + LogicalPosition::new(x, y) + } else { + LogicalPosition { + x: event.movement_x() as f64, + y: event.movement_y() as f64, + } + } } } @@ -172,3 +213,67 @@ pub fn mouse_modifiers(event: &MouseEvent) -> ModifiersState { pub fn touch_position(event: &PointerEvent, canvas: &HtmlCanvasElement) -> LogicalPosition { mouse_position_by_client(event, canvas) } + +pub fn pointer_move_event(event: PointerEvent) -> impl Iterator { + // make a single iterator depending on the availability of coalesced events + if has_coalesced_events_support(&event) { + None.into_iter().chain( + Some( + event + .get_coalesced_events() + .into_iter() + .map(PointerEvent::unchecked_from_js), + ) + .into_iter() + .flatten(), + ) + } else { + Some(event).into_iter().chain(None.into_iter().flatten()) + } +} + +// TODO: Remove when all browsers implement it correctly. +// See . +pub fn has_pointer_raw_support(window: &web_sys::Window) -> bool { + thread_local! { + static POINTER_RAW_SUPPORT: OnceCell = OnceCell::new(); + } + + POINTER_RAW_SUPPORT.with(|support| { + *support.get_or_init(|| { + #[wasm_bindgen] + extern "C" { + type PointerRawSupport; + + #[wasm_bindgen(method, getter, js_name = onpointerrawupdate)] + fn has_on_pointerrawupdate(this: &PointerRawSupport) -> JsValue; + } + + let support: &PointerRawSupport = window.unchecked_ref(); + !support.has_on_pointerrawupdate().is_undefined() + }) + }) +} + +// TODO: Remove when Safari supports `getCoalescedEvents`. +// See . +pub fn has_coalesced_events_support(event: &PointerEvent) -> bool { + thread_local! { + static COALESCED_EVENTS_SUPPORT: OnceCell = OnceCell::new(); + } + + COALESCED_EVENTS_SUPPORT.with(|support| { + *support.get_or_init(|| { + #[wasm_bindgen] + extern "C" { + type PointerCoalescedEventsSupport; + + #[wasm_bindgen(method, getter, js_name = getCoalescedEvents)] + fn has_get_coalesced_events(this: &PointerCoalescedEventsSupport) -> JsValue; + } + + let support: &PointerCoalescedEventsSupport = event.unchecked_ref(); + !support.has_get_coalesced_events().is_undefined() + }) + }) +} diff --git a/src/platform_impl/web/web_sys/pointer.rs b/src/platform_impl/web/web_sys/pointer.rs index 80146f0a..a22a01aa 100644 --- a/src/platform_impl/web/web_sys/pointer.rs +++ b/src/platform_impl/web/web_sys/pointer.rs @@ -6,8 +6,6 @@ use crate::event::{Force, MouseButton}; use crate::keyboard::ModifiersState; use event::ButtonsState; -use wasm_bindgen::prelude::wasm_bindgen; -use wasm_bindgen::{JsCast, JsValue}; use web_sys::PointerEvent; #[allow(dead_code)] @@ -32,54 +30,40 @@ impl PointerHandler { } } - pub fn on_cursor_leave( - &mut self, - canvas_common: &Common, - mut modifier_handler: MOD, - mut mouse_handler: M, - ) where - MOD: 'static + FnMut(ModifiersState), - M: 'static + FnMut(i32), + pub fn on_cursor_leave(&mut self, canvas_common: &Common, mut handler: F) + where + F: 'static + FnMut(ModifiersState, Option), { self.on_cursor_leave = Some(canvas_common.add_event( "pointerout", move |event: PointerEvent| { - modifier_handler(event::mouse_modifiers(&event)); + let modifiers = event::mouse_modifiers(&event); // touch events are handled separately // handling them here would produce duplicate mouse events, inconsistent with // other platforms. - if event.pointer_type() != "mouse" { - return; - } + let pointer_id = (event.pointer_type() == "mouse").then(|| event.pointer_id()); - mouse_handler(event.pointer_id()); + handler(modifiers, pointer_id); }, )); } - pub fn on_cursor_enter( - &mut self, - canvas_common: &Common, - mut modifier_handler: MOD, - mut mouse_handler: M, - ) where - MOD: 'static + FnMut(ModifiersState), - M: 'static + FnMut(i32), + pub fn on_cursor_enter(&mut self, canvas_common: &Common, mut handler: F) + where + F: 'static + FnMut(ModifiersState, Option), { self.on_cursor_enter = Some(canvas_common.add_event( "pointerover", move |event: PointerEvent| { - modifier_handler(event::mouse_modifiers(&event)); + let modifiers = event::mouse_modifiers(&event); // touch events are handled separately // handling them here would produce duplicate mouse events, inconsistent with // other platforms. - if event.pointer_type() != "mouse" { - return; - } + let pointer_id = (event.pointer_type() == "mouse").then(|| event.pointer_id()); - mouse_handler(event.pointer_id()); + handler(modifiers, pointer_id); }, )); } @@ -92,29 +76,31 @@ impl PointerHandler { mut touch_handler: T, ) where MOD: 'static + FnMut(ModifiersState), - M: 'static + FnMut(i32, PhysicalPosition, MouseButton), - T: 'static + FnMut(i32, PhysicalPosition, Force), + M: 'static + FnMut(ModifiersState, i32, PhysicalPosition, MouseButton), + T: 'static + FnMut(ModifiersState, i32, PhysicalPosition, Force), { let window = canvas_common.window.clone(); let canvas = canvas_common.raw.clone(); self.on_pointer_release = Some(canvas_common.add_user_event( "pointerup", move |event: PointerEvent| { - modifier_handler(event::mouse_modifiers(&event)); + let modifiers = event::mouse_modifiers(&event); match event.pointer_type().as_str() { "touch" => touch_handler( + modifiers, event.pointer_id(), event::touch_position(&event, &canvas) .to_physical(super::scale_factor(&window)), Force::Normalized(event.pressure() as f64), ), "mouse" => mouse_handler( + modifiers, event.pointer_id(), event::mouse_position(&event).to_physical(super::scale_factor(&window)), event::mouse_button(&event).expect("no mouse button released"), ), - _ => (), + _ => modifier_handler(modifiers), } }, )); @@ -129,8 +115,8 @@ impl PointerHandler { prevent_default: bool, ) where MOD: 'static + FnMut(ModifiersState), - M: 'static + FnMut(i32, PhysicalPosition, MouseButton), - T: 'static + FnMut(i32, PhysicalPosition, Force), + M: 'static + FnMut(ModifiersState, i32, PhysicalPosition, MouseButton), + T: 'static + FnMut(ModifiersState, i32, PhysicalPosition, Force), { let window = canvas_common.window.clone(); let canvas = canvas_common.raw.clone(); @@ -144,11 +130,12 @@ impl PointerHandler { let _ = canvas.focus(); } - modifier_handler(event::mouse_modifiers(&event)); + let modifiers = event::mouse_modifiers(&event); match event.pointer_type().as_str() { "touch" => { touch_handler( + modifiers, event.pointer_id(), event::touch_position(&event, &canvas) .to_physical(super::scale_factor(&window)), @@ -157,6 +144,7 @@ impl PointerHandler { } "mouse" => { mouse_handler( + modifiers, event.pointer_id(), event::mouse_position(&event).to_physical(super::scale_factor(&window)), event::mouse_button(&event).expect("no mouse button pressed"), @@ -167,7 +155,7 @@ impl PointerHandler { // this could fail, that we care if it fails. let _e = canvas.set_pointer_capture(event.pointer_id()); } - _ => (), + _ => modifier_handler(modifiers), } }, )); @@ -183,32 +171,29 @@ impl PointerHandler { prevent_default: bool, ) where MOD: 'static + FnMut(ModifiersState), - M: 'static + FnMut(i32, PhysicalPosition, PhysicalPosition), - T: 'static + FnMut(i32, PhysicalPosition, Force), - B: 'static + FnMut(i32, PhysicalPosition, ButtonsState, MouseButton), + M: 'static + + FnMut( + ModifiersState, + i32, + &mut dyn Iterator, PhysicalPosition)>, + ), + T: 'static + + FnMut(ModifiersState, i32, &mut dyn Iterator, Force)>), + B: 'static + FnMut(ModifiersState, i32, PhysicalPosition, ButtonsState, MouseButton), { let window = canvas_common.window.clone(); let canvas = canvas_common.raw.clone(); self.on_cursor_move = Some(canvas_common.add_event( "pointermove", move |event: PointerEvent| { - // coalesced events are not available on Safari - #[wasm_bindgen] - extern "C" { - #[wasm_bindgen(extends = PointerEvent)] - type PointerEventExt; - - #[wasm_bindgen(method, getter, js_name = getCoalescedEvents)] - fn has_get_coalesced_events(this: &PointerEventExt) -> JsValue; - } - - modifier_handler(event::mouse_modifiers(&event)); + let modifiers = event::mouse_modifiers(&event); let pointer_type = event.pointer_type(); - match pointer_type.as_str() { - "touch" | "mouse" => (), - _ => return, + if let "touch" | "mouse" = pointer_type.as_str() { + } else { + modifier_handler(modifiers); + return; } let id = event.pointer_id(); @@ -228,6 +213,7 @@ impl PointerHandler { } button_handler( + modifiers, id, event::mouse_position(&event).to_physical(super::scale_factor(&window)), event::mouse_buttons(&event), @@ -238,40 +224,36 @@ 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); - let event: PointerEventExt = event.unchecked_into(); - - // store coalesced events to extend it's lifetime - let events = (!event.has_get_coalesced_events().is_undefined()) - .then(|| event.get_coalesced_events()); - - // make a single iterator depending on the availability of coalesced events - let events = if let Some(events) = &events { - None.into_iter().chain( - Some(events.iter().map(PointerEventExt::unchecked_from_js)) - .into_iter() - .flatten(), - ) - } else { - Some(event).into_iter().chain(None.into_iter().flatten()) - }; - - for event in events { - match pointer_type.as_str() { - "mouse" => mouse_handler( + mouse_handler( + modifiers, id, - event::mouse_position(&event).to_physical(super::scale_factor(&window)), - event::mouse_delta(&event).to_physical(super::scale_factor(&window)), - ), - "touch" => touch_handler( - id, - event::touch_position(&event, &canvas) - .to_physical(super::scale_factor(&window)), - Force::Normalized(event.pressure() as f64), - ), - _ => unreachable!("didn't return early before"), + &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( + modifiers, + id, + &mut event::pointer_move_event(event).map(|event| { + ( + event::touch_position(&event, &canvas).to_physical(scale), + Force::Normalized(event.pressure() as f64), + ) + }), + ), + _ => unreachable!("didn't return early before"), + }; }, )); }