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