home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / NCSATELN / TEL23SRC.ZIP / KEYMAP / MSUCHK.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-08-06  |  18.8 KB  |  448 lines

  1. /* scanchek.c */
  2. /*
  3. ** By: Phil Benchoff, June 1986
  4. ** v2.0: 31 Aug 1987, Update Kermit to v2.29C, add Turbo-C support.
  5. ** v3.0: 31 Aug 1987 merge header and main body, telescope code, add
  6. **    some revisons and Bios support for most C compilers. Joe R. Doupnik
  7. ** v3.1: 01 Sep 1987, add #ifndef before bioskey() function.
  8. ** v4.0: 22 Jan 1988, Computer Innovations C86 support dropped.
  9. **                    Enhanced keyboard support added
  10. **                    Mods to match MS-Kermit 2.30
  11. **                    A few JRD suggestions
  12. ** v4.1: 20 Jan 1989, fix bug with NumLock/Shift, match MS-Kermit 2.32
  13. **                    Matthias Reichling
  14. **
  15. ** This program displays various information about the keys pressed.
  16. ** It's original intent is to be used in testing the new IBM keyboards
  17. ** (you know the ones, with the F keys on the top).
  18. **
  19. ** Enhanced keyboard:
  20. ** For more information on the enhanced keyboard see:
  21. ** 'Keying on a Standard', _PC_TECH_JOURNAL_, July 1987, pp. 134-156
  22. ** Minor error in article,  Table 1:  Numeric Keypad:
  23. **    Buffer codes with lsb=0xF0 are actually translated to have
  24. **    lsb=00 by int 0x16.
  25. **
  26. ** The BIOS interrupt 0x16 is used for keyboard services. The particular
  27. ** service is determined by the service code in AH when the interrupt
  28. ** is invoked.
  29. **
  30. ** AH = 0 returns the next available keyboard character.
  31. **        AL = extended-ASCII character code
  32. **        AH = keyboard scan code ( 0 if the alt-numeric input used )
  33. **  or
  34. **        AL = 0
  35. **        AH = special character code ( F1-F10, Home, End, etc.)
  36. ** AH = 1 test for a character ( don't wait )
  37. **        returned values same as above
  38. ** AH = 2 returns the current shift states
  39. **        AL = shift states
  40. ** AH = 0x10 or 0x11
  41. **        enhanced keyboard versions of AH=0 and AH=1
  42. **
  43. ** The MS-Kermit (2.32) 'key ident' is also printed.  This value
  44. ** is used in the SET KEY command.  Note that Kermit uses the shift
  45. ** bits differently than the BIOS routines,  so multiple shifts
  46. ** (e.g. Ctrl-Alt-F1) can be used with the same key in some cases.
  47. */
  48.  
  49. #include <stdio.h>
  50. #include <string.h>
  51. #include <dos.h>
  52.  
  53. /* Kermit-MS keyboard shift flags (most significant byte of key_ident) */
  54. #define SCAN    0x0100  /* scan code */
  55. #define SHIFT   0x0200  /* left or right shift */
  56. #define CONTROL 0x0400  /* Ctrl shift */
  57. #define ALT     0x0800  /* Alt shift */
  58. #define ENHANCE 0x1000  /* Enhanced keyboard special key */
  59.  
  60. #define BS 0x08
  61. #define TAB 0x09
  62. #define EOS '\0'
  63. /*
  64. ** These two tables are useful for relating ascii and scan codes
  65. ** to the characters entered or keys pressed.
  66. ** There are several types of characters included.
  67. ** ASCII characters:
  68. ** - Characters 0x00 to 0x1F are control characters.
  69. **   The array ascii_chars[i] contains the names of these
  70. **   control characters. 'Space' is included for lack of
  71. **   a better place to put it. The index i should be
  72. **   the ascii code for the character. Note that the ascii
  73. **   character NUL (0x00) cannot be entered on the IBM-PC keyboard.
  74. ** - The character codes 0x20 - 0xff are printable on the
  75. **   IBM-PC and are not considered here (except 'space').
  76. ** Special characters:
  77. **   For some characters, no ascii value is returned by BIOS interrupt
  78. **   0x16. The scan codes of these characters identify them.
  79. **   They include F keys, arrow keys, and alt keys.
  80. **   With the enhanced keyboard,  BIOS may return the following:
  81. **   - scancode = 0xe0, ascii = non-enhanced scancode
  82. **   - scancode = non-enhanced scancode, ascii = 0xe0 of 0xf0
  83. **
  84. **   The array special_chars[i] contains tha names of these keys.
  85. **   The index i should be the scan code for the key.
  86. **   The array is 166 elements long, but not all of the
  87. **   scan codes in that range are special keys.
  88. **
  89. ** Phil Benchoff, June 1986
  90. ** revised Jan 88
  91. */
  92.  
  93. char *ascii_chars[] = {                 /* ANSI names of control codes */
  94.    "NUL", "SOH", "STX", "ETX", "EOT", "ENQ",  /* ^@, ^A, ^B, ^C, ^D, ^E */
  95.    "ACK", "BEL", "BS" , "HT" , "LF" , "VT",   /* ^F, ^G, ^H, ^I, ^J, ^K */
  96.    "FF" , "CR" , "SO" , "SI" , "DLE", "DC1",  /* ^L, ^M, ^N, ^O, ^P, ^Q */
  97.    "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",  /* ^R, ^S, ^T, ^U, ^V, ^W */
  98.    "CAN", "EM" , "SUB", "ESC", "FS" , "GS",   /* ^X, ^Y, ^Z, ^[, ^\, ^] */
  99.    "RS" , "US" , "Space" } ;                  /* ^^, ^_, space */
  100.  
  101. char *special_keys[] = {            /* common text for given scan code */
  102.    "", "Alt-Esc", "", "NUL", "", "", "", "",                    /* 0-7 */
  103.    "", "", "Ctrl-Num-Ent", "", "Alt-Enter", "Num-Enter",        /* 8-13 */
  104.    "Alt-BS", "Shift-Tab",                                       /* 14-15 */
  105.    "Alt-Q", "Alt-W", "Alt-E", "Alt-R", "Alt-T",                 /* 16-20 */
  106.    "Alt-Y", "Alt-U", "Alt-I", "Alt-O", "Alt-P",                 /* 21-25 */
  107.    "Alt-[", "Alt-]", "Alt-Enter", "",                           /* 26-29 */
  108.    "Alt-A", "Alt-S", "Alt-D", "Alt-F", "Alt-G",                 /* 30-34 */
  109.    "Alt-H", "Alt-J", "Alt-K", "Alt-L",                          /* 35-38 */
  110.    "Alt-;", "Alt-'", "Alt-`", "", "Alt-\\",                     /* 39-43 */
  111.    "Alt-Z", "Alt-X", "Alt-C", "Alt-V", "Alt-B",                 /* 44-48 */
  112.    "Alt-N", "Alt-M",                                            /* 49-50 */
  113.    "Alt-,", "Alt-.", "Alt-/", "", "Alt-Num-*", "", "", "",      /* 51-58 */
  114.    "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", /* 59-68 */
  115.    "", "",                                                      /* 69-70 */
  116.    "Home", "U-arrow", "PgUp", "Alt-NumMinus",                   /* 71-74 */
  117.    "L-arrow", "Num-5", "R-arrow",                               /* 75-77 */
  118.    "Alt-Num-+", "End", "D-arrow", "PgDn", "Ins", "Del",         /* 78-83 */
  119.    "Shift-F1", "Shift-F2", "Shift-F3", "Shift-F4", "Shift-F5",  /* 84-88 */
  120.    "Shift-F6", "Shift-F7", "Shift-F8", "Shift-F9", "Shift-F10", /* 89-93 */
  121.    "Ctrl-F1",  "Ctrl-F2",  "Ctrl-F3",  "Ctrl-F4",  "Ctrl-F5",   /* 94-98 */
  122.    "Ctrl-F6",  "Ctrl-F7",  "Ctrl-F8",  "Ctrl-F9",  "Ctrl-F10",  /* 99-103 */
  123.    "Alt-F1",   "Alt-F2",   "Alt-F3",   "Alt-F4",   "Alt-F5",    /* 104-108 */
  124.    "Alt-F6",   "Alt-F7",   "Alt-F8",   "Alt-F9",   "Alt-F10",   /* 109-113 */
  125.    "Ctrl-PrtSc", "Ctrl-L-arrow", "Ctrl-R-arrow",                /* 114-116 */
  126.    "Ctrl-End",   "Ctrl-PgDn",    "Ctrl-Home",                   /* 117-119 */
  127.    "Alt-1", "Alt-2", "Alt-3", "Alt-4", "Alt-5", "Alt-6",        /* 120-125 */
  128.    "Alt-7", "Alt-8", "Alt-9", "Alt-0", "Alt--", "Alt-=",        /* 126-131 */
  129.    "Ctrl-PgUp", "F11", "F12", "Shift-F11",  "Shift-F12",        /* 132-136 */
  130.    "Ctrl-F11", "Ctrl-F12", "Alt-F11", "Alt-F12",                /* 137-140 */
  131.    "Ctrl-U-arrow", "Ctrl-NumMinus", "Ctrl-Num-5",               /* 141-143 */
  132.    "Ctrl-Num-+", "Ctrl-D-Arrow", "Ctrl-Insert",                 /* 144-146 */
  133.    "Ctrl-Delete", "Ctrl-Tab", "Ctrl-Num-/", "Ctrl-Num-*",       /* 147-150 */
  134.    "Alt-Home", "Alt-U-arrow", "Alt-PgUp", "",                   /* 151-154 */
  135.    "Alt-L-arrow", "", "Alt-R-Arrow", "", "Alt-End",             /* 155-159 */
  136.    "Alt-D-Arrow", "Alt-PgDn", "Alt-Insert", "Alt-Del",          /* 160-163 */
  137.    "Alt-Num-/", "Alt-Tab", "Alt-Num-Ent."                       /* 164-166 */
  138. };
  139. #define NSPECIALS 166  /* length of special_keys[] */
  140.  
  141.  
  142. main()
  143. {
  144.    unsigned int count, ascii, scan;
  145.    int read_fn, enh_key;
  146.    static char *comment();
  147.    unsigned int bios_key, bios_shifts, key_ident, kerm_key();
  148.  
  149.    explain();  /* display instructions */
  150.  
  151.    /*
  152.    ** Determine if we have an enhanced keyboard.
  153.    ** Select the function to use when calling the keyboard interrupt.
  154.    **  read_fn = peekb(seg,offset) may need replacing by
  155.    **  peek(seg,offset,&read_fn,1); read_fn &= 0x10;  for Lattice C.
  156.    */
  157.  
  158. #ifdef QAK_FOR_NOW
  159.    read_fn = peekb(0x40,0x96) & 0x10; /* get BIOS enhanced keyboard flag */
  160.              /* read_fn is either 0x00 or 0x10 */
  161. #else
  162.     read_fn=0x10;
  163. #endif
  164.    if ( 0 == read_fn ) {              /* flag = 0,  standard keyboard */
  165.       printf("Standard keyboard:\n");
  166.    }
  167.    else {                             /* flag = 1, enhanced keyboard */
  168.       printf("Enhanced keyboard:\n");
  169.    }
  170.  
  171.    count = 1;
  172.  
  173.    while ( 1 ) {
  174.       if (1 == count ) {
  175.          header();
  176.          count = 21;
  177.       } else
  178.          count--;
  179.  
  180.       enh_key=0; /* set this to 1 in the following code if this key */
  181.                  /* is only available on the enhanced keyboard */
  182.       bios_key = bioskey(read_fn);
  183.       bios_shifts = bioskey(2);
  184.  
  185.       ascii = bios_key & 0x00FF;     /* ASCII value is in low byte */
  186.       scan  = bios_key >> 8;         /* Scan code is in high byte  */
  187.       key_ident = kerm_key(bios_key,bios_shifts);
  188.  
  189.       /* Note: You can't enter a NUL (ascii 00) from the keyboard */
  190.  
  191.       if ( 0xe0 == scan ) {                       /* enhanced keyboard */
  192.          enh_key = 1;
  193.          /*
  194.          ** The IBM memorial exception:
  195.          ** The buffer code for Numeric-/ is 0xe02f; however 0x2f is
  196.          ** the scan code for Alt-V,  so we can't just use al as the
  197.          ** scan code.
  198.          */
  199.          if ( 0x2f == ascii )
  200.             printf("| %-13s ", "Numeric-/");
  201.          else if (ascii <= NSPECIALS)
  202.             printf("| %-13s ", special_keys[ascii]);
  203.          else
  204.             printf("| * unknown *   ");
  205.       } else if ( (0!=scan) && (0xe0==ascii) ) {  /* enhanced keyboard */
  206.          enh_key = 1;
  207.          if (scan <= NSPECIALS)
  208.             printf("| %-13s ", special_keys[scan]);
  209.          else
  210.             printf("| * unknown *   ");
  211.       } else if ( (ascii >= 33) && (ascii <= 255) ) {  /* Printable char. */
  212.          printf("| %-13c ", ascii );
  213.       } else if ( (ascii > 0) && (ascii <= 31) ) {  /* control char */
  214.          printf("| Ctrl-%c %-6s ", ascii + 64, ascii_chars[ascii]);
  215.       } else if (ascii == 32) {                /* Space       */
  216.          printf("| Space         ");
  217.       } else if ( ascii == 0 ) {      /* special key (no ascii value) */
  218.          if (scan <= NSPECIALS) {              /* in table? */
  219.             if ( 0x84 < scan )        /* enhanced keyboard if scan > 84 */
  220.                enh_key = 1;
  221.             else {
  222.                switch (scan) {
  223.                   /*
  224.                   ** The following keys produce a scan code and
  225.                   ** no ascii value,  but are only available on
  226.                   ** the enhanced keyboard.
  227.                   */
  228.                   case 0x01:      /* Alt-ESC */
  229.                   case 0x0e:      /* Alt-Backspace */
  230.                   case 0x1a:      /* Alt-[ */
  231.                   case 0x1b:      /* Alt-] */
  232.                   case 0x1c:      /* Alt-Enter */
  233.                      /* Alt-Enter produces scancode 12 (dec.) on my */
  234.                      /* PC Limited AT-8 w/standard keyboard */
  235.                   case 0x27:      /* Alt-; */
  236.                   case 0x28:      /* Alt-' */
  237.                   case 0x29:      /* Alt-` */
  238.                   case 0x2b:      /* Alt-\ */
  239.                   case 0x33:      /* Alt-, */
  240.                   case 0x34:      /* Alt-. */
  241.                   case 0x35:      /* Alt-/ */
  242.                   case 0x37:      /* Alt-* */
  243.                   case 0x4a:      /* Alt-Num- */
  244.                   case 0x4c:      /* Num-5 */
  245.                   case 0x4e:      /* Alt-Num+ */
  246.                      enh_key = 1;
  247.                      break;
  248.                   default:
  249.                      break;
  250.                };
  251.             }
  252.             printf("| %-13s ", special_keys[scan]);
  253.          }
  254.          else
  255.             printf("| * unknown *   ");
  256.       } else {
  257.          printf("| Out of range  ");
  258.       }
  259.  
  260.       printf("| %3d | 0x%02x |%c| \\%-4d ", scan, ascii,
  261.               enh_key ? '*' : ' ', key_ident);
  262.  
  263.       /* print Kermit shift bit status */
  264.       if ( SCAN & key_ident ) {
  265.          printf("| %c", (key_ident & ENHANCE) ? 'E' : '-');
  266.          printf("%c",(key_ident & ALT) ? 'A' : '-');
  267.          printf("%c",(key_ident & CONTROL) ? 'C' : '-');
  268.          printf("%c ",(key_ident & SHIFT) ? 'S' : '-');
  269.       } else printf("|      ");
  270.  
  271.       printf("| %-29s|\n", comment(scan,ascii) );
  272.         if (key_ident == 1280) break;         /* Control-Break exit */
  273.    }
  274.    exit(0);
  275. }
  276.  
  277. /*
  278. ** This function should match 'getkey' in MSUIBM.ASM.
  279. **
  280. ** Kermit-MS determines the 'key ident' from the value returned in ax
  281. ** (ah=scan code, al=ascii value) from BIOS call 0x16 function 0
  282. ** (standard keyboard) or 0x10 (enhanced keyboard), the
  283. ** status of various shift keys, and a table of special keys (aliaskey).
  284. ** The aliaskey table handles cases where more than one key may generate
  285. ** the same ascii value (i.e. the numeric keypad).  The entries in table
  286. ** aliaskey are words with the high byte holding a scan code and the low
  287. ** byte holding an ascii value.  The general method is as follows:
  288. **
  289. **    BIOS int 0x16 function 0 or 0x10   returns key's code in register ax.
  290. **    if (ah!=0 and al=0xe0)             enhanced
  291. **       al = 0                          zero ascii
  292. **       key_ident |= ENHANCE            set enhanced flag
  293. **    else if (ah==0xe0)                 enhanced
  294. **       ah=al                           put scan in ah
  295. **       al=0                            zero ascii
  296. **       key_ident |= ENHANCE            set enhanced flag
  297. **    if (ax is in aliaskey list)
  298. **       al = 0                    clear normal ascii to simulate special key
  299. **    ascii = al                         do this in either case
  300. **    if ( ascii == 0 ) {                now, if the key is a special one ...
  301. **    scancode = ah                      work with scan code instead
  302. **       key_ident = scancode + SCAN     set SCAN code flag bit
  303. **       if ( (LeftShift || RightShift) && (no NumKeypadWhiteKey)
  304. **           || (NumKeypadWhiteKey && NumLock && no Shift)
  305. **           || (NumKeypadWhiteKey && no NumLock && Shift) )
  306. **          key_ident |= SHIFT           set smart SHIFT key flag bit
  307. **       if ( Ctrl )
  308. **          key_ident |= CONTROL         set CONTROL key flag bit
  309. **       If ( Alt )
  310. **          key_ident |= ALT             set ALT key flag bit
  311. **    } else
  312. **       key_ident = ascii
  313. */
  314. unsigned int kerm_key(bios_key,bios_shifts)
  315. unsigned int bios_key, bios_shifts;
  316. {
  317.    unsigned  key_id, shift_hlp;
  318.  
  319.    key_id = 0;
  320.    shift_hlp = 0;
  321.    /* getky1a */
  322.    if ( 0 != (bios_key & 0xff00) ) {        /* not alt-numeric */
  323.       if ( 0xe000 == (bios_key & 0xff00) ) {
  324.          bios_key <<= 8;
  325.          key_id |= ENHANCE;
  326.       }
  327.       /* getky1b */
  328.       if ( 0x00e0 == (bios_key & 0x00ff) ) {
  329.          bios_key &= 0xff00;
  330.          key_id |= ENHANCE;
  331.       }
  332.    }
  333.    if ( 0 != (bios_key & 0x00ff) ) {        /* not scan code only */
  334.       /* getky1c */
  335.       /* aliaskey processing */
  336.       switch (bios_key)
  337.       {
  338.          case ( 14 * SCAN ) + BS:
  339.          case ( 55 * SCAN ) + '*':
  340.          case ( 74 * SCAN ) + '-':
  341.          case ( 78 * SCAN ) + '+':
  342.          case ( 71 * SCAN ) + '7':
  343.          case ( 72 * SCAN ) + '8':
  344.          case ( 73 * SCAN ) + '9':
  345.          case ( 75 * SCAN ) + '4':
  346.          case ( 76 * SCAN ) + '5':
  347.          case ( 77 * SCAN ) + '6':
  348.          case ( 79 * SCAN ) + '1':
  349.          case ( 80 * SCAN ) + '2':
  350.          case ( 81 * SCAN ) + '3':
  351.          case ( 82 * SCAN ) + '0':
  352.          case ( 83 * SCAN ) + '.':
  353.          case ( 83 * SCAN ) + ',':
  354.          case ( 15 * SCAN ) + TAB:
  355.                    bios_key &= 0xff00;     /* clear ascii low byte */
  356.                    break;
  357.          default:                        /* key is not in the list */
  358.                    break;
  359.       };
  360.    }
  361.    if ( (bios_key & 0x00ff) == 0 ) {
  362.                            /* No ASCII value, get a kermit scan code. */
  363.       key_id |= ((bios_key >> 8) | SCAN);       /* set scancode flag */
  364.       if (bios_shifts & 3)                      /* left or right shift?*/
  365.          shift_hlp |= SHIFT;                    /* yes, set shift flag */
  366.       if ((bios_shifts & 0x20)                  /* NumLock set? */
  367.              && ( key_id >= ( 71 + SCAN ) )     /* on numeric keypad ? */
  368.              && ( key_id <= ( 83 + SCAN ) )
  369.              && ( key_id != ( 74 + SCAN ) )     /* not the grey - key? */
  370.              && ( key_id != ( 78 + SCAN ) ) )   /* not the grey + key? */
  371.          shift_hlp ^= SHIFT;                    /* all true, xor shift */
  372.       key_id |= shift_hlp;
  373.       if (bios_shifts & 0x04)                   /* Ctrl-key pressed? */
  374.          key_id |= CONTROL;
  375.       if (bios_shifts & 0x08)                   /* Alt-key pressed? */
  376.          key_id |= ALT;
  377.    } else
  378.       /* We have an ASCII value,  return that */
  379.       key_id = bios_key & 0xff;
  380.  
  381.    return key_id;
  382. }
  383.  
  384. char *comment(scan,ascii)
  385. int  scan, ascii;
  386. {
  387.     static char line[40];
  388.  
  389.     line[0] = '\0';                     /* start with an empty line */
  390.  
  391.    if ( (0xe0 == ascii) && (0 != scan) ) {
  392.       ascii = 0;
  393.    } else if ( 0xe0 == scan ) {
  394.       scan = ascii;
  395.       ascii = 0;
  396.    }
  397.     if ( (ascii !=0) && (scan >= 71) )
  398.        strcpy(line,"Numeric Keypad");
  399.     else if ( (ascii == 0) &&  (scan != 0) )
  400.        strcpy(line,"Special Key");
  401.     else if ( (ascii != 0) && (scan == 0) )
  402.        strcpy(line,"Alt-numeric method.");
  403.     return(line);
  404. }
  405.  
  406. header() {
  407.    char *dash38 = "--------------------------------------",
  408.         *left1  = "|           B I O S            |Kermit-",
  409.         *right1 = "MSv2.32|                              |",
  410.         *left2  = "|Key            |Scan |ASCII |E|KeyIdnt",
  411.         *right2 = "|Flags |Notes                         |";
  412.  
  413.    printf("+%s%s+\n%s%s\n%s%s\n+%s%s+\n",dash38,dash38,left1,right1,
  414.            left2,right2,dash38,dash38);
  415.  
  416. }
  417.  
  418. explain()
  419. {
  420. /* Tell what the program does, and how to get out */
  421.    printf("ScanChek 4.1 (20 Jan 89)\n\n");
  422.    printf("This program displays the scan code, ASCII code, and\n");
  423.    printf("the Kermit 'key ident' used in the Kermit-MS SET KEY command. ");
  424.    printf("Keycodes are \nobtained from the IBM-PC keyboard BIOS interrupt");
  425.    printf(" 16H, function 0 or 0x10.\n");
  426.    printf("Do not type ahead of the display.\n\n");
  427.    printf("Key    - The key pressed. Determined from ascii value or");
  428.    printf(" BIOS scan code.\n");
  429.    printf("Scan   - The BIOS scan code (ah).\n");
  430.    printf("ASCII  - The ASCII value (al).\n");
  431.    printf("E      - * if available on enhanced keyboard only.\n");
  432.    printf("KeyIdnt- The Kermit-MS v2.32 key ident.\n");
  433.    printf("Flags  - Flags present in KeyIdnt. Valid only if \"Kermit\" field");
  434.    printf(" is > 255\n         (E=Enhanced, A=Alt, C=Ctrl, S=Shift)\n");
  435.    printf("E      - * if key ident enhanced bit is set.\n");
  436.    printf("\nPress Control-BREAK to exit.\n\n");
  437. }
  438.  
  439. bioskey(function)                       /* For most C compilers [jrd] */
  440. int function;                           /* do Interrupt 16H via int86() */
  441. {
  442.    static union REGS reg;                       /* for Bios int86 calls */
  443.    reg.h.ah = function;
  444.    int86(0x16, ®, ®);
  445.    return (reg.x.ax);
  446. }
  447.  
  448.