xref: /illumos-gate/usr/src/cmd/loadkeys/dumpkeys.c (revision f52943a93040563107b95bccb9db87d9971ef47d)
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 
35 typedef 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 
42 typedef struct {
43 	char	*sm_name;
44 	int	sm_mask;
45 	smtype_t sm_type;
46 } smentry_t;
47 
48 
49 smentry_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 
61 static void	printentry(struct kiockeymap *kio);
62 static void	printchar(int character, int delim);
63 
64 /*ARGSUSED*/
65 int
66 main(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 
212 static 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 
229 static char *buckybits[] = {
230 	"metabit",
231 	"systembit",
232 };
233 
234 #define	NBUCKYBITS	(sizeof (buckybits) / sizeof (buckybits[0]))
235 
236 static 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 
252 static 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 
272 typedef struct {
273 	char	*string;
274 	char	*name;
275 } builtin_string_t;
276 
277 builtin_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 
288 static char	*fkeysets[] = {
289 	"lf",
290 	"rf",
291 	"tf",
292 	"bf",
293 };
294 
295 #define	NFKEYSETS	(sizeof (fkeysets) / sizeof (fkeysets[0]))
296 
297 static 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 
320 static void
321 printentry(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 
403 static void
404 printchar(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