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