diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index f5cd2a6b18..9e9a479cb4 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -52,6 +52,7 @@ changelog entry. to send specific data to be processed on the main thread. - Changed `EventLoopProxy::send_event` to `EventLoopProxy::wake_up`, it now only wakes up the loop. +- On Web, slightly improve accuracy of `DeviceEvent::MouseMotion`. ### Removed diff --git a/src/platform_impl/web/event_loop/runner.rs b/src/platform_impl/web/event_loop/runner.rs index 92a7d624b8..b47421abd2 100644 --- a/src/platform_impl/web/event_loop/runner.rs +++ b/src/platform_impl/web/event_loop/runner.rs @@ -234,7 +234,7 @@ impl Shared { )); let runner = self.clone(); - let window = self.window().clone(); + let mut delta = backend::event::MouseDelta::new(); *self.0.on_mouse_move.borrow_mut() = Some(EventListenerHandle::new( self.window().clone(), "pointermove", @@ -273,23 +273,26 @@ impl Shared { } // 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 delta = delta.delta(&event); + + if delta.x == 0 && delta.y == 0 { + return None.into_iter().chain(None).chain(None); + } - let x_motion = (delta.x != 0.0).then_some(Event::DeviceEvent { + let x_motion = (delta.x != 0).then_some(Event::DeviceEvent { device_id, - event: DeviceEvent::Motion { axis: 0, value: delta.x }, + event: DeviceEvent::Motion { axis: 0, value: delta.x.into() }, }); - let y_motion = (delta.y != 0.0).then_some(Event::DeviceEvent { + let y_motion = (delta.y != 0).then_some(Event::DeviceEvent { device_id, - event: DeviceEvent::Motion { axis: 1, value: delta.y }, + event: DeviceEvent::Motion { axis: 1, value: delta.y.into() }, }); - x_motion.into_iter().chain(y_motion).chain(iter::once(Event::DeviceEvent { + x_motion.into_iter().chain(y_motion).chain(Some(Event::DeviceEvent { device_id, - event: DeviceEvent::MouseMotion { delta: (delta.x, delta.y) }, + event: DeviceEvent::MouseMotion { delta: (delta.x.into(), delta.y.into()) }, })) })); }), diff --git a/src/platform_impl/web/web_sys/event.rs b/src/platform_impl/web/web_sys/event.rs index 51df63714b..b76cce9b5a 100644 --- a/src/platform_impl/web/web_sys/event.rs +++ b/src/platform_impl/web/web_sys/event.rs @@ -1,7 +1,7 @@ -use crate::dpi::LogicalPosition; use crate::event::{MouseButton, MouseScrollDelta}; use crate::keyboard::{Key, KeyLocation, ModifiersState, NamedKey, PhysicalKey}; +use dpi::{LogicalPosition, PhysicalPosition}; use smol_str::SmolStr; use std::cell::OnceCell; use wasm_bindgen::prelude::wasm_bindgen; @@ -95,42 +95,23 @@ pub fn mouse_position(event: &MouseEvent) -> LogicalPosition { LogicalPosition { x: event.offset_x(), y: event.offset_y() } } -// 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, -} +pub struct MouseDelta(Option>); 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 new() -> Self { + Self(None) } - 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) + pub fn delta(&mut self, event: &MouseEvent) -> PhysicalPosition { + let new = PhysicalPosition::new(event.screen_x(), event.screen_y()); + + if let Some(old) = self.0 { + let delta = PhysicalPosition::new(new.x - old.x, new.y - old.y); + self.0 = Some(new); + delta } else { - LogicalPosition { x: event.movement_x() as f64, y: event.movement_y() as f64 } + self.0 = Some(new); + PhysicalPosition::default() } } } @@ -238,29 +219,6 @@ pub fn pointer_move_event(event: PointerEvent) -> impl Iterator. -pub fn has_pointer_raw_support(window: &web_sys::Window) -> bool { - thread_local! { - static POINTER_RAW_SUPPORT: OnceCell = const { 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 {