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
|