Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MouseMotion event returns absolute instead of relative values, when running Linux in a VM #946

Open
iceiix opened this issue Nov 30, 2018 · 11 comments
Labels
B - bug Dang, that shouldn't have happened D - easy Likely easier than most tasks here DS - x11 H - good first issue Ideal for new contributors

Comments

@iceiix
Copy link

iceiix commented Nov 30, 2018

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 causes xrel and yrel 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?

iceiix referenced this issue in iceiix/steven Nov 30, 2018
For the third issue on #35 (comment)
https://github.com/tomaka/glutin/issues/1084 MouseMotion event returns absolute instead of relative values, when running Linux in a VM
iceiix referenced this issue in iceiix/steven Nov 30, 2018
* Add glutin dependency

* Create a glutin window

* Use the glutin window, basics work

* Store DPI factor on game object, update on Resized

* Use physical size for rendering only. Fixes UI scaled too small

Fixes #35 (comment)
See also https://github.com/iceiix/steven/issues/22

* Begin adding mouse input events

* Listen for DeviceEvents

* Call hover_at on mouse motion

* Listen for CursorMoved window event, hovering works

Glutin has separate WindowEvent::CursorMoved and
DeviceEvent::MouseMotion events, for absolute cursor and relative mouse
motion, respectively, instead of SDL's Event::MouseMotion for both.

* Use tuple pattern matching instead of nested if for MouseInput

* Implement left clicking

* Use grab_cursor() to capture the cursor

* Hide the cursor when grabbing

* Implement MouseWheel event

* Listen for keyboard input, escape key release

* Keyboard input: console toggling, glutin calls backquote 'grave'

* Implement fullscreen in glutin, updates #31

* Update settings for glutin VirtualKeyCode

* Keyboard controls (note: must clear conf.cfg to use correct bindings)

* Move DeviceEvent match arm up higher for clarity

* Remove SDL

* Pass physical dimensions to renderer tick so blit_framebuffer can use full size but the ui is still sized logically.

* Listen for DeviceEvent::Text

* Implement text input using ReceivedCharacter window event, works

#35 (comment)

* Request specific version of OpenGL, version 3.2

* Request OpenGL 3.2 but fallback to OpenGL ES 2.0 if available (not tested)

* Set core profile and depth 24-bits, stencil 0-bits

* Allow changing vsync, but require restarting (until rust-windowing/glutin#693)

* Clarify specific Rust version requirement

* Import glutin::* in handle_window_event() to avoid overly repetitive code

* Linux in VM fix: manually calculate delta in MouseMotion

For the third issue on #35 (comment)
https://github.com/tomaka/glutin/issues/1084 MouseMotion event returns absolute instead of relative values, when running Linux in a VM

* Heuristic to detect absolute/relative MouseMotion from delta:(xrel, yrel); use a higher scaling factor

* Add clipboard pasting with clipboard crate instead of sdl2

#35 (comment)
@francesca64
Copy link
Member

francesca64 commented Dec 22, 2018

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).

@goddessfreya
Copy link
Contributor

Closing in favor of upstream. #876

@Osspial Osspial transferred this issue from rust-windowing/glutin Jun 20, 2019
@Osspial Osspial reopened this Jun 20, 2019
@Osspial Osspial added DS - x11 B - bug Dang, that shouldn't have happened labels Jun 20, 2019
@goddessfreya goddessfreya added D - easy Likely easier than most tasks here H - good first issue Ideal for new contributors Contributer Push Issue and removed Contributer Push Issue labels Jun 20, 2019
@psychon
Copy link
Contributor

psychon commented Aug 20, 2019

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)

@Osspial
Copy link
Contributor

Osspial commented Aug 26, 2019

@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 🤷‍♀

@chelmich
Copy link
Contributor

chelmich commented Nov 16, 2019

For what it's worth I was able to recreate this issue as of b6e8dd0 by using cargo run --example window with the following setup:

  • Windows 10 host
  • VirtualBox 6.0
  • Ubuntu 19.10 client

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?

@goddessfreya
Copy link
Contributor

@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

@OvermindDL1
Copy link

OvermindDL1 commented Nov 18, 2019

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.

@chelmich
Copy link
Contributor

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.

@OvermindDL1
Copy link

OvermindDL1 commented Nov 19, 2019

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?).

@Osspial
Copy link
Contributor

Osspial commented Nov 21, 2019

@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.

@Caellian
Copy link

Caellian commented Apr 15, 2024

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:

  • xorg-server 21.1.12-1
  • xorg-xinput 1.6.4-1
  • xf86-input-libinput 1.4.0-1

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B - bug Dang, that shouldn't have happened D - easy Likely easier than most tasks here DS - x11 H - good first issue Ideal for new contributors
Development

No branches or pull requests

8 participants