1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-29 04:40:03 -04:00

Remove Modifiers from RawInput and make it a egui::Event (#8336)

- needs #8335 

Previously it was impossible to correctly set modifiers via egui
inspection, since that only passes egui::Event and egui::Event had no
way to generally express modifiers.
Now modifiers are passed to egui as a Event and not as a field of
`RawInput`.

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
Lucas Meurer
2026-07-27 16:17:22 +02:00
committed by GitHub
parent e6eb00a31c
commit 2cb071f7f6
8 changed files with 106 additions and 69 deletions

View File

@@ -20,6 +20,12 @@ pub(crate) struct WebInput {
/// Helps to track the delta rotation from gesture events /// Helps to track the delta rotation from gesture events
pub accumulated_rotation: f32, pub accumulated_rotation: f32,
/// The last modifier state we sent to egui.
///
/// The web has no dedicated modifier event, so we derive the state from each DOM event and
/// emit [`egui::Event::ModifiersChanged`] when it changes (see [`Self::set_modifiers`]).
pub modifiers: egui::Modifiers,
/// The raw input to `egui`. /// The raw input to `egui`.
pub raw: egui::RawInput, pub raw: egui::RawInput,
} }
@@ -53,11 +59,23 @@ impl WebInput {
} }
// log::debug!("on_web_page_focus_change: {focused}"); // log::debug!("on_web_page_focus_change: {focused}");
self.raw.modifiers = egui::Modifiers::default(); // Avoid sticky modifier keys on alt-tab: self.modifiers = egui::Modifiers::default(); // Avoid sticky modifier keys on alt-tab:
self.raw.focused = focused; self.raw.focused = focused;
self.raw.events.push(egui::Event::WindowFocused(focused)); self.raw.events.push(egui::Event::WindowFocused(focused));
self.primary_touch = None; self.primary_touch = None;
} }
/// Update the modifier state, emitting [`egui::Event::ModifiersChanged`] if it changed.
///
/// Call before pushing the DOM event itself so egui sees the new modifier state first.
pub fn set_modifiers(&mut self, modifiers: egui::Modifiers) {
if self.modifiers != modifiers {
self.modifiers = modifiers;
self.raw
.events
.push(egui::Event::ModifiersChanged(modifiers));
}
}
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@@ -196,7 +196,7 @@ pub(crate) fn on_keydown(event: web_sys::KeyboardEvent, runner: &mut AppRunner)
} }
let modifiers = modifiers_from_kb_event(&event); let modifiers = modifiers_from_kb_event(&event);
runner.input.raw.modifiers = modifiers; runner.input.set_modifiers(modifiers);
let key = event.key(); let key = event.key();
let egui_key = translate_key(&key); let egui_key = translate_key(&key);
@@ -287,7 +287,7 @@ fn install_keyup(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), JsV
#[expect(clippy::needless_pass_by_value)] // So that we can pass it directly to `add_event_listener` #[expect(clippy::needless_pass_by_value)] // So that we can pass it directly to `add_event_listener`
pub(crate) fn on_keyup(event: web_sys::KeyboardEvent, runner: &mut AppRunner) { pub(crate) fn on_keyup(event: web_sys::KeyboardEvent, runner: &mut AppRunner) {
let modifiers = modifiers_from_kb_event(&event); let modifiers = modifiers_from_kb_event(&event);
runner.input.raw.modifiers = modifiers; runner.input.set_modifiers(modifiers);
let mut should_stop_propagation = true; let mut should_stop_propagation = true;
@@ -535,11 +535,11 @@ fn install_pointerdown(runner_ref: &WebRunner, target: &EventTarget) -> Result<(
"pointerdown", "pointerdown",
|event: web_sys::PointerEvent, runner: &mut AppRunner| { |event: web_sys::PointerEvent, runner: &mut AppRunner| {
let modifiers = modifiers_from_mouse_event(&event); let modifiers = modifiers_from_mouse_event(&event);
runner.input.raw.modifiers = modifiers; runner.input.set_modifiers(modifiers);
let mut should_stop_propagation = true; let mut should_stop_propagation = true;
if let Some(button) = button_from_mouse_event(&event) { if let Some(button) = button_from_mouse_event(&event) {
let pos = pos_from_mouse_event(runner.canvas(), &event, runner.egui_ctx()); let pos = pos_from_mouse_event(runner.canvas(), &event, runner.egui_ctx());
let modifiers = runner.input.raw.modifiers; let modifiers = runner.input.modifiers;
let egui_event = egui::Event::PointerButton { let egui_event = egui::Event::PointerButton {
pos, pos,
button, button,
@@ -572,7 +572,7 @@ fn install_pointerup(runner_ref: &WebRunner, target: &EventTarget) -> Result<(),
"pointerup", "pointerup",
|event: web_sys::PointerEvent, runner| { |event: web_sys::PointerEvent, runner| {
let modifiers = modifiers_from_mouse_event(&event); let modifiers = modifiers_from_mouse_event(&event);
runner.input.raw.modifiers = modifiers; runner.input.set_modifiers(modifiers);
let pos = pos_from_mouse_event(runner.canvas(), &event, runner.egui_ctx()); let pos = pos_from_mouse_event(runner.canvas(), &event, runner.egui_ctx());
@@ -581,7 +581,7 @@ fn install_pointerup(runner_ref: &WebRunner, target: &EventTarget) -> Result<(),
egui::pos2(event.client_x() as f32, event.client_y() as f32), egui::pos2(event.client_x() as f32, event.client_y() as f32),
) && let Some(button) = button_from_mouse_event(&event) ) && let Some(button) = button_from_mouse_event(&event)
{ {
let modifiers = runner.input.raw.modifiers; let modifiers = runner.input.modifiers;
let egui_event = egui::Event::PointerButton { let egui_event = egui::Event::PointerButton {
pos, pos,
button, button,
@@ -647,7 +647,7 @@ fn is_interested_in_pointer_event(runner: &AppRunner, pos: egui::Pos2) -> bool {
fn install_mousemove(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), JsValue> { fn install_mousemove(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), JsValue> {
runner_ref.add_event_listener(target, "mousemove", |event: web_sys::MouseEvent, runner| { runner_ref.add_event_listener(target, "mousemove", |event: web_sys::MouseEvent, runner| {
let modifiers = modifiers_from_mouse_event(&event); let modifiers = modifiers_from_mouse_event(&event);
runner.input.raw.modifiers = modifiers; runner.input.set_modifiers(modifiers);
let pos = pos_from_mouse_event(runner.canvas(), &event, runner.egui_ctx()); let pos = pos_from_mouse_event(runner.canvas(), &event, runner.egui_ctx());
@@ -705,7 +705,7 @@ fn install_touchstart(runner_ref: &WebRunner, target: &EventTarget) -> Result<()
pos, pos,
button: egui::PointerButton::Primary, button: egui::PointerButton::Primary,
pressed: true, pressed: true,
modifiers: runner.input.raw.modifiers, modifiers: runner.input.modifiers,
}; };
should_stop_propagation = (runner.web_options.should_stop_propagation)(&egui_event); should_stop_propagation = (runner.web_options.should_stop_propagation)(&egui_event);
should_prevent_default = (runner.web_options.should_prevent_default)(&egui_event); should_prevent_default = (runner.web_options.should_prevent_default)(&egui_event);
@@ -770,7 +770,7 @@ fn install_touchend(runner_ref: &WebRunner, target: &EventTarget) -> Result<(),
pos, pos,
button: egui::PointerButton::Primary, button: egui::PointerButton::Primary,
pressed: false, pressed: false,
modifiers: runner.input.raw.modifiers, modifiers: runner.input.modifiers,
}; };
should_stop_propagation &= (runner.web_options.should_stop_propagation)(&egui_event); should_stop_propagation &= (runner.web_options.should_stop_propagation)(&egui_event);
should_prevent_default &= (runner.web_options.should_prevent_default)(&egui_event); should_prevent_default &= (runner.web_options.should_prevent_default)(&egui_event);
@@ -832,7 +832,7 @@ fn install_wheel(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), JsV
let modifiers = modifiers_from_wheel_event(&event); let modifiers = modifiers_from_wheel_event(&event);
let egui_event = if modifiers.ctrl && !runner.input.raw.modifiers.ctrl { let egui_event = if modifiers.ctrl && !runner.input.modifiers.ctrl {
// The browser is saying the ctrl key is down, but it isn't _really_. // The browser is saying the ctrl key is down, but it isn't _really_.
// This happens on pinch-to-zoom on multitouch trackpads // This happens on pinch-to-zoom on multitouch trackpads
// egui will treat ctrl+scroll as zoom, so it all works. // egui will treat ctrl+scroll as zoom, so it all works.

View File

@@ -84,6 +84,13 @@ pub struct State {
viewport_id: ViewportId, viewport_id: ViewportId,
start_time: web_time::Instant, start_time: web_time::Instant,
egui_input: egui::RawInput, egui_input: egui::RawInput,
/// The current modifier state.
///
/// We keep a copy so we can stamp
/// it onto per-event `modifiers` fields and emit [`egui::Event::ModifiersChanged`].
modifiers: egui::Modifiers,
pointer_pos_in_points: Option<egui::Pos2>, pointer_pos_in_points: Option<egui::Pos2>,
any_pointer_button_down: bool, any_pointer_button_down: bool,
current_cursor_icon: Option<egui::CursorIcon>, current_cursor_icon: Option<egui::CursorIcon>,
@@ -146,6 +153,7 @@ impl State {
.unwrap_or_else(web_time::Instant::now), .unwrap_or_else(web_time::Instant::now),
egui_ctx, egui_ctx,
egui_input, egui_input,
modifiers: egui::Modifiers::default(),
pointer_pos_in_points: None, pointer_pos_in_points: None,
any_pointer_button_down: false, any_pointer_button_down: false,
current_cursor_icon: None, current_cursor_icon: None,
@@ -422,6 +430,10 @@ impl State {
}; };
self.egui_input.focused = focused; self.egui_input.focused = focused;
if !focused {
// Avoid sticky modifiers when focus is lost (egui clears its own copy too).
self.modifiers = egui::Modifiers::default();
}
self.egui_input self.egui_input
.events .events
.push(egui::Event::WindowFocused(focused)); .push(egui::Event::WindowFocused(focused));
@@ -473,16 +485,20 @@ impl State {
let shift = state.shift_key(); let shift = state.shift_key();
let super_ = state.super_key(); let super_ = state.super_key();
self.egui_input.modifiers.alt = alt; self.modifiers.alt = alt;
self.egui_input.modifiers.ctrl = ctrl; self.modifiers.ctrl = ctrl;
self.egui_input.modifiers.shift = shift; self.modifiers.shift = shift;
self.egui_input.modifiers.mac_cmd = cfg!(target_os = "macos") && super_; self.modifiers.mac_cmd = cfg!(target_os = "macos") && super_;
self.egui_input.modifiers.command = if cfg!(target_os = "macos") { self.modifiers.command = if cfg!(target_os = "macos") {
super_ super_
} else { } else {
ctrl ctrl
}; };
self.egui_input
.events
.push(egui::Event::ModifiersChanged(self.modifiers));
EventResponse { EventResponse {
repaint: true, repaint: true,
consumed: false, consumed: false,
@@ -541,7 +557,7 @@ impl State {
unit: egui::MouseWheelUnit::Point, unit: egui::MouseWheelUnit::Point,
delta: Vec2::new(delta.x, delta.y) / pixels_per_point, delta: Vec2::new(delta.x, delta.y) / pixels_per_point,
phase: to_egui_touch_phase(*phase), phase: to_egui_touch_phase(*phase),
modifiers: self.egui_input.modifiers, modifiers: self.modifiers,
}); });
EventResponse { EventResponse {
repaint: true, repaint: true,
@@ -790,7 +806,7 @@ impl State {
pos, pos,
button, button,
pressed, pressed,
modifiers: self.egui_input.modifiers, modifiers: self.modifiers,
}); });
if self.simulate_touch_screen { if self.simulate_touch_screen {
@@ -937,7 +953,7 @@ impl State {
), ),
}; };
let phase = to_egui_touch_phase(phase); let phase = to_egui_touch_phase(phase);
let modifiers = self.egui_input.modifiers; let modifiers = self.modifiers;
self.egui_input.events.push(egui::Event::MouseWheel { self.egui_input.events.push(egui::Event::MouseWheel {
unit, unit,
delta, delta,
@@ -998,13 +1014,13 @@ impl State {
// See also: https://github.com/emilk/egui/issues/3653 // See also: https://github.com/emilk/egui/issues/3653
if let Some(active_key) = logical_key.or(physical_key) { if let Some(active_key) = logical_key.or(physical_key) {
if pressed { if pressed {
if is_cut_command(self.egui_input.modifiers, active_key) { if is_cut_command(self.modifiers, active_key) {
self.egui_input.events.push(egui::Event::Cut); self.egui_input.events.push(egui::Event::Cut);
return; return;
} else if is_copy_command(self.egui_input.modifiers, active_key) { } else if is_copy_command(self.modifiers, active_key) {
self.egui_input.events.push(egui::Event::Copy); self.egui_input.events.push(egui::Event::Copy);
return; return;
} else if is_paste_command(self.egui_input.modifiers, active_key) { } else if is_paste_command(self.modifiers, active_key) {
if let Some(contents) = self.clipboard.get() { if let Some(contents) = self.clipboard.get() {
let contents = contents.replace("\r\n", "\n"); let contents = contents.replace("\r\n", "\n");
if !contents.is_empty() { if !contents.is_empty() {
@@ -1020,7 +1036,7 @@ impl State {
physical_key, physical_key,
pressed, pressed,
repeat: false, // egui will fill this in for us! repeat: false, // egui will fill this in for us!
modifiers: self.egui_input.modifiers, modifiers: self.modifiers,
}); });
} }
@@ -1036,9 +1052,8 @@ impl State {
// We need to ignore these characters that are side-effects of commands. // We need to ignore these characters that are side-effects of commands.
// Also make sure the key is pressed (not released). On Linux, text might // Also make sure the key is pressed (not released). On Linux, text might
// contain some data even when the key is released. // contain some data even when the key is released.
let is_cmd = self.egui_input.modifiers.ctrl let is_cmd =
|| self.egui_input.modifiers.command self.modifiers.ctrl || self.modifiers.command || self.modifiers.mac_cmd;
|| self.egui_input.modifiers.mac_cmd;
if pressed && !is_cmd { if pressed && !is_cmd {
self.egui_input self.egui_input
.events .events

View File

@@ -69,6 +69,9 @@ pub enum Event {
modifiers: Modifiers, modifiers: Modifiers,
}, },
/// The set of held modifier keys changed.
ModifiersChanged(Modifiers),
/// The mouse or touch moved to a new place. /// The mouse or touch moved to a new place.
PointerMoved(Pos2), PointerMoved(Pos2),

View File

@@ -1,6 +1,6 @@
use crate::{OrderedViewportIdMap, Theme, ViewportId, ViewportIdMap, emath::Rect}; use crate::{OrderedViewportIdMap, Theme, ViewportId, ViewportIdMap, emath::Rect};
use super::{DroppedFile, Event, HoveredFile, Modifiers, SafeAreaInsets, ViewportInfo}; use super::{DroppedFile, Event, HoveredFile, SafeAreaInsets, ViewportInfo};
/// What the integrations provides to egui at the start of each frame. /// What the integrations provides to egui at the start of each frame.
/// ///
@@ -53,9 +53,6 @@ pub struct RawInput {
/// Can safely be left at its default value. /// Can safely be left at its default value.
pub predicted_dt: f32, pub predicted_dt: f32,
/// Which modifier keys are down at the start of the frame?
pub modifiers: Modifiers,
/// In-order events received this frame. /// In-order events received this frame.
/// ///
/// There is currently no way to know if egui handles a particular event, /// There is currently no way to know if egui handles a particular event,
@@ -92,7 +89,6 @@ impl Default for RawInput {
max_texture_side: None, max_texture_side: None,
time: None, time: None,
predicted_dt: 1.0 / 60.0, predicted_dt: 1.0 / 60.0,
modifiers: Modifiers::default(),
events: vec![], events: vec![],
hovered_files: Default::default(), hovered_files: Default::default(),
dropped_files: Default::default(), dropped_files: Default::default(),
@@ -127,7 +123,6 @@ impl RawInput {
max_texture_side: self.max_texture_side.take(), max_texture_side: self.max_texture_side.take(),
time: self.time, time: self.time,
predicted_dt: self.predicted_dt, predicted_dt: self.predicted_dt,
modifiers: self.modifiers,
events: std::mem::take(&mut self.events), events: std::mem::take(&mut self.events),
hovered_files: self.hovered_files.clone(), hovered_files: self.hovered_files.clone(),
dropped_files: std::mem::take(&mut self.dropped_files), dropped_files: std::mem::take(&mut self.dropped_files),
@@ -145,7 +140,6 @@ impl RawInput {
max_texture_side, max_texture_side,
time, time,
predicted_dt, predicted_dt,
modifiers,
mut events, mut events,
mut hovered_files, mut hovered_files,
mut dropped_files, mut dropped_files,
@@ -160,7 +154,6 @@ impl RawInput {
self.max_texture_side = max_texture_side.or(self.max_texture_side); self.max_texture_side = max_texture_side.or(self.max_texture_side);
self.time = time; // use latest time self.time = time; // use latest time
self.predicted_dt = predicted_dt; // use latest dt self.predicted_dt = predicted_dt; // use latest dt
self.modifiers = modifiers; // use latest
self.events.append(&mut events); self.events.append(&mut events);
self.hovered_files.append(&mut hovered_files); self.hovered_files.append(&mut hovered_files);
self.dropped_files.append(&mut dropped_files); self.dropped_files.append(&mut dropped_files);
@@ -179,7 +172,6 @@ impl RawInput {
max_texture_side, max_texture_side,
time, time,
predicted_dt, predicted_dt,
modifiers,
events, events,
hovered_files, hovered_files,
dropped_files, dropped_files,
@@ -210,7 +202,6 @@ impl RawInput {
ui.label("time: None"); ui.label("time: None");
} }
ui.label(format!("predicted_dt: {:.1} ms", 1e3 * predicted_dt)); ui.label(format!("predicted_dt: {:.1} ms", 1e3 * predicted_dt));
ui.label(format!("modifiers: {modifiers:#?}"));
ui.label(format!("hovered_files: {}", hovered_files.len())); ui.label(format!("hovered_files: {}", hovered_files.len()));
ui.label(format!("dropped_files: {}", dropped_files.len())); ui.label(format!("dropped_files: {}", dropped_files.len()));
ui.label(format!("focused: {focused}")); ui.label(format!("focused: {focused}"));

View File

@@ -393,6 +393,7 @@ impl InputState {
let pointer = self.pointer.begin_pass(time, &new, options); let pointer = self.pointer.begin_pass(time, &new, options);
let mut keys_down = self.keys_down; let mut keys_down = self.keys_down;
let mut modifiers = self.modifiers;
let mut zoom_factor_delta = 1.0; // TODO(emilk): smoothing for zoom factor let mut zoom_factor_delta = 1.0; // TODO(emilk): smoothing for zoom factor
let mut rotation_radians = 0.0; let mut rotation_radians = 0.0;
@@ -429,6 +430,9 @@ impl InputState {
*modifiers, *modifiers,
); );
} }
Event::ModifiersChanged(new_modifiers) => {
modifiers = *new_modifiers;
}
Event::Zoom(factor) => { Event::Zoom(factor) => {
zoom_factor_delta *= *factor; zoom_factor_delta *= *factor;
} }
@@ -442,6 +446,7 @@ impl InputState {
// So we take the safe route and just clear all the keys and modifiers when // So we take the safe route and just clear all the keys and modifiers when
// the app loses focus. // the app loses focus.
keys_down.clear(); keys_down.clear();
modifiers = Modifiers::default();
} }
_ => {} _ => {}
} }
@@ -482,7 +487,7 @@ impl InputState {
predicted_dt: new.predicted_dt, predicted_dt: new.predicted_dt,
stable_dt, stable_dt,
focused: new.focused, focused: new.focused,
modifiers: new.modifiers, modifiers,
keys_down, keys_down,
events: new.events.clone(), // TODO(emilk): remove clone() and use raw.events events: new.events.clone(), // TODO(emilk): remove clone() and use raw.events
raw: new, raw: new,

View File

@@ -251,14 +251,7 @@ impl<'a, State> Harness<'a, State> {
self._step(false); self._step(false);
} }
for event in events { for event in events {
match event {
EventType::Event(event) => {
self.input.events.push(event); self.input.events.push(event);
}
EventType::Modifiers(modifiers) => {
self.input.modifiers = modifiers;
}
}
self._step(false); self._step(false);
} }
} }
@@ -471,7 +464,7 @@ impl<'a, State> Harness<'a, State> {
/// Queue an event to be processed in the next frame. /// Queue an event to be processed in the next frame.
pub fn event(&self, event: egui::Event) { pub fn event(&self, event: egui::Event) {
self.queued_events.lock().push(EventType::Event(event)); self.queued_events.lock().push(event);
} }
/// Queue an event with modifiers. /// Queue an event with modifiers.
@@ -479,15 +472,15 @@ impl<'a, State> Harness<'a, State> {
/// Queues the modifiers to be pressed, then the event, then the modifiers to be released. /// Queues the modifiers to be pressed, then the event, then the modifiers to be released.
pub fn event_modifiers(&self, event: egui::Event, modifiers: Modifiers) { pub fn event_modifiers(&self, event: egui::Event, modifiers: Modifiers) {
let mut queue = self.queued_events.lock(); let mut queue = self.queued_events.lock();
queue.push(EventType::Modifiers(modifiers)); queue.push(egui::Event::ModifiersChanged(modifiers));
queue.push(EventType::Event(event)); queue.push(event);
queue.push(EventType::Modifiers(Modifiers::default())); queue.push(egui::Event::ModifiersChanged(Modifiers::default()));
} }
fn modifiers(&self, modifiers: Modifiers) { fn modifiers(&self, modifiers: Modifiers) {
self.queued_events self.queued_events
.lock() .lock()
.push(EventType::Modifiers(modifiers)); .push(egui::Event::ModifiersChanged(modifiers));
} }
pub fn key_down(&self, key: egui::Key) { pub fn key_down(&self, key: egui::Key) {
@@ -735,10 +728,11 @@ impl<'a, State> Harness<'a, State> {
/// The root node of the test harness. /// The root node of the test harness.
pub fn root(&self) -> Node<'_> { pub fn root(&self) -> Node<'_> {
Node { Node::new(
accesskit_node: self.kittest.root(), self.kittest.root(),
queue: &self.queued_events, &self.queued_events,
} self.ctx.pixels_per_point(),
)
} }
/// Spawn a real native eframe window running this harness's app, reusing its [`egui::Context`]. /// Spawn a real native eframe window running this harness's app, reusing its [`egui::Context`].

View File

@@ -4,17 +4,13 @@ use egui::{Modifiers, PointerButton, Pos2, accesskit};
use kittest::{AccessKitNode, NodeT, debug_fmt_node}; use kittest::{AccessKitNode, NodeT, debug_fmt_node};
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
pub(crate) enum EventType { pub type EventQueue = Mutex<Vec<egui::Event>>;
Event(egui::Event),
Modifiers(Modifiers),
}
pub(crate) type EventQueue = Mutex<Vec<EventType>>;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct Node<'tree> { pub struct Node<'tree> {
pub(crate) accesskit_node: AccessKitNode<'tree>, pub(crate) accesskit_node: AccessKitNode<'tree>,
pub(crate) queue: &'tree EventQueue, pub(crate) queue: &'tree EventQueue,
pub(crate) pixels_per_point: f32,
} }
impl Debug for Node<'_> { impl Debug for Node<'_> {
@@ -29,20 +25,32 @@ impl<'tree> NodeT<'tree> for Node<'tree> {
} }
fn new_related(&self, child_node: AccessKitNode<'tree>) -> Self { fn new_related(&self, child_node: AccessKitNode<'tree>) -> Self {
Self { Self::new(child_node, self.queue, self.pixels_per_point)
queue: self.queue, }
accesskit_node: child_node, }
}
impl<'tree> Node<'tree> {
/// Construct a new accesskit node
pub fn new(
accesskit_node: AccessKitNode<'tree>,
queue: &'tree EventQueue,
pixels_per_point: f32,
) -> Self {
Self {
accesskit_node,
queue,
pixels_per_point,
} }
} }
impl Node<'_> {
fn event(&self, event: egui::Event) { fn event(&self, event: egui::Event) {
self.queue.lock().push(EventType::Event(event)); self.queue.lock().push(event);
} }
fn modifiers(&self, modifiers: Modifiers) { fn modifiers(&self, modifiers: Modifiers) {
self.queue.lock().push(EventType::Modifiers(modifiers)); self.queue
.lock()
.push(egui::Event::ModifiersChanged(modifiers));
} }
pub fn hover(&self) { pub fn hover(&self) {
@@ -104,14 +112,17 @@ impl Node<'_> {
)); ));
} }
/// This returns the rect in logical ui coordinates while the underlying [`accesskit::Node`] has it
/// in physical screen coordinates.
pub fn rect(&self) -> egui::Rect { pub fn rect(&self) -> egui::Rect {
let rect = self let rect = self
.accesskit_node .accesskit_node
.bounding_box() .bounding_box()
.expect("Every egui node should have a rect"); .expect("Every egui node should have a rect");
let ppp = self.pixels_per_point;
egui::Rect { egui::Rect {
min: Pos2::new(rect.x0 as f32, rect.y0 as f32), min: Pos2::new(rect.x0 as f32 / ppp, rect.y0 as f32 / ppp),
max: Pos2::new(rect.x1 as f32, rect.y1 as f32), max: Pos2::new(rect.x1 as f32 / ppp, rect.y1 as f32 / ppp),
} }
} }