xref: /freebsd/usr.sbin/kbdcontrol/kbdcontrol.c (revision 952d112864d8008aa87278a30a539d888a8493cd)
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  *	$Id$
29  */
30 
31 #include <ctype.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <machine/console.h>
35 #include "path.h"
36 #include "lex.h"
37 
38 char ctrl_names[32][4] = {
39 	"nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
40 	"bs ", "ht ", "nl ", "vt ", "ff ", "cr ", "so ", "si ",
41 	"dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
42 	"can", "em ", "sub", "esc", "fs ", "gs ", "rs ", "ns "
43 	};
44 
45 char fkey_table[96][MAXFK] = {
46 /* 01-04 */	"\033[M", "\033[N", "\033[O", "\033[P",
47 /* 05-08 */	"\033[Q", "\033[R", "\033[S", "\033[T",
48 /* 09-12 */	"\033[U", "\033[V", "\033[W", "\033[X",
49 /* 13-16 */	"\033[Y", "\033[Z", "\033[a", "\033[b",
50 /* 17-20 */	"\033[c", "\033[d", "\033[e", "\033[f",
51 /* 21-24 */	"\033[g", "\033[h", "\033[i", "\033[j",
52 /* 25-28 */	"\033[k", "\033[l", "\033[m", "\033[n",
53 /* 29-32 */	"\033[o", "\033[p", "\033[q", "\033[r",
54 /* 33-36 */	"\033[s", "\033[t", "\033[u", "\033[v",
55 /* 37-40 */	"\033[w", "\033[x", "\033[y", "\033[z",
56 /* 41-44 */	"\033[@", "\033[[", "\033[\\","\033[]",
57 /* 45-48 */     "\033[^", "\033[_", "\033[`", "\033[{",
58 /* 49-52 */	"\033[H", "\033[A", "\033[I", "-"     ,
59 /* 53-56 */	"\033[D", "\033[E", "\033[C", "+"     ,
60 /* 57-60 */	"\033[F", "\033[B", "\033[G", "\033[L",
61 /* 61-64 */     "\177",   "\033[J", "\033[~", "\033[}",
62 /* 65-68 */	""      , ""      , ""      , ""      ,
63 /* 69-72 */	""      , ""      , ""      , ""      ,
64 /* 73-76 */	""      , ""      , ""      , ""      ,
65 /* 77-80 */	""      , ""      , ""      , ""      ,
66 /* 81-84 */	""      , ""      , ""      , ""      ,
67 /* 85-88 */	""      , ""      , ""      , ""      ,
68 /* 89-92 */	""      , ""      , ""      , ""      ,
69 /* 93-96 */	""      , ""      , ""      , ""      ,
70 	};
71 
72 const int	delays[]  = {250, 500, 750, 1000};
73 const int	repeats[] = { 34,  38,  42,  46,  50,  55,  59,  63,
74 			      68,  76,  84,  92, 100, 110, 118, 126,
75 			     136, 152, 168, 184, 200, 220, 236, 252,
76 			     272, 304, 336, 368, 400, 440, 472, 504};
77 const int	ndelays = (sizeof(delays) / sizeof(int));
78 const int	nrepeats = (sizeof(repeats) / sizeof(int));
79 int 		hex = 0;
80 int 		number;
81 char 		letter;
82 
83 
84 char *
85 nextarg(int ac, char **av, int *indp, int oc)
86 {
87 	if (*indp < ac)
88 		return(av[(*indp)++]);
89 	fprintf(stderr, "%s: option requires two arguments -- %c\n", av[0], oc);
90 	usage();
91 	exit(1);
92 	return("");
93 }
94 
95 
96 char *
97 mkfullname(const char *s1, const char *s2, const char *s3)
98 {
99 	static char	*buf = NULL;
100 	static int	bufl = 0;
101 	int		f;
102 
103 	f = strlen(s1) + strlen(s2) + strlen(s3) + 1;
104 	if (f > bufl)
105 		if (buf)
106 			buf = (char *)realloc(buf, f);
107 		else
108 			buf = (char *)malloc(f);
109 	if (!buf) {
110 		bufl = 0;
111 		return(NULL);
112 	}
113 
114 	bufl = f;
115 	strcpy(buf, s1);
116 	strcat(buf, s2);
117 	strcat(buf, s3);
118 	return(buf);
119 }
120 
121 
122 int
123 get_entry()
124 {
125 	switch (yylex()) {
126 	case TNOP:
127 		return NOP | 0x100;
128 	case TLSH:
129 		return LSH | 0x100;
130 	case TRSH:
131 		return RSH | 0x100;
132 	case TCLK:
133 		return CLK | 0x100;
134 	case TNLK:
135 		return NLK | 0x100;
136 	case TSLK:
137 		return SLK | 0x100;
138 	case TBTAB:
139 		return BTAB | 0x100;
140 	case TLALT:
141 		return LALT | 0x100;
142 	case TLCTR:
143 		return LCTR | 0x100;
144 	case TNEXT:
145 		return NEXT | 0x100;
146 	case TRCTR:
147 		return RCTR | 0x100;
148 	case TRALT:
149 		return RALT | 0x100;
150 	case TALK:
151 		return ALK | 0x100;
152 	case TASH:
153 		return ASH | 0x100;
154 	case TMETA:
155 		return META | 0x100;
156 	case TRBT:
157 		return RBT | 0x100;
158 	case TDBG:
159 		return DBG | 0x100;
160 	case TSUSP:
161 		return SUSP | 0x100;
162 	case TFUNC:
163 		if (F(number) > L_FN)
164 			return -1;
165 		return F(number) | 0x100;
166 	case TSCRN:
167 		if (S(number) > L_SCR)
168 			return -1;
169 		return S(number) | 0x100;
170 	case TLET:
171 		return (unsigned char)letter;
172 	case TNUM:
173 		if (number < 0 || number > 255)
174 			return -1;
175 		return number;
176 	default:
177 		return -1;
178 	}
179 }
180 
181 
182 int
183 get_key_definition_line(FILE* fd, keymap_t *map)
184 {
185 	int i, def, scancode;
186 
187 	yyin = fd;
188 
189 	/* get scancode number */
190 	if (yylex() != TNUM)
191 		return -1;
192 	if (number < 0 || number >= NUM_KEYS)
193 		return -1;
194 	scancode = number;
195 
196 	/* get key definitions */
197 	map->key[scancode].spcl = 0;
198 	for (i=0; i<NUM_STATES; i++) {
199 		if ((def = get_entry()) == -1)
200 			return -1;
201 		if (def & 0x100)
202 			map->key[scancode].spcl |= (0x80 >> i);
203 		map->key[scancode].map[i] = def & 0xFF;
204 	}
205 	/* get lock state key def */
206 	if (yylex() != TFLAG)
207 		return -1;
208 	map->key[scancode].flgs = number;
209 		return scancode;
210 }
211 
212 
213 int
214 print_entry(FILE *fp, int value)
215 {
216 	int val = value & 0xFF;
217 
218 	switch (value) {
219 	case NOP | 0x100:
220 		fprintf(fp, " nop   ");
221 		break;
222 	case LSH | 0x100:
223 		fprintf(fp, " lshift");
224 		break;
225 	case RSH | 0x100:
226 		fprintf(fp, " rshift");
227 		break;
228 	case CLK | 0x100:
229 		fprintf(fp, " clock ");
230 		break;
231 	case NLK | 0x100:
232 		fprintf(fp, " nlock ");
233 		break;
234 	case SLK | 0x100:
235 		fprintf(fp, " slock ");
236 		break;
237 	case BTAB | 0x100:
238 		fprintf(fp, " btab  ");
239 		break;
240 	case LALT | 0x100:
241 		fprintf(fp, " lalt  ");
242 		break;
243 	case LCTR | 0x100:
244 		fprintf(fp, " lctrl ");
245 		break;
246 	case NEXT | 0x100:
247 		fprintf(fp, " nscr  ");
248 		break;
249 	case RCTR | 0x100:
250 		fprintf(fp, " rctrl ");
251 		break;
252 	case RALT | 0x100:
253 		fprintf(fp, " ralt  ");
254 		break;
255 	case ALK | 0x100:
256 		fprintf(fp, " alock ");
257 		break;
258 	case ASH | 0x100:
259 		fprintf(fp, " ashift");
260 		break;
261 	case META | 0x100:
262 		fprintf(fp, " meta  ");
263 		break;
264 	case RBT | 0x100:
265 		fprintf(fp, " boot  ");
266 		break;
267 	case DBG | 0x100:
268 		fprintf(fp, " debug ");
269 		break;
270 	default:
271 		if (value & 0x100) {
272 		 	if (val >= F_FN && val <= L_FN)
273 				fprintf(fp, " fkey%02d", val - F_FN + 1);
274 		 	else if (val >= F_SCR && val <= L_SCR)
275 				fprintf(fp, " scr%02d ", val - F_SCR + 1);
276 			else if (hex)
277 				fprintf(fp, " 0x%02x  ", val);
278 			else
279 				fprintf(fp, "  %3d  ", val);
280 		}
281 		else {
282 			if (val < ' ')
283 				fprintf(fp, " %s   ", ctrl_names[val]);
284 			else if (val == 127)
285 				fprintf(fp, " del   ");
286 			else if (isascii(val) && isprint(val))
287 				fprintf(fp, " '%c'   ", val);
288 			else if (hex)
289 				fprintf(fp, " 0x%02x  ", val);
290 			else
291 				fprintf(fp, " %3d   ", val);
292 		}
293 	}
294 }
295 
296 
297 void
298 print_key_definition_line(FILE *fp, int scancode, struct key_t *key)
299 {
300 	int i, value;
301 
302 	/* print scancode number */
303 	if (hex)
304 		fprintf(fp, " 0x%02x  ", scancode);
305 	else
306 		fprintf(fp, "  %03d  ", scancode);
307 
308 	/* print key definitions */
309 	for (i=0; i<NUM_STATES; i++) {
310 		if (key->spcl & (0x80 >> i))
311 			print_entry(fp, key->map[i] | 0x100);
312 		else
313 			print_entry(fp, key->map[i]);
314 	}
315 
316 	/* print lock state key def */
317 	switch (key->flgs) {
318 	case 0:
319 		fprintf(fp, "  O\n");
320 		break;
321 	case 1:
322 		fprintf(fp, "  C\n");
323 		break;
324 	case 2:
325 		fprintf(fp, "  N\n");
326 		break;
327 	case 3:
328 		fprintf(fp, "  B\n");
329 		break;
330 	}
331 }
332 
333 
334 void
335 load_keymap(char *opt, int dumponly)
336 {
337 	keymap_t map;
338 	FILE	*fd;
339 	int	scancode, i, j;
340 	struct key_t *kp;
341 	char	*name, *cp;
342 	char	*prefix[]  = {"", "", KEYMAP_PATH, NULL};
343 	char	*postfix[] = {"", ".kbd", ".kbd"};
344 
345 	for (i=0; prefix[i]; i++) {
346 		name = mkfullname(prefix[i], opt, postfix[i]);
347 		if (fd = fopen(name, "r"))
348 			break;
349 	}
350 	if (fd == NULL) {
351 		perror("keymap file not found");
352 		return;
353 	}
354 	memset(&map, 0, sizeof(map));
355 	while (1) {
356 		if ((scancode = get_key_definition_line(fd, &map)) < 0)
357 			break;
358 		if (scancode > map.n_keys) map.n_keys = scancode;
359     	}
360 	if (dumponly) {
361 		/* fix up the filename to make it a valid C identifier */
362 		for (cp = opt; *cp; cp++)
363 			if (!isalpha(*cp) && !isdigit(*cp)) *cp = '_';
364 		printf("static const struct keymap keymap_%s = {\n"
365 		       "/*\n * Automatically generated from %s.\n"
366 		       " * DO NOT EDIT!\n */\n\n\t%u,\n{\n",
367 		       opt, name, (unsigned)map.n_keys);
368 		for (i = 0; i < map.n_keys; i++) {
369 			kp = &map.key[i];
370 
371 			printf("\t{{ ");
372 			for (j = 0; j < NUM_STATES; j++)
373 				printf("0x%02x%c", (unsigned)kp->map[j],
374 					j == NUM_STATES-1? '}': ',');
375 			printf(", 0x%x, 0x%x },\n",
376 			       (unsigned)kp->spcl, (unsigned)kp->flgs);
377 		}
378 		printf("}\n};\n\n");
379 		return;
380 	}
381 	if (ioctl(0, PIO_KEYMAP, &map) < 0) {
382 		perror("setting keymap");
383 		fclose(fd);
384 		return;
385 	}
386 }
387 
388 
389 void
390 print_keymap()
391 {
392 	keymap_t map;
393 	int i;
394 
395 	if (ioctl(0, GIO_KEYMAP, &map) < 0) {
396 		perror("getting keymap");
397 		exit(1);
398 	}
399     	printf(
400 "#                                                         alt\n"
401 "# scan                       cntrl          alt    alt   cntrl lock\n"
402 "# code  base   shift  cntrl  shift  alt    shift  cntrl  shift state\n"
403 "# ------------------------------------------------------------------\n"
404     	);
405 	for (i=0; i<map.n_keys; i++)
406 		print_key_definition_line(stdout, i, &map.key[i]);
407 }
408 
409 
410 void
411 load_default_functionkeys()
412 {
413 	fkeyarg_t fkey;
414 	int i;
415 
416 	for (i=0; i<NUM_FKEYS; i++) {
417 		fkey.keynum = i;
418 		strcpy(fkey.keydef, fkey_table[i]);
419 		fkey.flen = strlen(fkey_table[i]);
420 		if (ioctl(0, SETFKEY, &fkey) < 0)
421 			perror("setting function key");
422 	}
423 }
424 
425 void
426 set_functionkey(char *keynumstr, char *string)
427 {
428 	fkeyarg_t fkey;
429 	int keynum;
430 
431 	if (!strcmp(keynumstr, "load") && !strcmp(string, "default")) {
432 		load_default_functionkeys();
433 		return;
434 	}
435 	fkey.keynum = atoi(keynumstr);
436 	if (fkey.keynum < 1 || fkey.keynum > NUM_FKEYS) {
437 		fprintf(stderr,
438 			"function key number must be between 1 and %d\n",
439 			NUM_FKEYS);
440 		return;
441 	}
442 	if ((fkey.flen = strlen(string)) > MAXFK) {
443 		fprintf(stderr, "function key string too long (%d > %d)\n",
444 			fkey.flen, MAXFK);
445 		return;
446 	}
447 	strcpy(fkey.keydef, string);
448 	fkey.keynum -= 1;
449 	if (ioctl(0, SETFKEY, &fkey) < 0)
450 		perror("setting function key");
451 }
452 
453 
454 void
455 set_bell_values(char *opt)
456 {
457 	int bell, duration, pitch;
458 
459 	if (!strcmp(opt, "visual"))
460 		bell = 1, duration = 1, pitch = 800;
461 	else if (!strcmp(opt, "normal"))
462 		bell = 0, duration = 1, pitch = 800;
463 	else {
464 		int		n;
465 		char		*v1;
466 
467 		bell = 0;
468 		duration = strtol(opt, &v1, 0);
469 		if ((duration < 0) || (*v1 != '.'))
470 			goto badopt;
471 		opt = ++v1;
472 		pitch = strtol(opt, &v1, 0);
473 		if ((pitch < 0) || (*opt == '\0') || (*v1 != '\0')) {
474 badopt:
475 			fprintf(stderr,
476 				"argument to -b must be DURATION.PITCH\n");
477 			return;
478 		}
479 	}
480 
481 	ioctl(0, CONS_BELLTYPE, &bell);
482 	if (!bell)
483 		fprintf(stderr, "[=%d;%dB", pitch, duration);
484 }
485 
486 
487 void
488 set_keyrates(char *opt)
489 {
490 struct	{
491 	int	rep:5;
492 	int	del:2;
493 	int	pad:1;
494 	}rate;
495 
496 	if (!strcmp(opt, "slow"))
497 		rate.del = 3, rate.rep = 31;
498 	else if (!strcmp(opt, "normal"))
499 		rate.del = 1, rate.rep = 15;
500 	else if (!strcmp(opt, "fast"))
501 		rate.del = rate.rep = 0;
502 	else {
503 		int		n;
504 		int		delay, repeat;
505 		char		*v1;
506 
507 		delay = strtol(opt, &v1, 0);
508 		if ((delay < 0) || (*v1 != '.'))
509 			goto badopt;
510 		opt = ++v1;
511 		repeat = strtol(opt, &v1, 0);
512 		if ((repeat < 0) || (*opt == '\0') || (*v1 != '\0')) {
513 badopt:
514 			fprintf(stderr,
515 				"argument to -r must be delay.repeat\n");
516 			return;
517 		}
518 		for (n = 0; n < ndelays - 1; n++)
519 			if (delay <= delays[n])
520 				break;
521 		rate.del = n;
522 		for (n = 0; n < nrepeats - 1; n++)
523 			if (repeat <= repeats[n])
524 				break;
525 		rate.rep = n;
526 	}
527 
528 	if (ioctl(0, KDSETRAD, rate) < 0)
529 		perror("setting keyboard rate");
530 }
531 
532 
533 void
534 set_history(char *opt)
535 {
536 	int size;
537 
538 	size = atoi(opt);
539 	if ((*opt == '\0') || size < 0) {
540 		fprintf(stderr, "argument must be a positive number\n");
541 		return;
542 	}
543 	if (ioctl(0, CONS_HISTORY, &size) == -1)
544 		perror("setting history buffer size");
545 }
546 
547 
548 usage()
549 {
550 	fprintf(stderr,
551 "Usage: kbdcontrol -b duration.pitch   (set bell duration & pitch)\n"
552 "                  -b normal | visual  (set bell to visual type)\n"
553 "                  -d                  (dump keyboard map to stdout)\n"
554 "                  -l filename         (load keyboard map file)\n"
555 "                  -h <N>              (set history buffer size (in lines))\n"
556 "                  -f <N> string       (set function key N to send <string>)\n"
557 "                  -F                  (set function keys back to default)\n"
558 "                  -r delay.repeat     (set keyboard delay & repeat rate)\n"
559 "                  -r slow             (set keyboard delay & repeat to slow)\n"
560 "                  -r normal           (set keyboard delay & repeat to normal)\n"
561 "                  -r fast             (set keyboard delay & repeat to fast)\n"
562 "                  -x                  (use hexadecimal numbers in -d option)\n"
563 	);
564 }
565 
566 
567 void
568 main(int argc, char **argv)
569 {
570 	extern char	*optarg;
571 	extern int	optind;
572 	int		opt;
573 
574 	while((opt = getopt(argc, argv, "b:df:h:Fl:L:r:x")) != -1)
575 		switch(opt) {
576 			case 'b':
577 				set_bell_values(optarg);
578 				break;
579 			case 'd':
580 				print_keymap();
581 				break;
582 			case 'l':
583 				load_keymap(optarg, 0);
584 				break;
585 			case 'L':
586 				load_keymap(optarg, 1);
587 				break;
588 			case 'f':
589 				set_functionkey(optarg,
590 					nextarg(argc, argv, &optind, 'f'));
591 				break;
592 			case 'F':
593 				load_default_functionkeys();
594 				break;
595 			case 'h':
596 				set_history(optarg);
597 				break;
598 			case 'r':
599 				set_keyrates(optarg);
600 				break;
601 			case 'x':
602 				hex = 1;
603 				break;
604 			default:
605 				usage();
606 				exit(1);
607 		}
608 	if ((optind != argc) || (argc == 1)) {
609 		usage();
610 		exit(1);
611 	}
612 	exit(0);
613 }
614 
615 
616