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