mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +11:00
On Web, implement DeviceEvent
s (#2871)
This commit is contained in:
parent
9a9c9b15ba
commit
6300cf915e
|
@ -81,6 +81,10 @@ And please only add new entries to the top of this list, right below the `# Unre
|
||||||
- On Web, use `Window.requestIdleCallback()` for `ControlFlow::Poll` when available.
|
- On Web, use `Window.requestIdleCallback()` for `ControlFlow::Poll` when available.
|
||||||
- **Breaking:** On Web, the canvas size is not controlled by Winit anymore and external changes to
|
- **Breaking:** On Web, the canvas size is not controlled by Winit anymore and external changes to
|
||||||
the canvas size will be reported through `WindowEvent::Resized`.
|
the canvas size will be reported through `WindowEvent::Resized`.
|
||||||
|
- On Web, respect `EventLoopWindowTarget::listen_device_events()` settings.
|
||||||
|
- On Web, fix `DeviceEvent::MouseMotion` only being emitted for each canvas instead of the whole window.
|
||||||
|
- On Web, add `DeviceEvent::Motion`, `DeviceEvent::MouseWheel`, `DeviceEvent::Button` and
|
||||||
|
`DeviceEvent::Key` support.
|
||||||
|
|
||||||
# 0.28.6
|
# 0.28.6
|
||||||
|
|
||||||
|
|
|
@ -356,11 +356,11 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
///
|
///
|
||||||
/// ## Platform-specific
|
/// ## Platform-specific
|
||||||
///
|
///
|
||||||
/// - **Wayland / macOS / iOS / Android / Web / Orbital:** Unsupported.
|
/// - **Wayland / macOS / iOS / Android / Orbital:** Unsupported.
|
||||||
///
|
///
|
||||||
/// [`DeviceEvent`]: crate::event::DeviceEvent
|
/// [`DeviceEvent`]: crate::event::DeviceEvent
|
||||||
pub fn listen_device_events(&self, _allowed: DeviceEvents) {
|
pub fn listen_device_events(&self, _allowed: DeviceEvents) {
|
||||||
#[cfg(any(x11_platform, wayland_platform, windows))]
|
#[cfg(any(x11_platform, wasm_platform, wayland_platform, windows))]
|
||||||
self.p.listen_device_events(_allowed);
|
self.p.listen_device_events(_allowed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,24 @@
|
||||||
|
use super::super::DeviceId;
|
||||||
use super::{backend, state::State};
|
use super::{backend, state::State};
|
||||||
use crate::dpi::PhysicalSize;
|
use crate::dpi::PhysicalSize;
|
||||||
use crate::event::{Event, StartCause};
|
use crate::event::{
|
||||||
use crate::event_loop::ControlFlow;
|
DeviceEvent, DeviceId as RootDeviceId, ElementState, Event, RawKeyEvent, StartCause,
|
||||||
|
};
|
||||||
|
use crate::event_loop::{ControlFlow, DeviceEvents};
|
||||||
|
use crate::platform_impl::platform::backend::EventListenerHandle;
|
||||||
use crate::window::WindowId;
|
use crate::window::WindowId;
|
||||||
|
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::{Cell, RefCell},
|
||||||
clone::Clone,
|
clone::Clone,
|
||||||
collections::{HashSet, VecDeque},
|
collections::{HashSet, VecDeque},
|
||||||
iter,
|
iter,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
rc::{Rc, Weak},
|
rc::{Rc, Weak},
|
||||||
};
|
};
|
||||||
|
use wasm_bindgen::prelude::Closure;
|
||||||
|
use web_sys::{KeyboardEvent, PointerEvent, WheelEvent};
|
||||||
use web_time::{Duration, Instant};
|
use web_time::{Duration, Instant};
|
||||||
|
|
||||||
pub struct Shared<T: 'static>(Rc<Execution<T>>);
|
pub struct Shared<T: 'static>(Rc<Execution<T>>);
|
||||||
|
@ -24,6 +31,8 @@ impl<T> Clone for Shared<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OnEventHandle<T> = RefCell<Option<EventListenerHandle<dyn FnMut(T)>>>;
|
||||||
|
|
||||||
pub struct Execution<T: 'static> {
|
pub struct Execution<T: 'static> {
|
||||||
runner: RefCell<RunnerEnum<T>>,
|
runner: RefCell<RunnerEnum<T>>,
|
||||||
events: RefCell<VecDeque<EventWrapper<T>>>,
|
events: RefCell<VecDeque<EventWrapper<T>>>,
|
||||||
|
@ -33,6 +42,13 @@ pub struct Execution<T: 'static> {
|
||||||
redraw_pending: RefCell<HashSet<WindowId>>,
|
redraw_pending: RefCell<HashSet<WindowId>>,
|
||||||
destroy_pending: RefCell<VecDeque<WindowId>>,
|
destroy_pending: RefCell<VecDeque<WindowId>>,
|
||||||
unload_event_handle: RefCell<Option<backend::UnloadEventHandle>>,
|
unload_event_handle: RefCell<Option<backend::UnloadEventHandle>>,
|
||||||
|
device_events: Cell<DeviceEvents>,
|
||||||
|
on_mouse_move: OnEventHandle<PointerEvent>,
|
||||||
|
on_wheel: OnEventHandle<WheelEvent>,
|
||||||
|
on_mouse_press: OnEventHandle<PointerEvent>,
|
||||||
|
on_mouse_release: OnEventHandle<PointerEvent>,
|
||||||
|
on_key_press: OnEventHandle<KeyboardEvent>,
|
||||||
|
on_key_release: OnEventHandle<KeyboardEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RunnerEnum<T: 'static> {
|
enum RunnerEnum<T: 'static> {
|
||||||
|
@ -131,6 +147,13 @@ impl<T: 'static> Shared<T> {
|
||||||
redraw_pending: RefCell::new(HashSet::new()),
|
redraw_pending: RefCell::new(HashSet::new()),
|
||||||
destroy_pending: RefCell::new(VecDeque::new()),
|
destroy_pending: RefCell::new(VecDeque::new()),
|
||||||
unload_event_handle: RefCell::new(None),
|
unload_event_handle: RefCell::new(None),
|
||||||
|
device_events: Cell::default(),
|
||||||
|
on_mouse_move: RefCell::new(None),
|
||||||
|
on_wheel: RefCell::new(None),
|
||||||
|
on_mouse_press: RefCell::new(None),
|
||||||
|
on_mouse_release: RefCell::new(None),
|
||||||
|
on_key_press: RefCell::new(None),
|
||||||
|
on_key_release: RefCell::new(None),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,6 +188,184 @@ impl<T: 'static> Shared<T> {
|
||||||
Some(backend::on_unload(self.window(), move || {
|
Some(backend::on_unload(self.window(), move || {
|
||||||
close_instance.handle_unload()
|
close_instance.handle_unload()
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
let runner = self.clone();
|
||||||
|
let window = self.window().clone();
|
||||||
|
*self.0.on_mouse_move.borrow_mut() = Some(EventListenerHandle::new(
|
||||||
|
self.window(),
|
||||||
|
"pointermove",
|
||||||
|
Closure::new(move |event: PointerEvent| {
|
||||||
|
if !runner.device_events() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pointer_type = event.pointer_type();
|
||||||
|
|
||||||
|
if pointer_type != "mouse" {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// chorded button event
|
||||||
|
let device_id = RootDeviceId(DeviceId(event.pointer_id()));
|
||||||
|
|
||||||
|
if let Some(button) = backend::event::mouse_button(&event) {
|
||||||
|
debug_assert_eq!(
|
||||||
|
pointer_type, "mouse",
|
||||||
|
"expect pointer type of a chorded button event to be a mouse"
|
||||||
|
);
|
||||||
|
|
||||||
|
let state = if backend::event::mouse_buttons(&event).contains(button.into()) {
|
||||||
|
ElementState::Pressed
|
||||||
|
} else {
|
||||||
|
ElementState::Released
|
||||||
|
};
|
||||||
|
|
||||||
|
runner.send_event(Event::DeviceEvent {
|
||||||
|
device_id,
|
||||||
|
event: DeviceEvent::Button {
|
||||||
|
button: button.to_id(),
|
||||||
|
state,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 x_motion = (delta.x != 0.0).then_some(Event::DeviceEvent {
|
||||||
|
device_id,
|
||||||
|
event: DeviceEvent::Motion {
|
||||||
|
axis: 0,
|
||||||
|
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),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
}));
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
let runner = self.clone();
|
||||||
|
let window = self.window().clone();
|
||||||
|
*self.0.on_wheel.borrow_mut() = Some(EventListenerHandle::new(
|
||||||
|
self.window(),
|
||||||
|
"wheel",
|
||||||
|
Closure::new(move |event: WheelEvent| {
|
||||||
|
if !runner.device_events() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(delta) = backend::event::mouse_scroll_delta(&window, &event) {
|
||||||
|
runner.send_event(Event::DeviceEvent {
|
||||||
|
device_id: RootDeviceId(DeviceId(0)),
|
||||||
|
event: DeviceEvent::MouseWheel { delta },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
let runner = self.clone();
|
||||||
|
*self.0.on_mouse_press.borrow_mut() = Some(EventListenerHandle::new(
|
||||||
|
self.window(),
|
||||||
|
"pointerdown",
|
||||||
|
Closure::new(move |event: PointerEvent| {
|
||||||
|
if !runner.device_events() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.pointer_type() != "mouse" {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let button = backend::event::mouse_button(&event).expect("no mouse button pressed");
|
||||||
|
runner.send_event(Event::DeviceEvent {
|
||||||
|
device_id: RootDeviceId(DeviceId(event.pointer_id())),
|
||||||
|
event: DeviceEvent::Button {
|
||||||
|
button: button.to_id(),
|
||||||
|
state: ElementState::Pressed,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
let runner = self.clone();
|
||||||
|
*self.0.on_mouse_release.borrow_mut() = Some(EventListenerHandle::new(
|
||||||
|
self.window(),
|
||||||
|
"pointerup",
|
||||||
|
Closure::new(move |event: PointerEvent| {
|
||||||
|
if !runner.device_events() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.pointer_type() != "mouse" {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let button = backend::event::mouse_button(&event).expect("no mouse button pressed");
|
||||||
|
runner.send_event(Event::DeviceEvent {
|
||||||
|
device_id: RootDeviceId(DeviceId(event.pointer_id())),
|
||||||
|
event: DeviceEvent::Button {
|
||||||
|
button: button.to_id(),
|
||||||
|
state: ElementState::Released,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
let runner = self.clone();
|
||||||
|
*self.0.on_key_press.borrow_mut() = Some(EventListenerHandle::new(
|
||||||
|
self.window(),
|
||||||
|
"keydown",
|
||||||
|
Closure::new(move |event: KeyboardEvent| {
|
||||||
|
if !runner.device_events() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
runner.send_event(Event::DeviceEvent {
|
||||||
|
device_id: RootDeviceId(unsafe { DeviceId::dummy() }),
|
||||||
|
event: DeviceEvent::Key(RawKeyEvent {
|
||||||
|
physical_key: backend::event::key_code(&event),
|
||||||
|
state: ElementState::Pressed,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
let runner = self.clone();
|
||||||
|
*self.0.on_key_release.borrow_mut() = Some(EventListenerHandle::new(
|
||||||
|
self.window(),
|
||||||
|
"keyup",
|
||||||
|
Closure::new(move |event: KeyboardEvent| {
|
||||||
|
if !runner.device_events() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
runner.send_event(Event::DeviceEvent {
|
||||||
|
device_id: RootDeviceId(unsafe { DeviceId::dummy() }),
|
||||||
|
event: DeviceEvent::Key(RawKeyEvent {
|
||||||
|
physical_key: backend::event::key_code(&event),
|
||||||
|
state: ElementState::Released,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a strictly increasing ID
|
// Generate a strictly increasing ID
|
||||||
|
@ -405,6 +606,12 @@ impl<T: 'static> Shared<T> {
|
||||||
self.handle_event(Event::LoopDestroyed, control);
|
self.handle_event(Event::LoopDestroyed, control);
|
||||||
let all_canvases = std::mem::take(&mut *self.0.all_canvases.borrow_mut());
|
let all_canvases = std::mem::take(&mut *self.0.all_canvases.borrow_mut());
|
||||||
*self.0.unload_event_handle.borrow_mut() = None;
|
*self.0.unload_event_handle.borrow_mut() = None;
|
||||||
|
*self.0.on_mouse_move.borrow_mut() = None;
|
||||||
|
*self.0.on_wheel.borrow_mut() = None;
|
||||||
|
*self.0.on_mouse_press.borrow_mut() = None;
|
||||||
|
*self.0.on_mouse_release.borrow_mut() = None;
|
||||||
|
*self.0.on_key_press.borrow_mut() = None;
|
||||||
|
*self.0.on_key_release.borrow_mut() = None;
|
||||||
// Dropping the `Runner` drops the event handler closure, which will in
|
// Dropping the `Runner` drops the event handler closure, which will in
|
||||||
// turn drop all `Window`s moved into the closure.
|
// turn drop all `Window`s moved into the closure.
|
||||||
*self.0.runner.borrow_mut() = RunnerEnum::Destroyed;
|
*self.0.runner.borrow_mut() = RunnerEnum::Destroyed;
|
||||||
|
@ -450,6 +657,24 @@ impl<T: 'static> Shared<T> {
|
||||||
RunnerEnum::Destroyed => ControlFlow::Exit,
|
RunnerEnum::Destroyed => ControlFlow::Exit,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn listen_device_events(&self, allowed: DeviceEvents) {
|
||||||
|
self.0.device_events.set(allowed)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn device_events(&self) -> bool {
|
||||||
|
match self.0.device_events.get() {
|
||||||
|
DeviceEvents::Always => true,
|
||||||
|
DeviceEvents::WhenFocused => self.0.all_canvases.borrow().iter().any(|(_, canvas)| {
|
||||||
|
if let Some(canvas) = canvas.upgrade() {
|
||||||
|
canvas.borrow().has_focus.load(Ordering::Relaxed)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
DeviceEvents::Never => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) enum EventWrapper<T: 'static> {
|
pub(crate) enum EventWrapper<T: 'static> {
|
||||||
|
|
|
@ -3,8 +3,7 @@ use std::clone::Clone;
|
||||||
use std::collections::{vec_deque::IntoIter as VecDequeIter, VecDeque};
|
use std::collections::{vec_deque::IntoIter as VecDequeIter, VecDeque};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::Ordering;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use raw_window_handle::{RawDisplayHandle, WebDisplayHandle};
|
use raw_window_handle::{RawDisplayHandle, WebDisplayHandle};
|
||||||
|
|
||||||
|
@ -18,9 +17,10 @@ use super::{
|
||||||
window::WindowId,
|
window::WindowId,
|
||||||
};
|
};
|
||||||
use crate::event::{
|
use crate::event::{
|
||||||
DeviceEvent, DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase,
|
DeviceEvent, DeviceId as RootDeviceId, ElementState, Event, KeyEvent, RawKeyEvent, Touch,
|
||||||
WindowEvent,
|
TouchPhase, WindowEvent,
|
||||||
};
|
};
|
||||||
|
use crate::event_loop::DeviceEvents;
|
||||||
use crate::keyboard::ModifiersState;
|
use crate::keyboard::ModifiersState;
|
||||||
use crate::window::{Theme, WindowId as RootWindowId};
|
use crate::window::{Theme, WindowId as RootWindowId};
|
||||||
|
|
||||||
|
@ -82,7 +82,6 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
canvas: &Rc<RefCell<backend::Canvas>>,
|
canvas: &Rc<RefCell<backend::Canvas>>,
|
||||||
id: WindowId,
|
id: WindowId,
|
||||||
prevent_default: bool,
|
prevent_default: bool,
|
||||||
has_focus: Arc<AtomicBool>,
|
|
||||||
) {
|
) {
|
||||||
self.runner.add_canvas(RootWindowId(id), canvas);
|
self.runner.add_canvas(RootWindowId(id), canvas);
|
||||||
let canvas_clone = canvas.clone();
|
let canvas_clone = canvas.clone();
|
||||||
|
@ -92,10 +91,10 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
canvas.on_touch_start(prevent_default);
|
canvas.on_touch_start(prevent_default);
|
||||||
|
|
||||||
let runner = self.runner.clone();
|
let runner = self.runner.clone();
|
||||||
let has_focus_clone = has_focus.clone();
|
let has_focus = canvas.has_focus.clone();
|
||||||
let modifiers = self.modifiers.clone();
|
let modifiers = self.modifiers.clone();
|
||||||
canvas.on_blur(move || {
|
canvas.on_blur(move || {
|
||||||
has_focus_clone.store(false, Ordering::Relaxed);
|
has_focus.store(false, Ordering::Relaxed);
|
||||||
|
|
||||||
let clear_modifiers = (!modifiers.get().is_empty()).then(|| {
|
let clear_modifiers = (!modifiers.get().is_empty()).then(|| {
|
||||||
modifiers.set(ModifiersState::empty());
|
modifiers.set(ModifiersState::empty());
|
||||||
|
@ -116,9 +115,9 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
});
|
});
|
||||||
|
|
||||||
let runner = self.runner.clone();
|
let runner = self.runner.clone();
|
||||||
let has_focus_clone = has_focus.clone();
|
let has_focus = canvas.has_focus.clone();
|
||||||
canvas.on_focus(move || {
|
canvas.on_focus(move || {
|
||||||
if !has_focus_clone.swap(true, Ordering::Relaxed) {
|
if !has_focus.swap(true, Ordering::Relaxed) {
|
||||||
runner.send_event(Event::WindowEvent {
|
runner.send_event(Event::WindowEvent {
|
||||||
window_id: RootWindowId(id),
|
window_id: RootWindowId(id),
|
||||||
event: WindowEvent::Focused(true),
|
event: WindowEvent::Focused(true),
|
||||||
|
@ -138,24 +137,36 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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(
|
||||||
iter::once(Event::WindowEvent {
|
device_event
|
||||||
window_id: RootWindowId(id),
|
.into_iter()
|
||||||
event: WindowEvent::KeyboardInput {
|
.chain(iter::once(Event::WindowEvent {
|
||||||
device_id: RootDeviceId(unsafe { DeviceId::dummy() }),
|
window_id: RootWindowId(id),
|
||||||
event: KeyEvent {
|
event: WindowEvent::KeyboardInput {
|
||||||
physical_key,
|
device_id,
|
||||||
logical_key,
|
event: KeyEvent {
|
||||||
text,
|
physical_key,
|
||||||
location,
|
logical_key,
|
||||||
state: ElementState::Pressed,
|
text,
|
||||||
repeat,
|
location,
|
||||||
platform_specific: KeyEventExtra,
|
state: ElementState::Pressed,
|
||||||
|
repeat,
|
||||||
|
platform_specific: KeyEventExtra,
|
||||||
|
},
|
||||||
|
is_synthetic: false,
|
||||||
},
|
},
|
||||||
is_synthetic: false,
|
}))
|
||||||
},
|
.chain(modifiers_changed),
|
||||||
})
|
|
||||||
.chain(modifiers_changed),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
prevent_default,
|
prevent_default,
|
||||||
|
@ -173,29 +184,42 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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(
|
||||||
iter::once(Event::WindowEvent {
|
device_event
|
||||||
window_id: RootWindowId(id),
|
.into_iter()
|
||||||
event: WindowEvent::KeyboardInput {
|
.chain(iter::once(Event::WindowEvent {
|
||||||
device_id: RootDeviceId(unsafe { DeviceId::dummy() }),
|
window_id: RootWindowId(id),
|
||||||
event: KeyEvent {
|
event: WindowEvent::KeyboardInput {
|
||||||
physical_key,
|
device_id,
|
||||||
logical_key,
|
event: KeyEvent {
|
||||||
text,
|
physical_key,
|
||||||
location,
|
logical_key,
|
||||||
state: ElementState::Released,
|
text,
|
||||||
repeat,
|
location,
|
||||||
platform_specific: KeyEventExtra,
|
state: ElementState::Released,
|
||||||
|
repeat,
|
||||||
|
platform_specific: KeyEventExtra,
|
||||||
|
},
|
||||||
|
is_synthetic: false,
|
||||||
},
|
},
|
||||||
is_synthetic: false,
|
}))
|
||||||
},
|
.chain(modifiers_changed),
|
||||||
})
|
|
||||||
.chain(modifiers_changed),
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
prevent_default,
|
prevent_default,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let has_focus = canvas.has_focus.clone();
|
||||||
canvas.on_cursor_leave({
|
canvas.on_cursor_leave({
|
||||||
let runner = self.runner.clone();
|
let runner = self.runner.clone();
|
||||||
let has_focus = has_focus.clone();
|
let has_focus = has_focus.clone();
|
||||||
|
@ -290,13 +314,34 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
|(position, delta)| {
|
|(position, delta)| {
|
||||||
let device_id = RootDeviceId(DeviceId(pointer_id));
|
let device_id = RootDeviceId(DeviceId(pointer_id));
|
||||||
|
|
||||||
[
|
let device_events = runner.device_events().then(|| {
|
||||||
Event::DeviceEvent {
|
let x_motion = (delta.x != 0.0).then_some(Event::DeviceEvent {
|
||||||
device_id,
|
device_id,
|
||||||
event: DeviceEvent::MouseMotion {
|
event: DeviceEvent::Motion {
|
||||||
delta: (delta.x, delta.y),
|
axis: 0,
|
||||||
|
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 {
|
Event::WindowEvent {
|
||||||
window_id: RootWindowId(id),
|
window_id: RootWindowId(id),
|
||||||
event: WindowEvent::CursorMoved {
|
event: WindowEvent::CursorMoved {
|
||||||
|
@ -304,7 +349,7 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
position,
|
position,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
))
|
||||||
},
|
},
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
@ -359,38 +404,41 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let button_event = if buttons.contains(button.into()) {
|
let device_id = RootDeviceId(DeviceId(pointer_id));
|
||||||
Event::WindowEvent {
|
|
||||||
window_id: RootWindowId(id),
|
let state = if buttons.contains(button.into()) {
|
||||||
event: WindowEvent::MouseInput {
|
ElementState::Pressed
|
||||||
device_id: RootDeviceId(DeviceId(pointer_id)),
|
|
||||||
state: ElementState::Pressed,
|
|
||||||
button,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Event::WindowEvent {
|
ElementState::Released
|
||||||
window_id: RootWindowId(id),
|
|
||||||
event: WindowEvent::MouseInput {
|
|
||||||
device_id: RootDeviceId(DeviceId(pointer_id)),
|
|
||||||
state: ElementState::Released,
|
|
||||||
button,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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([
|
runner.send_events(modifiers.into_iter().chain(device_event).chain([
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
window_id: RootWindowId(id),
|
window_id: RootWindowId(id),
|
||||||
event: WindowEvent::CursorMoved {
|
event: WindowEvent::CursorMoved {
|
||||||
device_id: RootDeviceId(DeviceId(pointer_id)),
|
device_id,
|
||||||
position,
|
position,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
button_event,
|
Event::WindowEvent {
|
||||||
|
window_id: RootWindowId(id),
|
||||||
|
event: WindowEvent::MouseInput {
|
||||||
|
device_id,
|
||||||
|
state,
|
||||||
|
button,
|
||||||
|
},
|
||||||
|
},
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -425,21 +473,30 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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([
|
runner.send_events(modifiers.into_iter().chain(device_event).chain([
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
window_id: RootWindowId(id),
|
window_id: RootWindowId(id),
|
||||||
event: WindowEvent::CursorMoved {
|
event: WindowEvent::CursorMoved {
|
||||||
device_id: RootDeviceId(DeviceId(pointer_id)),
|
device_id,
|
||||||
position,
|
position,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
window_id: RootWindowId(id),
|
window_id: RootWindowId(id),
|
||||||
event: WindowEvent::MouseInput {
|
event: WindowEvent::MouseInput {
|
||||||
device_id: RootDeviceId(DeviceId(pointer_id)),
|
device_id,
|
||||||
state: ElementState::Pressed,
|
state: ElementState::Pressed,
|
||||||
button,
|
button,
|
||||||
},
|
},
|
||||||
|
@ -509,21 +566,30 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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([
|
runner.send_events(modifiers.into_iter().chain(device_event).chain([
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
window_id: RootWindowId(id),
|
window_id: RootWindowId(id),
|
||||||
event: WindowEvent::CursorMoved {
|
event: WindowEvent::CursorMoved {
|
||||||
device_id: RootDeviceId(DeviceId(pointer_id)),
|
device_id,
|
||||||
position,
|
position,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
window_id: RootWindowId(id),
|
window_id: RootWindowId(id),
|
||||||
event: WindowEvent::MouseInput {
|
event: WindowEvent::MouseInput {
|
||||||
device_id: RootDeviceId(DeviceId(pointer_id)),
|
device_id,
|
||||||
state: ElementState::Released,
|
state: ElementState::Released,
|
||||||
button,
|
button,
|
||||||
},
|
},
|
||||||
|
@ -577,16 +643,21 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
runner.send_events(modifiers_changed.into_iter().chain(iter::once(
|
let device_event = runner.device_events().then_some(Event::DeviceEvent {
|
||||||
Event::WindowEvent {
|
device_id: RootDeviceId(DeviceId(pointer_id)),
|
||||||
|
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,
|
||||||
);
|
);
|
||||||
|
@ -661,4 +732,8 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
pub fn raw_display_handle(&self) -> RawDisplayHandle {
|
pub fn raw_display_handle(&self) -> RawDisplayHandle {
|
||||||
RawDisplayHandle::Web(WebDisplayHandle::empty())
|
RawDisplayHandle::Web(WebDisplayHandle::empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn listen_device_events(&self, allowed: DeviceEvents) {
|
||||||
|
self.runner.listen_device_events(allowed)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@ use crate::window::{WindowAttributes, WindowId as RootWindowId};
|
||||||
|
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::sync::atomic::AtomicBool;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use js_sys::Promise;
|
use js_sys::Promise;
|
||||||
use smol_str::SmolStr;
|
use smol_str::SmolStr;
|
||||||
|
@ -24,6 +26,7 @@ use web_sys::{Event, FocusEvent, HtmlCanvasElement, KeyboardEvent, WheelEvent};
|
||||||
pub struct Canvas {
|
pub struct Canvas {
|
||||||
common: Common,
|
common: Common,
|
||||||
id: WindowId,
|
id: WindowId,
|
||||||
|
pub has_focus: Arc<AtomicBool>,
|
||||||
on_touch_start: Option<EventListenerHandle<dyn FnMut(Event)>>,
|
on_touch_start: Option<EventListenerHandle<dyn FnMut(Event)>>,
|
||||||
on_touch_end: Option<EventListenerHandle<dyn FnMut(Event)>>,
|
on_touch_end: Option<EventListenerHandle<dyn FnMut(Event)>>,
|
||||||
on_focus: Option<EventListenerHandle<dyn FnMut(FocusEvent)>>,
|
on_focus: Option<EventListenerHandle<dyn FnMut(FocusEvent)>>,
|
||||||
|
@ -91,6 +94,7 @@ impl Canvas {
|
||||||
wants_fullscreen: Rc::new(RefCell::new(false)),
|
wants_fullscreen: Rc::new(RefCell::new(false)),
|
||||||
},
|
},
|
||||||
id,
|
id,
|
||||||
|
has_focus: Arc::new(AtomicBool::new(false)),
|
||||||
on_touch_start: None,
|
on_touch_start: None,
|
||||||
on_touch_end: None,
|
on_touch_end: None,
|
||||||
on_blur: None,
|
on_blur: None,
|
||||||
|
|
|
@ -57,6 +57,17 @@ pub fn mouse_button(event: &MouseEvent) -> Option<MouseButton> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MouseButton {
|
||||||
|
pub fn to_id(self) -> u32 {
|
||||||
|
match self {
|
||||||
|
MouseButton::Left => 0,
|
||||||
|
MouseButton::Right => 1,
|
||||||
|
MouseButton::Middle => 2,
|
||||||
|
MouseButton::Other(value) => value.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mouse_position(event: &MouseEvent) -> LogicalPosition<f64> {
|
pub fn mouse_position(event: &MouseEvent) -> LogicalPosition<f64> {
|
||||||
LogicalPosition {
|
LogicalPosition {
|
||||||
x: event.offset_x() as f64,
|
x: event.offset_x() as f64,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
mod canvas;
|
mod canvas;
|
||||||
mod event;
|
pub mod event;
|
||||||
mod event_handle;
|
mod event_handle;
|
||||||
mod media_query_handle;
|
mod media_query_handle;
|
||||||
mod pointer;
|
mod pointer;
|
||||||
|
@ -8,6 +8,7 @@ mod timeout;
|
||||||
|
|
||||||
pub use self::canvas::Canvas;
|
pub use self::canvas::Canvas;
|
||||||
pub use self::event::ButtonsState;
|
pub use self::event::ButtonsState;
|
||||||
|
pub use self::event_handle::EventListenerHandle;
|
||||||
pub use self::resize_scaling::ResizeScaleHandle;
|
pub use self::resize_scaling::ResizeScaleHandle;
|
||||||
pub use self::timeout::{IdleCallback, Timeout};
|
pub use self::timeout::{IdleCallback, Timeout};
|
||||||
|
|
||||||
|
|
|
@ -51,12 +51,12 @@ impl Window {
|
||||||
|
|
||||||
let register_redraw_request = Box::new(move || runner.request_redraw(RootWI(id)));
|
let register_redraw_request = Box::new(move || runner.request_redraw(RootWI(id)));
|
||||||
|
|
||||||
let has_focus = Arc::new(AtomicBool::new(false));
|
target.register(&canvas, id, prevent_default);
|
||||||
target.register(&canvas, id, prevent_default, has_focus.clone());
|
|
||||||
|
|
||||||
let runner = target.runner.clone();
|
let runner = target.runner.clone();
|
||||||
let destroy_fn = Box::new(move || runner.notify_destroy_window(RootWI(id)));
|
let destroy_fn = Box::new(move || runner.notify_destroy_window(RootWI(id)));
|
||||||
|
|
||||||
|
let has_focus = canvas.borrow().has_focus.clone();
|
||||||
let window = Window {
|
let window = Window {
|
||||||
id,
|
id,
|
||||||
has_focus,
|
has_focus,
|
||||||
|
|
Loading…
Reference in a new issue