handle.c revision 1a30de1f
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 fmt = "%lo"; 278 if (*str == '\0') { 279 *val = 0; 280 return 1; 281 } 282 if (*str == 'x' || *str == 'X') { 283 str++; 284 fmt = "%lx"; 285 } 286 } 287 return (sscanf (str, fmt, val) == 1); 288} 289 290static Bool 291parse_keysym(const char *line, int n, char **name, KeySym *keysym) 292{ 293 *name = copy_to_scratch (line, n); 294 if (!strcmp(*name, "NoSymbol")) { 295 *keysym = NoSymbol; 296 return (True); 297 } 298 *keysym = XStringToKeysym (*name); 299 if (*keysym == NoSymbol && '0' <= **name && **name <= '9') 300 return parse_number(*name, keysym); 301 return (*keysym != NoSymbol); 302} 303 304/* 305 * do_keycode - parse off lines of the form 306 * 307 * "keycode" number "=" [keysym ...] 308 * ^ 309 * 310 * where number is in decimal, hex, or octal. Any number of keysyms may be 311 * listed. 312 */ 313 314static void 315do_keycode(char *line, int len) 316{ 317 int dummy; 318 char *fmt = "%d"; 319 KeyCode keycode; 320 321 if (len < 3 || !line || *line == '\0') { /* 5=a minimum */ 322 badmsg0 ("keycode input line"); 323 return; 324 } 325 326 /* 327 * We need not bother to advance line/len past the 328 * number (or the string 'any') as finish_keycodes() will 329 * first advance past the '='. 330 */ 331 if (!strncmp("any", line, 3)) { 332 keycode = 0; 333 } else { 334 if (*line == '0') line++, len--, fmt = "%o"; 335 if (*line == 'x' || *line == 'X') line++, len--, fmt = "%x"; 336 337 dummy = 0; 338 if (sscanf (line, fmt, &dummy) != 1 || dummy == 0) { 339 badmsg0 ("keycode value"); 340 return; 341 } 342 keycode = (KeyCode) dummy; 343 if ((int)keycode < min_keycode || (int)keycode > max_keycode) { 344 badmsg0 ("keycode value (out of range)"); 345 return; 346 } 347 } 348 349 finish_keycodes (line, len, &keycode, 1); 350} 351 352 353/* 354 * do_keysym - parse off lines of the form 355 * 356 * "keysym" keysym "=" [keysym ...] 357 * ^ 358 * 359 * The left keysyms has to be checked for validity and evaluated. 360 */ 361 362static void 363do_keysym(char *line, int len) 364{ 365 int n; 366 KeyCode *keycodes; 367 KeySym keysym; 368 char *tmpname; 369 370 if (len < 3 || !line || *line == '\0') { /* a=b minimum */ 371 badmsg0 ("keysym input line"); 372 return; 373 } 374 375 n = skip_chars (line, len); 376 if (n < 1) { 377 badmsg0 ("target keysym name"); 378 return; 379 } 380 if (!parse_keysym(line, n, &tmpname, &keysym)) { 381 badmsg ("keysym target key symbol '%s'", tmpname); 382 return; 383 } 384 385 keycodes = KeysymToKeycodes (dpy, keysym, &n); 386 if (n == 0) { 387 badmsg ("keysym target keysym '%s', no corresponding keycodes", 388 tmpname); 389 return; 390 } 391 if (verbose) { 392 int i; 393 printf ("! Keysym %s (0x%lx) corresponds to keycode(s)", 394 tmpname, (long) keysym); 395 for (i = 0; i < n; i++) 396 printf (" 0x%x", keycodes[i]); 397 printf("\n"); 398 } 399 400 finish_keycodes (line, len, keycodes, n); 401} 402 403static void 404finish_keycodes(const char *line, int len, KeyCode *keycodes, int count) 405{ 406 int n; 407 KeySym *kslist; 408 union op *uop; 409 struct op_keycode *opk; 410 411 n = skip_until_char (line, len, '='); 412 line += n, len -= n; 413 414 if (len < 1 || *line != '=') { /* = minimum */ 415 badmsg0 ("keycode command (missing keysym list),"); 416 return; 417 } 418 line++, len--; /* skip past the = */ 419 420 n = skip_space (line, len); 421 line += n, len -= n; 422 423 /* allow empty list */ 424 if (get_keysym_list (line, len, &n, &kslist) < 0) 425 return; 426 427 while (--count >= 0) { 428 uop = AllocStruct (union op); 429 if (!uop) { 430 badmsg ("attempt to allocate a %ld byte keycode opcode", 431 (long) sizeof (struct op_keycode)); 432 return; 433 } 434 opk = &uop->keycode; 435 436 opk->type = doKeycode; 437 opk->target_keycode = keycodes[count]; 438 opk->count = n; 439 opk->keysyms = kslist; 440 441 add_to_work_queue (uop); 442 } 443 444#ifdef later 445 /* make sure we handle any special keys */ 446 check_special_keys (keycode, n, kslist); 447#endif 448} 449 450 451/* 452 * parse_modifier - convert a modifier string name to its index 453 */ 454 455struct modtab modifier_table[] = { /* keep in order so it can be index */ 456 { "shift", 5, 0 }, 457 { "lock", 4, 1 }, 458 { "control", 7, 2 }, 459 { "mod1", 4, 3 }, 460 { "mod2", 4, 4 }, 461 { "mod3", 4, 5 }, 462 { "mod4", 4, 6 }, 463 { "mod5", 4, 7 }, 464 { "ctrl", 4, 2 }, 465 { NULL, 0, 0 }}; 466 467static int 468parse_modifier(char *line, int n) 469{ 470 register int i; 471 struct modtab *mt; 472 473 /* lowercase for comparison against table */ 474 for (i = 0; i < n; i++) { 475 if (isupper (line[i])) line[i] = tolower (line[i]); 476 } 477 478 for (mt = modifier_table; mt->name; mt++) { 479 if (n == mt->length && strncmp (line, mt->name, n) == 0) 480 return (mt->value); 481 } 482 return (-1); 483} 484 485 486/* 487 * do_add - parse off lines of the form 488 * 489 * add MODIFIER = keysym ... 490 * ^ 491 * where the MODIFIER is one of Shift, Lock, Control, Mod[1-5] where case 492 * is not important. There should also be an alias Ctrl for control. 493 */ 494 495static void 496do_add(char *line, int len) 497{ 498 int n; 499 int modifier; 500 KeySym *kslist; 501 union op *uop; 502 struct op_addmodifier *opam; 503 504 if (len < 6 || !line || *line == '\0') { /* Lock=a minimum */ 505 badmsg0 ("add modifier input line"); 506 return; 507 } 508 509 n = skip_chars (line, len); 510 if (n < 1) { 511 badmsg ("add modifier name %s", line); 512 return; 513 } 514 515 modifier = parse_modifier (line, n); 516 if (modifier < 0) { 517 badmsgn ("add modifier name '%s', not allowed", line, n); 518 return; 519 } 520 521 line += n, len -= n; 522 n = skip_until_char (line, len, '='); 523 if (n < 0) { 524 badmsg0 ("add modifier = keysym"); 525 return; 526 } 527 528 n++; /* skip = */ 529 n += skip_space (line+n, len-n); 530 line += n, len -= n; 531 532 if (get_keysym_list (line, len, &n, &kslist) < 0) 533 return; 534 if (n == 0) { 535 badmsg0 ("add modifier keysym list (empty)"); 536 return; 537 } 538 539 uop = AllocStruct (union op); 540 if (!uop) { 541 badmsg ("attempt to allocate %ld byte addmodifier opcode", 542 (long) sizeof (struct op_addmodifier)); 543 return; 544 } 545 opam = &uop->addmodifier; 546 547 opam->type = doAddModifier; 548 opam->modifier = modifier; 549 opam->count = n; 550 opam->keysyms = kslist; 551 552 add_to_work_queue (uop); 553} 554 555#ifdef AUTO_ADD_REMOVE 556/* 557 * make_add - stick a single add onto the queue 558 */ 559static void 560make_add(int modifier, KeySym keysym) 561{ 562 union op *uop; 563 struct op_addmodifier *opam; 564 565 uop = AllocStruct (union op); 566 if (!uop) { 567 badmsg ("attempt to allocate %ld byte addmodifier opcode", 568 (long) sizeof (struct op_addmodifier)); 569 return; 570 } 571 opam = &uop->addmodifier; 572 573 opam->type = doAddModifier; 574 opam->modifier = modifier; 575 opam->count = 1; 576 opam->keysyms = (KeySym *) malloc (sizeof (KeySym)); 577 if (!opam->keysyms) { 578 badmsg ("attempt to allocate %ld byte KeySym", (long) sizeof (KeySym)); 579 free ((char *) opam); 580 return; 581 } 582 opam->keysyms[0] = keysym; 583 584 add_to_work_queue (uop); 585 return; 586} 587#endif /* AUTO_ADD_REMOVE */ 588 589 590/* 591 * do_remove - parse off lines of the form 592 * 593 * remove MODIFIER = oldkeysym ... 594 * ^ 595 * where the MODIFIER is one of Shift, Lock, Control, Mod[1-5] where case 596 * is not important. There should also be an alias Ctrl for control. 597 */ 598 599static void 600do_remove(char *line, int len) 601{ 602 int n; 603 int nc; 604 int i; 605 int tot; 606 int modifier; 607 KeySym *kslist; 608 KeyCode *kclist; 609 union op *uop; 610 struct op_removemodifier *oprm; 611 612 if (len < 6 || !line || *line == '\0') { /* Lock=a minimum */ 613 badmsg0 ("remove modifier input line"); 614 return; 615 } 616 617 n = skip_chars (line, len); 618 if (n < 1) { 619 badmsg ("remove modifier name %s", line); 620 return; 621 } 622 623 modifier = parse_modifier (line, n); 624 if (modifier < 0) { 625 badmsgn ("remove modifier name '%s', not allowed", line, n); 626 return; 627 } 628 629 line += n, len -= n; 630 n = skip_until_char (line, len, '='); 631 if (n < 0) { 632 badmsg0 ("remove modifier = keysym"); 633 return; 634 } 635 636 n++; 637 n += skip_space (line+n, len-n); 638 line += n, len -= n; 639 640 if (get_keysym_list (line, len, &n, &kslist) < 0) 641 return; 642 if (n == 0) { 643 badmsg0 ("remove modifier keysym list (empty)"); 644 return; 645 } 646 647 /* 648 * unlike the add command, we have to now evaluate the keysyms 649 */ 650 651 kclist = (KeyCode *) malloc (n * sizeof (KeyCode)); 652 if (!kclist) { 653 badmsg ("attempt to allocate %ld byte keycode list", 654 (long) (n * sizeof (KeyCode))); 655 free ((char *) kslist); 656 return; 657 } 658 659 tot = n; 660 nc = 0; 661 for (i = 0; i < n; i++) { 662 int num_kcs; 663 KeyCode *kcs; 664 kcs = KeysymToKeycodes (dpy, kslist[i], &num_kcs); 665 if (num_kcs == 0) { 666 char *tmpname = XKeysymToString (kslist[i]); 667 badmsg ("keysym in remove modifier list '%s', no corresponding keycodes", 668 tmpname ? tmpname : "?"); 669 continue; 670 } 671 if (verbose) { 672 int j; 673 char *tmpname = XKeysymToString (kslist[i]); 674 printf ("! Keysym %s (0x%lx) corresponds to keycode(s)", 675 tmpname ? tmpname : "?", (long) kslist[i]); 676 for (j = 0; j < num_kcs; j++) 677 printf(" 0x%x", kcs[j]); 678 printf("\n"); 679 } 680 if (nc + num_kcs > tot) { 681 tot = nc + num_kcs; 682 kclist = (KeyCode *)realloc((char *)kclist, tot * sizeof(KeyCode)); 683 if (!kclist) { 684 badmsg ("attempt to allocate %ld byte keycode list", 685 (long) (tot * sizeof (KeyCode))); 686 free ((char *) kslist); 687 return; 688 } 689 } 690 while (--num_kcs >= 0) 691 kclist[nc++] = *kcs++; /* okay, add it to list */ 692 } 693 694 free ((char *) kslist); /* all done with it */ 695 696 uop = AllocStruct (union op); 697 if (!uop) { 698 badmsg ("attempt to allocate %ld byte removemodifier opcode", 699 (long) sizeof (struct op_removemodifier)); 700 return; 701 } 702 oprm = &uop->removemodifier; 703 704 oprm->type = doRemoveModifier; 705 oprm->modifier = modifier; 706 oprm->count = nc; 707 oprm->keycodes = kclist; 708 709 add_to_work_queue (uop); 710} 711 712#ifdef AUTO_ADD_REMOVE 713/* 714 * make_remove - stick a single remove onto the queue 715 */ 716static void 717make_remove(int modifier, KeyCode keycode) 718{ 719 union op *uop; 720 struct op_removemodifier *oprm; 721 722 uop = AllocStruct (union op); 723 if (!uop) { 724 badmsg ("attempt to allocate %ld byte removemodifier opcode", 725 (long) sizeof (struct op_removemodifier)); 726 return; 727 } 728 oprm = &uop->removemodifier; 729 730 oprm->type = doRemoveModifier; 731 oprm->modifier = modifier; 732 oprm->count = 1; 733 oprm->keycodes = (KeyCode *) malloc (sizeof (KeyCode)); 734 if (!oprm->keycodes) { 735 badmsg ("attempt to allocate %ld byte KeyCode", 736 (long) sizeof (KeyCode)); 737 free ((char *) oprm); 738 return; 739 } 740 oprm->keycodes[0] = keycode; 741 742 add_to_work_queue (uop); 743 return; 744} 745#endif /* AUTO_ADD_REMOVE */ 746 747 748/* 749 * do_clear - parse off lines of the form 750 * 751 * clear MODIFIER 752 * ^ 753 */ 754 755static void 756do_clear(char *line, int len) 757{ 758 int n; 759 int modifier; 760 union op *uop; 761 struct op_clearmodifier *opcm; 762 763 if (len < 4 || !line || *line == '\0') { /* Lock minimum */ 764 badmsg0 ("clear modifier input line"); 765 return; 766 } 767 768 n = skip_chars (line, len); 769 770 modifier = parse_modifier (line, n); 771 if (modifier < 0) { 772 badmsgn ("clear modifier name '%s'", line, n); 773 return; 774 } 775 n += skip_space (line+n, len-n); 776 if (n != len) { 777 badmsgn ("extra argument '%s' to clear modifier", line+n, len-n); 778 /* okay to continue */ 779 } 780 781 uop = AllocStruct (union op); 782 if (!uop) { 783 badmsg ("attempt to allocate %ld byte clearmodifier opcode", 784 (long) sizeof (struct op_clearmodifier)); 785 return; 786 } 787 opcm = &uop->clearmodifier; 788 789 opcm->type = doClearModifier; 790 opcm->modifier = modifier; 791 792 add_to_work_queue (uop); 793} 794 795#ifndef HAVE_STRNCASECMP 796static int 797strncasecmp(const char *a, const char *b, int n) 798{ 799 int i; 800 int a1, b1; 801 802 for (i = 0; i < n; i++, a++, b++) { 803 if (!*a) return -1; 804 if (!*b) return 1; 805 806 if (*a != *b) { 807 a1 = (isascii(*a) && isupper(*a)) ? tolower(*a) : *a; 808 b1 = (isascii(*b) && isupper(*b)) ? tolower(*b) : *b; 809 if (a1 != b1) return b1 - a1; 810 } 811 } 812 return 0; 813} 814#endif 815 816/* 817 * do_pointer = get list of numbers of the form 818 * 819 * buttons = NUMBER ... 820 * ^ 821 */ 822 823static void 824do_pointer(char *line, int len) 825{ 826 int n; 827 int i; 828 unsigned long val; 829 union op *uop; 830 struct op_pointer *opp; 831 unsigned char buttons[MAXBUTTONCODES]; 832 int nbuttons; 833 char *strval; 834 Bool ok; 835 836 if (len < 2 || !line || *line == '\0') { /* =1 minimum */ 837 badmsg0 ("buttons input line"); 838 return; 839 } 840 841 nbuttons = XGetPointerMapping (dpy, buttons, MAXBUTTONCODES); 842 843 n = skip_space (line, len); 844 line += n, len -= n; 845 846 if (line[0] != '=') { 847 badmsg0 ("buttons pointer code list, missing equal sign"); 848 return; 849 } 850 851 line++, len--; /* skip = */ 852 n = skip_space (line, len); 853 line += n, len -= n; 854 855 i = 0; 856 if (len < 7 || strncasecmp (line, "default", 7) != 0) { 857 while (len > 0) { 858 n = skip_space (line, len); 859 line += n, len -= n; 860 if (line[0] == '\0') break; 861 n = skip_word (line, len); 862 if (n < 1) { 863 badmsg ("skip of word in buttons line: %s", line); 864 return; 865 } 866 strval = copy_to_scratch(line, n); 867 ok = parse_number (strval, &val); 868 if (!ok || val >= MAXBUTTONCODES) { 869 badmsg ("value %s given for buttons list", strval); 870 return; 871 } 872 buttons[i++] = (unsigned char) val; 873 line += n, len -= n; 874 } 875 } 876 877 if (i > 0 && i != nbuttons) { 878 fprintf (stderr, "Warning: Only changing the first %d of %d buttons.\n", 879 i, nbuttons); 880 i = nbuttons; 881 } 882 883 uop = AllocStruct (union op); 884 if (!uop) { 885 badmsg ("attempt to allocate a %ld byte pointer opcode", 886 (long) sizeof (struct op_pointer)); 887 return; 888 } 889 opp = &uop->pointer; 890 891 opp->type = doPointer; 892 opp->count = i; 893 for (i = 0; i < opp->count; i++) { 894 opp->button_codes[i] = buttons[i]; 895 } 896 897 add_to_work_queue (uop); 898} 899 900 901/* 902 * get_keysym_list - parses the rest of the line into a keysyms assumes 903 * that the = sign has been parsed off but there may be leading whitespace 904 * 905 * keysym ... 906 * ^ 907 * 908 * this involves getting the word containing the keysym, checking its range, 909 * and adding it to the list. 910 */ 911 912static int 913get_keysym_list(const char *line, int len, int *np, KeySym **kslistp) 914{ 915 int havesofar, maxcanhave; 916 KeySym *keysymlist; 917 918 *np = 0; 919 *kslistp = NULL; 920 921 if (len == 0) return (0); /* empty list */ 922 923 havesofar = 0; 924 maxcanhave = 4; /* most lists are small */ 925 keysymlist = (KeySym *) malloc (maxcanhave * sizeof (KeySym)); 926 if (!keysymlist) { 927 badmsg ("attempt to allocate %ld byte initial keysymlist", 928 (long) (maxcanhave * sizeof (KeySym))); 929 return (-1); 930 } 931 932 while (len > 0) { 933 KeySym keysym; 934 int n; 935 char *tmpname; 936 Bool ok; 937 938 n = skip_space (line, len); 939 line += n, len -= n; 940 941 n = skip_chars (line, len); 942 if (n < 0) { 943 badmsg0 ("keysym name list"); 944 free(keysymlist); 945 return (-1); 946 } 947 948 ok = parse_keysym (line, n, &tmpname, &keysym); 949 line += n, len -= n; 950 if (!ok) { 951 badmsg ("keysym name '%s' in keysym list", tmpname); 952 /* do NOT return here, look for others */ 953 continue; 954 } 955 956 /* 957 * Do NOT test to see if the keysym translates to a keycode or you 958 * won't be able to assign new ones.... 959 */ 960 961 /* grow the list bigger if necessary */ 962 if (havesofar >= maxcanhave) { 963 KeySym *origkeysymlist = keysymlist; 964 maxcanhave *= 2; 965 keysymlist = (KeySym *) realloc (keysymlist, 966 maxcanhave * sizeof (KeySym)); 967 if (!keysymlist) { 968 badmsg ("attempt to grow keysym list to %ld bytes", 969 (long) (maxcanhave * sizeof (KeySym))); 970 free(origkeysymlist); 971 return (-1); 972 } 973 } 974 975 /* and add it to the list */ 976 keysymlist[havesofar++] = keysym; 977 } 978 979 *kslistp = keysymlist; 980 *np = havesofar; 981 return (0); 982} 983 984 985#ifdef later 986/* 987 * check_special_keys - run through list of keysyms and generate "add" or 988 * "remove" commands for for any of the key syms that appear in the modifier 989 * list. this involves running down the modifier map which is an array of 990 * 8 by map->max_keypermod keycodes. 991 */ 992 993static void 994check_special_keys(KeyCode keycode, int n, KeySym *kslist) 995{ 996 int i; /* iterator variable */ 997 KeyCode *kcp; /* keycode pointer */ 998 999 /* 1000 * walk the modifiermap array. since its dimensions are not known at 1001 * compile time, we have to walk it by hand instead of indexing. this 1002 * is why it is initialized outside the loop, but incremented inside the 1003 * second loop. 1004 */ 1005 1006 kcp = map->modifiermap; /* start at beginning and iterate */ 1007 for (i = 0; i < 8; i++) { /* there are 8 modifier keys */ 1008 int j; 1009 1010 for (j = 0; j < map->max_keypermod; j++, kcp++) { 1011 KeySym keysym; 1012 int k; 1013 1014 if (!*kcp) continue; /* only non-zero entries significant */ 1015 1016 /* 1017 * check to see if the target keycode is already a modifier; if so, 1018 * then we have to remove it 1019 */ 1020 if (keycode == *kcp) { 1021 make_remove (i, keycode); 1022 } 1023 1024 /* 1025 * now, check to see if any of the keysyms map to keycodes 1026 * that are in the modifier list 1027 */ 1028 for (k = 0; k < n; k++) { 1029 KeyCodes kc; 1030 1031 kc = XKeysymToKeycode (dpy, kslist[k]); 1032 if (kc == *kcp) { /* yup, found one */ 1033 /* 1034 * have to generate a remove of the CURRENT keycode 1035 * and then an add of the new KEYCODE 1036 */ 1037 make_remove (i, kc); /* modifier, keycode */ 1038 make_add (i, kslist[k]); /* modifier, keysym */ 1039 } 1040 } 1041 } 1042 } 1043 return; 1044} 1045#endif 1046 1047/* 1048 * print_work_queue - disassemble the work queue and print it on stdout 1049 */ 1050 1051void 1052print_work_queue(void) 1053{ 1054 union op *op; 1055 1056 printf ("! dump of work queue\n"); 1057 for (op = work_queue.head; op; op = op->generic.next) { 1058 print_opcode (op); 1059 } 1060 return; 1061} 1062 1063static void 1064print_opcode(union op *op) 1065{ 1066 int i; 1067 1068 printf (" "); 1069 switch (op->generic.type) { 1070 case doKeycode: 1071 if (op->keycode.target_keycode) 1072 printf ("keycode 0x%lx =", (long) op->keycode.target_keycode); 1073 else 1074 printf ("keycode any ="); 1075 for (i = 0; i < op->keycode.count; i++) { 1076 char *name = XKeysymToString (op->keycode.keysyms[i]); 1077 1078 printf (" %s", name ? name : "BADKEYSYM"); 1079 } 1080 printf ("\n"); 1081 break; 1082 case doAddModifier: 1083 printf ("add %s =", modifier_table[op->addmodifier.modifier].name); 1084 for (i = 0; i < op->addmodifier.count; i++) { 1085 char *name = XKeysymToString (op->addmodifier.keysyms[i]); 1086 printf (" %s", name ? name : "BADKEYSYM"); 1087 } 1088 printf ("\n"); 1089 break; 1090 case doRemoveModifier: 1091 printf ("remove %s = ", 1092 modifier_table[op->removemodifier.modifier].name); 1093 for (i = 0; i < op->removemodifier.count; i++) { 1094 printf (" 0x%lx", (long) op->removemodifier.keycodes[i]); 1095 } 1096 printf ("\n"); 1097 break; 1098 case doClearModifier: 1099 printf ("clear %s\n", modifier_table[op->clearmodifier.modifier].name); 1100 break; 1101 case doPointer: 1102 printf ("pointer = "); 1103 if (op->pointer.count == 0) 1104 printf(" default"); 1105 else for (i=0; i < op->pointer.count; i++) 1106 printf(" %d", op->pointer.button_codes[i]); 1107 printf ("\n"); 1108 break; 1109 default: 1110 printf ("! unknown opcode %d\n", op->generic.type); 1111 break; 1112 } /* end switch */ 1113 return; 1114} 1115 1116/* 1117 * execute_work_queue - do the real meat and potatoes now that we know what 1118 * we need to do and that all of the input is correct. 1119 */ 1120static int exec_keycode ( struct op_keycode *opk ); 1121static int exec_add ( struct op_addmodifier *opam ); 1122static int exec_remove ( struct op_removemodifier *oprm ); 1123static int exec_clear ( struct op_clearmodifier *opcm ); 1124static int exec_pointer ( struct op_pointer *opp ); 1125 1126 1127int 1128execute_work_queue (void) 1129{ 1130 union op *op; 1131 int errors; 1132 Bool update_map = False; 1133 int dosync; 1134 1135 if (verbose) { 1136 printf ("!\n"); 1137 printf ("! executing work queue\n"); 1138 printf ("!\n"); 1139 } 1140 1141 errors = 0; 1142 dosync = 0; 1143 1144 for (op = work_queue.head; op; op = op->generic.next) { 1145 if (verbose) print_opcode (op); 1146 1147 /* check to see if we have to update the keyboard mapping */ 1148 if (dosync && 1149 (dosync < 0 || 1150 op->generic.type != doKeycode || 1151 !op->keycode.target_keycode)) { 1152 XSync (dpy, 0); 1153 while (XEventsQueued (dpy, QueuedAlready) > 0) { 1154 XEvent event; 1155 XNextEvent (dpy, &event); 1156 if (event.type == MappingNotify) { 1157 /* read all MappingNotify events */ 1158 while (XCheckTypedEvent (dpy, MappingNotify, &event)) ; 1159 XRefreshKeyboardMapping (&event.xmapping); 1160 } else { 1161 fprintf (stderr, "%s: unknown event %ld\n", 1162 ProgramName, (long) event.type); 1163 } 1164 } 1165 } 1166 dosync = 0; 1167 switch (op->generic.type) { 1168 case doKeycode: 1169 if (exec_keycode (&op->keycode) < 0) errors++; 1170 if (op->keycode.target_keycode) 1171 dosync = 1; 1172 else 1173 dosync = -1; 1174 break; 1175 case doAddModifier: 1176 if (exec_add (&op->addmodifier) < 0) errors++; 1177 else update_map = True; 1178 break; 1179 case doRemoveModifier: 1180 if (exec_remove (&op->removemodifier) < 0) errors++; 1181 else update_map = True; 1182 break; 1183 case doClearModifier: 1184 if (exec_clear (&op->clearmodifier) < 0) errors++; 1185 else update_map = True; 1186 break; 1187 case doPointer: 1188 if (exec_pointer (&op->pointer) < 0) errors++; 1189 break; 1190 default: 1191 fprintf (stderr, "%s: unknown opcode %d\n", 1192 ProgramName, op->generic.type); 1193 break; 1194 } 1195 } 1196 1197 if (update_map) { 1198 if (UpdateModifierMapping (map) < 0) errors++; 1199 } 1200 1201 return (errors > 0 ? -1 : 0); 1202} 1203 1204static int 1205exec_keycode(struct op_keycode *opk) 1206{ 1207 if (!opk->target_keycode) { 1208 int i, j; 1209 KeyCode free; 1210 if (!opk->count) 1211 return (0); 1212 free = 0; 1213 for (i = min_keycode; i <= max_keycode; i++) { 1214 for (j = 0; j < opk->count; j++) { 1215 if (XKeycodeToKeysym(dpy, (KeyCode) i, j) != opk->keysyms[j]) 1216 break; 1217 } 1218 if (j >= opk->count) 1219 return (0); 1220 if (free) 1221 continue; 1222 for (j = 0; j < 8; j++) { 1223 if (XKeycodeToKeysym(dpy, (KeyCode) i, j) != None) 1224 break; 1225 } 1226 if (j >= 8) 1227 free = i; 1228 } 1229 if (!free) { 1230 fprintf(stderr, "%s: no available keycode for assignment\n", 1231 ProgramName); 1232 return (-1); 1233 } 1234 XChangeKeyboardMapping (dpy, free, opk->count, opk->keysyms, 1); 1235 } else if (opk->count == 0) { 1236 KeySym dummy = NoSymbol; 1237 XChangeKeyboardMapping (dpy, opk->target_keycode, 1, 1238 &dummy, 1); 1239 } else { 1240 XChangeKeyboardMapping (dpy, opk->target_keycode, opk->count, 1241 opk->keysyms, 1); 1242 } 1243 return (0); 1244} 1245 1246static int 1247exec_add(struct op_addmodifier *opam) 1248{ 1249 int i; 1250 int status; 1251 1252 status = 0; 1253 for (i = 0; i < opam->count; i++) { 1254 int num_kcs; 1255 KeyCode *kcs; 1256 1257 kcs = KeysymToKeycodes (dpy, opam->keysyms[i], &num_kcs); 1258 if (num_kcs == 0) 1259 status = -1; 1260 while (--num_kcs >= 0) { 1261 if (AddModifier (&map, *kcs++, opam->modifier) < 0) 1262 status = -1; 1263 } 1264 } 1265 return (status); 1266} 1267 1268static int 1269exec_remove(struct op_removemodifier *oprm) 1270{ 1271 int i; 1272 int status; 1273 1274 status = 0; 1275 for (i = 0; i < oprm->count; i++) { 1276 if (RemoveModifier (&map, oprm->keycodes[i], oprm->modifier) < 0) 1277 status = -1; 1278 } 1279 return (status); 1280} 1281 1282static int 1283exec_clear(struct op_clearmodifier *opcm) 1284{ 1285 return (ClearModifier (&map, opcm->modifier)); 1286} 1287 1288 1289static int 1290exec_pointer(struct op_pointer *opp) 1291{ 1292 return (SetPointerMap (opp->button_codes, opp->count)); 1293} 1294 1295void 1296print_modifier_map(void) 1297{ 1298 PrintModifierMapping (map, stdout); 1299 return; 1300} 1301 1302void 1303print_key_table(Bool exprs) 1304{ 1305 PrintKeyTable (exprs, stdout); 1306 return; 1307} 1308 1309void 1310print_pointer_map(void) 1311{ 1312 PrintPointerMap (stdout); 1313 return; 1314} 1315 1316 1317