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