On X11, filter out tiny device mouse events

Usually, if mouse events are equal to (0, 0) we filter them out.
However, if the event is very close to zero it will still be given to
the user. In some cases this can be caused by bad float math on the X11
server side.

Fix it by filtering absolute values smaller than floating point epsilon.

Signed-off-by: John Nunley <dev@notgull.net>
Closes: #3500
This commit is contained in:
John Nunley 2024-03-01 01:11:28 -08:00 committed by GitHub
parent f0b4889227
commit 3d4c53459a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 64 additions and 9 deletions

View file

@ -1518,8 +1518,8 @@ impl EventProcessor {
let mask =
unsafe { slice::from_raw_parts(xev.valuators.mask, xev.valuators.mask_len as usize) };
let mut value = xev.raw_values;
let mut mouse_delta = (0.0, 0.0);
let mut scroll_delta = (0.0, 0.0);
let mut mouse_delta = util::Delta::default();
let mut scroll_delta = util::Delta::default();
for i in 0..xev.valuators.mask_len * 8 {
if !xinput2::XIMaskIsSet(mask, i) {
continue;
@ -1529,10 +1529,10 @@ impl EventProcessor {
// We assume that every XInput2 device with analog axes is a pointing device emitting
// relative coordinates.
match i {
0 => mouse_delta.0 = x,
1 => mouse_delta.1 = x,
2 => scroll_delta.0 = x as f32,
3 => scroll_delta.1 = x as f32,
0 => mouse_delta.set_x(x),
1 => mouse_delta.set_y(x),
2 => scroll_delta.set_x(x as f32),
3 => scroll_delta.set_y(x as f32),
_ => {}
}
@ -1548,7 +1548,7 @@ impl EventProcessor {
value = unsafe { value.offset(1) };
}
if mouse_delta != (0.0, 0.0) {
if let Some(mouse_delta) = mouse_delta.consume() {
let event = Event::DeviceEvent {
device_id: did,
event: DeviceEvent::MouseMotion { delta: mouse_delta },
@ -1556,7 +1556,7 @@ impl EventProcessor {
callback(&self.target, event);
}
if scroll_delta != (0.0, 0.0) {
if let Some(scroll_delta) = scroll_delta.consume() {
let event = Event::DeviceEvent {
device_id: did,
event: DeviceEvent::MouseWheel {

View file

@ -15,13 +15,15 @@ mod icon;
mod input;
pub mod keys;
pub(crate) mod memory;
mod mouse;
mod randr;
mod window_property;
mod wm;
mod xmodmap;
pub use self::{
cursor::*, geometry::*, hint::*, input::*, window_property::*, wm::*, xmodmap::ModifierKeymap,
cursor::*, geometry::*, hint::*, input::*, mouse::*, window_property::*, wm::*,
xmodmap::ModifierKeymap,
};
use super::{atoms::*, ffi, VoidCookie, X11Error, XConnection, XError};

View file

@ -0,0 +1,52 @@
//! Utilities for handling mouse events.
/// Recorded mouse delta designed to filter out noise.
pub struct Delta<T> {
x: T,
y: T,
}
impl<T: Default> Default for Delta<T> {
fn default() -> Self {
Self {
x: Default::default(),
y: Default::default(),
}
}
}
impl<T: Default> Delta<T> {
pub(crate) fn set_x(&mut self, x: T) {
self.x = x;
}
pub(crate) fn set_y(&mut self, y: T) {
self.y = y;
}
}
macro_rules! consume {
($this:expr, $ty:ty) => {{
let this = $this;
let (x, y) = match (this.x.abs() < <$ty>::EPSILON, this.y.abs() < <$ty>::EPSILON) {
(true, true) => return None,
(true, false) => (this.x, 0.0),
(false, true) => (0.0, this.y),
(false, false) => (this.x, this.y),
};
Some((x, y))
}};
}
impl Delta<f32> {
pub(crate) fn consume(self) -> Option<(f32, f32)> {
consume!(self, f32)
}
}
impl Delta<f64> {
pub(crate) fn consume(self) -> Option<(f64, f64)> {
consume!(self, f64)
}
}