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