From d2cdd2cfd1dc6f30d968fb559904534d1c20a3e7 Mon Sep 17 00:00:00 2001 From: HMH Date: Fri, 18 Oct 2024 12:33:40 +0200 Subject: [PATCH] Workaround for hovering pens and touch rejection Some browsers do not send a pointer event to indicate that a hovering pen has left the hovering range. This results in the pen still being active, even if there are touch events and the pen is lifted. In this case we manually remove the pen to prevent touch rejection. --- src/input/uinput_device.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/input/uinput_device.rs b/src/input/uinput_device.rs index ac412d2..80e8023 100644 --- a/src/input/uinput_device.rs +++ b/src/input/uinput_device.rs @@ -1,6 +1,7 @@ use std::cmp::Ordering; use std::ffi::CString; use std::os::raw::{c_char, c_int}; +use std::time::{Duration, Instant}; use crate::capturable::x11::X11Context; use crate::capturable::{Capturable, Geometry}; @@ -35,6 +36,7 @@ pub struct UInputDevice { touches: [Option; 5], tool_pen_active: bool, pen_touching: bool, + last_pen_event: Instant, capturable: Box, geometry: Rect, name_mouse_device: String, @@ -99,6 +101,7 @@ impl UInputDevice { touches: Default::default(), tool_pen_active: false, pen_touching: false, + last_pen_event: Instant::now(), capturable, geometry: Rect::default(), name_mouse_device: name_mouse, @@ -304,6 +307,28 @@ impl InputDevice for UInputDevice { } self.num_touch_mapping_tries += 1; } + + // This is a workaround for browsers that send events when the pen is hovering but + // do not send an event when the pen leaves the hovering range. If the pen is left + // in this state touch rejection may stay active and touch won't work. + // Therefore, we manually remove the pen after a short delay. + if self.tool_pen_active + && !self.pen_touching + && (Instant::now() - self.last_pen_event) > Duration::from_millis(50) + { + self.tool_pen_active = false; + self.send(self.stylus_fd, ET_KEY, EC_KEY_TOUCH, 0); + self.send(self.stylus_fd, ET_KEY, EC_KEY_TOOL_PEN, 0); + self.send(self.stylus_fd, ET_KEY, EC_KEY_TOOL_RUBBER, 0); + self.send(self.stylus_fd, ET_ABSOLUTE, EC_ABSOLUTE_PRESSURE, 0); + self.send( + self.stylus_fd, + ET_MSC, + EC_MSC_TIMESTAMP, + (event.timestamp % (i32::MAX as u64 + 1)) as i32, + ); + self.send(self.stylus_fd, ET_SYNC, EC_SYNC_REPORT, 0); + } match event.event_type { PointerEventType::DOWN | PointerEventType::MOVE @@ -446,6 +471,7 @@ impl InputDevice for UInputDevice { }; } PointerType::Pen => { + self.last_pen_event = Instant::now(); if self.num_stylus_mapping_tries < MAX_SCREEN_MAPPING_TRIES { if let Some(x11ctx) = &mut self.x11ctx { // Mapping input does not work on XWayland as xinput list does not expose