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?
I cannot reproduce this on Windows. The cursor is still disabled after the window regains focus. What OS are you on?
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)
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?
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
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();
}
}
Hmm, your code works fine for me. Does anyone else have this issue?
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)
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();
}
}
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?
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
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.
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)
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
Have you tried running the test outside your IDE, from the command-line?
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!)