From ee5a85b14e41bf0d034b63ebd32db643e9eae6ee Mon Sep 17 00:00:00 2001 From: Kaj Schittecat Date: Sun, 18 Oct 2026 13:01:28 +0200 Subject: [PATCH] web: every tap reaches the UI (hold a press across LVGL input reads) The page hands one press/release edge to the UI per animation frame, but LVGL reads the pointer every 30 ms. A press that lasted a single 16 ms frame (a trackpad tap-to-click, or a synthetic click) was often never seen, so taps landed at random. A press is now held for at least 70 ms before its release is delivered. Co-Authored-By: Claude Opus 5.5 --- web/platform/web_main.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/web/platform/web_main.cpp b/web/platform/web_main.cpp index 0c78dc83..a1309e47 100644 --- a/web/platform/web_main.cpp +++ b/web/platform/web_main.cpp @@ -44,12 +44,19 @@ struct PtrEv { bool down; int16_t x, y; }; PtrEv s_q[64]; unsigned s_qh = 0, s_qt = 0; bool s_down = false; +uint32_t s_down_ms = 0; +// A press must outlive a couple of LVGL input reads (LV_INDEV_DEF_READ_PERIOD) or the UI +// never sees it: a trackpad tap-to-click sends press and release in the same frame, and +// one 16 ms step was shorter than the 30 ms read period, so taps landed at random. +constexpr uint32_t kMinPressMs = 70; void drainPointer() { while (s_qt != s_qh) { const PtrEv e = s_q[s_qt]; if (e.down != s_down) { // an edge: deliver it and stop until the next step + if (!e.down && (uint32_t)(millis() - s_down_ms) < kMinPressMs) return; // hold the press s_down = e.down; + if (e.down) s_down_ms = millis(); webPointer(e.down, e.x, e.y); s_qt = (s_qt + 1) & 63u; return;