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