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.21 1999/01/12 23:06:29 mjacob 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 <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 TRCTR: 167 return RCTR | 0x100; 168 case TRALT: 169 return RALT | 0x100; 170 case TALK: 171 return ALK | 0x100; 172 case TASH: 173 return ASH | 0x100; 174 case TMETA: 175 return META | 0x100; 176 case TRBT: 177 return RBT | 0x100; 178 case TDBG: 179 return DBG | 0x100; 180 case TSUSP: 181 return SUSP | 0x100; 182 case TSPSC: 183 return SPSC | 0x100; 184 case TACC: 185 if (ACC(number) > L_ACC) 186 return -1; 187 return ACC(number) | 0x100; 188 case TFUNC: 189 if (F(number) > L_FN) 190 return -1; 191 return F(number) | 0x100; 192 case TSCRN: 193 if (S(number) > L_SCR) 194 return -1; 195 return S(number) | 0x100; 196 case TLET: 197 return (unsigned char)letter; 198 case TNUM: 199 if (number < 0 || number > 255) 200 return -1; 201 return number; 202 default: 203 return -1; 204 } 205 } 206 207 int 208 get_definition_line(FILE *fd, keymap_t *keymap, accentmap_t *accentmap) 209 { 210 int c; 211 212 yyin = fd; 213 214 if (token < 0) 215 token = yylex(); 216 switch (token) { 217 case TNUM: 218 c = get_key_definition_line(keymap); 219 if (c < 0) 220 errx(1, "invalid key definition"); 221 if (c > keymap->n_keys) 222 keymap->n_keys = c; 223 break; 224 case TACC: 225 c = get_accent_definition_line(accentmap); 226 if (c < 0) 227 errx(1, "invalid accent key definition"); 228 if (c > accentmap->n_accs) 229 accentmap->n_accs = c; 230 break; 231 case 0: 232 /* EOF */ 233 return -1; 234 default: 235 errx(1, "illegal definition line"); 236 } 237 return c; 238 } 239 240 int 241 get_key_definition_line(keymap_t *map) 242 { 243 int i, def, scancode; 244 245 /* check scancode number */ 246 if (number < 0 || number >= NUM_KEYS) 247 return -1; 248 scancode = number; 249 250 /* get key definitions */ 251 map->key[scancode].spcl = 0; 252 for (i=0; i<NUM_STATES; i++) { 253 if ((def = get_entry()) == -1) 254 return -1; 255 if (def & 0x100) 256 map->key[scancode].spcl |= (0x80 >> i); 257 map->key[scancode].map[i] = def & 0xFF; 258 } 259 /* get lock state key def */ 260 if ((token = yylex()) != TFLAG) 261 return -1; 262 map->key[scancode].flgs = number; 263 token = yylex(); 264 return (scancode + 1); 265 } 266 267 int 268 get_accent_definition_line(accentmap_t *map) 269 { 270 int accent; 271 int c1, c2; 272 int i; 273 274 if (ACC(number) < F_ACC || ACC(number) > L_ACC) 275 /* number out of range */ 276 return -1; 277 accent = number; 278 if (map->acc[accent].accchar != 0) { 279 /* this entry has already been defined before! */ 280 errx(1, "duplicated accent key definition"); 281 } 282 283 switch ((token = yylex())) { 284 case TLET: 285 map->acc[accent].accchar = letter; 286 break; 287 case TNUM: 288 map->acc[accent].accchar = number; 289 break; 290 default: 291 return -1; 292 } 293 294 for (i = 0; (token = yylex()) == '(';) { 295 switch ((token = yylex())) { 296 case TLET: 297 c1 = letter; 298 break; 299 case TNUM: 300 c1 = number; 301 break; 302 default: 303 return -1; 304 } 305 switch ((token = yylex())) { 306 case TLET: 307 c2 = letter; 308 break; 309 case TNUM: 310 c2 = number; 311 break; 312 default: 313 return -1; 314 } 315 if ((token = yylex()) != ')') 316 return -1; 317 if (i >= NUM_ACCENTCHARS) { 318 warnx("too many accented characters, ignored"); 319 continue; 320 } 321 map->acc[accent].map[i][0] = c1; 322 map->acc[accent].map[i][1] = c2; 323 ++i; 324 } 325 return (accent + 1); 326 } 327 328 void 329 print_entry(FILE *fp, int value) 330 { 331 int val = value & 0xFF; 332 333 switch (value) { 334 case NOP | 0x100: 335 fprintf(fp, " nop "); 336 break; 337 case LSH | 0x100: 338 fprintf(fp, " lshift"); 339 break; 340 case RSH | 0x100: 341 fprintf(fp, " rshift"); 342 break; 343 case CLK | 0x100: 344 fprintf(fp, " clock "); 345 break; 346 case NLK | 0x100: 347 fprintf(fp, " nlock "); 348 break; 349 case SLK | 0x100: 350 fprintf(fp, " slock "); 351 break; 352 case BTAB | 0x100: 353 fprintf(fp, " btab "); 354 break; 355 case LALT | 0x100: 356 fprintf(fp, " lalt "); 357 break; 358 case LCTR | 0x100: 359 fprintf(fp, " lctrl "); 360 break; 361 case NEXT | 0x100: 362 fprintf(fp, " nscr "); 363 break; 364 case RCTR | 0x100: 365 fprintf(fp, " rctrl "); 366 break; 367 case RALT | 0x100: 368 fprintf(fp, " ralt "); 369 break; 370 case ALK | 0x100: 371 fprintf(fp, " alock "); 372 break; 373 case ASH | 0x100: 374 fprintf(fp, " ashift"); 375 break; 376 case META | 0x100: 377 fprintf(fp, " meta "); 378 break; 379 case RBT | 0x100: 380 fprintf(fp, " boot "); 381 break; 382 case DBG | 0x100: 383 fprintf(fp, " debug "); 384 break; 385 case SUSP | 0x100: 386 fprintf(fp, " susp "); 387 break; 388 case SPSC | 0x100: 389 fprintf(fp, " saver "); 390 break; 391 default: 392 if (value & 0x100) { 393 if (val >= F_FN && val <= L_FN) 394 fprintf(fp, " fkey%02d", val - F_FN + 1); 395 else if (val >= F_SCR && val <= L_SCR) 396 fprintf(fp, " scr%02d ", val - F_SCR + 1); 397 else if (val >= F_ACC && val <= L_ACC) 398 fprintf(fp, " %-6s", acc_names[val - F_ACC]); 399 else if (hex) 400 fprintf(fp, " 0x%02x ", val); 401 else 402 fprintf(fp, " %3d ", val); 403 } 404 else { 405 if (val < ' ') 406 fprintf(fp, " %s ", ctrl_names[val]); 407 else if (val == 127) 408 fprintf(fp, " del "); 409 else if (isascii(val) && isprint(val)) 410 fprintf(fp, " '%c' ", val); 411 else if (hex) 412 fprintf(fp, " 0x%02x ", val); 413 else 414 fprintf(fp, " %3d ", val); 415 } 416 } 417 } 418 419 420 void 421 print_key_definition_line(FILE *fp, int scancode, struct keyent_t *key) 422 { 423 int i; 424 425 /* print scancode number */ 426 if (hex) 427 fprintf(fp, " 0x%02x ", scancode); 428 else 429 fprintf(fp, " %03d ", scancode); 430 431 /* print key definitions */ 432 for (i=0; i<NUM_STATES; i++) { 433 if (key->spcl & (0x80 >> i)) 434 print_entry(fp, key->map[i] | 0x100); 435 else 436 print_entry(fp, key->map[i]); 437 } 438 439 /* print lock state key def */ 440 switch (key->flgs) { 441 case 0: 442 fprintf(fp, " O\n"); 443 break; 444 case 1: 445 fprintf(fp, " C\n"); 446 break; 447 case 2: 448 fprintf(fp, " N\n"); 449 break; 450 case 3: 451 fprintf(fp, " B\n"); 452 break; 453 } 454 } 455 456 void 457 print_accent_definition_line(FILE *fp, int accent, struct acc_t *key) 458 { 459 int c; 460 int i; 461 462 if (key->accchar == 0) 463 return; 464 465 /* print accent number */ 466 fprintf(fp, " %-6s", acc_names[accent]); 467 if (isascii(key->accchar) && isprint(key->accchar)) 468 fprintf(fp, "'%c' ", key->accchar); 469 else if (hex) 470 fprintf(fp, "0x%02x ", key->accchar); 471 else 472 fprintf(fp, "%03d ", key->accchar); 473 474 for (i = 0; i < NUM_ACCENTCHARS; ++i) { 475 c = key->map[i][0]; 476 if (c == 0) 477 break; 478 if ((i > 0) && ((i % 4) == 0)) 479 fprintf(fp, "\n "); 480 if (isascii(c) && isprint(c)) 481 fprintf(fp, "( '%c' ", c); 482 else if (hex) 483 fprintf(fp, "(0x%02x ", c); 484 else 485 fprintf(fp, "( %03d ", c); 486 c = key->map[i][1]; 487 if (isascii(c) && isprint(c)) 488 fprintf(fp, "'%c' ) ", c); 489 else if (hex) 490 fprintf(fp, "0x%02x) ", c); 491 else 492 fprintf(fp, "%03d ) ", c); 493 } 494 fprintf(fp, "\n"); 495 } 496 497 void 498 dump_entry(int value) 499 { 500 if (value & 0x100) { 501 value &= 0x00ff; 502 switch (value) { 503 case NOP: 504 printf(" NOP, "); 505 break; 506 case LSH: 507 printf(" LSH, "); 508 break; 509 case RSH: 510 printf(" RSH, "); 511 break; 512 case CLK: 513 printf(" CLK, "); 514 break; 515 case NLK: 516 printf(" NLK, "); 517 break; 518 case SLK: 519 printf(" SLK, "); 520 break; 521 case BTAB: 522 printf(" BTAB, "); 523 break; 524 case LALT: 525 printf(" LALT, "); 526 break; 527 case LCTR: 528 printf(" LCTR, "); 529 break; 530 case NEXT: 531 printf(" NEXT, "); 532 break; 533 case RCTR: 534 printf(" RCTR, "); 535 break; 536 case RALT: 537 printf(" RALT, "); 538 break; 539 case ALK: 540 printf(" ALK, "); 541 break; 542 case ASH: 543 printf(" ASH, "); 544 break; 545 case META: 546 printf(" META, "); 547 break; 548 case RBT: 549 printf(" RBT, "); 550 break; 551 case DBG: 552 printf(" DBG, "); 553 break; 554 case SUSP: 555 printf(" SUSP, "); 556 break; 557 case SPSC: 558 printf(" SPSC, "); 559 break; 560 default: 561 if (value >= F_FN && value <= L_FN) 562 printf(" F(%2d),", value - F_FN + 1); 563 else if (value >= F_SCR && value <= L_SCR) 564 printf(" S(%2d),", value - F_SCR + 1); 565 else if (value >= F_ACC && value <= L_ACC) 566 printf(" %-4s, ", acc_names_u[value - F_ACC]); 567 else 568 printf(" 0x%02X, ", value); 569 break; 570 } 571 } else if (value == '\'') { 572 printf(" '\\'', "); 573 } else if (value == '\\') { 574 printf(" '\\\\', "); 575 } else if (isascii(value) && isprint(value)) { 576 printf(" '%c', ", value); 577 } else { 578 printf(" 0x%02X, ", value); 579 } 580 } 581 582 void 583 dump_key_definition(char *name, keymap_t *keymap) 584 { 585 int i, j; 586 587 printf("static keymap_t keymap_%s = { 0x%02x, {\n", 588 name, (unsigned)keymap->n_keys); 589 printf( 590 "/* alt\n" 591 " * scan cntrl alt alt cntrl\n" 592 " * code base shift cntrl shift alt shift cntrl shift spcl flgs\n" 593 " * ---------------------------------------------------------------------------\n" 594 " */\n"); 595 for (i = 0; i < keymap->n_keys; i++) { 596 printf("/*%02x*/{{", i); 597 for (j = 0; j < NUM_STATES; j++) { 598 if (keymap->key[i].spcl & (0x80 >> j)) 599 dump_entry(keymap->key[i].map[j] | 0x100); 600 else 601 dump_entry(keymap->key[i].map[j]); 602 } 603 printf("}, 0x%02X,0x%02X },\n", 604 (unsigned)keymap->key[i].spcl, 605 (unsigned)keymap->key[i].flgs); 606 } 607 printf("} };\n\n"); 608 } 609 610 void 611 dump_accent_definition(char *name, accentmap_t *accentmap) 612 { 613 int i, j; 614 int c; 615 616 printf("static accentmap_t accentmap_%s = { %d", 617 name, accentmap->n_accs); 618 if (accentmap->n_accs <= 0) { 619 printf(" };\n\n"); 620 return; 621 } 622 printf(", {\n"); 623 for (i = 0; i < NUM_DEADKEYS; i++) { 624 printf(" /* %s=%d */\n {", acc_names[i], i); 625 c = accentmap->acc[i].accchar; 626 if (c == '\'') 627 printf(" '\\'', {"); 628 else if (c == '\\') 629 printf(" '\\\\', {"); 630 else if (isascii(c) && isprint(c)) 631 printf(" '%c', {", c); 632 else if (c == 0) { 633 printf(" 0x00 }, \n"); 634 continue; 635 } else 636 printf(" 0x%02x, {", c); 637 for (j = 0; j < NUM_ACCENTCHARS; j++) { 638 c = accentmap->acc[i].map[j][0]; 639 if (c == 0) 640 break; 641 if ((j > 0) && ((j % 4) == 0)) 642 printf("\n\t "); 643 if (isascii(c) && isprint(c)) 644 printf(" { '%c',", c); 645 else 646 printf(" { 0x%02x,", c); 647 printf("0x%02x },", accentmap->acc[i].map[j][1]); 648 } 649 printf(" }, },\n"); 650 } 651 printf("} };\n\n"); 652 } 653 654 void 655 load_keymap(char *opt, int dumponly) 656 { 657 keymap_t keymap; 658 accentmap_t accentmap; 659 FILE *fd; 660 int i; 661 char *name, *cp; 662 char *prefix[] = {"", "", KEYMAP_PATH, KEYMAP_PATH, NULL}; 663 char *postfix[] = {"", ".kbd", "", ".kbd"}; 664 665 for (i=0; prefix[i]; i++) { 666 name = mkfullname(prefix[i], opt, postfix[i]); 667 if ((fd = fopen(name, "r"))) 668 break; 669 } 670 if (fd == NULL) { 671 warn("keymap file not found"); 672 return; 673 } 674 memset(&keymap, 0, sizeof(keymap)); 675 memset(&accentmap, 0, sizeof(accentmap)); 676 token = -1; 677 while (1) { 678 if (get_definition_line(fd, &keymap, &accentmap) < 0) 679 break; 680 } 681 if (dumponly) { 682 /* fix up the filename to make it a valid C identifier */ 683 for (cp = opt; *cp; cp++) 684 if (!isalpha(*cp) && !isdigit(*cp)) *cp = '_'; 685 printf("/*\n" 686 " * Automatically generated from %s.\n" 687 " * DO NOT EDIT!\n" 688 " */\n", name); 689 dump_key_definition(opt, &keymap); 690 dump_accent_definition(opt, &accentmap); 691 return; 692 } 693 if ((keymap.n_keys > 0) && (ioctl(0, PIO_KEYMAP, &keymap) < 0)) { 694 warn("setting keymap"); 695 fclose(fd); 696 return; 697 } 698 if ((accentmap.n_accs > 0) 699 && (ioctl(0, PIO_DEADKEYMAP, &accentmap) < 0)) { 700 warn("setting accentmap"); 701 fclose(fd); 702 return; 703 } 704 } 705 706 void 707 print_keymap() 708 { 709 keymap_t keymap; 710 accentmap_t accentmap; 711 int i; 712 713 if (ioctl(0, GIO_KEYMAP, &keymap) < 0) 714 err(1, "getting keymap"); 715 if (ioctl(0, GIO_DEADKEYMAP, &accentmap) < 0) 716 memset(&accentmap, 0, sizeof(accentmap)); 717 printf( 718 "# alt\n" 719 "# scan cntrl alt alt cntrl lock\n" 720 "# code base shift cntrl shift alt shift cntrl shift state\n" 721 "# ------------------------------------------------------------------\n" 722 ); 723 for (i=0; i<keymap.n_keys; i++) 724 print_key_definition_line(stdout, i, &keymap.key[i]); 725 726 printf("\n"); 727 for (i = 0; i < NUM_DEADKEYS; i++) 728 print_accent_definition_line(stdout, i, &accentmap.acc[i]); 729 730 } 731 732 733 void 734 load_default_functionkeys() 735 { 736 fkeyarg_t fkey; 737 int i; 738 739 for (i=0; i<NUM_FKEYS; i++) { 740 fkey.keynum = i; 741 strcpy(fkey.keydef, fkey_table[i]); 742 fkey.flen = strlen(fkey_table[i]); 743 if (ioctl(0, SETFKEY, &fkey) < 0) 744 warn("setting function key"); 745 } 746 } 747 748 void 749 set_functionkey(char *keynumstr, char *string) 750 { 751 fkeyarg_t fkey; 752 753 if (!strcmp(keynumstr, "load") && !strcmp(string, "default")) { 754 load_default_functionkeys(); 755 return; 756 } 757 fkey.keynum = atoi(keynumstr); 758 if (fkey.keynum < 1 || fkey.keynum > NUM_FKEYS) { 759 warnx("function key number must be between 1 and %d", 760 NUM_FKEYS); 761 return; 762 } 763 if ((fkey.flen = strlen(string)) > MAXFK) { 764 warnx("function key string too long (%d > %d)", 765 fkey.flen, MAXFK); 766 return; 767 } 768 strcpy(fkey.keydef, string); 769 fkey.keynum -= 1; 770 if (ioctl(0, SETFKEY, &fkey) < 0) 771 warn("setting function key"); 772 } 773 774 775 void 776 set_bell_values(char *opt) 777 { 778 int bell, duration, pitch; 779 780 bell = 0; 781 if (!strncmp(opt, "quiet.", 6)) { 782 bell = 2; 783 opt += 6; 784 } 785 if (!strcmp(opt, "visual")) 786 bell |= 1; 787 else if (!strcmp(opt, "normal")) 788 duration = 5, pitch = 800; 789 else { 790 char *v1; 791 792 bell = 0; 793 duration = strtol(opt, &v1, 0); 794 if ((duration < 0) || (*v1 != '.')) 795 goto badopt; 796 opt = ++v1; 797 pitch = strtol(opt, &v1, 0); 798 if ((pitch < 0) || (*opt == '\0') || (*v1 != '\0')) { 799 badopt: 800 warnx("argument to -b must be DURATION.PITCH"); 801 return; 802 } 803 if (pitch != 0) 804 pitch = 1193182 / pitch; /* in Hz */ 805 duration /= 10; /* in 10 m sec */ 806 } 807 808 ioctl(0, CONS_BELLTYPE, &bell); 809 if ((bell & ~2) == 0) 810 fprintf(stderr, "[=%d;%dB", pitch, duration); 811 } 812 813 814 void 815 set_keyrates(char *opt) 816 { 817 int repeat; 818 int delay; 819 820 if (!strcmp(opt, "slow")) 821 delay = 3, repeat = 31; 822 else if (!strcmp(opt, "normal")) 823 delay = 1, repeat = 15; 824 else if (!strcmp(opt, "fast")) 825 delay = repeat = 0; 826 else { 827 int n; 828 char *v1; 829 830 delay = strtol(opt, &v1, 0); 831 if ((delay < 0) || (*v1 != '.')) 832 goto badopt; 833 opt = ++v1; 834 repeat = strtol(opt, &v1, 0); 835 if ((repeat < 0) || (*opt == '\0') || (*v1 != '\0')) { 836 badopt: 837 warnx("argument to -r must be delay.repeat"); 838 return; 839 } 840 for (n = 0; n < ndelays - 1; n++) 841 if (delay <= delays[n]) 842 break; 843 delay = n; 844 for (n = 0; n < nrepeats - 1; n++) 845 if (repeat <= repeats[n]) 846 break; 847 repeat = n; 848 } 849 850 if (ioctl(0, KDSETRAD, (delay << 5) | repeat) < 0) 851 warn("setting keyboard rate"); 852 } 853 854 855 void 856 set_history(char *opt) 857 { 858 int size; 859 860 size = atoi(opt); 861 if ((*opt == '\0') || size < 0) { 862 warnx("argument must be a positive number"); 863 return; 864 } 865 if (ioctl(0, CONS_HISTORY, &size) == -1) 866 warn("setting history buffer size"); 867 } 868 869 #ifdef __i386__ 870 static char 871 *get_kbd_type_name(int type) 872 { 873 static struct { 874 int type; 875 char *name; 876 } name_table[] = { 877 { KB_84, "AT 84" }, 878 { KB_101, "AT 101/102" }, 879 { KB_OTHER, "generic" }, 880 }; 881 int i; 882 883 for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) { 884 if (type == name_table[i].type) 885 return name_table[i].name; 886 } 887 return "unknown"; 888 } 889 890 void 891 show_kbd_info(void) 892 { 893 keyboard_info_t info; 894 895 if (ioctl(0, KDGKBINFO, &info) == -1) { 896 warn("unable to obtain keyboard information"); 897 return; 898 } 899 printf("kbd%d:\n", info.kb_index); 900 printf(" %.*s%d, type:%s (%d)\n", 901 sizeof(info.kb_name), info.kb_name, info.kb_unit, 902 get_kbd_type_name(info.kb_type), info.kb_type); 903 } 904 905 906 void 907 set_keyboard(char *device) 908 { 909 keyboard_info_t info; 910 int fd; 911 912 fd = open(device, O_RDONLY); 913 if (fd < 0) { 914 warn("cannot open %s", device); 915 return; 916 } 917 if (ioctl(fd, KDGKBINFO, &info) == -1) { 918 warn("unable to obtain keyboard information"); 919 close(fd); 920 return; 921 } 922 /* 923 * The keyboard device driver won't release the keyboard by 924 * the following ioctl, but it automatically will, when the device 925 * is closed. So, we don't check error here. 926 */ 927 ioctl(fd, CONS_RELKBD, 0); 928 close(fd); 929 #if 1 930 printf("kbd%d\n", info.kb_index); 931 printf(" %.*s%d, type:%s (%d)\n", 932 sizeof(info.kb_name), info.kb_name, info.kb_unit, 933 get_kbd_type_name(info.kb_type), info.kb_type); 934 #endif 935 936 if (ioctl(0, CONS_SETKBD, info.kb_index) == -1) 937 warn("unable to set keyboard"); 938 } 939 940 941 void 942 release_keyboard(void) 943 { 944 keyboard_info_t info; 945 946 /* 947 * If stdin is not associated with a keyboard, the following ioctl 948 * will fail. 949 */ 950 if (ioctl(0, KDGKBINFO, &info) == -1) { 951 warn("unable to obtain keyboard information"); 952 return; 953 } 954 #if 1 955 printf("kbd%d\n", info.kb_index); 956 printf(" %.*s%d, type:%s (%d)\n", 957 sizeof(info.kb_name), info.kb_name, info.kb_unit, 958 get_kbd_type_name(info.kb_type), info.kb_type); 959 #endif 960 if (ioctl(0, CONS_RELKBD, 0) == -1) 961 warn("unable to release the keyboard"); 962 } 963 #endif /* __i386__ */ 964 965 966 static void 967 usage() 968 { 969 fprintf(stderr, "%s\n%s\n%s\n", 970 #ifdef __i386__ 971 "usage: kbdcontrol [-dFKix] [-b duration.pitch | [quiet.]belltype]", 972 " [-r delay.repeat | speed] [-l mapfile] [-f # string]", 973 " [-h size] [-k device] [-L mapfile]"); 974 #else 975 "usage: kbdcontrol [-dFx] [-b duration.pitch | [quiet.]belltype]", 976 " [-r delay.repeat | speed] [-l mapfile] [-f # string]", 977 " [-h size] [-L mapfile]"); 978 #endif 979 exit(1); 980 } 981 982 983 void 984 main(int argc, char **argv) 985 { 986 int opt; 987 988 #ifdef __i386__ 989 while((opt = getopt(argc, argv, "b:df:h:iKk:Fl:L:r:x")) != -1) 990 #else 991 while((opt = getopt(argc, argv, "b:df:h:Fl:L:r:x")) != -1) 992 #endif 993 switch(opt) { 994 case 'b': 995 set_bell_values(optarg); 996 break; 997 case 'd': 998 print_keymap(); 999 break; 1000 case 'l': 1001 load_keymap(optarg, 0); 1002 break; 1003 case 'L': 1004 load_keymap(optarg, 1); 1005 break; 1006 case 'f': 1007 set_functionkey(optarg, 1008 nextarg(argc, argv, &optind, 'f')); 1009 break; 1010 case 'F': 1011 load_default_functionkeys(); 1012 break; 1013 case 'h': 1014 set_history(optarg); 1015 break; 1016 #ifdef __i386__ 1017 case 'i': 1018 show_kbd_info(); 1019 break; 1020 case 'K': 1021 release_keyboard(); 1022 break; 1023 case 'k': 1024 set_keyboard(optarg); 1025 break; 1026 #endif /* __i386__ */ 1027 case 'r': 1028 set_keyrates(optarg); 1029 break; 1030 case 'x': 1031 hex = 1; 1032 break; 1033 default: 1034 usage(); 1035 } 1036 if ((optind != argc) || (argc == 1)) 1037 usage(); 1038 exit(0); 1039 } 1040 1041 1042