Describe the bug
mouse_motion_event appears to be being called every single frame with some small delta, even while the mouse is not moving. This is possibly a winit bug because it looks like it means we're getting CursorMoved events continually from winit. As an aside, input::mouse::delta looks like it only changes when we get MouseMotion events from winit so will always return the last mouse motion delta, despite the documentation saying it "[gets] the distance the cursor was moved during last frame".
To Reproduce
// main.rs
use ggez::graphics::{DrawMode, DrawParam, Mesh};
use ggez::*;
struct State {
x: f32,
y: f32,
}
impl event::EventHandler for State {
fn mouse_motion_event(&mut self, _ctx: &mut Context, _x: f32, _y: f32, dx: f32, dy: f32) {
self.x += dx;
self.y += dy;
}
fn update(&mut self, _ctx: &mut Context) -> GameResult<()> {
Ok(())
}
fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
graphics::clear(ctx, graphics::BLACK);
let circle = Mesh::new_circle(
ctx,
DrawMode::fill(),
[self.x, self.y],
5.0,
0.1,
graphics::WHITE,
)?;
graphics::draw(ctx, &circle, DrawParam::default())?;
graphics::present(ctx)
}
}
fn main() {
let c = conf::Conf::new();
let (ref mut ctx, ref mut event_loop) = ContextBuilder::new("hello_ggez", "awesome_person")
.conf(c)
.build()
.unwrap();
let state = &mut State { x: 0.0, y: 0.0 };
event::run(ctx, event_loop, state).unwrap();
}
Expected behavior
The white circle to track the cursor, since its position is determined by summing over all the mouse deltas.
Screenshots or pasted code
https://i.imgur.com/RWql7gD.gifv
Hardware and Software:
So yeah, this is not a particularly difficult issue to work around since you can recompute the deltas yourself, but it is kinda annoying that there's a function for doing it in the library but it doesn't work.
Thank you for the bug report! Can't reproduce on Linux; I'm traveling with just my Linux laptop so I can't try on Windows until like, Friday. Will see if I can make a program with just winit 0.19 to reproduce upstream.
Windows reproduction video: https://i.imgur.com/aXUJ4ye.mp4
Only drifts when the window is in focus.
I got this bug too, and only on Windows. On Linux it's fine.
I debugged it a bit. It seems like winit keeps receiving the WM_MOUSEMOVE event from windows,
even though it correctly returns 0 from the callback (and signals windows, that the event has
been handled).
The main problem for me is, that the relative movement of the mouse is not updated correctly in ggez. The delta is separately calculated and set in the context.rs file, where the winit_event::DeviceEvent::MouseMotion is handled. However, the winit_event::DeviceEvent::MouseMotion event is not based on the WM_MOUSEMOVE windows message, but on the WM_INPUT message (where it also gets the delta of the movement from
windows).
I am not sure whether ggez should handle things differently, but maybe the delta in event.rs
when handling the WindowEvent::CursorMoved should be calculated based on the last x/y positions
and not just read from a stored delta when the last WM_INPUT ( MouseMotion ) event has been received. But that might just be a workaround that winit should do, I am not sure.
Try this on the latest devel branch, since winit has updated a bunch?
Most helpful comment
Windows reproduction video: https://i.imgur.com/aXUJ4ye.mp4
Only drifts when the window is in focus.