LWJGL Forum

Programming => Lightweight Java Gaming Library => Topic started by: abcdef on February 25, 2015, 09:48:43

Title: LWJGL3 - alt-tab then try to grab the cursor issue
Post by: abcdef on February 25, 2015, 09:48:43
Hi

I use this code to grab the cursor

Code: [Select]
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?
Title: Re: LWJGL3 - alt-tab then try to grab the cursor issue
Post by: spasi on February 25, 2015, 10:33:35
I cannot reproduce this on Windows. The cursor is still disabled after the window regains focus. What OS are you on?
Title: Re: LWJGL3 - alt-tab then try to grab the cursor issue
Post by: abcdef on February 25, 2015, 14:27:03
I'm on Linux, the set of events is
Title: Re: LWJGL3 - alt-tab then try to grab the cursor issue
Post by: spasi on February 25, 2015, 15:27:00
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?
Title: Re: LWJGL3 - alt-tab then try to grab the cursor issue
Post by: abcdef on February 25, 2015, 18:08:10
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
Title: Re: LWJGL3 - alt-tab then try to grab the cursor issue
Post by: abcdef on February 25, 2015, 18:43:02
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

Code: [Select]
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();
    }
}
Title: Re: LWJGL3 - alt-tab then try to grab the cursor issue
Post by: spasi on February 25, 2015, 20:08:15
Hmm, your code works fine for me. Does anyone else have this issue?
Title: Re: LWJGL3 - alt-tab then try to grab the cursor issue
Post by: abcdef on February 25, 2015, 21:35:45
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)
Title: Re: LWJGL3 - alt-tab then try to grab the cursor issue
Post by: abcdef on February 26, 2015, 10:01:51
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

Code: [Select]
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();
    }
}
Title: Re: LWJGL3 - alt-tab then try to grab the cursor issue
Post by: spasi on February 27, 2015, 10:31:49
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?
Title: Re: LWJGL3 - alt-tab then try to grab the cursor issue
Post by: abcdef on February 27, 2015, 13:07:50
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
Title: Re: LWJGL3 - alt-tab then try to grab the cursor issue
Post by: spasi on February 27, 2015, 14:22:30
The only relevant, post 3.1, commit I see is this (https://github.com/glfw/glfw/commit/a343e9a4756382b5f95141a7072ba09be8104e2e). But that still relies on focus lost/gained events to work properly.
Title: Re: LWJGL3 - alt-tab then try to grab the cursor issue
Post by: spasi on February 27, 2015, 15:19:29
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)
Title: Re: LWJGL3 - alt-tab then try to grab the cursor issue
Post by: abcdef on February 27, 2015, 16:11:35
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
Title: Re: LWJGL3 - alt-tab then try to grab the cursor issue
Post by: spasi on February 27, 2015, 17:03:39
Have you tried running the test outside your IDE, from the command-line?
Title: Re: LWJGL3 - alt-tab then try to grab the cursor issue
Post by: abcdef on February 27, 2015, 21:58:34
I hadn't but trying just now it seems to work! Bit of a pain as I run debug mode a lot (which needs the ide) but now I know it works on other work spaces I will just use that going forwards.

Sorry to make you investigate something that looks like its an ide issue (but a strange one at that!)