kbdcontrol.c revision 74118
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 74118 2001-03-11 22:51:05Z ache $";
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;
750	char	*name, *cp;
751	char	*prefix[]  = {"", "", KEYMAP_PATH, KEYMAP_PATH, NULL};
752	char	*postfix[] = {"", ".kbd", "", ".kbd"};
753
754	for (i=0; prefix[i]; i++) {
755		name = mkfullname(prefix[i], opt, postfix[i]);
756		if ((fd = fopen(name, "r")))
757			break;
758	}
759	if (fd == NULL) {
760		warn("keymap file not found");
761		return;
762	}
763	memset(&keymap, 0, sizeof(keymap));
764	memset(&accentmap, 0, sizeof(accentmap));
765	token = -1;
766	while (1) {
767		if (get_definition_line(fd, &keymap, &accentmap) < 0)
768			break;
769    	}
770	if (dumponly) {
771		/* fix up the filename to make it a valid C identifier */
772		for (cp = opt; *cp; cp++)
773			if (!isalpha(*cp) && !isdigit(*cp)) *cp = '_';
774		printf("/*\n"
775		       " * Automatically generated from %s.\n"
776	               " * DO NOT EDIT!\n"
777		       " */\n", name);
778		dump_key_definition(opt, &keymap);
779		dump_accent_definition(opt, &accentmap);
780		return;
781	}
782	if ((keymap.n_keys > 0) && (ioctl(0, PIO_KEYMAP, &keymap) < 0)) {
783		warn("setting keymap");
784		fclose(fd);
785		return;
786	}
787	if ((accentmap.n_accs > 0)
788		&& (ioctl(0, PIO_DEADKEYMAP, &accentmap) < 0)) {
789		warn("setting accentmap");
790		fclose(fd);
791		return;
792	}
793}
794
795void
796print_keymap()
797{
798	keymap_t keymap;
799	accentmap_t accentmap;
800	int i;
801
802	if (ioctl(0, GIO_KEYMAP, &keymap) < 0)
803		err(1, "getting keymap");
804	if (ioctl(0, GIO_DEADKEYMAP, &accentmap) < 0)
805		memset(&accentmap, 0, sizeof(accentmap));
806    	printf(
807"#                                                         alt\n"
808"# scan                       cntrl          alt    alt   cntrl lock\n"
809"# code  base   shift  cntrl  shift  alt    shift  cntrl  shift state\n"
810"# ------------------------------------------------------------------\n"
811    	);
812	for (i=0; i<keymap.n_keys; i++)
813		print_key_definition_line(stdout, i, &keymap.key[i]);
814
815	printf("\n");
816	for (i = 0; i < NUM_DEADKEYS; i++)
817		print_accent_definition_line(stdout, i, &accentmap.acc[i]);
818
819}
820
821
822void
823load_default_functionkeys()
824{
825	fkeyarg_t fkey;
826	int i;
827
828	for (i=0; i<NUM_FKEYS; i++) {
829		fkey.keynum = i;
830		strcpy(fkey.keydef, fkey_table[i]);
831		fkey.flen = strlen(fkey_table[i]);
832		if (ioctl(0, SETFKEY, &fkey) < 0)
833			warn("setting function key");
834	}
835}
836
837void
838set_functionkey(char *keynumstr, char *string)
839{
840	fkeyarg_t fkey;
841
842	if (!strcmp(keynumstr, "load") && !strcmp(string, "default")) {
843		load_default_functionkeys();
844		return;
845	}
846	fkey.keynum = atoi(keynumstr);
847	if (fkey.keynum < 1 || fkey.keynum > NUM_FKEYS) {
848		warnx("function key number must be between 1 and %d",
849			NUM_FKEYS);
850		return;
851	}
852	if ((fkey.flen = strlen(string)) > MAXFK) {
853		warnx("function key string too long (%d > %d)",
854			fkey.flen, MAXFK);
855		return;
856	}
857	strcpy(fkey.keydef, string);
858	fkey.keynum -= 1;
859	if (ioctl(0, SETFKEY, &fkey) < 0)
860		warn("setting function key");
861}
862
863
864void
865set_bell_values(char *opt)
866{
867	int bell, duration, pitch;
868
869	bell = 0;
870	if (!strncmp(opt, "quiet.", 6)) {
871		bell = 2;
872		opt += 6;
873	}
874	if (!strcmp(opt, "visual"))
875		bell |= 1;
876	else if (!strcmp(opt, "normal"))
877		duration = 5, pitch = 800;
878	else if (!strcmp(opt, "off"))
879		duration = 0, pitch = 0;
880	else {
881		char		*v1;
882
883		bell = 0;
884		duration = strtol(opt, &v1, 0);
885		if ((duration < 0) || (*v1 != '.'))
886			goto badopt;
887		opt = ++v1;
888		pitch = strtol(opt, &v1, 0);
889		if ((pitch < 0) || (*opt == '\0') || (*v1 != '\0')) {
890badopt:
891			warnx("argument to -b must be DURATION.PITCH");
892			return;
893		}
894		if (pitch != 0)
895			pitch = 1193182 / pitch;	/* in Hz */
896		duration /= 10;	/* in 10 m sec */
897	}
898
899	ioctl(0, CONS_BELLTYPE, &bell);
900	if ((bell & ~2) == 0)
901		fprintf(stderr, "[=%d;%dB", pitch, duration);
902}
903
904
905void
906set_keyrates(char *opt)
907{
908	int arg[2];
909	int repeat;
910	int delay;
911	int r, d;
912
913	if (!strcmp(opt, "slow")) {
914		delay = 1000, repeat = 500;
915		d = 3, r = 31;
916	} else if (!strcmp(opt, "normal")) {
917		delay = 500, repeat = 125;
918		d = 1, r = 15;
919	} else if (!strcmp(opt, "fast")) {
920		delay = repeat = 0;
921		d = r = 0;
922	} else {
923		int		n;
924		char		*v1;
925
926		delay = strtol(opt, &v1, 0);
927		if ((delay < 0) || (*v1 != '.'))
928			goto badopt;
929		opt = ++v1;
930		repeat = strtol(opt, &v1, 0);
931		if ((repeat < 0) || (*opt == '\0') || (*v1 != '\0')) {
932badopt:
933			warnx("argument to -r must be delay.repeat");
934			return;
935		}
936		for (n = 0; n < ndelays - 1; n++)
937			if (delay <= delays[n])
938				break;
939		d = n;
940		for (n = 0; n < nrepeats - 1; n++)
941			if (repeat <= repeats[n])
942				break;
943		r = n;
944	}
945
946	arg[0] = delay;
947	arg[1] = repeat;
948	if (ioctl(0, KDSETREPEAT, arg)) {
949		if (ioctl(0, KDSETRAD, (d << 5) | r))
950			warn("setting keyboard rate");
951	}
952}
953
954
955void
956set_history(char *opt)
957{
958	int size;
959
960	size = atoi(opt);
961	if ((*opt == '\0') || size < 0) {
962		warnx("argument must be a positive number");
963		return;
964	}
965	if (ioctl(0, CONS_HISTORY, &size) == -1)
966		warn("setting history buffer size");
967}
968
969static char
970*get_kbd_type_name(int type)
971{
972	static struct {
973		int type;
974		char *name;
975	} name_table[] = {
976		{ KB_84,	"AT 84" },
977		{ KB_101,	"AT 101/102" },
978		{ KB_OTHER,	"generic" },
979	};
980	int i;
981
982	for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) {
983		if (type == name_table[i].type)
984			return name_table[i].name;
985	}
986	return "unknown";
987}
988
989void
990show_kbd_info(void)
991{
992	keyboard_info_t info;
993
994	if (ioctl(0, KDGKBINFO, &info) == -1) {
995		warn("unable to obtain keyboard information");
996		return;
997	}
998	printf("kbd%d:\n", info.kb_index);
999	printf("    %.*s%d, type:%s (%d)\n",
1000		sizeof(info.kb_name), info.kb_name, info.kb_unit,
1001		get_kbd_type_name(info.kb_type), info.kb_type);
1002}
1003
1004
1005void
1006set_keyboard(char *device)
1007{
1008	keyboard_info_t info;
1009	int fd;
1010
1011	fd = open(device, O_RDONLY);
1012	if (fd < 0) {
1013		warn("cannot open %s", device);
1014		return;
1015	}
1016	if (ioctl(fd, KDGKBINFO, &info) == -1) {
1017		warn("unable to obtain keyboard information");
1018		close(fd);
1019		return;
1020	}
1021	/*
1022	 * The keyboard device driver won't release the keyboard by
1023	 * the following ioctl, but it automatically will, when the device
1024	 * is closed.  So, we don't check error here.
1025	 */
1026	ioctl(fd, CONS_RELKBD, 0);
1027	close(fd);
1028#if 1
1029	printf("kbd%d\n", info.kb_index);
1030	printf("    %.*s%d, type:%s (%d)\n",
1031		sizeof(info.kb_name), info.kb_name, info.kb_unit,
1032		get_kbd_type_name(info.kb_type), info.kb_type);
1033#endif
1034
1035	if (ioctl(0, CONS_SETKBD, info.kb_index) == -1)
1036		warn("unable to set keyboard");
1037}
1038
1039
1040void
1041release_keyboard(void)
1042{
1043	keyboard_info_t info;
1044
1045	/*
1046	 * If stdin is not associated with a keyboard, the following ioctl
1047	 * will fail.
1048	 */
1049	if (ioctl(0, KDGKBINFO, &info) == -1) {
1050		warn("unable to obtain keyboard information");
1051		return;
1052	}
1053#if 1
1054	printf("kbd%d\n", info.kb_index);
1055	printf("    %.*s%d, type:%s (%d)\n",
1056		sizeof(info.kb_name), info.kb_name, info.kb_unit,
1057		get_kbd_type_name(info.kb_type), info.kb_type);
1058#endif
1059	if (ioctl(0, CONS_RELKBD, 0) == -1)
1060		warn("unable to release the keyboard");
1061}
1062
1063
1064static void
1065usage()
1066{
1067	fprintf(stderr, "%s\n%s\n%s\n",
1068"usage: kbdcontrol [-dFKix] [-b  duration.pitch | [quiet.]belltype]",
1069"                  [-r delay.repeat | speed] [-l mapfile] [-f # string]",
1070"                  [-h size] [-k device] [-L mapfile]");
1071	exit(1);
1072}
1073
1074
1075int
1076main(int argc, char **argv)
1077{
1078	int		opt;
1079
1080	while((opt = getopt(argc, argv, "b:df:h:iKk:Fl:L:r:x")) != -1)
1081		switch(opt) {
1082			case 'b':
1083				set_bell_values(optarg);
1084				break;
1085			case 'd':
1086				print_keymap();
1087				break;
1088			case 'l':
1089				load_keymap(optarg, 0);
1090				break;
1091			case 'L':
1092				load_keymap(optarg, 1);
1093				break;
1094			case 'f':
1095				set_functionkey(optarg,
1096					nextarg(argc, argv, &optind, 'f'));
1097				break;
1098			case 'F':
1099				load_default_functionkeys();
1100				break;
1101			case 'h':
1102				set_history(optarg);
1103				break;
1104			case 'i':
1105				show_kbd_info();
1106				break;
1107			case 'K':
1108				release_keyboard();
1109				break;
1110			case 'k':
1111				set_keyboard(optarg);
1112				break;
1113			case 'r':
1114				set_keyrates(optarg);
1115				break;
1116			case 'x':
1117				hex = 1;
1118				break;
1119			default:
1120				usage();
1121		}
1122	if ((optind != argc) || (argc == 1))
1123		usage();
1124	exit(0);
1125}
1126
1127
1128