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 }