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