home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 328_02 / wkbd.c < prev    next >
C/C++ Source or Header  |  1991-03-17  |  7KB  |  286 lines

  1. /*! wkbd.c       low-level keyboard access
  2.  *
  3.  *    get a key from the keyboard
  4.  *
  5.  *    wkbd_init() - detect enhanced kbd. setup interrupts as needed.
  6.  *      wread_kbd() - read a keystroke
  7.  *    wready_kbd()- see if a keystroke is waiting
  8.  *    wenhanced_kbd() - see if enhanced keyboard is present.
  9.  *    wflush_kbd() - flushes all keystrokes from the kbd buffer.
  10.  *
  11.  * NOTE: enhanced kbd support added for version 1.1, July 1990
  12.  *    
  13.  *    The method used in VERSION_10 is only available in TurboC, not Microsoft.
  14.  *     TurboC lets program check the zero flag, needed for wready_kbd()
  15.  *     Microsoft doesn't allow this, so can't check for wready_kbd()
  16.  *      in MIcrosoft version, call is interrupt 0x21 (DOS) instead.
  17.  *        (using the microsoft library function kbhit() )
  18.  *
  19.  *    In VERSION_11, a new method uses direct access to BIOS memory areas
  20.  *    as described in the C User's Journal July 1990 article, "Controlling the
  21.  *    Keyboard Buffer" by Steve Gruel. This method works in either Turbo C
  22.  *    or Microsoft C. 
  23.  *
  24.  *    To revert to BIOS calls using interrupt x16, undefine the symbol VERSION_11
  25.  *
  26.  *                    @ David Blum, 1986, 1989, 1990
  27.  */
  28.  
  29. #include "wsys.h"
  30.  
  31. /* Option to use BIOS MEMORY AREAS rather than interrupts.
  32.  */
  33. #define VERSION_11  1.1
  34.  
  35.  
  36. /* enhanced keyboard support -
  37.  * if enh. kbd is present, change these interrupt functions to x10, x11, etc
  38.  */
  39. static unsigned char   W_NEAR   func_get = 0;
  40.  
  41.  
  42.  
  43.  
  44. #ifdef VERSION_11
  45.     /* Keyboard buffer location pointers, stored in BIOS
  46.      *     the buffer is a revolving buffer located at 0x0040:001E 
  47.      *        with an offset to the next empty spot (tail)
  48.      *        and  to oldest keystroke in the buffer (head)
  49.      *    The index range is 30->60, 2 bytes per key.
  50.      *    The next keystroke is at 0x0040:K_HEAD
  51.      *    The offsets for HEAD and TAIL are stored at 0x0040:001A and 0x0040:001C
  52.      *
  53.      * The buffer is empty if the BIOS pointers to head and tail are equal.
  54.      */
  55.     #define K_HEAD  *((int far *)0x0040001AL)
  56.     #define K_TAIL  *((int far *)0x0040001CL)
  57.  
  58.     #define KBD_BUFFER_EMPTY     ( K_HEAD == K_TAIL )
  59.     #define KBD_BUFFER_NOTEMPTY  ( K_HEAD != K_TAIL )
  60. #else
  61.     /* in early version, need to have a seperate interrupt function
  62.      * for reg. versus enh. kbd.  VALUE IS 0x01 if reg kbd, 0x11 for enh kbd.
  63.      */
  64.     static unsigned char   W_NEAR   func_chk = 1;
  65. #endif  /* VERSION_11 */
  66.  
  67.  
  68.  
  69.  
  70.  
  71. #ifdef VERSION_11
  72. void wkbd_init ( void )
  73.     {
  74.  
  75.     /* logic is to stuff a char in the kbd buffer
  76.      * and use the enhanced check function to see if
  77.      * anything is there
  78.      */
  79.     int n;
  80.     unsigned char key, scancode;
  81.     PSEUDOREGS    
  82.     
  83.     /* flush keyboard by manipulating keyboard buffer
  84.      * (more compact than calling wflush_kbd() in large model.)
  85.      */
  86.     K_TAIL = K_HEAD;
  87.  
  88.  
  89.     /* write to enh. kbd buffer
  90.      *  CX contains scancodes and keycodes that are 'enhanced characters'
  91.      */
  92.     _AH = 0x05;
  93.     _CH = 0xff;
  94.     _CL = 0xff;
  95.     INTERRUPT ( 0x16 );
  96.  
  97.  
  98.     /*try to read back from the enhanced kbd. 
  99.      * If 16 tries doesn't return xff written above, then isn't enh. kbd.
  100.      */
  101.     for ( n=0; n<16; ++n )     /* note: 16 = size of kbd buffer */
  102.         {
  103.         _AH = 0x10;
  104.         INTERRUPT ( 0x16 );
  105.         key = _AL;
  106.         scancode = _AH;
  107.         if ( key == 0xff  && scancode == 0xff )
  108.             {
  109.             /* is enhanced kbd, so change function request codes.
  110.              */
  111.             func_get = 0x10;
  112.             /* dont need to set func_chk = 0x11 in version 1.1 */
  113.  
  114.             break;
  115.             }
  116.         }
  117.  
  118.     return;        /* wkbd_init, version 1.1 */
  119.     }
  120.  
  121.  
  122. #else
  123.     /* NOT VERSION_11, so Microsoft C cant detect enh. kbd. */
  124.  
  125. void wkbd_init ( void )
  126.     {
  127.  
  128.     #ifdef __TURBOC__
  129.  
  130.  
  131.     /* logic is to stuff a char in the kbd buffer
  132.      * and use the enhanced check function to see if
  133.      * anything is there
  134.      */
  135.     int n;
  136.     unsigned char key, scancode;
  137.     
  138.  
  139.     wflush_kbd ();
  140.     
  141.  
  142.     /* write to enh. kbd buffer
  143.      *  CX contains scancodes and keycodes that are 'enhanced characters'
  144.      */
  145.     _AH = 0x05;
  146.     _CH = 0xff;
  147.     _CL = 0xff;
  148.     INTERRUPT ( 0x16 );
  149.  
  150.  
  151.     /*try to read back from the enhanced kbd. 
  152.      * If 16 tries doesn't return xff written above, then isn't enh. kbd.
  153.      */
  154.     for ( n=0; n<16; ++n )     /* note: 16 = size of kbd buffer */
  155.         {
  156.         _AH = 0x10;
  157.         INTERRUPT ( 0x16 );
  158.         key = _AL;
  159.         scancode = _AH;
  160.         if ( key == 0xff  && scancode == 0xff )
  161.             {
  162.             /* is enhanced kbd, so change function request codes.
  163.              */
  164.             func_get = 0x10;
  165.             func_chk = 0x11;
  166.  
  167.             break;
  168.             }
  169.         }
  170.  
  171.  
  172.     #endif    /* TurboC */
  173.     /* if microsoft, don't check for enh kbd (can't use anyway)
  174.      *  just leave func_get = 0x00 and leave func_chk = 0x01.
  175.      */
  176.  
  177.  
  178.     return;        /* wkbd_init, version 1.0 */
  179.     }
  180. #endif        /* else not VERSION_11 */
  181.  
  182.  
  183.  
  184.  
  185.  
  186. int wkbd_enhanced (void)
  187.     {
  188.     return (func_get);    /* 0 for non-AT keyboards */
  189.     }
  190.  
  191.  
  192. /* wready_kbd()
  193.  *
  194.  *    tests keyboard only o see if a key has been hit.
  195.  *
  196.  */
  197. int wready_kbd(void)
  198.     {
  199. #ifdef VERSION_11
  200.         /* a key is ready if buffer head is not same as buffer tail.
  201.          */
  202.         return ( KBD_BUFFER_NOTEMPTY );    /* wready_kbd */
  203. #else    
  204.         /* VERSION 1.0 logic, tests zero flag, only works for TurboC */
  205.     #ifdef __TURBOC__
  206.  
  207.         register int n;
  208.  
  209.         _AH = func_chk;    /* service code for checking wready */
  210.         INTERRUPT (0x16);
  211.         n = _FLAGS;
  212.         return ( (n & 0x40) ? 0 : 1 );
  213.  
  214.     #else /* MICROSOFT C - compiler can't test the zero flags
  215.            */
  216.             #include <conio.h>
  217.             return ( kbhit() );
  218.  
  219.     #endif /* VERSION 1.0 check kbd for not TURBOC */
  220. #endif     /* else not VERSION_11 */
  221.  
  222.     }
  223.  
  224.  
  225.  
  226.  
  227. /*! wread_kbd ()
  228.  *
  229.  *    read keyboard, map extended key codes
  230.  *
  231.  *    NOTE for std/enhanced keyboard:
  232.  *        The std keybd returns keys 0-127, 0 means check scancode.
  233.  *        The enh keybd returns keys 0-255, 0 means check scancode.
  234.  *            but key values 128 & up
  235.  *                diferentiate num pad from cursor
  236.  *
  237.  *        The asignment using signed and unsigned chars bypasses this
  238.  *        so numeric keypad and cursor keypad are the same.
  239.  *        (that's how most users think about them anyways)
  240.  */
  241. int wread_kbd (void)
  242.     {
  243.     /* NOTE use of signed & unsigned to provide correct conversions.
  244.      */
  245.     signed char key;
  246.     unsigned char  scancode;
  247.     register int      retval;
  248.  
  249.     PSEUDOREGS
  250.  
  251.     _AH = func_get;  /*service requested is get data */
  252.     INTERRUPT ( 0x16 );
  253.     key =      (signed char) _AL;
  254.     scancode = (unsigned char) _AH;
  255.  
  256.     /* key mapping to place all keys into one return value
  257.      */
  258.     retval = (key>0) ?  key : 128+scancode ;
  259.  
  260.     return (retval);
  261.     }
  262.  
  263.  
  264. void wflush_kbd (void)
  265.     {
  266.     #ifdef VERSION_11
  267.     /* flush keyboard by manipulating keyboard buffer
  268.      */
  269.     K_TAIL = K_HEAD;
  270.     
  271.     #else
  272.     /* flush keyboard using interrupts.
  273.      */
  274.     while ( wready_kbd()  )
  275.         {
  276.         _AH = func_get;
  277.         INTERRUPT ( 0x16 );    /* flush kbd */
  278.         }
  279.     #endif     /* not VERSION_11 */
  280.     }
  281.  
  282.  
  283.  
  284.  
  285.     /*------------- end of wkbd.c --------------------------*/
  286.