Open iceiix opened 5 years ago
Thanks for reporting this! For future reference, this issue relates to code in winit, which glutin depends on.
does/could Glutin have something similar?
We currently don't, but if the aforementioned fix in SDL works fine, then it shouldn't be hard to make a similar fix here. Relevant code: https://github.com/spurious/SDL-mirror/blob/d3d9a9ddd00f710835a3c133d6c196b7c4bd1792/src/events/SDL_mouse.c#L302
It would be awesome if you'd like to try making a PR for this to winit, since it could take a bit of time before I'd be able to get to it (and I wouldn't be able to repro/test this myself).
Closing in favor of upstream. https://github.com/rust-windowing/winit/issues/876
What is necessary to reproduce this? Running cargo run --example window
on latest master with X11 and moving the cursor around results in lots of these, which look quite relative to me:
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: Motion { axis: 0, value: -6.0 } }
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: Motion { axis: 1, value: 0.0 } }
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: MouseMotion { delta: (-6.0, 0.0) } }
WindowEvent { window_id: WindowId(X(WindowId(31457281))), event: CursorMoved { device_id: DeviceId(X(DeviceId(2))), position: LogicalPosition { x: 218.02351262019232, y: 221.65562086838943 }, modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: false } } }
WindowEvent { window_id: WindowId(X(WindowId(31457281))), event: AxisMotion { device_id: DeviceId(X(DeviceId(2))), axis: 0, value: 661.1921524943318 } }
EventsCleared
NewEvents(WaitCancelled { start: Instant { tv_sec: 2554, tv_nsec: 982201931 }, requested_resume: None })
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: Motion { axis: 0, value: -12.0 } }
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: Motion { axis: 1, value: 1.0 } }
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: MouseMotion { delta: (-12.0, 1.0) } }
WindowEvent { window_id: WindowId(X(WindowId(31457281))), event: CursorMoved { device_id: DeviceId(X(DeviceId(2))), position: LogicalPosition { x: 198.4947228064904, y: 223.28303410456732 }, modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: false } } }
WindowEvent { window_id: WindowId(X(WindowId(31457281))), event: AxisMotion { device_id: DeviceId(X(DeviceId(2))), axis: 0, value: 640.0359673062339 } }
WindowEvent { window_id: WindowId(X(WindowId(31457281))), event: AxisMotion { device_id: DeviceId(X(DeviceId(2))), axis: 1, value: 332.8899452071637 } }
EventsCleared
NewEvents(WaitCancelled { start: Instant { tv_sec: 2554, tv_nsec: 990172372 }, requested_resume: None })
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: Motion { axis: 0, value: -8.0 } }
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: Motion { axis: 1, value: 1.0 } }
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: MouseMotion { delta: (-8.0, 1.0) } }
WindowEvent { window_id: WindowId(X(WindowId(31457281))), event: CursorMoved { device_id: DeviceId(X(DeviceId(2))), position: LogicalPosition { x: 184.40799654447116, y: 225.04386080228366 }, modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: false } } }
WindowEvent { window_id: WindowId(X(WindowId(31457281))), event: AxisMotion { device_id: DeviceId(X(DeviceId(2))), axis: 0, value: 624.775324880844 } }
WindowEvent { window_id: WindowId(X(WindowId(31457281))), event: AxisMotion { device_id: DeviceId(X(DeviceId(2))), axis: 1, value: 334.79752551042475 } }
EventsCleared
(Well, at least the values called delta
look like deltas)
@psychon You need to run this in a VM, I believe. I'm not entirely sure what to make of it if you already are and it's working 🤷♀
For what it's worth I was able to recreate this issue as of b6e8dd0d8a51fa7f3324f84d3529b2e2573a529e by using cargo run --example window
with the following setup:
I would be glad to try tackling this issue but I'm not really sure where to start.
Edit: After a bit more investigating the culprit seems to be VirtualBox's "mouse integration" device. Allowing the VM to capture the cursor yields correct behavior. Below is the output of xinput list --long
on the mouse integration device.
VirtualBox mouse integration id=9 [slave pointer (2)]
Reporting 7 classes:
Class originated from: 9. Type: XIButtonClass
Buttons supported: 7
Button labels: "Button Left" "Button Middle" "Button Right" "Button Wheel Up" "Button Wheel Down" "Button Horiz Wheel Left" "Button Horiz Wheel Right"
Button state:
Class originated from: 9. Type: XIValuatorClass
Detail for Valuator 0:
Label: Abs X
Range: 0.000000 - 65535.000000
Resolution: 0 units/m
Mode: absolute
Current value: 22454.657364
Class originated from: 9. Type: XIValuatorClass
Detail for Valuator 1:
Label: Abs Y
Range: 0.000000 - 65535.000000
Resolution: 0 units/m
Mode: absolute
Current value: 17652.730637
Compare that to the device used when pointer capture is enabled:
ImExPS/2 Generic Explorer Mouse id=12 [slave pointer (2)]
Reporting 7 classes:
Class originated from: 12. Type: XIButtonClass
Buttons supported: 9
Button labels: "Button Left" "Button Middle" "Button Right" "Button Wheel Up" "Button Wheel Down" "Button Horiz Wheel Left" "Button Horiz Wheel Right" "Button Side" "Button Extra"
Button state:
Class originated from: 12. Type: XIValuatorClass
Detail for Valuator 0:
Label: Rel X
Range: -1.000000 - -1.000000
Resolution: 0 units/m
Mode: relative
Class originated from: 12. Type: XIValuatorClass
Detail for Valuator 1:
Label: Rel Y
Range: -1.000000 - -1.000000
Resolution: 0 units/m
Mode: relative
So it looks like some devices only produce absolute coordinates. Any ideas on how best to handle this?
@chelmich Well, there are a couple possible solutions:
Try to detect when the mouse is in absolute mode, and if it is, winit could internally track the the last position and output the difference.
Replace DeviceEvent::Motion
's value
's and DeviceEvent::Motion
's delta
's (f64, f64)
with a new type like enum MotionType<T> { Absolute(T), Relative(T) }
, where T
is f64
and (f64, f64)
, respectively. Try to detect when the mouse is in absolute mode, and if it is, return it in enum's appropriate variant.
I'm leaning towards the second solution, since according to my limited reading of the related SDL issues, this issue, or similar ones, might also affect android and macos, somehow.
cc @Osspial
I'm for the enum, knowing the difference between the event type is highly useful in many cases and makes it obvious that it should be handled instead of just ignored.
I can take a crack at implementing it then. If there's going to be breaking changes they might as well be in 0.20. One thing to note is that the absolute coordinates can be weird because I think they might be based off the monitor on the host machine? I'm not entirely sure.
I'm actually thinking, I wonder if it's better to have both delta and absolute position. The delta is always there, the absolute is an Option
that may or may not be there (maybe it could be there for the absolute screen position with a non-exclusive mouse in addition to touchscreens and so forth?).
@goddessfreya That second solution is actually implemented on the dpi-overhaul
branch. You run into this same issue when you're processing input from pen/tablet devices.
I believe this bug stems all the way down from Xlib/libinput (as @chelmich has shown). I'm experiencing it on Arch, lemurs, Openbox, without a VM:
I'm not using winit, just raw Xlib, from a completely unrelated C++ codebase. But I'd like to add to discussion because I've been staring at this for a few days now.
For some reason, XInput returns absolute values for valuators with mode: relative
and "Rel" in their name (both scroll and move). This is the case for both my trackpad and mouse. SDL probably just wraps the event data provided by Xi.
Might have to do with libinput and/or the fact that the device is being passed through a virtualization layer.
There's no correct way of amortizing for this because cursors can teleport, synthetic events exist, etc. and so all measurements/comparisons/tracking can give false positives. I'll personally just end up allowing an override through xorg.conf
options, but that's not something winit can/should probably do.
EDIT: This weirdly only happened because window type wasn't normal
but instead desktop
/panel
/dock
or root (it's conky, that's why it's configurable). On normal
windows it works as expected.
I'm listening for
glutin::DeviceEvent::MouseMotion{delta:(xrel, yrel)}
and it works fine on most systems, but Ubuntu 18.04.1 in VMware Fusion causesxrel
andyrel
to be set to large absolute values as the mouse moves, for example:MouseMotion 39128.40293884277 25325.613555908203 MouseMotion 39128.40293884277 25371.612854003906 MouseMotion 39128.40293884277 25416.6121673584
instead of the expected relative delta values. When implementing mouse look in a game using this event, this causes the player to rapidly spin instead of look where their mouse is pointing. SDL2 has similar issues: https://bugzilla.libsdl.org/show_bug.cgi?id=2150 https://bugzilla.libsdl.org/show_bug.cgi?id=2954 https://stackoverflow.com/questions/25576438/sdl-getrelativemousestate-strange-behaviour, but there is an option to enable a "relative mode warp" hint in SDL2, does/could Glutin have something similar?