🧞 `egui_winit::State::handle_event.consumed` is `false` on touch input where `true` would be expected
Context
I am using egui_winit to pass winit events to egui. The egui ui is drawn on top of another texture using a custom (non-public) render backend. The events, when not handled by egui (i.e. when anywhere else is clicked/dragged), are passed along to another system. This entire system is running on an Android device, so all pointer input is done through Touch.
Description
A winit::WindowEvent::Touch has four possible phases: Started, Moved, Ended, and Cancelled. The issue I am having is in two of them.
TouchPhase::Started
The consumed value is based on Context::wants_pointer_input, however since
during this event, there is no known mouse position, as the event isn't passed to egui::Context::begin_frame yet. This results in the wants_pointer_input to always be false, thus this event is never consumed.
TouchPhase::Moved
In the previous TouchPhase::Started event, the actual mouse position is set. However, egui_winit uses the Context::is_using_pointer value for the consumed state. The value emitted by this function becomes true when there is either a known clicked or dragged Widget Id. However, these values aren't set immediately, instead are set after a few frames delay, causing the first few events to be unconsumed.
TouchPhase::Ended | TouchPhase::Cancelled
These two phases currently use wants_pointer_input, however I feel like the more semantically correct choice would be to use is_using_pointer instead, as it's the last event in the chain.
Current workaround
To ensure the event doesn't accidentally fall through, I am currently using basically the following workaround:
let consumed = state.on_event(&ctx, event).consumed;
let actually_consumed = match event {
WindowEvent::Touch(Touch { phase, .. }) => match phase {
TouchPhase::Started => true,
TouchPhase::Moved => consumed || ctx.input(|i| i.pointer.interact_pos().is_none()),
TouchPhase::Ended | TouchPhase::Cancelled => false,
},
_ => consumed,
};
I ran into the same problem but on mouse input.
i am using bevy, so fetching input using Input<MouseButton>
it goes something like this.
wants_pointer_input -> true
is_pointer_over_area -> true
Input<MouseButton>::just_pressed(MouseButton::Left) -> false
Input<MouseButton>::pressed(MouseButton::Left) -> false
wants_pointer_input -> false (should have been true)
is_pointer_over_area -> true
Input<MouseButton>::just_pressed(MouseButton::Left) -> true
Input<MouseButton>::pressed(MouseButton::Left) -> true
wants_pointer_input -> true
is_pointer_over_area -> true
Input<MouseButton>::just_pressed(MouseButton::Left) -> false
Input<MouseButton>::pressed(MouseButton::Left) -> true