handle.c revision a733a5bf
11a30de1fSmrg/* 21a30de1fSmrg 31a30de1fSmrgCopyright 1988, 1998 The Open Group 41a30de1fSmrg 51a30de1fSmrgPermission to use, copy, modify, distribute, and sell this software and its 61a30de1fSmrgdocumentation for any purpose is hereby granted without fee, provided that 71a30de1fSmrgthe above copyright notice appear in all copies and that both that 81a30de1fSmrgcopyright notice and this permission notice appear in supporting 91a30de1fSmrgdocumentation. 101a30de1fSmrg 111a30de1fSmrgThe above copyright notice and this permission notice shall be included 121a30de1fSmrgin all copies or substantial portions of the Software. 131a30de1fSmrg 141a30de1fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 151a30de1fSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 161a30de1fSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 171a30de1fSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 181a30de1fSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 191a30de1fSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 201a30de1fSmrgOTHER DEALINGS IN THE SOFTWARE. 211a30de1fSmrg 221a30de1fSmrgExcept as contained in this notice, the name of The Open Group shall 231a30de1fSmrgnot be used in advertising or otherwise to promote the sale, use or 241a30de1fSmrgother dealings in this Software without prior written authorization 251a30de1fSmrgfrom The Open Group. 261a30de1fSmrg 271a30de1fSmrg*/ 281a30de1fSmrg 291a30de1fSmrg#include "config.h" 301a30de1fSmrg#include <X11/Xos.h> 311a30de1fSmrg#include <X11/Xlib.h> 321a30de1fSmrg#include <stdio.h> 331a30de1fSmrg#include <ctype.h> 341a30de1fSmrg#include "xmodmap.h" 351a30de1fSmrg#include "wq.h" 361a30de1fSmrg#include <stdlib.h> 371a30de1fSmrg 38a733a5bfSmrg#ifdef HAVE_STRNCASECMP 39a733a5bfSmrg#include <strings.h> 40a733a5bfSmrg#endif 41a733a5bfSmrg 421a30de1fSmrgstatic XModifierKeymap *map = NULL; 431a30de1fSmrg 441a30de1fSmrg 451a30de1fSmrg/* 461a30de1fSmrg * The routines in this file manipulate a queue of intructions. Instead of 471a30de1fSmrg * executing each line as it is entered, we build up a list of actions to 481a30de1fSmrg * take and execute them all at the end. This allows us to find all errors 491a30de1fSmrg * at once, and to preserve the context in which we are looking up keysyms. 501a30de1fSmrg */ 511a30de1fSmrg 521a30de1fSmrgstruct wq work_queue = {NULL, NULL}; 531a30de1fSmrg 541a30de1fSmrg 551a30de1fSmrg/* 561a30de1fSmrg * common utility routines 571a30de1fSmrg */ 581a30de1fSmrg 591a30de1fSmrgstatic KeyCode * 601a30de1fSmrgKeysymToKeycodes(Display *dpy, KeySym keysym, int *pnum_kcs) 611a30de1fSmrg{ 621a30de1fSmrg KeyCode *kcs = NULL; 631a30de1fSmrg int i, j; 641a30de1fSmrg 651a30de1fSmrg *pnum_kcs = 0; 661a30de1fSmrg for (i = min_keycode; i <= max_keycode; i++) { 671a30de1fSmrg for (j = 0; j < 8; j++) { 681a30de1fSmrg if (XKeycodeToKeysym(dpy, (KeyCode) i, j) == keysym) { 691a30de1fSmrg if (!kcs) 701a30de1fSmrg kcs = (KeyCode *)malloc(sizeof(KeyCode)); 711a30de1fSmrg else 721a30de1fSmrg kcs = (KeyCode *)realloc((char *)kcs, 731a30de1fSmrg sizeof(KeyCode) * (*pnum_kcs + 1)); 741a30de1fSmrg kcs[*pnum_kcs] = i; 751a30de1fSmrg *pnum_kcs += 1; 761a30de1fSmrg break; 771a30de1fSmrg } 781a30de1fSmrg } 791a30de1fSmrg } 801a30de1fSmrg return kcs; 811a30de1fSmrg} 821a30de1fSmrg 831a30de1fSmrgstatic char * 841a30de1fSmrgcopy_to_scratch(const char *s, int len) 851a30de1fSmrg{ 861a30de1fSmrg static char *buf = NULL; 871a30de1fSmrg static int buflen = 0; 881a30de1fSmrg 89a733a5bfSmrg if (len < 0) 90a733a5bfSmrg len = 0; 91a733a5bfSmrg 92a733a5bfSmrg if (len >= buflen) { 931a30de1fSmrg if (buf) free (buf); 941a30de1fSmrg buflen = (len < 40) ? 80 : (len * 2); 951a30de1fSmrg buf = (char *) malloc (buflen+1); 96a733a5bfSmrg if (!buf) { 97a733a5bfSmrg fprintf (stderr, "attempt to allocate %d byte scratch buffer\n", buflen + 1); 98a733a5bfSmrg return NULL; 99a733a5bfSmrg } 1001a30de1fSmrg } 1011a30de1fSmrg 102a733a5bfSmrg strncpy (buf, s, len); 1031a30de1fSmrg buf[len] = '\0'; 104a733a5bfSmrg 1051a30de1fSmrg return (buf); 1061a30de1fSmrg} 1071a30de1fSmrg 1081a30de1fSmrgstatic void 1091a30de1fSmrgbadheader(void) 1101a30de1fSmrg{ 1111a30de1fSmrg fprintf (stderr, "%s: %s:%d: bad ", ProgramName, inputFilename, lineno+1); 1121a30de1fSmrg parse_errors++; 1131a30de1fSmrg} 1141a30de1fSmrg 1151a30de1fSmrg#define badmsg0(what) { badheader(); fprintf (stderr, what); \ 1161a30de1fSmrg putc ('\n', stderr); } 1171a30de1fSmrg 1181a30de1fSmrg#define badmsg(what,arg) { badheader(); fprintf (stderr, what, arg); \ 1191a30de1fSmrg putc ('\n', stderr); } 1201a30de1fSmrg 1211a30de1fSmrg#define badmsgn(what,s,len) badmsg (what, copy_to_scratch (s, len)) 1221a30de1fSmrg 1231a30de1fSmrgvoid 1241a30de1fSmrginitialize_map (void) 1251a30de1fSmrg{ 1261a30de1fSmrg map = XGetModifierMapping (dpy); 1271a30de1fSmrg return; 1281a30de1fSmrg} 1291a30de1fSmrg 1301a30de1fSmrgstatic void do_keycode ( char *line, int len ); 1311a30de1fSmrgstatic void do_keysym ( char *line, int len ); 1321a30de1fSmrgstatic void finish_keycodes ( const char *line, int len, KeyCode *keycodes, 1331a30de1fSmrg int count ); 1341a30de1fSmrgstatic void do_add ( char *line, int len ); 1351a30de1fSmrgstatic void do_remove ( char *line, int len ); 1361a30de1fSmrgstatic void do_clear ( char *line, int len ); 1371a30de1fSmrgstatic void do_pointer ( char *line, int len ); 1381a30de1fSmrgstatic int get_keysym_list ( const char *line, int len, int *np, KeySym **kslistp ); 1391a30de1fSmrg 1401a30de1fSmrgstatic void print_opcode(union op *op); 1411a30de1fSmrg 1421a30de1fSmrgstatic int skip_word ( const char *s, int len ); 1431a30de1fSmrgstatic int skip_chars ( const char *s, int len ); 1441a30de1fSmrgstatic int skip_space ( const char *s, int len ); 1451a30de1fSmrg 1461a30de1fSmrgstatic struct dt { 147a733a5bfSmrg const char *command; /* name of input command */ 1481a30de1fSmrg int length; /* length of command */ 1491a30de1fSmrg void (*proc)(char *, int); /* handler */ 1501a30de1fSmrg} dispatch_table[] = { 1511a30de1fSmrg { "keycode", 7, do_keycode }, 1521a30de1fSmrg { "keysym", 6, do_keysym }, 1531a30de1fSmrg { "add", 3, do_add }, 1541a30de1fSmrg { "remove", 6, do_remove }, 1551a30de1fSmrg { "clear", 5, do_clear }, 1561a30de1fSmrg { "pointer", 7, do_pointer }, 1571a30de1fSmrg { NULL, 0, NULL }}; 1581a30de1fSmrg 1591a30de1fSmrg/* 1601a30de1fSmrg * handle_line - this routine parses the input line (which has had all leading 1611a30de1fSmrg * and trailing whitespace removed) and builds up the work queue. 1621a30de1fSmrg */ 1631a30de1fSmrg 1641a30de1fSmrgvoid 1651a30de1fSmrghandle_line(char *line, /* string to parse */ 1661a30de1fSmrg int len) /* length of line */ 1671a30de1fSmrg{ 1681a30de1fSmrg int n; 1691a30de1fSmrg struct dt *dtp; 1701a30de1fSmrg 1711a30de1fSmrg n = skip_chars (line, len); 1721a30de1fSmrg if (n < 0) { 1731a30de1fSmrg badmsg ("input line '%s'", line); 1741a30de1fSmrg return; 1751a30de1fSmrg } 1761a30de1fSmrg 1771a30de1fSmrg for (dtp = dispatch_table; dtp->command != NULL; dtp++) { 1781a30de1fSmrg if (n == dtp->length && 1791a30de1fSmrg strncmp (line, dtp->command, dtp->length) == 0) { 1801a30de1fSmrg 1811a30de1fSmrg n += skip_space (line+n, len-n); 1821a30de1fSmrg line += n, len -= n; 1831a30de1fSmrg 1841a30de1fSmrg (*(dtp->proc)) (line, len); 1851a30de1fSmrg return; 1861a30de1fSmrg } 1871a30de1fSmrg } 1881a30de1fSmrg 1891a30de1fSmrg fprintf (stderr, "%s: unknown command on line %s:%d\n", 1901a30de1fSmrg ProgramName, inputFilename, lineno+1); 1911a30de1fSmrg parse_errors++; 1921a30de1fSmrg} 1931a30de1fSmrg 1941a30de1fSmrg/* 1951a30de1fSmrg * the following routines are useful for parsing 1961a30de1fSmrg */ 1971a30de1fSmrg 1981a30de1fSmrgstatic int 1991a30de1fSmrgskip_word (const char *s, int len) 2001a30de1fSmrg{ 2011a30de1fSmrg register int n; 2021a30de1fSmrg 2031a30de1fSmrg n = skip_chars (s, len); 2041a30de1fSmrg return (n + skip_space (s+n, len-n)); 2051a30de1fSmrg} 2061a30de1fSmrg 2071a30de1fSmrgstatic int 2081a30de1fSmrgskip_chars(const char *s, int len) 2091a30de1fSmrg{ 2101a30de1fSmrg register int i; 2111a30de1fSmrg 2121a30de1fSmrg if (len <= 0 || !s || *s == '\0') return (0); 2131a30de1fSmrg 2141a30de1fSmrg for (i = 0; i < len; i++) { 2151a30de1fSmrg if (isspace(s[i])) break; 2161a30de1fSmrg } 2171a30de1fSmrg return (i); 2181a30de1fSmrg} 2191a30de1fSmrg 2201a30de1fSmrgstatic int 2211a30de1fSmrgskip_space(const char *s, int len) 2221a30de1fSmrg{ 2231a30de1fSmrg register int i; 2241a30de1fSmrg 2251a30de1fSmrg if (len <= 0 || !s || *s == '\0') return (0); 2261a30de1fSmrg 2271a30de1fSmrg for (i = 0; i < len; i++) { 2281a30de1fSmrg if (!s[i] || !isspace(s[i])) break; 2291a30de1fSmrg } 2301a30de1fSmrg return (i); 2311a30de1fSmrg} 2321a30de1fSmrg 2331a30de1fSmrg 2341a30de1fSmrgstatic int 2351a30de1fSmrgskip_until_char(const char *s, int len, char c) 2361a30de1fSmrg{ 2371a30de1fSmrg register int i; 2381a30de1fSmrg 2391a30de1fSmrg for (i = 0; i < len; i++) { 2401a30de1fSmrg if (s[i] == c) break; 2411a30de1fSmrg } 2421a30de1fSmrg return (i); 2431a30de1fSmrg} 2441a30de1fSmrg 2451a30de1fSmrg 2461a30de1fSmrg/* 2471a30de1fSmrg * The action routines. 2481a30de1fSmrg * 2491a30de1fSmrg * This is where the real work gets done. Each routine is responsible for 2501a30de1fSmrg * parsing its input (note that the command keyword has been stripped off) 2511a30de1fSmrg * and adding to the work queue. They are also in charge of outputting 2521a30de1fSmrg * error messages and returning non-zero if there is a problem. 2531a30de1fSmrg * 2541a30de1fSmrg * The following global variables are available: 2551a30de1fSmrg * dpy the display descriptor 2561a30de1fSmrg * work_queue linked list of opcodes 2571a30de1fSmrg * inputFilename name of the file being processed 2581a30de1fSmrg * lineno line number of current line in input file 2591a30de1fSmrg */ 2601a30de1fSmrgstatic void 2611a30de1fSmrgadd_to_work_queue(union op *p) /* this can become a macro someday */ 2621a30de1fSmrg{ 2631a30de1fSmrg if (work_queue.head == NULL) { /* nothing on the list */ 2641a30de1fSmrg work_queue.head = work_queue.tail = p; /* head, tail, no prev */ 2651a30de1fSmrg } else { 2661a30de1fSmrg work_queue.tail->generic.next = p; /* head okay, prev */ 2671a30de1fSmrg work_queue.tail = p; /* tail */ 2681a30de1fSmrg } 2691a30de1fSmrg p->generic.next = NULL; 2701a30de1fSmrg 2711a30de1fSmrg if (verbose) { 2721a30de1fSmrg print_opcode (p); 2731a30de1fSmrg } 2741a30de1fSmrg return; 2751a30de1fSmrg} 2761a30de1fSmrg 2771a30de1fSmrgstatic Bool 2781a30de1fSmrgparse_number(const char *str, unsigned long *val) 2791a30de1fSmrg{ 280a733a5bfSmrg const char *fmt = "%ld"; 2811a30de1fSmrg 2821a30de1fSmrg if (*str == '0') { 2831a30de1fSmrg str++; 284b7fb5eacSmrg while (isspace(*str)) 285b7fb5eacSmrg str++; 2861a30de1fSmrg fmt = "%lo"; 2871a30de1fSmrg if (*str == '\0') { 2881a30de1fSmrg *val = 0; 2891a30de1fSmrg return 1; 2901a30de1fSmrg } 2911a30de1fSmrg if (*str == 'x' || *str == 'X') { 2921a30de1fSmrg str++; 2931a30de1fSmrg fmt = "%lx"; 2941a30de1fSmrg } 2951a30de1fSmrg } 2961a30de1fSmrg return (sscanf (str, fmt, val) == 1); 2971a30de1fSmrg} 2981a30de1fSmrg 2991a30de1fSmrgstatic Bool 3001a30de1fSmrgparse_keysym(const char *line, int n, char **name, KeySym *keysym) 3011a30de1fSmrg{ 3021a30de1fSmrg *name = copy_to_scratch (line, n); 3031a30de1fSmrg if (!strcmp(*name, "NoSymbol")) { 3041a30de1fSmrg *keysym = NoSymbol; 3051a30de1fSmrg return (True); 3061a30de1fSmrg } 3071a30de1fSmrg *keysym = XStringToKeysym (*name); 3081a30de1fSmrg if (*keysym == NoSymbol && '0' <= **name && **name <= '9') 3091a30de1fSmrg return parse_number(*name, keysym); 3101a30de1fSmrg return (*keysym != NoSymbol); 3111a30de1fSmrg} 3121a30de1fSmrg 3131a30de1fSmrg/* 3141a30de1fSmrg * do_keycode - parse off lines of the form 3151a30de1fSmrg * 3161a30de1fSmrg * "keycode" number "=" [keysym ...] 3171a30de1fSmrg * ^ 3181a30de1fSmrg * 3191a30de1fSmrg * where number is in decimal, hex, or octal. Any number of keysyms may be 3201a30de1fSmrg * listed. 3211a30de1fSmrg */ 3221a30de1fSmrg 3231a30de1fSmrgstatic void 3241a30de1fSmrgdo_keycode(char *line, int len) 3251a30de1fSmrg{ 3261a30de1fSmrg int dummy; 327a733a5bfSmrg const char *fmt = "%d"; 3281a30de1fSmrg KeyCode keycode; 3291a30de1fSmrg 3301a30de1fSmrg if (len < 3 || !line || *line == '\0') { /* 5=a minimum */ 3311a30de1fSmrg badmsg0 ("keycode input line"); 3321a30de1fSmrg return; 3331a30de1fSmrg } 3341a30de1fSmrg 3351a30de1fSmrg /* 3361a30de1fSmrg * We need not bother to advance line/len past the 3371a30de1fSmrg * number (or the string 'any') as finish_keycodes() will 3381a30de1fSmrg * first advance past the '='. 3391a30de1fSmrg */ 3401a30de1fSmrg if (!strncmp("any", line, 3)) { 3411a30de1fSmrg keycode = 0; 3421a30de1fSmrg } else { 3431a30de1fSmrg if (*line == '0') line++, len--, fmt = "%o"; 3441a30de1fSmrg if (*line == 'x' || *line == 'X') line++, len--, fmt = "%x"; 3451a30de1fSmrg 3461a30de1fSmrg dummy = 0; 3471a30de1fSmrg if (sscanf (line, fmt, &dummy) != 1 || dummy == 0) { 3481a30de1fSmrg badmsg0 ("keycode value"); 3491a30de1fSmrg return; 3501a30de1fSmrg } 3511a30de1fSmrg keycode = (KeyCode) dummy; 3521a30de1fSmrg if ((int)keycode < min_keycode || (int)keycode > max_keycode) { 3531a30de1fSmrg badmsg0 ("keycode value (out of range)"); 3541a30de1fSmrg return; 3551a30de1fSmrg } 3561a30de1fSmrg } 3571a30de1fSmrg 3581a30de1fSmrg finish_keycodes (line, len, &keycode, 1); 3591a30de1fSmrg} 3601a30de1fSmrg 3611a30de1fSmrg 3621a30de1fSmrg/* 3631a30de1fSmrg * do_keysym - parse off lines of the form 3641a30de1fSmrg * 3651a30de1fSmrg * "keysym" keysym "=" [keysym ...] 3661a30de1fSmrg * ^ 3671a30de1fSmrg * 3681a30de1fSmrg * The left keysyms has to be checked for validity and evaluated. 3691a30de1fSmrg */ 3701a30de1fSmrg 3711a30de1fSmrgstatic void 3721a30de1fSmrgdo_keysym(char *line, int len) 3731a30de1fSmrg{ 3741a30de1fSmrg int n; 3751a30de1fSmrg KeyCode *keycodes; 3761a30de1fSmrg KeySym keysym; 3771a30de1fSmrg char *tmpname; 3781a30de1fSmrg 3791a30de1fSmrg if (len < 3 || !line || *line == '\0') { /* a=b minimum */ 3801a30de1fSmrg badmsg0 ("keysym input line"); 3811a30de1fSmrg return; 3821a30de1fSmrg } 3831a30de1fSmrg 3841a30de1fSmrg n = skip_chars (line, len); 3851a30de1fSmrg if (n < 1) { 3861a30de1fSmrg badmsg0 ("target keysym name"); 3871a30de1fSmrg return; 3881a30de1fSmrg } 3891a30de1fSmrg if (!parse_keysym(line, n, &tmpname, &keysym)) { 3901a30de1fSmrg badmsg ("keysym target key symbol '%s'", tmpname); 3911a30de1fSmrg return; 3921a30de1fSmrg } 3931a30de1fSmrg 3941a30de1fSmrg keycodes = KeysymToKeycodes (dpy, keysym, &n); 3951a30de1fSmrg if (n == 0) { 3961a30de1fSmrg badmsg ("keysym target keysym '%s', no corresponding keycodes", 3971a30de1fSmrg tmpname); 3981a30de1fSmrg return; 3991a30de1fSmrg } 4001a30de1fSmrg if (verbose) { 4011a30de1fSmrg int i; 4021a30de1fSmrg printf ("! Keysym %s (0x%lx) corresponds to keycode(s)", 4031a30de1fSmrg tmpname, (long) keysym); 4041a30de1fSmrg for (i = 0; i < n; i++) 4051a30de1fSmrg printf (" 0x%x", keycodes[i]); 4061a30de1fSmrg printf("\n"); 4071a30de1fSmrg } 4081a30de1fSmrg 4091a30de1fSmrg finish_keycodes (line, len, keycodes, n); 4101a30de1fSmrg} 4111a30de1fSmrg 4121a30de1fSmrgstatic void 4131a30de1fSmrgfinish_keycodes(const char *line, int len, KeyCode *keycodes, int count) 4141a30de1fSmrg{ 4151a30de1fSmrg int n; 4161a30de1fSmrg KeySym *kslist; 4171a30de1fSmrg union op *uop; 4181a30de1fSmrg struct op_keycode *opk; 4191a30de1fSmrg 4201a30de1fSmrg n = skip_until_char (line, len, '='); 4211a30de1fSmrg line += n, len -= n; 4221a30de1fSmrg 4231a30de1fSmrg if (len < 1 || *line != '=') { /* = minimum */ 4241a30de1fSmrg badmsg0 ("keycode command (missing keysym list),"); 4251a30de1fSmrg return; 4261a30de1fSmrg } 4271a30de1fSmrg line++, len--; /* skip past the = */ 4281a30de1fSmrg 4291a30de1fSmrg n = skip_space (line, len); 4301a30de1fSmrg line += n, len -= n; 4311a30de1fSmrg 4321a30de1fSmrg /* allow empty list */ 4331a30de1fSmrg if (get_keysym_list (line, len, &n, &kslist) < 0) 4341a30de1fSmrg return; 4351a30de1fSmrg 4361a30de1fSmrg while (--count >= 0) { 4371a30de1fSmrg uop = AllocStruct (union op); 4381a30de1fSmrg if (!uop) { 4391a30de1fSmrg badmsg ("attempt to allocate a %ld byte keycode opcode", 4401a30de1fSmrg (long) sizeof (struct op_keycode)); 4411a30de1fSmrg return; 4421a30de1fSmrg } 4431a30de1fSmrg opk = &uop->keycode; 4441a30de1fSmrg 4451a30de1fSmrg opk->type = doKeycode; 4461a30de1fSmrg opk->target_keycode = keycodes[count]; 4471a30de1fSmrg opk->count = n; 4481a30de1fSmrg opk->keysyms = kslist; 4491a30de1fSmrg 4501a30de1fSmrg add_to_work_queue (uop); 4511a30de1fSmrg } 4521a30de1fSmrg 4531a30de1fSmrg#ifdef later 4541a30de1fSmrg /* make sure we handle any special keys */ 4551a30de1fSmrg check_special_keys (keycode, n, kslist); 4561a30de1fSmrg#endif 4571a30de1fSmrg} 4581a30de1fSmrg 4591a30de1fSmrg 4601a30de1fSmrg/* 4611a30de1fSmrg * parse_modifier - convert a modifier string name to its index 4621a30de1fSmrg */ 4631a30de1fSmrg 4641a30de1fSmrgstruct modtab modifier_table[] = { /* keep in order so it can be index */ 4651a30de1fSmrg { "shift", 5, 0 }, 4661a30de1fSmrg { "lock", 4, 1 }, 4671a30de1fSmrg { "control", 7, 2 }, 4681a30de1fSmrg { "mod1", 4, 3 }, 4691a30de1fSmrg { "mod2", 4, 4 }, 4701a30de1fSmrg { "mod3", 4, 5 }, 4711a30de1fSmrg { "mod4", 4, 6 }, 4721a30de1fSmrg { "mod5", 4, 7 }, 4731a30de1fSmrg { "ctrl", 4, 2 }, 4741a30de1fSmrg { NULL, 0, 0 }}; 4751a30de1fSmrg 4761a30de1fSmrgstatic int 4771a30de1fSmrgparse_modifier(char *line, int n) 4781a30de1fSmrg{ 4791a30de1fSmrg register int i; 4801a30de1fSmrg struct modtab *mt; 4811a30de1fSmrg 4821a30de1fSmrg /* lowercase for comparison against table */ 4831a30de1fSmrg for (i = 0; i < n; i++) { 4841a30de1fSmrg if (isupper (line[i])) line[i] = tolower (line[i]); 4851a30de1fSmrg } 4861a30de1fSmrg 4871a30de1fSmrg for (mt = modifier_table; mt->name; mt++) { 4881a30de1fSmrg if (n == mt->length && strncmp (line, mt->name, n) == 0) 4891a30de1fSmrg return (mt->value); 4901a30de1fSmrg } 4911a30de1fSmrg return (-1); 4921a30de1fSmrg} 4931a30de1fSmrg 4941a30de1fSmrg 4951a30de1fSmrg/* 4961a30de1fSmrg * do_add - parse off lines of the form 4971a30de1fSmrg * 4981a30de1fSmrg * add MODIFIER = keysym ... 4991a30de1fSmrg * ^ 5001a30de1fSmrg * where the MODIFIER is one of Shift, Lock, Control, Mod[1-5] where case 5011a30de1fSmrg * is not important. There should also be an alias Ctrl for control. 5021a30de1fSmrg */ 5031a30de1fSmrg 5041a30de1fSmrgstatic void 5051a30de1fSmrgdo_add(char *line, int len) 5061a30de1fSmrg{ 5071a30de1fSmrg int n; 5081a30de1fSmrg int modifier; 5091a30de1fSmrg KeySym *kslist; 5101a30de1fSmrg union op *uop; 5111a30de1fSmrg struct op_addmodifier *opam; 5121a30de1fSmrg 5131a30de1fSmrg if (len < 6 || !line || *line == '\0') { /* Lock=a minimum */ 5141a30de1fSmrg badmsg0 ("add modifier input line"); 5151a30de1fSmrg return; 5161a30de1fSmrg } 5171a30de1fSmrg 5181a30de1fSmrg n = skip_chars (line, len); 5191a30de1fSmrg if (n < 1) { 5201a30de1fSmrg badmsg ("add modifier name %s", line); 5211a30de1fSmrg return; 5221a30de1fSmrg } 5231a30de1fSmrg 5241a30de1fSmrg modifier = parse_modifier (line, n); 5251a30de1fSmrg if (modifier < 0) { 5261a30de1fSmrg badmsgn ("add modifier name '%s', not allowed", line, n); 5271a30de1fSmrg return; 5281a30de1fSmrg } 5291a30de1fSmrg 5301a30de1fSmrg line += n, len -= n; 5311a30de1fSmrg n = skip_until_char (line, len, '='); 5321a30de1fSmrg if (n < 0) { 5331a30de1fSmrg badmsg0 ("add modifier = keysym"); 5341a30de1fSmrg return; 5351a30de1fSmrg } 5361a30de1fSmrg 5371a30de1fSmrg n++; /* skip = */ 5381a30de1fSmrg n += skip_space (line+n, len-n); 5391a30de1fSmrg line += n, len -= n; 5401a30de1fSmrg 5411a30de1fSmrg if (get_keysym_list (line, len, &n, &kslist) < 0) 5421a30de1fSmrg return; 5431a30de1fSmrg if (n == 0) { 5441a30de1fSmrg badmsg0 ("add modifier keysym list (empty)"); 5451a30de1fSmrg return; 5461a30de1fSmrg } 5471a30de1fSmrg 5481a30de1fSmrg uop = AllocStruct (union op); 5491a30de1fSmrg if (!uop) { 5501a30de1fSmrg badmsg ("attempt to allocate %ld byte addmodifier opcode", 5511a30de1fSmrg (long) sizeof (struct op_addmodifier)); 5521a30de1fSmrg return; 5531a30de1fSmrg } 5541a30de1fSmrg opam = &uop->addmodifier; 5551a30de1fSmrg 5561a30de1fSmrg opam->type = doAddModifier; 5571a30de1fSmrg opam->modifier = modifier; 5581a30de1fSmrg opam->count = n; 5591a30de1fSmrg opam->keysyms = kslist; 5601a30de1fSmrg 5611a30de1fSmrg add_to_work_queue (uop); 5621a30de1fSmrg} 5631a30de1fSmrg 5641a30de1fSmrg#ifdef AUTO_ADD_REMOVE 5651a30de1fSmrg/* 5661a30de1fSmrg * make_add - stick a single add onto the queue 5671a30de1fSmrg */ 5681a30de1fSmrgstatic void 5691a30de1fSmrgmake_add(int modifier, KeySym keysym) 5701a30de1fSmrg{ 5711a30de1fSmrg union op *uop; 5721a30de1fSmrg struct op_addmodifier *opam; 5731a30de1fSmrg 5741a30de1fSmrg uop = AllocStruct (union op); 5751a30de1fSmrg if (!uop) { 5761a30de1fSmrg badmsg ("attempt to allocate %ld byte addmodifier opcode", 5771a30de1fSmrg (long) sizeof (struct op_addmodifier)); 5781a30de1fSmrg return; 5791a30de1fSmrg } 5801a30de1fSmrg opam = &uop->addmodifier; 5811a30de1fSmrg 5821a30de1fSmrg opam->type = doAddModifier; 5831a30de1fSmrg opam->modifier = modifier; 5841a30de1fSmrg opam->count = 1; 5851a30de1fSmrg opam->keysyms = (KeySym *) malloc (sizeof (KeySym)); 5861a30de1fSmrg if (!opam->keysyms) { 5871a30de1fSmrg badmsg ("attempt to allocate %ld byte KeySym", (long) sizeof (KeySym)); 5881a30de1fSmrg free ((char *) opam); 5891a30de1fSmrg return; 5901a30de1fSmrg } 5911a30de1fSmrg opam->keysyms[0] = keysym; 5921a30de1fSmrg 5931a30de1fSmrg add_to_work_queue (uop); 5941a30de1fSmrg return; 5951a30de1fSmrg} 5961a30de1fSmrg#endif /* AUTO_ADD_REMOVE */ 5971a30de1fSmrg 5981a30de1fSmrg 5991a30de1fSmrg/* 6001a30de1fSmrg * do_remove - parse off lines of the form 6011a30de1fSmrg * 6021a30de1fSmrg * remove MODIFIER = oldkeysym ... 6031a30de1fSmrg * ^ 6041a30de1fSmrg * where the MODIFIER is one of Shift, Lock, Control, Mod[1-5] where case 6051a30de1fSmrg * is not important. There should also be an alias Ctrl for control. 6061a30de1fSmrg */ 6071a30de1fSmrg 6081a30de1fSmrgstatic void 6091a30de1fSmrgdo_remove(char *line, int len) 6101a30de1fSmrg{ 6111a30de1fSmrg int n; 6121a30de1fSmrg int nc; 6131a30de1fSmrg int i; 6141a30de1fSmrg int tot; 6151a30de1fSmrg int modifier; 6161a30de1fSmrg KeySym *kslist; 6171a30de1fSmrg KeyCode *kclist; 6181a30de1fSmrg union op *uop; 6191a30de1fSmrg struct op_removemodifier *oprm; 6201a30de1fSmrg 6211a30de1fSmrg if (len < 6 || !line || *line == '\0') { /* Lock=a minimum */ 6221a30de1fSmrg badmsg0 ("remove modifier input line"); 6231a30de1fSmrg return; 6241a30de1fSmrg } 6251a30de1fSmrg 6261a30de1fSmrg n = skip_chars (line, len); 6271a30de1fSmrg if (n < 1) { 6281a30de1fSmrg badmsg ("remove modifier name %s", line); 6291a30de1fSmrg return; 6301a30de1fSmrg } 6311a30de1fSmrg 6321a30de1fSmrg modifier = parse_modifier (line, n); 6331a30de1fSmrg if (modifier < 0) { 6341a30de1fSmrg badmsgn ("remove modifier name '%s', not allowed", line, n); 6351a30de1fSmrg return; 6361a30de1fSmrg } 6371a30de1fSmrg 6381a30de1fSmrg line += n, len -= n; 6391a30de1fSmrg n = skip_until_char (line, len, '='); 6401a30de1fSmrg if (n < 0) { 6411a30de1fSmrg badmsg0 ("remove modifier = keysym"); 6421a30de1fSmrg return; 6431a30de1fSmrg } 6441a30de1fSmrg 6451a30de1fSmrg n++; 6461a30de1fSmrg n += skip_space (line+n, len-n); 6471a30de1fSmrg line += n, len -= n; 6481a30de1fSmrg 6491a30de1fSmrg if (get_keysym_list (line, len, &n, &kslist) < 0) 6501a30de1fSmrg return; 6511a30de1fSmrg if (n == 0) { 6521a30de1fSmrg badmsg0 ("remove modifier keysym list (empty)"); 6531a30de1fSmrg return; 6541a30de1fSmrg } 6551a30de1fSmrg 6561a30de1fSmrg /* 6571a30de1fSmrg * unlike the add command, we have to now evaluate the keysyms 6581a30de1fSmrg */ 6591a30de1fSmrg 6601a30de1fSmrg kclist = (KeyCode *) malloc (n * sizeof (KeyCode)); 6611a30de1fSmrg if (!kclist) { 6621a30de1fSmrg badmsg ("attempt to allocate %ld byte keycode list", 6631a30de1fSmrg (long) (n * sizeof (KeyCode))); 6641a30de1fSmrg free ((char *) kslist); 6651a30de1fSmrg return; 6661a30de1fSmrg } 6671a30de1fSmrg 6681a30de1fSmrg tot = n; 6691a30de1fSmrg nc = 0; 6701a30de1fSmrg for (i = 0; i < n; i++) { 6711a30de1fSmrg int num_kcs; 6721a30de1fSmrg KeyCode *kcs; 6731a30de1fSmrg kcs = KeysymToKeycodes (dpy, kslist[i], &num_kcs); 6741a30de1fSmrg if (num_kcs == 0) { 6751a30de1fSmrg char *tmpname = XKeysymToString (kslist[i]); 6761a30de1fSmrg badmsg ("keysym in remove modifier list '%s', no corresponding keycodes", 6771a30de1fSmrg tmpname ? tmpname : "?"); 6781a30de1fSmrg continue; 6791a30de1fSmrg } 6801a30de1fSmrg if (verbose) { 6811a30de1fSmrg int j; 6821a30de1fSmrg char *tmpname = XKeysymToString (kslist[i]); 6831a30de1fSmrg printf ("! Keysym %s (0x%lx) corresponds to keycode(s)", 6841a30de1fSmrg tmpname ? tmpname : "?", (long) kslist[i]); 6851a30de1fSmrg for (j = 0; j < num_kcs; j++) 6861a30de1fSmrg printf(" 0x%x", kcs[j]); 6871a30de1fSmrg printf("\n"); 6881a30de1fSmrg } 6891a30de1fSmrg if (nc + num_kcs > tot) { 6901a30de1fSmrg tot = nc + num_kcs; 6911a30de1fSmrg kclist = (KeyCode *)realloc((char *)kclist, tot * sizeof(KeyCode)); 6921a30de1fSmrg if (!kclist) { 6931a30de1fSmrg badmsg ("attempt to allocate %ld byte keycode list", 6941a30de1fSmrg (long) (tot * sizeof (KeyCode))); 6951a30de1fSmrg free ((char *) kslist); 6961a30de1fSmrg return; 6971a30de1fSmrg } 6981a30de1fSmrg } 6991a30de1fSmrg while (--num_kcs >= 0) 7001a30de1fSmrg kclist[nc++] = *kcs++; /* okay, add it to list */ 7011a30de1fSmrg } 7021a30de1fSmrg 7031a30de1fSmrg free ((char *) kslist); /* all done with it */ 7041a30de1fSmrg 7051a30de1fSmrg uop = AllocStruct (union op); 7061a30de1fSmrg if (!uop) { 7071a30de1fSmrg badmsg ("attempt to allocate %ld byte removemodifier opcode", 7081a30de1fSmrg (long) sizeof (struct op_removemodifier)); 7091a30de1fSmrg return; 7101a30de1fSmrg } 7111a30de1fSmrg oprm = &uop->removemodifier; 7121a30de1fSmrg 7131a30de1fSmrg oprm->type = doRemoveModifier; 7141a30de1fSmrg oprm->modifier = modifier; 7151a30de1fSmrg oprm->count = nc; 7161a30de1fSmrg oprm->keycodes = kclist; 7171a30de1fSmrg 7181a30de1fSmrg add_to_work_queue (uop); 7191a30de1fSmrg} 7201a30de1fSmrg 7211a30de1fSmrg#ifdef AUTO_ADD_REMOVE 7221a30de1fSmrg/* 7231a30de1fSmrg * make_remove - stick a single remove onto the queue 7241a30de1fSmrg */ 7251a30de1fSmrgstatic void 7261a30de1fSmrgmake_remove(int modifier, KeyCode keycode) 7271a30de1fSmrg{ 7281a30de1fSmrg union op *uop; 7291a30de1fSmrg struct op_removemodifier *oprm; 7301a30de1fSmrg 7311a30de1fSmrg uop = AllocStruct (union op); 7321a30de1fSmrg if (!uop) { 7331a30de1fSmrg badmsg ("attempt to allocate %ld byte removemodifier opcode", 7341a30de1fSmrg (long) sizeof (struct op_removemodifier)); 7351a30de1fSmrg return; 7361a30de1fSmrg } 7371a30de1fSmrg oprm = &uop->removemodifier; 7381a30de1fSmrg 7391a30de1fSmrg oprm->type = doRemoveModifier; 7401a30de1fSmrg oprm->modifier = modifier; 7411a30de1fSmrg oprm->count = 1; 7421a30de1fSmrg oprm->keycodes = (KeyCode *) malloc (sizeof (KeyCode)); 7431a30de1fSmrg if (!oprm->keycodes) { 7441a30de1fSmrg badmsg ("attempt to allocate %ld byte KeyCode", 7451a30de1fSmrg (long) sizeof (KeyCode)); 7461a30de1fSmrg free ((char *) oprm); 7471a30de1fSmrg return; 7481a30de1fSmrg } 7491a30de1fSmrg oprm->keycodes[0] = keycode; 7501a30de1fSmrg 7511a30de1fSmrg add_to_work_queue (uop); 7521a30de1fSmrg return; 7531a30de1fSmrg} 7541a30de1fSmrg#endif /* AUTO_ADD_REMOVE */ 7551a30de1fSmrg 7561a30de1fSmrg 7571a30de1fSmrg/* 7581a30de1fSmrg * do_clear - parse off lines of the form 7591a30de1fSmrg * 7601a30de1fSmrg * clear MODIFIER 7611a30de1fSmrg * ^ 7621a30de1fSmrg */ 7631a30de1fSmrg 7641a30de1fSmrgstatic void 7651a30de1fSmrgdo_clear(char *line, int len) 7661a30de1fSmrg{ 7671a30de1fSmrg int n; 7681a30de1fSmrg int modifier; 7691a30de1fSmrg union op *uop; 7701a30de1fSmrg struct op_clearmodifier *opcm; 7711a30de1fSmrg 7721a30de1fSmrg if (len < 4 || !line || *line == '\0') { /* Lock minimum */ 7731a30de1fSmrg badmsg0 ("clear modifier input line"); 7741a30de1fSmrg return; 7751a30de1fSmrg } 7761a30de1fSmrg 7771a30de1fSmrg n = skip_chars (line, len); 7781a30de1fSmrg 7791a30de1fSmrg modifier = parse_modifier (line, n); 7801a30de1fSmrg if (modifier < 0) { 7811a30de1fSmrg badmsgn ("clear modifier name '%s'", line, n); 7821a30de1fSmrg return; 7831a30de1fSmrg } 7841a30de1fSmrg n += skip_space (line+n, len-n); 7851a30de1fSmrg if (n != len) { 7861a30de1fSmrg badmsgn ("extra argument '%s' to clear modifier", line+n, len-n); 7871a30de1fSmrg /* okay to continue */ 7881a30de1fSmrg } 7891a30de1fSmrg 7901a30de1fSmrg uop = AllocStruct (union op); 7911a30de1fSmrg if (!uop) { 7921a30de1fSmrg badmsg ("attempt to allocate %ld byte clearmodifier opcode", 7931a30de1fSmrg (long) sizeof (struct op_clearmodifier)); 7941a30de1fSmrg return; 7951a30de1fSmrg } 7961a30de1fSmrg opcm = &uop->clearmodifier; 7971a30de1fSmrg 7981a30de1fSmrg opcm->type = doClearModifier; 7991a30de1fSmrg opcm->modifier = modifier; 8001a30de1fSmrg 8011a30de1fSmrg add_to_work_queue (uop); 8021a30de1fSmrg} 8031a30de1fSmrg 8041a30de1fSmrg#ifndef HAVE_STRNCASECMP 8051a30de1fSmrgstatic int 8061a30de1fSmrgstrncasecmp(const char *a, const char *b, int n) 8071a30de1fSmrg{ 8081a30de1fSmrg int i; 8091a30de1fSmrg int a1, b1; 8101a30de1fSmrg 8111a30de1fSmrg for (i = 0; i < n; i++, a++, b++) { 8121a30de1fSmrg if (!*a) return -1; 8131a30de1fSmrg if (!*b) return 1; 8141a30de1fSmrg 8151a30de1fSmrg if (*a != *b) { 8161a30de1fSmrg a1 = (isascii(*a) && isupper(*a)) ? tolower(*a) : *a; 8171a30de1fSmrg b1 = (isascii(*b) && isupper(*b)) ? tolower(*b) : *b; 8181a30de1fSmrg if (a1 != b1) return b1 - a1; 8191a30de1fSmrg } 8201a30de1fSmrg } 8211a30de1fSmrg return 0; 8221a30de1fSmrg} 8231a30de1fSmrg#endif 8241a30de1fSmrg 8251a30de1fSmrg/* 8261a30de1fSmrg * do_pointer = get list of numbers of the form 8271a30de1fSmrg * 8281a30de1fSmrg * buttons = NUMBER ... 8291a30de1fSmrg * ^ 8301a30de1fSmrg */ 8311a30de1fSmrg 8321a30de1fSmrgstatic void 8331a30de1fSmrgdo_pointer(char *line, int len) 8341a30de1fSmrg{ 8351a30de1fSmrg int n; 8361a30de1fSmrg int i; 8371a30de1fSmrg unsigned long val; 8381a30de1fSmrg union op *uop; 8391a30de1fSmrg struct op_pointer *opp; 8401a30de1fSmrg unsigned char buttons[MAXBUTTONCODES]; 8411a30de1fSmrg int nbuttons; 8421a30de1fSmrg char *strval; 8431a30de1fSmrg Bool ok; 8441a30de1fSmrg 8451a30de1fSmrg if (len < 2 || !line || *line == '\0') { /* =1 minimum */ 8461a30de1fSmrg badmsg0 ("buttons input line"); 8471a30de1fSmrg return; 8481a30de1fSmrg } 8491a30de1fSmrg 8501a30de1fSmrg nbuttons = XGetPointerMapping (dpy, buttons, MAXBUTTONCODES); 8511a30de1fSmrg 8521a30de1fSmrg n = skip_space (line, len); 8531a30de1fSmrg line += n, len -= n; 8541a30de1fSmrg 8551a30de1fSmrg if (line[0] != '=') { 8561a30de1fSmrg badmsg0 ("buttons pointer code list, missing equal sign"); 8571a30de1fSmrg return; 8581a30de1fSmrg } 8591a30de1fSmrg 8601a30de1fSmrg line++, len--; /* skip = */ 8611a30de1fSmrg n = skip_space (line, len); 8621a30de1fSmrg line += n, len -= n; 8631a30de1fSmrg 8641a30de1fSmrg i = 0; 8651a30de1fSmrg if (len < 7 || strncasecmp (line, "default", 7) != 0) { 8661a30de1fSmrg while (len > 0) { 8671a30de1fSmrg n = skip_space (line, len); 8681a30de1fSmrg line += n, len -= n; 8691a30de1fSmrg if (line[0] == '\0') break; 8701a30de1fSmrg n = skip_word (line, len); 8711a30de1fSmrg if (n < 1) { 8721a30de1fSmrg badmsg ("skip of word in buttons line: %s", line); 8731a30de1fSmrg return; 8741a30de1fSmrg } 8751a30de1fSmrg strval = copy_to_scratch(line, n); 8761a30de1fSmrg ok = parse_number (strval, &val); 8771a30de1fSmrg if (!ok || val >= MAXBUTTONCODES) { 8781a30de1fSmrg badmsg ("value %s given for buttons list", strval); 8791a30de1fSmrg return; 8801a30de1fSmrg } 8811a30de1fSmrg buttons[i++] = (unsigned char) val; 8821a30de1fSmrg line += n, len -= n; 8831a30de1fSmrg } 8841a30de1fSmrg } 8851a30de1fSmrg 8861a30de1fSmrg if (i > 0 && i != nbuttons) { 8871a30de1fSmrg fprintf (stderr, "Warning: Only changing the first %d of %d buttons.\n", 8881a30de1fSmrg i, nbuttons); 8891a30de1fSmrg i = nbuttons; 8901a30de1fSmrg } 8911a30de1fSmrg 8921a30de1fSmrg uop = AllocStruct (union op); 8931a30de1fSmrg if (!uop) { 8941a30de1fSmrg badmsg ("attempt to allocate a %ld byte pointer opcode", 8951a30de1fSmrg (long) sizeof (struct op_pointer)); 8961a30de1fSmrg return; 8971a30de1fSmrg } 8981a30de1fSmrg opp = &uop->pointer; 8991a30de1fSmrg 9001a30de1fSmrg opp->type = doPointer; 9011a30de1fSmrg opp->count = i; 9021a30de1fSmrg for (i = 0; i < opp->count; i++) { 9031a30de1fSmrg opp->button_codes[i] = buttons[i]; 9041a30de1fSmrg } 9051a30de1fSmrg 9061a30de1fSmrg add_to_work_queue (uop); 9071a30de1fSmrg} 9081a30de1fSmrg 9091a30de1fSmrg 9101a30de1fSmrg/* 9111a30de1fSmrg * get_keysym_list - parses the rest of the line into a keysyms assumes 9121a30de1fSmrg * that the = sign has been parsed off but there may be leading whitespace 9131a30de1fSmrg * 9141a30de1fSmrg * keysym ... 9151a30de1fSmrg * ^ 9161a30de1fSmrg * 9171a30de1fSmrg * this involves getting the word containing the keysym, checking its range, 9181a30de1fSmrg * and adding it to the list. 9191a30de1fSmrg */ 9201a30de1fSmrg 9211a30de1fSmrgstatic int 9221a30de1fSmrgget_keysym_list(const char *line, int len, int *np, KeySym **kslistp) 9231a30de1fSmrg{ 9241a30de1fSmrg int havesofar, maxcanhave; 9251a30de1fSmrg KeySym *keysymlist; 9261a30de1fSmrg 9271a30de1fSmrg *np = 0; 9281a30de1fSmrg *kslistp = NULL; 9291a30de1fSmrg 9301a30de1fSmrg if (len == 0) return (0); /* empty list */ 9311a30de1fSmrg 9321a30de1fSmrg havesofar = 0; 9331a30de1fSmrg maxcanhave = 4; /* most lists are small */ 9341a30de1fSmrg keysymlist = (KeySym *) malloc (maxcanhave * sizeof (KeySym)); 9351a30de1fSmrg if (!keysymlist) { 9361a30de1fSmrg badmsg ("attempt to allocate %ld byte initial keysymlist", 9371a30de1fSmrg (long) (maxcanhave * sizeof (KeySym))); 9381a30de1fSmrg return (-1); 9391a30de1fSmrg } 9401a30de1fSmrg 9411a30de1fSmrg while (len > 0) { 9421a30de1fSmrg KeySym keysym; 9431a30de1fSmrg int n; 9441a30de1fSmrg char *tmpname; 9451a30de1fSmrg Bool ok; 9461a30de1fSmrg 9471a30de1fSmrg n = skip_space (line, len); 9481a30de1fSmrg line += n, len -= n; 9491a30de1fSmrg 9501a30de1fSmrg n = skip_chars (line, len); 9511a30de1fSmrg if (n < 0) { 9521a30de1fSmrg badmsg0 ("keysym name list"); 9531a30de1fSmrg free(keysymlist); 9541a30de1fSmrg return (-1); 9551a30de1fSmrg } 9561a30de1fSmrg 9571a30de1fSmrg ok = parse_keysym (line, n, &tmpname, &keysym); 9581a30de1fSmrg line += n, len -= n; 9591a30de1fSmrg if (!ok) { 9601a30de1fSmrg badmsg ("keysym name '%s' in keysym list", tmpname); 9611a30de1fSmrg /* do NOT return here, look for others */ 9621a30de1fSmrg continue; 9631a30de1fSmrg } 9641a30de1fSmrg 9651a30de1fSmrg /* 9661a30de1fSmrg * Do NOT test to see if the keysym translates to a keycode or you 9671a30de1fSmrg * won't be able to assign new ones.... 9681a30de1fSmrg */ 9691a30de1fSmrg 9701a30de1fSmrg /* grow the list bigger if necessary */ 9711a30de1fSmrg if (havesofar >= maxcanhave) { 9721a30de1fSmrg KeySym *origkeysymlist = keysymlist; 9731a30de1fSmrg maxcanhave *= 2; 9741a30de1fSmrg keysymlist = (KeySym *) realloc (keysymlist, 9751a30de1fSmrg maxcanhave * sizeof (KeySym)); 9761a30de1fSmrg if (!keysymlist) { 9771a30de1fSmrg badmsg ("attempt to grow keysym list to %ld bytes", 9781a30de1fSmrg (long) (maxcanhave * sizeof (KeySym))); 9791a30de1fSmrg free(origkeysymlist); 9801a30de1fSmrg return (-1); 9811a30de1fSmrg } 9821a30de1fSmrg } 9831a30de1fSmrg 9841a30de1fSmrg /* and add it to the list */ 9851a30de1fSmrg keysymlist[havesofar++] = keysym; 9861a30de1fSmrg } 9871a30de1fSmrg 9881a30de1fSmrg *kslistp = keysymlist; 9891a30de1fSmrg *np = havesofar; 9901a30de1fSmrg return (0); 9911a30de1fSmrg} 9921a30de1fSmrg 9931a30de1fSmrg 9941a30de1fSmrg#ifdef later 9951a30de1fSmrg/* 9961a30de1fSmrg * check_special_keys - run through list of keysyms and generate "add" or 9971a30de1fSmrg * "remove" commands for for any of the key syms that appear in the modifier 9981a30de1fSmrg * list. this involves running down the modifier map which is an array of 9991a30de1fSmrg * 8 by map->max_keypermod keycodes. 10001a30de1fSmrg */ 10011a30de1fSmrg 10021a30de1fSmrgstatic void 10031a30de1fSmrgcheck_special_keys(KeyCode keycode, int n, KeySym *kslist) 10041a30de1fSmrg{ 10051a30de1fSmrg int i; /* iterator variable */ 10061a30de1fSmrg KeyCode *kcp; /* keycode pointer */ 10071a30de1fSmrg 10081a30de1fSmrg /* 10091a30de1fSmrg * walk the modifiermap array. since its dimensions are not known at 10101a30de1fSmrg * compile time, we have to walk it by hand instead of indexing. this 10111a30de1fSmrg * is why it is initialized outside the loop, but incremented inside the 10121a30de1fSmrg * second loop. 10131a30de1fSmrg */ 10141a30de1fSmrg 10151a30de1fSmrg kcp = map->modifiermap; /* start at beginning and iterate */ 10161a30de1fSmrg for (i = 0; i < 8; i++) { /* there are 8 modifier keys */ 10171a30de1fSmrg int j; 10181a30de1fSmrg 10191a30de1fSmrg for (j = 0; j < map->max_keypermod; j++, kcp++) { 10201a30de1fSmrg KeySym keysym; 10211a30de1fSmrg int k; 10221a30de1fSmrg 10231a30de1fSmrg if (!*kcp) continue; /* only non-zero entries significant */ 10241a30de1fSmrg 10251a30de1fSmrg /* 10261a30de1fSmrg * check to see if the target keycode is already a modifier; if so, 10271a30de1fSmrg * then we have to remove it 10281a30de1fSmrg */ 10291a30de1fSmrg if (keycode == *kcp) { 10301a30de1fSmrg make_remove (i, keycode); 10311a30de1fSmrg } 10321a30de1fSmrg 10331a30de1fSmrg /* 10341a30de1fSmrg * now, check to see if any of the keysyms map to keycodes 10351a30de1fSmrg * that are in the modifier list 10361a30de1fSmrg */ 10371a30de1fSmrg for (k = 0; k < n; k++) { 10381a30de1fSmrg KeyCodes kc; 10391a30de1fSmrg 10401a30de1fSmrg kc = XKeysymToKeycode (dpy, kslist[k]); 10411a30de1fSmrg if (kc == *kcp) { /* yup, found one */ 10421a30de1fSmrg /* 10431a30de1fSmrg * have to generate a remove of the CURRENT keycode 10441a30de1fSmrg * and then an add of the new KEYCODE 10451a30de1fSmrg */ 10461a30de1fSmrg make_remove (i, kc); /* modifier, keycode */ 10471a30de1fSmrg make_add (i, kslist[k]); /* modifier, keysym */ 10481a30de1fSmrg } 10491a30de1fSmrg } 10501a30de1fSmrg } 10511a30de1fSmrg } 10521a30de1fSmrg return; 10531a30de1fSmrg} 10541a30de1fSmrg#endif 10551a30de1fSmrg 10561a30de1fSmrg/* 10571a30de1fSmrg * print_work_queue - disassemble the work queue and print it on stdout 10581a30de1fSmrg */ 10591a30de1fSmrg 10601a30de1fSmrgvoid 10611a30de1fSmrgprint_work_queue(void) 10621a30de1fSmrg{ 10631a30de1fSmrg union op *op; 10641a30de1fSmrg 10651a30de1fSmrg printf ("! dump of work queue\n"); 10661a30de1fSmrg for (op = work_queue.head; op; op = op->generic.next) { 10671a30de1fSmrg print_opcode (op); 10681a30de1fSmrg } 10691a30de1fSmrg return; 10701a30de1fSmrg} 10711a30de1fSmrg 10721a30de1fSmrgstatic void 10731a30de1fSmrgprint_opcode(union op *op) 10741a30de1fSmrg{ 10751a30de1fSmrg int i; 10761a30de1fSmrg 10771a30de1fSmrg printf (" "); 10781a30de1fSmrg switch (op->generic.type) { 10791a30de1fSmrg case doKeycode: 10801a30de1fSmrg if (op->keycode.target_keycode) 10811a30de1fSmrg printf ("keycode 0x%lx =", (long) op->keycode.target_keycode); 10821a30de1fSmrg else 10831a30de1fSmrg printf ("keycode any ="); 10841a30de1fSmrg for (i = 0; i < op->keycode.count; i++) { 10851a30de1fSmrg char *name = XKeysymToString (op->keycode.keysyms[i]); 10861a30de1fSmrg 10871a30de1fSmrg printf (" %s", name ? name : "BADKEYSYM"); 10881a30de1fSmrg } 10891a30de1fSmrg printf ("\n"); 10901a30de1fSmrg break; 10911a30de1fSmrg case doAddModifier: 10921a30de1fSmrg printf ("add %s =", modifier_table[op->addmodifier.modifier].name); 10931a30de1fSmrg for (i = 0; i < op->addmodifier.count; i++) { 10941a30de1fSmrg char *name = XKeysymToString (op->addmodifier.keysyms[i]); 10951a30de1fSmrg printf (" %s", name ? name : "BADKEYSYM"); 10961a30de1fSmrg } 10971a30de1fSmrg printf ("\n"); 10981a30de1fSmrg break; 10991a30de1fSmrg case doRemoveModifier: 11001a30de1fSmrg printf ("remove %s = ", 11011a30de1fSmrg modifier_table[op->removemodifier.modifier].name); 11021a30de1fSmrg for (i = 0; i < op->removemodifier.count; i++) { 11031a30de1fSmrg printf (" 0x%lx", (long) op->removemodifier.keycodes[i]); 11041a30de1fSmrg } 11051a30de1fSmrg printf ("\n"); 11061a30de1fSmrg break; 11071a30de1fSmrg case doClearModifier: 11081a30de1fSmrg printf ("clear %s\n", modifier_table[op->clearmodifier.modifier].name); 11091a30de1fSmrg break; 11101a30de1fSmrg case doPointer: 11111a30de1fSmrg printf ("pointer = "); 11121a30de1fSmrg if (op->pointer.count == 0) 11131a30de1fSmrg printf(" default"); 11141a30de1fSmrg else for (i=0; i < op->pointer.count; i++) 11151a30de1fSmrg printf(" %d", op->pointer.button_codes[i]); 11161a30de1fSmrg printf ("\n"); 11171a30de1fSmrg break; 11181a30de1fSmrg default: 11191a30de1fSmrg printf ("! unknown opcode %d\n", op->generic.type); 11201a30de1fSmrg break; 11211a30de1fSmrg } /* end switch */ 11221a30de1fSmrg return; 11231a30de1fSmrg} 11241a30de1fSmrg 11251a30de1fSmrg/* 11261a30de1fSmrg * execute_work_queue - do the real meat and potatoes now that we know what 11271a30de1fSmrg * we need to do and that all of the input is correct. 11281a30de1fSmrg */ 11291a30de1fSmrgstatic int exec_keycode ( struct op_keycode *opk ); 11301a30de1fSmrgstatic int exec_add ( struct op_addmodifier *opam ); 11311a30de1fSmrgstatic int exec_remove ( struct op_removemodifier *oprm ); 11321a30de1fSmrgstatic int exec_clear ( struct op_clearmodifier *opcm ); 11331a30de1fSmrgstatic int exec_pointer ( struct op_pointer *opp ); 11341a30de1fSmrg 11351a30de1fSmrg 11361a30de1fSmrgint 11371a30de1fSmrgexecute_work_queue (void) 11381a30de1fSmrg{ 11391a30de1fSmrg union op *op; 11401a30de1fSmrg int errors; 11411a30de1fSmrg Bool update_map = False; 11421a30de1fSmrg int dosync; 11431a30de1fSmrg 11441a30de1fSmrg if (verbose) { 11451a30de1fSmrg printf ("!\n"); 11461a30de1fSmrg printf ("! executing work queue\n"); 11471a30de1fSmrg printf ("!\n"); 11481a30de1fSmrg } 11491a30de1fSmrg 11501a30de1fSmrg errors = 0; 11511a30de1fSmrg dosync = 0; 11521a30de1fSmrg 11531a30de1fSmrg for (op = work_queue.head; op; op = op->generic.next) { 11541a30de1fSmrg if (verbose) print_opcode (op); 11551a30de1fSmrg 11561a30de1fSmrg /* check to see if we have to update the keyboard mapping */ 11571a30de1fSmrg if (dosync && 11581a30de1fSmrg (dosync < 0 || 11591a30de1fSmrg op->generic.type != doKeycode || 11601a30de1fSmrg !op->keycode.target_keycode)) { 11611a30de1fSmrg XSync (dpy, 0); 11621a30de1fSmrg while (XEventsQueued (dpy, QueuedAlready) > 0) { 11631a30de1fSmrg XEvent event; 11641a30de1fSmrg XNextEvent (dpy, &event); 11651a30de1fSmrg if (event.type == MappingNotify) { 11661a30de1fSmrg /* read all MappingNotify events */ 11671a30de1fSmrg while (XCheckTypedEvent (dpy, MappingNotify, &event)) ; 11681a30de1fSmrg XRefreshKeyboardMapping (&event.xmapping); 11691a30de1fSmrg } else { 11701a30de1fSmrg fprintf (stderr, "%s: unknown event %ld\n", 11711a30de1fSmrg ProgramName, (long) event.type); 11721a30de1fSmrg } 11731a30de1fSmrg } 11741a30de1fSmrg } 11751a30de1fSmrg dosync = 0; 11761a30de1fSmrg switch (op->generic.type) { 11771a30de1fSmrg case doKeycode: 11781a30de1fSmrg if (exec_keycode (&op->keycode) < 0) errors++; 11791a30de1fSmrg if (op->keycode.target_keycode) 11801a30de1fSmrg dosync = 1; 11811a30de1fSmrg else 11821a30de1fSmrg dosync = -1; 11831a30de1fSmrg break; 11841a30de1fSmrg case doAddModifier: 11851a30de1fSmrg if (exec_add (&op->addmodifier) < 0) errors++; 11861a30de1fSmrg else update_map = True; 11871a30de1fSmrg break; 11881a30de1fSmrg case doRemoveModifier: 11891a30de1fSmrg if (exec_remove (&op->removemodifier) < 0) errors++; 11901a30de1fSmrg else update_map = True; 11911a30de1fSmrg break; 11921a30de1fSmrg case doClearModifier: 11931a30de1fSmrg if (exec_clear (&op->clearmodifier) < 0) errors++; 11941a30de1fSmrg else update_map = True; 11951a30de1fSmrg break; 11961a30de1fSmrg case doPointer: 11971a30de1fSmrg if (exec_pointer (&op->pointer) < 0) errors++; 11981a30de1fSmrg break; 11991a30de1fSmrg default: 12001a30de1fSmrg fprintf (stderr, "%s: unknown opcode %d\n", 12011a30de1fSmrg ProgramName, op->generic.type); 12021a30de1fSmrg break; 12031a30de1fSmrg } 12041a30de1fSmrg } 12051a30de1fSmrg 12061a30de1fSmrg if (update_map) { 12071a30de1fSmrg if (UpdateModifierMapping (map) < 0) errors++; 12081a30de1fSmrg } 12091a30de1fSmrg 12101a30de1fSmrg return (errors > 0 ? -1 : 0); 12111a30de1fSmrg} 12121a30de1fSmrg 12131a30de1fSmrgstatic int 12141a30de1fSmrgexec_keycode(struct op_keycode *opk) 12151a30de1fSmrg{ 12161a30de1fSmrg if (!opk->target_keycode) { 12171a30de1fSmrg int i, j; 12181a30de1fSmrg KeyCode free; 12191a30de1fSmrg if (!opk->count) 12201a30de1fSmrg return (0); 12211a30de1fSmrg free = 0; 12221a30de1fSmrg for (i = min_keycode; i <= max_keycode; i++) { 12231a30de1fSmrg for (j = 0; j < opk->count; j++) { 12241a30de1fSmrg if (XKeycodeToKeysym(dpy, (KeyCode) i, j) != opk->keysyms[j]) 12251a30de1fSmrg break; 12261a30de1fSmrg } 12271a30de1fSmrg if (j >= opk->count) 12281a30de1fSmrg return (0); 12291a30de1fSmrg if (free) 12301a30de1fSmrg continue; 12311a30de1fSmrg for (j = 0; j < 8; j++) { 12321a30de1fSmrg if (XKeycodeToKeysym(dpy, (KeyCode) i, j) != None) 12331a30de1fSmrg break; 12341a30de1fSmrg } 12351a30de1fSmrg if (j >= 8) 12361a30de1fSmrg free = i; 12371a30de1fSmrg } 12381a30de1fSmrg if (!free) { 12391a30de1fSmrg fprintf(stderr, "%s: no available keycode for assignment\n", 12401a30de1fSmrg ProgramName); 12411a30de1fSmrg return (-1); 12421a30de1fSmrg } 12431a30de1fSmrg XChangeKeyboardMapping (dpy, free, opk->count, opk->keysyms, 1); 12441a30de1fSmrg } else if (opk->count == 0) { 12451a30de1fSmrg KeySym dummy = NoSymbol; 12461a30de1fSmrg XChangeKeyboardMapping (dpy, opk->target_keycode, 1, 12471a30de1fSmrg &dummy, 1); 12481a30de1fSmrg } else { 12491a30de1fSmrg XChangeKeyboardMapping (dpy, opk->target_keycode, opk->count, 12501a30de1fSmrg opk->keysyms, 1); 12511a30de1fSmrg } 12521a30de1fSmrg return (0); 12531a30de1fSmrg} 12541a30de1fSmrg 12551a30de1fSmrgstatic int 12561a30de1fSmrgexec_add(struct op_addmodifier *opam) 12571a30de1fSmrg{ 12581a30de1fSmrg int i; 12591a30de1fSmrg int status; 12601a30de1fSmrg 12611a30de1fSmrg status = 0; 12621a30de1fSmrg for (i = 0; i < opam->count; i++) { 12631a30de1fSmrg int num_kcs; 12641a30de1fSmrg KeyCode *kcs; 12651a30de1fSmrg 12661a30de1fSmrg kcs = KeysymToKeycodes (dpy, opam->keysyms[i], &num_kcs); 12671a30de1fSmrg if (num_kcs == 0) 12681a30de1fSmrg status = -1; 12691a30de1fSmrg while (--num_kcs >= 0) { 12701a30de1fSmrg if (AddModifier (&map, *kcs++, opam->modifier) < 0) 12711a30de1fSmrg status = -1; 12721a30de1fSmrg } 12731a30de1fSmrg } 12741a30de1fSmrg return (status); 12751a30de1fSmrg} 12761a30de1fSmrg 12771a30de1fSmrgstatic int 12781a30de1fSmrgexec_remove(struct op_removemodifier *oprm) 12791a30de1fSmrg{ 12801a30de1fSmrg int i; 12811a30de1fSmrg int status; 12821a30de1fSmrg 12831a30de1fSmrg status = 0; 12841a30de1fSmrg for (i = 0; i < oprm->count; i++) { 12851a30de1fSmrg if (RemoveModifier (&map, oprm->keycodes[i], oprm->modifier) < 0) 12861a30de1fSmrg status = -1; 12871a30de1fSmrg } 12881a30de1fSmrg return (status); 12891a30de1fSmrg} 12901a30de1fSmrg 12911a30de1fSmrgstatic int 12921a30de1fSmrgexec_clear(struct op_clearmodifier *opcm) 12931a30de1fSmrg{ 12941a30de1fSmrg return (ClearModifier (&map, opcm->modifier)); 12951a30de1fSmrg} 12961a30de1fSmrg 12971a30de1fSmrg 12981a30de1fSmrgstatic int 12991a30de1fSmrgexec_pointer(struct op_pointer *opp) 13001a30de1fSmrg{ 13011a30de1fSmrg return (SetPointerMap (opp->button_codes, opp->count)); 13021a30de1fSmrg} 13031a30de1fSmrg 13041a30de1fSmrgvoid 13051a30de1fSmrgprint_modifier_map(void) 13061a30de1fSmrg{ 13071a30de1fSmrg PrintModifierMapping (map, stdout); 13081a30de1fSmrg return; 13091a30de1fSmrg} 13101a30de1fSmrg 13111a30de1fSmrgvoid 13121a30de1fSmrgprint_key_table(Bool exprs) 13131a30de1fSmrg{ 13141a30de1fSmrg PrintKeyTable (exprs, stdout); 13151a30de1fSmrg return; 13161a30de1fSmrg} 13171a30de1fSmrg 13181a30de1fSmrgvoid 13191a30de1fSmrgprint_pointer_map(void) 13201a30de1fSmrg{ 13211a30de1fSmrg PrintPointerMap (stdout); 13221a30de1fSmrg return; 13231a30de1fSmrg} 13241a30de1fSmrg 13251a30de1fSmrg 1326