To some extent, the way X treats keyboard input is more complicated than handling the pointing device events (or many other events). The information about a key in the event structure isn't suitable for immediate use, instead it has to go through one of several conversion stages before it becomes useful to the application. The main reason is that X is designed to support all kinds of keyboards. However, the drawback is increased complexity.
Keyboard input appears in three ``flavours'': as keycodes, keysyms or keystrings. Naturally, M*TIF adds a fourth one: the CSF keysyms. They are a special set of keysyms. Figure shows how keycodes, keysyms and keystrings relate.
A keycode is a hardware-dependent coding of the key being pressed or released. Thus, keycodes aren't really usefull to LESSTIF application writers. With the help of the keyboard mapping, every Xlib and/or Xt intrinsics client converts the hardware-dependent keycodes into hardware-independent keysyms. These keysyms are integers representing the symbol engraved on a key (``a'', ``A'', ``+'' as well as ``Shift'', ``PageDn'' and other ones). The keyboard mapping is read from the server and cached to speed up look-ups and prevent unnecessary round-trips to the server. The translation from keycodes to keysyms can be done with XtTranslateKeycode(). This calls the currently registered key translator procedure, which is XmTranslateKey() by default. The translation manager calls the key translator procedure, too.
Keysyms that represent printable characters can be further translated into keystrings by calling XTranslateKey(). This mapping between keysyms and keystrings is not stored in the X server, but rather hardwired into the Xlib.