WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH 0 of 3][IOEMU] Fix keymap handling for vnc console

To: xen-devel <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH 0 of 3][IOEMU] Fix keymap handling for vnc console
From: John Haxby <john.haxby@xxxxxxxxxx>
Date: Thu, 11 Dec 2008 16:37:54 +0000
Delivery-date: Thu, 11 Dec 2008 08:38:34 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Thunderbird 2.0.0.18 (X11/20081119)
This is a slightly updated version of the patch I posted a little while ago. It is a patch against the ioemu-remote tree in xen-3.3-testing. I'll be sending a corresponding patch to qemu-devel when I've got my qemu build environment sorted out.

There are presently a few problems dogging keymap handling for the vnc console:

  * Some keystrokes that generate a symbol locally are ignored.

* Some keystrokes in some keymaps generate the wrong scancode and thence the wrong character

  * The capslock key is handled inconsistently

The first problem is typically caused by missing entries in the keymap. For example, the "Q" key in many European keyboards generates "@" and "Ω" in addition to the normal "q" and "Q" when used with the AltGr key. However, the keysym defintions in vnc_keysym.h are incomplete and so, for example, "Ω" will never be recognised even if it is in the keymap definition (which it often isn't).

The second problem is a little more subtle. The code presently assumes that there is a many-to-one mapping from keysyms to scancodes. So, for example, "q", "Q", "@" and "Ω" all generate the scancode 0x10. However, on a UK keyboard the "@" keysym can arise from typing either AltGr-Q (scancode 0x10) or Shift-apostrophe (scancode 0x28). For some keymaps this is particularly damaging -- for example in http://article.gmane.org/gmane.comp.emulators.qemu/32241 the "1", "4" and "6" keys should give "&", "'" (apostrophe) and "§" respectively but actually give "k", "b" and "s".

The final problem is related to the numlock handling problem that was fixed fairly recently. For that particular problem, the various keysyms that are generated when the only when the numlock key is pressed or released result in an implicit press or release of the numlock key in order to change the state of the key. In the case of the capslock key, however, it isn't, in general, possible to distinguish between a "A" generated from a capslock and one generated with a shift sequence.

The following patches are designed to fix these problems.

The first uses five keysym to scancode keymaps for plain, shifted, AltGr'd, shift-AltGr'd and numlocked keys to handle the many-to-many mapping from keysyms to scancodes. The current state of the shift and altgr keys that the guest is aware of is tracked and a keysym looked up in the corresponding map to find the right scancode. If the scancode is not defined in that keymap then the other keymaps are checked and implicit keypress or keyrelease events for shift and AltGr sent to produce the right scancode and modifier set to generate the correct keysym in the guest's application. The first lookup means that the right scancode will be generated for a keysym in all but the most pathological of cases; the second lookup means that, for example, a client UK keyboard will work correctly against a guest Belgian keyboard because the implicit shift and AltGr keypresses and releases will do the necessary shuffling behind the scenes.

The second patch adds the missing keysym names to vnc_keysym.h. Not all the X keysym names are in here, but there are enough to satisfy all the keysyms used by the keymaps presently defined.

The third and final patch corrects most of the keymap definitions. The ones I haven't changed are the ones I am unsure of -- the names do not always correspond that well to the xkb keymap names and for the non-european keyboards I have very little confidence that what I am typing is what is intended!

There is a remaining problem with the numlock key handling which is beyond the scope of these patches: if software running in the guest toggles the numlock key (for example, the X server) then the behaviour of the numlock key may become inverted. Also note that the initial state of the numlock key was wrong in the existing code, but that was easy to fix.

Finally, the two attached programs -- evkey.c and evconv.c -- can be used to help generate and test keymap definitions. The former, evkey, is Linux specific and matches up keysyms received through a small X window with the scancodes retrieved from a PS/2 keyboard (and it must be a PS/2 keyboard, USB keyboards generate different scancodes). The latter, evconv, uses the xen keymap to generate find the scancode and can be used to check that a keymap definition is going to give the expected scancodes for a given (X) keyboard mapping. Hopefully the comments at the head of each file will describe the intention sufficiently well.

jch

/*
 * Generate Xen keymaps
 *
 * Compile:
 *    cc -o evkey evkey.c -lX11
 *
 * Usage:
 *    evkey /usr/share/xen/qemu/keymaps/<prototype-keymap>
 *
 * The prototype keymap typically has "include common" and not much
 * else.  keysym to scancode lines not already in the protoype (or
 * anything it includes) will be emitted on the corresponding keypress
 * events.  The keypress MUST come from a PS/2 keyboard so the correct
 * scancode can be found.
 *
 * A complete and correct keymap that matches the current xkb keymap
 * will produce no output at all for any keypress.
 * 
 */
#include <ctype.h>
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <linux/input.h>

#define MAX_SCANCODE 255

typedef struct {
    int plain[MAX_SCANCODE];
    int shift[MAX_SCANCODE];
    int altgr[MAX_SCANCODE];
    int shift_altgr[MAX_SCANCODE];
    int numlock[MAX_SCANCODE];
} keysym_map_t;
    
const char *keyboard_name = "AT Translated Set 2 keyboard";

static Display *open_display (char *display_name, int argc, char **argv);
static void get_keyboard_info (Display *dpy, int *numlock_mask, int 
*altgr_mask);
static int open_keyboard(void);
static int get_lastkeypress (int fd);
static void load_keymap (char *path, keysym_map_t *map);
static void load_keymap1 (char *file, keysym_map_t *map);
static char *check_scancode (keysym_map_t *map, KeySym ks, int scancode, bool 
shift, bool altgr, bool numlock);
static void handler (int sig);

static volatile bool done = false;

int main (int argc, char **argv)
{
    Display *dpy;
    int numlock_mask = 0;
    int altgr_mask = 0;
    int evfd;
    keysym_map_t map;

    dpy = open_display(NULL, argc, argv);
    evfd = open_keyboard();
    get_keyboard_info(dpy, &numlock_mask, &altgr_mask);

    memset(&map, 0, sizeof(map));
    if (argv[1])
        load_keymap(argv[1], &map);

    sigaction(SIGINT, &((struct sigaction) { .sa_handler = handler }), NULL);

    while (!done) {
        XEvent event;
        XNextEvent(dpy, &event);
        if (event.type == KeyPress) {
            XKeyEvent *ev = (XKeyEvent *) &event;
            KeySym ks = NoSymbol;
            char *keyname;
            int scancode;
            char *msg = NULL;
            char str[256];

            XLookupString(ev, str, sizeof(str)-1, &ks, NULL);
            keyname = XKeysymToString(ks);
            if (!keyname)
                continue;

            if (ev->state & LockMask)
                fprintf(stderr, "warning: capslock pressed\n");

            scancode = get_lastkeypress(evfd);
            if (IsModifierKey(ks))
                msg = check_scancode(&map, ks, scancode, false, false, false);
            else if (ks != NoSymbol)
                msg = check_scancode(&map, ks, scancode,
                                     (ev->state & ShiftMask),
                                     (ev->state & altgr_mask),
                                     (ev->state & numlock_mask));
            if (msg) {
                if (ks == NoSymbol)
                    printf("%sNoSymbol\n", msg);
                else if (IsModifierKey(ks))
                    printf("%s%s 0x%02x\n", msg, keyname, scancode);
                else if (IsKeypadKey(ks))
                    printf("%s%s 0x%02x%s\n", msg, keyname, scancode,
                           (ev->state & numlock_mask) ? " numlock" : "");
                else
                    printf("%s%s 0x%02x%s%s\n", msg, keyname, scancode,
                           (ev->state & ShiftMask) ? " shift" : "",
                           (ev->state & altgr_mask) ? " altgr" : "");
                fflush(stdout);
            }
        }
    }
    exit(0);
}

static Display *open_display (char *display_name, int argc, char **argv)
{
    Display *dpy;
    XSizeHints hints;
    XSetWindowAttributes attr;
    Window w;

    if (!(dpy = XOpenDisplay(display_name))) {
        fprintf(stderr, "Can't open display\n");
        exit(1);
    }
    hints.width = hints.min_width = 100;
    hints.height = hints.min_height = 100;
    hints.flags = PMinSize;
    hints.x = hints.y = 0;
    memset(&attr, 0, sizeof(attr));
    attr.background_pixel = WhitePixel(dpy, DefaultScreen(dpy));
    attr.border_pixel = BlackPixel(dpy, DefaultScreen(dpy));
    attr.event_mask = KeyPressMask | KeyReleaseMask;
    w = XCreateWindow(dpy, DefaultRootWindow(dpy),
                      0, 0, 100, 100, 0, 0,
                      InputOutput, CopyFromParent,
                      CWBackPixel | CWBorderPixel | CWEventMask, &attr);
    XSetStandardProperties(dpy, w, "evkey", NULL, 0, argv, argc, &hints);
    XMapWindow(dpy, w);
    return dpy;
}

static void get_keyboard_info (Display *dpy,
                               int *numlock_mask,
                               int *altgr_mask)
{
    int min_keycode, max_keycode, keysyms_per_keycode;
    XModifierKeymap *map;
    int i, j;

    XDisplayKeycodes(dpy, &min_keycode, &max_keycode);
    XGetKeyboardMapping(dpy, min_keycode, max_keycode - min_keycode + 1, 
&keysyms_per_keycode);
    
    map = XGetModifierMapping(dpy);
    for (i = 0; i < 8*map->max_keypermod; i += map->max_keypermod) {
        for (j = 0; j < map->max_keypermod; j++) {
            if (map->modifiermap[i+j]) {
                int index = 0;
                KeySym ks = NoSymbol;
                while (ks == NoSymbol && index < keysyms_per_keycode)
                    ks = XKeycodeToKeysym(dpy, map->modifiermap[i+j], index++);
                if (*numlock_mask == 0 && ks == XK_Num_Lock)
                    *numlock_mask = 1 << (i / map->max_keypermod);
                else if (*altgr_mask == 0 && ks == XK_ISO_Level3_Shift)
                    *altgr_mask = 1 << (i / map->max_keypermod);
            }
        }
    }
}

static int selector (const struct dirent *dirent) {
    int n;
    return (sscanf(dirent->d_name, "event%d", &n) == 1);
}

static int cmp (const void *d1, const void *d2)
{
    int n1 = 0, n2 = 0;
    sscanf((*((struct dirent **) d1))->d_name, "event%d", &n1);
    sscanf((*((struct dirent **) d2))->d_name, "event%d", &n2);
    return n1 - n2;
}

static int open_keyboard ()
{
    struct dirent **namelist;
    int fd = -1, i, n;

    if ((n = scandir("/dev/input", &namelist, selector, cmp)) < 0) {
        perror("/dev/input");
        exit(1);
    }
    for (i = 0; i < n; i++) {
        char file[sizeof("/dev/input/") + strlen(namelist[i]->d_name)];
        int version;
        char name[256];
        
        sprintf(file, "/dev/input/%s", namelist[i]->d_name);
        if ((fd = open(file, O_RDONLY)) < 0) {
            perror(file);
            exit(1);
        }
        if (ioctl(fd, EVIOCGVERSION, &version) >= 0 &&
            ioctl(fd, EVIOCGNAME(sizeof(name)), name) >= 0 &&
            strcasecmp(name, keyboard_name) == 0)
            return fd;
        close(fd);
    }
    fprintf(stderr, "Cannot find input device for \"%s\"\n", keyboard_name);
    exit(1);
}

static int get_lastkeypress (int fd)
{
    struct input_event ev[64];
    int keycode = -1;
    int scancode = -1;
    int i, n;

    if ((n = read(fd, ev, sizeof(ev))) < sizeof(struct input_event)) {
        perror("read event");
        exit(1);
    }
    for (i = 0; i < n/sizeof(struct input_event); i++) {
        if (ev[i].type == EV_MSC && ev[i].code == MSC_SCAN)
            scancode = ev[i].value;
        if (ev[i].type == EV_KEY && ev[i].value == 1 && scancode >= 0) {
            keycode = scancode;
            scancode = -1;
        }
    }
    return keycode;
}

static void load_keymap (char *path, keysym_map_t *map)
{
    if (strchr(path, '/')) {
        char *dir = strdup(path);
        char *file = strrchr(dir, '/');
        *file++ = '\0';
        chdir(dir);
        load_keymap1(file, map);
        free(dir);
    } else {
        load_keymap1(path, map);
    }
}

static void load_keymap1 (char *file, keysym_map_t *map)
{
    char line[1024];
    FILE *f;

    if (!(f = fopen(file, "r"))) {
        perror(file);
        exit(1);
    }
    while (fgets(line, sizeof(line), f)) {
        char *ptr = strchr(line, '#');
        char *keyname, *p1, *p2;
        KeySym ks;
        int code = -1;
        bool shift = false;
        bool altgr = false;
        bool addupper = false;
        bool numlock = false;
        bool inhibit = false;
        
        if (ptr)
            *ptr-- = '\0';
        else
            ptr = &line[strlen(line)-1];
        while (isspace(*ptr))
            *ptr-- = '\0';

        if (sscanf(line, "include %as", &p1) == 1) {
            load_keymap(p1, map);
            free(p1);
            continue;
        } else if (sscanf(line, "map %i", &code) == 1) {
            continue;
        } else if (sscanf(line, "%as %i %as %as", &keyname, &code, &p1, &p2) == 
4) {
            altgr = (strcmp(p1, "altgr") == 0 || strcmp(p2, "altgr") == 0);
            shift = (strcmp(p1, "shift") == 0 || strcmp(p2, "shift") == 0);
            free(p1);
            free(p2);
        } else if (sscanf(line, "%as %i %as", &keyname, &code, &p1) == 3) {
            altgr = (strcmp(p1, "altgr") == 0);
            shift = (strcmp(p1, "shift") == 0);
            addupper = (strcmp(p1, "addupper") == 0);
            numlock = (strcmp(p1, "numlock") == 0);
            inhibit = (strcmp(p1, "inhibit") == 0);
            free(p1);
        } else if (sscanf(line, "%as %i", &keyname, &code) != 2) {
            continue;
        }

        if (!keyname) {
            fprintf(stderr, "malformed line: \"%s\"\n", line);
            continue;
        }
        if ((ks = XStringToKeysym(keyname)) == NoSymbol) {
            fprintf(stderr, "Unknown keysym \"%s\"\n", keyname);
            free(keyname);
            continue;
        }
        free(keyname);
        if (inhibit)
            continue;
        if (code <= 0 || code >= MAX_SCANCODE) {
            fprintf(stderr, "Scancode out of range at \"%s\"\n", line);
            continue;
        }
        if (numlock)
            map->numlock[code] = ks;
        else if (shift && altgr)
            map->shift_altgr[code] = ks;
        else if (shift)
            map->shift[code] = ks;
        else if (altgr)
            map->altgr[code] = ks;
        else {
            map->plain[code] = ks;
            if (addupper)
                /* this is somewhat dubious */
                map->shift[code] = ks + 'A' - 'a';
        }
    }
}

static char *check_scancode (keysym_map_t *map,
                             KeySym ks, int scancode,
                             bool shift, bool altgr, bool numlock)
{
    static char msg[128];
    int *mmap;

    if (numlock)
        mmap = map->numlock;
    else if (shift & altgr)
        mmap = map->shift_altgr;
    else if (shift)
        mmap = map->shift;
    else if (altgr)
        mmap = map->altgr;
    else
        mmap = map->plain;

    if (scancode <= 0 || scancode >= MAX_SCANCODE)
        snprintf(msg, sizeof(msg), "# scancode %#x out of range\n# ", scancode);
    else if (mmap[scancode] == 0)
        return "";
    else if (mmap[scancode] != ks)
        return "";
    else
        return NULL;

    return msg;
}

static void handler (int sig) {
    done = true;
    exit(0);
}
/*
 * Test Xen keymaps
 *
 * Compile:
 *    cc -o evconv evconv.c -lX11
 *
 * Usage:
 *    evconv /usr/share/xen/qemu/keymaps/<keymap>
 *
 * The keysyms coming from a keypress or keyrelease in a small X
 * window are matched to the corresponding scancode from a PS/2
 * keyboard (and it must be a PS/2 keyboard: USB keyboards won't
 * work).  Each distinct keypress or keyrelese is printed out as the
 * corresponding scancode and keysym.  For example, "Q", "Shift-Q"
 * "AltGr-Q" and "Shift-Altgr-Q" should all produce the scancode 0x10
 * although they will, of course, result in four different keysyms.
 * 
 */
#include <ctype.h>
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

#ifdef USE_VNC_KEYSYM
#include "vnc_keysym.h"
#endif

#define MAX_SCANCODE 255

struct ks {
    int keysym;
    int scancode;
};

typedef struct {
    int n;
    struct ks k[MAX_SCANCODE];
} keysym_map_t;

#define KEY_LOCALSTATE 0x1
#define KEY_KEYPAD     0x2

typedef struct {
    keysym_map_t plain;
    keysym_map_t shift;
    keysym_map_t altgr;
    keysym_map_t shift_altgr;
    keysym_map_t numlock;
    unsigned char flags [MAX_SCANCODE];
} keysym_maps_t;
    
const char *keyboard_name = "AT Translated Set 2 keyboard";

static Display *open_display (char *display_name, int argc, char **argv);
static void get_keyboard_info (Display *dpy, int *numlock_mask, int 
*altgr_mask);
static void load_keymap (char *path, keysym_maps_t *map);
static void load_keymap1 (char *file, keysym_maps_t *map);
static void handler (int sig);
static void prepare_keymap(keysym_maps_t *);
static int lookup_scancode(keysym_map_t *map, int keysym);
static int lookup_keysym (const char *name);

static volatile bool done = false;

int main (int argc, char **argv)
{
    Display *dpy;
    int numlock_mask = 0;
    int altgr_mask = 0;
    keysym_maps_t map;
    KeySym last = NoSymbol;

    dpy = open_display(NULL, argc, argv);
    get_keyboard_info(dpy, &numlock_mask, &altgr_mask);

    memset(&map, 0, sizeof(map));
    if (argv[1])
        load_keymap(argv[1], &map);
    prepare_keymap(&map);
    sigaction(SIGINT, &((struct sigaction) { .sa_handler = handler }), NULL);

    while (!done) {
        XEvent event;
        XNextEvent(dpy, &event);
        if (event.type == KeyPress || event.type == KeyRelease) {
            XKeyEvent *ev = (XKeyEvent *) &event;
            KeySym ks = NoSymbol;
            char *keyname;
            char str[256];
            int scancode;

            XLookupString(ev, str, sizeof(str)-1, &ks, NULL);
            if (last == ks) {
                if (event.type == KeyRelease)
                    last = NoSymbol;
                continue;
            }
            if (event.type == KeyPress)
                last = ks;
            keyname = XKeysymToString(ks) ?: "VoidSymbol";
            if ((scancode = lookup_scancode(&map.plain, ks)))
                printf("%02x %s%s%s\n", scancode, keyname,
                       (map.flags[scancode] & KEY_LOCALSTATE) ? " (localstate)" 
: "",
                       (map.flags[scancode] & KEY_KEYPAD) ? " (numlock off)" : 
"");
            if ((scancode = lookup_scancode(&map.shift, ks)))
                printf("%02x %s (shift)\n", scancode, keyname);
            if ((scancode = lookup_scancode(&map.altgr, ks)))
                printf("%02x %s (altgr)\n", scancode, keyname);
            if ((scancode = lookup_scancode(&map.shift_altgr, ks)))
                 printf("%02x %s (shift altgr)\n", scancode, keyname);
            if ((scancode = lookup_scancode(&map.numlock, ks)))
                printf("%02x %s (numlock on)\n", scancode, keyname);
            fflush(stdout);
        }
    }
    exit(0);
}

static Display *open_display (char *display_name, int argc, char **argv)
{
    Display *dpy;
    XSizeHints hints;
    XSetWindowAttributes attr;
    Window w;

    if (!(dpy = XOpenDisplay(display_name))) {
        fprintf(stderr, "Can't open display\n");
        exit(1);
    }
    hints.width = hints.min_width = 100;
    hints.height = hints.min_height = 100;
    hints.flags = PMinSize;
    hints.x = hints.y = 0;
    memset(&attr, 0, sizeof(attr));
    attr.background_pixel = WhitePixel(dpy, DefaultScreen(dpy));
    attr.border_pixel = BlackPixel(dpy, DefaultScreen(dpy));
    attr.event_mask = KeyPressMask | KeyReleaseMask;
    w = XCreateWindow(dpy, DefaultRootWindow(dpy),
                      0, 0, 100, 100, 0, 0,
                      InputOutput, CopyFromParent,
                      CWBackPixel | CWBorderPixel | CWEventMask, &attr);
    XSetStandardProperties(dpy, w, "evkey", NULL, 0, argv, argc, &hints);
    XMapWindow(dpy, w);
    return dpy;
}

static void get_keyboard_info (Display *dpy,
                               int *numlock_mask,
                               int *altgr_mask)
{
    int min_keycode, max_keycode, keysyms_per_keycode;
    XModifierKeymap *map;
    int i, j;

    XDisplayKeycodes(dpy, &min_keycode, &max_keycode);
    XGetKeyboardMapping(dpy, min_keycode, max_keycode - min_keycode + 1, 
&keysyms_per_keycode);
    
    map = XGetModifierMapping(dpy);
    for (i = 0; i < 8*map->max_keypermod; i += map->max_keypermod) {
        for (j = 0; j < map->max_keypermod; j++) {
            if (map->modifiermap[i+j]) {
                int index = 0;
                KeySym ks = NoSymbol;
                while (ks == NoSymbol && index < keysyms_per_keycode)
                    ks = XKeycodeToKeysym(dpy, map->modifiermap[i+j], index++);
                if (*numlock_mask == 0 && ks == XK_Num_Lock)
                    *numlock_mask = 1 << (i / map->max_keypermod);
                else if (*altgr_mask == 0 && ks == XK_ISO_Level3_Shift)
                    *altgr_mask = 1 << (i / map->max_keypermod);
            }
        }
    }
}

static void load_keymap (char *path, keysym_maps_t *map)
{
    if (strchr(path, '/')) {
        char *dir = strdup(path);
        char *file = strrchr(dir, '/');
        *file++ = '\0';
        chdir(dir);
        load_keymap1(file, map);
        free(dir);
    } else {
        load_keymap1(path, map);
    }
}

static void load_keymap1 (char *file, keysym_maps_t *map)
{
    char line[1024];
    FILE *f;

    if (!(f = fopen(file, "r"))) {
        perror(file);
        exit(1);
    }
    while (fgets(line, sizeof(line), f)) {
        char *ptr = strchr(line, '#');
        char *keyname, *p1, *p2;
        KeySym ks;
        int code = -1;
        bool shift = false;
        bool altgr = false;
        bool addupper = false;
        bool numlock = false;
        bool inhibit = false;
        
        if (ptr)
            *ptr-- = '\0';
        else
            ptr = &line[strlen(line)-1];
        while (isspace(*ptr))
            *ptr-- = '\0';

        if (sscanf(line, "include %as", &p1) == 1) {
            load_keymap(p1, map);
            free(p1);
            continue;
        } else if (sscanf(line, "map %i", &code) == 1) {
            continue;
        } else if (sscanf(line, "%as %i %as %as", &keyname, &code, &p1, &p2) == 
4) {
            altgr = (strcmp(p1, "altgr") == 0 || strcmp(p2, "altgr") == 0);
            shift = (strcmp(p1, "shift") == 0 || strcmp(p2, "shift") == 0);
            free(p1);
            free(p2);
        } else if (sscanf(line, "%as %i %as", &keyname, &code, &p1) == 3) {
            altgr = (strcmp(p1, "altgr") == 0);
            shift = (strcmp(p1, "shift") == 0);
            addupper = (strcmp(p1, "addupper") == 0);
            numlock = (strcmp(p1, "numlock") == 0);
            inhibit = (strcmp(p1, "inhibit") == 0);
            free(p1);
        } else if (sscanf(line, "%as %i", &keyname, &code) != 2) {
            continue;
        }

        if (!keyname) {
            fprintf(stderr, "malformed line: \"%s\"\n", line);
            continue;
        }
        if ((ks = lookup_keysym(keyname)) == 0) {
            fprintf(stderr, "Unknown keysym \"%s\"\n", keyname);
            free(keyname);
            continue;
        }
        free(keyname);
        if (inhibit)
            continue;
        if (code <= 0 || code >= MAX_SCANCODE) {
            fprintf(stderr, "Scancode out of range at \"%s\"\n", line);
            continue;
        }
        if (numlock)
            map->numlock.k[code].keysym = ks;
        else if (shift && altgr)
            map->shift_altgr.k[code].keysym = ks;
        else if (shift)
            map->shift.k[code].keysym = ks;
        else if (altgr)
            map->altgr.k[code].keysym = ks;
        else {
            map->plain.k[code].keysym = ks;
            if (addupper)
                /* this is somewhat dubious */
                map->shift.k[code].keysym = ks + 'A' - 'a';
        }
    }
}

static void handler (int sig) {
    done = true;
    exit(0);
}

int cmp (const void *a, const void *b) {
    return ((struct ks *) b)->keysym - ((struct ks *) a)->keysym;
}

static void sort_map (keysym_map_t *map) {
    int i;
    for (i = 0; i < MAX_SCANCODE; i++)
        map->k[i].scancode = i;
    qsort(map->k, MAX_SCANCODE, sizeof(struct ks), cmp);
    for (map->n = 0; map->n < MAX_SCANCODE; map->n++)
        if (!map->k[map->n].keysym)
            break;
}
    
static void prepare_keymap (keysym_maps_t *map)
{
    int i;
    for (i = 0; i < MAX_SCANCODE; i++) {
        if (!(map->shift.k[i].keysym || map->altgr.k[i].keysym || 
map->shift_altgr.k[i].keysym))
            map->flags[i] |= KEY_LOCALSTATE;
        if (map->numlock.k[i].keysym)
            map->flags[i] |= KEY_KEYPAD;
    }
    sort_map(&map->plain);
    sort_map(&map->shift);
    sort_map(&map->altgr);
    sort_map(&map->shift_altgr);
    sort_map(&map->numlock);
}

static int lookup_scancode (keysym_map_t *map, int keysym) {
    int l = 0, r = map->n-1;

    while (l <= r) {
        int m = (l + r)/2;
        if (map->k[m].keysym == keysym)
            return map->k[m].scancode;
        else if (map->k[m].keysym < keysym)
            r = m-1;
        else
            l = m+1;
    }
    return 0;
}

#ifdef USE_VNC_KEYSYM
static int keysym_cmp (const void *a, const void *b) {
    return strcmp(((name2keysym_t *) a)->name, ((name2keysym_t *) b)->name);
}

static int lookup_keysym (const char *name)
{
    int l, r;
    static int n = -1;

    if (n < 0) {
        for (n = 0; name2keysym[n].name; n++);
        qsort(name2keysym, n, sizeof(name2keysym_t), keysym_cmp);
    }

    l = 0;
    r = n-1;
    while (l <= r) {
        int m = (l + r)/2;
        int cmp = strcmp(name2keysym[m].name, name);
        if (cmp < 0)
            l = m + 1;
        else if (cmp > 0)
            r = m - 1;
        else
            return name2keysym[m].keysym;
    }
    if (name[0] == 'U') {
        /* unicode symbol key */
        char *ptr;
        int k = strtol(name+1, &ptr, 16);
        return *ptr ? 0 : k;
    }
    return 0;
}
#else
static int lookup_keysym (const char *name) {
    return XStringToKeysym(name);
}
#endif
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel