kbdcontrol.c revision 38044
1130561Sobrien/*-
2130561Sobrien * Copyright (c) 1994-1995 S�ren Schmidt
3130561Sobrien * All rights reserved.
4130561Sobrien *
5130561Sobrien * Redistribution and use in source and binary forms, with or without
6130561Sobrien * modification, are permitted provided that the following conditions
7130561Sobrien * are met:
8130561Sobrien * 1. Redistributions of source code must retain the above copyright
9130561Sobrien *    notice, this list of conditions and the following disclaimer,
10130561Sobrien *    in this position and unchanged.
11130561Sobrien * 2. Redistributions in binary form must reproduce the above copyright
12130561Sobrien *    notice, this list of conditions and the following disclaimer in the
13130561Sobrien *    documentation and/or other materials provided with the distribution.
14130561Sobrien * 3. The name of the author may not be used to endorse or promote products
15130561Sobrien *    derived from this software withough specific prior written permission
16130561Sobrien *
17130561Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18130561Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19130561Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20218822Sdim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21218822Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22130561Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23130561Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24130561Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25130561Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26130561Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27130561Sobrien */
28130561Sobrien
29130561Sobrien#ifndef lint
30130561Sobrienstatic const char rcsid[] =
31130561Sobrien	"$Id: kbdcontrol.c,v 1.14 1998/05/05 19:02:01 des Exp $";
32130561Sobrien#endif /* not lint */
33130561Sobrien
34130561Sobrien#include <ctype.h>
35130561Sobrien#include <err.h>
36130561Sobrien#include <stdio.h>
37130561Sobrien#include <stdlib.h>
38130561Sobrien#include <string.h>
39130561Sobrien#include <unistd.h>
40130561Sobrien#include <machine/console.h>
41130561Sobrien#include "path.h"
42130561Sobrien#include "lex.h"
43130561Sobrien
44130561Sobrienchar ctrl_names[32][4] = {
45130561Sobrien	"nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
46130561Sobrien	"bs ", "ht ", "nl ", "vt ", "ff ", "cr ", "so ", "si ",
47130561Sobrien	"dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
48130561Sobrien	"can", "em ", "sub", "esc", "fs ", "gs ", "rs ", "ns "
49130561Sobrien	};
50130561Sobrien
51130561Sobrienchar acc_names[15][5] = {
52130561Sobrien	"dgra", "dacu", "dcir", "dtil", "dmac", "dbre", "ddot",
53130561Sobrien	"duml", "dsla", "drin", "dced", "dapo", "ddac", "dogo",
54130561Sobrien	"dcar",
55130561Sobrien	};
56130561Sobrien
57130561Sobrienchar acc_names_u[15][5] = {
58130561Sobrien	"DGRA", "DACU", "DCIR", "DTIL", "DMAC", "DBRE", "DDOT",
59130561Sobrien	"DUML", "DSLA", "DRIN", "DCED", "DAPO", "DDAC", "DOGO",
60130561Sobrien	"DCAR",
61130561Sobrien	};
62130561Sobrien
63130561Sobrienchar fkey_table[96][MAXFK] = {
64130561Sobrien/* 01-04 */	"\033[M", "\033[N", "\033[O", "\033[P",
65130561Sobrien/* 05-08 */	"\033[Q", "\033[R", "\033[S", "\033[T",
66130561Sobrien/* 09-12 */	"\033[U", "\033[V", "\033[W", "\033[X",
67218822Sdim/* 13-16 */	"\033[Y", "\033[Z", "\033[a", "\033[b",
68218822Sdim/* 17-20 */	"\033[c", "\033[d", "\033[e", "\033[f",
69218822Sdim/* 21-24 */	"\033[g", "\033[h", "\033[i", "\033[j",
70218822Sdim/* 25-28 */	"\033[k", "\033[l", "\033[m", "\033[n",
71218822Sdim/* 29-32 */	"\033[o", "\033[p", "\033[q", "\033[r",
72218822Sdim/* 33-36 */	"\033[s", "\033[t", "\033[u", "\033[v",
73130561Sobrien/* 37-40 */	"\033[w", "\033[x", "\033[y", "\033[z",
74130561Sobrien/* 41-44 */	"\033[@", "\033[[", "\033[\\","\033[]",
75130561Sobrien/* 45-48 */     "\033[^", "\033[_", "\033[`", "\033[{",
76218822Sdim/* 49-52 */	"\033[H", "\033[A", "\033[I", "-"     ,
77130561Sobrien/* 53-56 */	"\033[D", "\033[E", "\033[C", "+"     ,
78130561Sobrien/* 57-60 */	"\033[F", "\033[B", "\033[G", "\033[L",
79130561Sobrien/* 61-64 */     "\177",   "\033[J", "\033[~", "\033[}",
80130561Sobrien/* 65-68 */	""      , ""      , ""      , ""      ,
81130561Sobrien/* 69-72 */	""      , ""      , ""      , ""      ,
82130561Sobrien/* 73-76 */	""      , ""      , ""      , ""      ,
83130561Sobrien/* 77-80 */	""      , ""      , ""      , ""      ,
84130561Sobrien/* 81-84 */	""      , ""      , ""      , ""      ,
85130561Sobrien/* 85-88 */	""      , ""      , ""      , ""      ,
86130561Sobrien/* 89-92 */	""      , ""      , ""      , ""      ,
87130561Sobrien/* 93-96 */	""      , ""      , ""      , ""      ,
88130561Sobrien	};
89130561Sobrien
90130561Sobrienconst int	delays[]  = {250, 500, 750, 1000};
91130561Sobrienconst int	repeats[] = { 34,  38,  42,  46,  50,  55,  59,  63,
92130561Sobrien			      68,  76,  84,  92, 100, 110, 118, 126,
93130561Sobrien			     136, 152, 168, 184, 200, 220, 236, 252,
94130561Sobrien			     272, 304, 336, 368, 400, 440, 472, 504};
95130561Sobrienconst int	ndelays = (sizeof(delays) / sizeof(int));
96130561Sobrienconst int	nrepeats = (sizeof(repeats) / sizeof(int));
97130561Sobrienint 		hex = 0;
98130561Sobrienint 		number;
99130561Sobrienchar 		letter;
100130561Sobrienint		token;
101130561Sobrien
102130561Sobrienstatic void usage __P((void));
103130561Sobrien
104130561Sobrienchar *
105130561Sobriennextarg(int ac, char **av, int *indp, int oc)
106130561Sobrien{
107130561Sobrien	if (*indp < ac)
108130561Sobrien		return(av[(*indp)++]);
109130561Sobrien	warnx("option requires two arguments -- %c", oc);
110130561Sobrien	usage();
111130561Sobrien	return("");
112130561Sobrien}
113130561Sobrien
114130561Sobrien
115130561Sobrienchar *
116130561Sobrienmkfullname(const char *s1, const char *s2, const char *s3)
117130561Sobrien{
118130561Sobrien	static char	*buf = NULL;
119130561Sobrien	static int	bufl = 0;
120218822Sdim	int		f;
121130561Sobrien
122130561Sobrien	f = strlen(s1) + strlen(s2) + strlen(s3) + 1;
123130561Sobrien	if (f > bufl)
124130561Sobrien		if (buf)
125130561Sobrien			buf = (char *)realloc(buf, f);
126130561Sobrien		else
127130561Sobrien			buf = (char *)malloc(f);
128130561Sobrien	if (!buf) {
129130561Sobrien		bufl = 0;
130130561Sobrien		return(NULL);
131218822Sdim	}
132218822Sdim
133218822Sdim	bufl = f;
134218822Sdim	strcpy(buf, s1);
135218822Sdim	strcat(buf, s2);
136218822Sdim	strcat(buf, s3);
137218822Sdim	return(buf);
138218822Sdim}
139218822Sdim
140218822Sdim
141218822Sdimint
142218822Sdimget_entry()
143218822Sdim{
144218822Sdim	switch ((token = yylex())) {
145218822Sdim	case TNOP:
146218822Sdim		return NOP | 0x100;
147218822Sdim	case TLSH:
148218822Sdim		return LSH | 0x100;
149218822Sdim	case TRSH:
150218822Sdim		return RSH | 0x100;
151218822Sdim	case TCLK:
152218822Sdim		return CLK | 0x100;
153218822Sdim	case TNLK:
154218822Sdim		return NLK | 0x100;
155130561Sobrien	case TSLK:
156130561Sobrien		return SLK | 0x100;
157130561Sobrien	case TBTAB:
158		return BTAB | 0x100;
159	case TLALT:
160		return LALT | 0x100;
161	case TLCTR:
162		return LCTR | 0x100;
163	case TNEXT:
164		return NEXT | 0x100;
165	case TRCTR:
166		return RCTR | 0x100;
167	case TRALT:
168		return RALT | 0x100;
169	case TALK:
170		return ALK | 0x100;
171	case TASH:
172		return ASH | 0x100;
173	case TMETA:
174		return META | 0x100;
175	case TRBT:
176		return RBT | 0x100;
177	case TDBG:
178		return DBG | 0x100;
179	case TSUSP:
180		return SUSP | 0x100;
181	case TACC:
182		if (ACC(number) > L_ACC)
183			return -1;
184		return ACC(number) | 0x100;
185	case TFUNC:
186		if (F(number) > L_FN)
187			return -1;
188		return F(number) | 0x100;
189	case TSCRN:
190		if (S(number) > L_SCR)
191			return -1;
192		return S(number) | 0x100;
193	case TLET:
194		return (unsigned char)letter;
195	case TNUM:
196		if (number < 0 || number > 255)
197			return -1;
198		return number;
199	default:
200		return -1;
201	}
202}
203
204int
205get_definition_line(FILE *fd, keymap_t *keymap, accentmap_t *accentmap)
206{
207	int c;
208
209	yyin = fd;
210
211	if (token < 0)
212		token = yylex();
213	switch (token) {
214	case TNUM:
215		c = get_key_definition_line(keymap);
216		if (c < 0)
217			errx(1, "invalid key definition");
218		if (c > keymap->n_keys)
219			keymap->n_keys = c;
220		break;
221	case TACC:
222		c = get_accent_definition_line(accentmap);
223		if (c < 0)
224			errx(1, "invalid accent key definition");
225		if (c > accentmap->n_accs)
226			accentmap->n_accs = c;
227		break;
228	case 0:
229		/* EOF */
230		return -1;
231	default:
232		errx(1, "illegal definition line");
233	}
234	return c;
235}
236
237int
238get_key_definition_line(keymap_t *map)
239{
240	int i, def, scancode;
241
242	/* check scancode number */
243	if (number < 0 || number >= NUM_KEYS)
244		return -1;
245	scancode = number;
246
247	/* get key definitions */
248	map->key[scancode].spcl = 0;
249	for (i=0; i<NUM_STATES; i++) {
250		if ((def = get_entry()) == -1)
251			return -1;
252		if (def & 0x100)
253			map->key[scancode].spcl |= (0x80 >> i);
254		map->key[scancode].map[i] = def & 0xFF;
255	}
256	/* get lock state key def */
257	if ((token = yylex()) != TFLAG)
258		return -1;
259	map->key[scancode].flgs = number;
260	token = yylex();
261	return (scancode + 1);
262}
263
264int
265get_accent_definition_line(accentmap_t *map)
266{
267	int accent;
268	int c1, c2;
269	int i;
270
271	if (ACC(number) < F_ACC || ACC(number) > L_ACC)
272		/* number out of range */
273		return -1;
274	accent = number;
275	if (map->acc[accent].accchar != 0) {
276		/* this entry has already been defined before! */
277		errx(1, "duplicated accent key definition");
278	}
279
280	switch ((token = yylex())) {
281	case TLET:
282		map->acc[accent].accchar = letter;
283		break;
284	case TNUM:
285		map->acc[accent].accchar = number;
286		break;
287	default:
288		return -1;
289	}
290
291	for (i = 0; (token = yylex()) == '(';) {
292		switch ((token = yylex())) {
293		case TLET:
294			c1 = letter;
295			break;
296		case TNUM:
297			c1 = number;
298			break;
299		default:
300			return -1;
301		}
302		switch ((token = yylex())) {
303		case TLET:
304			c2 = letter;
305			break;
306		case TNUM:
307			c2 = number;
308			break;
309		default:
310			return -1;
311		}
312		if ((token = yylex()) != ')')
313			return -1;
314		if (i >= NUM_ACCENTCHARS) {
315			warnx("too many accented characters, ignored");
316			continue;
317		}
318		map->acc[accent].map[i][0] = c1;
319		map->acc[accent].map[i][1] = c2;
320		++i;
321	}
322	return (accent + 1);
323}
324
325void
326print_entry(FILE *fp, int value)
327{
328	int val = value & 0xFF;
329
330	switch (value) {
331	case NOP | 0x100:
332		fprintf(fp, " nop   ");
333		break;
334	case LSH | 0x100:
335		fprintf(fp, " lshift");
336		break;
337	case RSH | 0x100:
338		fprintf(fp, " rshift");
339		break;
340	case CLK | 0x100:
341		fprintf(fp, " clock ");
342		break;
343	case NLK | 0x100:
344		fprintf(fp, " nlock ");
345		break;
346	case SLK | 0x100:
347		fprintf(fp, " slock ");
348		break;
349	case BTAB | 0x100:
350		fprintf(fp, " btab  ");
351		break;
352	case LALT | 0x100:
353		fprintf(fp, " lalt  ");
354		break;
355	case LCTR | 0x100:
356		fprintf(fp, " lctrl ");
357		break;
358	case NEXT | 0x100:
359		fprintf(fp, " nscr  ");
360		break;
361	case RCTR | 0x100:
362		fprintf(fp, " rctrl ");
363		break;
364	case RALT | 0x100:
365		fprintf(fp, " ralt  ");
366		break;
367	case ALK | 0x100:
368		fprintf(fp, " alock ");
369		break;
370	case ASH | 0x100:
371		fprintf(fp, " ashift");
372		break;
373	case META | 0x100:
374		fprintf(fp, " meta  ");
375		break;
376	case RBT | 0x100:
377		fprintf(fp, " boot  ");
378		break;
379	case DBG | 0x100:
380		fprintf(fp, " debug ");
381		break;
382	case SUSP | 0x100:
383		fprintf(fp, " susp  ");
384		break;
385	default:
386		if (value & 0x100) {
387		 	if (val >= F_FN && val <= L_FN)
388				fprintf(fp, " fkey%02d", val - F_FN + 1);
389		 	else if (val >= F_SCR && val <= L_SCR)
390				fprintf(fp, " scr%02d ", val - F_SCR + 1);
391		 	else if (val >= F_ACC && val <= L_ACC)
392				fprintf(fp, " %-6s", acc_names[val - F_ACC]);
393			else if (hex)
394				fprintf(fp, " 0x%02x  ", val);
395			else
396				fprintf(fp, " %3d   ", val);
397		}
398		else {
399			if (val < ' ')
400				fprintf(fp, " %s   ", ctrl_names[val]);
401			else if (val == 127)
402				fprintf(fp, " del   ");
403			else if (isascii(val) && isprint(val))
404				fprintf(fp, " '%c'   ", val);
405			else if (hex)
406				fprintf(fp, " 0x%02x  ", val);
407			else
408				fprintf(fp, " %3d   ", val);
409		}
410	}
411}
412
413
414void
415print_key_definition_line(FILE *fp, int scancode, struct key_t *key)
416{
417	int i;
418
419	/* print scancode number */
420	if (hex)
421		fprintf(fp, " 0x%02x  ", scancode);
422	else
423		fprintf(fp, "  %03d  ", scancode);
424
425	/* print key definitions */
426	for (i=0; i<NUM_STATES; i++) {
427		if (key->spcl & (0x80 >> i))
428			print_entry(fp, key->map[i] | 0x100);
429		else
430			print_entry(fp, key->map[i]);
431	}
432
433	/* print lock state key def */
434	switch (key->flgs) {
435	case 0:
436		fprintf(fp, "  O\n");
437		break;
438	case 1:
439		fprintf(fp, "  C\n");
440		break;
441	case 2:
442		fprintf(fp, "  N\n");
443		break;
444	case 3:
445		fprintf(fp, "  B\n");
446		break;
447	}
448}
449
450void
451print_accent_definition_line(FILE *fp, int accent, struct acc_t *key)
452{
453	int c;
454	int i;
455
456	if (key->accchar == 0)
457		return;
458
459	/* print accent number */
460	fprintf(fp, "  %-6s", acc_names[accent]);
461	if (isascii(key->accchar) && isprint(key->accchar))
462		fprintf(fp, "'%c'  ", key->accchar);
463	else if (hex)
464		fprintf(fp, "0x%02x ", key->accchar);
465	else
466		fprintf(fp, "%03d  ", key->accchar);
467
468	for (i = 0; i < NUM_ACCENTCHARS; ++i) {
469		c = key->map[i][0];
470		if (c == 0)
471			break;
472		if ((i > 0) && ((i % 4) == 0))
473			fprintf(fp, "\n             ");
474		if (isascii(c) && isprint(c))
475			fprintf(fp, "( '%c' ", c);
476		else if (hex)
477			fprintf(fp, "(0x%02x ", c);
478		else
479			fprintf(fp, "( %03d ", c);
480		c = key->map[i][1];
481		if (isascii(c) && isprint(c))
482			fprintf(fp, "'%c' ) ", c);
483		else if (hex)
484			fprintf(fp, "0x%02x) ", c);
485		else
486			fprintf(fp, "%03d ) ", c);
487	}
488	fprintf(fp, "\n");
489}
490
491void
492dump_entry(int value)
493{
494	if (value & 0x100) {
495		value &= 0x00ff;
496		switch (value) {
497		case NOP:
498			printf("  NOP, ");
499			break;
500		case LSH:
501			printf("  LSH, ");
502			break;
503		case RSH:
504			printf("  RSH, ");
505			break;
506		case CLK:
507			printf("  CLK, ");
508			break;
509		case NLK:
510			printf("  NLK, ");
511			break;
512		case SLK:
513			printf("  SLK, ");
514			break;
515		case BTAB:
516			printf(" BTAB, ");
517			break;
518		case LALT:
519			printf(" LALT, ");
520			break;
521		case LCTR:
522			printf(" LCTR, ");
523			break;
524		case NEXT:
525			printf(" NEXT, ");
526			break;
527		case RCTR:
528			printf(" RCTR, ");
529			break;
530		case RALT:
531			printf(" RALT, ");
532			break;
533		case ALK:
534			printf("  ALK, ");
535			break;
536		case ASH:
537			printf("  ASH, ");
538			break;
539		case META:
540			printf(" META, ");
541			break;
542		case RBT:
543			printf("  RBT, ");
544			break;
545		case DBG:
546			printf("  DBG, ");
547			break;
548		case SUSP:
549			printf(" SUSP, ");
550			break;
551		default:
552	 		if (value >= F_FN && value <= L_FN)
553				printf(" F(%2d),", value - F_FN + 1);
554	 		else if (value >= F_SCR && value <= L_SCR)
555				printf(" S(%2d),", value - F_SCR + 1);
556	 		else if (value >= F_ACC && value <= L_ACC)
557				printf(" %-4s, ", acc_names_u[value - F_ACC]);
558			else
559				printf(" 0x%02X, ", value);
560			break;
561		}
562	} else if (value == '\'') {
563		printf(" '\\'', ");
564	} else if (value == '\\') {
565		printf(" '\\\\', ");
566	} else if (isascii(value) && isprint(value)) {
567		printf("  '%c', ", value);
568	} else {
569		printf(" 0x%02X, ", value);
570	}
571}
572
573void
574dump_key_definition(char *name, keymap_t *keymap)
575{
576	int	i, j;
577
578	printf("static keymap_t keymap_%s = { 0x%02x, {\n",
579	       name, (unsigned)keymap->n_keys);
580	printf(
581"/*                                                         alt\n"
582" * scan                       cntrl          alt    alt   cntrl\n"
583" * code  base   shift  cntrl  shift   alt   shift  cntrl  shift    spcl flgs\n"
584" * ---------------------------------------------------------------------------\n"
585" */\n");
586	for (i = 0; i < keymap->n_keys; i++) {
587		printf("/*%02x*/{{", i);
588		for (j = 0; j < NUM_STATES; j++) {
589			if (keymap->key[i].spcl & (0x80 >> j))
590				dump_entry(keymap->key[i].map[j] | 0x100);
591			else
592				dump_entry(keymap->key[i].map[j]);
593		}
594		printf("}, 0x%02X,0x%02X },\n",
595		       (unsigned)keymap->key[i].spcl,
596		       (unsigned)keymap->key[i].flgs);
597	}
598	printf("} };\n\n");
599}
600
601void
602dump_accent_definition(char *name, accentmap_t *accentmap)
603{
604	int i, j;
605	int c;
606
607	printf("static accentmap_t accentmap_%s = { %d",
608		name, accentmap->n_accs);
609	if (accentmap->n_accs <= 0) {
610		printf(" };\n\n");
611		return;
612	}
613	printf(", {\n");
614	for (i = 0; i < NUM_DEADKEYS; i++) {
615		printf("    /* %s=%d */\n    {", acc_names[i], i);
616		c = accentmap->acc[i].accchar;
617		if (c == '\'')
618			printf(" '\\'', {");
619		else if (c == '\\')
620			printf(" '\\\\', {");
621		else if (isascii(c) && isprint(c))
622			printf("  '%c', {", c);
623		else if (c == 0) {
624			printf(" 0x00 }, \n");
625			continue;
626		} else
627			printf(" 0x%02x, {", c);
628		for (j = 0; j < NUM_ACCENTCHARS; j++) {
629			c = accentmap->acc[i].map[j][0];
630			if (c == 0)
631				break;
632			if ((j > 0) && ((j % 4) == 0))
633				printf("\n\t     ");
634			if (isascii(c) && isprint(c))
635				printf(" {  '%c',", c);
636			else
637				printf(" { 0x%02x,", c);
638			printf("0x%02x },", accentmap->acc[i].map[j][1]);
639		}
640		printf(" }, },\n");
641	}
642	printf("} };\n\n");
643}
644
645void
646load_keymap(char *opt, int dumponly)
647{
648	keymap_t keymap;
649	accentmap_t accentmap;
650	FILE	*fd;
651	int	i;
652	char	*name, *cp;
653	char	*prefix[]  = {"", "", KEYMAP_PATH, KEYMAP_PATH, NULL};
654	char	*postfix[] = {"", ".kbd", "", ".kbd"};
655
656	for (i=0; prefix[i]; i++) {
657		name = mkfullname(prefix[i], opt, postfix[i]);
658		if ((fd = fopen(name, "r")))
659			break;
660	}
661	if (fd == NULL) {
662		warn("keymap file not found");
663		return;
664	}
665	memset(&keymap, 0, sizeof(keymap));
666	memset(&accentmap, 0, sizeof(accentmap));
667	token = -1;
668	while (1) {
669		if (get_definition_line(fd, &keymap, &accentmap) < 0)
670			break;
671    	}
672	if (dumponly) {
673		/* fix up the filename to make it a valid C identifier */
674		for (cp = opt; *cp; cp++)
675			if (!isalpha(*cp) && !isdigit(*cp)) *cp = '_';
676		printf("/*\n"
677		       " * Automatically generated from %s.\n"
678	               " * DO NOT EDIT!\n"
679		       " */\n", name);
680		dump_key_definition(opt, &keymap);
681		dump_accent_definition(opt, &accentmap);
682		return;
683	}
684	if ((keymap.n_keys > 0) && (ioctl(0, PIO_KEYMAP, &keymap) < 0)) {
685		warn("setting keymap");
686		fclose(fd);
687		return;
688	}
689	if ((accentmap.n_accs > 0)
690		&& (ioctl(0, PIO_DEADKEYMAP, &accentmap) < 0)) {
691		warn("setting accentmap");
692		fclose(fd);
693		return;
694	}
695}
696
697void
698print_keymap()
699{
700	keymap_t keymap;
701	accentmap_t accentmap;
702	int i;
703
704	if (ioctl(0, GIO_KEYMAP, &keymap) < 0)
705		err(1, "getting keymap");
706	if (ioctl(0, GIO_DEADKEYMAP, &accentmap) < 0)
707		memset(&accentmap, 0, sizeof(accentmap));
708    	printf(
709"#                                                         alt\n"
710"# scan                       cntrl          alt    alt   cntrl lock\n"
711"# code  base   shift  cntrl  shift  alt    shift  cntrl  shift state\n"
712"# ------------------------------------------------------------------\n"
713    	);
714	for (i=0; i<keymap.n_keys; i++)
715		print_key_definition_line(stdout, i, &keymap.key[i]);
716
717	printf("\n");
718	for (i = 0; i < NUM_DEADKEYS; i++)
719		print_accent_definition_line(stdout, i, &accentmap.acc[i]);
720
721}
722
723
724void
725load_default_functionkeys()
726{
727	fkeyarg_t fkey;
728	int i;
729
730	for (i=0; i<NUM_FKEYS; i++) {
731		fkey.keynum = i;
732		strcpy(fkey.keydef, fkey_table[i]);
733		fkey.flen = strlen(fkey_table[i]);
734		if (ioctl(0, SETFKEY, &fkey) < 0)
735			warn("setting function key");
736	}
737}
738
739void
740set_functionkey(char *keynumstr, char *string)
741{
742	fkeyarg_t fkey;
743
744	if (!strcmp(keynumstr, "load") && !strcmp(string, "default")) {
745		load_default_functionkeys();
746		return;
747	}
748	fkey.keynum = atoi(keynumstr);
749	if (fkey.keynum < 1 || fkey.keynum > NUM_FKEYS) {
750		warnx("function key number must be between 1 and %d",
751			NUM_FKEYS);
752		return;
753	}
754	if ((fkey.flen = strlen(string)) > MAXFK) {
755		warnx("function key string too long (%d > %d)",
756			fkey.flen, MAXFK);
757		return;
758	}
759	strcpy(fkey.keydef, string);
760	fkey.keynum -= 1;
761	if (ioctl(0, SETFKEY, &fkey) < 0)
762		warn("setting function key");
763}
764
765
766void
767set_bell_values(char *opt)
768{
769	int bell, duration, pitch;
770
771	bell = 0;
772	if (!strncmp(opt, "quiet.", 6)) {
773		bell = 2;
774		opt += 6;
775	}
776	if (!strcmp(opt, "visual"))
777		bell |= 1;
778	else if (!strcmp(opt, "normal"))
779		duration = 5, pitch = 800;
780	else {
781		char		*v1;
782
783		bell = 0;
784		duration = strtol(opt, &v1, 0);
785		if ((duration < 0) || (*v1 != '.'))
786			goto badopt;
787		opt = ++v1;
788		pitch = strtol(opt, &v1, 0);
789		if ((pitch < 0) || (*opt == '\0') || (*v1 != '\0')) {
790badopt:
791			warnx("argument to -b must be DURATION.PITCH");
792			return;
793		}
794		if (pitch != 0)
795			pitch = 1193182 / pitch;	/* in Hz */
796		duration /= 10;	/* in 10 m sec */
797	}
798
799	ioctl(0, CONS_BELLTYPE, &bell);
800	if ((bell & ~2) == 0)
801		fprintf(stderr, "[=%d;%dB", pitch, duration);
802}
803
804
805void
806set_keyrates(char *opt)
807{
808struct	{
809	int	rep:5;
810	int	del:2;
811	int	pad:1;
812	}rate;
813
814	if (!strcmp(opt, "slow"))
815		rate.del = 3, rate.rep = 31;
816	else if (!strcmp(opt, "normal"))
817		rate.del = 1, rate.rep = 15;
818	else if (!strcmp(opt, "fast"))
819		rate.del = rate.rep = 0;
820	else {
821		int		n;
822		int		delay, repeat;
823		char		*v1;
824
825		delay = strtol(opt, &v1, 0);
826		if ((delay < 0) || (*v1 != '.'))
827			goto badopt;
828		opt = ++v1;
829		repeat = strtol(opt, &v1, 0);
830		if ((repeat < 0) || (*opt == '\0') || (*v1 != '\0')) {
831badopt:
832			warnx("argument to -r must be delay.repeat");
833			return;
834		}
835		for (n = 0; n < ndelays - 1; n++)
836			if (delay <= delays[n])
837				break;
838		rate.del = n;
839		for (n = 0; n < nrepeats - 1; n++)
840			if (repeat <= repeats[n])
841				break;
842		rate.rep = n;
843	}
844
845	if (ioctl(0, KDSETRAD, rate) < 0)
846		warn("setting keyboard rate");
847}
848
849
850void
851set_history(char *opt)
852{
853	int size;
854
855	size = atoi(opt);
856	if ((*opt == '\0') || size < 0) {
857		warnx("argument must be a positive number");
858		return;
859	}
860	if (ioctl(0, CONS_HISTORY, &size) == -1)
861		warn("setting history buffer size");
862}
863
864
865static void
866usage()
867{
868	fprintf(stderr, "%s\n%s\n%s\n",
869"usage: kbdcontrol [-dFx] [-b  duration.pitch | [quiet.]belltype]",
870"                  [-r delay.repeat | speed] [-l mapfile] [-f # string]",
871"                  [-h size] [-L mapfile]");
872	exit(1);
873}
874
875
876void
877main(int argc, char **argv)
878{
879	int		opt;
880
881	while((opt = getopt(argc, argv, "b:df:h:Fl:L:r:x")) != -1)
882		switch(opt) {
883			case 'b':
884				set_bell_values(optarg);
885				break;
886			case 'd':
887				print_keymap();
888				break;
889			case 'l':
890				load_keymap(optarg, 0);
891				break;
892			case 'L':
893				load_keymap(optarg, 1);
894				break;
895			case 'f':
896				set_functionkey(optarg,
897					nextarg(argc, argv, &optind, 'f'));
898				break;
899			case 'F':
900				load_default_functionkeys();
901				break;
902			case 'h':
903				set_history(optarg);
904				break;
905			case 'r':
906				set_keyrates(optarg);
907				break;
908			case 'x':
909				hex = 1;
910				break;
911			default:
912				usage();
913		}
914	if ((optind != argc) || (argc == 1))
915		usage();
916	exit(0);
917}
918
919
920