Key callback sometimes reports key == -1 for all function keys

I have built GLFW from source on Linux, commit 6aca3e99 (master~4 at the time of writing).

It mostly works as intended, but I can consistently reproduce one issue if I start my application after changing the keyboard layout via XFCE’s keyboard shortcut. If I do that, pressing any function key will deliver a key value of minus one in the key callback.

More precisely, my standard configuration has a two keyboard layouts: SE (default) and US. If I stay in the default layout, no problem (pressing escape will deliver key==256 for instance). But if I toggle the keyboard layout to US via the configurable XFCE keyboard shortcut or by pressing the xfce4-xkb-plugin button, and then start my application, I systematically get the problem: the key callback delivers key==-1 for all function keys. Non-function keys still seem to work fine. When in that state, switching back to SE layout does not come around the issue. Please note that what I am using here is as far as I know the standard way to toggle the keyboard layout in XFCE.

However, the US layout is not a problem in itself. If, instead of using the XFCE utilities, I change the keyboard layout by typing setxkbmap us in a terminal and start my application after that, everything works fine.

I have therefore tried to understand the difference in state between these two procedures, and I have found one: when I use setxkbmap us (or setxkbmap se for that matter), my double-layout is disabled, which it is not when I use XFCE utilities: setxkbmap -query shows layout: se,us after XFCE layout switch, but shows layout: us or layout: se after the keyboard switch.

So it seems to be the combination multiple keyboard layouts + non default layout selected, that triggers the issue.

At last, it could be worth mentioning that the scancode always seems to be correct (the problem is only with the key value).

Since GLFW seems like a very good cross-platform library, I hope there exists a solution for this problem.

Thanks in advance for any help.

1 Like

This sounds like a bug worth posting in the GLFW issues.

If you’re able to debug a bit further this could help a lot. The key table is initialized in x11_init.c createKeyTables, with the table defaulted to -1 at the start. By debugging it you might find out what’s causing this issue on your system and that would help speed up any fix.

@dougbinks, I’m happy to debug more. I’m just wondering what procedure you would recommend.

My current project does not have the GLFW source files as a dependency. After building GLFW, I have “make installed” it, and I’m just relying on CMake to find the headers and link GLFW with my application.

To debug GLFW, I guess I should start from one of the examples in the GLFW source tree? Then I guess the GLFW source files would be an explicit dependency? Also, are there any particular build flags I should use to debug GLFW?

Any advice is appreciated.

Actually, some good news, I guess, I can reproduce the issue with the triangle-opengl as is. Also, I am using CLion and if I open the top directory of a new clone of GLFW, it just builds everything out-of-the-box. I will now try to break in the GLFW code.

Excellent - thank you for this.

Adding printf’s to x11_init.c to see what the name variable is might help if all else fails.

Tricky.

As far as I can see, _glfw.x11.xkb.group is zero when I use se (default). Then XkbKeycodeToKeysym(_glfw.x11.display, scancode, _glfw.x11.xkb.group, 0) returns the correct value (0xff1b for scancode 9).

But when I switch to us before starting the application, _glfw.x11.xkb.group is one, which looks logical, but then XkbKeycodeToKeysym(_glfw.x11.display, scancode, _glfw.x11.xkb.group, 0) returns zero (bad).

Note that the level parameter (the last one of XkbKeycodeToKeysym()) makes no difference. The function is invoked twice in translateKeyCode() with level 1 and 0 and the return value is the same in both cases.

I don’t really know why the incorrect value is returned when group is one. Any idea?

I have also just tried to change the group value to zero with the debugger before the second XkbKeycodeToKeysym() invokation, in the us case, but it makes no difference.

I’m quite a beginner at that kind of stuff, but this stackoverflow answer seems to suggest that xcb should cover all keyboard needs, without ever needing to use XKB. I have felt like learning xcb a few times. Maybe now is the occasion…

Thank you for reporting this! It is indeed a bug in GLFW, with a PR in the process of being merged.

The PR works but is specific to the evdev keycode set so I’m expanding it right now. If you’re on a modern Linux system it will likely work for you without modification but it won’t yet on servers like Cygwin/X or on some non-PC hardware.

The function keys likely only have a single group. The existing code in GLFW incorrectly assumes that every key has the same number of groups but in XKB this can vary per key. You can see the XKB version your setup with xkbcomp -o myfilename.txt $DISPLAY.

GLFW needs to use XKB to be able to map GLFW_KEY_* constants to physical keys, as key symbols vary between layouts. The core protocol only provides undifferentiated keycodes.

1 Like

@elmindreda, great that this is a known issue that already has a solution. It’s not like I can’t come around it, so it’s perfectly OK for me to wait for the merge. It was interesting to read that @ZenulAbidin basically was in the same situation as I was, and had pretty much drawn the same conclusion, although he obviously went much further than me, since he implemented a solution.

A few thoughts:

  • I do not really understand why setting _glfw.x11.xkb.group to zero in the debugger did not solve the issue when I tested that yesterday, but I assume your coming fix will work for me anyway.
  • I am a little confused by the GLFW release scheme. I see a mention of “milestone 3.3.3” in the pull request, but the main GLFW site seems to indicate that the next release will be 3.4 (oh maybe I get it: there are several milestones on the way to a release, right?). In any case, my current working procedure is to just pull latest master, build it myself, and install it. I supposed there is nothing wrong with that procedure?
  • I’d be happy to somehow be notified when the fix is merged. What’s the best way to achieve that?

If you want me to test something, I’d be happy to do that. In that case, please tell me exactly what commit you want me to test.

Thanks a lot for your amazing work.

I guess I won’t learn xcb this time either…

1 Like

Sorry for the late response, I wasn’t following discourse lately. So let me clarify some of the issues and quirks I experienced when debugging this issue.

3.3.3 is the next bugfix release. It doesn’t have new features, those will be delayed until 3.4. Originally my PR was to be merged in 3.3.2 but for some reason it was delayed to 3.3.3.

In my case I had a primary, default arabic keyboard layout (it’s group 0 for me) and an auxiliary, secondary en_US layout (group 1 for me). I only experienced this problem if I start a GLFW program while using my secondary, which happened to be english, keyboard layout. It doesn’t happen if I start it while using my primary arabic layout for some reason.

The commit that introduced this bug was https://github.com/glfw/glfw/commit/b3eb6dd38b5390f3d5a5bd00b66cec1bdb56e49d, ( X11: Query and keep track of Xkb group index). This commit solves a problem where only keyboard input from the primary keyboard layout is returned correctly. Before then, input while using secondary keyboard layouts would sometimes cause the wrong characters to be returned.

Maybe when a program opens an X11 connection the X11 display initializes it to use group 0, the first keyboard layout (the “group” in X terminology). So if that’s true then the side effect of that fix was that only keys on group 0, the primary character set, were recognized, and that explains why the problem goes away when I change keyboard layouts. Since function keys were not being recognized I suspect they were only on my secondary en_US keyboard layout “group 1”.

So what I did in x11_init.c was dispense with the second keycode translation, which was done in translateKeyCode(), and instead took all the character names from the evdev keycode set and assigned them in the first keycode translation, the one that’s done in createKeyTables. My assumption for doing this was that I thought GLFW doesn’t run on very old Linux systems, which I might be wrong about that, and reasoned that since most Linux kernels in circulation use only evdev, that I just make a fix specific to evdev.

I also didn’t know that not all Unix systems were using evdev, Cygwin in particular. In fact, I only just realized that GLFW can be used with package managers like Cygwin and MinGW, as I didn’t have those at hand to test against when I made this PR. But I’m still wondering what non-PC hardware can run GLFW, are they perhaps mobile operating systems?

This particular pull request also taught me a hard lesson not to merge PRs using your master branch on github, or you won’t be able to pull new changes to your fork until the PR is merged or closed. But I can live with that.

1 Like

Thank you for the great explanation!

I just had to learn more about XKB to be of help with this PR and 3.3.2 needed to go out quickly because of another already fixed issue.

Mostly I’m worried about the BSDs. They have GLFW packages, run on many non-PC platforms and do not use evdev. That’s a small demographic but I’d like not to break things for it if possible.

You can subscribe to the GitHub issue for notifications. I’ll also post in this thread once the issue is resolved.

Thank you!

The proposed changes are now in the x11-xkb-key-names-r2 branch.