Skip to content

MouseMotion and AccumulatedMouseMotion deltas are doubled when cursor grab mode is not None #20178

@Sykotes

Description

@Sykotes

Bevy version

16.1

[Optional] Relevant system information

I found the issue on two machines

  • Both are running wayland on linux
  • One is using the sway window manager with intel iris graphics
  • The other is using gnome desktop manager with an nvidia rtx 3060

What you did

I tried to use AccumulatedMouseMotion or MouseMotion deltas when also capturing the cursor

Use this code to test:

use bevy::input::mouse::{AccumulatedMouseMotion, MouseMotion};
use bevy::prelude::*;
use bevy::window::{CursorGrabMode, PrimaryWindow};

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Update, (print_mouse_delta, print_mouse_delta_2, setup))
        .run();
}

fn print_mouse_delta(mouse_motion: Res<AccumulatedMouseMotion>) {
    println!(
        "adelta x: {} - adelta y: {}",
        mouse_motion.delta.x, mouse_motion.delta.y
    );
}

fn print_mouse_delta_2(mut motion_events: EventReader<MouseMotion>) {
    let mut sum = Vec2::new(0., 0.);
    for motion in motion_events.read() {
        sum += motion.delta;
    }
    println!("mdelta x: {} - mdelta y: {}", sum.x, sum.y);
}

pub fn setup(mut window: Single<&mut Window, With<PrimaryWindow>>) {
    // this only happens when this is set
    window.cursor_options.grab_mode = CursorGrabMode::Confined;

    // or this is set
    window.cursor_options.grab_mode = CursorGrabMode::Locked;
}

What went wrong

Upon capturing the cursor either using Confined or Locked the delta x and delta y were multiplied by two

Logged output with lock:

mdelta x: -6 - mdelta y: -12
adelta x: -4 - adelta y: -16
mdelta x: -4 - mdelta y: -16
adelta x: -4 - adelta y: -16
mdelta x: -4 - mdelta y: -16
adelta x: -6 - adelta y: -16
mdelta x: -6 - mdelta y: -16
adelta x: -2 - adelta y: -12

Expected output:

mdelta x: -3 - mdelta y: -3
adelta x: -2 - adelta y: -8
mdelta x: -2 - mdelta y: -8
adelta x: -2 - adelta y: -8
mdelta x: -2 - mdelta y: -8
adelta x: -3 - adelta y: - 8
mdelta x: -3 - mdelta y: -8
adelta x: -1 - adelta y: -6

Additional information

This is evidenced by the fact that all the outputs are even

I also know it is exactly multiplied by two and not any other value because I tested using CM/360 camera with the cursor locked and unlocked

This is supposed to make the player turn around in 80cm of mouse movement but it turns the player in 40 only when the cursor is locked

pub fn camera_look(
    mut player: Single<&mut Transform, With<Player>>,
    mouse_motion: Res<AccumulatedMouseMotion>,
    window: Single<&Window, With<PrimaryWindow>>,
) {
    if !window.focused {
        return;
    }

    const DPI: f32 = 1600.;
    const CM_PER_360: f32 = 80.;
    const CM_PER_INCH: f32 = 2.54;

    let inches_per_360 = CM_PER_360 / CM_PER_INCH;
    let pixels_per_360 = inches_per_360 * DPI;

    let sensitivity = (2. * std::f32::consts::PI) / pixels_per_360;

    let (mut yaw, mut pitch, _) = player.rotation.to_euler(EulerRot::YXZ);
    pitch -= mouse_motion.delta.y * sensitivity;
    yaw -= mouse_motion.delta.x * sensitivity;

    pitch = pitch.clamp(-1.57, 1.57);
    player.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, 0.);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-BugAn unexpected or incorrect behaviorS-Needs-TriageThis issue needs to be labelled

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions