Search code examples
cx11xlib

Why is XKeysymToKeycode() making all of my keys lowercase?


I'm currently having a problem with Xlib where whenever I call XKeysymToKeycode() and pass in an uppercase KeySym, it returns a lowercase KeyCode. Google doesn't really seem to have an answer to this question, or too much documentation at all on the functions I'm using, for that matter.

Here's the code I am using:

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/extensions/XTest.h>

int main(void) {
    Display *display;
    char *ptr;
    char c[2] = {0, 0};
    KeySym ksym;
    KeyCode kcode;

    display = XOpenDisplay(0);
    ptr = "Test";

    while (*ptr) {
        c[0] = *ptr;
        ksym = XStringToKeysym(c);
        printf("Before XKeysymToKeycode(): %s\n", XKeysymToString(ksym));
        kcode = XKeysymToKeycode(display, ksym);
        printf("Key code after XKeysymToKeycode(): %s\n", XKeysymToString(XKeycodeToKeysym(display, kcode, 0)));
        ptr++;
    }

    XCloseDisplay(display);

    return 0;
}    

It can be compiled with gcc -o sendkeys sendkeys_min.c -lX11 -lXtst -g -Wall -Wextra -pedantic -ansi (Assuming it has been saved as sendkeys_min.c.)

The current output is the following:

Before XKeysymToKeycode(): T
Key code after XKeysymToKeycode(): t
Before XKeysymToKeycode(): e
Key code after XKeysymToKeycode(): e
Before XKeysymToKeycode(): s
Key code after XKeysymToKeycode(): s
Before XKeysymToKeycode(): t
Key code after XKeysymToKeycode(): t

The expected output, is, of course, that the first T in "Test" is still uppercase after being ran through XKeysymToKeycode(). (Note that this is not my actual program, but a simplified version for posting here. In the actual program, I am sending key events with the resulting keycode, and the keys sent still have the problem exhibited here (They all become lowercase))


Solution

  • KeySyms and KeyCodes are semantically different, and there is not a 1-1 relationship between them.

    • A KeyCode is an arbitrary small integer representing a key on the keyboard. (Not a character. A key.) Xlib requires that key codes be in the range [8, 255], but fortunately most keyboards have only a bit more than 100 keys.

    • A KeySym is a representation of some actual character associated with a key. There will almost always be several of these: lower- and upper-case letters correspond to the same key on most terminal layouts.

    So there is no such thing as an "upper-case" or "lower-case" KeyCode. When you get the KeyCode corresponding to a Keysym, you are actually losing information.

    In Xlib, a given key has at least four corresponding KeySyms (lower-case, upper-case, alternate lower-case, alternate upper-case), although some might be unassigned. When you ask for the KeySym corresponding to a KeyCode, you need to supply an index; index 0 (as in your code) will get the unshifted unmodified character.

    For a given keypress, the translation to a KeySym will take into account the state of the modifier keys. There are eight of these, including the Shift and Lock modifiers. Ignoring Lock, which complicates the situation, the shift modifier key would normally turn lower-case letters into their upper-case equivalents (for alphabetic keys).

    Keyboard handling is much more complicated than that brief summary, but it's a start.

    For your task, you probably should take a look at XkbKeysymToModifiers.