[Linux] xinput custom settings breaks mouse position with GLFW_CURSOR_DISABLED

Hi everyone :slight_smile:

GLFW Version: 3.2.1 X11 GLX EGL clock_gettime /dev/js Xf86vm shared

I’m trying to implement FPS camera using glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); feature of GLFW. However, whatever the direction I’m moving the mouse, the position recieved in the callback glfwSetCursorPosCallback(window, mouse_pos_callback); is always decreasing.

Test code

static void error_callback(int error, const char *description)
{
    fprintf(stderr, "Error: %s\n", description);
}

static void mouse_pos_callback(GLFWwindow *window, double x, double y)
{
    fprintf(stderr, "Pos: %f, %f\n", x, y);
}

int main(void)
{
    GLFWwindow *window;
    glfwSetErrorCallback(error_callback);
    if (!glfwInit())
        exit(EXIT_FAILURE);

    window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }

    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
    glfwSetCursorPosCallback(window, mouse_pos_callback);

    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);

    while (!glfwWindowShouldClose(window))
    {
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwDestroyWindow(window);
    glfwTerminate();

    exit(EXIT_SUCCESS);
}

Output

joris@joris-MS-7998:~/projects/graphics/build/linux$ ./demo 
Pos: -555.000000, -333.000000
Pos: -875.000000, -573.000000
Pos: -1195.000000, -813.000000
Pos: -1515.000000, -1053.000000
Pos: -1835.000000, -1293.000000
Pos: -2155.000000, -1533.000000
Pos: -2475.000000, -1773.000000
....
// moving mouse up/down/left/right/kicking_it_on_the_table
// the value is always getting lower and lower and lower :smile: 

Using glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); is however working properly.

Software/Hardware

I'm using XUbuntu 17.04 and my mouse is "ROCCAT ROCCAT Kone XTD" as shown with xinput command line. Am I doing something wrong or is this a bug ?

What I've tested

TEST1: I just tested on my laptop, running the same Ubuntu version, but using the trackpad and everything is working properly.

TEST2: I plugged the mouse on the laptop. Everything working proplery.

TEST3: Plugged back the mouse on the desktop... and it's working properly as well, like what the hell. So something is my configuration is fucked up xD.

The actual problem

I figured it out. Actually, when the os start, I run the following script to reduce the mouse sensivity:
xinput --set-prop 12 "libinput Accel Speed" -0.25
// This line seems to be causing the issue, but I don't understand why since
// it's a simple scale matrix without any negative sign in it
xinput --set-prop 12 "Coordinate Transformation Matrix" 0.6 0 0 0 0.6 0 0 0 2

Can I have a direction in GLFW sources so I can understand why is this causing trouble ?

Best regards.

If you build from source http://www.glfw.org/docs/latest/compile_guide.html and then put a breakpoint at the callback you should be able to trace what’s going on.

The source for X11 cursor handling is in:

and if you search for calls to the function _glfwInputCursorPos you should find how this works.

1 Like

Before trying to narrow the problem down in source, it’s probably worth trying again with a build of the current master. IIRC disabled cursor mode has had some significant changes since the 3.2.1 release.

1 Like

Maybe, but that would not let me the chance to find the issue by myself which is funnier :smiley:

1 Like

I got the problem.

Scenario 1 (the normal one)

Using uniform matrix `xinput --set-prop 12 140 1 0 0 0 1 0 0 0 1`

The window size is 1280x720.

When recieving a MotionNotify event, we print the values of

const int x = event->xmotion.x; // x position of the cursor for x11
const int y = event->xmotion.y; // y position of the cursor for x11

and it always gives [640, 360] which is logic because glfw always re-center the mouse after polling x11 events (so half of the window size we gave at the beginning).

The scenario gives the expected results.

Scenario 2 (the broken one)

Using non uniform matrix `xinput --set-prop 12 140 0.5 0 0 0 0.5 0 0 0 1 `

The window size is still 1280x720.

When recieving a MotionNotify event, we print the values of

const int x = event->xmotion.x; // x position of the cursor for x11
const int y = event->xmotion.y; // y position of the cursor for x11

and it always gives [319, 166] which is around half of the previous results. This would correspond to the 0.5 scale factor we applied with xinput. (Don’t ask for the real computation, because I have not idea. It seems x11 is using so kind of depth because changing the last factor from 1 to 2 will give different result)

However, since we are in GLFW_CURSOR_DISABLED mode, glfw will always recenter the mouse (center of the window).
So for the next events, the delta will be computed between [640, 360] and [319, 166] (and it will be done everytime). This leads to the issue I faced at the beginning.

Improvements/Fix?

In GLFW_CURSOR_DISABLED mode, glfw should reset the mouse to the last know position gave by x11, instead of recentering it in the middle of the window. But I think it could raises new issues like “What if the position given by x11 is outside the window, and then the use click on a mouse button? Will the window loose focus?” (this kind of thing).

Anyway. Problem understood and (half) solved :smiley:
If you have any feedback/questions :wink:

Best regards.

1 Like

Excellent detective work! Just to clarify, were you working with 3.2.1 the whole time, or do you know if the bug also affects latest master?

I don’t think we can consider it as a “bug” since I’m probably the 1/100000 user who actually messed up his mouse driver settings :wink:.
And yes, the issue will also appears on master since after polling events, they are still recentering to the middle of the window using (glfw master github source file)

_glfwPlatformSetCursorPos(window, width / 2, height / 2);

Quick question - did you modify the xinput matrix before launching the glfw app or after?

If you made the change before then this is probably something which should be investigated after checking it still happens on main, albeit with a low priority.

Always before launching the GLFW application. Good point. I didn’t test changing xinput setting while the application is running. But I would guess that it does not really matter and the issue would still appears.

I’m pretty sure this will also happens on master since the delta calculation is still based on the center of the window :slight_smile:.

There’s a subtle difference between “messed up” and “messed with” :stuck_out_tongue: As far as I can see you made a completely valid change to the mouse sensitivity, and it caused glfw to misbehave. I’ve messed with cursor props before to try and undo mouse acceleration, so it’s not unheard of for people to change these settings.

That said, I’ve now reproduced this on my machine and assert that it has been fixed at some point between 3.2.1 and current master. Please check this on your machine. I’ll leave it as an exercise for you to bisect which commit changed the behaviour, if you’re interested.

I do still see a bug, though: after leaving DISABLED mode, the first time I move the mouse causes the cursor to teleport outside of the window, whereas with default scaling it remains in place. I’ll look into that.

1 Like

There’s a subtle difference between “messed up” and “messed with”

Nice one :smile:

All right then I will test with master next week to see if I can reproduce my issue. I will post the results on this topic as well.

Just a quick note to say that I was not able to reproduce the issue on master (of Nov 2, 2017).

2 Likes

This may have been the same issue as #999.

A bisect will likely point to the move to XI_RawMotion as the fix.

3 Likes