1 /*- 2 * Copyright (c) 1994-1995 S�ren Schmidt 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software withough specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #ifndef lint 30 static const char rcsid[] = 31 "$Id: kbdcontrol.c,v 1.12 1998/01/07 08:43:27 yokota Exp $"; 32 #endif /* not lint */ 33 34 #include <ctype.h> 35 #include <err.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 #include <machine/console.h> 41 #include "path.h" 42 #include "lex.h" 43 44 char ctrl_names[32][4] = { 45 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", 46 "bs ", "ht ", "nl ", "vt ", "ff ", "cr ", "so ", "si ", 47 "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", 48 "can", "em ", "sub", "esc", "fs ", "gs ", "rs ", "ns " 49 }; 50 51 char acc_names[15][5] = { 52 "dgra", "dacu", "dcir", "dtil", "dmac", "dbre", "ddot", 53 "duml", "dsla", "drin", "dced", "dapo", "ddac", "dogo", 54 "dcar", 55 }; 56 57 char acc_names_u[15][5] = { 58 "DGRA", "DACU", "DCIR", "DTIL", "DMAC", "DBRE", "DDOT", 59 "DUML", "DSLA", "DRIN", "DCED", "DAPO", "DDAC", "DOGO", 60 "DCAR", 61 }; 62 63 char fkey_table[96][MAXFK] = { 64 /* 01-04 */ "\033[M", "\033[N", "\033[O", "\033[P", 65 /* 05-08 */ "\033[Q", "\033[R", "\033[S", "\033[T", 66 /* 09-12 */ "\033[U", "\033[V", "\033[W", "\033[X", 67 /* 13-16 */ "\033[Y", "\033[Z", "\033[a", "\033[b", 68 /* 17-20 */ "\033[c", "\033[d", "\033[e", "\033[f", 69 /* 21-24 */ "\033[g", "\033[h", "\033[i", "\033[j", 70 /* 25-28 */ "\033[k", "\033[l", "\033[m", "\033[n", 71 /* 29-32 */ "\033[o", "\033[p", "\033[q", "\033[r", 72 /* 33-36 */ "\033[s", "\033[t", "\033[u", "\033[v", 73 /* 37-40 */ "\033[w", "\033[x", "\033[y", "\033[z", 74 /* 41-44 */ "\033[@", "\033[[", "\033[\\","\033[]", 75 /* 45-48 */ "\033[^", "\033[_", "\033[`", "\033[{", 76 /* 49-52 */ "\033[H", "\033[A", "\033[I", "-" , 77 /* 53-56 */ "\033[D", "\033[E", "\033[C", "+" , 78 /* 57-60 */ "\033[F", "\033[B", "\033[G", "\033[L", 79 /* 61-64 */ "\177", "\033[J", "\033[~", "\033[}", 80 /* 65-68 */ "" , "" , "" , "" , 81 /* 69-72 */ "" , "" , "" , "" , 82 /* 73-76 */ "" , "" , "" , "" , 83 /* 77-80 */ "" , "" , "" , "" , 84 /* 81-84 */ "" , "" , "" , "" , 85 /* 85-88 */ "" , "" , "" , "" , 86 /* 89-92 */ "" , "" , "" , "" , 87 /* 93-96 */ "" , "" , "" , "" , 88 }; 89 90 const int delays[] = {250, 500, 750, 1000}; 91 const int repeats[] = { 34, 38, 42, 46, 50, 55, 59, 63, 92 68, 76, 84, 92, 100, 110, 118, 126, 93 136, 152, 168, 184, 200, 220, 236, 252, 94 272, 304, 336, 368, 400, 440, 472, 504}; 95 const int ndelays = (sizeof(delays) / sizeof(int)); 96 const int nrepeats = (sizeof(repeats) / sizeof(int)); 97 int hex = 0; 98 int number; 99 char letter; 100 int token; 101 102 static void usage __P((void)); 103 104 char * 105 nextarg(int ac, char **av, int *indp, int oc) 106 { 107 if (*indp < ac) 108 return(av[(*indp)++]); 109 warnx("option requires two arguments -- %c", oc); 110 usage(); 111 return(""); 112 } 113 114 115 char * 116 mkfullname(const char *s1, const char *s2, const char *s3) 117 { 118 static char *buf = NULL; 119 static int bufl = 0; 120 int f; 121 122 f = strlen(s1) + strlen(s2) + strlen(s3) + 1; 123 if (f > bufl) 124 if (buf) 125 buf = (char *)realloc(buf, f); 126 else 127 buf = (char *)malloc(f); 128 if (!buf) { 129 bufl = 0; 130 return(NULL); 131 } 132 133 bufl = f; 134 strcpy(buf, s1); 135 strcat(buf, s2); 136 strcat(buf, s3); 137 return(buf); 138 } 139 140 141 int 142 get_entry() 143 { 144 switch ((token = yylex())) { 145 case TNOP: 146 return NOP | 0x100; 147 case TLSH: 148 return LSH | 0x100; 149 case TRSH: 150 return RSH | 0x100; 151 case TCLK: 152 return CLK | 0x100; 153 case TNLK: 154 return NLK | 0x100; 155 case TSLK: 156 return SLK | 0x100; 157 case TBTAB: 158 return BTAB | 0x100; 159 case TLALT: 160 return LALT | 0x100; 161 case TLCTR: 162 return LCTR | 0x100; 163 case TNEXT: 164 return NEXT | 0x100; 165 case TRCTR: 166 return RCTR | 0x100; 167 case TRALT: 168 return RALT | 0x100; 169 case TALK: 170 return ALK | 0x100; 171 case TASH: 172 return ASH | 0x100; 173 case TMETA: 174 return META | 0x100; 175 case TRBT: 176 return RBT | 0x100; 177 case TDBG: 178 return DBG | 0x100; 179 case TSUSP: 180 return SUSP | 0x100; 181 case TACC: 182 if (ACC(number) > L_ACC) 183 return -1; 184 return ACC(number) | 0x100; 185 case TFUNC: 186 if (F(number) > L_FN) 187 return -1; 188 return F(number) | 0x100; 189 case TSCRN: 190 if (S(number) > L_SCR) 191 return -1; 192 return S(number) | 0x100; 193 case TLET: 194 return (unsigned char)letter; 195 case TNUM: 196 if (number < 0 || number > 255) 197 return -1; 198 return number; 199 default: 200 return -1; 201 } 202 } 203 204 int 205 get_definition_line(FILE *fd, keymap_t *keymap, accentmap_t *accentmap) 206 { 207 int c; 208 209 yyin = fd; 210 211 if (token < 0) 212 token = yylex(); 213 switch (token) { 214 case TNUM: 215 c = get_key_definition_line(keymap); 216 if (c < 0) 217 errx(1, "invalid key definition"); 218 if (c > keymap->n_keys) 219 keymap->n_keys = c; 220 break; 221 case TACC: 222 c = get_accent_definition_line(accentmap); 223 if (c < 0) 224 errx(1, "invalid accent key definition"); 225 if (c > accentmap->n_accs) 226 accentmap->n_accs = c; 227 break; 228 case 0: 229 /* EOF */ 230 return -1; 231 default: 232 errx(1, "illegal definition line"); 233 } 234 return c; 235 } 236 237 int 238 get_key_definition_line(keymap_t *map) 239 { 240 int i, def, scancode; 241 242 /* check scancode number */ 243 if (number < 0 || number >= NUM_KEYS) 244 return -1; 245 scancode = number; 246 247 /* get key definitions */ 248 map->key[scancode].spcl = 0; 249 for (i=0; i<NUM_STATES; i++) { 250 if ((def = get_entry()) == -1) 251 return -1; 252 if (def & 0x100) 253 map->key[scancode].spcl |= (0x80 >> i); 254 map->key[scancode].map[i] = def & 0xFF; 255 } 256 /* get lock state key def */ 257 if ((token = yylex()) != TFLAG) 258 return -1; 259 map->key[scancode].flgs = number; 260 token = yylex(); 261 return (scancode + 1); 262 } 263 264 int 265 get_accent_definition_line(accentmap_t *map) 266 { 267 int accent; 268 int c1, c2; 269 int i; 270 271 if (ACC(number) < F_ACC || ACC(number) > L_ACC) 272 /* number out of range */ 273 return -1; 274 accent = number; 275 if (map->acc[accent].accchar != 0) { 276 /* this entry has already been defined before! */ 277 errx(1, "duplicated accent key definition"); 278 } 279 280 switch ((token = yylex())) { 281 case TLET: 282 map->acc[accent].accchar = letter; 283 break; 284 case TNUM: 285 map->acc[accent].accchar = number; 286 break; 287 default: 288 return -1; 289 } 290 291 for (i = 0; (token = yylex()) == '(';) { 292 switch ((token = yylex())) { 293 case TLET: 294 c1 = letter; 295 break; 296 case TNUM: 297 c1 = number; 298 break; 299 default: 300 return -1; 301 } 302 switch ((token = yylex())) { 303 case TLET: 304 c2 = letter; 305 break; 306 case TNUM: 307 c2 = number; 308 break; 309 default: 310 return -1; 311 } 312 if ((token = yylex()) != ')') 313 return -1; 314 if (i >= NUM_ACCENTCHARS) { 315 warnx("too many accented characters, ignored"); 316 continue; 317 } 318 map->acc[accent].map[i][0] = c1; 319 map->acc[accent].map[i][1] = c2; 320 ++i; 321 } 322 return (accent + 1); 323 } 324 325 void 326 print_entry(FILE *fp, int value) 327 { 328 int val = value & 0xFF; 329 330 switch (value) { 331 case NOP | 0x100: 332 fprintf(fp, " nop "); 333 break; 334 case LSH | 0x100: 335 fprintf(fp, " lshift"); 336 break; 337 case RSH | 0x100: 338 fprintf(fp, " rshift"); 339 break; 340 case CLK | 0x100: 341 fprintf(fp, " clock "); 342 break; 343 case NLK | 0x100: 344 fprintf(fp, " nlock "); 345 break; 346 case SLK | 0x100: 347 fprintf(fp, " slock "); 348 break; 349 case BTAB | 0x100: 350 fprintf(fp, " btab "); 351 break; 352 case LALT | 0x100: 353 fprintf(fp, " lalt "); 354 break; 355 case LCTR | 0x100: 356 fprintf(fp, " lctrl "); 357 break; 358 case NEXT | 0x100: 359 fprintf(fp, " nscr "); 360 break; 361 case RCTR | 0x100: 362 fprintf(fp, " rctrl "); 363 break; 364 case RALT | 0x100: 365 fprintf(fp, " ralt "); 366 break; 367 case ALK | 0x100: 368 fprintf(fp, " alock "); 369 break; 370 case ASH | 0x100: 371 fprintf(fp, " ashift"); 372 break; 373 case META | 0x100: 374 fprintf(fp, " meta "); 375 break; 376 case RBT | 0x100: 377 fprintf(fp, " boot "); 378 break; 379 case DBG | 0x100: 380 fprintf(fp, " debug "); 381 break; 382 case SUSP | 0x100: 383 fprintf(fp, " susp "); 384 break; 385 default: 386 if (value & 0x100) { 387 if (val >= F_FN && val <= L_FN) 388 fprintf(fp, " fkey%02d", val - F_FN + 1); 389 else if (val >= F_SCR && val <= L_SCR) 390 fprintf(fp, " scr%02d ", val - F_SCR + 1); 391 else if (val >= F_ACC && val <= L_ACC) 392 fprintf(fp, " %-6s", acc_names[val - F_ACC]); 393 else if (hex) 394 fprintf(fp, " 0x%02x ", val); 395 else 396 fprintf(fp, " %3d ", val); 397 } 398 else { 399 if (val < ' ') 400 fprintf(fp, " %s ", ctrl_names[val]); 401 else if (val == 127) 402 fprintf(fp, " del "); 403 else if (isascii(val) && isprint(val)) 404 fprintf(fp, " '%c' ", val); 405 else if (hex) 406 fprintf(fp, " 0x%02x ", val); 407 else 408 fprintf(fp, " %3d ", val); 409 } 410 } 411 } 412 413 414 void 415 print_key_definition_line(FILE *fp, int scancode, struct key_t *key) 416 { 417 int i; 418 419 /* print scancode number */ 420 if (hex) 421 fprintf(fp, " 0x%02x ", scancode); 422 else 423 fprintf(fp, " %03d ", scancode); 424 425 /* print key definitions */ 426 for (i=0; i<NUM_STATES; i++) { 427 if (key->spcl & (0x80 >> i)) 428 print_entry(fp, key->map[i] | 0x100); 429 else 430 print_entry(fp, key->map[i]); 431 } 432 433 /* print lock state key def */ 434 switch (key->flgs) { 435 case 0: 436 fprintf(fp, " O\n"); 437 break; 438 case 1: 439 fprintf(fp, " C\n"); 440 break; 441 case 2: 442 fprintf(fp, " N\n"); 443 break; 444 case 3: 445 fprintf(fp, " B\n"); 446 break; 447 } 448 } 449 450 void 451 print_accent_definition_line(FILE *fp, int accent, struct acc_t *key) 452 { 453 int c; 454 int i; 455 456 if (key->accchar == 0) 457 return; 458 459 /* print accent number */ 460 fprintf(fp, " %-6s", acc_names[accent]); 461 if (isascii(key->accchar) && isprint(key->accchar)) 462 fprintf(fp, "'%c' ", key->accchar); 463 else if (hex) 464 fprintf(fp, "0x%02x ", key->accchar); 465 else 466 fprintf(fp, "%03d ", key->accchar); 467 468 for (i = 0; i < NUM_ACCENTCHARS; ++i) { 469 c = key->map[i][0]; 470 if (c == 0) 471 break; 472 if ((i > 0) && ((i % 4) == 0)) 473 fprintf(fp, "\n "); 474 if (isascii(c) && isprint(c)) 475 fprintf(fp, "( '%c' ", c); 476 else if (hex) 477 fprintf(fp, "(0x%02x ", c); 478 else 479 fprintf(fp, "( %03d ", c); 480 c = key->map[i][1]; 481 if (isascii(c) && isprint(c)) 482 fprintf(fp, "'%c' ) ", c); 483 else if (hex) 484 fprintf(fp, "0x%02x) ", c); 485 else 486 fprintf(fp, "%03d ) ", c); 487 } 488 fprintf(fp, "\n"); 489 } 490 491 void 492 dump_entry(int value) 493 { 494 if (value & 0x100) { 495 value &= 0x00ff; 496 switch (value) { 497 case NOP: 498 printf(" NOP, "); 499 break; 500 case LSH: 501 printf(" LSH, "); 502 break; 503 case RSH: 504 printf(" RSH, "); 505 break; 506 case CLK: 507 printf(" CLK, "); 508 break; 509 case NLK: 510 printf(" NLK, "); 511 break; 512 case SLK: 513 printf(" SLK, "); 514 break; 515 case BTAB: 516 printf(" BTAB, "); 517 break; 518 case LALT: 519 printf(" LALT, "); 520 break; 521 case LCTR: 522 printf(" LCTR, "); 523 break; 524 case NEXT: 525 printf(" NEXT, "); 526 break; 527 case RCTR: 528 printf(" RCTR, "); 529 break; 530 case RALT: 531 printf(" RALT, "); 532 break; 533 case ALK: 534 printf(" ALK, "); 535 break; 536 case ASH: 537 printf(" ASH, "); 538 break; 539 case META: 540 printf(" META, "); 541 break; 542 case RBT: 543 printf(" RBT, "); 544 break; 545 case DBG: 546 printf(" DBG, "); 547 break; 548 case SUSP: 549 printf(" SUSP, "); 550 break; 551 default: 552 if (value >= F_FN && value <= L_FN) 553 printf(" F(%2d),", value - F_FN + 1); 554 else if (value >= F_SCR && value <= L_SCR) 555 printf(" S(%2d),", value - F_SCR + 1); 556 else if (value >= F_ACC && value <= L_ACC) 557 printf(" %-4s, ", acc_names_u[value - F_ACC]); 558 else 559 printf(" 0x%02X, ", value); 560 break; 561 } 562 } else if (value == '\'') { 563 printf(" '\\'', "); 564 } else if (value == '\\') { 565 printf(" '\\\\', "); 566 } else if (isascii(value) && isprint(value)) { 567 printf(" '%c', ", value); 568 } else { 569 printf(" 0x%02X, ", value); 570 } 571 } 572 573 void 574 dump_key_definition(char *name, keymap_t *keymap) 575 { 576 int i, j; 577 578 printf("static keymap_t keymap_%s = { 0x%02x, {\n", 579 name, (unsigned)keymap->n_keys); 580 printf( 581 "/* alt\n" 582 " * scan cntrl alt alt cntrl\n" 583 " * code base shift cntrl shift alt shift cntrl shift spcl flgs\n" 584 " * ---------------------------------------------------------------------------\n" 585 " */\n"); 586 for (i = 0; i < keymap->n_keys; i++) { 587 printf("/*%02x*/{{", i); 588 for (j = 0; j < NUM_STATES; j++) { 589 if (keymap->key[i].spcl & (0x80 >> j)) 590 dump_entry(keymap->key[i].map[j] | 0x100); 591 else 592 dump_entry(keymap->key[i].map[j]); 593 } 594 printf("}, 0x%02X,0x%02X },\n", 595 (unsigned)keymap->key[i].spcl, 596 (unsigned)keymap->key[i].flgs); 597 } 598 printf("} };\n\n"); 599 } 600 601 void 602 dump_accent_definition(char *name, accentmap_t *accentmap) 603 { 604 int i, j; 605 int c; 606 607 printf("static accentmap_t accentmap_%s = { %d", 608 name, accentmap->n_accs); 609 if (accentmap->n_accs <= 0) { 610 printf(" };\n\n"); 611 return; 612 } 613 printf(", {\n"); 614 for (i = 0; i < NUM_DEADKEYS; i++) { 615 printf(" /* %s=%d */\n {", acc_names[i], i); 616 c = accentmap->acc[i].accchar; 617 if (c == '\'') 618 printf(" '\\'', {"); 619 else if (c == '\\') 620 printf(" '\\\\', {"); 621 else if (isascii(c) && isprint(c)) 622 printf(" '%c', {", c); 623 else if (c == 0) { 624 printf(" 0x00 }, \n"); 625 continue; 626 } else 627 printf(" 0x%02x, {", c); 628 for (j = 0; j < NUM_ACCENTCHARS; j++) { 629 c = accentmap->acc[i].map[j][0]; 630 if (c == 0) 631 break; 632 if ((j > 0) && ((j % 4) == 0)) 633 printf("\n\t "); 634 if (isascii(c) && isprint(c)) 635 printf(" { '%c',", c); 636 else 637 printf(" { 0x%02x,", c); 638 printf("0x%02x },", accentmap->acc[i].map[j][1]); 639 } 640 printf(" }, },\n"); 641 } 642 printf("} };\n\n"); 643 } 644 645 void 646 load_keymap(char *opt, int dumponly) 647 { 648 keymap_t keymap; 649 accentmap_t accentmap; 650 FILE *fd; 651 int i; 652 char *name, *cp; 653 char *prefix[] = {"", "", KEYMAP_PATH, NULL}; 654 char *postfix[] = {"", ".kbd", ".kbd"}; 655 656 for (i=0; prefix[i]; i++) { 657 name = mkfullname(prefix[i], opt, postfix[i]); 658 if ((fd = fopen(name, "r"))) 659 break; 660 } 661 if (fd == NULL) { 662 warn("keymap file not found"); 663 return; 664 } 665 memset(&keymap, 0, sizeof(keymap)); 666 memset(&accentmap, 0, sizeof(accentmap)); 667 token = -1; 668 while (1) { 669 if (get_definition_line(fd, &keymap, &accentmap) < 0) 670 break; 671 } 672 if (dumponly) { 673 /* fix up the filename to make it a valid C identifier */ 674 for (cp = opt; *cp; cp++) 675 if (!isalpha(*cp) && !isdigit(*cp)) *cp = '_'; 676 printf("/*\n" 677 " * Automatically generated from %s.\n" 678 " * DO NOT EDIT!\n" 679 " */\n", name); 680 dump_key_definition(opt, &keymap); 681 dump_accent_definition(opt, &accentmap); 682 return; 683 } 684 if ((keymap.n_keys > 0) && (ioctl(0, PIO_KEYMAP, &keymap) < 0)) { 685 warn("setting keymap"); 686 fclose(fd); 687 return; 688 } 689 if ((accentmap.n_accs > 0) 690 && (ioctl(0, PIO_DEADKEYMAP, &accentmap) < 0)) { 691 warn("setting accentmap"); 692 fclose(fd); 693 return; 694 } 695 } 696 697 void 698 print_keymap() 699 { 700 keymap_t keymap; 701 accentmap_t accentmap; 702 int i; 703 704 if (ioctl(0, GIO_KEYMAP, &keymap) < 0) 705 err(1, "getting keymap"); 706 if (ioctl(0, GIO_DEADKEYMAP, &accentmap) < 0) 707 memset(&accentmap, 0, sizeof(accentmap)); 708 printf( 709 "# alt\n" 710 "# scan cntrl alt alt cntrl lock\n" 711 "# code base shift cntrl shift alt shift cntrl shift state\n" 712 "# ------------------------------------------------------------------\n" 713 ); 714 for (i=0; i<keymap.n_keys; i++) 715 print_key_definition_line(stdout, i, &keymap.key[i]); 716 717 printf("\n"); 718 for (i = 0; i < NUM_DEADKEYS; i++) 719 print_accent_definition_line(stdout, i, &accentmap.acc[i]); 720 721 } 722 723 724 void 725 load_default_functionkeys() 726 { 727 fkeyarg_t fkey; 728 int i; 729 730 for (i=0; i<NUM_FKEYS; i++) { 731 fkey.keynum = i; 732 strcpy(fkey.keydef, fkey_table[i]); 733 fkey.flen = strlen(fkey_table[i]); 734 if (ioctl(0, SETFKEY, &fkey) < 0) 735 warn("setting function key"); 736 } 737 } 738 739 void 740 set_functionkey(char *keynumstr, char *string) 741 { 742 fkeyarg_t fkey; 743 744 if (!strcmp(keynumstr, "load") && !strcmp(string, "default")) { 745 load_default_functionkeys(); 746 return; 747 } 748 fkey.keynum = atoi(keynumstr); 749 if (fkey.keynum < 1 || fkey.keynum > NUM_FKEYS) { 750 warnx("function key number must be between 1 and %d", 751 NUM_FKEYS); 752 return; 753 } 754 if ((fkey.flen = strlen(string)) > MAXFK) { 755 warnx("function key string too long (%d > %d)", 756 fkey.flen, MAXFK); 757 return; 758 } 759 strcpy(fkey.keydef, string); 760 fkey.keynum -= 1; 761 if (ioctl(0, SETFKEY, &fkey) < 0) 762 warn("setting function key"); 763 } 764 765 766 void 767 set_bell_values(char *opt) 768 { 769 int bell, duration, pitch; 770 771 if (!strcmp(opt, "visual")) 772 bell = 1, duration = 1, pitch = 800; 773 else if (!strcmp(opt, "normal")) 774 bell = 0, duration = 1, pitch = 800; 775 else { 776 char *v1; 777 778 bell = 0; 779 duration = strtol(opt, &v1, 0); 780 if ((duration < 0) || (*v1 != '.')) 781 goto badopt; 782 opt = ++v1; 783 pitch = strtol(opt, &v1, 0); 784 if ((pitch < 0) || (*opt == '\0') || (*v1 != '\0')) { 785 badopt: 786 warnx("argument to -b must be DURATION.PITCH"); 787 return; 788 } 789 } 790 791 ioctl(0, CONS_BELLTYPE, &bell); 792 if (!bell) 793 fprintf(stderr, "[=%d;%dB", pitch, duration); 794 } 795 796 797 void 798 set_keyrates(char *opt) 799 { 800 struct { 801 int rep:5; 802 int del:2; 803 int pad:1; 804 }rate; 805 806 if (!strcmp(opt, "slow")) 807 rate.del = 3, rate.rep = 31; 808 else if (!strcmp(opt, "normal")) 809 rate.del = 1, rate.rep = 15; 810 else if (!strcmp(opt, "fast")) 811 rate.del = rate.rep = 0; 812 else { 813 int n; 814 int delay, repeat; 815 char *v1; 816 817 delay = strtol(opt, &v1, 0); 818 if ((delay < 0) || (*v1 != '.')) 819 goto badopt; 820 opt = ++v1; 821 repeat = strtol(opt, &v1, 0); 822 if ((repeat < 0) || (*opt == '\0') || (*v1 != '\0')) { 823 badopt: 824 warnx("argument to -r must be delay.repeat"); 825 return; 826 } 827 for (n = 0; n < ndelays - 1; n++) 828 if (delay <= delays[n]) 829 break; 830 rate.del = n; 831 for (n = 0; n < nrepeats - 1; n++) 832 if (repeat <= repeats[n]) 833 break; 834 rate.rep = n; 835 } 836 837 if (ioctl(0, KDSETRAD, rate) < 0) 838 warn("setting keyboard rate"); 839 } 840 841 842 void 843 set_history(char *opt) 844 { 845 int size; 846 847 size = atoi(opt); 848 if ((*opt == '\0') || size < 0) { 849 warnx("argument must be a positive number"); 850 return; 851 } 852 if (ioctl(0, CONS_HISTORY, &size) == -1) 853 warn("setting history buffer size"); 854 } 855 856 857 static void 858 usage() 859 { 860 fprintf(stderr, "%s\n%s\n%s\n", 861 "usage: kbdcontrol [-dFx] [-b duration.pitch | belltype]", 862 " [-r delay.repeat | speed] [-l mapfile] [-f # string]", 863 " [-h size] [-L mapfile]"); 864 exit(1); 865 } 866 867 868 void 869 main(int argc, char **argv) 870 { 871 int opt; 872 873 while((opt = getopt(argc, argv, "b:df:h:Fl:L:r:x")) != -1) 874 switch(opt) { 875 case 'b': 876 set_bell_values(optarg); 877 break; 878 case 'd': 879 print_keymap(); 880 break; 881 case 'l': 882 load_keymap(optarg, 0); 883 break; 884 case 'L': 885 load_keymap(optarg, 1); 886 break; 887 case 'f': 888 set_functionkey(optarg, 889 nextarg(argc, argv, &optind, 'f')); 890 break; 891 case 'F': 892 load_default_functionkeys(); 893 break; 894 case 'h': 895 set_history(optarg); 896 break; 897 case 'r': 898 set_keyrates(optarg); 899 break; 900 case 'x': 901 hex = 1; 902 break; 903 default: 904 usage(); 905 } 906 if ((optind != argc) || (argc == 1)) 907 usage(); 908 exit(0); 909 } 910 911 912