Unexpected NULL return from `XkbGetKeyboard` and further `xkbdescptr->names->num_keys == 0` regardless of bitmask passed to `XkbGet[Keyboard|Map]`
I'm building a window abstraction layer for personal use, and I'm at the point of consolidating keycodes.
Consider this small program:
// main.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/XKBlib.h>
int
main(void)
{
Display *display = XOpenDisplay(NULL);
if (!display) {
fputs("XOpenDisplay\n", stderr);
exit(1);
}
int screen = DefaultScreen(display);
struct {
int opcode;
int event_base;
int error_base;
int major;
int minor;
} xkb;
if (!XkbQueryExtension(display,
&xkb.opcode,
&xkb.event_base,
&xkb.error_base,
&xkb.major,
&xkb.minor))
{
fputs("XkbQueryExtension\n", stderr);
exit(1);
}
#if 1 // XkbDescPtr is null at times, while not being mentioned in the manpages
{
XkbDescPtr xdp = XkbGetKeyboard(display, XkbNamesMask, XkbUseCoreKbd);
if (!xdp) {
fputs("Null with XkbGetKeyboard(XkbNamesMask)\n", stderr);
}
else {
puts("XkbGetKeyboard(XkbNamesMask) returns as expected.");
}
}
#endif
#if 1 // num_keys via XkbGetKeyboard
{
XkbDescPtr xdp = XkbGetKeyboard(display, XkbAllComponentsMask, XkbUseCoreKbd);
if (!xdp) {
fputs("XkbGetKeyboard\n", stderr);
exit(1);
}
printf("names %p\n", xdp->names);
printf("num_keys %d\n", xdp->names->num_keys);
printf("num_key_aliases %d\n", xdp->names->num_key_aliases);
for (int i = 8; i < 16; ++i) { // 8..16 just for brevity
char buf[XkbKeyNameLength+1] = {};
strncpy(buf, xdp->names->keys[i].name, XkbKeyNameLength);
printf("%d:\t%s\n", i, buf);
}
}
#endif
#if 1 // num_keys via XkbGetMap
{
XkbDescPtr xdp = XkbGetMap(display, 0, XkbUseCoreKbd);
if (!xdp) {
fputs("XkbGetMap\n", stderr);
exit(1);
}
XkbGetNames(display, XkbKeyNamesMask | XkbKeyAliasesMask, xdp);
printf("names %p\n", xdp->names);
printf("num_keys %d\n", xdp->names->num_keys);
printf("num_key_aliases %d\n", xdp->names->num_key_aliases);
for (int i = 8; i < 16; ++i) { // 8..16 just for brevity
char buf[XkbKeyNameLength+1] = {};
strncpy(buf, xdp->names->keys[i].name, XkbKeyNameLength);
printf("%d:\t%s\n", i, buf);
}
}
#endif
XCloseDisplay(display);
return 0;
}
Here is my machine:
$ make
pacman -Qi libx11 | head -n 3
Name : libx11
Version : 1.8.1-2
Description : X11 client-side library
uname -a
Linux archlinux 5.18.9-arch1-1 #1 SMP PREEMPT_DYNAMIC Sat, 02 Jul 2022 21:03:06 +0000 x86_64 GNU/Linux
cc --version
cc (GCC) 12.1.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
cc -Og -ggdb -lX11 main.c
Here is the program output:
$ ./a.out
Null with XkbGetKeyboard(XkbNamesMask)
names 0x563341aae3e0
num_keys 0
num_key_aliases 72
8:
9: ESC
10: AE01
11: AE02
12: AE03
13: AE04
14: AE05
15: AE06
names 0x563341ab1750
num_keys 0
num_key_aliases 72
8:
9: ESC
10: AE01
11: AE02
12: AE03
13: AE04
14: AE05
15: AE06
In the first block, I would expect XkbGetKeyboard(display, XkbNamesMask, XkbUseCoreKbd)
to return a usable XkbDescPtr instead of NULL. According to the manpages:
XkbGetKeyboard allocates and returns a pointer to a keyboard description. It queries the server for those components specified in the which parameter for device device_spec and copies the results to the XkbDescRec it allocated. The remaining fields in the keyboard description are set to NULL. The valid masks for which are those listed in Table 1.
Instead, I have to specify at the very least XkbServerMapMask | XkbNamesMask
to get a non-NULL result. I recognize that per the XKBlib spec (https://www.x.org/releases/X11R7.7/doc/libX11/XKB/xkblib.pdf) there are various dependencies among the members, but a heads up somewhere in the docs about this would be nice.
Lastly, in the last two blocks, no matter which way I call it, the XkbNamesPtr
always has num_keys == 0
. I don't think it's my issue either because GLFW completely ignores the field in it's own X11 wrapper (https://github.com/glfw/glfw/blob/36f0bf00a92b15e301bb28e840a4361e0b74b123/src/x11_init.c#L225). That said, num_key_aliases
seems to be reporting something.
P.S., is the XkbNamesPtr->keys
array guaranteed to map one-to-one with X11 KeyCodes (as GLFW's source code implies)?
Thanks for your time.