/* scanchek.c */ /* ** By: Phil Benchoff, June 1986 ** v2.0: 31 Aug 1987, Update Kermit to v2.29C, add Turbo-C support. ** v3.0: 31 Aug 1987 merge header and main body, telescope code, add ** some revisons and Bios support for most C compilers. Joe R. Doupnik ** v3.1: 01 Sep 1987, add #ifndef before bioskey() function. ** ** Compiled with Computer Innovations C-86 ** The C-86 IBMPC library will be needed at link time. ** ** This program displays various information about the keys pressed. ** It's original intent is to be used in testing the new IBM keyboards ** (you know the ones, with the F keys on the top). ** ** The key_getc() function in the C-86 IBMPC library returns the contents ** of the AX register after an interrupt 0x16, function 0. Most C compilers ** support the library int86() function to do an interrupt [jrd]. ** ** The BIOS interrupt 0x16 is used for keyboard services. The particular ** service is determined by the service code in AH when the interrupt ** is invoked. ** ** AH = 0 returns the next available keyboard character. ** AL = extended-ASCII character code ** AH = keyboard scan code ( 0 if the alt-numeric input used ) ** or ** AL = 0 ** AH = special character code ( F1-F10, Home, End, etc.) ** AH = 1 test for a character ( don't wait ) ** returned values same as above ** AH = 2 returns the current shift states ** AL = shift states ** ** The MS-Kermit (2.29C) 'key ident' is also printed. This value ** is used in the SET KEY command. Note that Kermit uses the shift ** bits differently than the BIOS routines, so multiple shifts ** (e.g. Ctrl-Alt-F1) can be used with the same key. */ #include #include #define SCAN 256 #define SHIFT 512 #define CONTROL 1024 #define ALT 2048 #define BS 0x08 #define EOS '\0' /* ** These two tables are useful for relating ascii and scan codes ** to the characters entered or keys pressed. ** There are several types of characters included. ** ASCII characters: ** - Characters 0x00 to 0x1F are control characters. ** The array ascii_chars[i] contains the names of these ** control characters. 'Space' is included for lack of ** a better place to put it. The index i should be ** the ascii code for the character. Note that the ascii ** character NUL (0x00) cannot be entered on the IBM-PC keyboard. ** - The character codes 0x20 - 0xff are printable on the ** IBM-PC and are not considered here (except 'space'). ** Special characters: ** For some characters, no ascii value is returned by BIOS interrupt ** 0x16. The scan codes of these characters identify them. ** They include F keys, arrow keys, and alt keys. ** The array special_chars[i] contains tha names of these keys. ** The index i should be the scan code for the key. ** The array is 132 elements long, but not all of the ** scan codes in that range are special keys. ** ** Phil Benchoff, June 1986 */ char *ascii_chars[] = { /* ANSI names of control codes */ "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", /* ^@, ^A, ^B, ^C, ^D, ^E */ "ACK", "BEL", "BS" , "HT" , "LF" , "VT", /* ^F, ^G, ^H, ^I, ^J, ^K */ "FF" , "CR" , "SO" , "SI" , "DLE", "DC1", /* ^L, ^M, ^N, ^O, ^P, ^Q */ "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", /* ^R, ^S, ^T, ^U, ^V, ^W */ "CAN", "EM" , "SUB", "ESC", "FS" , "GS", /* ^X, ^Y, ^Z, ^[, ^\, ^] */ "RS" , "US" , "Space" } ; /* ^^, ^_, space */ char *special_keys[] = { /* common text for given scan code */ "", "", "", "NUL", "", "", "", "", "", "", "", "", "", "", "", /* 0-14 */ "Shift-Tab", /* 15 */ "Alt-Q", "Alt-W", "Alt-E", "Alt-R", "Alt-T", /* 16-20 */ "Alt-Y", "Alt-U", "Alt-I", "Alt-O", "Alt-P", /* 21-25 */ "", "", "", "", /* 27-29 */ "Alt-A", "Alt-S", "Alt-D", "Alt-F", "Alt-G", /* 30-34 */ "Alt-H", "Alt-J", "Alt-K", "Alt-L", /* 35-38 */ "", "", "", "", "", /* 40-43 */ "Alt-Z", "Alt-X", "Alt-C", "Alt-V", "Alt-B", /* 44-48 */ "Alt-N", "Alt-M", /* 49-50 */ "", "", "", "", "", "", "", "", /* 52-58 */ "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", /* 59-68 */ "", "", /* 69-70 */ "Home", "U-arrow", "PgUp", "", "L-arrow", "", "R-arrow", /* 71-77 */ "", "End", "D-arrow", "PgDn", "Ins", "Del", /* 79-83 */ "Shift-F1", "Shift-F2", "Shift-F3", "Shift-F4", "Shift-F5", /* 84-88 */ "Shift-F6", "Shift-F7", "Shift-F8", "Shift-F9", "Shift-F10", /* 89-93 */ "Ctrl-F1", "Ctrl-F2", "Ctrl-F3", "Ctrl-F4", "Ctrl-F5", /* 94-98 */ "Ctrl-F6", "Ctrl-F7", "Ctrl-F8", "Ctrl-F9", "Ctrl-F10", /* 99-103 */ "Alt-F1", "Alt-F2", "Alt-F3", "Alt-F4", "Alt-F5", /* 104-108 */ "Alt-F6", "Alt-F7", "Alt-F8", "Alt-F9", "Alt-F10", /* 109-113 */ "Ctrl-PrtSc", "Ctrl-L-arraw", "Ctrl-R-arrow", /* 114-116 */ "Ctrl-End", "Ctrl-PgDn", "Ctrl-Home", /* 117-119 */ "Alt-1", "Alt-2", "Alt-3", "Alt-4", "Alt-5", "Alt-6", /* 120-125 */ "Alt-7", "Alt-8", "Alt-9", "Alt-0", "Alt--", "Alt-=", /* 126-131 */ "Ctrl-PgUp" /* 132 */ }; main() { unsigned int count, ascii, scan; char *comment(); unsigned int bios_key, bios_shifts, key_ident, kerm_key(); #ifdef C86 int key_shft(), key_getc(); #endif explain(); count = 1; while ( 1 ) { if (1 == count ) { header(); count = 22; } else count--; #ifdef C86 bios_key = (unsigned_int)key_getc(); bios_shifts = (unsigned int)key_shft(); #else bios_key = bioskey(0); bios_shifts = bioskey(2); #endif ascii = bios_key & 0x00FF; /* ASCII value is in low byte */ scan = bios_key >> 8; /* Scan code is in high byte */ key_ident = kerm_key(bios_key,bios_shifts); /* Note: You can't enter a NUL (ascii 00) from the keyboard */ if ( (ascii >= 33) && (ascii <= 255) ) /* Printable char. */ printf("| %-13c ", ascii ); else if ( (ascii >= 1) && (ascii <= 31) ) /* Control char. */ printf("| Ctrl-%c %-6s ", ascii + 64, ascii_chars[ascii]); else if (ascii == 32) /* Space */ printf("| Space "); else if (ascii == 0) { /* Special Key */ if (scan <= 132) printf("| %-13s ", special_keys[scan]); else printf("| * unknown * "); } else printf("| Out of range "); printf("| %3d | 0x%02x | \\%-4d ", scan, ascii, key_ident); if (key_ident & ALT) printf("| A"); else printf("| -"); if (key_ident & CONTROL) printf("C"); else printf("-"); if (key_ident & SHIFT) printf("S "); else printf("- "); printf("| %-32s|\n", comment(scan,ascii) ); } exit(0); } /* ** Kermit-MS determines the 'key ident' from the value returned in ax ** (ah=scan code, al=ascii value) from BIOS call 0x16 function 0, the ** status of various shift keys, and a table of special keys (aliaskey). ** The aliaskey table handles cases where more than one key may generate ** the same ascii value (i.e. the numeric keypad). The entries in table ** aliaskey are words with the high byte holding a scan code and the low ** byte holding an ascii value. The general method is as follows: ** ** BIOS int 0x16 function 0 returns key's code in register ax. ** if (ax is in aliaskey list) ** al = 0 clear normal ascii to simulate special key ** ascii = al do this in either case ** if ( ascii == 0 ) { now, if the key is a special one ... ** scancode = ah work with scan code instead ** key_ident = scancode + 256 set SCAN code flag bit ** if ( LeftShift || RightShift || (NumKeypadWhiteKey && NumLock) ) ** key_ident |= 512 set smart SHIFT key flag bit ** if ( Ctrl ) ** key_ident |= 1024 set CONTROL key flag bit ** If ( Alt ) ** key_ident |= 2048 set ALT key flag bit ** } else ** key_ident = ascii */ unsigned int kerm_key(bios_key,bios_shifts) unsigned int bios_key, bios_shifts; { unsigned key_id; /* table of Bios keycodes needing inspection*/ switch (bios_key) { case ( 14 * SCAN ) + BS: /* high byte = scan code, low byte = ascii */ case ( 55 * SCAN ) + '*': case ( 74 * SCAN ) + '-': case ( 78 * SCAN ) + '+': case ( 71 * SCAN ) + '7': case ( 72 * SCAN ) + '8': case ( 73 * SCAN ) + '9': case ( 75 * SCAN ) + '4': case ( 76 * SCAN ) + '5': case ( 77 * SCAN ) + '6': case ( 79 * SCAN ) + '1': case ( 80 * SCAN ) + '2': case ( 81 * SCAN ) + '3': case ( 82 * SCAN ) + '0': case ( 83 * SCAN ) + '.': key_id = bios_key & 0xff00; /* clear ascii low byte */ break; default: key_id = bios_key; /* key is not in the list */ break; }; if ( (key_id & 0x00ff) == 0 ) { /* No ASCII value, get a kermit scan code. */ key_id = ( key_id >> 8 ) | SCAN; /* set scancode flag */ if (bios_shifts & 3) /* left or right shift?*/ key_id |= SHIFT; /* yes, set shift flag */ else if ((bios_shifts & 0x20) /* NumLock set? */ && ( key_id >= ( 71 + SCAN ) ) /* on numeric keypad ? */ && ( key_id <= ( 83 + SCAN ) ) && ( key_id != ( 74 + SCAN ) ) /* not the grey - key? */ && ( key_id != ( 78 + SCAN ) ) ) /* not the grey + key? */ key_id |= SHIFT; /* all true, set shift */ if (bios_shifts & 0x04) /* Ctrl-key pressed? */ key_id |= CONTROL; if (bios_shifts & 0x08) /* Alt-key pressed? */ key_id |= ALT; } else /* We have an ASCII value, return that */ key_id &= 0xff; return key_id; } char *comment(scan,ascii) int scan, ascii; { static char line[40]; line[0] = '\0'; /* start with an empty line */ if ( (ascii !=0) && (scan >= 71) ) strcpy(line,"Numeric Keypad"); else if ( (ascii == 0) && (scan != 0) ) strcpy(line,"Special Key"); else if ( (ascii != 0) && (scan == 0) ) strcpy(line,"Alt-numeric method."); return(line); } header() { char *dash39 = "---------------------------------------", *left = "|Key |Scan |ASCII |Kermit |S", *right = "hift| Notes |"; printf("%s%s\n%s%s\n%s%s\n",dash39,dash39,left,right,dash39,dash39); } explain() { /* Tell what the program does, and how to get out */ printf("ScanChek 3.1\n\n"); printf("This program displays the scan code, ASCII code, and\n"); printf("the Kermit 'key ident' used in the Kermit-MS SET KEY command.\n"); printf("Keycodes are obtained from the IBM-PC keyboard BIOS interrupt"); printf(" 16H, function 0.\n"); printf("Do not type ahead of the display.\n\n"); printf("Key - The key pressed. Determined from ascii value or\n"); printf(" BIOS scan code.\n"); printf("Scan - The BIOS scan code (ah).\n"); printf("ASCII - The ASCII value (al).\n"); printf("Kermit - The Kermit-MS key ident.\n"); printf("Shift - Shift key pressed, valid only if \"Kermit\" field"); printf(" is > 255\n (A=Alt, C=Ctrl, S=Shift)\n"); printf("\nPress Control-BREAK to exit.\n\n"); } #ifndef C86 bioskey(function) /* For most C compilers [jrd] */ int function; /* do Interrupt 16H via int86() */ { static union REGS reg; /* for Bios int86 calls */ reg.h.ah = function; int86(0x16, ®, ®); return (reg.x.ax); } #endif