rust-windowing / winit

Window handling library in pure Rust
https://docs.rs/winit/
Apache License 2.0
4.78k stars 891 forks source link

Add cursor locking support for X11 and Windows #3094

Open Imberflur opened 1 year ago

Imberflur commented 1 year ago

As noted in https://github.com/rust-windowing/winit/issues/1677 locking the cursor (rather than just confining to the window) can be useful for cases like camera control. winit does not currently provide cursor locking for Windows and X11 but the information in that issue indicates that it should be possible for Windows and is maybe(?) possible for X11.

GiantBlargg commented 1 year ago

Hacking around it isn't too bad. This is what I've been using on a recent project of mine. Haven't tested windows yet but x11(XWayland) seems to work.

#[derive(Default)]
struct MouseGrabber {
    last_pos: PhysicalPosition<f64>,
    manual_lock: bool,
}

impl MouseGrabber {
    // Call this on every WindowEvent::CursorMoved to update the last known position
    fn cursor_moved(&mut self, window: &Window, pos: PhysicalPosition<f64>) {
        if self.manual_lock {
            window.set_cursor_position(self.last_pos).unwrap();
        } else {
            self.last_pos = pos;
        }
    }
    // Call this with true to lock and false to unlock
    fn grab(&mut self, window: &Window, grab: bool) {
        if grab {
            if window.set_cursor_grab(CursorGrabMode::Locked).is_err() {
                window.set_cursor_grab(CursorGrabMode::Confined).unwrap();
                self.manual_lock = true;
            }
        } else {
            self.manual_lock = false;
            window.set_cursor_grab(CursorGrabMode::None).unwrap();
        }
        window.set_cursor_visible(!grab);
    }
}

This puts the mouse back to its last unlocked position, but it could probably be made simpler if you just wanted to lock to the center of the window.

Imberflur commented 1 year ago

@GiantBlargg thanks for sharing a workaround!

kchibisov commented 1 year ago

You can also submit this upstream, just saying. It's not like it'll be any different....

ten3roberts commented 4 months ago

Is there any reason or hurdles to implementing cursor locking in winit itself, rather than using this workaround?

dbartussek commented 4 months ago

I'd also like to know if there is a reason why this is not implemented on Windows?

It seems very easy to implement by just taking the current cursor position and setting the cursor clipping window to just this position: https://github.com/dbartussek/winit/commit/dbd7cbdfc09252a7bfb1fda95e6607b2040c1ba7 Is there some hidden pitfall here I'm not seeing?