handle.c revision 1b983734
1/* 2 3Copyright 1988, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included 12in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall 23not be used in advertising or otherwise to promote the sale, use or 24other dealings in this Software without prior written authorization 25from The Open Group. 26 27*/ 28 29#include "config.h" 30#include <X11/Xos.h> 31#include <X11/Xlib.h> 32#include <stdio.h> 33#include <ctype.h> 34#include "xmodmap.h" 35#include "wq.h" 36#include <stdlib.h> 37 38#ifdef HAVE_STRNCASECMP 39#include <strings.h> 40#endif 41 42static XModifierKeymap *map = NULL; 43 44 45/* 46 * The routines in this file manipulate a queue of intructions. Instead of 47 * executing each line as it is entered, we build up a list of actions to 48 * take and execute them all at the end. This allows us to find all errors 49 * at once, and to preserve the context in which we are looking up keysyms. 50 */ 51 52struct wq work_queue = {NULL, NULL}; 53 54 55/* 56 * common utility routines 57 */ 58 59static KeyCode * 60KeysymToKeycodes(Display *dpy, KeySym keysym, int *pnum_kcs) 61{ 62 KeyCode *kcs = NULL; 63 int i, j; 64 65 *pnum_kcs = 0; 66 for (i = min_keycode; i <= max_keycode; i++) { 67 for (j = 0; j < 8; j++) { 68 if (XKeycodeToKeysym(dpy, (KeyCode) i, j) == keysym) { 69 if (!kcs) 70 kcs = malloc(sizeof(KeyCode)); 71 else 72 kcs = realloc(kcs, sizeof(KeyCode) * (*pnum_kcs + 1)); 73 kcs[*pnum_kcs] = i; 74 *pnum_kcs += 1; 75 break; 76 } 77 } 78 } 79 return kcs; 80} 81 82static char * 83copy_to_scratch(const char *s, int len) 84{ 85 static char *buf = NULL; 86 static int buflen = 0; 87 88 if (len < 0) 89 len = 0; 90 91 if (len >= buflen) { 92 if (buf) free (buf); 93 buflen = (len < 40) ? 80 : (len * 2); 94 buf = malloc (buflen+1); 95 if (!buf) { 96 fprintf (stderr, "attempt to allocate %d byte scratch buffer\n", buflen + 1); 97 return NULL; 98 } 99 } 100 101 strncpy (buf, s, len); 102 buf[len] = '\0'; 103 104 return (buf); 105} 106 107static void 108badheader(void) 109{ 110 fprintf (stderr, "%s: %s:%d: bad ", ProgramName, inputFilename, lineno+1); 111 parse_errors++; 112} 113 114#define badmsg0(what) { badheader(); fprintf (stderr, what); \ 115 putc ('\n', stderr); } 116 117#define badmsg(what,arg) { badheader(); fprintf (stderr, what, arg); \ 118 putc ('\n', stderr); } 119 120#define badmsgn(what,s,len) badmsg (what, copy_to_scratch (s, len)) 121 122void 123initialize_map (void) 124{ 125 map = XGetModifierMapping (dpy); 126 return; 127} 128 129static void do_keycode ( char *line, int len ); 130static void do_keysym ( char *line, int len ); 131static void finish_keycodes ( const char *line, int len, KeyCode *keycodes, 132 int count ); 133static void do_add ( char *line, int len ); 134static void do_remove ( char *line, int len ); 135static void do_clear ( char *line, int len ); 136static void do_pointer ( char *line, int len ); 137static int get_keysym_list ( const char *line, int len, int *np, KeySym **kslistp ); 138 139static void print_opcode(union op *op); 140 141static int skip_word ( const char *s, int len ); 142static int skip_chars ( const char *s, int len ); 143static int skip_space ( const char *s, int len ); 144 145static struct dt { 146 const char *command; /* name of input command */ 147 int length; /* length of command */ 148 void (*proc)(char *, int); /* handler */ 149} dispatch_table[] = { 150 { "keycode", 7, do_keycode }, 151 { "keysym", 6, do_keysym }, 152 { "add", 3, do_add }, 153 { "remove", 6, do_remove }, 154 { "clear", 5, do_clear }, 155 { "pointer", 7, do_pointer }, 156 { NULL, 0, NULL }}; 157 158/* 159 * handle_line - this routine parses the input line (which has had all leading 160 * and trailing whitespace removed) and builds up the work queue. 161 */ 162 163void 164handle_line(char *line, /* string to parse */ 165 int len) /* length of line */ 166{ 167 int n; 168 struct dt *dtp; 169 170 n = skip_chars (line, len); 171 if (n < 0) { 172 badmsg ("input line '%s'", line); 173 return; 174 } 175 176 for (dtp = dispatch_table; dtp->command != NULL; dtp++) { 177 if (n == dtp->length && 178 strncmp (line, dtp->command, dtp->length) == 0) { 179 180 n += skip_space (line+n, len-n); 181 line += n, len -= n; 182 183 (*(dtp->proc)) (line, len); 184 return; 185 } 186 } 187 188 fprintf (stderr, "%s: unknown command on line %s:%d\n", 189 ProgramName, inputFilename, lineno+1); 190 parse_errors++; 191} 192 193/* 194 * the following routines are useful for parsing 195 */ 196 197static int 198skip_word (const char *s, int len) 199{ 200 register int n; 201 202 n = skip_chars (s, len); 203 return (n + skip_space (s+n, len-n)); 204} 205 206static int 207skip_chars(const char *s, int len) 208{ 209 register int i; 210 211 if (len <= 0 || !s || *s == '\0') return (0); 212 213 for (i = 0; i < len; i++) { 214 if (isspace(s[i])) break; 215 } 216 return (i); 217} 218 219static int 220skip_space(const char *s, int len) 221{ 222 register int i; 223 224 if (len <= 0 || !s || *s == '\0') return (0); 225 226 for (i = 0; i < len; i++) { 227 if (!s[i] || !isspace(s[i])) break; 228 } 229 return (i); 230} 231 232 233static int 234skip_until_char(const char *s, int len, char c) 235{ 236 register int i; 237 238 for (i = 0; i < len; i++) { 239 if (s[i] == c) break; 240 } 241 return (i); 242} 243 244 245/* 246 * The action routines. 247 * 248 * This is where the real work gets done. Each routine is responsible for 249 * parsing its input (note that the command keyword has been stripped off) 250 * and adding to the work queue. They are also in charge of outputting 251 * error messages and returning non-zero if there is a problem. 252 * 253 * The following global variables are available: 254 * dpy the display descriptor 255 * work_queue linked list of opcodes 256 * inputFilename name of the file being processed 257 * lineno line number of current line in input file 258 */ 259static void 260add_to_work_queue(union op *p) /* this can become a macro someday */ 261{ 262 if (work_queue.head == NULL) { /* nothing on the list */ 263 work_queue.head = work_queue.tail = p; /* head, tail, no prev */ 264 } else { 265 work_queue.tail->generic.next = p; /* head okay, prev */ 266 work_queue.tail = p; /* tail */ 267 } 268 p->generic.next = NULL; 269 270 if (verbose) { 271 print_opcode (p); 272 } 273 return; 274} 275 276static Bool 277parse_number(const char *str, unsigned long *val) 278{ 279 const char *fmt = "%ld"; 280 281 if (*str == '0') { 282 str++; 283 while (isspace(*str)) 284 str++; 285 fmt = "%lo"; 286 if (*str == '\0') { 287 *val = 0; 288 return 1; 289 } 290 if (*str == 'x' || *str == 'X') { 291 str++; 292 fmt = "%lx"; 293 } 294 } 295 return (sscanf (str, fmt, val) == 1); 296} 297 298static Bool 299parse_keysym(const char *line, int n, char **name, KeySym *keysym) 300{ 301 *name = copy_to_scratch (line, n); 302 if (!strcmp(*name, "NoSymbol")) { 303 *keysym = NoSymbol; 304 return (True); 305 } 306 *keysym = XStringToKeysym (*name); 307 if (*keysym == NoSymbol && '0' <= **name && **name <= '9') 308 return parse_number(*name, keysym); 309 return (*keysym != NoSymbol); 310} 311 312/* 313 * do_keycode - parse off lines of the form 314 * 315 * "keycode" number "=" [keysym ...] 316 * ^ 317 * 318 * where number is in decimal, hex, or octal. Any number of keysyms may be 319 * listed. 320 */ 321 322static void 323do_keycode(char *line, int len) 324{ 325 int dummy; 326 const char *fmt = "%d"; 327 KeyCode keycode; 328 329 if (len < 3 || !line || *line == '\0') { /* 5=a minimum */ 330 badmsg0 ("keycode input line"); 331 return; 332 } 333 334 /* 335 * We need not bother to advance line/len past the 336 * number (or the string 'any') as finish_keycodes() will 337 * first advance past the '='. 338 */ 339 if (!strncmp("any", line, 3)) { 340 keycode = 0; 341 } else { 342 if (*line == '0') line++, len--, fmt = "%o"; 343 if (*line == 'x' || *line == 'X') line++, len--, fmt = "%x"; 344 345 dummy = 0; 346 if (sscanf (line, fmt, &dummy) != 1 || dummy == 0) { 347 badmsg0 ("keycode value"); 348 return; 349 } 350 keycode = (KeyCode) dummy; 351 if ((int)keycode < min_keycode || (int)keycode > max_keycode) { 352 badmsg0 ("keycode value (out of range)"); 353 return; 354 } 355 } 356 357 finish_keycodes (line, len, &keycode, 1); 358} 359 360 361/* 362 * do_keysym - parse off lines of the form 363 * 364 * "keysym" keysym "=" [keysym ...] 365 * ^ 366 * 367 * The left keysyms has to be checked for validity and evaluated. 368 */ 369 370static void 371do_keysym(char *line, int len) 372{ 373 int n; 374 KeyCode *keycodes; 375 KeySym keysym; 376 char *tmpname; 377 378 if (len < 3 || !line || *line == '\0') { /* a=b minimum */ 379 badmsg0 ("keysym input line"); 380 return; 381 } 382 383 n = skip_chars (line, len); 384 if (n < 1) { 385 badmsg0 ("target keysym name"); 386 return; 387 } 388 if (!parse_keysym(line, n, &tmpname, &keysym)) { 389 badmsg ("keysym target key symbol '%s'", tmpname); 390 return; 391 } 392 393 keycodes = KeysymToKeycodes (dpy, keysym, &n); 394 if (n == 0) { 395 badmsg ("keysym target keysym '%s', no corresponding keycodes", 396 tmpname); 397 return; 398 } 399 if (verbose) { 400 int i; 401 printf ("! Keysym %s (0x%lx) corresponds to keycode(s)", 402 tmpname, (long) keysym); 403 for (i = 0; i < n; i++) 404 printf (" 0x%x", keycodes[i]); 405 printf("\n"); 406 } 407 408 finish_keycodes (line, len, keycodes, n); 409} 410 411static void 412finish_keycodes(const char *line, int len, KeyCode *keycodes, int count) 413{ 414 int n; 415 KeySym *kslist; 416 union op *uop; 417 struct op_keycode *opk; 418 419 n = skip_until_char (line, len, '='); 420 line += n, len -= n; 421 422 if (len < 1 || *line != '=') { /* = minimum */ 423 badmsg0 ("keycode command (missing keysym list),"); 424 return; 425 } 426 line++, len--; /* skip past the = */ 427 428 n = skip_space (line, len); 429 line += n, len -= n; 430 431 /* allow empty list */ 432 if (get_keysym_list (line, len, &n, &kslist) < 0) 433 return; 434 435 while (--count >= 0) { 436 uop = AllocStruct (union op); 437 if (!uop) { 438 badmsg ("attempt to allocate a %ld byte keycode opcode", 439 (long) sizeof (struct op_keycode)); 440 return; 441 } 442 opk = &uop->keycode; 443 444 opk->type = doKeycode; 445 opk->target_keycode = keycodes[count]; 446 opk->count = n; 447 opk->keysyms = kslist; 448 449 add_to_work_queue (uop); 450 } 451 452#ifdef later 453 /* make sure we handle any special keys */ 454 check_special_keys (keycode, n, kslist); 455#endif 456} 457 458 459/* 460 * parse_modifier - convert a modifier string name to its index 461 */ 462 463struct modtab modifier_table[] = { /* keep in order so it can be index */ 464 { "shift", 5, 0 }, 465 { "lock", 4, 1 }, 466 { "control", 7, 2 }, 467 { "mod1", 4, 3 }, 468 { "mod2", 4, 4 }, 469 { "mod3", 4, 5 }, 470 { "mod4", 4, 6 }, 471 { "mod5", 4, 7 }, 472 { "ctrl", 4, 2 }, 473 { NULL, 0, 0 }}; 474 475static int 476parse_modifier(char *line, int n) 477{ 478 register int i; 479 struct modtab *mt; 480 481 /* lowercase for comparison against table */ 482 for (i = 0; i < n; i++) { 483 if (isupper (line[i])) line[i] = tolower (line[i]); 484 } 485 486 for (mt = modifier_table; mt->name; mt++) { 487 if (n == mt->length && strncmp (line, mt->name, n) == 0) 488 return (mt->value); 489 } 490 return (-1); 491} 492 493 494/* 495 * do_add - parse off lines of the form 496 * 497 * add MODIFIER = keysym ... 498 * ^ 499 * where the MODIFIER is one of Shift, Lock, Control, Mod[1-5] where case 500 * is not important. There should also be an alias Ctrl for control. 501 */ 502 503static void 504do_add(char *line, int len) 505{ 506 int n; 507 int modifier; 508 KeySym *kslist; 509 union op *uop; 510 struct op_addmodifier *opam; 511 512 if (len < 6 || !line || *line == '\0') { /* Lock=a minimum */ 513 badmsg0 ("add modifier input line"); 514 return; 515 } 516 517 n = skip_chars (line, len); 518 if (n < 1) { 519 badmsg ("add modifier name %s", line); 520 return; 521 } 522 523 modifier = parse_modifier (line, n); 524 if (modifier < 0) { 525 badmsgn ("add modifier name '%s', not allowed", line, n); 526 return; 527 } 528 529 line += n, len -= n; 530 n = skip_until_char (line, len, '='); 531 if (n < 0) { 532 badmsg0 ("add modifier = keysym"); 533 return; 534 } 535 536 n++; /* skip = */ 537 n += skip_space (line+n, len-n); 538 line += n, len -= n; 539 540 if (get_keysym_list (line, len, &n, &kslist) < 0) 541 return; 542 if (n == 0) { 543 badmsg0 ("add modifier keysym list (empty)"); 544 return; 545 } 546 547 uop = AllocStruct (union op); 548 if (!uop) { 549 badmsg ("attempt to allocate %ld byte addmodifier opcode", 550 (long) sizeof (struct op_addmodifier)); 551 return; 552 } 553 opam = &uop->addmodifier; 554 555 opam->type = doAddModifier; 556 opam->modifier = modifier; 557 opam->count = n; 558 opam->keysyms = kslist; 559 560 add_to_work_queue (uop); 561} 562 563#ifdef AUTO_ADD_REMOVE 564/* 565 * make_add - stick a single add onto the queue 566 */ 567static void 568make_add(int modifier, KeySym keysym) 569{ 570 union op *uop; 571 struct op_addmodifier *opam; 572 573 uop = AllocStruct (union op); 574 if (!uop) { 575 badmsg ("attempt to allocate %ld byte addmodifier opcode", 576 (long) sizeof (struct op_addmodifier)); 577 return; 578 } 579 opam = &uop->addmodifier; 580 581 opam->type = doAddModifier; 582 opam->modifier = modifier; 583 opam->count = 1; 584 opam->keysyms = malloc (sizeof (KeySym)); 585 if (!opam->keysyms) { 586 badmsg ("attempt to allocate %ld byte KeySym", (long) sizeof (KeySym)); 587 free (opam); 588 return; 589 } 590 opam->keysyms[0] = keysym; 591 592 add_to_work_queue (uop); 593 return; 594} 595#endif /* AUTO_ADD_REMOVE */ 596 597 598/* 599 * do_remove - parse off lines of the form 600 * 601 * remove MODIFIER = oldkeysym ... 602 * ^ 603 * where the MODIFIER is one of Shift, Lock, Control, Mod[1-5] where case 604 * is not important. There should also be an alias Ctrl for control. 605 */ 606 607static void 608do_remove(char *line, int len) 609{ 610 int n; 611 int nc; 612 int i; 613 int tot; 614 int modifier; 615 KeySym *kslist; 616 KeyCode *kclist; 617 union op *uop; 618 struct op_removemodifier *oprm; 619 620 if (len < 6 || !line || *line == '\0') { /* Lock=a minimum */ 621 badmsg0 ("remove modifier input line"); 622 return; 623 } 624 625 n = skip_chars (line, len); 626 if (n < 1) { 627 badmsg ("remove modifier name %s", line); 628 return; 629 } 630 631 modifier = parse_modifier (line, n); 632 if (modifier < 0) { 633 badmsgn ("remove modifier name '%s', not allowed", line, n); 634 return; 635 } 636 637 line += n, len -= n; 638 n = skip_until_char (line, len, '='); 639 if (n < 0) { 640 badmsg0 ("remove modifier = keysym"); 641 return; 642 } 643 644 n++; 645 n += skip_space (line+n, len-n); 646 line += n, len -= n; 647 648 if (get_keysym_list (line, len, &n, &kslist) < 0) 649 return; 650 if (n == 0) { 651 badmsg0 ("remove modifier keysym list (empty)"); 652 return; 653 } 654 655 /* 656 * unlike the add command, we have to now evaluate the keysyms 657 */ 658 659 kclist = malloc (n * sizeof (KeyCode)); 660 if (!kclist) { 661 badmsg ("attempt to allocate %ld byte keycode list", 662 (long) (n * sizeof (KeyCode))); 663 free (kslist); 664 return; 665 } 666 667 tot = n; 668 nc = 0; 669 for (i = 0; i < n; i++) { 670 int num_kcs; 671 KeyCode *kcs; 672 kcs = KeysymToKeycodes (dpy, kslist[i], &num_kcs); 673 if (num_kcs == 0) { 674 char *tmpname = XKeysymToString (kslist[i]); 675 badmsg ("keysym in remove modifier list '%s', no corresponding keycodes", 676 tmpname ? tmpname : "?"); 677 continue; 678 } 679 if (verbose) { 680 int j; 681 char *tmpname = XKeysymToString (kslist[i]); 682 printf ("! Keysym %s (0x%lx) corresponds to keycode(s)", 683 tmpname ? tmpname : "?", (long) kslist[i]); 684 for (j = 0; j < num_kcs; j++) 685 printf(" 0x%x", kcs[j]); 686 printf("\n"); 687 } 688 if (nc + num_kcs > tot) { 689 tot = nc + num_kcs; 690 kclist = realloc(kclist, tot * sizeof(KeyCode)); 691 if (!kclist) { 692 badmsg ("attempt to allocate %ld byte keycode list", 693 (long) (tot * sizeof (KeyCode))); 694 free (kslist); 695 return; 696 } 697 } 698 while (--num_kcs >= 0) 699 kclist[nc++] = *kcs++; /* okay, add it to list */ 700 } 701 702 free (kslist); /* all done with it */ 703 704 uop = AllocStruct (union op); 705 if (!uop) { 706 badmsg ("attempt to allocate %ld byte removemodifier opcode", 707 (long) sizeof (struct op_removemodifier)); 708 return; 709 } 710 oprm = &uop->removemodifier; 711 712 oprm->type = doRemoveModifier; 713 oprm->modifier = modifier; 714 oprm->count = nc; 715 oprm->keycodes = kclist; 716 717 add_to_work_queue (uop); 718} 719 720#ifdef AUTO_ADD_REMOVE 721/* 722 * make_remove - stick a single remove onto the queue 723 */ 724static void 725make_remove(int modifier, KeyCode keycode) 726{ 727 union op *uop; 728 struct op_removemodifier *oprm; 729 730 uop = AllocStruct (union op); 731 if (!uop) { 732 badmsg ("attempt to allocate %ld byte removemodifier opcode", 733 (long) sizeof (struct op_removemodifier)); 734 return; 735 } 736 oprm = &uop->removemodifier; 737 738 oprm->type = doRemoveModifier; 739 oprm->modifier = modifier; 740 oprm->count = 1; 741 oprm->keycodes = malloc (sizeof (KeyCode)); 742 if (!oprm->keycodes) { 743 badmsg ("attempt to allocate %ld byte KeyCode", 744 (long) sizeof (KeyCode)); 745 free (oprm); 746 return; 747 } 748 oprm->keycodes[0] = keycode; 749 750 add_to_work_queue (uop); 751 return; 752} 753#endif /* AUTO_ADD_REMOVE */ 754 755 756/* 757 * do_clear - parse off lines of the form 758 * 759 * clear MODIFIER 760 * ^ 761 */ 762 763static void 764do_clear(char *line, int len) 765{ 766 int n; 767 int modifier; 768 union op *uop; 769 struct op_clearmodifier *opcm; 770 771 if (len < 4 || !line || *line == '\0') { /* Lock minimum */ 772 badmsg0 ("clear modifier input line"); 773 return; 774 } 775 776 n = skip_chars (line, len); 777 778 modifier = parse_modifier (line, n); 779 if (modifier < 0) { 780 badmsgn ("clear modifier name '%s'", line, n); 781 return; 782 } 783 n += skip_space (line+n, len-n); 784 if (n != len) { 785 badmsgn ("extra argument '%s' to clear modifier", line+n, len-n); 786 /* okay to continue */ 787 } 788 789 uop = AllocStruct (union op); 790 if (!uop) { 791 badmsg ("attempt to allocate %ld byte clearmodifier opcode", 792 (long) sizeof (struct op_clearmodifier)); 793 return; 794 } 795 opcm = &uop->clearmodifier; 796 797 opcm->type = doClearModifier; 798 opcm->modifier = modifier; 799 800 add_to_work_queue (uop); 801} 802 803#ifndef HAVE_STRNCASECMP 804static int 805strncasecmp(const char *a, const char *b, int n) 806{ 807 int i; 808 int a1, b1; 809 810 for (i = 0; i < n; i++, a++, b++) { 811 if (!*a) return -1; 812 if (!*b) return 1; 813 814 if (*a != *b) { 815 a1 = (isascii(*a) && isupper(*a)) ? tolower(*a) : *a; 816 b1 = (isascii(*b) && isupper(*b)) ? tolower(*b) : *b; 817 if (a1 != b1) return b1 - a1; 818 } 819 } 820 return 0; 821} 822#endif 823 824/* 825 * do_pointer = get list of numbers of the form 826 * 827 * buttons = NUMBER ... 828 * ^ 829 */ 830 831static void 832do_pointer(char *line, int len) 833{ 834 int n; 835 int i; 836 unsigned long val; 837 union op *uop; 838 struct op_pointer *opp; 839 unsigned char buttons[MAXBUTTONCODES]; 840 int nbuttons; 841 char *strval; 842 Bool ok; 843 844 if (len < 2 || !line || *line == '\0') { /* =1 minimum */ 845 badmsg0 ("buttons input line"); 846 return; 847 } 848 849 nbuttons = XGetPointerMapping (dpy, buttons, MAXBUTTONCODES); 850 851 n = skip_space (line, len); 852 line += n, len -= n; 853 854 if (line[0] != '=') { 855 badmsg0 ("buttons pointer code list, missing equal sign"); 856 return; 857 } 858 859 line++, len--; /* skip = */ 860 n = skip_space (line, len); 861 line += n, len -= n; 862 863 i = 0; 864 if (len < 7 || strncasecmp (line, "default", 7) != 0) { 865 while (len > 0) { 866 n = skip_space (line, len); 867 line += n, len -= n; 868 if (line[0] == '\0') break; 869 n = skip_word (line, len); 870 if (n < 1) { 871 badmsg ("skip of word in buttons line: %s", line); 872 return; 873 } 874 strval = copy_to_scratch(line, n); 875 if (strval == NULL) 876 /* copy_to_scratch already printed error message */ 877 return; 878 ok = parse_number (strval, &val); 879 if (!ok || val >= MAXBUTTONCODES) { 880 badmsg ("value %s given for buttons list", strval); 881 return; 882 } 883 buttons[i++] = (unsigned char) val; 884 line += n, len -= n; 885 } 886 } 887 888 if (i > 0 && i != nbuttons) { 889 fprintf (stderr, "Warning: Only changing the first %d of %d buttons.\n", 890 i, nbuttons); 891 i = nbuttons; 892 } 893 894 uop = AllocStruct (union op); 895 if (!uop) { 896 badmsg ("attempt to allocate a %ld byte pointer opcode", 897 (long) sizeof (struct op_pointer)); 898 return; 899 } 900 opp = &uop->pointer; 901 902 opp->type = doPointer; 903 opp->count = i; 904 for (i = 0; i < opp->count; i++) { 905 opp->button_codes[i] = buttons[i]; 906 } 907 908 add_to_work_queue (uop); 909} 910 911 912/* 913 * get_keysym_list - parses the rest of the line into a keysyms assumes 914 * that the = sign has been parsed off but there may be leading whitespace 915 * 916 * keysym ... 917 * ^ 918 * 919 * this involves getting the word containing the keysym, checking its range, 920 * and adding it to the list. 921 */ 922 923static int 924get_keysym_list(const char *line, int len, int *np, KeySym **kslistp) 925{ 926 int havesofar, maxcanhave; 927 KeySym *keysymlist; 928 929 *np = 0; 930 *kslistp = NULL; 931 932 if (len == 0) return (0); /* empty list */ 933 934 havesofar = 0; 935 maxcanhave = 4; /* most lists are small */ 936 keysymlist = malloc (maxcanhave * sizeof (KeySym)); 937 if (!keysymlist) { 938 badmsg ("attempt to allocate %ld byte initial keysymlist", 939 (long) (maxcanhave * sizeof (KeySym))); 940 return (-1); 941 } 942 943 while (len > 0) { 944 KeySym keysym; 945 int n; 946 char *tmpname; 947 Bool ok; 948 949 n = skip_space (line, len); 950 line += n, len -= n; 951 952 n = skip_chars (line, len); 953 if (n < 0) { 954 badmsg0 ("keysym name list"); 955 free(keysymlist); 956 return (-1); 957 } 958 959 ok = parse_keysym (line, n, &tmpname, &keysym); 960 line += n, len -= n; 961 if (!ok) { 962 badmsg ("keysym name '%s' in keysym list", tmpname); 963 /* do NOT return here, look for others */ 964 continue; 965 } 966 967 /* 968 * Do NOT test to see if the keysym translates to a keycode or you 969 * won't be able to assign new ones.... 970 */ 971 972 /* grow the list bigger if necessary */ 973 if (havesofar >= maxcanhave) { 974 KeySym *origkeysymlist = keysymlist; 975 maxcanhave *= 2; 976 keysymlist = realloc (keysymlist, maxcanhave * sizeof (KeySym)); 977 if (!keysymlist) { 978 badmsg ("attempt to grow keysym list to %ld bytes", 979 (long) (maxcanhave * sizeof (KeySym))); 980 free(origkeysymlist); 981 return (-1); 982 } 983 } 984 985 /* and add it to the list */ 986 keysymlist[havesofar++] = keysym; 987 } 988 989 *kslistp = keysymlist; 990 *np = havesofar; 991 return (0); 992} 993 994 995#ifdef later 996/* 997 * check_special_keys - run through list of keysyms and generate "add" or 998 * "remove" commands for for any of the key syms that appear in the modifier 999 * list. this involves running down the modifier map which is an array of 1000 * 8 by map->max_keypermod keycodes. 1001 */ 1002 1003static void 1004check_special_keys(KeyCode keycode, int n, KeySym *kslist) 1005{ 1006 int i; /* iterator variable */ 1007 KeyCode *kcp; /* keycode pointer */ 1008 1009 /* 1010 * walk the modifiermap array. since its dimensions are not known at 1011 * compile time, we have to walk it by hand instead of indexing. this 1012 * is why it is initialized outside the loop, but incremented inside the 1013 * second loop. 1014 */ 1015 1016 kcp = map->modifiermap; /* start at beginning and iterate */ 1017 for (i = 0; i < 8; i++) { /* there are 8 modifier keys */ 1018 int j; 1019 1020 for (j = 0; j < map->max_keypermod; j++, kcp++) { 1021 KeySym keysym; 1022 int k; 1023 1024 if (!*kcp) continue; /* only non-zero entries significant */ 1025 1026 /* 1027 * check to see if the target keycode is already a modifier; if so, 1028 * then we have to remove it 1029 */ 1030 if (keycode == *kcp) { 1031 make_remove (i, keycode); 1032 } 1033 1034 /* 1035 * now, check to see if any of the keysyms map to keycodes 1036 * that are in the modifier list 1037 */ 1038 for (k = 0; k < n; k++) { 1039 KeyCodes kc; 1040 1041 kc = XKeysymToKeycode (dpy, kslist[k]); 1042 if (kc == *kcp) { /* yup, found one */ 1043 /* 1044 * have to generate a remove of the CURRENT keycode 1045 * and then an add of the new KEYCODE 1046 */ 1047 make_remove (i, kc); /* modifier, keycode */ 1048 make_add (i, kslist[k]); /* modifier, keysym */ 1049 } 1050 } 1051 } 1052 } 1053 return; 1054} 1055#endif 1056 1057/* 1058 * print_work_queue - disassemble the work queue and print it on stdout 1059 */ 1060 1061void 1062print_work_queue(void) 1063{ 1064 union op *op; 1065 1066 printf ("! dump of work queue\n"); 1067 for (op = work_queue.head; op; op = op->generic.next) { 1068 print_opcode (op); 1069 } 1070 return; 1071} 1072 1073static void 1074print_opcode(union op *op) 1075{ 1076 int i; 1077 1078 printf (" "); 1079 switch (op->generic.type) { 1080 case doKeycode: 1081 if (op->keycode.target_keycode) 1082 printf ("keycode 0x%lx =", (long) op->keycode.target_keycode); 1083 else 1084 printf ("keycode any ="); 1085 for (i = 0; i < op->keycode.count; i++) { 1086 char *name = XKeysymToString (op->keycode.keysyms[i]); 1087 1088 printf (" %s", name ? name : "BADKEYSYM"); 1089 } 1090 printf ("\n"); 1091 break; 1092 case doAddModifier: 1093 printf ("add %s =", modifier_table[op->addmodifier.modifier].name); 1094 for (i = 0; i < op->addmodifier.count; i++) { 1095 char *name = XKeysymToString (op->addmodifier.keysyms[i]); 1096 printf (" %s", name ? name : "BADKEYSYM"); 1097 } 1098 printf ("\n"); 1099 break; 1100 case doRemoveModifier: 1101 printf ("remove %s = ", 1102 modifier_table[op->removemodifier.modifier].name); 1103 for (i = 0; i < op->removemodifier.count; i++) { 1104 printf (" 0x%lx", (long) op->removemodifier.keycodes[i]); 1105 } 1106 printf ("\n"); 1107 break; 1108 case doClearModifier: 1109 printf ("clear %s\n", modifier_table[op->clearmodifier.modifier].name); 1110 break; 1111 case doPointer: 1112 printf ("pointer = "); 1113 if (op->pointer.count == 0) 1114 printf(" default"); 1115 else for (i=0; i < op->pointer.count; i++) 1116 printf(" %d", op->pointer.button_codes[i]); 1117 printf ("\n"); 1118 break; 1119 default: 1120 printf ("! unknown opcode %d\n", op->generic.type); 1121 break; 1122 } /* end switch */ 1123 return; 1124} 1125 1126/* 1127 * execute_work_queue - do the real meat and potatoes now that we know what 1128 * we need to do and that all of the input is correct. 1129 */ 1130static int exec_keycode ( struct op_keycode *opk ); 1131static int exec_add ( struct op_addmodifier *opam ); 1132static int exec_remove ( struct op_removemodifier *oprm ); 1133static int exec_clear ( struct op_clearmodifier *opcm ); 1134static int exec_pointer ( struct op_pointer *opp ); 1135 1136 1137int 1138execute_work_queue (void) 1139{ 1140 union op *op; 1141 int errors; 1142 Bool update_map = False; 1143 int dosync; 1144 1145 if (verbose) { 1146 printf ("!\n"); 1147 printf ("! executing work queue\n"); 1148 printf ("!\n"); 1149 } 1150 1151 errors = 0; 1152 dosync = 0; 1153 1154 for (op = work_queue.head; op; op = op->generic.next) { 1155 if (verbose) print_opcode (op); 1156 1157 /* check to see if we have to update the keyboard mapping */ 1158 if (dosync && 1159 (dosync < 0 || 1160 op->generic.type != doKeycode || 1161 !op->keycode.target_keycode)) { 1162 XSync (dpy, 0); 1163 while (XEventsQueued (dpy, QueuedAlready) > 0) { 1164 XEvent event; 1165 XNextEvent (dpy, &event); 1166 if (event.type == MappingNotify) { 1167 /* read all MappingNotify events */ 1168 while (XCheckTypedEvent (dpy, MappingNotify, &event)) ; 1169 XRefreshKeyboardMapping (&event.xmapping); 1170 } else { 1171 fprintf (stderr, "%s: unknown event %ld\n", 1172 ProgramName, (long) event.type); 1173 } 1174 } 1175 } 1176 dosync = 0; 1177 switch (op->generic.type) { 1178 case doKeycode: 1179 if (exec_keycode (&op->keycode) < 0) errors++; 1180 if (op->keycode.target_keycode) 1181 dosync = 1; 1182 else 1183 dosync = -1; 1184 break; 1185 case doAddModifier: 1186 if (exec_add (&op->addmodifier) < 0) errors++; 1187 else update_map = True; 1188 break; 1189 case doRemoveModifier: 1190 if (exec_remove (&op->removemodifier) < 0) errors++; 1191 else update_map = True; 1192 break; 1193 case doClearModifier: 1194 if (exec_clear (&op->clearmodifier) < 0) errors++; 1195 else update_map = True; 1196 break; 1197 case doPointer: 1198 if (exec_pointer (&op->pointer) < 0) errors++; 1199 break; 1200 default: 1201 fprintf (stderr, "%s: unknown opcode %d\n", 1202 ProgramName, op->generic.type); 1203 break; 1204 } 1205 } 1206 1207 if (update_map) { 1208 if (UpdateModifierMapping (map) < 0) errors++; 1209 } 1210 1211 return (errors > 0 ? -1 : 0); 1212} 1213 1214static int 1215exec_keycode(struct op_keycode *opk) 1216{ 1217 if (!opk->target_keycode) { 1218 int i, j; 1219 KeyCode free; 1220 if (!opk->count) 1221 return (0); 1222 free = 0; 1223 for (i = min_keycode; i <= max_keycode; i++) { 1224 for (j = 0; j < opk->count; j++) { 1225 if (XKeycodeToKeysym(dpy, (KeyCode) i, j) != opk->keysyms[j]) 1226 break; 1227 } 1228 if (j >= opk->count) 1229 return (0); 1230 if (free) 1231 continue; 1232 for (j = 0; j < 8; j++) { 1233 if (XKeycodeToKeysym(dpy, (KeyCode) i, j) != None) 1234 break; 1235 } 1236 if (j >= 8) 1237 free = i; 1238 } 1239 if (!free) { 1240 fprintf(stderr, "%s: no available keycode for assignment\n", 1241 ProgramName); 1242 return (-1); 1243 } 1244 XChangeKeyboardMapping (dpy, free, opk->count, opk->keysyms, 1); 1245 } else if (opk->count == 0) { 1246 KeySym dummy = NoSymbol; 1247 XChangeKeyboardMapping (dpy, opk->target_keycode, 1, 1248 &dummy, 1); 1249 } else { 1250 XChangeKeyboardMapping (dpy, opk->target_keycode, opk->count, 1251 opk->keysyms, 1); 1252 } 1253 return (0); 1254} 1255 1256static int 1257exec_add(struct op_addmodifier *opam) 1258{ 1259 int i; 1260 int status; 1261 1262 status = 0; 1263 for (i = 0; i < opam->count; i++) { 1264 int num_kcs; 1265 KeyCode *kcs; 1266 1267 kcs = KeysymToKeycodes (dpy, opam->keysyms[i], &num_kcs); 1268 if (num_kcs == 0) 1269 status = -1; 1270 while (--num_kcs >= 0) { 1271 if (AddModifier (&map, *kcs++, opam->modifier) < 0) 1272 status = -1; 1273 } 1274 } 1275 return (status); 1276} 1277 1278static int 1279exec_remove(struct op_removemodifier *oprm) 1280{ 1281 int i; 1282 int status; 1283 1284 status = 0; 1285 for (i = 0; i < oprm->count; i++) { 1286 if (RemoveModifier (&map, oprm->keycodes[i], oprm->modifier) < 0) 1287 status = -1; 1288 } 1289 return (status); 1290} 1291 1292static int 1293exec_clear(struct op_clearmodifier *opcm) 1294{ 1295 return (ClearModifier (&map, opcm->modifier)); 1296} 1297 1298 1299static int 1300exec_pointer(struct op_pointer *opp) 1301{ 1302 return (SetPointerMap (opp->button_codes, opp->count)); 1303} 1304 1305void 1306print_modifier_map(void) 1307{ 1308 PrintModifierMapping (map, stdout); 1309 return; 1310} 1311 1312void 1313print_key_table(Bool exprs) 1314{ 1315 PrintKeyTable (exprs, stdout); 1316 return; 1317} 1318 1319void 1320print_pointer_map(void) 1321{ 1322 PrintPointerMap (stdout); 1323 return; 1324} 1325 1326 1327