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 "$FreeBSD$"; 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 <fcntl.h> 41 #include <machine/console.h> 42 #include "path.h" 43 #include "lex.h" 44 45 char ctrl_names[32][4] = { 46 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", 47 "bs ", "ht ", "nl ", "vt ", "ff ", "cr ", "so ", "si ", 48 "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", 49 "can", "em ", "sub", "esc", "fs ", "gs ", "rs ", "us " 50 }; 51 52 char acc_names[15][5] = { 53 "dgra", "dacu", "dcir", "dtil", "dmac", "dbre", "ddot", 54 "duml", "dsla", "drin", "dced", "dapo", "ddac", "dogo", 55 "dcar", 56 }; 57 58 char acc_names_u[15][5] = { 59 "DGRA", "DACU", "DCIR", "DTIL", "DMAC", "DBRE", "DDOT", 60 "DUML", "DSLA", "DRIN", "DCED", "DAPO", "DDAC", "DOGO", 61 "DCAR", 62 }; 63 64 char fkey_table[96][MAXFK] = { 65 /* 01-04 */ "\033[M", "\033[N", "\033[O", "\033[P", 66 /* 05-08 */ "\033[Q", "\033[R", "\033[S", "\033[T", 67 /* 09-12 */ "\033[U", "\033[V", "\033[W", "\033[X", 68 /* 13-16 */ "\033[Y", "\033[Z", "\033[a", "\033[b", 69 /* 17-20 */ "\033[c", "\033[d", "\033[e", "\033[f", 70 /* 21-24 */ "\033[g", "\033[h", "\033[i", "\033[j", 71 /* 25-28 */ "\033[k", "\033[l", "\033[m", "\033[n", 72 /* 29-32 */ "\033[o", "\033[p", "\033[q", "\033[r", 73 /* 33-36 */ "\033[s", "\033[t", "\033[u", "\033[v", 74 /* 37-40 */ "\033[w", "\033[x", "\033[y", "\033[z", 75 /* 41-44 */ "\033[@", "\033[[", "\033[\\","\033[]", 76 /* 45-48 */ "\033[^", "\033[_", "\033[`", "\033[{", 77 /* 49-52 */ "\033[H", "\033[A", "\033[I", "-" , 78 /* 53-56 */ "\033[D", "\033[E", "\033[C", "+" , 79 /* 57-60 */ "\033[F", "\033[B", "\033[G", "\033[L", 80 /* 61-64 */ "\177", "\033[J", "\033[~", "\033[}", 81 /* 65-68 */ "" , "" , "" , "" , 82 /* 69-72 */ "" , "" , "" , "" , 83 /* 73-76 */ "" , "" , "" , "" , 84 /* 77-80 */ "" , "" , "" , "" , 85 /* 81-84 */ "" , "" , "" , "" , 86 /* 85-88 */ "" , "" , "" , "" , 87 /* 89-92 */ "" , "" , "" , "" , 88 /* 93-96 */ "" , "" , "" , "" , 89 }; 90 91 const int delays[] = {250, 500, 750, 1000}; 92 const int repeats[] = { 34, 38, 42, 46, 50, 55, 59, 63, 93 68, 76, 84, 92, 100, 110, 118, 126, 94 136, 152, 168, 184, 200, 220, 236, 252, 95 272, 304, 336, 368, 400, 440, 472, 504}; 96 const int ndelays = (sizeof(delays) / sizeof(int)); 97 const int nrepeats = (sizeof(repeats) / sizeof(int)); 98 int hex = 0; 99 int number; 100 char letter; 101 int token; 102 103 static void usage __P((void)); 104 105 char * 106 nextarg(int ac, char **av, int *indp, int oc) 107 { 108 if (*indp < ac) 109 return(av[(*indp)++]); 110 warnx("option requires two arguments -- %c", oc); 111 usage(); 112 return(""); 113 } 114 115 116 char * 117 mkfullname(const char *s1, const char *s2, const char *s3) 118 { 119 static char *buf = NULL; 120 static int bufl = 0; 121 int f; 122 123 f = strlen(s1) + strlen(s2) + strlen(s3) + 1; 124 if (f > bufl) 125 if (buf) 126 buf = (char *)realloc(buf, f); 127 else 128 buf = (char *)malloc(f); 129 if (!buf) { 130 bufl = 0; 131 return(NULL); 132 } 133 134 bufl = f; 135 strcpy(buf, s1); 136 strcat(buf, s2); 137 strcat(buf, s3); 138 return(buf); 139 } 140 141 142 int 143 get_entry() 144 { 145 switch ((token = yylex())) { 146 case TNOP: 147 return NOP | 0x100; 148 case TLSH: 149 return LSH | 0x100; 150 case TRSH: 151 return RSH | 0x100; 152 case TCLK: 153 return CLK | 0x100; 154 case TNLK: 155 return NLK | 0x100; 156 case TSLK: 157 return SLK | 0x100; 158 case TBTAB: 159 return BTAB | 0x100; 160 case TLALT: 161 return LALT | 0x100; 162 case TLCTR: 163 return LCTR | 0x100; 164 case TNEXT: 165 return NEXT | 0x100; 166 case TPREV: 167 return PREV | 0x100; 168 case TRCTR: 169 return RCTR | 0x100; 170 case TRALT: 171 return RALT | 0x100; 172 case TALK: 173 return ALK | 0x100; 174 case TASH: 175 return ASH | 0x100; 176 case TMETA: 177 return META | 0x100; 178 case TRBT: 179 return RBT | 0x100; 180 case TDBG: 181 return DBG | 0x100; 182 case TSUSP: 183 return SUSP | 0x100; 184 case TSPSC: 185 return SPSC | 0x100; 186 case TPANIC: 187 return PNC | 0x100; 188 case TLSHA: 189 return LSHA | 0x100; 190 case TRSHA: 191 return RSHA | 0x100; 192 case TLCTRA: 193 return LCTRA | 0x100; 194 case TRCTRA: 195 return RCTRA | 0x100; 196 case TLALTA: 197 return LALTA | 0x100; 198 case TRALTA: 199 return RALTA | 0x100; 200 case TACC: 201 if (ACC(number) > L_ACC) 202 return -1; 203 return ACC(number) | 0x100; 204 case TFUNC: 205 if (F(number) > L_FN) 206 return -1; 207 return F(number) | 0x100; 208 case TSCRN: 209 if (S(number) > L_SCR) 210 return -1; 211 return S(number) | 0x100; 212 case TLET: 213 return (unsigned char)letter; 214 case TNUM: 215 if (number < 0 || number > 255) 216 return -1; 217 return number; 218 default: 219 return -1; 220 } 221 } 222 223 int 224 get_definition_line(FILE *fd, keymap_t *keymap, accentmap_t *accentmap) 225 { 226 int c; 227 228 yyin = fd; 229 230 if (token < 0) 231 token = yylex(); 232 switch (token) { 233 case TNUM: 234 c = get_key_definition_line(keymap); 235 if (c < 0) 236 errx(1, "invalid key definition"); 237 if (c > keymap->n_keys) 238 keymap->n_keys = c; 239 break; 240 case TACC: 241 c = get_accent_definition_line(accentmap); 242 if (c < 0) 243 errx(1, "invalid accent key definition"); 244 if (c > accentmap->n_accs) 245 accentmap->n_accs = c; 246 break; 247 case 0: 248 /* EOF */ 249 return -1; 250 default: 251 errx(1, "illegal definition line"); 252 } 253 return c; 254 } 255 256 int 257 get_key_definition_line(keymap_t *map) 258 { 259 int i, def, scancode; 260 261 /* check scancode number */ 262 if (number < 0 || number >= NUM_KEYS) 263 return -1; 264 scancode = number; 265 266 /* get key definitions */ 267 map->key[scancode].spcl = 0; 268 for (i=0; i<NUM_STATES; i++) { 269 if ((def = get_entry()) == -1) 270 return -1; 271 if (def & 0x100) 272 map->key[scancode].spcl |= (0x80 >> i); 273 map->key[scancode].map[i] = def & 0xFF; 274 } 275 /* get lock state key def */ 276 if ((token = yylex()) != TFLAG) 277 return -1; 278 map->key[scancode].flgs = number; 279 token = yylex(); 280 return (scancode + 1); 281 } 282 283 int 284 get_accent_definition_line(accentmap_t *map) 285 { 286 int accent; 287 int c1, c2; 288 int i; 289 290 if (ACC(number) < F_ACC || ACC(number) > L_ACC) 291 /* number out of range */ 292 return -1; 293 accent = number; 294 if (map->acc[accent].accchar != 0) { 295 /* this entry has already been defined before! */ 296 errx(1, "duplicated accent key definition"); 297 } 298 299 switch ((token = yylex())) { 300 case TLET: 301 map->acc[accent].accchar = letter; 302 break; 303 case TNUM: 304 map->acc[accent].accchar = number; 305 break; 306 default: 307 return -1; 308 } 309 310 for (i = 0; (token = yylex()) == '(';) { 311 switch ((token = yylex())) { 312 case TLET: 313 c1 = letter; 314 break; 315 case TNUM: 316 c1 = number; 317 break; 318 default: 319 return -1; 320 } 321 switch ((token = yylex())) { 322 case TLET: 323 c2 = letter; 324 break; 325 case TNUM: 326 c2 = number; 327 break; 328 default: 329 return -1; 330 } 331 if ((token = yylex()) != ')') 332 return -1; 333 if (i >= NUM_ACCENTCHARS) { 334 warnx("too many accented characters, ignored"); 335 continue; 336 } 337 map->acc[accent].map[i][0] = c1; 338 map->acc[accent].map[i][1] = c2; 339 ++i; 340 } 341 return (accent + 1); 342 } 343 344 void 345 print_entry(FILE *fp, int value) 346 { 347 int val = value & 0xFF; 348 349 switch (value) { 350 case NOP | 0x100: 351 fprintf(fp, " nop "); 352 break; 353 case LSH | 0x100: 354 fprintf(fp, " lshift"); 355 break; 356 case RSH | 0x100: 357 fprintf(fp, " rshift"); 358 break; 359 case CLK | 0x100: 360 fprintf(fp, " clock "); 361 break; 362 case NLK | 0x100: 363 fprintf(fp, " nlock "); 364 break; 365 case SLK | 0x100: 366 fprintf(fp, " slock "); 367 break; 368 case BTAB | 0x100: 369 fprintf(fp, " btab "); 370 break; 371 case LALT | 0x100: 372 fprintf(fp, " lalt "); 373 break; 374 case LCTR | 0x100: 375 fprintf(fp, " lctrl "); 376 break; 377 case NEXT | 0x100: 378 fprintf(fp, " nscr "); 379 break; 380 case PREV | 0x100: 381 fprintf(fp, " pscr "); 382 break; 383 case RCTR | 0x100: 384 fprintf(fp, " rctrl "); 385 break; 386 case RALT | 0x100: 387 fprintf(fp, " ralt "); 388 break; 389 case ALK | 0x100: 390 fprintf(fp, " alock "); 391 break; 392 case ASH | 0x100: 393 fprintf(fp, " ashift"); 394 break; 395 case META | 0x100: 396 fprintf(fp, " meta "); 397 break; 398 case RBT | 0x100: 399 fprintf(fp, " boot "); 400 break; 401 case DBG | 0x100: 402 fprintf(fp, " debug "); 403 break; 404 case SUSP | 0x100: 405 fprintf(fp, " susp "); 406 break; 407 case SPSC | 0x100: 408 fprintf(fp, " saver "); 409 break; 410 case PNC | 0x100: 411 fprintf(fp, " panic "); 412 break; 413 case LSHA | 0x100: 414 fprintf(fp, " lshifta"); 415 break; 416 case RSHA | 0x100: 417 fprintf(fp, " rshifta"); 418 break; 419 case LCTRA | 0x100: 420 fprintf(fp, " lctrla"); 421 break; 422 case RCTRA | 0x100: 423 fprintf(fp, " rctrla"); 424 break; 425 case LALTA | 0x100: 426 fprintf(fp, " lalta "); 427 break; 428 case RALTA | 0x100: 429 fprintf(fp, " ralta "); 430 break; 431 default: 432 if (value & 0x100) { 433 if (val >= F_FN && val <= L_FN) 434 fprintf(fp, " fkey%02d", val - F_FN + 1); 435 else if (val >= F_SCR && val <= L_SCR) 436 fprintf(fp, " scr%02d ", val - F_SCR + 1); 437 else if (val >= F_ACC && val <= L_ACC) 438 fprintf(fp, " %-6s", acc_names[val - F_ACC]); 439 else if (hex) 440 fprintf(fp, " 0x%02x ", val); 441 else 442 fprintf(fp, " %3d ", val); 443 } 444 else { 445 if (val < ' ') 446 fprintf(fp, " %s ", ctrl_names[val]); 447 else if (val == 127) 448 fprintf(fp, " del "); 449 else if (isascii(val) && isprint(val)) 450 fprintf(fp, " '%c' ", val); 451 else if (hex) 452 fprintf(fp, " 0x%02x ", val); 453 else 454 fprintf(fp, " %3d ", val); 455 } 456 } 457 } 458 459 460 void 461 print_key_definition_line(FILE *fp, int scancode, struct keyent_t *key) 462 { 463 int i; 464 465 /* print scancode number */ 466 if (hex) 467 fprintf(fp, " 0x%02x ", scancode); 468 else 469 fprintf(fp, " %03d ", scancode); 470 471 /* print key definitions */ 472 for (i=0; i<NUM_STATES; i++) { 473 if (key->spcl & (0x80 >> i)) 474 print_entry(fp, key->map[i] | 0x100); 475 else 476 print_entry(fp, key->map[i]); 477 } 478 479 /* print lock state key def */ 480 switch (key->flgs) { 481 case 0: 482 fprintf(fp, " O\n"); 483 break; 484 case 1: 485 fprintf(fp, " C\n"); 486 break; 487 case 2: 488 fprintf(fp, " N\n"); 489 break; 490 case 3: 491 fprintf(fp, " B\n"); 492 break; 493 } 494 } 495 496 void 497 print_accent_definition_line(FILE *fp, int accent, struct acc_t *key) 498 { 499 int c; 500 int i; 501 502 if (key->accchar == 0) 503 return; 504 505 /* print accent number */ 506 fprintf(fp, " %-6s", acc_names[accent]); 507 if (isascii(key->accchar) && isprint(key->accchar)) 508 fprintf(fp, "'%c' ", key->accchar); 509 else if (hex) 510 fprintf(fp, "0x%02x ", key->accchar); 511 else 512 fprintf(fp, "%03d ", key->accchar); 513 514 for (i = 0; i < NUM_ACCENTCHARS; ++i) { 515 c = key->map[i][0]; 516 if (c == 0) 517 break; 518 if ((i > 0) && ((i % 4) == 0)) 519 fprintf(fp, "\n "); 520 if (isascii(c) && isprint(c)) 521 fprintf(fp, "( '%c' ", c); 522 else if (hex) 523 fprintf(fp, "(0x%02x ", c); 524 else 525 fprintf(fp, "( %03d ", c); 526 c = key->map[i][1]; 527 if (isascii(c) && isprint(c)) 528 fprintf(fp, "'%c' ) ", c); 529 else if (hex) 530 fprintf(fp, "0x%02x) ", c); 531 else 532 fprintf(fp, "%03d ) ", c); 533 } 534 fprintf(fp, "\n"); 535 } 536 537 void 538 dump_entry(int value) 539 { 540 if (value & 0x100) { 541 value &= 0x00ff; 542 switch (value) { 543 case NOP: 544 printf(" NOP, "); 545 break; 546 case LSH: 547 printf(" LSH, "); 548 break; 549 case RSH: 550 printf(" RSH, "); 551 break; 552 case CLK: 553 printf(" CLK, "); 554 break; 555 case NLK: 556 printf(" NLK, "); 557 break; 558 case SLK: 559 printf(" SLK, "); 560 break; 561 case BTAB: 562 printf(" BTAB, "); 563 break; 564 case LALT: 565 printf(" LALT, "); 566 break; 567 case LCTR: 568 printf(" LCTR, "); 569 break; 570 case NEXT: 571 printf(" NEXT, "); 572 break; 573 case PREV: 574 printf(" PREV, "); 575 break; 576 case RCTR: 577 printf(" RCTR, "); 578 break; 579 case RALT: 580 printf(" RALT, "); 581 break; 582 case ALK: 583 printf(" ALK, "); 584 break; 585 case ASH: 586 printf(" ASH, "); 587 break; 588 case META: 589 printf(" META, "); 590 break; 591 case RBT: 592 printf(" RBT, "); 593 break; 594 case DBG: 595 printf(" DBG, "); 596 break; 597 case SUSP: 598 printf(" SUSP, "); 599 break; 600 case SPSC: 601 printf(" SPSC, "); 602 break; 603 case PNC: 604 printf(" PNC, "); 605 break; 606 case LSHA: 607 printf(" LSHA, "); 608 break; 609 case RSHA: 610 printf(" RSHA, "); 611 break; 612 case LCTRA: 613 printf("LCTRA, "); 614 break; 615 case RCTRA: 616 printf("RCTRA, "); 617 break; 618 case LALTA: 619 printf("LALTA, "); 620 break; 621 case RALTA: 622 printf("RALTA, "); 623 break; 624 default: 625 if (value >= F_FN && value <= L_FN) 626 printf(" F(%2d),", value - F_FN + 1); 627 else if (value >= F_SCR && value <= L_SCR) 628 printf(" S(%2d),", value - F_SCR + 1); 629 else if (value >= F_ACC && value <= L_ACC) 630 printf(" %-4s, ", acc_names_u[value - F_ACC]); 631 else 632 printf(" 0x%02X, ", value); 633 break; 634 } 635 } else if (value == '\'') { 636 printf(" '\\'', "); 637 } else if (value == '\\') { 638 printf(" '\\\\', "); 639 } else if (isascii(value) && isprint(value)) { 640 printf(" '%c', ", value); 641 } else { 642 printf(" 0x%02X, ", value); 643 } 644 } 645 646 void 647 dump_key_definition(char *name, keymap_t *keymap) 648 { 649 int i, j; 650 651 printf("static keymap_t keymap_%s = { 0x%02x, {\n", 652 name, (unsigned)keymap->n_keys); 653 printf( 654 "/* alt\n" 655 " * scan cntrl alt alt cntrl\n" 656 " * code base shift cntrl shift alt shift cntrl shift spcl flgs\n" 657 " * ---------------------------------------------------------------------------\n" 658 " */\n"); 659 for (i = 0; i < keymap->n_keys; i++) { 660 printf("/*%02x*/{{", i); 661 for (j = 0; j < NUM_STATES; j++) { 662 if (keymap->key[i].spcl & (0x80 >> j)) 663 dump_entry(keymap->key[i].map[j] | 0x100); 664 else 665 dump_entry(keymap->key[i].map[j]); 666 } 667 printf("}, 0x%02X,0x%02X },\n", 668 (unsigned)keymap->key[i].spcl, 669 (unsigned)keymap->key[i].flgs); 670 } 671 printf("} };\n\n"); 672 } 673 674 void 675 dump_accent_definition(char *name, accentmap_t *accentmap) 676 { 677 int i, j; 678 int c; 679 680 printf("static accentmap_t accentmap_%s = { %d", 681 name, accentmap->n_accs); 682 if (accentmap->n_accs <= 0) { 683 printf(" };\n\n"); 684 return; 685 } 686 printf(", {\n"); 687 for (i = 0; i < NUM_DEADKEYS; i++) { 688 printf(" /* %s=%d */\n {", acc_names[i], i); 689 c = accentmap->acc[i].accchar; 690 if (c == '\'') 691 printf(" '\\'', {"); 692 else if (c == '\\') 693 printf(" '\\\\', {"); 694 else if (isascii(c) && isprint(c)) 695 printf(" '%c', {", c); 696 else if (c == 0) { 697 printf(" 0x00 }, \n"); 698 continue; 699 } else 700 printf(" 0x%02x, {", c); 701 for (j = 0; j < NUM_ACCENTCHARS; j++) { 702 c = accentmap->acc[i].map[j][0]; 703 if (c == 0) 704 break; 705 if ((j > 0) && ((j % 4) == 0)) 706 printf("\n\t "); 707 if (isascii(c) && isprint(c)) 708 printf(" { '%c',", c); 709 else 710 printf(" { 0x%02x,", c); 711 printf("0x%02x },", accentmap->acc[i].map[j][1]); 712 } 713 printf(" }, },\n"); 714 } 715 printf("} };\n\n"); 716 } 717 718 void 719 load_keymap(char *opt, int dumponly) 720 { 721 keymap_t keymap; 722 accentmap_t accentmap; 723 FILE *fd; 724 int i; 725 char *name, *cp; 726 char *prefix[] = {"", "", KEYMAP_PATH, KEYMAP_PATH, NULL}; 727 char *postfix[] = {"", ".kbd", "", ".kbd"}; 728 729 for (i=0; prefix[i]; i++) { 730 name = mkfullname(prefix[i], opt, postfix[i]); 731 if ((fd = fopen(name, "r"))) 732 break; 733 } 734 if (fd == NULL) { 735 warn("keymap file not found"); 736 return; 737 } 738 memset(&keymap, 0, sizeof(keymap)); 739 memset(&accentmap, 0, sizeof(accentmap)); 740 token = -1; 741 while (1) { 742 if (get_definition_line(fd, &keymap, &accentmap) < 0) 743 break; 744 } 745 if (dumponly) { 746 /* fix up the filename to make it a valid C identifier */ 747 for (cp = opt; *cp; cp++) 748 if (!isalpha(*cp) && !isdigit(*cp)) *cp = '_'; 749 printf("/*\n" 750 " * Automatically generated from %s.\n" 751 " * DO NOT EDIT!\n" 752 " */\n", name); 753 dump_key_definition(opt, &keymap); 754 dump_accent_definition(opt, &accentmap); 755 return; 756 } 757 if ((keymap.n_keys > 0) && (ioctl(0, PIO_KEYMAP, &keymap) < 0)) { 758 warn("setting keymap"); 759 fclose(fd); 760 return; 761 } 762 if ((accentmap.n_accs > 0) 763 && (ioctl(0, PIO_DEADKEYMAP, &accentmap) < 0)) { 764 warn("setting accentmap"); 765 fclose(fd); 766 return; 767 } 768 } 769 770 void 771 print_keymap() 772 { 773 keymap_t keymap; 774 accentmap_t accentmap; 775 int i; 776 777 if (ioctl(0, GIO_KEYMAP, &keymap) < 0) 778 err(1, "getting keymap"); 779 if (ioctl(0, GIO_DEADKEYMAP, &accentmap) < 0) 780 memset(&accentmap, 0, sizeof(accentmap)); 781 printf( 782 "# alt\n" 783 "# scan cntrl alt alt cntrl lock\n" 784 "# code base shift cntrl shift alt shift cntrl shift state\n" 785 "# ------------------------------------------------------------------\n" 786 ); 787 for (i=0; i<keymap.n_keys; i++) 788 print_key_definition_line(stdout, i, &keymap.key[i]); 789 790 printf("\n"); 791 for (i = 0; i < NUM_DEADKEYS; i++) 792 print_accent_definition_line(stdout, i, &accentmap.acc[i]); 793 794 } 795 796 797 void 798 load_default_functionkeys() 799 { 800 fkeyarg_t fkey; 801 int i; 802 803 for (i=0; i<NUM_FKEYS; i++) { 804 fkey.keynum = i; 805 strcpy(fkey.keydef, fkey_table[i]); 806 fkey.flen = strlen(fkey_table[i]); 807 if (ioctl(0, SETFKEY, &fkey) < 0) 808 warn("setting function key"); 809 } 810 } 811 812 void 813 set_functionkey(char *keynumstr, char *string) 814 { 815 fkeyarg_t fkey; 816 817 if (!strcmp(keynumstr, "load") && !strcmp(string, "default")) { 818 load_default_functionkeys(); 819 return; 820 } 821 fkey.keynum = atoi(keynumstr); 822 if (fkey.keynum < 1 || fkey.keynum > NUM_FKEYS) { 823 warnx("function key number must be between 1 and %d", 824 NUM_FKEYS); 825 return; 826 } 827 if ((fkey.flen = strlen(string)) > MAXFK) { 828 warnx("function key string too long (%d > %d)", 829 fkey.flen, MAXFK); 830 return; 831 } 832 strcpy(fkey.keydef, string); 833 fkey.keynum -= 1; 834 if (ioctl(0, SETFKEY, &fkey) < 0) 835 warn("setting function key"); 836 } 837 838 839 void 840 set_bell_values(char *opt) 841 { 842 int bell, duration, pitch; 843 844 bell = 0; 845 if (!strncmp(opt, "quiet.", 6)) { 846 bell = 2; 847 opt += 6; 848 } 849 if (!strcmp(opt, "visual")) 850 bell |= 1; 851 else if (!strcmp(opt, "normal")) 852 duration = 5, pitch = 800; 853 else if (!strcmp(opt, "off")) 854 duration = 0, pitch = 0; 855 else { 856 char *v1; 857 858 bell = 0; 859 duration = strtol(opt, &v1, 0); 860 if ((duration < 0) || (*v1 != '.')) 861 goto badopt; 862 opt = ++v1; 863 pitch = strtol(opt, &v1, 0); 864 if ((pitch < 0) || (*opt == '\0') || (*v1 != '\0')) { 865 badopt: 866 warnx("argument to -b must be DURATION.PITCH"); 867 return; 868 } 869 if (pitch != 0) 870 pitch = 1193182 / pitch; /* in Hz */ 871 duration /= 10; /* in 10 m sec */ 872 } 873 874 ioctl(0, CONS_BELLTYPE, &bell); 875 if ((bell & ~2) == 0) 876 fprintf(stderr, "[=%d;%dB", pitch, duration); 877 } 878 879 880 void 881 set_keyrates(char *opt) 882 { 883 int arg[2]; 884 int repeat; 885 int delay; 886 int r, d; 887 888 if (!strcmp(opt, "slow")) { 889 delay = 1000, repeat = 500; 890 d = 3, r = 31; 891 } else if (!strcmp(opt, "normal")) { 892 delay = 500, repeat = 125; 893 d = 1, r = 15; 894 } else if (!strcmp(opt, "fast")) { 895 delay = repeat = 0; 896 d = r = 0; 897 } else { 898 int n; 899 char *v1; 900 901 delay = strtol(opt, &v1, 0); 902 if ((delay < 0) || (*v1 != '.')) 903 goto badopt; 904 opt = ++v1; 905 repeat = strtol(opt, &v1, 0); 906 if ((repeat < 0) || (*opt == '\0') || (*v1 != '\0')) { 907 badopt: 908 warnx("argument to -r must be delay.repeat"); 909 return; 910 } 911 for (n = 0; n < ndelays - 1; n++) 912 if (delay <= delays[n]) 913 break; 914 d = n; 915 for (n = 0; n < nrepeats - 1; n++) 916 if (repeat <= repeats[n]) 917 break; 918 r = n; 919 } 920 921 arg[0] = delay; 922 arg[1] = repeat; 923 if (ioctl(0, KDSETREPEAT, arg)) { 924 if (ioctl(0, KDSETRAD, (d << 5) | r)) 925 warn("setting keyboard rate"); 926 } 927 } 928 929 930 void 931 set_history(char *opt) 932 { 933 int size; 934 935 size = atoi(opt); 936 if ((*opt == '\0') || size < 0) { 937 warnx("argument must be a positive number"); 938 return; 939 } 940 if (ioctl(0, CONS_HISTORY, &size) == -1) 941 warn("setting history buffer size"); 942 } 943 944 static char 945 *get_kbd_type_name(int type) 946 { 947 static struct { 948 int type; 949 char *name; 950 } name_table[] = { 951 { KB_84, "AT 84" }, 952 { KB_101, "AT 101/102" }, 953 { KB_OTHER, "generic" }, 954 }; 955 int i; 956 957 for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) { 958 if (type == name_table[i].type) 959 return name_table[i].name; 960 } 961 return "unknown"; 962 } 963 964 void 965 show_kbd_info(void) 966 { 967 keyboard_info_t info; 968 969 if (ioctl(0, KDGKBINFO, &info) == -1) { 970 warn("unable to obtain keyboard information"); 971 return; 972 } 973 printf("kbd%d:\n", info.kb_index); 974 printf(" %.*s%d, type:%s (%d)\n", 975 sizeof(info.kb_name), info.kb_name, info.kb_unit, 976 get_kbd_type_name(info.kb_type), info.kb_type); 977 } 978 979 980 void 981 set_keyboard(char *device) 982 { 983 keyboard_info_t info; 984 int fd; 985 986 fd = open(device, O_RDONLY); 987 if (fd < 0) { 988 warn("cannot open %s", device); 989 return; 990 } 991 if (ioctl(fd, KDGKBINFO, &info) == -1) { 992 warn("unable to obtain keyboard information"); 993 close(fd); 994 return; 995 } 996 /* 997 * The keyboard device driver won't release the keyboard by 998 * the following ioctl, but it automatically will, when the device 999 * is closed. So, we don't check error here. 1000 */ 1001 ioctl(fd, CONS_RELKBD, 0); 1002 close(fd); 1003 #if 1 1004 printf("kbd%d\n", info.kb_index); 1005 printf(" %.*s%d, type:%s (%d)\n", 1006 sizeof(info.kb_name), info.kb_name, info.kb_unit, 1007 get_kbd_type_name(info.kb_type), info.kb_type); 1008 #endif 1009 1010 if (ioctl(0, CONS_SETKBD, info.kb_index) == -1) 1011 warn("unable to set keyboard"); 1012 } 1013 1014 1015 void 1016 release_keyboard(void) 1017 { 1018 keyboard_info_t info; 1019 1020 /* 1021 * If stdin is not associated with a keyboard, the following ioctl 1022 * will fail. 1023 */ 1024 if (ioctl(0, KDGKBINFO, &info) == -1) { 1025 warn("unable to obtain keyboard information"); 1026 return; 1027 } 1028 #if 1 1029 printf("kbd%d\n", info.kb_index); 1030 printf(" %.*s%d, type:%s (%d)\n", 1031 sizeof(info.kb_name), info.kb_name, info.kb_unit, 1032 get_kbd_type_name(info.kb_type), info.kb_type); 1033 #endif 1034 if (ioctl(0, CONS_RELKBD, 0) == -1) 1035 warn("unable to release the keyboard"); 1036 } 1037 1038 1039 static void 1040 usage() 1041 { 1042 fprintf(stderr, "%s\n%s\n%s\n", 1043 "usage: kbdcontrol [-dFKix] [-b duration.pitch | [quiet.]belltype]", 1044 " [-r delay.repeat | speed] [-l mapfile] [-f # string]", 1045 " [-h size] [-k device] [-L mapfile]"); 1046 exit(1); 1047 } 1048 1049 1050 int 1051 main(int argc, char **argv) 1052 { 1053 int opt; 1054 1055 while((opt = getopt(argc, argv, "b:df:h:iKk:Fl:L:r:x")) != -1) 1056 switch(opt) { 1057 case 'b': 1058 set_bell_values(optarg); 1059 break; 1060 case 'd': 1061 print_keymap(); 1062 break; 1063 case 'l': 1064 load_keymap(optarg, 0); 1065 break; 1066 case 'L': 1067 load_keymap(optarg, 1); 1068 break; 1069 case 'f': 1070 set_functionkey(optarg, 1071 nextarg(argc, argv, &optind, 'f')); 1072 break; 1073 case 'F': 1074 load_default_functionkeys(); 1075 break; 1076 case 'h': 1077 set_history(optarg); 1078 break; 1079 case 'i': 1080 show_kbd_info(); 1081 break; 1082 case 'K': 1083 release_keyboard(); 1084 break; 1085 case 'k': 1086 set_keyboard(optarg); 1087 break; 1088 case 'r': 1089 set_keyrates(optarg); 1090 break; 1091 case 'x': 1092 hex = 1; 1093 break; 1094 default: 1095 usage(); 1096 } 1097 if ((optind != argc) || (argc == 1)) 1098 usage(); 1099 exit(0); 1100 } 1101 1102 1103