mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 13:51:30 +11:00
web: add with_prevent_default
, with_focusable
(#2365)
* web: add `with_prevent_default`, `with_focusable` `with_prevent_default` controls whether `event.preventDefault` is called `with_focusable` controls whether `tabindex` is added Fixes #1768 * Remove extra space from CHANGELOG
This commit is contained in:
parent
472d7b9376
commit
990e34a129
|
@ -70,6 +70,7 @@ And please only add new entries to the top of this list, right below the `# Unre
|
|||
- Added `From<u64>` for `WindowId` and `From<WindowId>` for `u64`.
|
||||
- Added `MonitorHandle::refresh_rate_millihertz` to get monitor's refresh rate.
|
||||
- **Breaking**, Replaced `VideoMode::refresh_rate` with `VideoMode::refresh_rate_millihertz` providing better precision.
|
||||
- On Web, add `with_prevent_default` and `with_focusable` to `WindowBuilderExtWebSys` to control whether events should be propagated.
|
||||
|
||||
# 0.26.1 (2022-01-05)
|
||||
|
||||
|
|
|
@ -22,6 +22,17 @@ pub trait WindowExtWebSys {
|
|||
|
||||
pub trait WindowBuilderExtWebSys {
|
||||
fn with_canvas(self, canvas: Option<HtmlCanvasElement>) -> Self;
|
||||
|
||||
/// Whether `event.preventDefault` should be automatically called to prevent event propagation
|
||||
/// when appropriate.
|
||||
///
|
||||
/// For example, mouse wheel events are only handled by the canvas by default. This avoids
|
||||
/// the default behavior of scrolling the page.
|
||||
fn with_prevent_default(self, prevent_default: bool) -> Self;
|
||||
|
||||
/// Whether the canvas should be focusable using the tab key. This is necessary to capture
|
||||
/// canvas keyboard events.
|
||||
fn with_focusable(self, focusable: bool) -> Self;
|
||||
}
|
||||
|
||||
impl WindowBuilderExtWebSys for WindowBuilder {
|
||||
|
@ -30,6 +41,18 @@ impl WindowBuilderExtWebSys for WindowBuilder {
|
|||
|
||||
self
|
||||
}
|
||||
|
||||
fn with_prevent_default(mut self, prevent_default: bool) -> Self {
|
||||
self.platform_specific.prevent_default = prevent_default;
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
fn with_focusable(mut self, focusable: bool) -> Self {
|
||||
self.platform_specific.focusable = focusable;
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Additional methods on `EventLoop` that are specific to the web.
|
||||
|
|
|
@ -50,7 +50,12 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
WindowId(self.runner.generate_id())
|
||||
}
|
||||
|
||||
pub fn register(&self, canvas: &Rc<RefCell<backend::Canvas>>, id: WindowId) {
|
||||
pub fn register(
|
||||
&self,
|
||||
canvas: &Rc<RefCell<backend::Canvas>>,
|
||||
id: WindowId,
|
||||
prevent_default: bool,
|
||||
) {
|
||||
self.runner.add_canvas(RootWindowId(id), canvas);
|
||||
let mut canvas = canvas.borrow_mut();
|
||||
canvas.set_attribute("data-raw-handle", &id.0.to_string());
|
||||
|
@ -72,48 +77,57 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
});
|
||||
|
||||
let runner = self.runner.clone();
|
||||
canvas.on_keyboard_press(move |scancode, virtual_keycode, modifiers| {
|
||||
#[allow(deprecated)]
|
||||
runner.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
event: WindowEvent::KeyboardInput {
|
||||
device_id: RootDeviceId(unsafe { DeviceId::dummy() }),
|
||||
input: KeyboardInput {
|
||||
scancode,
|
||||
state: ElementState::Pressed,
|
||||
virtual_keycode,
|
||||
modifiers,
|
||||
canvas.on_keyboard_press(
|
||||
move |scancode, virtual_keycode, modifiers| {
|
||||
#[allow(deprecated)]
|
||||
runner.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
event: WindowEvent::KeyboardInput {
|
||||
device_id: RootDeviceId(unsafe { DeviceId::dummy() }),
|
||||
input: KeyboardInput {
|
||||
scancode,
|
||||
state: ElementState::Pressed,
|
||||
virtual_keycode,
|
||||
modifiers,
|
||||
},
|
||||
is_synthetic: false,
|
||||
},
|
||||
is_synthetic: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
prevent_default,
|
||||
);
|
||||
|
||||
let runner = self.runner.clone();
|
||||
canvas.on_keyboard_release(move |scancode, virtual_keycode, modifiers| {
|
||||
#[allow(deprecated)]
|
||||
runner.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
event: WindowEvent::KeyboardInput {
|
||||
device_id: RootDeviceId(unsafe { DeviceId::dummy() }),
|
||||
input: KeyboardInput {
|
||||
scancode,
|
||||
state: ElementState::Released,
|
||||
virtual_keycode,
|
||||
modifiers,
|
||||
canvas.on_keyboard_release(
|
||||
move |scancode, virtual_keycode, modifiers| {
|
||||
#[allow(deprecated)]
|
||||
runner.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
event: WindowEvent::KeyboardInput {
|
||||
device_id: RootDeviceId(unsafe { DeviceId::dummy() }),
|
||||
input: KeyboardInput {
|
||||
scancode,
|
||||
state: ElementState::Released,
|
||||
virtual_keycode,
|
||||
modifiers,
|
||||
},
|
||||
is_synthetic: false,
|
||||
},
|
||||
is_synthetic: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
prevent_default,
|
||||
);
|
||||
|
||||
let runner = self.runner.clone();
|
||||
canvas.on_received_character(move |char_code| {
|
||||
runner.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
event: WindowEvent::ReceivedCharacter(char_code),
|
||||
});
|
||||
});
|
||||
canvas.on_received_character(
|
||||
move |char_code| {
|
||||
runner.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
event: WindowEvent::ReceivedCharacter(char_code),
|
||||
});
|
||||
},
|
||||
prevent_default,
|
||||
);
|
||||
|
||||
let runner = self.runner.clone();
|
||||
canvas.on_cursor_leave(move |pointer_id| {
|
||||
|
@ -197,17 +211,20 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
});
|
||||
|
||||
let runner = self.runner.clone();
|
||||
canvas.on_mouse_wheel(move |pointer_id, delta, modifiers| {
|
||||
runner.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
event: WindowEvent::MouseWheel {
|
||||
device_id: RootDeviceId(DeviceId(pointer_id)),
|
||||
delta,
|
||||
phase: TouchPhase::Moved,
|
||||
modifiers,
|
||||
},
|
||||
});
|
||||
});
|
||||
canvas.on_mouse_wheel(
|
||||
move |pointer_id, delta, modifiers| {
|
||||
runner.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
event: WindowEvent::MouseWheel {
|
||||
device_id: RootDeviceId(DeviceId(pointer_id)),
|
||||
delta,
|
||||
phase: TouchPhase::Moved,
|
||||
modifiers,
|
||||
},
|
||||
});
|
||||
},
|
||||
prevent_default,
|
||||
);
|
||||
|
||||
let runner = self.runner.clone();
|
||||
let raw = canvas.raw().clone();
|
||||
|
|
|
@ -62,9 +62,11 @@ impl Canvas {
|
|||
// sequential keyboard navigation, but its order is defined by the
|
||||
// document's source order.
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
|
||||
canvas
|
||||
.set_attribute("tabindex", "0")
|
||||
.map_err(|_| os_error!(OsError("Failed to set a tabindex".to_owned())))?;
|
||||
if attr.focusable {
|
||||
canvas
|
||||
.set_attribute("tabindex", "0")
|
||||
.map_err(|_| os_error!(OsError("Failed to set a tabindex".to_owned())))?;
|
||||
}
|
||||
|
||||
let mouse_state = if has_pointer_event() {
|
||||
MouseState::HasPointerEvent(pointer_handler::PointerHandler::new())
|
||||
|
@ -148,14 +150,17 @@ impl Canvas {
|
|||
}));
|
||||
}
|
||||
|
||||
pub fn on_keyboard_release<F>(&mut self, mut handler: F)
|
||||
pub fn on_keyboard_release<F>(&mut self, mut handler: F, prevent_default: bool)
|
||||
where
|
||||
F: 'static + FnMut(ScanCode, Option<VirtualKeyCode>, ModifiersState),
|
||||
{
|
||||
self.on_keyboard_release = Some(self.common.add_user_event(
|
||||
"keyup",
|
||||
move |event: KeyboardEvent| {
|
||||
event.prevent_default();
|
||||
if prevent_default {
|
||||
event.prevent_default();
|
||||
}
|
||||
|
||||
handler(
|
||||
event::scan_code(&event),
|
||||
event::virtual_key_code(&event),
|
||||
|
@ -165,7 +170,7 @@ impl Canvas {
|
|||
));
|
||||
}
|
||||
|
||||
pub fn on_keyboard_press<F>(&mut self, mut handler: F)
|
||||
pub fn on_keyboard_press<F>(&mut self, mut handler: F, prevent_default: bool)
|
||||
where
|
||||
F: 'static + FnMut(ScanCode, Option<VirtualKeyCode>, ModifiersState),
|
||||
{
|
||||
|
@ -173,16 +178,19 @@ impl Canvas {
|
|||
"keydown",
|
||||
move |event: KeyboardEvent| {
|
||||
// event.prevent_default() would suppress subsequent on_received_character() calls. That
|
||||
// supression is correct for key sequences like Tab/Shift-Tab, Ctrl+R, PgUp/Down to
|
||||
// suppression is correct for key sequences like Tab/Shift-Tab, Ctrl+R, PgUp/Down to
|
||||
// scroll, etc. We should not do it for key sequences that result in meaningful character
|
||||
// input though.
|
||||
let event_key = &event.key();
|
||||
let is_key_string = event_key.len() == 1 || !event_key.is_ascii();
|
||||
let is_shortcut_modifiers =
|
||||
(event.ctrl_key() || event.alt_key()) && !event.get_modifier_state("AltGr");
|
||||
if !is_key_string || is_shortcut_modifiers {
|
||||
event.prevent_default();
|
||||
if prevent_default {
|
||||
let event_key = &event.key();
|
||||
let is_key_string = event_key.len() == 1 || !event_key.is_ascii();
|
||||
let is_shortcut_modifiers =
|
||||
(event.ctrl_key() || event.alt_key()) && !event.get_modifier_state("AltGr");
|
||||
if !is_key_string || is_shortcut_modifiers {
|
||||
event.prevent_default();
|
||||
}
|
||||
}
|
||||
|
||||
handler(
|
||||
event::scan_code(&event),
|
||||
event::virtual_key_code(&event),
|
||||
|
@ -192,7 +200,7 @@ impl Canvas {
|
|||
));
|
||||
}
|
||||
|
||||
pub fn on_received_character<F>(&mut self, mut handler: F)
|
||||
pub fn on_received_character<F>(&mut self, mut handler: F, prevent_default: bool)
|
||||
where
|
||||
F: 'static + FnMut(char),
|
||||
{
|
||||
|
@ -204,8 +212,11 @@ impl Canvas {
|
|||
self.on_received_character = Some(self.common.add_user_event(
|
||||
"keypress",
|
||||
move |event: KeyboardEvent| {
|
||||
// Supress further handling to stop keys like the space key from scrolling the page.
|
||||
event.prevent_default();
|
||||
// Suppress further handling to stop keys like the space key from scrolling the page.
|
||||
if prevent_default {
|
||||
event.prevent_default();
|
||||
}
|
||||
|
||||
handler(event::codepoint(&event));
|
||||
},
|
||||
));
|
||||
|
@ -261,12 +272,15 @@ impl Canvas {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn on_mouse_wheel<F>(&mut self, mut handler: F)
|
||||
pub fn on_mouse_wheel<F>(&mut self, mut handler: F, prevent_default: bool)
|
||||
where
|
||||
F: 'static + FnMut(i32, MouseScrollDelta, ModifiersState),
|
||||
{
|
||||
self.on_mouse_wheel = Some(self.common.add_event("wheel", move |event: WheelEvent| {
|
||||
event.prevent_default();
|
||||
if prevent_default {
|
||||
event.prevent_default();
|
||||
}
|
||||
|
||||
if let Some(delta) = event::mouse_scroll_delta(&event) {
|
||||
handler(0, delta, event::mouse_modifiers(&event));
|
||||
}
|
||||
|
|
|
@ -35,12 +35,14 @@ impl Window {
|
|||
|
||||
let id = target.generate_id();
|
||||
|
||||
let prevent_default = platform_attr.prevent_default;
|
||||
|
||||
let canvas = backend::Canvas::create(platform_attr)?;
|
||||
let canvas = Rc::new(RefCell::new(canvas));
|
||||
|
||||
let register_redraw_request = Box::new(move || runner.request_redraw(RootWI(id)));
|
||||
|
||||
target.register(&canvas, id);
|
||||
target.register(&canvas, id, prevent_default);
|
||||
|
||||
let runner = target.runner.clone();
|
||||
let resize_notify_fn = Box::new(move |new_size| {
|
||||
|
@ -392,7 +394,19 @@ impl From<u64> for WindowId {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct PlatformSpecificWindowBuilderAttributes {
|
||||
pub(crate) canvas: Option<backend::RawCanvasType>,
|
||||
pub(crate) prevent_default: bool,
|
||||
pub(crate) focusable: bool,
|
||||
}
|
||||
|
||||
impl Default for PlatformSpecificWindowBuilderAttributes {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
canvas: None,
|
||||
prevent_default: true,
|
||||
focusable: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue