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:
parent
f0b4889227
commit
3d4c53459a
4 changed files with 64 additions and 9 deletions
|
|
@ -11,6 +11,7 @@ Unreleased` header.
|
||||||
|
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- On X11, filter close to zero values in mouse device events
|
||||||
- Move `dpi` types to its own crate, and re-export it from the root crate.
|
- Move `dpi` types to its own crate, and re-export it from the root crate.
|
||||||
- Implement `Sync` for `EventLoopProxy<T: Send>`.
|
- Implement `Sync` for `EventLoopProxy<T: Send>`.
|
||||||
- **Breaking:** Move `Window::new` to `ActiveEventLoop::create_window` and `EventLoop::create_window` (with the latter being deprecated).
|
- **Breaking:** Move `Window::new` to `ActiveEventLoop::create_window` and `EventLoop::create_window` (with the latter being deprecated).
|
||||||
|
|
|
||||||
|
|
@ -1518,8 +1518,8 @@ impl EventProcessor {
|
||||||
let mask =
|
let mask =
|
||||||
unsafe { slice::from_raw_parts(xev.valuators.mask, xev.valuators.mask_len as usize) };
|
unsafe { slice::from_raw_parts(xev.valuators.mask, xev.valuators.mask_len as usize) };
|
||||||
let mut value = xev.raw_values;
|
let mut value = xev.raw_values;
|
||||||
let mut mouse_delta = (0.0, 0.0);
|
let mut mouse_delta = util::Delta::default();
|
||||||
let mut scroll_delta = (0.0, 0.0);
|
let mut scroll_delta = util::Delta::default();
|
||||||
for i in 0..xev.valuators.mask_len * 8 {
|
for i in 0..xev.valuators.mask_len * 8 {
|
||||||
if !xinput2::XIMaskIsSet(mask, i) {
|
if !xinput2::XIMaskIsSet(mask, i) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -1529,10 +1529,10 @@ impl EventProcessor {
|
||||||
// We assume that every XInput2 device with analog axes is a pointing device emitting
|
// We assume that every XInput2 device with analog axes is a pointing device emitting
|
||||||
// relative coordinates.
|
// relative coordinates.
|
||||||
match i {
|
match i {
|
||||||
0 => mouse_delta.0 = x,
|
0 => mouse_delta.set_x(x),
|
||||||
1 => mouse_delta.1 = x,
|
1 => mouse_delta.set_y(x),
|
||||||
2 => scroll_delta.0 = x as f32,
|
2 => scroll_delta.set_x(x as f32),
|
||||||
3 => scroll_delta.1 = x as f32,
|
3 => scroll_delta.set_y(x as f32),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1548,7 +1548,7 @@ impl EventProcessor {
|
||||||
value = unsafe { value.offset(1) };
|
value = unsafe { value.offset(1) };
|
||||||
}
|
}
|
||||||
|
|
||||||
if mouse_delta != (0.0, 0.0) {
|
if let Some(mouse_delta) = mouse_delta.consume() {
|
||||||
let event = Event::DeviceEvent {
|
let event = Event::DeviceEvent {
|
||||||
device_id: did,
|
device_id: did,
|
||||||
event: DeviceEvent::MouseMotion { delta: mouse_delta },
|
event: DeviceEvent::MouseMotion { delta: mouse_delta },
|
||||||
|
|
@ -1556,7 +1556,7 @@ impl EventProcessor {
|
||||||
callback(&self.target, event);
|
callback(&self.target, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
if scroll_delta != (0.0, 0.0) {
|
if let Some(scroll_delta) = scroll_delta.consume() {
|
||||||
let event = Event::DeviceEvent {
|
let event = Event::DeviceEvent {
|
||||||
device_id: did,
|
device_id: did,
|
||||||
event: DeviceEvent::MouseWheel {
|
event: DeviceEvent::MouseWheel {
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,15 @@ mod icon;
|
||||||
mod input;
|
mod input;
|
||||||
pub mod keys;
|
pub mod keys;
|
||||||
pub(crate) mod memory;
|
pub(crate) mod memory;
|
||||||
|
mod mouse;
|
||||||
mod randr;
|
mod randr;
|
||||||
mod window_property;
|
mod window_property;
|
||||||
mod wm;
|
mod wm;
|
||||||
mod xmodmap;
|
mod xmodmap;
|
||||||
|
|
||||||
pub use self::{
|
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};
|
use super::{atoms::*, ffi, VoidCookie, X11Error, XConnection, XError};
|
||||||
|
|
|
||||||
52
src/platform_impl/linux/x11/util/mouse.rs
Normal file
52
src/platform_impl/linux/x11/util/mouse.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue