Hello Guest

GLFW KeyCallback Only certain keys seem to work

  • 17 Replies
  • 11115 Views
*

Offline Lugen

  • *
  • 18
GLFW KeyCallback Only certain keys seem to work
« on: July 06, 2015, 08:06:27 »
So this is a rather odd problem I'm having. I would guess that I'm missing something here.

So I'm currently following this tutorial and I'm getting a strange problem with keyboard input. At first it appeared that no keys where detected but then after pressing randomly I found only a few where triggering the callback and even stranger, pressing these keys would for a brief moment enable a couple of other keys as well.

I'm pointing to the GLFWKeyCallback function through this class.
Code: [Select]
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWKeyCallback;

public class Input extends GLFWKeyCallback{

// Keycode sate list, size set according to available number of keys
public static boolean[] keys = new boolean[65536];

// Main key callback
// This functions needs to be wrapped in a class in order to be referenced
public void invoke(long window, int key, int scancode, int action, int mods) {
System.out.println(key);
keys[key] = action != GLFW.GLFW_RELEASE;
}

// Key down
public static boolean isKeyDown(int keycode) {
return keys[keycode];
}
}

Then set the callback like this during initialization of the window.
Code: [Select]
if (glfwInit() == GL_FALSE) {
return;
}

glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);

window = glfwCreateWindow(width, height, "Tutorial", NULL, NULL);
if (window == NULL) {
System.err.println("Could not create GLFW window.");
return;
}

ByteBuffer videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(window, (GLFWvidmode.width(videoMode) - width) / 2,
(GLFWvidmode.height(videoMode) - height) / 2);

glfwSetKeyCallback(window, new Input());

glfwMakeContextCurrent(window);
glfwShowWindow(window);
GLContext.createFromCurrent();

Then in my update function I simply run glfwPollEvents(). Ups is at 60.

I've also tried this code and it gives the same result.

Any clues whatsoever are very much appreciated!

*

Online spasi

  • *****
  • 2111
    • WebHotelier
Re: GLFW KeyCallback Only certain keys seem to work
« Reply #1 on: July 06, 2015, 08:19:08 »
The part of your code that polls events and tests for key state is missing. Could you please post a fully working example?

From the above code, I see two issues: a) you're not holding a reference to "new Input()", the program will crash if you don't and b) the boolean[] keys array is too big; you don't need more than GLFW_KEY_LAST+1 elements.

*

Offline Lugen

  • *
  • 18
Re: GLFW KeyCallback Only certain keys seem to work
« Reply #2 on: July 06, 2015, 09:25:57 »
The part of your code that polls events and tests for key state is missing. Could you please post a fully working example?

From the above code, I see two issues: a) you're not holding a reference to "new Input()", the program will crash if you don't and b) the boolean[] keys array is too big; you don't need more than GLFW_KEY_LAST+1 elements.

Thanks for the fast reply.
I mentioned the poll test passingly as it's just this code.
Code: [Select]
private void update() {
glfwPollEvents();
level.update();
}

Is this what you mean by holding a reference to new Input()?
"input" in this case is a private variable in the main class declaration.
Code: [Select]
input = new Input();
glfwSetKeyCallback(window, input);

Heck, I'll just post the entire Main-class in case that helps.
Code: [Select]
package tutorial;

// Imports static methods
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.system.MemoryUtil.*;

import java.nio.ByteBuffer;

import org.lwjgl.glfw.GLFWvidmode;
import org.lwjgl.opengl.GLContext;

import tutorial.graphic.Shader;
import tutorial.input.Input;
import tutorial.level.Level;
import tutorial.math.Mat4;

public class Main implements Runnable {

private int width = 1280;
private int height = 720;

private Thread thread;
private boolean bRunning = false;

// There are no objects in C, only identifiers
private long window;
private Input input;

// Level instance
private Level level;

public void start() {
bRunning = true;
thread = new Thread(this, "Game");
thread.start();
}

// Initiate opengl, needs to be on same thread as render()
public void init() {
// Handle if initialization failed
if (glfwInit() == GL_FALSE) {
return;
}

// Create window
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);

// Will return id for window, perhaps memory adress
window = glfwCreateWindow(width, height, "Tutorial", NULL, NULL);
if (window == NULL) {
System.err.println("Could not create GLFW window.");
return;
}
// Set window position
ByteBuffer videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(window, (GLFWvidmode.width(videoMode) - width) / 2,
(GLFWvidmode.height(videoMode) - height) / 2);

// Initiate key callback with our Input class
input = new Input();
glfwSetKeyCallback(window, input);

glfwMakeContextCurrent(window);
glfwShowWindow(window);
// Make sure Opengl is running under the current window context
GLContext.createFromCurrent();

// OpenGl stuff
glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
glEnable(GL_DEPTH_TEST);
glActiveTexture(GL_TEXTURE1);

// Print OpenGL info
System.out.println("OpenGl: " + glGetString(GL_VERSION));

// Load shaders
Shader.loadAll();

// Projection matrix
Mat4 matrixProjection = Mat4.orthographic(-10, 10, -10 * 9 / 16, 10 * 9 / 16, -1, 1);
Shader.BG.setUniformMat4("projection", matrixProjection);
Shader.BG.setUniformInt("tex", 1);

Shader.BIRD.setUniformMat4("projection", matrixProjection);
Shader.BIRD.setUniformInt("tex", 1);

// Create level
level = new Level();
}

public void run() {
init();

// Timer
long timer = System.currentTimeMillis();
long timeLast = System.nanoTime();
// Not time delta for checking time between frames
double timeDelta = 0;
double timeUpdate = 1000000000.0 / 60.0;

int countUpdate = 0;
int countRender = 0;

while (bRunning) {
long timeNow = System.nanoTime();
timeDelta += (timeNow - timeLast) / timeUpdate;
timeLast = timeNow;

// Every time delta reaches 1 do update
if (timeDelta >= 1.0) {
update();
countUpdate++;
timeDelta--;
}

render();
countRender++;

// Reset counters when one second has passed
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println(countUpdate + " ups, " + countRender + " fps");
countUpdate = 0;
countRender = 0;
}

// Window close event
if (glfwWindowShouldClose(window) == GL_TRUE)
bRunning = false;
}

glfwDestroyWindow(window);
glfwTerminate();
}

// Update
private void update() {
glfwPollEvents();
level.update();
}

// Render
private void render() {
// Clear previous frame
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Draw new things
level.render();

int error = glGetError();
if (error != GL_NO_ERROR)
System.out.println(error);

glfwSwapBuffers(window);
}

public static void main(String[] args) {
new Main().start();
}
}

*

Online spasi

  • *****
  • 2111
    • WebHotelier
Re: GLFW KeyCallback Only certain keys seem to work
« Reply #3 on: July 06, 2015, 09:37:23 »
Key input works fine for me with the above code. Could you describe the sequence of key presses/releases you're doing and the expected vs actual outcome?

*

Offline Lugen

  • *
  • 18
Re: GLFW KeyCallback Only certain keys seem to work
« Reply #4 on: July 06, 2015, 11:35:28 »
Key input works fine for me with the above code. Could you describe the sequence of key presses/releases you're doing and the expected vs actual outcome?
Interesting, might be worth to mention that I have a Swedish keyboard but that shouldn't make any difference right?
http://frontype.com/keyboarding/540px-Computer-keyboard-Sweden.svg.png

Right now I'm just printing the key id to console whenever the key callback is being called, to check which keys generate a response. The pattern seems to to be that only the buttons marked with red (see reference above) calls the callback and some other buttons (W , A , S, D, Enter, Backspace, + and perhaps more) works as well if pressed shortly after.

Am I being clear? To me it seems like there's some weird timing going on and/or polls being lost for some reason.

I also have controls set up for a player object to move around. The controls do actually work but only right after pressing those red buttons as mentioned.
Update method from the player class. Is executed after glfwPollEvents().
Code: [Select]
public void update() {
if (Input.keys[GLFW.GLFW_KEY_W])
position.y += 0.1f;
if (Input.keys[GLFW.GLFW_KEY_S])
position.y -= 0.1f;
if (Input.keys[GLFW.GLFW_KEY_A])
position.x -= 0.1f;
if (Input.keys[GLFW.GLFW_KEY_D])
position.x += 0.1f;
}

*

Online spasi

  • *****
  • 2111
    • WebHotelier
Re: GLFW KeyCallback Only certain keys seem to work
« Reply #5 on: July 06, 2015, 15:29:51 »
The pattern seems to to be that only the buttons marked with red (see reference above) calls the callback and some other buttons (W , A , S, D, Enter, Backspace, + and perhaps more) works as well if pressed shortly after.

That sounds very weird. Could you try on another PC or a different keyboard?

To me it seems like there's some weird timing going on and/or polls being lost for some reason.

Does it help if you enable vsync? Call glfwSwapInterval(1) after glfwMakeContextCurrent(window).

*

Offline Lugen

  • *
  • 18
Re: GLFW KeyCallback Only certain keys seem to work
« Reply #6 on: July 06, 2015, 17:54:29 »
The pattern seems to to be that only the buttons marked with red (see reference above) calls the callback and some other buttons (W , A , S, D, Enter, Backspace, + and perhaps more) works as well if pressed shortly after.

That sounds very weird. Could you try on another PC or a different keyboard?

Not at the moment sorry. It's weird indeed.

To me it seems like there's some weird timing going on and/or polls being lost for some reason.

Does it help if you enable vsync? Call glfwSwapInterval(1) after glfwMakeContextCurrent(window).

No difference. Seems like it was already enabled anyway.

Studying the console output the two "red keys" seem to pretty much enable any other key in the same way as mentioned. Also I noticed that pressing any other key while holding one of the "red keys" down stops their keycodes to get printed, so something is happening there. It's like those two buttons act like some kind of floodgate, blocking the rest of the keyboard.

Btw, doing input with the standard java libraries work fine. I haven't had any input problems with any linux applications before.

*

Online spasi

  • *****
  • 2111
    • WebHotelier
Re: GLFW KeyCallback Only certain keys seem to work
« Reply #7 on: July 06, 2015, 18:22:13 »
Sounds like GLFW cannot handle your keyboard layout properly. Have you tried switching layouts from the linux keyboard settings? What Linux distribution are you using?

*

Offline Lugen

  • *
  • 18
Re: GLFW KeyCallback Only certain keys seem to work
« Reply #8 on: July 06, 2015, 20:10:33 »
Sounds like GLFW cannot handle your keyboard layout properly. Have you tried switching layouts from the linux keyboard settings? What Linux distribution are you using?
Tried some of the English keyboard layouts (US, Canada, UK) but didn't seem to get any response at all.
I'm on Ubuntu 12.04, thinking of upgrading to 14.04 someday, just haven't bothered with it for the time being, just mentioning in case that's relevant. I also replaced the default desktop environment "Unity" with "Gnome Classic".

*

Online spasi

  • *****
  • 2111
    • WebHotelier
Re: GLFW KeyCallback Only certain keys seem to work
« Reply #9 on: July 06, 2015, 20:18:52 »
Could you try the Events demo? Try pressing a few keys, what output are you getting?

*

Offline Lugen

  • *
  • 18
Re: GLFW KeyCallback Only certain keys seem to work
« Reply #10 on: July 06, 2015, 21:59:51 »
Could you try the Events demo? Try pressing a few keys, what output are you getting?

Seems like it's working as it should. I can move the mouse cursor around and the console responds to any key presses with messages like this.
53.146: Window [0x7F5B80259F60] char mods h
53.146: Window [0x7F5B80259F60] char h


That's a positive sign. Will have a closer look at the code and see if I understand it. Anything particular with this setup I should take interest in?

*

Online spasi

  • *****
  • 2111
    • WebHotelier
Re: GLFW KeyCallback Only certain keys seem to work
« Reply #11 on: July 07, 2015, 09:24:59 »
The demo simply prints the events received to stdout. This is the output I see when pressing the 'H' key:

Quote
28.007: Window [0xE9E850] key [GLFW_KEY_H - 35] was pressed
28.008: Window [0xE9E850] char mods h
28.008: Window [0xE9E850] char h
28.075: Window [0xE9E850] key [GLFW_KEY_H - 35] was released

*

Online spasi

  • *****
  • 2111
    • WebHotelier
Re: GLFW KeyCallback Only certain keys seem to work
« Reply #12 on: July 07, 2015, 09:38:39 »
Looks like there is indeed an issue related to input method in the latest GLFW builds.

*

Offline Lugen

  • *
  • 18
Re: GLFW KeyCallback Only certain keys seem to work
« Reply #13 on: July 07, 2015, 11:07:22 »
The demo simply prints the events received to stdout. This is the output I see when pressing the 'H' key:

Quote
28.007: Window [0xE9E850] key [GLFW_KEY_H - 35] was pressed
28.008: Window [0xE9E850] char mods h
28.008: Window [0xE9E850] char h
28.075: Window [0xE9E850] key [GLFW_KEY_H - 35] was released

With that in mind I tried the demo again and noticed the same button enabling pattern. Only the "red keys" gives me the GLFW printouts.
The key next to "Backspace".
2.141: Window [0x7FA3CC268440] key [GLFW_KEY_EQUAL - 21] was pressed
2.220: Window [0x7FA3CC268440] key [GLFW_KEY_EQUAL - 21] was released

The key next to "Enter".
6.255: Window [0x7FD27826DFE0] key [GLFW_KEY_RIGHT_BRACKET - 35] was pressed
6.415: Window [0x7FD27826DFE0] key [GLFW_KEY_RIGHT_BRACKET - 35] was released

Same pattern as before. Some keys get GLFW messages after pressing this key.
9.922: Window [0x7FD6082705C0] key [GLFW_KEY_EQUAL - 21] was pressed
10.034: Window [0x7FD6082705C0] key [GLFW_KEY_EQUAL - 21] was released
10.162: Window [0x7FD6082705C0] key [GLFW_KEY_H - 43] was pressed
10.274: Window [0x7FD6082705C0] key [GLFW_KEY_H - 43] was released

And others after pressing this one.
51.018: Window [0x7FFAA4280760] key [GLFW_KEY_RIGHT_BRACKET - 35] was pressed
51.122: Window [0x7FFAA4280760] key [GLFW_KEY_RIGHT_BRACKET - 35] was released
51.218: Window [0x7FFAA4280760] key [GLFW_KEY_S - 39] was pressed
51.290: Window [0x7FFAA4280760] key [GLFW_KEY_S - 39] was released

I also get this when the program starts, but I assume the error is just a test?
---- [ Error callback test ] ----
[LWJGL] GLFW_NOT_INITIALIZED error
   Description : The GLFW library is not initialized
   Stacktrace  :
      test.Events.main(Events.java:42)
---- [ Error callback done ] ----
GLFW initialized
Window opened.
0.210: Window [0x7FFAA4280760] moved to 1, 28
0.229: Window [0x7FFAA4280760] restored
0.230: Window [0x7FFAA4280760] refreshed
0.230: Window [0x7FFAA4280760] cursor entered
0.231: Window [0x7FFAA4280760] gained focus

Looks like there is indeed an issue related to input method in the latest GLFW builds.
That makes sense if the reason why the keys aren't working is because they are being interpreted as characters. Pressing those two special keys seem to temporarily "correct" them.

*

Offline Lugen

  • *
  • 18
Re: GLFW KeyCallback Only certain keys seem to work
« Reply #14 on: July 31, 2015, 20:44:52 »
In case this info is useful. I recently switched to Ubuntu 14.04 and key input seems to work fine now. Still using the same version, 3.0.0a.