Process pointer button events

This commit is contained in:
dAxpeDDa 2023-06-02 11:37:23 +02:00 committed by daxpedda
parent 2ade772ab0
commit d273518ce9
7 changed files with 140 additions and 43 deletions

View file

@ -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

View file

@ -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);
@ -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 {

View file

@ -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};
@ -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 {

View file

@ -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)>>>>;
@ -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))
@ -158,12 +162,11 @@ 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),
);
},
));
@ -171,7 +174,15 @@ impl MouseHandler {
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();
@ -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),
);
}
}

View file

@ -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)]
@ -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));
},
));
}
@ -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));
},
));
}
@ -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),
);
}
},
));
@ -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
@ -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();
@ -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),
);
}
},

View file

@ -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"),
)),
}
}

View file

@ -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};