emilk / emilk/egui

🧞 `egui_winit::State::handle_event.consumed` is `false` on touch input where `true` would be expected

Open
#3,210 1 comment 2 reactions 0 assignees View on GitHub
bug
Dominant language
Rust
Stars
30.6k
Forks
2.1k
Avg merge
1d 9h
Merged PRs (30d)
72

Description

# 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:
```rust
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,
};
```

Contributor guide

Open the contributing guide

Research direction

Start with egui_winit::State::handle_event and State::on_event, then trace how TouchPhase::Started, Moved, Ended, and Cancelled determine consumed from Context::wants_pointer_input and Context::is_using_pointer. Compare those paths with the reported workaround and establish consistent consumed behavior for all touch phases, with regression coverage if the existing test structure supports it.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, rust
Domain
frontend, mobile-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.