kbdcontrol.c revision 66834
1191783Srmacklem/*-
2191783Srmacklem * Copyright (c) 1994-1995 S�ren Schmidt
3191783Srmacklem * All rights reserved.
4191783Srmacklem *
5191783Srmacklem * Redistribution and use in source and binary forms, with or without
6191783Srmacklem * modification, are permitted provided that the following conditions
7191783Srmacklem * are met:
8191783Srmacklem * 1. Redistributions of source code must retain the above copyright
9191783Srmacklem *    notice, this list of conditions and the following disclaimer,
10191783Srmacklem *    in this position and unchanged.
11191783Srmacklem * 2. Redistributions in binary form must reproduce the above copyright
12191783Srmacklem *    notice, this list of conditions and the following disclaimer in the
13191783Srmacklem *    documentation and/or other materials provided with the distribution.
14191783Srmacklem * 3. The name of the author may not be used to endorse or promote products
15191783Srmacklem *    derived from this software withough specific prior written permission
16191783Srmacklem *
17191783Srmacklem * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18191783Srmacklem * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19191783Srmacklem * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20191783Srmacklem * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21191783Srmacklem * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22191783Srmacklem * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23191783Srmacklem * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24191783Srmacklem * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25191783Srmacklem * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26191783Srmacklem * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27191783Srmacklem */
28191783Srmacklem
29191783Srmacklem#ifndef lint
30191783Srmacklemstatic const char rcsid[] =
31191783Srmacklem  "$FreeBSD: head/usr.sbin/kbdcontrol/kbdcontrol.c 66834 2000-10-08 21:34:00Z phk $";
32191783Srmacklem#endif /* not lint */
33191783Srmacklem
34191783Srmacklem#include <ctype.h>
35191783Srmacklem#include <err.h>
36191783Srmacklem#include <stdio.h>
37191783Srmacklem#include <stdlib.h>
38191783Srmacklem#include <string.h>
39191783Srmacklem#include <unistd.h>
40191783Srmacklem#include <fcntl.h>
41191783Srmacklem#include <sys/kbio.h>
42191783Srmacklem#include <sys/consio.h>
43191783Srmacklem#include "path.h"
44191783Srmacklem#include "lex.h"
45191783Srmacklem
46191783Srmacklemchar ctrl_names[32][4] = {
47191783Srmacklem	"nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
48191783Srmacklem	"bs ", "ht ", "nl ", "vt ", "ff ", "cr ", "so ", "si ",
49191783Srmacklem	"dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
50191783Srmacklem	"can", "em ", "sub", "esc", "fs ", "gs ", "rs ", "us "
51191783Srmacklem	};
52191783Srmacklem
53191783Srmacklemchar acc_names[15][5] = {
54191783Srmacklem	"dgra", "dacu", "dcir", "dtil", "dmac", "dbre", "ddot",
55191783Srmacklem	"duml", "dsla", "drin", "dced", "dapo", "ddac", "dogo",
56191783Srmacklem	"dcar",
57191783Srmacklem	};
58191783Srmacklem
59191783Srmacklemchar acc_names_u[15][5] = {
60191783Srmacklem	"DGRA", "DACU", "DCIR", "DTIL", "DMAC", "DBRE", "DDOT",
61191783Srmacklem	"DUML", "DSLA", "DRIN", "DCED", "DAPO", "DDAC", "DOGO",
62191783Srmacklem	"DCAR",
63191783Srmacklem	};
64191783Srmacklem
65191783Srmacklemchar fkey_table[96][MAXFK] = {
66191783Srmacklem/* 01-04 */	"\033[M", "\033[N", "\033[O", "\033[P",
67191783Srmacklem/* 05-08 */	"\033[Q", "\033[R", "\033[S", "\033[T",
68191783Srmacklem/* 09-12 */	"\033[U", "\033[V", "\033[W", "\033[X",
69191783Srmacklem/* 13-16 */	"\033[Y", "\033[Z", "\033[a", "\033[b",
70191783Srmacklem/* 17-20 */	"\033[c", "\033[d", "\033[e", "\033[f",
71191783Srmacklem/* 21-24 */	"\033[g", "\033[h", "\033[i", "\033[j",
72191783Srmacklem/* 25-28 */	"\033[k", "\033[l", "\033[m", "\033[n",
73191783Srmacklem/* 29-32 */	"\033[o", "\033[p", "\033[q", "\033[r",
74191783Srmacklem/* 33-36 */	"\033[s", "\033[t", "\033[u", "\033[v",
75191783Srmacklem/* 37-40 */	"\033[w", "\033[x", "\033[y", "\033[z",
76191783Srmacklem/* 41-44 */	"\033[@", "\033[[", "\033[\\","\033[]",
77191783Srmacklem/* 45-48 */     "\033[^", "\033[_", "\033[`", "\033[{",
78191783Srmacklem/* 49-52 */	"\033[H", "\033[A", "\033[I", "-"     ,
79191783Srmacklem/* 53-56 */	"\033[D", "\033[E", "\033[C", "+"     ,
80191783Srmacklem/* 57-60 */	"\033[F", "\033[B", "\033[G", "\033[L",
81191783Srmacklem/* 61-64 */     "\177",   "\033[J", "\033[~", "\033[}",
82191783Srmacklem/* 65-68 */	""      , ""      , ""      , ""      ,
83191783Srmacklem/* 69-72 */	""      , ""      , ""      , ""      ,
84191783Srmacklem/* 73-76 */	""      , ""      , ""      , ""      ,
85191783Srmacklem/* 77-80 */	""      , ""      , ""      , ""      ,
86191783Srmacklem/* 81-84 */	""      , ""      , ""      , ""      ,
87191783Srmacklem/* 85-88 */	""      , ""      , ""      , ""      ,
88191783Srmacklem/* 89-92 */	""      , ""      , ""      , ""      ,
89191783Srmacklem/* 93-96 */	""      , ""      , ""      , ""      ,
90191783Srmacklem	};
91191783Srmacklem
92191783Srmacklemconst int	delays[]  = {250, 500, 750, 1000};
93191783Srmacklemconst int	repeats[] = { 34,  38,  42,  46,  50,  55,  59,  63,
94191783Srmacklem			      68,  76,  84,  92, 100, 110, 118, 126,
95191783Srmacklem			     136, 152, 168, 184, 200, 220, 236, 252,
96191783Srmacklem			     272, 304, 336, 368, 400, 440, 472, 504};
97191783Srmacklemconst int	ndelays = (sizeof(delays) / sizeof(int));
98191783Srmacklemconst int	nrepeats = (sizeof(repeats) / sizeof(int));
99191783Srmacklemint 		hex = 0;
100191783Srmacklemint 		number;
101191783Srmacklemchar 		letter;
102191783Srmacklemint		token;
103191783Srmacklem
104191783Srmacklemstatic void usage __P((void));
105191783Srmacklem
106191783Srmacklemchar *
107191783Srmacklemnextarg(int ac, char **av, int *indp, int oc)
108191783Srmacklem{
109191783Srmacklem	if (*indp < ac)
110191783Srmacklem		return(av[(*indp)++]);
111191783Srmacklem	warnx("option requires two arguments -- %c", oc);
112191783Srmacklem	usage();
113191783Srmacklem	return("");
114191783Srmacklem}
115191783Srmacklem
116191783Srmacklem
117191783Srmacklemchar *
118191783Srmacklemmkfullname(const char *s1, const char *s2, const char *s3)
119191783Srmacklem{
120191783Srmacklem	static char	*buf = NULL;
121191783Srmacklem	static int	bufl = 0;
122191783Srmacklem	int		f;
123191783Srmacklem
124191783Srmacklem	f = strlen(s1) + strlen(s2) + strlen(s3) + 1;
125191783Srmacklem	if (f > bufl)
126191783Srmacklem		if (buf)
127191783Srmacklem			buf = (char *)realloc(buf, f);
128191783Srmacklem		else
129191783Srmacklem			buf = (char *)malloc(f);
130191783Srmacklem	if (!buf) {
131191783Srmacklem		bufl = 0;
132191783Srmacklem		return(NULL);
133191783Srmacklem	}
134191783Srmacklem
135191783Srmacklem	bufl = f;
136191783Srmacklem	strcpy(buf, s1);
137191783Srmacklem	strcat(buf, s2);
138191783Srmacklem	strcat(buf, s3);
139191783Srmacklem	return(buf);
140191783Srmacklem}
141191783Srmacklem
142191783Srmacklem
143191783Srmacklemint
144191783Srmacklemget_entry()
145191783Srmacklem{
146191783Srmacklem	switch ((token = yylex())) {
147191783Srmacklem	case TNOP:
148191783Srmacklem		return NOP | 0x100;
149191783Srmacklem	case TLSH:
150191783Srmacklem		return LSH | 0x100;
151191783Srmacklem	case TRSH:
152191783Srmacklem		return RSH | 0x100;
153191783Srmacklem	case TCLK:
154191783Srmacklem		return CLK | 0x100;
155191783Srmacklem	case TNLK:
156191783Srmacklem		return NLK | 0x100;
157191783Srmacklem	case TSLK:
158191783Srmacklem		return SLK | 0x100;
159191783Srmacklem	case TBTAB:
160191783Srmacklem		return BTAB | 0x100;
161191783Srmacklem	case TLALT:
162191783Srmacklem		return LALT | 0x100;
163191783Srmacklem	case TLCTR:
164191783Srmacklem		return LCTR | 0x100;
165191783Srmacklem	case TNEXT:
166191783Srmacklem		return NEXT | 0x100;
167191783Srmacklem	case TPREV:
168191783Srmacklem		return PREV | 0x100;
169191783Srmacklem	case TRCTR:
170191783Srmacklem		return RCTR | 0x100;
171191783Srmacklem	case TRALT:
172191783Srmacklem		return RALT | 0x100;
173191783Srmacklem	case TALK:
174191783Srmacklem		return ALK | 0x100;
175191783Srmacklem	case TASH:
176191783Srmacklem		return ASH | 0x100;
177191783Srmacklem	case TMETA:
178191783Srmacklem		return META | 0x100;
179191783Srmacklem	case TRBT:
180191783Srmacklem		return RBT | 0x100;
181191783Srmacklem	case TDBG:
182191783Srmacklem		return DBG | 0x100;
183191783Srmacklem	case TSUSP:
184191783Srmacklem		return SUSP | 0x100;
185191783Srmacklem	case TSPSC:
186191783Srmacklem		return SPSC | 0x100;
187191783Srmacklem	case TPANIC:
188191783Srmacklem		return PNC | 0x100;
189191783Srmacklem	case TLSHA:
190191783Srmacklem		return LSHA | 0x100;
191191783Srmacklem	case TRSHA:
192191783Srmacklem		return RSHA | 0x100;
193191783Srmacklem	case TLCTRA:
194191783Srmacklem		return LCTRA | 0x100;
195191783Srmacklem	case TRCTRA:
196191783Srmacklem		return RCTRA | 0x100;
197191783Srmacklem	case TLALTA:
198191783Srmacklem		return LALTA | 0x100;
199191783Srmacklem	case TRALTA:
200191783Srmacklem		return RALTA | 0x100;
201191783Srmacklem	case THALT:
202191783Srmacklem		return HALT | 0x100;
203191783Srmacklem	case TPDWN:
204191783Srmacklem		return PDWN | 0x100;
205191783Srmacklem	case TACC:
206191783Srmacklem		if (ACC(number) > L_ACC)
207191783Srmacklem			return -1;
208		return ACC(number) | 0x100;
209	case TFUNC:
210		if (F(number) > L_FN)
211			return -1;
212		return F(number) | 0x100;
213	case TSCRN:
214		if (S(number) > L_SCR)
215			return -1;
216		return S(number) | 0x100;
217	case TLET:
218		return (unsigned char)letter;
219	case TNUM:
220		if (number < 0 || number > 255)
221			return -1;
222		return number;
223	default:
224		return -1;
225	}
226}
227
228int
229get_definition_line(FILE *fd, keymap_t *keymap, accentmap_t *accentmap)
230{
231	int c;
232
233	yyin = fd;
234
235	if (token < 0)
236		token = yylex();
237	switch (token) {
238	case TNUM:
239		c = get_key_definition_line(keymap);
240		if (c < 0)
241			errx(1, "invalid key definition");
242		if (c > keymap->n_keys)
243			keymap->n_keys = c;
244		break;
245	case TACC:
246		c = get_accent_definition_line(accentmap);
247		if (c < 0)
248			errx(1, "invalid accent key definition");
249		if (c > accentmap->n_accs)
250			accentmap->n_accs = c;
251		break;
252	case 0:
253		/* EOF */
254		return -1;
255	default:
256		errx(1, "illegal definition line");
257	}
258	return c;
259}
260
261int
262get_key_definition_line(keymap_t *map)
263{
264	int i, def, scancode;
265
266	/* check scancode number */
267	if (number < 0 || number >= NUM_KEYS)
268		return -1;
269	scancode = number;
270
271	/* get key definitions */
272	map->key[scancode].spcl = 0;
273	for (i=0; i<NUM_STATES; i++) {
274		if ((def = get_entry()) == -1)
275			return -1;
276		if (def & 0x100)
277			map->key[scancode].spcl |= (0x80 >> i);
278		map->key[scancode].map[i] = def & 0xFF;
279	}
280	/* get lock state key def */
281	if ((token = yylex()) != TFLAG)
282		return -1;
283	map->key[scancode].flgs = number;
284	token = yylex();
285	return (scancode + 1);
286}
287
288int
289get_accent_definition_line(accentmap_t *map)
290{
291	int accent;
292	int c1, c2;
293	int i;
294
295	if (ACC(number) < F_ACC || ACC(number) > L_ACC)
296		/* number out of range */
297		return -1;
298	accent = number;
299	if (map->acc[accent].accchar != 0) {
300		/* this entry has already been defined before! */
301		errx(1, "duplicated accent key definition");
302	}
303
304	switch ((token = yylex())) {
305	case TLET:
306		map->acc[accent].accchar = letter;
307		break;
308	case TNUM:
309		map->acc[accent].accchar = number;
310		break;
311	default:
312		return -1;
313	}
314
315	for (i = 0; (token = yylex()) == '(';) {
316		switch ((token = yylex())) {
317		case TLET:
318			c1 = letter;
319			break;
320		case TNUM:
321			c1 = number;
322			break;
323		default:
324			return -1;
325		}
326		switch ((token = yylex())) {
327		case TLET:
328			c2 = letter;
329			break;
330		case TNUM:
331			c2 = number;
332			break;
333		default:
334			return -1;
335		}
336		if ((token = yylex()) != ')')
337			return -1;
338		if (i >= NUM_ACCENTCHARS) {
339			warnx("too many accented characters, ignored");
340			continue;
341		}
342		map->acc[accent].map[i][0] = c1;
343		map->acc[accent].map[i][1] = c2;
344		++i;
345	}
346	return (accent + 1);
347}
348
349void
350print_entry(FILE *fp, int value)
351{
352	int val = value & 0xFF;
353
354	switch (value) {
355	case NOP | 0x100:
356		fprintf(fp, " nop   ");
357		break;
358	case LSH | 0x100:
359		fprintf(fp, " lshift");
360		break;
361	case RSH | 0x100:
362		fprintf(fp, " rshift");
363		break;
364	case CLK | 0x100:
365		fprintf(fp, " clock ");
366		break;
367	case NLK | 0x100:
368		fprintf(fp, " nlock ");
369		break;
370	case SLK | 0x100:
371		fprintf(fp, " slock ");
372		break;
373	case BTAB | 0x100:
374		fprintf(fp, " btab  ");
375		break;
376	case LALT | 0x100:
377		fprintf(fp, " lalt  ");
378		break;
379	case LCTR | 0x100:
380		fprintf(fp, " lctrl ");
381		break;
382	case NEXT | 0x100:
383		fprintf(fp, " nscr  ");
384		break;
385	case PREV | 0x100:
386		fprintf(fp, " pscr  ");
387		break;
388	case RCTR | 0x100:
389		fprintf(fp, " rctrl ");
390		break;
391	case RALT | 0x100:
392		fprintf(fp, " ralt  ");
393		break;
394	case ALK | 0x100:
395		fprintf(fp, " alock ");
396		break;
397	case ASH | 0x100:
398		fprintf(fp, " ashift");
399		break;
400	case META | 0x100:
401		fprintf(fp, " meta  ");
402		break;
403	case RBT | 0x100:
404		fprintf(fp, " boot  ");
405		break;
406	case DBG | 0x100:
407		fprintf(fp, " debug ");
408		break;
409	case SUSP | 0x100:
410		fprintf(fp, " susp  ");
411		break;
412	case SPSC | 0x100:
413		fprintf(fp, " saver ");
414		break;
415	case PNC | 0x100:
416		fprintf(fp, " panic ");
417		break;
418	case LSHA | 0x100:
419		fprintf(fp, " lshifta");
420		break;
421	case RSHA | 0x100:
422		fprintf(fp, " rshifta");
423		break;
424	case LCTRA | 0x100:
425		fprintf(fp, " lctrla");
426		break;
427	case RCTRA | 0x100:
428		fprintf(fp, " rctrla");
429		break;
430	case LALTA | 0x100:
431		fprintf(fp, " lalta ");
432		break;
433	case RALTA | 0x100:
434		fprintf(fp, " ralta ");
435		break;
436	case HALT | 0x100:
437		fprintf(fp, " halt  ");
438		break;
439	case PDWN | 0x100:
440		fprintf(fp, " pdwn  ");
441		break;
442	default:
443		if (value & 0x100) {
444		 	if (val >= F_FN && val <= L_FN)
445				fprintf(fp, " fkey%02d", val - F_FN + 1);
446		 	else if (val >= F_SCR && val <= L_SCR)
447				fprintf(fp, " scr%02d ", val - F_SCR + 1);
448		 	else if (val >= F_ACC && val <= L_ACC)
449				fprintf(fp, " %-6s", acc_names[val - F_ACC]);
450			else if (hex)
451				fprintf(fp, " 0x%02x  ", val);
452			else
453				fprintf(fp, " %3d   ", val);
454		}
455		else {
456			if (val < ' ')
457				fprintf(fp, " %s   ", ctrl_names[val]);
458			else if (val == 127)
459				fprintf(fp, " del   ");
460			else if (isascii(val) && isprint(val))
461				fprintf(fp, " '%c'   ", val);
462			else if (hex)
463				fprintf(fp, " 0x%02x  ", val);
464			else
465				fprintf(fp, " %3d   ", val);
466		}
467	}
468}
469
470
471void
472print_key_definition_line(FILE *fp, int scancode, struct keyent_t *key)
473{
474	int i;
475
476	/* print scancode number */
477	if (hex)
478		fprintf(fp, " 0x%02x  ", scancode);
479	else
480		fprintf(fp, "  %03d  ", scancode);
481
482	/* print key definitions */
483	for (i=0; i<NUM_STATES; i++) {
484		if (key->spcl & (0x80 >> i))
485			print_entry(fp, key->map[i] | 0x100);
486		else
487			print_entry(fp, key->map[i]);
488	}
489
490	/* print lock state key def */
491	switch (key->flgs) {
492	case 0:
493		fprintf(fp, "  O\n");
494		break;
495	case 1:
496		fprintf(fp, "  C\n");
497		break;
498	case 2:
499		fprintf(fp, "  N\n");
500		break;
501	case 3:
502		fprintf(fp, "  B\n");
503		break;
504	}
505}
506
507void
508print_accent_definition_line(FILE *fp, int accent, struct acc_t *key)
509{
510	int c;
511	int i;
512
513	if (key->accchar == 0)
514		return;
515
516	/* print accent number */
517	fprintf(fp, "  %-6s", acc_names[accent]);
518	if (isascii(key->accchar) && isprint(key->accchar))
519		fprintf(fp, "'%c'  ", key->accchar);
520	else if (hex)
521		fprintf(fp, "0x%02x ", key->accchar);
522	else
523		fprintf(fp, "%03d  ", key->accchar);
524
525	for (i = 0; i < NUM_ACCENTCHARS; ++i) {
526		c = key->map[i][0];
527		if (c == 0)
528			break;
529		if ((i > 0) && ((i % 4) == 0))
530			fprintf(fp, "\n             ");
531		if (isascii(c) && isprint(c))
532			fprintf(fp, "( '%c' ", c);
533		else if (hex)
534			fprintf(fp, "(0x%02x ", c);
535		else
536			fprintf(fp, "( %03d ", c);
537		c = key->map[i][1];
538		if (isascii(c) && isprint(c))
539			fprintf(fp, "'%c' ) ", c);
540		else if (hex)
541			fprintf(fp, "0x%02x) ", c);
542		else
543			fprintf(fp, "%03d ) ", c);
544	}
545	fprintf(fp, "\n");
546}
547
548void
549dump_entry(int value)
550{
551	if (value & 0x100) {
552		value &= 0x00ff;
553		switch (value) {
554		case NOP:
555			printf("  NOP, ");
556			break;
557		case LSH:
558			printf("  LSH, ");
559			break;
560		case RSH:
561			printf("  RSH, ");
562			break;
563		case CLK:
564			printf("  CLK, ");
565			break;
566		case NLK:
567			printf("  NLK, ");
568			break;
569		case SLK:
570			printf("  SLK, ");
571			break;
572		case BTAB:
573			printf(" BTAB, ");
574			break;
575		case LALT:
576			printf(" LALT, ");
577			break;
578		case LCTR:
579			printf(" LCTR, ");
580			break;
581		case NEXT:
582			printf(" NEXT, ");
583			break;
584		case PREV:
585			printf(" PREV, ");
586			break;
587		case RCTR:
588			printf(" RCTR, ");
589			break;
590		case RALT:
591			printf(" RALT, ");
592			break;
593		case ALK:
594			printf("  ALK, ");
595			break;
596		case ASH:
597			printf("  ASH, ");
598			break;
599		case META:
600			printf(" META, ");
601			break;
602		case RBT:
603			printf("  RBT, ");
604			break;
605		case DBG:
606			printf("  DBG, ");
607			break;
608		case SUSP:
609			printf(" SUSP, ");
610			break;
611		case SPSC:
612			printf(" SPSC, ");
613			break;
614		case PNC:
615			printf("  PNC, ");
616			break;
617		case LSHA:
618			printf(" LSHA, ");
619			break;
620		case RSHA:
621			printf(" RSHA, ");
622			break;
623		case LCTRA:
624			printf("LCTRA, ");
625			break;
626		case RCTRA:
627			printf("RCTRA, ");
628			break;
629		case LALTA:
630			printf("LALTA, ");
631			break;
632		case RALTA:
633			printf("RALTA, ");
634			break;
635		case HALT:
636			printf(" HALT, ");
637			break;
638		case PDWN:
639			printf(" PDWN, ");
640			break;
641		default:
642	 		if (value >= F_FN && value <= L_FN)
643				printf(" F(%2d),", value - F_FN + 1);
644	 		else if (value >= F_SCR && value <= L_SCR)
645				printf(" S(%2d),", value - F_SCR + 1);
646	 		else if (value >= F_ACC && value <= L_ACC)
647				printf(" %-4s, ", acc_names_u[value - F_ACC]);
648			else
649				printf(" 0x%02X, ", value);
650			break;
651		}
652	} else if (value == '\'') {
653		printf(" '\\'', ");
654	} else if (value == '\\') {
655		printf(" '\\\\', ");
656	} else if (isascii(value) && isprint(value)) {
657		printf("  '%c', ", value);
658	} else {
659		printf(" 0x%02X, ", value);
660	}
661}
662
663void
664dump_key_definition(char *name, keymap_t *keymap)
665{
666	int	i, j;
667
668	printf("static keymap_t keymap_%s = { 0x%02x, {\n",
669	       name, (unsigned)keymap->n_keys);
670	printf(
671"/*                                                         alt\n"
672" * scan                       cntrl          alt    alt   cntrl\n"
673" * code  base   shift  cntrl  shift   alt   shift  cntrl  shift    spcl flgs\n"
674" * ---------------------------------------------------------------------------\n"
675" */\n");
676	for (i = 0; i < keymap->n_keys; i++) {
677		printf("/*%02x*/{{", i);
678		for (j = 0; j < NUM_STATES; j++) {
679			if (keymap->key[i].spcl & (0x80 >> j))
680				dump_entry(keymap->key[i].map[j] | 0x100);
681			else
682				dump_entry(keymap->key[i].map[j]);
683		}
684		printf("}, 0x%02X,0x%02X },\n",
685		       (unsigned)keymap->key[i].spcl,
686		       (unsigned)keymap->key[i].flgs);
687	}
688	printf("} };\n\n");
689}
690
691void
692dump_accent_definition(char *name, accentmap_t *accentmap)
693{
694	int i, j;
695	int c;
696
697	printf("static accentmap_t accentmap_%s = { %d",
698		name, accentmap->n_accs);
699	if (accentmap->n_accs <= 0) {
700		printf(" };\n\n");
701		return;
702	}
703	printf(", {\n");
704	for (i = 0; i < NUM_DEADKEYS; i++) {
705		printf("    /* %s=%d */\n    {", acc_names[i], i);
706		c = accentmap->acc[i].accchar;
707		if (c == '\'')
708			printf(" '\\'', {");
709		else if (c == '\\')
710			printf(" '\\\\', {");
711		else if (isascii(c) && isprint(c))
712			printf("  '%c', {", c);
713		else if (c == 0) {
714			printf(" 0x00 }, \n");
715			continue;
716		} else
717			printf(" 0x%02x, {", c);
718		for (j = 0; j < NUM_ACCENTCHARS; j++) {
719			c = accentmap->acc[i].map[j][0];
720			if (c == 0)
721				break;
722			if ((j > 0) && ((j % 4) == 0))
723				printf("\n\t     ");
724			if (isascii(c) && isprint(c))
725				printf(" {  '%c',", c);
726			else
727				printf(" { 0x%02x,", c);
728			printf("0x%02x },", accentmap->acc[i].map[j][1]);
729		}
730		printf(" }, },\n");
731	}
732	printf("} };\n\n");
733}
734
735void
736load_keymap(char *opt, int dumponly)
737{
738	keymap_t keymap;
739	accentmap_t accentmap;
740	FILE	*fd;
741	int	i;
742	char	*name, *cp;
743	char	*prefix[]  = {"", "", KEYMAP_PATH, KEYMAP_PATH, NULL};
744	char	*postfix[] = {"", ".kbd", "", ".kbd"};
745
746	for (i=0; prefix[i]; i++) {
747		name = mkfullname(prefix[i], opt, postfix[i]);
748		if ((fd = fopen(name, "r")))
749			break;
750	}
751	if (fd == NULL) {
752		warn("keymap file not found");
753		return;
754	}
755	memset(&keymap, 0, sizeof(keymap));
756	memset(&accentmap, 0, sizeof(accentmap));
757	token = -1;
758	while (1) {
759		if (get_definition_line(fd, &keymap, &accentmap) < 0)
760			break;
761    	}
762	if (dumponly) {
763		/* fix up the filename to make it a valid C identifier */
764		for (cp = opt; *cp; cp++)
765			if (!isalpha(*cp) && !isdigit(*cp)) *cp = '_';
766		printf("/*\n"
767		       " * Automatically generated from %s.\n"
768	               " * DO NOT EDIT!\n"
769		       " */\n", name);
770		dump_key_definition(opt, &keymap);
771		dump_accent_definition(opt, &accentmap);
772		return;
773	}
774	if ((keymap.n_keys > 0) && (ioctl(0, PIO_KEYMAP, &keymap) < 0)) {
775		warn("setting keymap");
776		fclose(fd);
777		return;
778	}
779	if ((accentmap.n_accs > 0)
780		&& (ioctl(0, PIO_DEADKEYMAP, &accentmap) < 0)) {
781		warn("setting accentmap");
782		fclose(fd);
783		return;
784	}
785}
786
787void
788print_keymap()
789{
790	keymap_t keymap;
791	accentmap_t accentmap;
792	int i;
793
794	if (ioctl(0, GIO_KEYMAP, &keymap) < 0)
795		err(1, "getting keymap");
796	if (ioctl(0, GIO_DEADKEYMAP, &accentmap) < 0)
797		memset(&accentmap, 0, sizeof(accentmap));
798    	printf(
799"#                                                         alt\n"
800"# scan                       cntrl          alt    alt   cntrl lock\n"
801"# code  base   shift  cntrl  shift  alt    shift  cntrl  shift state\n"
802"# ------------------------------------------------------------------\n"
803    	);
804	for (i=0; i<keymap.n_keys; i++)
805		print_key_definition_line(stdout, i, &keymap.key[i]);
806
807	printf("\n");
808	for (i = 0; i < NUM_DEADKEYS; i++)
809		print_accent_definition_line(stdout, i, &accentmap.acc[i]);
810
811}
812
813
814void
815load_default_functionkeys()
816{
817	fkeyarg_t fkey;
818	int i;
819
820	for (i=0; i<NUM_FKEYS; i++) {
821		fkey.keynum = i;
822		strcpy(fkey.keydef, fkey_table[i]);
823		fkey.flen = strlen(fkey_table[i]);
824		if (ioctl(0, SETFKEY, &fkey) < 0)
825			warn("setting function key");
826	}
827}
828
829void
830set_functionkey(char *keynumstr, char *string)
831{
832	fkeyarg_t fkey;
833
834	if (!strcmp(keynumstr, "load") && !strcmp(string, "default")) {
835		load_default_functionkeys();
836		return;
837	}
838	fkey.keynum = atoi(keynumstr);
839	if (fkey.keynum < 1 || fkey.keynum > NUM_FKEYS) {
840		warnx("function key number must be between 1 and %d",
841			NUM_FKEYS);
842		return;
843	}
844	if ((fkey.flen = strlen(string)) > MAXFK) {
845		warnx("function key string too long (%d > %d)",
846			fkey.flen, MAXFK);
847		return;
848	}
849	strcpy(fkey.keydef, string);
850	fkey.keynum -= 1;
851	if (ioctl(0, SETFKEY, &fkey) < 0)
852		warn("setting function key");
853}
854
855
856void
857set_bell_values(char *opt)
858{
859	int bell, duration, pitch;
860
861	bell = 0;
862	if (!strncmp(opt, "quiet.", 6)) {
863		bell = 2;
864		opt += 6;
865	}
866	if (!strcmp(opt, "visual"))
867		bell |= 1;
868	else if (!strcmp(opt, "normal"))
869		duration = 5, pitch = 800;
870	else if (!strcmp(opt, "off"))
871		duration = 0, pitch = 0;
872	else {
873		char		*v1;
874
875		bell = 0;
876		duration = strtol(opt, &v1, 0);
877		if ((duration < 0) || (*v1 != '.'))
878			goto badopt;
879		opt = ++v1;
880		pitch = strtol(opt, &v1, 0);
881		if ((pitch < 0) || (*opt == '\0') || (*v1 != '\0')) {
882badopt:
883			warnx("argument to -b must be DURATION.PITCH");
884			return;
885		}
886		if (pitch != 0)
887			pitch = 1193182 / pitch;	/* in Hz */
888		duration /= 10;	/* in 10 m sec */
889	}
890
891	ioctl(0, CONS_BELLTYPE, &bell);
892	if ((bell & ~2) == 0)
893		fprintf(stderr, "[=%d;%dB", pitch, duration);
894}
895
896
897void
898set_keyrates(char *opt)
899{
900	int arg[2];
901	int repeat;
902	int delay;
903	int r, d;
904
905	if (!strcmp(opt, "slow")) {
906		delay = 1000, repeat = 500;
907		d = 3, r = 31;
908	} else if (!strcmp(opt, "normal")) {
909		delay = 500, repeat = 125;
910		d = 1, r = 15;
911	} else if (!strcmp(opt, "fast")) {
912		delay = repeat = 0;
913		d = r = 0;
914	} else {
915		int		n;
916		char		*v1;
917
918		delay = strtol(opt, &v1, 0);
919		if ((delay < 0) || (*v1 != '.'))
920			goto badopt;
921		opt = ++v1;
922		repeat = strtol(opt, &v1, 0);
923		if ((repeat < 0) || (*opt == '\0') || (*v1 != '\0')) {
924badopt:
925			warnx("argument to -r must be delay.repeat");
926			return;
927		}
928		for (n = 0; n < ndelays - 1; n++)
929			if (delay <= delays[n])
930				break;
931		d = n;
932		for (n = 0; n < nrepeats - 1; n++)
933			if (repeat <= repeats[n])
934				break;
935		r = n;
936	}
937
938	arg[0] = delay;
939	arg[1] = repeat;
940	if (ioctl(0, KDSETREPEAT, arg)) {
941		if (ioctl(0, KDSETRAD, (d << 5) | r))
942			warn("setting keyboard rate");
943	}
944}
945
946
947void
948set_history(char *opt)
949{
950	int size;
951
952	size = atoi(opt);
953	if ((*opt == '\0') || size < 0) {
954		warnx("argument must be a positive number");
955		return;
956	}
957	if (ioctl(0, CONS_HISTORY, &size) == -1)
958		warn("setting history buffer size");
959}
960
961static char
962*get_kbd_type_name(int type)
963{
964	static struct {
965		int type;
966		char *name;
967	} name_table[] = {
968		{ KB_84,	"AT 84" },
969		{ KB_101,	"AT 101/102" },
970		{ KB_OTHER,	"generic" },
971	};
972	int i;
973
974	for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) {
975		if (type == name_table[i].type)
976			return name_table[i].name;
977	}
978	return "unknown";
979}
980
981void
982show_kbd_info(void)
983{
984	keyboard_info_t info;
985
986	if (ioctl(0, KDGKBINFO, &info) == -1) {
987		warn("unable to obtain keyboard information");
988		return;
989	}
990	printf("kbd%d:\n", info.kb_index);
991	printf("    %.*s%d, type:%s (%d)\n",
992		sizeof(info.kb_name), info.kb_name, info.kb_unit,
993		get_kbd_type_name(info.kb_type), info.kb_type);
994}
995
996
997void
998set_keyboard(char *device)
999{
1000	keyboard_info_t info;
1001	int fd;
1002
1003	fd = open(device, O_RDONLY);
1004	if (fd < 0) {
1005		warn("cannot open %s", device);
1006		return;
1007	}
1008	if (ioctl(fd, KDGKBINFO, &info) == -1) {
1009		warn("unable to obtain keyboard information");
1010		close(fd);
1011		return;
1012	}
1013	/*
1014	 * The keyboard device driver won't release the keyboard by
1015	 * the following ioctl, but it automatically will, when the device
1016	 * is closed.  So, we don't check error here.
1017	 */
1018	ioctl(fd, CONS_RELKBD, 0);
1019	close(fd);
1020#if 1
1021	printf("kbd%d\n", info.kb_index);
1022	printf("    %.*s%d, type:%s (%d)\n",
1023		sizeof(info.kb_name), info.kb_name, info.kb_unit,
1024		get_kbd_type_name(info.kb_type), info.kb_type);
1025#endif
1026
1027	if (ioctl(0, CONS_SETKBD, info.kb_index) == -1)
1028		warn("unable to set keyboard");
1029}
1030
1031
1032void
1033release_keyboard(void)
1034{
1035	keyboard_info_t info;
1036
1037	/*
1038	 * If stdin is not associated with a keyboard, the following ioctl
1039	 * will fail.
1040	 */
1041	if (ioctl(0, KDGKBINFO, &info) == -1) {
1042		warn("unable to obtain keyboard information");
1043		return;
1044	}
1045#if 1
1046	printf("kbd%d\n", info.kb_index);
1047	printf("    %.*s%d, type:%s (%d)\n",
1048		sizeof(info.kb_name), info.kb_name, info.kb_unit,
1049		get_kbd_type_name(info.kb_type), info.kb_type);
1050#endif
1051	if (ioctl(0, CONS_RELKBD, 0) == -1)
1052		warn("unable to release the keyboard");
1053}
1054
1055
1056static void
1057usage()
1058{
1059	fprintf(stderr, "%s\n%s\n%s\n",
1060"usage: kbdcontrol [-dFKix] [-b  duration.pitch | [quiet.]belltype]",
1061"                  [-r delay.repeat | speed] [-l mapfile] [-f # string]",
1062"                  [-h size] [-k device] [-L mapfile]");
1063	exit(1);
1064}
1065
1066
1067int
1068main(int argc, char **argv)
1069{
1070	int		opt;
1071
1072	while((opt = getopt(argc, argv, "b:df:h:iKk:Fl:L:r:x")) != -1)
1073		switch(opt) {
1074			case 'b':
1075				set_bell_values(optarg);
1076				break;
1077			case 'd':
1078				print_keymap();
1079				break;
1080			case 'l':
1081				load_keymap(optarg, 0);
1082				break;
1083			case 'L':
1084				load_keymap(optarg, 1);
1085				break;
1086			case 'f':
1087				set_functionkey(optarg,
1088					nextarg(argc, argv, &optind, 'f'));
1089				break;
1090			case 'F':
1091				load_default_functionkeys();
1092				break;
1093			case 'h':
1094				set_history(optarg);
1095				break;
1096			case 'i':
1097				show_kbd_info();
1098				break;
1099			case 'K':
1100				release_keyboard();
1101				break;
1102			case 'k':
1103				set_keyboard(optarg);
1104				break;
1105			case 'r':
1106				set_keyrates(optarg);
1107				break;
1108			case 'x':
1109				hex = 1;
1110				break;
1111			default:
1112				usage();
1113		}
1114	if ((optind != argc) || (argc == 1))
1115		usage();
1116	exit(0);
1117}
1118
1119
1120