1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 1994-1995 Søren Schmidt 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer, 12 * in this position and unchanged. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 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 <sys/kbio.h> 42 #include <sys/consio.h> 43 #include <sys/queue.h> 44 #include <sys/sysctl.h> 45 #include "path.h" 46 #include "lex.h" 47 48 /* 49 * HALT, PDWN, and PASTE aren't defined in 4.x, but we need them to bridge 50 * to 5.0-current so define them here as a stop gap transition measure. 51 */ 52 #ifndef HALT 53 #define HALT 0xa1 /* halt machine */ 54 #endif 55 #ifndef PDWN 56 #define PDWN 0xa2 /* halt machine and power down */ 57 #endif 58 #ifndef PASTE 59 #define PASTE 0xa3 /* paste from cut-paste buffer */ 60 #endif 61 62 #define SPECIAL 0x80000000 63 64 static const char ctrl_names[32][4] = { 65 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", 66 "bs ", "ht ", "nl ", "vt ", "ff ", "cr ", "so ", "si ", 67 "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", 68 "can", "em ", "sub", "esc", "fs ", "gs ", "rs ", "us " 69 }; 70 71 static const char acc_names[15][5] = { 72 "dgra", "dacu", "dcir", "dtil", "dmac", "dbre", "ddot", 73 "duml", "dsla", "drin", "dced", "dapo", "ddac", "dogo", 74 "dcar", 75 }; 76 77 static const char acc_names_u[15][5] = { 78 "DGRA", "DACU", "DCIR", "DTIL", "DMAC", "DBRE", "DDOT", 79 "DUML", "DSLA", "DRIN", "DCED", "DAPO", "DDAC", "DOGO", 80 "DCAR", 81 }; 82 83 static const char fkey_table[96][MAXFK] = { 84 /* 01-04 */ "\033[M", "\033[N", "\033[O", "\033[P", 85 /* 05-08 */ "\033[Q", "\033[R", "\033[S", "\033[T", 86 /* 09-12 */ "\033[U", "\033[V", "\033[W", "\033[X", 87 /* 13-16 */ "\033[Y", "\033[Z", "\033[a", "\033[b", 88 /* 17-20 */ "\033[c", "\033[d", "\033[e", "\033[f", 89 /* 21-24 */ "\033[g", "\033[h", "\033[i", "\033[j", 90 /* 25-28 */ "\033[k", "\033[l", "\033[m", "\033[n", 91 /* 29-32 */ "\033[o", "\033[p", "\033[q", "\033[r", 92 /* 33-36 */ "\033[s", "\033[t", "\033[u", "\033[v", 93 /* 37-40 */ "\033[w", "\033[x", "\033[y", "\033[z", 94 /* 41-44 */ "\033[@", "\033[[", "\033[\\","\033[]", 95 /* 45-48 */ "\033[^", "\033[_", "\033[`", "\033[{", 96 /* 49-52 */ "\033[H", "\033[A", "\033[I", "-" , 97 /* 53-56 */ "\033[D", "\033[E", "\033[C", "+" , 98 /* 57-60 */ "\033[F", "\033[B", "\033[G", "\033[L", 99 /* 61-64 */ "\177", "\033[J", "\033[~", "\033[}", 100 /* 65-68 */ "" , "" , "" , "" , 101 /* 69-72 */ "" , "" , "" , "" , 102 /* 73-76 */ "" , "" , "" , "" , 103 /* 77-80 */ "" , "" , "" , "" , 104 /* 81-84 */ "" , "" , "" , "" , 105 /* 85-88 */ "" , "" , "" , "" , 106 /* 89-92 */ "" , "" , "" , "" , 107 /* 93-96 */ "" , "" , "" , "" , 108 }; 109 110 static const int delays[] = {250, 500, 750, 1000}; 111 static const int repeats[] = { 34, 38, 42, 46, 50, 55, 59, 63, 112 68, 76, 84, 92, 100, 110, 118, 126, 113 136, 152, 168, 184, 200, 220, 236, 252, 114 272, 304, 336, 368, 400, 440, 472, 504}; 115 static const int ndelays = (sizeof(delays) / sizeof(int)); 116 static const int nrepeats = (sizeof(repeats) / sizeof(int)); 117 static int hex = 0; 118 static int paths_configured = 0; 119 static int token; 120 121 int number; 122 char letter; 123 124 static void add_keymap_path(const char *path); 125 static void dump_accent_definition(char *name, accentmap_t *accentmap); 126 static void dump_entry(int value); 127 static void dump_key_definition(char *name, keymap_t *keymap); 128 static int get_accent_definition_line(accentmap_t *); 129 static int get_entry(void); 130 static int get_key_definition_line(keymap_t *); 131 static void load_keymap(char *opt, int dumponly); 132 static void load_default_functionkeys(void); 133 static char * nextarg(int ac, char **av, int *indp, int oc); 134 static char * mkfullname(const char *s1, const char *s2, const char *s3); 135 static void print_accent_definition_line(FILE *fp, int accent, 136 struct acc_t *key); 137 static void print_entry(FILE *fp, int value); 138 static void print_key_definition_line(FILE *fp, int scancode, 139 struct keyent_t *key); 140 static void print_keymap(void); 141 static void release_keyboard(void); 142 static void mux_keyboard(u_int op, char *kbd); 143 static void set_bell_values(char *opt); 144 static void set_functionkey(char *keynumstr, char *string); 145 static void set_keyboard(char *device); 146 static void set_keyrates(char *opt); 147 static void show_kbd_info(void); 148 static void usage(void) __dead2; 149 150 struct pathent { 151 STAILQ_ENTRY(pathent) next; 152 char *path; 153 }; 154 static STAILQ_HEAD(, pathent) pathlist = STAILQ_HEAD_INITIALIZER(pathlist); 155 156 /* Detect presence of vt(4). */ 157 static int 158 is_vt4(void) 159 { 160 char vty_name[4] = ""; 161 size_t len = sizeof(vty_name); 162 163 if (sysctlbyname("kern.vty", vty_name, &len, NULL, 0) != 0) 164 return (0); 165 return (strcmp(vty_name, "vt") == 0); 166 } 167 168 static char * 169 nextarg(int ac, char **av, int *indp, int oc) 170 { 171 if (*indp < ac) 172 return(av[(*indp)++]); 173 warnx("option requires two arguments -- %c", oc); 174 usage(); 175 } 176 177 178 static char * 179 mkfullname(const char *s1, const char *s2, const char *s3) 180 { 181 static char *buf = NULL; 182 static int bufl = 0; 183 int f; 184 185 f = strlen(s1) + strlen(s2) + strlen(s3) + 1; 186 if (f > bufl) { 187 if (buf) 188 buf = (char *)realloc(buf, f); 189 else 190 buf = (char *)malloc(f); 191 } 192 if (!buf) { 193 bufl = 0; 194 return(NULL); 195 } 196 197 bufl = f; 198 strcpy(buf, s1); 199 strcat(buf, s2); 200 strcat(buf, s3); 201 return(buf); 202 } 203 204 205 static int 206 get_entry(void) 207 { 208 switch ((token = yylex())) { 209 case TNOP: 210 return NOP | SPECIAL; 211 case TLSH: 212 return LSH | SPECIAL; 213 case TRSH: 214 return RSH | SPECIAL; 215 case TCLK: 216 return CLK | SPECIAL; 217 case TNLK: 218 return NLK | SPECIAL; 219 case TSLK: 220 return SLK | SPECIAL; 221 case TBTAB: 222 return BTAB | SPECIAL; 223 case TLALT: 224 return LALT | SPECIAL; 225 case TLCTR: 226 return LCTR | SPECIAL; 227 case TNEXT: 228 return NEXT | SPECIAL; 229 case TPREV: 230 return PREV | SPECIAL; 231 case TRCTR: 232 return RCTR | SPECIAL; 233 case TRALT: 234 return RALT | SPECIAL; 235 case TALK: 236 return ALK | SPECIAL; 237 case TASH: 238 return ASH | SPECIAL; 239 case TMETA: 240 return META | SPECIAL; 241 case TRBT: 242 return RBT | SPECIAL; 243 case TDBG: 244 return DBG | SPECIAL; 245 case TSUSP: 246 return SUSP | SPECIAL; 247 case TSPSC: 248 return SPSC | SPECIAL; 249 case TPANIC: 250 return PNC | SPECIAL; 251 case TLSHA: 252 return LSHA | SPECIAL; 253 case TRSHA: 254 return RSHA | SPECIAL; 255 case TLCTRA: 256 return LCTRA | SPECIAL; 257 case TRCTRA: 258 return RCTRA | SPECIAL; 259 case TLALTA: 260 return LALTA | SPECIAL; 261 case TRALTA: 262 return RALTA | SPECIAL; 263 case THALT: 264 return HALT | SPECIAL; 265 case TPDWN: 266 return PDWN | SPECIAL; 267 case TPASTE: 268 return PASTE | SPECIAL; 269 case TACC: 270 if (ACC(number) > L_ACC) 271 return -1; 272 return ACC(number) | SPECIAL; 273 case TFUNC: 274 if (F(number) > L_FN) 275 return -1; 276 return F(number) | SPECIAL; 277 case TSCRN: 278 if (S(number) > L_SCR) 279 return -1; 280 return S(number) | SPECIAL; 281 case TLET: 282 return (unsigned char)letter; 283 case TNUM: 284 if (number < 0x000000 || number > 0x10FFFF) 285 return -1; 286 return number; 287 default: 288 return -1; 289 } 290 } 291 292 static int 293 get_definition_line(FILE *file, keymap_t *keymap, accentmap_t *accentmap) 294 { 295 int c; 296 297 yyin = file; 298 299 if (token < 0) 300 token = yylex(); 301 switch (token) { 302 case TNUM: 303 c = get_key_definition_line(keymap); 304 if (c < 0) 305 errx(1, "invalid key definition"); 306 if (c > keymap->n_keys) 307 keymap->n_keys = c; 308 break; 309 case TACC: 310 c = get_accent_definition_line(accentmap); 311 if (c < 0) 312 errx(1, "invalid accent key definition"); 313 if (c > accentmap->n_accs) 314 accentmap->n_accs = c; 315 break; 316 case 0: 317 /* EOF */ 318 return -1; 319 default: 320 errx(1, "illegal definition line"); 321 } 322 return c; 323 } 324 325 static int 326 get_key_definition_line(keymap_t *map) 327 { 328 int i, def, scancode; 329 330 /* check scancode number */ 331 if (number < 0 || number >= NUM_KEYS) 332 return -1; 333 scancode = number; 334 335 /* get key definitions */ 336 map->key[scancode].spcl = 0; 337 for (i=0; i<NUM_STATES; i++) { 338 if ((def = get_entry()) == -1) 339 return -1; 340 if (def & SPECIAL) 341 map->key[scancode].spcl |= (0x80 >> i); 342 map->key[scancode].map[i] = def & ~SPECIAL; 343 } 344 /* get lock state key def */ 345 if ((token = yylex()) != TFLAG) 346 return -1; 347 map->key[scancode].flgs = number; 348 token = yylex(); 349 return (scancode + 1); 350 } 351 352 static int 353 get_accent_definition_line(accentmap_t *map) 354 { 355 int accent; 356 int c1, c2; 357 int i; 358 359 if (ACC(number) < F_ACC || ACC(number) > L_ACC) 360 /* number out of range */ 361 return -1; 362 accent = number; 363 if (map->acc[accent].accchar != 0) { 364 /* this entry has already been defined before! */ 365 errx(1, "duplicated accent key definition"); 366 } 367 368 switch ((token = yylex())) { 369 case TLET: 370 map->acc[accent].accchar = letter; 371 break; 372 case TNUM: 373 map->acc[accent].accchar = number; 374 break; 375 default: 376 return -1; 377 } 378 379 for (i = 0; (token = yylex()) == '(';) { 380 switch ((token = yylex())) { 381 case TLET: 382 c1 = letter; 383 break; 384 case TNUM: 385 c1 = number; 386 break; 387 default: 388 return -1; 389 } 390 switch ((token = yylex())) { 391 case TLET: 392 c2 = letter; 393 break; 394 case TNUM: 395 c2 = number; 396 break; 397 default: 398 return -1; 399 } 400 if ((token = yylex()) != ')') 401 return -1; 402 if (i >= NUM_ACCENTCHARS) { 403 warnx("too many accented characters, ignored"); 404 continue; 405 } 406 map->acc[accent].map[i][0] = c1; 407 map->acc[accent].map[i][1] = c2; 408 ++i; 409 } 410 return (accent + 1); 411 } 412 413 static void 414 print_entry(FILE *fp, int value) 415 { 416 int val = value & ~SPECIAL; 417 418 switch (value) { 419 case NOP | SPECIAL: 420 fprintf(fp, " nop "); 421 break; 422 case LSH | SPECIAL: 423 fprintf(fp, " lshift"); 424 break; 425 case RSH | SPECIAL: 426 fprintf(fp, " rshift"); 427 break; 428 case CLK | SPECIAL: 429 fprintf(fp, " clock "); 430 break; 431 case NLK | SPECIAL: 432 fprintf(fp, " nlock "); 433 break; 434 case SLK | SPECIAL: 435 fprintf(fp, " slock "); 436 break; 437 case BTAB | SPECIAL: 438 fprintf(fp, " btab "); 439 break; 440 case LALT | SPECIAL: 441 fprintf(fp, " lalt "); 442 break; 443 case LCTR | SPECIAL: 444 fprintf(fp, " lctrl "); 445 break; 446 case NEXT | SPECIAL: 447 fprintf(fp, " nscr "); 448 break; 449 case PREV | SPECIAL: 450 fprintf(fp, " pscr "); 451 break; 452 case RCTR | SPECIAL: 453 fprintf(fp, " rctrl "); 454 break; 455 case RALT | SPECIAL: 456 fprintf(fp, " ralt "); 457 break; 458 case ALK | SPECIAL: 459 fprintf(fp, " alock "); 460 break; 461 case ASH | SPECIAL: 462 fprintf(fp, " ashift"); 463 break; 464 case META | SPECIAL: 465 fprintf(fp, " meta "); 466 break; 467 case RBT | SPECIAL: 468 fprintf(fp, " boot "); 469 break; 470 case DBG | SPECIAL: 471 fprintf(fp, " debug "); 472 break; 473 case SUSP | SPECIAL: 474 fprintf(fp, " susp "); 475 break; 476 case SPSC | SPECIAL: 477 fprintf(fp, " saver "); 478 break; 479 case PNC | SPECIAL: 480 fprintf(fp, " panic "); 481 break; 482 case LSHA | SPECIAL: 483 fprintf(fp, " lshifta"); 484 break; 485 case RSHA | SPECIAL: 486 fprintf(fp, " rshifta"); 487 break; 488 case LCTRA | SPECIAL: 489 fprintf(fp, " lctrla"); 490 break; 491 case RCTRA | SPECIAL: 492 fprintf(fp, " rctrla"); 493 break; 494 case LALTA | SPECIAL: 495 fprintf(fp, " lalta "); 496 break; 497 case RALTA | SPECIAL: 498 fprintf(fp, " ralta "); 499 break; 500 case HALT | SPECIAL: 501 fprintf(fp, " halt "); 502 break; 503 case PDWN | SPECIAL: 504 fprintf(fp, " pdwn "); 505 break; 506 case PASTE | SPECIAL: 507 fprintf(fp, " paste "); 508 break; 509 default: 510 if (value & SPECIAL) { 511 if (val >= F_FN && val <= L_FN) 512 fprintf(fp, " fkey%02d", val - F_FN + 1); 513 else if (val >= F_SCR && val <= L_SCR) 514 fprintf(fp, " scr%02d ", val - F_SCR + 1); 515 else if (val >= F_ACC && val <= L_ACC) 516 fprintf(fp, " %-6s", acc_names[val - F_ACC]); 517 else if (hex) 518 fprintf(fp, " 0x%02x ", val); 519 else 520 fprintf(fp, " %3d ", val); 521 } 522 else { 523 if (val < ' ') 524 fprintf(fp, " %s ", ctrl_names[val]); 525 else if (val == 127) 526 fprintf(fp, " del "); 527 else if (isascii(val) && isprint(val)) 528 fprintf(fp, " '%c' ", val); 529 else if (hex) 530 fprintf(fp, " 0x%02x ", val); 531 else 532 fprintf(fp, " %3d ", val); 533 } 534 } 535 } 536 537 static void 538 print_key_definition_line(FILE *fp, int scancode, struct keyent_t *key) 539 { 540 int i; 541 542 /* print scancode number */ 543 if (hex) 544 fprintf(fp, " 0x%02x ", scancode); 545 else 546 fprintf(fp, " %03d ", scancode); 547 548 /* print key definitions */ 549 for (i=0; i<NUM_STATES; i++) { 550 if (key->spcl & (0x80 >> i)) 551 print_entry(fp, key->map[i] | SPECIAL); 552 else 553 print_entry(fp, key->map[i]); 554 } 555 556 /* print lock state key def */ 557 switch (key->flgs) { 558 case 0: 559 fprintf(fp, " O\n"); 560 break; 561 case 1: 562 fprintf(fp, " C\n"); 563 break; 564 case 2: 565 fprintf(fp, " N\n"); 566 break; 567 case 3: 568 fprintf(fp, " B\n"); 569 break; 570 } 571 } 572 573 static void 574 print_accent_definition_line(FILE *fp, int accent, struct acc_t *key) 575 { 576 int c; 577 int i; 578 579 if (key->accchar == 0) 580 return; 581 582 /* print accent number */ 583 fprintf(fp, " %-6s", acc_names[accent]); 584 if (isascii(key->accchar) && isprint(key->accchar)) 585 fprintf(fp, "'%c' ", key->accchar); 586 else if (hex) 587 fprintf(fp, "0x%02x ", key->accchar); 588 else 589 fprintf(fp, "%03d ", key->accchar); 590 591 for (i = 0; i < NUM_ACCENTCHARS; ++i) { 592 c = key->map[i][0]; 593 if (c == 0) 594 break; 595 if ((i > 0) && ((i % 4) == 0)) 596 fprintf(fp, "\n "); 597 if (isascii(c) && isprint(c)) 598 fprintf(fp, "( '%c' ", c); 599 else if (hex) 600 fprintf(fp, "(0x%02x ", c); 601 else 602 fprintf(fp, "( %03d ", c); 603 c = key->map[i][1]; 604 if (isascii(c) && isprint(c)) 605 fprintf(fp, "'%c' ) ", c); 606 else if (hex) 607 fprintf(fp, "0x%02x) ", c); 608 else 609 fprintf(fp, "%03d ) ", c); 610 } 611 fprintf(fp, "\n"); 612 } 613 614 static void 615 dump_entry(int value) 616 { 617 if (value & SPECIAL) { 618 value &= ~SPECIAL; 619 switch (value) { 620 case NOP: 621 printf(" NOP, "); 622 break; 623 case LSH: 624 printf(" LSH, "); 625 break; 626 case RSH: 627 printf(" RSH, "); 628 break; 629 case CLK: 630 printf(" CLK, "); 631 break; 632 case NLK: 633 printf(" NLK, "); 634 break; 635 case SLK: 636 printf(" SLK, "); 637 break; 638 case BTAB: 639 printf(" BTAB, "); 640 break; 641 case LALT: 642 printf(" LALT, "); 643 break; 644 case LCTR: 645 printf(" LCTR, "); 646 break; 647 case NEXT: 648 printf(" NEXT, "); 649 break; 650 case PREV: 651 printf(" PREV, "); 652 break; 653 case RCTR: 654 printf(" RCTR, "); 655 break; 656 case RALT: 657 printf(" RALT, "); 658 break; 659 case ALK: 660 printf(" ALK, "); 661 break; 662 case ASH: 663 printf(" ASH, "); 664 break; 665 case META: 666 printf(" META, "); 667 break; 668 case RBT: 669 printf(" RBT, "); 670 break; 671 case DBG: 672 printf(" DBG, "); 673 break; 674 case SUSP: 675 printf(" SUSP, "); 676 break; 677 case SPSC: 678 printf(" SPSC, "); 679 break; 680 case PNC: 681 printf(" PNC, "); 682 break; 683 case LSHA: 684 printf(" LSHA, "); 685 break; 686 case RSHA: 687 printf(" RSHA, "); 688 break; 689 case LCTRA: 690 printf("LCTRA, "); 691 break; 692 case RCTRA: 693 printf("RCTRA, "); 694 break; 695 case LALTA: 696 printf("LALTA, "); 697 break; 698 case RALTA: 699 printf("RALTA, "); 700 break; 701 case HALT: 702 printf(" HALT, "); 703 break; 704 case PDWN: 705 printf(" PDWN, "); 706 break; 707 case PASTE: 708 printf("PASTE, "); 709 break; 710 default: 711 if (value >= F_FN && value <= L_FN) 712 printf(" F(%2d),", value - F_FN + 1); 713 else if (value >= F_SCR && value <= L_SCR) 714 printf(" S(%2d),", value - F_SCR + 1); 715 else if (value >= F_ACC && value <= L_ACC) 716 printf(" %-4s, ", acc_names_u[value - F_ACC]); 717 else 718 printf(" 0x%02X, ", value); 719 break; 720 } 721 } else if (value == '\'') { 722 printf(" '\\'', "); 723 } else if (value == '\\') { 724 printf(" '\\\\', "); 725 } else if (isascii(value) && isprint(value)) { 726 printf(" '%c', ", value); 727 } else { 728 printf(" 0x%02X, ", value); 729 } 730 } 731 732 static void 733 dump_key_definition(char *name, keymap_t *keymap) 734 { 735 int i, j; 736 737 printf("static keymap_t keymap_%s = { 0x%02x, {\n", 738 name, (unsigned)keymap->n_keys); 739 printf( 740 "/* alt\n" 741 " * scan cntrl alt alt cntrl\n" 742 " * code base shift cntrl shift alt shift cntrl shift spcl flgs\n" 743 " * ---------------------------------------------------------------------------\n" 744 " */\n"); 745 for (i = 0; i < keymap->n_keys; i++) { 746 printf("/*%02x*/{{", i); 747 for (j = 0; j < NUM_STATES; j++) { 748 if (keymap->key[i].spcl & (0x80 >> j)) 749 dump_entry(keymap->key[i].map[j] | SPECIAL); 750 else 751 dump_entry(keymap->key[i].map[j]); 752 } 753 printf("}, 0x%02X,0x%02X },\n", 754 (unsigned)keymap->key[i].spcl, 755 (unsigned)keymap->key[i].flgs); 756 } 757 printf("} };\n\n"); 758 } 759 760 static void 761 dump_accent_definition(char *name, accentmap_t *accentmap) 762 { 763 int i, j; 764 int c; 765 766 printf("static accentmap_t accentmap_%s = { %d", 767 name, accentmap->n_accs); 768 if (accentmap->n_accs <= 0) { 769 printf(" };\n\n"); 770 return; 771 } 772 printf(", {\n"); 773 for (i = 0; i < NUM_DEADKEYS; i++) { 774 printf(" /* %s=%d */\n {", acc_names[i], i); 775 c = accentmap->acc[i].accchar; 776 if (c == '\'') 777 printf(" '\\'', {"); 778 else if (c == '\\') 779 printf(" '\\\\', {"); 780 else if (isascii(c) && isprint(c)) 781 printf(" '%c', {", c); 782 else if (c == 0) { 783 printf(" 0x00 }, \n"); 784 continue; 785 } else 786 printf(" 0x%02x, {", c); 787 for (j = 0; j < NUM_ACCENTCHARS; j++) { 788 c = accentmap->acc[i].map[j][0]; 789 if (c == 0) 790 break; 791 if ((j > 0) && ((j % 4) == 0)) 792 printf("\n\t "); 793 if (isascii(c) && isprint(c)) 794 printf(" { '%c',", c); 795 else 796 printf(" { 0x%02x,", c); 797 printf("0x%02x },", accentmap->acc[i].map[j][1]); 798 } 799 printf(" }, },\n"); 800 } 801 printf("} };\n\n"); 802 } 803 804 static void 805 add_keymap_path(const char *path) 806 { 807 struct pathent* pe; 808 size_t len; 809 810 len = strlen(path); 811 if ((pe = malloc(sizeof(*pe))) == NULL || 812 (pe->path = malloc(len + 2)) == NULL) 813 err(1, "malloc"); 814 memcpy(pe->path, path, len); 815 if (len > 0 && path[len - 1] != '/') 816 pe->path[len++] = '/'; 817 pe->path[len] = '\0'; 818 STAILQ_INSERT_TAIL(&pathlist, pe, next); 819 } 820 821 #ifdef OPIO_DEADKEYMAP 822 static void 823 to_old_accentmap(accentmap_t *from, oaccentmap_t *to) 824 { 825 int i, j; 826 827 to->n_accs = from->n_accs; 828 for (i = 0; i < NUM_DEADKEYS; i++) { 829 for (j = 0; j < NUM_ACCENTCHARS; j++) { 830 to->acc[i].map[j][0] = from->acc[i].map[j][0]; 831 to->acc[i].map[j][1] = from->acc[i].map[j][1]; 832 to->acc[i].accchar = from->acc[i].accchar; 833 } 834 } 835 } 836 #endif /* OPIO_DEADKEYMAP */ 837 838 static void 839 load_keymap(char *opt, int dumponly) 840 { 841 keymap_t keymap; 842 accentmap_t accentmap; 843 #ifdef OPIO_DEADKEYMAP 844 oaccentmap_t oaccentmap; 845 #endif /* OPIO_DEADKEYMAP */ 846 struct pathent *pe; 847 FILE *file; 848 int j; 849 char *name, *cp; 850 char blank[] = "", keymap_path[] = KEYMAP_PATH; 851 char vt_keymap_path[] = VT_KEYMAP_PATH, dotkbd[] = ".kbd"; 852 char *postfix[] = {blank, dotkbd, NULL}; 853 854 if (!paths_configured) { 855 cp = getenv("KEYMAP_PATH"); 856 if (cp != NULL) 857 add_keymap_path(cp); 858 add_keymap_path(""); 859 if (is_vt4()) 860 add_keymap_path(vt_keymap_path); 861 else 862 add_keymap_path(keymap_path); 863 paths_configured = 1; 864 } 865 866 file = NULL; 867 STAILQ_FOREACH(pe, &pathlist, next) { 868 for (j=0; postfix[j] && file == NULL; j++) { 869 name = mkfullname(pe->path, opt, postfix[j]); 870 file = fopen(name, "r"); 871 if (file != NULL) 872 break; 873 } 874 } 875 if (file == NULL) { 876 warn("keymap file \"%s\" not found", opt); 877 return; 878 } 879 memset(&keymap, 0, sizeof(keymap)); 880 memset(&accentmap, 0, sizeof(accentmap)); 881 token = -1; 882 while (1) { 883 if (get_definition_line(file, &keymap, &accentmap) < 0) 884 break; 885 } 886 if (dumponly) { 887 /* fix up the filename to make it a valid C identifier */ 888 for (cp = opt; *cp; cp++) 889 if (!isalpha(*cp) && !isdigit(*cp)) *cp = '_'; 890 printf("/*\n" 891 " * Automatically generated from %s.\n" 892 " * DO NOT EDIT!\n" 893 " */\n", name); 894 dump_key_definition(opt, &keymap); 895 dump_accent_definition(opt, &accentmap); 896 return; 897 } 898 if ((keymap.n_keys > 0) && (ioctl(0, PIO_KEYMAP, &keymap) < 0)) { 899 warn("setting keymap"); 900 fclose(file); 901 return; 902 } 903 if ((accentmap.n_accs > 0) 904 && (ioctl(0, PIO_DEADKEYMAP, &accentmap) < 0)) { 905 #ifdef OPIO_DEADKEYMAP 906 to_old_accentmap(&accentmap, &oaccentmap); 907 if (ioctl(0, OPIO_DEADKEYMAP, &oaccentmap) < 0) 908 #endif /* OGIO_DEADKEYMAP */ 909 { 910 warn("setting accentmap"); 911 fclose(file); 912 return; 913 } 914 } 915 } 916 917 #ifdef OPIO_DEADKEYMAP 918 static void 919 to_new_accentmap(oaccentmap_t *from, accentmap_t *to) 920 { 921 int i, j; 922 923 to->n_accs = from->n_accs; 924 for (i = 0; i < NUM_DEADKEYS; i++) { 925 for (j = 0; j < NUM_ACCENTCHARS; j++) { 926 to->acc[i].map[j][0] = from->acc[i].map[j][0]; 927 to->acc[i].map[j][1] = from->acc[i].map[j][1]; 928 to->acc[i].accchar = from->acc[i].accchar; 929 } 930 } 931 } 932 #endif /* OPIO_DEADKEYMAP */ 933 934 static void 935 print_keymap(void) 936 { 937 keymap_t keymap; 938 accentmap_t accentmap; 939 #ifdef OGIO_DEADKEYMAP 940 oaccentmap_t oaccentmap; 941 #endif /* OPIO_DEADKEYMAP */ 942 int i; 943 944 if (ioctl(0, GIO_KEYMAP, &keymap) < 0) 945 err(1, "getting keymap"); 946 if (ioctl(0, GIO_DEADKEYMAP, &accentmap) < 0) { 947 #ifdef OGIO_DEADKEYMAP 948 if (ioctl(0, OGIO_DEADKEYMAP, &oaccentmap) == 0) 949 to_new_accentmap(&oaccentmap, &accentmap); 950 else 951 #endif /* OGIO_DEADKEYMAP */ 952 memset(&accentmap, 0, sizeof(accentmap)); 953 } 954 printf( 955 "# alt\n" 956 "# scan cntrl alt alt cntrl lock\n" 957 "# code base shift cntrl shift alt shift cntrl shift state\n" 958 "# ------------------------------------------------------------------\n" 959 ); 960 for (i=0; i<keymap.n_keys; i++) 961 print_key_definition_line(stdout, i, &keymap.key[i]); 962 963 printf("\n"); 964 for (i = 0; i < NUM_DEADKEYS; i++) 965 print_accent_definition_line(stdout, i, &accentmap.acc[i]); 966 967 } 968 969 static void 970 load_default_functionkeys(void) 971 { 972 fkeyarg_t fkey; 973 int i; 974 975 for (i=0; i<NUM_FKEYS; i++) { 976 fkey.keynum = i; 977 strcpy(fkey.keydef, fkey_table[i]); 978 fkey.flen = strlen(fkey_table[i]); 979 if (ioctl(0, SETFKEY, &fkey) < 0) 980 warn("setting function key"); 981 } 982 } 983 984 static void 985 set_functionkey(char *keynumstr, char *string) 986 { 987 fkeyarg_t fkey; 988 989 if (!strcmp(keynumstr, "load") && !strcmp(string, "default")) { 990 load_default_functionkeys(); 991 return; 992 } 993 fkey.keynum = atoi(keynumstr); 994 if (fkey.keynum < 1 || fkey.keynum > NUM_FKEYS) { 995 warnx("function key number must be between 1 and %d", 996 NUM_FKEYS); 997 return; 998 } 999 if ((fkey.flen = strlen(string)) > MAXFK) { 1000 warnx("function key string too long (%d > %d)", 1001 fkey.flen, MAXFK); 1002 return; 1003 } 1004 strncpy(fkey.keydef, string, MAXFK); 1005 fkey.keynum -= 1; 1006 if (ioctl(0, SETFKEY, &fkey) < 0) 1007 warn("setting function key"); 1008 } 1009 1010 static void 1011 set_bell_values(char *opt) 1012 { 1013 int bell, duration, pitch; 1014 1015 bell = 0; 1016 duration = 0; 1017 pitch = 0; 1018 if (!strncmp(opt, "quiet.", 6)) { 1019 bell = CONS_QUIET_BELL; 1020 opt += 6; 1021 } 1022 if (!strcmp(opt, "visual")) 1023 bell |= CONS_VISUAL_BELL; 1024 else if (!strcmp(opt, "normal")) 1025 duration = 5, pitch = 800; 1026 else if (!strcmp(opt, "off")) 1027 duration = 0, pitch = 0; 1028 else { 1029 char *v1; 1030 1031 bell = 0; 1032 duration = strtol(opt, &v1, 0); 1033 if ((duration < 0) || (*v1 != '.')) 1034 goto badopt; 1035 opt = ++v1; 1036 pitch = strtol(opt, &v1, 0); 1037 if ((pitch < 0) || (*opt == '\0') || (*v1 != '\0')) { 1038 badopt: 1039 warnx("argument to -b must be duration.pitch or [quiet.]visual|normal|off"); 1040 return; 1041 } 1042 if (pitch != 0) 1043 pitch = 1193182 / pitch; /* in Hz */ 1044 duration /= 10; /* in 10 m sec */ 1045 } 1046 1047 ioctl(0, CONS_BELLTYPE, &bell); 1048 if (duration > 0 && pitch > 0) 1049 fprintf(stderr, "\e[=%d;%dB", pitch, duration); 1050 } 1051 1052 static void 1053 set_keyrates(char *opt) 1054 { 1055 int arg[2]; 1056 int repeat; 1057 int delay; 1058 int r, d; 1059 1060 if (!strcmp(opt, "slow")) { 1061 delay = 1000, repeat = 500; 1062 d = 3, r = 31; 1063 } else if (!strcmp(opt, "normal")) { 1064 delay = 500, repeat = 125; 1065 d = 1, r = 15; 1066 } else if (!strcmp(opt, "fast")) { 1067 delay = repeat = 0; 1068 d = r = 0; 1069 } else { 1070 int n; 1071 char *v1; 1072 1073 delay = strtol(opt, &v1, 0); 1074 if ((delay < 0) || (*v1 != '.')) 1075 goto badopt; 1076 opt = ++v1; 1077 repeat = strtol(opt, &v1, 0); 1078 if ((repeat < 0) || (*opt == '\0') || (*v1 != '\0')) { 1079 badopt: 1080 warnx("argument to -r must be delay.repeat or slow|normal|fast"); 1081 return; 1082 } 1083 for (n = 0; n < ndelays - 1; n++) 1084 if (delay <= delays[n]) 1085 break; 1086 d = n; 1087 for (n = 0; n < nrepeats - 1; n++) 1088 if (repeat <= repeats[n]) 1089 break; 1090 r = n; 1091 } 1092 1093 arg[0] = delay; 1094 arg[1] = repeat; 1095 if (ioctl(0, KDSETREPEAT, arg)) { 1096 if (ioctl(0, KDSETRAD, (d << 5) | r)) 1097 warn("setting keyboard rate"); 1098 } 1099 } 1100 1101 static const char * 1102 get_kbd_type_name(int type) 1103 { 1104 static struct { 1105 int type; 1106 const char *name; 1107 } name_table[] = { 1108 { KB_84, "AT 84" }, 1109 { KB_101, "AT 101/102" }, 1110 { KB_OTHER, "generic" }, 1111 }; 1112 unsigned int i; 1113 1114 for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) { 1115 if (type == name_table[i].type) 1116 return name_table[i].name; 1117 } 1118 return "unknown"; 1119 } 1120 1121 static void 1122 show_kbd_info(void) 1123 { 1124 keyboard_info_t info; 1125 1126 if (ioctl(0, KDGKBINFO, &info) == -1) { 1127 warn("unable to obtain keyboard information"); 1128 return; 1129 } 1130 printf("kbd%d:\n", info.kb_index); 1131 printf(" %.*s%d, type:%s (%d)\n", 1132 (int)sizeof(info.kb_name), info.kb_name, info.kb_unit, 1133 get_kbd_type_name(info.kb_type), info.kb_type); 1134 } 1135 1136 static void 1137 set_keyboard(char *device) 1138 { 1139 keyboard_info_t info; 1140 int fd; 1141 1142 fd = open(device, O_RDONLY); 1143 if (fd < 0) { 1144 warn("cannot open %s", device); 1145 return; 1146 } 1147 if (ioctl(fd, KDGKBINFO, &info) == -1) { 1148 warn("unable to obtain keyboard information"); 1149 close(fd); 1150 return; 1151 } 1152 /* 1153 * The keyboard device driver won't release the keyboard by 1154 * the following ioctl, but it automatically will, when the device 1155 * is closed. So, we don't check error here. 1156 */ 1157 ioctl(fd, CONS_RELKBD, 0); 1158 close(fd); 1159 #if 1 1160 printf("kbd%d\n", info.kb_index); 1161 printf(" %.*s%d, type:%s (%d)\n", 1162 (int)sizeof(info.kb_name), info.kb_name, info.kb_unit, 1163 get_kbd_type_name(info.kb_type), info.kb_type); 1164 #endif 1165 1166 if (ioctl(0, CONS_SETKBD, info.kb_index) == -1) 1167 warn("unable to set keyboard"); 1168 } 1169 1170 static void 1171 release_keyboard(void) 1172 { 1173 keyboard_info_t info; 1174 1175 /* 1176 * If stdin is not associated with a keyboard, the following ioctl 1177 * will fail. 1178 */ 1179 if (ioctl(0, KDGKBINFO, &info) == -1) { 1180 warn("unable to obtain keyboard information"); 1181 return; 1182 } 1183 #if 1 1184 printf("kbd%d\n", info.kb_index); 1185 printf(" %.*s%d, type:%s (%d)\n", 1186 (int)sizeof(info.kb_name), info.kb_name, info.kb_unit, 1187 get_kbd_type_name(info.kb_type), info.kb_type); 1188 #endif 1189 if (ioctl(0, CONS_RELKBD, 0) == -1) 1190 warn("unable to release the keyboard"); 1191 } 1192 1193 static void 1194 mux_keyboard(u_int op, char *kbd) 1195 { 1196 keyboard_info_t info; 1197 char *unit, *ep; 1198 1199 /* 1200 * If stdin is not associated with a keyboard, the following ioctl 1201 * will fail. 1202 */ 1203 if (ioctl(0, KDGKBINFO, &info) == -1) { 1204 warn("unable to obtain keyboard information"); 1205 return; 1206 } 1207 #if 1 1208 printf("kbd%d\n", info.kb_index); 1209 printf(" %.*s%d, type:%s (%d)\n", 1210 (int)sizeof(info.kb_name), info.kb_name, info.kb_unit, 1211 get_kbd_type_name(info.kb_type), info.kb_type); 1212 #endif 1213 /* 1214 * split kbd into name and unit. find the right most part of the 1215 * kbd string that consist of only digits. 1216 */ 1217 1218 memset(&info, 0, sizeof(info)); 1219 1220 info.kb_unit = -1; 1221 ep = kbd - 1; 1222 1223 do { 1224 unit = strpbrk(ep + 1, "0123456789"); 1225 if (unit != NULL) { 1226 info.kb_unit = strtol(unit, &ep, 10); 1227 if (*ep != '\0') 1228 info.kb_unit = -1; 1229 } 1230 } while (unit != NULL && info.kb_unit == -1); 1231 1232 if (info.kb_unit == -1) { 1233 warnx("unable to find keyboard driver unit in '%s'", kbd); 1234 return; 1235 } 1236 1237 if (unit == kbd) { 1238 warnx("unable to find keyboard driver name in '%s'", kbd); 1239 return; 1240 } 1241 if (unit - kbd >= (int) sizeof(info.kb_name)) { 1242 warnx("keyboard name '%s' is too long", kbd); 1243 return; 1244 } 1245 1246 strncpy(info.kb_name, kbd, unit - kbd); 1247 1248 /* 1249 * If stdin is not associated with a kbdmux(4) keyboard, the following 1250 * ioctl will fail. 1251 */ 1252 1253 if (ioctl(0, op, &info) == -1) 1254 warn("unable to (un)mux the keyboard"); 1255 } 1256 1257 static void 1258 usage(void) 1259 { 1260 fprintf(stderr, "%s\n%s\n%s\n", 1261 "usage: kbdcontrol [-dFKix] [-A name] [-a name] [-b duration.pitch | [quiet.]belltype]", 1262 " [-r delay.repeat | speed] [-l mapfile] [-f # string]", 1263 " [-k device] [-L mapfile] [-P path]"); 1264 exit(1); 1265 } 1266 1267 1268 int 1269 main(int argc, char **argv) 1270 { 1271 const char *optstring = "A:a:b:df:iKk:Fl:L:P:r:x"; 1272 int opt; 1273 1274 /* Collect any -P arguments, regardless of where they appear. */ 1275 while ((opt = getopt(argc, argv, optstring)) != -1) { 1276 if (opt == 'P') 1277 add_keymap_path(optarg); 1278 if (opt == '?') 1279 usage(); 1280 } 1281 1282 optind = optreset = 1; 1283 while ((opt = getopt(argc, argv, optstring)) != -1) 1284 switch(opt) { 1285 case 'A': 1286 case 'a': 1287 mux_keyboard((opt == 'A')? KBRELKBD : KBADDKBD, optarg); 1288 break; 1289 case 'b': 1290 set_bell_values(optarg); 1291 break; 1292 case 'd': 1293 print_keymap(); 1294 break; 1295 case 'l': 1296 load_keymap(optarg, 0); 1297 break; 1298 case 'L': 1299 load_keymap(optarg, 1); 1300 break; 1301 case 'P': 1302 break; 1303 case 'f': 1304 set_functionkey(optarg, 1305 nextarg(argc, argv, &optind, 'f')); 1306 break; 1307 case 'F': 1308 load_default_functionkeys(); 1309 break; 1310 case 'i': 1311 show_kbd_info(); 1312 break; 1313 case 'K': 1314 release_keyboard(); 1315 break; 1316 case 'k': 1317 set_keyboard(optarg); 1318 break; 1319 case 'r': 1320 set_keyrates(optarg); 1321 break; 1322 case 'x': 1323 hex = 1; 1324 break; 1325 default: 1326 usage(); 1327 } 1328 if ((optind != argc) || (argc == 1)) 1329 usage(); 1330 exit(0); 1331 } 1332