Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ And please only add new entries to the top of this list, right below the `# Unre
- On Web: fix position of touch events to be relative to the canvas.
- On Web, fix `Window:::set_fullscreen` doing nothing when called outside the event loop but during
a transient activation.
- On Web, fix pointer button events not being processed when a buttons is already pressed.

# 0.28.6

Expand Down
59 changes: 43 additions & 16 deletions src/platform_impl/web/event_loop/window_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ impl<T> EventLoopWindowTarget<T> {
let modifiers = self.modifiers.clone();
let has_focus_clone = has_focus.clone();
canvas.on_cursor_move(
move |pointer_id, position, delta, active_modifiers| {
move |pointer_id, position, delta, active_modifiers, buttons, button| {
let modifiers_changed =
(has_focus_clone.get() && modifiers.get() != active_modifiers).then(|| {
modifiers.set(active_modifiers);
Expand All @@ -259,21 +259,48 @@ impl<T> EventLoopWindowTarget<T> {
}
});

runner.send_events(modifiers_changed.into_iter().chain([
Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::CursorMoved {
device_id: RootDeviceId(DeviceId(pointer_id)),
position,
},
},
Event::DeviceEvent {
device_id: RootDeviceId(DeviceId(pointer_id)),
event: DeviceEvent::MouseMotion {
delta: (delta.x, delta.y),
},
},
]));
let button_event = button.map(|button| {
if buttons.contains(button.into()) {
Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::MouseInput {
device_id: RootDeviceId(DeviceId(pointer_id)),
state: ElementState::Pressed,
button,
},
}
} else {
Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::MouseInput {
device_id: RootDeviceId(DeviceId(pointer_id)),
state: ElementState::Released,
button,
},
}
}
});

runner.send_events(
modifiers_changed
.into_iter()
.chain([
Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::CursorMoved {
device_id: RootDeviceId(DeviceId(pointer_id)),
position,
},
},
Event::DeviceEvent {
device_id: RootDeviceId(DeviceId(pointer_id)),
event: DeviceEvent::MouseMotion {
delta: (delta.x, delta.y),
},
},
])
.chain(button_event),
);
},
move |device_id, location, force| {
runner_touch.send_event(Event::WindowEvent {
Expand Down
12 changes: 10 additions & 2 deletions src/platform_impl/web/web_sys/canvas.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::event;
use super::event_handle::EventListenerHandle;
use super::media_query_handle::MediaQueryListHandle;
use super::{event, ButtonsState};
use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
use crate::error::OsError as RootOE;
use crate::event::{Force, MouseButton, MouseScrollDelta};
Expand Down Expand Up @@ -273,7 +273,15 @@ impl Canvas {
touch_handler: T,
prevent_default: bool,
) where
M: 'static + FnMut(i32, PhysicalPosition<f64>, PhysicalPosition<f64>, ModifiersState),
M: 'static
+ FnMut(
i32,
PhysicalPosition<f64>,
PhysicalPosition<f64>,
ModifiersState,
ButtonsState,
Option<MouseButton>,
),
T: 'static + FnMut(i32, PhysicalPosition<f64>, Force),
{
match &mut self.mouse_state {
Expand Down
28 changes: 20 additions & 8 deletions src/platform_impl/web/web_sys/canvas/mouse_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::keyboard::ModifiersState;
use std::cell::RefCell;
use std::rc::Rc;

use event::ButtonsState;
use web_sys::{EventTarget, MouseEvent};

type MouseLeaveHandler = Rc<RefCell<Option<Box<dyn FnMut(i32, ModifiersState)>>>>;
Expand Down Expand Up @@ -108,8 +109,11 @@ impl MouseHandler {
MouseCaptureState::Captured => {}
}
event.stop_propagation();
let modifiers = event::mouse_modifiers(&event);
handler(0, event::mouse_button(&event), modifiers);
handler(
0,
event::mouse_button(&event).expect("no mouse button released"),
event::mouse_modifiers(&event),
);
if event
.target()
.map_or(false, |target| target != EventTarget::from(canvas))
Expand Down Expand Up @@ -158,20 +162,27 @@ impl MouseHandler {
}
*mouse_capture_state = MouseCaptureState::Captured;
event.stop_propagation();
let modifiers = event::mouse_modifiers(&event);
handler(
0,
event::mouse_position(&event).to_physical(super::super::scale_factor()),
event::mouse_button(&event),
modifiers,
event::mouse_button(&event).expect("no mouse button pressed"),
event::mouse_modifiers(&event),
);
},
));
}

pub fn on_cursor_move<F>(&mut self, canvas_common: &super::Common, mut handler: F)
where
F: 'static + FnMut(i32, PhysicalPosition<f64>, PhysicalPosition<f64>, ModifiersState),
F: 'static
+ FnMut(
i32,
PhysicalPosition<f64>,
PhysicalPosition<f64>,
ModifiersState,
ButtonsState,
Option<MouseButton>,
),
{
let mouse_capture_state = self.mouse_capture_state.clone();
let canvas = canvas_common.raw.clone();
Expand Down Expand Up @@ -202,12 +213,13 @@ impl MouseHandler {
event::mouse_position_by_client(&event, &canvas)
};
let mouse_delta = event::mouse_delta(&event);
let modifiers = event::mouse_modifiers(&event);
handler(
0,
mouse_pos.to_physical(super::super::scale_factor()),
mouse_delta.to_physical(super::super::scale_factor()),
modifiers,
event::mouse_modifiers(&event),
event::mouse_buttons(&event),
event::mouse_button(&event),
);
}
}
Expand Down
34 changes: 22 additions & 12 deletions src/platform_impl/web/web_sys/canvas/pointer_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::dpi::PhysicalPosition;
use crate::event::{Force, MouseButton};
use crate::keyboard::ModifiersState;

use event::ButtonsState;
use web_sys::PointerEvent;

#[allow(dead_code)]
Expand Down Expand Up @@ -42,8 +43,7 @@ impl PointerHandler {
return;
}

let modifiers = event::mouse_modifiers(&event);
handler(event.pointer_id(), modifiers);
handler(event.pointer_id(), event::mouse_modifiers(&event));
},
));
}
Expand All @@ -62,8 +62,7 @@ impl PointerHandler {
return;
}

let modifiers = event::mouse_modifiers(&event);
handler(event.pointer_id(), modifiers);
handler(event.pointer_id(), event::mouse_modifiers(&event));
},
));
}
Expand All @@ -89,8 +88,11 @@ impl PointerHandler {
Force::Normalized(event.pressure() as f64),
);
} else {
let modifiers = event::mouse_modifiers(&event);
mouse_handler(event.pointer_id(), event::mouse_button(&event), modifiers);
mouse_handler(
event.pointer_id(),
event::mouse_button(&event).expect("no mouse button released"),
event::mouse_modifiers(&event),
);
}
},
));
Expand All @@ -117,12 +119,11 @@ impl PointerHandler {
Force::Normalized(event.pressure() as f64),
);
} else {
let modifiers = event::mouse_modifiers(&event);
mouse_handler(
event.pointer_id(),
event::mouse_position(&event).to_physical(super::super::scale_factor()),
event::mouse_button(&event),
modifiers,
event::mouse_button(&event).expect("no mouse button pressed"),
event::mouse_modifiers(&event),
);

// Error is swallowed here since the error would occur every time the mouse is
Expand All @@ -141,7 +142,15 @@ impl PointerHandler {
mut touch_handler: T,
prevent_default: bool,
) where
M: 'static + FnMut(i32, PhysicalPosition<f64>, PhysicalPosition<f64>, ModifiersState),
M: 'static
+ FnMut(
i32,
PhysicalPosition<f64>,
PhysicalPosition<f64>,
ModifiersState,
ButtonsState,
Option<MouseButton>,
),
T: 'static + FnMut(i32, PhysicalPosition<f64>, Force),
{
let canvas = canvas_common.raw.clone();
Expand All @@ -160,12 +169,13 @@ impl PointerHandler {
Force::Normalized(event.pressure() as f64),
);
} else {
let modifiers = event::mouse_modifiers(&event);
mouse_handler(
event.pointer_id(),
event::mouse_position(&event).to_physical(super::super::scale_factor()),
event::mouse_delta(&event).to_physical(super::super::scale_factor()),
modifiers,
event::mouse_modifiers(&event),
event::mouse_buttons(&event),
event::mouse_button(&event),
);
}
},
Expand Down
48 changes: 43 additions & 5 deletions src/platform_impl/web/web_sys/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,50 @@ use smol_str::SmolStr;
use std::convert::TryInto;
use web_sys::{HtmlCanvasElement, KeyboardEvent, MouseEvent, PointerEvent, WheelEvent};

pub fn mouse_button(event: &MouseEvent) -> MouseButton {
bitflags! {
pub struct ButtonsState: u16 {
const LEFT = 0b001;
const RIGHT = 0b010;
const MIDDLE = 0b100;
}
}

impl From<ButtonsState> for MouseButton {
fn from(value: ButtonsState) -> Self {
match value {
ButtonsState::LEFT => MouseButton::Left,
ButtonsState::RIGHT => MouseButton::Right,
ButtonsState::MIDDLE => MouseButton::Middle,
_ => MouseButton::Other(value.bits()),
}
}
}

impl From<MouseButton> for ButtonsState {
fn from(value: MouseButton) -> Self {
match value {
MouseButton::Left => ButtonsState::LEFT,
MouseButton::Right => ButtonsState::RIGHT,
MouseButton::Middle => ButtonsState::MIDDLE,
MouseButton::Other(value) => unsafe { ButtonsState::from_bits_unchecked(value) },
}
}
}

pub fn mouse_buttons(event: &MouseEvent) -> ButtonsState {
unsafe { ButtonsState::from_bits_unchecked(event.buttons()) }
}

pub fn mouse_button(event: &MouseEvent) -> Option<MouseButton> {
match event.button() {
0 => MouseButton::Left,
1 => MouseButton::Middle,
2 => MouseButton::Right,
i => MouseButton::Other((i - 3).try_into().expect("very large mouse button value")),
-1 => None,
0 => Some(MouseButton::Left),
1 => Some(MouseButton::Middle),
2 => Some(MouseButton::Right),
i => Some(MouseButton::Other(
i.try_into()
.expect("unexpected negative mouse button value"),
)),
}
}

Expand Down
1 change: 1 addition & 0 deletions src/platform_impl/web/web_sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod scaling;
mod timeout;

pub use self::canvas::Canvas;
pub use self::event::ButtonsState;
pub use self::scaling::ScaleChangeDetector;
pub use self::timeout::{AnimationFrameRequest, Timeout};

Expand Down