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