LWJGL3 - alt-tab then try to grab the cursor issue

Started by abcdef, February 25, 2015, 09:48:43

Previous topic - Next topic

abcdef

Hi

I use this code to grab the cursor

GLFW.glfwSetInputMode(window, GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED);


This works fine, but if I alt tab to another OS window and then alt tab back. The code still gets called but the mouse grab action no longer takes place

Is there anything else I need to do when the window loses focus and gains it again?

spasi

I cannot reproduce this on Windows. The cursor is still disabled after the window regains focus. What OS are you on?

abcdef

I'm on Linux, the set of events is

  • Cursor is present
  • Grab cursor
  • Reset so cursor loads again
  • Alt Tab to another window
  • Alt Tab back
  • Attempt to Grab cursor - FAIL (cursor is still present)

spasi

Does the cursor remain grabbed if you alt-tab out and in again, without resetting it first?

edit: I cannot reproduce this on Linux (OpenSUSE) either. Could you post some example code?

abcdef

I can't alt tab in Linux once the mouse is grabbed when I have a windowed resolution (I believe this is typical of Linux), I'll try and get a standalone example

abcdef

Example code to repeat, to simulate use the escape key to flip between normal and disabled cursor and press F1 to exit.

The flipping will work until you alt tab and come back, but the text will print out regardless

public class TestBed
{

    private long window = MemoryUtil.NULL;
    // any control interface such as touch screen, keyboard, mouse    
    private final GLFWKeyCallback keyCallback;
    private final GLFWCursorPosCallback cursorPositionCallback;
    private boolean running = true;
    private boolean isGrabbed = false;
    private GLFWErrorCallback errorCallback;

    public TestBed()
    {
        keyCallback = new GLFWKeyCallback()
        {

            @Override
            public void invoke(long window, int key, int scancode, int action, int mods)
            {
                boolean isPressed = false;
                boolean isRepeated = false;

                switch (action)
                {
                    case GLFW.GLFW_RELEASE:
                        isPressed = false;
                        break;
                    case GLFW.GLFW_PRESS:
                        isPressed = true;
                        break;
                    case GLFW.GLFW_REPEAT:
                        isRepeated = true;
                        break;
                }

                System.out.println("Key : " + key + " Pressed : " + isPressed);

                if (key == GLFW.GLFW_KEY_ESCAPE && isPressed == true)
                {                    
                    if (isGrabbed)
                    {
                        System.out.println("Escape pressed, making cursor normal");
                        GLFW.glfwSetInputMode(window, GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL);   
                        isGrabbed = false;
                    }
                    else
                    {
                        System.out.println("Escape pressed, making cursor hidden");
                        GLFW.glfwSetInputMode(window, GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED);
                        isGrabbed = true;
                    }
                    
                }
                
                if (key == GLFW.GLFW_KEY_F1)
                {
                    System.out.println("Exiting");
                    running = false;
                }
            }
        };

        cursorPositionCallback = new GLFWCursorPosCallback()
        {
            @Override
            public void invoke(long window, double xpos, double ypos)
            {
                System.out.println("X : " + (int) xpos + " Y : " + (int) ypos);
            }
        };
    }

    public void run()
    {
        GLFW.glfwSetErrorCallback(errorCallback = errorCallbackPrint(System.err));

        if (GLFW.glfwInit() != GL11.GL_TRUE)
        {
            System.out.println("Exiting because could not initialise GLFW");
            System.exit(1);
        }
        
        GLFW.glfwDefaultWindowHints();
        GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GL_FALSE);
        GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, GL_TRUE);

        // tell the window what bits per pixel we are interested in
        GLFW.glfwWindowHint(GLFW.GLFW_RED_BITS, 8);
        GLFW.glfwWindowHint(GLFW.GLFW_GREEN_BITS, 8);
        GLFW.glfwWindowHint(GLFW.GLFW_BLUE_BITS, 8);
        GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE);
        GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3);
        GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 2);

        // create the actual window
        window = GLFW.glfwCreateWindow(800, 600, "", MemoryUtil.NULL, MemoryUtil.NULL);

        if (window == MemoryUtil.NULL)
        {
            System.out.println("Exiting because window is null");
            System.exit(2);
        }

        // if windowed then center
        ByteBuffer vidmode = GLFW.glfwGetVideoMode(GLFW.glfwGetPrimaryMonitor());
        GLFW.glfwSetWindowPos(window, (GLFWvidmode.width(vidmode) - 800) / 2, (GLFWvidmode.height(vidmode) - 600) / 2);

        GLFW.glfwMakeContextCurrent(window);
        GLContext.createFromCurrent();
        GL11.glViewport(0, 0, 800, 600);
        GLFW.glfwSwapInterval(1);

        GLFW.glfwShowWindow(window);

        GLFW.glfwSetKeyCallback(window, keyCallback);
        GLFW.glfwSetCursorPosCallback(window, cursorPositionCallback);

        while (running)
        {
            GLFW.glfwSwapBuffers(window);
            GLFW.glfwPollEvents();
        }
    }

    public static void main(String[] args)
    {
        TestBed tb = new TestBed();
        tb.run();
    }
}

spasi

Hmm, your code works fine for me. Does anyone else have this issue?

abcdef

To add some more info, I am running Linux Mint 17.1 with the Cinnamon desktop using the intel drivers (I have Nvidia too but waiting for an xorg-xserver bug to be deployed before using properly)

abcdef

Spasi

I ran another test using the window focus call back. I get the initial window focus but when I click off (lost focus triggered)  and click back I don't get an event saying that Focus has come back, I only get focus lost events (if i click off again another focus lost event is triggered). I guess the focus has to be true for the cursor to be hidden?

Some output from the below

Window[139768908528128] Focus[true]
Window[139768908528128] Key : 256 Pressed : true
Escape pressed, making cursor hidden
Window[139768908528128] Key : 256 Pressed : false
Window[139768908528128] Key : 256 Pressed : true
Escape pressed, making cursor normal
Window[139768908528128] Key : 256 Pressed : false
Window[139768908528128] Focus[false]
Window[139768908528128] Focus[false]

New test code below

public class TestBed
{

    private long window = MemoryUtil.NULL;
    // any control interface such as touch screen, keyboard, mouse    
    private final GLFWKeyCallback keyCallback;
    private final GLFWCursorPosCallback cursorPositionCallback;
    private final GLFWWindowFocusCallback windowFocusCallback;
    private boolean running = true;
    private boolean isGrabbed = false;
    private GLFWErrorCallback errorCallback;

    public TestBed()
    {
        windowFocusCallback = new GLFWWindowFocusCallback()
        {

            @Override
            public void invoke(long window, int focused)
            {
                System.out.println("Window[" + window + "] Focus[" + (focused == GL11.GL_TRUE) + "]");
            }
            
        };
                
        keyCallback = new GLFWKeyCallback()
        {

            @Override
            public void invoke(long window, int key, int scancode, int action, int mods)
            {
                boolean isPressed = false;
                boolean isRepeated = false;

                switch (action)
                {
                    case GLFW.GLFW_RELEASE:
                        isPressed = false;
                        break;
                    case GLFW.GLFW_PRESS:
                        isPressed = true;
                        break;
                    case GLFW.GLFW_REPEAT:
                        isRepeated = true;
                        break;
                }

                System.out.println("Window[" + window + "] Key : " + key + " Pressed : " + isPressed);

                if (key == GLFW.GLFW_KEY_ESCAPE && isPressed == true)
                {                    
                    if (isGrabbed)
                    {
                        System.out.println("Escape pressed, making cursor normal");
                        GLFW.glfwSetInputMode(window, GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL);   
                        isGrabbed = false;
                    }
                    else
                    {
                        System.out.println("Escape pressed, making cursor hidden");
                        GLFW.glfwSetInputMode(window, GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_HIDDEN);
                        isGrabbed = true;
                    }
                    
                }
                
                if (key == GLFW.GLFW_KEY_F1)
                {
                    System.out.println("Exiting");
                    running = false;
                }
            }
        };

        cursorPositionCallback = new GLFWCursorPosCallback()
        {
            @Override
            public void invoke(long window, double xpos, double ypos)
            {
                //System.out.println("X : " + (int) xpos + " Y : " + (int) ypos);
            }
        };
    }

    public void run()
    {
        GLFW.glfwSetErrorCallback(errorCallback = errorCallbackPrint(System.err));

        if (GLFW.glfwInit() != GL11.GL_TRUE)
        {
            System.out.println("Exiting because could not initialise GLFW");
            System.exit(1);
        }
        
        GLFW.glfwDefaultWindowHints();
        GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GL_FALSE);
        GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, GL_TRUE);

        // tell the window what bits per pixel we are interested in
        GLFW.glfwWindowHint(GLFW.GLFW_RED_BITS, 8);
        GLFW.glfwWindowHint(GLFW.GLFW_GREEN_BITS, 8);
        GLFW.glfwWindowHint(GLFW.GLFW_BLUE_BITS, 8);
        GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE);
        GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3);
        GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 2);

        // create the actual window
        window = GLFW.glfwCreateWindow(800, 600, "", MemoryUtil.NULL, MemoryUtil.NULL);

        if (window == MemoryUtil.NULL)
        {
            System.out.println("Exiting because window is null");
            System.exit(2);
        }

        // if windowed then center
        ByteBuffer vidmode = GLFW.glfwGetVideoMode(GLFW.glfwGetPrimaryMonitor());
        GLFW.glfwSetWindowPos(window, (GLFWvidmode.width(vidmode) - 800) / 2, (GLFWvidmode.height(vidmode) - 600) / 2);

        GLFW.glfwMakeContextCurrent(window);
        GLContext.createFromCurrent();
        GL11.glViewport(0, 0, 800, 600);
        GLFW.glfwSwapInterval(1);

        GLFW.glfwShowWindow(window);

        GLFW.glfwSetKeyCallback(window, keyCallback);
        GLFW.glfwSetCursorPosCallback(window, cursorPositionCallback);
        GLFW.glfwSetWindowFocusCallback(window, windowFocusCallback);

        while (running)
        {
            GLFW.glfwSwapBuffers(window);
            GLFW.glfwPollEvents();
        }
    }

    public static void main(String[] args)
    {
        TestBed tb = new TestBed();
        tb.run();
    }
}

spasi

Indeed, focus should work properly for GLFW_CURSOR_DISABLED to work as you'd expect. This sounds like a bug in GLFW or your window manager. Do you have any trouble with focus in LWJGL 2.x or other apps?

abcdef

I have GLFW 3.1.1 compiled and 3.0.4. When using the "wave" example app you can grab the cursor (left mouse click hold) and this works perfectly after alt-tab's (ie window losing and gaining focus). It looks like GLFW works on my machine for the circumstances above

spasi

The only relevant, post 3.1, commit I see is this. But that still relies on focus lost/gained events to work properly.

spasi

The latest LWJGL 3 nightly build (#40) has been updated with the latest GLFW changes. Could you please try again? (both code samples if possible)

abcdef

Ok, I have tried the new build and it doesn't fix the issue...but...I have found a much narrower use case to replicate the issue.

My IDE and subsequently my test class are being run on a secondary workspace (the 2nd desktop space in Linux). I can not get the test class I posted to work with build 40 if I start the program in this workspace. But if I move this window to the first work space then I can get the test program to work perfectly so you could probably replicate this if you run the example code on work space 2. Strangely if I run it on 3 or 4 things work fine too, its just work space 2 that has the issue.

I have recompiled wave.c  (from the GLFW examples) and added some debug for windows focus events and this works on all work spaces on my machine

spasi

Have you tried running the test outside your IDE, from the command-line?