diff options
Diffstat (limited to 'xmodmap/handle.c')
-rw-r--r-- | xmodmap/handle.c | 1318 |
1 files changed, 1318 insertions, 0 deletions
diff --git a/xmodmap/handle.c b/xmodmap/handle.c new file mode 100644 index 0000000..d43da21 --- /dev/null +++ b/xmodmap/handle.c @@ -0,0 +1,1318 @@ +/* $Xorg: handle.c,v 1.6 2001/02/09 02:05:56 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ +/* $XFree86: xc/programs/xmodmap/handle.c,v 3.6 2001/07/25 15:05:27 dawes Exp $ */ + +#include "config.h" +#include <X11/Xos.h> +#include <X11/Xlib.h> +#include <stdio.h> +#include <ctype.h> +#include "xmodmap.h" +#include "wq.h" +#include <stdlib.h> + +static XModifierKeymap *map = NULL; + + +/* + * The routines in this file manipulate a queue of intructions. Instead of + * executing each line as it is entered, we build up a list of actions to + * take and execute them all at the end. This allows us to find all errors + * at once, and to preserve the context in which we are looking up keysyms. + */ + +struct wq work_queue = {NULL, NULL}; + + +/* + * common utility routines + */ + +static KeyCode * +KeysymToKeycodes(Display *dpy, KeySym keysym, int *pnum_kcs) +{ + KeyCode *kcs = NULL; + int i, j; + + *pnum_kcs = 0; + for (i = min_keycode; i <= max_keycode; i++) { + for (j = 0; j < 8; j++) { + if (XKeycodeToKeysym(dpy, (KeyCode) i, j) == keysym) { + if (!kcs) + kcs = (KeyCode *)malloc(sizeof(KeyCode)); + else + kcs = (KeyCode *)realloc((char *)kcs, + sizeof(KeyCode) * (*pnum_kcs + 1)); + kcs[*pnum_kcs] = i; + *pnum_kcs += 1; + break; + } + } + } + return kcs; +} + +static char * +copy_to_scratch(const char *s, int len) +{ + static char *buf = NULL; + static int buflen = 0; + + if (len > buflen) { + if (buf) free (buf); + buflen = (len < 40) ? 80 : (len * 2); + buf = (char *) malloc (buflen+1); + } + if (len > 0) + strncpy (buf, s, len); + else + len = 0; + + buf[len] = '\0'; + return (buf); +} + +static void +badheader(void) +{ + fprintf (stderr, "%s: %s:%d: bad ", ProgramName, inputFilename, lineno+1); + parse_errors++; +} + +#define badmsg0(what) { badheader(); fprintf (stderr, what); \ + putc ('\n', stderr); } + +#define badmsg(what,arg) { badheader(); fprintf (stderr, what, arg); \ + putc ('\n', stderr); } + +#define badmsgn(what,s,len) badmsg (what, copy_to_scratch (s, len)) + +void +initialize_map (void) +{ + map = XGetModifierMapping (dpy); + return; +} + +static void do_keycode ( char *line, int len ); +static void do_keysym ( char *line, int len ); +static void finish_keycodes ( const char *line, int len, KeyCode *keycodes, + int count ); +static void do_add ( char *line, int len ); +static void do_remove ( char *line, int len ); +static void do_clear ( char *line, int len ); +static void do_pointer ( char *line, int len ); +static int get_keysym_list ( const char *line, int len, int *np, KeySym **kslistp ); + +static void print_opcode(union op *op); + +static int skip_word ( const char *s, int len ); +static int skip_chars ( const char *s, int len ); +static int skip_space ( const char *s, int len ); + +static struct dt { + char *command; /* name of input command */ + int length; /* length of command */ + void (*proc)(char *, int); /* handler */ +} dispatch_table[] = { + { "keycode", 7, do_keycode }, + { "keysym", 6, do_keysym }, + { "add", 3, do_add }, + { "remove", 6, do_remove }, + { "clear", 5, do_clear }, + { "pointer", 7, do_pointer }, + { NULL, 0, NULL }}; + +/* + * handle_line - this routine parses the input line (which has had all leading + * and trailing whitespace removed) and builds up the work queue. + */ + +void +handle_line(char *line, /* string to parse */ + int len) /* length of line */ +{ + int n; + struct dt *dtp; + + n = skip_chars (line, len); + if (n < 0) { + badmsg ("input line '%s'", line); + return; + } + + for (dtp = dispatch_table; dtp->command != NULL; dtp++) { + if (n == dtp->length && + strncmp (line, dtp->command, dtp->length) == 0) { + + n += skip_space (line+n, len-n); + line += n, len -= n; + + (*(dtp->proc)) (line, len); + return; + } + } + + fprintf (stderr, "%s: unknown command on line %s:%d\n", + ProgramName, inputFilename, lineno+1); + parse_errors++; +} + +/* + * the following routines are useful for parsing + */ + +static int +skip_word (const char *s, int len) +{ + register int n; + + n = skip_chars (s, len); + return (n + skip_space (s+n, len-n)); +} + +static int +skip_chars(const char *s, int len) +{ + register int i; + + if (len <= 0 || !s || *s == '\0') return (0); + + for (i = 0; i < len; i++) { + if (isspace(s[i])) break; + } + return (i); +} + +static int +skip_space(const char *s, int len) +{ + register int i; + + if (len <= 0 || !s || *s == '\0') return (0); + + for (i = 0; i < len; i++) { + if (!s[i] || !isspace(s[i])) break; + } + return (i); +} + + +static int +skip_until_char(const char *s, int len, char c) +{ + register int i; + + for (i = 0; i < len; i++) { + if (s[i] == c) break; + } + return (i); +} + + +/* + * The action routines. + * + * This is where the real work gets done. Each routine is responsible for + * parsing its input (note that the command keyword has been stripped off) + * and adding to the work queue. They are also in charge of outputting + * error messages and returning non-zero if there is a problem. + * + * The following global variables are available: + * dpy the display descriptor + * work_queue linked list of opcodes + * inputFilename name of the file being processed + * lineno line number of current line in input file + */ +static void +add_to_work_queue(union op *p) /* this can become a macro someday */ +{ + if (work_queue.head == NULL) { /* nothing on the list */ + work_queue.head = work_queue.tail = p; /* head, tail, no prev */ + } else { + work_queue.tail->generic.next = p; /* head okay, prev */ + work_queue.tail = p; /* tail */ + } + p->generic.next = NULL; + + if (verbose) { + print_opcode (p); + } + return; +} + +static Bool +parse_number(const char *str, unsigned long *val) +{ + char *fmt = "%ld"; + + if (*str == '0') { + str++; + while (isspace(*str)) + str++; + fmt = "%lo"; + if (*str == '\0') { + *val = 0; + return 1; + } + if (*str == 'x' || *str == 'X') { + str++; + fmt = "%lx"; + } + } + return (sscanf (str, fmt, val) == 1); +} + +static Bool +parse_keysym(const char *line, int n, char **name, KeySym *keysym) +{ + *name = copy_to_scratch (line, n); + if (!strcmp(*name, "NoSymbol")) { + *keysym = NoSymbol; + return (True); + } + *keysym = XStringToKeysym (*name); + if (*keysym == NoSymbol && '0' <= **name && **name <= '9') + return parse_number(*name, keysym); + return (*keysym != NoSymbol); +} + +/* + * do_keycode - parse off lines of the form + * + * "keycode" number "=" [keysym ...] + * ^ + * + * where number is in decimal, hex, or octal. Any number of keysyms may be + * listed. + */ + +static void +do_keycode(char *line, int len) +{ + int dummy; + char *fmt = "%d"; + KeyCode keycode; + + if (len < 3 || !line || *line == '\0') { /* 5=a minimum */ + badmsg0 ("keycode input line"); + return; + } + + /* + * We need not bother to advance line/len past the + * number (or the string 'any') as finish_keycodes() will + * first advance past the '='. + */ + if (!strncmp("any", line, 3)) { + keycode = 0; + } else { + if (*line == '0') line++, len--, fmt = "%o"; + if (*line == 'x' || *line == 'X') line++, len--, fmt = "%x"; + + dummy = 0; + if (sscanf (line, fmt, &dummy) != 1 || dummy == 0) { + badmsg0 ("keycode value"); + return; + } + keycode = (KeyCode) dummy; + if ((int)keycode < min_keycode || (int)keycode > max_keycode) { + badmsg0 ("keycode value (out of range)"); + return; + } + } + + finish_keycodes (line, len, &keycode, 1); +} + + +/* + * do_keysym - parse off lines of the form + * + * "keysym" keysym "=" [keysym ...] + * ^ + * + * The left keysyms has to be checked for validity and evaluated. + */ + +static void +do_keysym(char *line, int len) +{ + int n; + KeyCode *keycodes; + KeySym keysym; + char *tmpname; + + if (len < 3 || !line || *line == '\0') { /* a=b minimum */ + badmsg0 ("keysym input line"); + return; + } + + n = skip_chars (line, len); + if (n < 1) { + badmsg0 ("target keysym name"); + return; + } + if (!parse_keysym(line, n, &tmpname, &keysym)) { + badmsg ("keysym target key symbol '%s'", tmpname); + return; + } + + keycodes = KeysymToKeycodes (dpy, keysym, &n); + if (n == 0) { + badmsg ("keysym target keysym '%s', no corresponding keycodes", + tmpname); + return; + } + if (verbose) { + int i; + printf ("! Keysym %s (0x%lx) corresponds to keycode(s)", + tmpname, (long) keysym); + for (i = 0; i < n; i++) + printf (" 0x%x", keycodes[i]); + printf("\n"); + } + + finish_keycodes (line, len, keycodes, n); +} + +static void +finish_keycodes(const char *line, int len, KeyCode *keycodes, int count) +{ + int n; + KeySym *kslist; + union op *uop; + struct op_keycode *opk; + + n = skip_until_char (line, len, '='); + line += n, len -= n; + + if (len < 1 || *line != '=') { /* = minimum */ + badmsg0 ("keycode command (missing keysym list),"); + return; + } + line++, len--; /* skip past the = */ + + n = skip_space (line, len); + line += n, len -= n; + + /* allow empty list */ + if (get_keysym_list (line, len, &n, &kslist) < 0) + return; + + while (--count >= 0) { + uop = AllocStruct (union op); + if (!uop) { + badmsg ("attempt to allocate a %ld byte keycode opcode", + (long) sizeof (struct op_keycode)); + return; + } + opk = &uop->keycode; + + opk->type = doKeycode; + opk->target_keycode = keycodes[count]; + opk->count = n; + opk->keysyms = kslist; + + add_to_work_queue (uop); + } + +#ifdef later + /* make sure we handle any special keys */ + check_special_keys (keycode, n, kslist); +#endif +} + + +/* + * parse_modifier - convert a modifier string name to its index + */ + +struct modtab modifier_table[] = { /* keep in order so it can be index */ + { "shift", 5, 0 }, + { "lock", 4, 1 }, + { "control", 7, 2 }, + { "mod1", 4, 3 }, + { "mod2", 4, 4 }, + { "mod3", 4, 5 }, + { "mod4", 4, 6 }, + { "mod5", 4, 7 }, + { "ctrl", 4, 2 }, + { NULL, 0, 0 }}; + +static int +parse_modifier(char *line, int n) +{ + register int i; + struct modtab *mt; + + /* lowercase for comparison against table */ + for (i = 0; i < n; i++) { + if (isupper (line[i])) line[i] = tolower (line[i]); + } + + for (mt = modifier_table; mt->name; mt++) { + if (n == mt->length && strncmp (line, mt->name, n) == 0) + return (mt->value); + } + return (-1); +} + + +/* + * do_add - parse off lines of the form + * + * add MODIFIER = keysym ... + * ^ + * where the MODIFIER is one of Shift, Lock, Control, Mod[1-5] where case + * is not important. There should also be an alias Ctrl for control. + */ + +static void +do_add(char *line, int len) +{ + int n; + int modifier; + KeySym *kslist; + union op *uop; + struct op_addmodifier *opam; + + if (len < 6 || !line || *line == '\0') { /* Lock=a minimum */ + badmsg0 ("add modifier input line"); + return; + } + + n = skip_chars (line, len); + if (n < 1) { + badmsg ("add modifier name %s", line); + return; + } + + modifier = parse_modifier (line, n); + if (modifier < 0) { + badmsgn ("add modifier name '%s', not allowed", line, n); + return; + } + + line += n, len -= n; + n = skip_until_char (line, len, '='); + if (n < 0) { + badmsg0 ("add modifier = keysym"); + return; + } + + n++; /* skip = */ + n += skip_space (line+n, len-n); + line += n, len -= n; + + if (get_keysym_list (line, len, &n, &kslist) < 0) + return; + if (n == 0) { + badmsg0 ("add modifier keysym list (empty)"); + return; + } + + uop = AllocStruct (union op); + if (!uop) { + badmsg ("attempt to allocate %ld byte addmodifier opcode", + (long) sizeof (struct op_addmodifier)); + return; + } + opam = &uop->addmodifier; + + opam->type = doAddModifier; + opam->modifier = modifier; + opam->count = n; + opam->keysyms = kslist; + + add_to_work_queue (uop); +} + +#ifdef AUTO_ADD_REMOVE +/* + * make_add - stick a single add onto the queue + */ +static void +make_add(int modifier, KeySym keysym) +{ + union op *uop; + struct op_addmodifier *opam; + + uop = AllocStruct (union op); + if (!uop) { + badmsg ("attempt to allocate %ld byte addmodifier opcode", + (long) sizeof (struct op_addmodifier)); + return; + } + opam = &uop->addmodifier; + + opam->type = doAddModifier; + opam->modifier = modifier; + opam->count = 1; + opam->keysyms = (KeySym *) malloc (sizeof (KeySym)); + if (!opam->keysyms) { + badmsg ("attempt to allocate %ld byte KeySym", (long) sizeof (KeySym)); + free ((char *) opam); + return; + } + opam->keysyms[0] = keysym; + + add_to_work_queue (uop); + return; +} +#endif /* AUTO_ADD_REMOVE */ + + +/* + * do_remove - parse off lines of the form + * + * remove MODIFIER = oldkeysym ... + * ^ + * where the MODIFIER is one of Shift, Lock, Control, Mod[1-5] where case + * is not important. There should also be an alias Ctrl for control. + */ + +static void +do_remove(char *line, int len) +{ + int n; + int nc; + int i; + int tot; + int modifier; + KeySym *kslist; + KeyCode *kclist; + union op *uop; + struct op_removemodifier *oprm; + + if (len < 6 || !line || *line == '\0') { /* Lock=a minimum */ + badmsg0 ("remove modifier input line"); + return; + } + + n = skip_chars (line, len); + if (n < 1) { + badmsg ("remove modifier name %s", line); + return; + } + + modifier = parse_modifier (line, n); + if (modifier < 0) { + badmsgn ("remove modifier name '%s', not allowed", line, n); + return; + } + + line += n, len -= n; + n = skip_until_char (line, len, '='); + if (n < 0) { + badmsg0 ("remove modifier = keysym"); + return; + } + + n++; + n += skip_space (line+n, len-n); + line += n, len -= n; + + if (get_keysym_list (line, len, &n, &kslist) < 0) + return; + if (n == 0) { + badmsg0 ("remove modifier keysym list (empty)"); + return; + } + + /* + * unlike the add command, we have to now evaluate the keysyms + */ + + kclist = (KeyCode *) malloc (n * sizeof (KeyCode)); + if (!kclist) { + badmsg ("attempt to allocate %ld byte keycode list", + (long) (n * sizeof (KeyCode))); + free ((char *) kslist); + return; + } + + tot = n; + nc = 0; + for (i = 0; i < n; i++) { + int num_kcs; + KeyCode *kcs; + kcs = KeysymToKeycodes (dpy, kslist[i], &num_kcs); + if (num_kcs == 0) { + char *tmpname = XKeysymToString (kslist[i]); + badmsg ("keysym in remove modifier list '%s', no corresponding keycodes", + tmpname ? tmpname : "?"); + continue; + } + if (verbose) { + int j; + char *tmpname = XKeysymToString (kslist[i]); + printf ("! Keysym %s (0x%lx) corresponds to keycode(s)", + tmpname ? tmpname : "?", (long) kslist[i]); + for (j = 0; j < num_kcs; j++) + printf(" 0x%x", kcs[j]); + printf("\n"); + } + if (nc + num_kcs > tot) { + tot = nc + num_kcs; + kclist = (KeyCode *)realloc((char *)kclist, tot * sizeof(KeyCode)); + if (!kclist) { + badmsg ("attempt to allocate %ld byte keycode list", + (long) (tot * sizeof (KeyCode))); + free ((char *) kslist); + return; + } + } + while (--num_kcs >= 0) + kclist[nc++] = *kcs++; /* okay, add it to list */ + } + + free ((char *) kslist); /* all done with it */ + + uop = AllocStruct (union op); + if (!uop) { + badmsg ("attempt to allocate %ld byte removemodifier opcode", + (long) sizeof (struct op_removemodifier)); + return; + } + oprm = &uop->removemodifier; + + oprm->type = doRemoveModifier; + oprm->modifier = modifier; + oprm->count = nc; + oprm->keycodes = kclist; + + add_to_work_queue (uop); +} + +#ifdef AUTO_ADD_REMOVE +/* + * make_remove - stick a single remove onto the queue + */ +static void +make_remove(int modifier, KeyCode keycode) +{ + union op *uop; + struct op_removemodifier *oprm; + + uop = AllocStruct (union op); + if (!uop) { + badmsg ("attempt to allocate %ld byte removemodifier opcode", + (long) sizeof (struct op_removemodifier)); + return; + } + oprm = &uop->removemodifier; + + oprm->type = doRemoveModifier; + oprm->modifier = modifier; + oprm->count = 1; + oprm->keycodes = (KeyCode *) malloc (sizeof (KeyCode)); + if (!oprm->keycodes) { + badmsg ("attempt to allocate %ld byte KeyCode", + (long) sizeof (KeyCode)); + free ((char *) oprm); + return; + } + oprm->keycodes[0] = keycode; + + add_to_work_queue (uop); + return; +} +#endif /* AUTO_ADD_REMOVE */ + + +/* + * do_clear - parse off lines of the form + * + * clear MODIFIER + * ^ + */ + +static void +do_clear(char *line, int len) +{ + int n; + int modifier; + union op *uop; + struct op_clearmodifier *opcm; + + if (len < 4 || !line || *line == '\0') { /* Lock minimum */ + badmsg0 ("clear modifier input line"); + return; + } + + n = skip_chars (line, len); + + modifier = parse_modifier (line, n); + if (modifier < 0) { + badmsgn ("clear modifier name '%s'", line, n); + return; + } + n += skip_space (line+n, len-n); + if (n != len) { + badmsgn ("extra argument '%s' to clear modifier", line+n, len-n); + /* okay to continue */ + } + + uop = AllocStruct (union op); + if (!uop) { + badmsg ("attempt to allocate %ld byte clearmodifier opcode", + (long) sizeof (struct op_clearmodifier)); + return; + } + opcm = &uop->clearmodifier; + + opcm->type = doClearModifier; + opcm->modifier = modifier; + + add_to_work_queue (uop); +} + +#ifndef HAVE_STRNCASECMP +static int +strncasecmp(const char *a, const char *b, int n) +{ + int i; + int a1, b1; + + for (i = 0; i < n; i++, a++, b++) { + if (!*a) return -1; + if (!*b) return 1; + + if (*a != *b) { + a1 = (isascii(*a) && isupper(*a)) ? tolower(*a) : *a; + b1 = (isascii(*b) && isupper(*b)) ? tolower(*b) : *b; + if (a1 != b1) return b1 - a1; + } + } + return 0; +} +#endif + +/* + * do_pointer = get list of numbers of the form + * + * buttons = NUMBER ... + * ^ + */ + +static void +do_pointer(char *line, int len) +{ + int n; + int i; + unsigned long val; + union op *uop; + struct op_pointer *opp; + unsigned char buttons[MAXBUTTONCODES]; + int nbuttons; + char *strval; + Bool ok; + + if (len < 2 || !line || *line == '\0') { /* =1 minimum */ + badmsg0 ("buttons input line"); + return; + } + + nbuttons = XGetPointerMapping (dpy, buttons, MAXBUTTONCODES); + + n = skip_space (line, len); + line += n, len -= n; + + if (line[0] != '=') { + badmsg0 ("buttons pointer code list, missing equal sign"); + return; + } + + line++, len--; /* skip = */ + n = skip_space (line, len); + line += n, len -= n; + + i = 0; + if (len < 7 || strncasecmp (line, "default", 7) != 0) { + while (len > 0) { + n = skip_space (line, len); + line += n, len -= n; + if (line[0] == '\0') break; + n = skip_word (line, len); + if (n < 1) { + badmsg ("skip of word in buttons line: %s", line); + return; + } + strval = copy_to_scratch(line, n); + ok = parse_number (strval, &val); + if (!ok || val >= MAXBUTTONCODES) { + badmsg ("value %s given for buttons list", strval); + return; + } + buttons[i++] = (unsigned char) val; + line += n, len -= n; + } + } + + if (i > 0 && i != nbuttons) { + fprintf (stderr, "Warning: Only changing the first %d of %d buttons.\n", + i, nbuttons); + i = nbuttons; + } + + uop = AllocStruct (union op); + if (!uop) { + badmsg ("attempt to allocate a %ld byte pointer opcode", + (long) sizeof (struct op_pointer)); + return; + } + opp = &uop->pointer; + + opp->type = doPointer; + opp->count = i; + for (i = 0; i < opp->count; i++) { + opp->button_codes[i] = buttons[i]; + } + + add_to_work_queue (uop); +} + + +/* + * get_keysym_list - parses the rest of the line into a keysyms assumes + * that the = sign has been parsed off but there may be leading whitespace + * + * keysym ... + * ^ + * + * this involves getting the word containing the keysym, checking its range, + * and adding it to the list. + */ + +static int +get_keysym_list(const char *line, int len, int *np, KeySym **kslistp) +{ + int havesofar, maxcanhave; + KeySym *keysymlist; + + *np = 0; + *kslistp = NULL; + + if (len == 0) return (0); /* empty list */ + + havesofar = 0; + maxcanhave = 4; /* most lists are small */ + keysymlist = (KeySym *) malloc (maxcanhave * sizeof (KeySym)); + if (!keysymlist) { + badmsg ("attempt to allocate %ld byte initial keysymlist", + (long) (maxcanhave * sizeof (KeySym))); + return (-1); + } + + while (len > 0) { + KeySym keysym; + int n; + char *tmpname; + Bool ok; + + n = skip_space (line, len); + line += n, len -= n; + + n = skip_chars (line, len); + if (n < 0) { + badmsg0 ("keysym name list"); + free(keysymlist); + return (-1); + } + + ok = parse_keysym (line, n, &tmpname, &keysym); + line += n, len -= n; + if (!ok) { + badmsg ("keysym name '%s' in keysym list", tmpname); + /* do NOT return here, look for others */ + continue; + } + + /* + * Do NOT test to see if the keysym translates to a keycode or you + * won't be able to assign new ones.... + */ + + /* grow the list bigger if necessary */ + if (havesofar >= maxcanhave) { + KeySym *origkeysymlist = keysymlist; + maxcanhave *= 2; + keysymlist = (KeySym *) realloc (keysymlist, + maxcanhave * sizeof (KeySym)); + if (!keysymlist) { + badmsg ("attempt to grow keysym list to %ld bytes", + (long) (maxcanhave * sizeof (KeySym))); + free(origkeysymlist); + return (-1); + } + } + + /* and add it to the list */ + keysymlist[havesofar++] = keysym; + } + + *kslistp = keysymlist; + *np = havesofar; + return (0); +} + + +#ifdef later +/* + * check_special_keys - run through list of keysyms and generate "add" or + * "remove" commands for for any of the key syms that appear in the modifier + * list. this involves running down the modifier map which is an array of + * 8 by map->max_keypermod keycodes. + */ + +static void +check_special_keys(KeyCode keycode, int n, KeySym *kslist) +{ + int i; /* iterator variable */ + KeyCode *kcp; /* keycode pointer */ + + /* + * walk the modifiermap array. since its dimensions are not known at + * compile time, we have to walk it by hand instead of indexing. this + * is why it is initialized outside the loop, but incremented inside the + * second loop. + */ + + kcp = map->modifiermap; /* start at beginning and iterate */ + for (i = 0; i < 8; i++) { /* there are 8 modifier keys */ + int j; + + for (j = 0; j < map->max_keypermod; j++, kcp++) { + KeySym keysym; + int k; + + if (!*kcp) continue; /* only non-zero entries significant */ + + /* + * check to see if the target keycode is already a modifier; if so, + * then we have to remove it + */ + if (keycode == *kcp) { + make_remove (i, keycode); + } + + /* + * now, check to see if any of the keysyms map to keycodes + * that are in the modifier list + */ + for (k = 0; k < n; k++) { + KeyCodes kc; + + kc = XKeysymToKeycode (dpy, kslist[k]); + if (kc == *kcp) { /* yup, found one */ + /* + * have to generate a remove of the CURRENT keycode + * and then an add of the new KEYCODE + */ + make_remove (i, kc); /* modifier, keycode */ + make_add (i, kslist[k]); /* modifier, keysym */ + } + } + } + } + return; +} +#endif + +/* + * print_work_queue - disassemble the work queue and print it on stdout + */ + +void +print_work_queue(void) +{ + union op *op; + + printf ("! dump of work queue\n"); + for (op = work_queue.head; op; op = op->generic.next) { + print_opcode (op); + } + return; +} + +static void +print_opcode(union op *op) +{ + int i; + + printf (" "); + switch (op->generic.type) { + case doKeycode: + if (op->keycode.target_keycode) + printf ("keycode 0x%lx =", (long) op->keycode.target_keycode); + else + printf ("keycode any ="); + for (i = 0; i < op->keycode.count; i++) { + char *name = XKeysymToString (op->keycode.keysyms[i]); + + printf (" %s", name ? name : "BADKEYSYM"); + } + printf ("\n"); + break; + case doAddModifier: + printf ("add %s =", modifier_table[op->addmodifier.modifier].name); + for (i = 0; i < op->addmodifier.count; i++) { + char *name = XKeysymToString (op->addmodifier.keysyms[i]); + printf (" %s", name ? name : "BADKEYSYM"); + } + printf ("\n"); + break; + case doRemoveModifier: + printf ("remove %s = ", + modifier_table[op->removemodifier.modifier].name); + for (i = 0; i < op->removemodifier.count; i++) { + printf (" 0x%lx", (long) op->removemodifier.keycodes[i]); + } + printf ("\n"); + break; + case doClearModifier: + printf ("clear %s\n", modifier_table[op->clearmodifier.modifier].name); + break; + case doPointer: + printf ("pointer = "); + if (op->pointer.count == 0) + printf(" default"); + else for (i=0; i < op->pointer.count; i++) + printf(" %d", op->pointer.button_codes[i]); + printf ("\n"); + break; + default: + printf ("! unknown opcode %d\n", op->generic.type); + break; + } /* end switch */ + return; +} + +/* + * execute_work_queue - do the real meat and potatoes now that we know what + * we need to do and that all of the input is correct. + */ +static int exec_keycode ( struct op_keycode *opk ); +static int exec_add ( struct op_addmodifier *opam ); +static int exec_remove ( struct op_removemodifier *oprm ); +static int exec_clear ( struct op_clearmodifier *opcm ); +static int exec_pointer ( struct op_pointer *opp ); + + +int +execute_work_queue (void) +{ + union op *op; + int errors; + Bool update_map = False; + int dosync; + + if (verbose) { + printf ("!\n"); + printf ("! executing work queue\n"); + printf ("!\n"); + } + + errors = 0; + dosync = 0; + + for (op = work_queue.head; op; op = op->generic.next) { + if (verbose) print_opcode (op); + + /* check to see if we have to update the keyboard mapping */ + if (dosync && + (dosync < 0 || + op->generic.type != doKeycode || + !op->keycode.target_keycode)) { + XSync (dpy, 0); + while (XEventsQueued (dpy, QueuedAlready) > 0) { + XEvent event; + XNextEvent (dpy, &event); + if (event.type == MappingNotify) { + /* read all MappingNotify events */ + while (XCheckTypedEvent (dpy, MappingNotify, &event)) ; + XRefreshKeyboardMapping (&event.xmapping); + } else { + fprintf (stderr, "%s: unknown event %ld\n", + ProgramName, (long) event.type); + } + } + } + dosync = 0; + switch (op->generic.type) { + case doKeycode: + if (exec_keycode (&op->keycode) < 0) errors++; + if (op->keycode.target_keycode) + dosync = 1; + else + dosync = -1; + break; + case doAddModifier: + if (exec_add (&op->addmodifier) < 0) errors++; + else update_map = True; + break; + case doRemoveModifier: + if (exec_remove (&op->removemodifier) < 0) errors++; + else update_map = True; + break; + case doClearModifier: + if (exec_clear (&op->clearmodifier) < 0) errors++; + else update_map = True; + break; + case doPointer: + if (exec_pointer (&op->pointer) < 0) errors++; + break; + default: + fprintf (stderr, "%s: unknown opcode %d\n", + ProgramName, op->generic.type); + break; + } + } + + if (update_map) { + if (UpdateModifierMapping (map) < 0) errors++; + } + + return (errors > 0 ? -1 : 0); +} + +static int +exec_keycode(struct op_keycode *opk) +{ + if (!opk->target_keycode) { + int i, j; + KeyCode free; + if (!opk->count) + return (0); + free = 0; + for (i = min_keycode; i <= max_keycode; i++) { + for (j = 0; j < opk->count; j++) { + if (XKeycodeToKeysym(dpy, (KeyCode) i, j) != opk->keysyms[j]) + break; + } + if (j >= opk->count) + return (0); + if (free) + continue; + for (j = 0; j < 8; j++) { + if (XKeycodeToKeysym(dpy, (KeyCode) i, j) != None) + break; + } + if (j >= 8) + free = i; + } + if (!free) { + fprintf(stderr, "%s: no available keycode for assignment\n", + ProgramName); + return (-1); + } + XChangeKeyboardMapping (dpy, free, opk->count, opk->keysyms, 1); + } else if (opk->count == 0) { + KeySym dummy = NoSymbol; + XChangeKeyboardMapping (dpy, opk->target_keycode, 1, + &dummy, 1); + } else { + XChangeKeyboardMapping (dpy, opk->target_keycode, opk->count, + opk->keysyms, 1); + } + return (0); +} + +static int +exec_add(struct op_addmodifier *opam) +{ + int i; + int status; + + status = 0; + for (i = 0; i < opam->count; i++) { + int num_kcs; + KeyCode *kcs; + + kcs = KeysymToKeycodes (dpy, opam->keysyms[i], &num_kcs); + if (num_kcs == 0) + status = -1; + while (--num_kcs >= 0) { + if (AddModifier (&map, *kcs++, opam->modifier) < 0) + status = -1; + } + } + return (status); +} + +static int +exec_remove(struct op_removemodifier *oprm) +{ + int i; + int status; + + status = 0; + for (i = 0; i < oprm->count; i++) { + if (RemoveModifier (&map, oprm->keycodes[i], oprm->modifier) < 0) + status = -1; + } + return (status); +} + +static int +exec_clear(struct op_clearmodifier *opcm) +{ + return (ClearModifier (&map, opcm->modifier)); +} + + +static int +exec_pointer(struct op_pointer *opp) +{ + return (SetPointerMap (opp->button_codes, opp->count)); +} + +void +print_modifier_map(void) +{ + PrintModifierMapping (map, stdout); + return; +} + +void +print_key_table(Bool exprs) +{ + PrintKeyTable (exprs, stdout); + return; +} + +void +print_pointer_map(void) +{ + PrintPointerMap (stdout); + return; +} + + |