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 
  38 typedef 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 
  45 typedef struct {
  46         char    *sm_name;
  47         int     sm_mask;
  48         smtype_t sm_type;
  49 } smentry_t;
  50 
  51 
  52 smentry_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 
  64 static void     printentry(struct kiockeymap *kio);
  65 static void     printchar(int character, int delim);
  66 
  67 /*ARGSUSED*/
  68 int
  69 main(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 
 217 static 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 
 234 static char *buckybits[] = {
 235         "metabit",
 236         "systembit",
 237 };
 238 
 239 #define NBUCKYBITS      (sizeof (buckybits) / sizeof (buckybits[0]))
 240 
 241 static 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 
 254 static 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 
 265 typedef struct {
 266         char    *string;
 267         char    *name;
 268 } builtin_string_t;
 269 
 270 builtin_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 
 281 static char     *fkeysets[] = {
 282         "lf",
 283         "rf",
 284         "tf",
 285         "bf",
 286 };
 287 
 288 #define NFKEYSETS       (sizeof (fkeysets) / sizeof (fkeysets[0]))
 289 
 290 static 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 
 313 static void
 314 printentry(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 
 397 static void
 398 printchar(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 }