1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22#ifndef lint
23#ident	"%Z%%M%	%I%	%E% SMI"
24#endif
25
26/*
27 * Copyright (c) 1988 by Sun Microsystems, Inc.
28 */
29
30#include <sys/types.h>
31#include <ctype.h>
32#include <stdio.h>
33#include <fcntl.h>
34#include <sys/kbd.h>
35#include <sys/kbio.h>
36#include <errno.h>
37
38typedef enum {
39	SM_INVALID,	/* this shift mask is invalid for this keyboard */
40	SM_NORMAL,	/* "normal", valid shift mask */
41	SM_NUMLOCK,	/* "Num Lock" shift mask */
42	SM_UP		/* "Up" shift mask */
43} smtype_t;
44
45typedef struct {
46	char	*sm_name;
47	int	sm_mask;
48	smtype_t sm_type;
49} smentry_t;
50
51
52smentry_t shiftmasks[] = {
53	{ "base",	0,		SM_NORMAL },
54	{ "shift",	SHIFTMASK,	SM_NORMAL },
55	{ "caps",	CAPSMASK,	SM_NORMAL },
56	{ "ctrl",	CTRLMASK,	SM_NORMAL },
57	{ "altg",	ALTGRAPHMASK,	SM_NORMAL },
58	{ "numl",	NUMLOCKMASK,	SM_NUMLOCK },
59	{ "up",		UPMASK,		SM_UP },
60};
61
62#define	NSHIFTS	(sizeof (shiftmasks) / sizeof (shiftmasks[0]))
63
64static void	printentry(struct kiockeymap *kio);
65static void	printchar(int character, int delim);
66
67/*ARGSUSED*/
68int
69main(argc, argv)
70	int argc;
71	char **argv;
72{
73	register int kbdfd;
74	register int keystation;
75	register int shift;
76	int ktype;
77	struct kiockeymap keyentry[NSHIFTS];
78	register int allsame;
79
80	if ((kbdfd = open("/dev/kbd", O_WRONLY)) < 0) {
81		perror("dumpkeys: /dev/kbd");
82		return (1);
83	}
84	if (ioctl(kbdfd, KIOCTYPE, &ktype) < 0) {
85		perror("dumpkeys: ioctl(KIOCTYPE)");
86		return (1);
87	}
88	/* if no keyboard detected, or ascii terminal, exit silently */
89	if (ktype == KB_ASCII || ktype < 0)
90		exit(0);
91
92	/*
93	 * See which shift masks are valid for this keyboard.
94	 * We do that by trying to get the entry for keystation 0 and that
95	 * shift mask; if the "ioctl" fails, we assume it's because the shift
96	 * mask is invalid.
97	 */
98	for (shift = 0; shift < NSHIFTS; shift++) {
99		keyentry[shift].kio_tablemask =
100		    shiftmasks[shift].sm_mask;
101		keyentry[shift].kio_station = 0;
102		if (ioctl(kbdfd, KIOCGKEY, &keyentry[shift]) < 0)
103			shiftmasks[shift].sm_type = SM_INVALID;
104	}
105
106	/*
107	 * Loop until we get an EINVAL, so we don't have to know
108	 * how big the table might be.
109	 */
110	for (keystation = 0; ; keystation++) {
111		for (shift = 0; shift < NSHIFTS; shift++) {
112			if (shiftmasks[shift].sm_type != SM_INVALID) {
113				keyentry[shift].kio_tablemask =
114				    shiftmasks[shift].sm_mask;
115				keyentry[shift].kio_station = keystation;
116				if (ioctl(kbdfd, KIOCGKEY,
117				    &keyentry[shift]) < 0) {
118					if (errno == EINVAL)
119						return (0);
120					perror("dumpkeys: KIOCGKEY");
121					return (1);
122				}
123			}
124		}
125
126		(void) printf("key %d\t", keystation);
127
128		/*
129		 * See if all the "normal" entries (all but the Num Lock and Up
130		 * entries) are the same.
131		 */
132		allsame = 1;
133		for (shift = 1; shift < NSHIFTS; shift++) {
134			if (shiftmasks[shift].sm_type == SM_NORMAL) {
135				if (keyentry[0].kio_entry
136				    != keyentry[shift].kio_entry) {
137					allsame = 0;
138					break;
139				}
140			}
141		}
142
143		if (allsame) {
144			/*
145			 * All of the "normal" entries are the same; just print
146			 * "all".
147			 */
148			(void) printf(" all ");
149			printentry(&keyentry[0]);
150		} else {
151			/*
152			 * The normal entries aren't all the same; print them
153			 * individually.
154			 */
155			for (shift = 0; shift < NSHIFTS; shift++) {
156				if (shiftmasks[shift].sm_type == SM_NORMAL) {
157					(void) printf(" %s ",
158					    shiftmasks[shift].sm_name);
159					printentry(&keyentry[shift]);
160				}
161			}
162		}
163		if (allsame && keyentry[0].kio_entry == HOLE) {
164			/*
165			 * This key is a "hole"; if either the Num Lock or Up
166			 * entry isn't a "hole", print it.
167			 */
168			for (shift = 0; shift < NSHIFTS; shift++) {
169				switch (shiftmasks[shift].sm_type) {
170
171				case SM_NUMLOCK:
172				case SM_UP:
173					if (keyentry[shift].kio_entry
174					    != HOLE) {
175						(void) printf(" %s ",
176						    shiftmasks[shift].sm_name);
177						printentry(&keyentry[shift]);
178					}
179					break;
180				}
181			}
182		} else {
183			/*
184			 * This entry isn't a "hole"; if the Num Lock entry
185			 * isn't NONL (i.e, if Num Lock actually does
186			 * something) print it, and if the Up entry isn't NOP
187			 * (i.e., if up transitions on this key actually do
188			 * something) print it.
189			 */
190			for (shift = 0; shift < NSHIFTS; shift++) {
191				switch (shiftmasks[shift].sm_type) {
192
193				case SM_NUMLOCK:
194					if (keyentry[shift].kio_entry
195					    != NONL) {
196						(void) printf(" %s ",
197						    shiftmasks[shift].sm_name);
198						printentry(&keyentry[shift]);
199					}
200					break;
201
202				case SM_UP:
203					if (keyentry[shift].kio_entry
204					    != NOP) {
205						(void) printf(" %s ",
206						    shiftmasks[shift].sm_name);
207						printentry(&keyentry[shift]);
208					}
209					break;
210				}
211			}
212		}
213		(void) printf("\n");
214	}
215}
216
217static char *shiftkeys[] = {
218	"capslock",
219	"shiftlock",
220	"leftshift",
221	"rightshift",
222	"leftctrl",
223	"rightctrl",
224	"meta",			/* not used */
225	"top",			/* not used */
226	"cmd",			/* reserved */
227	"altgraph",
228	"alt",
229	"numlock",
230};
231
232#define	NSHIFTKEYS	(sizeof (shiftkeys) / sizeof (shiftkeys[0]))
233
234static char *buckybits[] = {
235	"metabit",
236	"systembit",
237};
238
239#define	NBUCKYBITS	(sizeof (buckybits) / sizeof (buckybits[0]))
240
241static char *funnies[] = {
242	"nop",
243	"oops",
244	"hole",
245	"reset",
246	"error",
247	"idle",
248	"compose",
249	"nonl",
250};
251
252#define	NFUNNIES	(sizeof (funnies) / sizeof (funnies[0]))
253
254static char *fa_class[] = {
255	"fa_umlaut",
256	"fa_cflex",
257	"fa_tilde",
258	"fa_cedilla",
259	"fa_acute",
260	"fa_grave",
261};
262
263#define	NFA_CLASS	(sizeof (fa_class) / sizeof (fa_class[0]))
264
265typedef struct {
266	char	*string;
267	char	*name;
268} builtin_string_t;
269
270builtin_string_t builtin_strings[] = {
271	{ "\033[H",	"homearrow" },
272	{ "\033[A",	"uparrow" },
273	{ "\033[B",	"downarrow" },
274	{ "\033[D",	"leftarrow" },
275	{ "\033[C",	"rightarrow" },
276};
277
278#define	NBUILTIN_STRINGS	(sizeof (builtin_strings) / \
279					sizeof (builtin_strings[0]))
280
281static char	*fkeysets[] = {
282	"lf",
283	"rf",
284	"tf",
285	"bf",
286};
287
288#define	NFKEYSETS	(sizeof (fkeysets) / sizeof (fkeysets[0]))
289
290static char	*padkeys[] = {
291	"padequal",
292	"padslash",
293	"padstar",
294	"padminus",
295	"padsep",
296	"pad7",
297	"pad8",
298	"pad9",
299	"padplus",
300	"pad4",
301	"pad5",
302	"pad6",
303	"pad1",
304	"pad2",
305	"pad3",
306	"pad0",
307	"paddot",
308	"padenter",
309};
310
311#define	NPADKEYS	(sizeof (padkeys) / sizeof (padkeys[0]))
312
313static void
314printentry(kio)
315	register struct kiockeymap *kio;
316{
317	register int entry = (kio->kio_entry & 0x1F);
318	register int fkeyset;
319	register int i;
320	register int c;
321
322	switch (kio->kio_entry >> 8) {
323
324	case 0x0:
325		if (kio->kio_entry == '"')
326			(void) printf("'\"'");	/* special case */
327		else if (kio->kio_entry == ' ')
328			(void) printf("' '");	/* special case */
329		else
330			printchar((int)kio->kio_entry, '\'');
331		break;
332
333	case SHIFTKEYS >> 8:
334		if (entry < NSHIFTKEYS)
335			(void) printf("shiftkeys+%s", shiftkeys[entry]);
336		else
337			(void) printf("%#4x", kio->kio_entry);
338		break;
339
340	case BUCKYBITS >> 8:
341		if (entry < NBUCKYBITS)
342			(void) printf("buckybits+%s", buckybits[entry]);
343		else
344			(void) printf("%#4x", kio->kio_entry);
345		break;
346
347	case FUNNY >> 8:
348		if (entry < NFUNNIES)
349			(void) printf("%s", funnies[entry]);
350		else
351			(void) printf("%#4x", kio->kio_entry);
352		break;
353
354	case FA_CLASS >> 8:
355		if (entry < NFA_CLASS)
356			(void) printf("%s", fa_class[entry]);
357		else
358			(void) printf("%#4x", kio->kio_entry);
359		break;
360
361	case STRING >> 8:
362		if (entry < NBUILTIN_STRINGS && strncmp(kio->kio_string,
363			builtin_strings[entry].string, KTAB_STRLEN) == 0)
364			(void) printf("string+%s", builtin_strings[entry].name);
365		else {
366			(void) printf("\"");
367			for (i = 0;
368			    i < KTAB_STRLEN && (c = kio->kio_string[i]) != '\0';
369			    i++)
370				printchar(c, '"');
371			(void) printf("\"");
372		}
373		break;
374
375	case FUNCKEYS >> 8:
376		fkeyset = (int)(kio->kio_entry & 0xF0) >> 4;
377		if (fkeyset < NFKEYSETS)
378			(void) printf("%s(%d)", fkeysets[fkeyset],
379					(entry&0x0F) + 1);
380		else
381			(void) printf("%#4x", kio->kio_entry);
382		break;
383
384	case PADKEYS >> 8:
385		if (entry < NPADKEYS)
386			(void) printf("%s", padkeys[entry]);
387		else
388			(void) printf("%#4x", kio->kio_entry);
389		break;
390
391	default:
392		(void) printf("%#4x", kio->kio_entry);
393		break;
394	}
395}
396
397static void
398printchar(character, delim)
399	int character;
400	int delim;
401{
402	switch (character) {
403
404	case '\n':
405		(void) printf("'\\n'");
406		break;
407
408	case '\t':
409		(void) printf("'\\t'");
410		break;
411
412	case '\b':
413		(void) printf("'\\b'");
414		break;
415
416	case '\r':
417		(void) printf("'\\r'");
418		break;
419
420	case '\v':
421		(void) printf("'\\v'");
422		break;
423
424	case '\\':
425		(void) printf("'\\\\'");
426		break;
427
428	default:
429		if (isprint(character)) {
430			if (character == delim)
431				(void) printf("'\\'");
432			(void) printf("%c", character);
433		} else {
434			if (character < 040)
435				(void) printf("^%c", character + 0100);
436			else
437				(void) printf("'\\%.3o'", character);
438		}
439		break;
440	}
441}
442