xref: /freebsd/usr.sbin/kbdcontrol/kbdcontrol.c (revision e627b39baccd1ec9129690167cf5e6d860509655)
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: kbdcontrol.c,v 1.6.2.1 1995/06/05 09:23:13 davidg Exp $
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)
336 {
337 	keymap_t map;
338 	FILE	*fd;
339 	int	scancode, i;
340 	char	*name;
341 	char	*prefix[]  = {"", "", KEYMAP_PATH, NULL};
342 	char	*postfix[] = {"", ".kbd", ".kbd"};
343 
344 	for (i=0; prefix[i]; i++) {
345 		name = mkfullname(prefix[i], opt, postfix[i]);
346 		if (fd = fopen(name, "r"))
347 			break;
348 	}
349 	if (fd == NULL) {
350 		perror("keymap file not found");
351 		return;
352 	}
353 	memset(&map, 0, sizeof(map));
354 	while (1) {
355 		if ((scancode = get_key_definition_line(fd, &map)) < 0)
356 			break;
357 		if (scancode > map.n_keys) map.n_keys = scancode;
358     	}
359 	if (ioctl(0, PIO_KEYMAP, &map) < 0) {
360 		perror("setting keymap");
361 		fclose(fd);
362 		return;
363 	}
364 }
365 
366 
367 void
368 print_keymap()
369 {
370 	keymap_t map;
371 	int i;
372 
373 	if (ioctl(0, GIO_KEYMAP, &map) < 0) {
374 		perror("getting keymap");
375 		exit(1);
376 	}
377     	printf(
378 "#                                                         alt\n"
379 "# scan                       cntrl          alt    alt   cntrl lock\n"
380 "# code  base   shift  cntrl  shift  alt    shift  cntrl  shift state\n"
381 "# ------------------------------------------------------------------\n"
382     	);
383 	for (i=0; i<map.n_keys; i++)
384 		print_key_definition_line(stdout, i, &map.key[i]);
385 }
386 
387 
388 void
389 load_default_functionkeys()
390 {
391 	fkeyarg_t fkey;
392 	int i;
393 
394 	for (i=0; i<NUM_FKEYS; i++) {
395 		fkey.keynum = i;
396 		strcpy(fkey.keydef, fkey_table[i]);
397 		fkey.flen = strlen(fkey_table[i]);
398 		if (ioctl(0, SETFKEY, &fkey) < 0)
399 			perror("setting function key");
400 	}
401 }
402 
403 void
404 set_functionkey(char *keynumstr, char *string)
405 {
406 	fkeyarg_t fkey;
407 	int keynum;
408 
409 	if (!strcmp(keynumstr, "load") && !strcmp(string, "default")) {
410 		load_default_functionkeys();
411 		return;
412 	}
413 	fkey.keynum = atoi(keynumstr);
414 	if (fkey.keynum < 1 || fkey.keynum > NUM_FKEYS) {
415 		fprintf(stderr,
416 			"function key number must be between 1 and %d\n",
417 			NUM_FKEYS);
418 		return;
419 	}
420 	if ((fkey.flen = strlen(string)) > MAXFK) {
421 		fprintf(stderr, "function key string too long (%d > %d)\n",
422 			fkey.flen, MAXFK);
423 		return;
424 	}
425 	strcpy(fkey.keydef, string);
426 	fkey.keynum -= 1;
427 	if (ioctl(0, SETFKEY, &fkey) < 0)
428 		perror("setting function key");
429 }
430 
431 
432 void
433 set_bell_values(char *opt)
434 {
435 	int bell, duration, pitch;
436 
437 	if (!strcmp(opt, "visual"))
438 		bell = 1, duration = 1, pitch = 800;
439 	else if (!strcmp(opt, "normal"))
440 		bell = 0, duration = 1, pitch = 800;
441 	else {
442 		int		n;
443 		char		*v1;
444 
445 		bell = 0;
446 		duration = strtol(opt, &v1, 0);
447 		if ((duration < 0) || (*v1 != '.'))
448 			goto badopt;
449 		opt = ++v1;
450 		pitch = strtol(opt, &v1, 0);
451 		if ((pitch < 0) || (*opt == '\0') || (*v1 != '\0')) {
452 badopt:
453 			fprintf(stderr,
454 				"argument to -b must be DURATION.PITCH\n");
455 			return;
456 		}
457 	}
458 
459 	ioctl(0, CONS_BELLTYPE, &bell);
460 	if (!bell)
461 		fprintf(stderr, "[=%d;%dB", pitch, duration);
462 }
463 
464 
465 void
466 set_keyrates(char *opt)
467 {
468 struct	{
469 	int	rep:5;
470 	int	del:2;
471 	int	pad:1;
472 	}rate;
473 
474 	if (!strcmp(opt, "slow"))
475 		rate.del = 3, rate.rep = 31;
476 	else if (!strcmp(opt, "normal"))
477 		rate.del = 1, rate.rep = 15;
478 	else if (!strcmp(opt, "fast"))
479 		rate.del = rate.rep = 0;
480 	else {
481 		int		n;
482 		int		delay, repeat;
483 		char		*v1;
484 
485 		delay = strtol(opt, &v1, 0);
486 		if ((delay < 0) || (*v1 != '.'))
487 			goto badopt;
488 		opt = ++v1;
489 		repeat = strtol(opt, &v1, 0);
490 		if ((repeat < 0) || (*opt == '\0') || (*v1 != '\0')) {
491 badopt:
492 			fprintf(stderr,
493 				"argument to -r must be delay.repeat\n");
494 			return;
495 		}
496 		for (n = 0; n < ndelays - 1; n++)
497 			if (delay <= delays[n])
498 				break;
499 		rate.del = n;
500 		for (n = 0; n < nrepeats - 1; n++)
501 			if (repeat <= repeats[n])
502 				break;
503 		rate.rep = n;
504 	}
505 
506 	if (ioctl(0, KDSETRAD, rate) < 0)
507 		perror("setting keyboard rate");
508 }
509 
510 
511 void
512 set_history(char *opt)
513 {
514 	int size;
515 
516 	size = atoi(opt);
517 	if ((*opt == '\0') || size < 0) {
518 		fprintf(stderr, "argument must be a positive number\n");
519 		return;
520 	}
521 	if (ioctl(0, CONS_HISTORY, &size) == -1)
522 		perror("setting history buffer size");
523 }
524 
525 
526 usage()
527 {
528 	fprintf(stderr,
529 "Usage: kbdcontrol -b duration.pitch   (set bell duration & pitch)\n"
530 "                  -b normal | visual  (set bell to visual type)\n"
531 "                  -d                  (dump keyboard map to stdout)\n"
532 "                  -l filename         (load keyboard map file)\n"
533 "                  -h <N>              (set history buffer size (in lines))\n"
534 "                  -f <N> string       (set function key N to send <string>)\n"
535 "                  -F                  (set function keys back to default)\n"
536 "                  -r delay.repeat     (set keyboard delay & repeat rate)\n"
537 "                  -r slow             (set keyboard delay & repeat to slow)\n"
538 "                  -r normal           (set keyboard delay & repeat to normal)\n"
539 "                  -r fast             (set keyboard delay & repeat to fast)\n"
540 "                  -x                  (use hexadecimal numbers in -d option)\n"
541 	);
542 }
543 
544 
545 void
546 main(int argc, char **argv)
547 {
548 	extern char	*optarg;
549 	extern int	optind;
550 	int		opt;
551 
552 	while((opt = getopt(argc, argv, "b:df:h:Fl:r:x")) != -1)
553 		switch(opt) {
554 			case 'b':
555 				set_bell_values(optarg);
556 				break;
557 			case 'd':
558 				print_keymap();
559 				break;
560 			case 'l':
561 				load_keymap(optarg);
562 				break;
563 			case 'f':
564 				set_functionkey(optarg,
565 					nextarg(argc, argv, &optind, 'f'));
566 				break;
567 			case 'F':
568 				load_default_functionkeys();
569 				break;
570 			case 'h':
571 				set_history(optarg);
572 				break;
573 			case 'r':
574 				set_keyrates(optarg);
575 				break;
576 			case 'x':
577 				hex = 1;
578 				break;
579 			default:
580 				usage();
581 				exit(1);
582 		}
583 	if ((optind != argc) || (argc == 1)) {
584 		usage();
585 		exit(1);
586 	}
587 	exit(0);
588 }
589 
590 
591