home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / getch.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  22KB  |  669 lines

  1. /***
  2. *getch.c - contains _getch(), _getche(), _ungetch() and kbhit for Win32
  3. *
  4. *       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       Defines the "direct console" functions listed above.
  8. *
  9. *       NOTE: The real-mode DOS versions of these functions read from
  10. *       standard input and are therefore redirected when standard input
  11. *       is redirected. However, these versions ALWAYS read from the console,
  12. *       even when standard input is redirected.
  13. *
  14. *******************************************************************************/
  15.  
  16. #include <cruntime.h>
  17. #include <oscalls.h>
  18. #include <conio.h>
  19. #include <internal.h>
  20. #include <mtdll.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <dbgint.h>
  24.  
  25. typedef struct {
  26.         unsigned char LeadChar;
  27.         unsigned char SecondChar;
  28.         } CharPair;
  29.  
  30. typedef struct {
  31.         unsigned short ScanCode;
  32.         CharPair RegChars;
  33.         CharPair ShiftChars;
  34.         CharPair CtrlChars;
  35.         CharPair AltChars;
  36.         } EnhKeyVals;
  37.  
  38. typedef struct {
  39.         CharPair RegChars;
  40.         CharPair ShiftChars;
  41.         CharPair CtrlChars;
  42.         CharPair AltChars;
  43.         } NormKeyVals;
  44.  
  45. /*
  46.  * Table of key values for enhanced keys
  47.  */
  48. static EnhKeyVals EnhancedKeys[] = {
  49.         { 28, {  13,   0 }, {  13,   0 }, {  10,   0 }, {   0, 166 } },
  50.         { 53, {  47,   0 }, {  63,   0 }, {   0, 149 }, {   0, 164 } },
  51.         { 71, { 224,  71 }, { 224,  71 }, { 224, 119 }, {   0, 151 } },
  52.         { 72, { 224,  72 }, { 224,  72 }, { 224, 141 }, {   0, 152 } },
  53.         { 73, { 224,  73 }, { 224,  73 }, { 224, 134 }, {   0, 153 } },
  54.         { 75, { 224,  75 }, { 224,  75 }, { 224, 115 }, {   0, 155 } },
  55.         { 77, { 224,  77 }, { 224,  77 }, { 224, 116 }, {   0, 157 } },
  56.         { 79, { 224,  79 }, { 224,  79 }, { 224, 117 }, {   0, 159 } },
  57.         { 80, { 224,  80 }, { 224,  80 }, { 224, 145 }, {   0, 160 } },
  58.         { 81, { 224,  81 }, { 224,  81 }, { 224, 118 }, {   0, 161 } },
  59.         { 82, { 224,  82 }, { 224,  82 }, { 224, 146 }, {   0, 162 } },
  60.         { 83, { 224,  83 }, { 224,  83 }, { 224, 147 }, {   0, 163 } }
  61.         };
  62.  
  63. /*
  64.  * macro for the number of elements of in EnhancedKeys[]
  65.  */
  66. #define NUM_EKA_ELTS    ( sizeof( EnhancedKeys ) / sizeof( EnhKeyVals ) )
  67.  
  68. /*
  69.  * Table of key values for normal keys. Note that the table is padded so
  70.  * that the key scan code serves as an index into the table.
  71.  */
  72. static NormKeyVals NormalKeys[] = {
  73.  
  74.         /* padding */
  75.         { /*  0 */ {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
  76.  
  77.         { /*  1 */ {  27,   0 }, {  27,   0 }, {  27,   0 }, {   0,   1 } },
  78.         { /*  2 */ {  49,   0 }, {  33,   0 }, {   0,   0 }, {   0, 120 } },
  79.         { /*  3 */ {  50,   0 }, {  64,   0 }, {   0,   3 }, {   0, 121 } },
  80.         { /*  4 */ {  51,   0 }, {  35,   0 }, {   0,   0 }, {   0, 122 } },
  81.         { /*  5 */ {  52,   0 }, {  36,   0 }, {   0,   0 }, {   0, 123 } },
  82.         { /*  6 */ {  53,   0 }, {  37,   0 }, {   0,   0 }, {   0, 124 } },
  83.         { /*  7 */ {  54,   0 }, {  94,   0 }, {  30,   0 }, {   0, 125 } },
  84.         { /*  8 */ {  55,   0 }, {  38,   0 }, {   0,   0 }, {   0, 126 } },
  85.         { /*  9 */ {  56,   0 }, {  42,   0 }, {   0,   0 }, {   0, 127 } },
  86.         { /* 10 */ {  57,   0 }, {  40,   0 }, {   0,   0 }, {   0, 128 } },
  87.         { /* 11 */ {  48,   0 }, {  41,   0 }, {   0,   0 }, {   0, 129 } },
  88.         { /* 12 */ {  45,   0 }, {  95,   0 }, {  31,   0 }, {   0, 130 } },
  89.         { /* 13 */ {  61,   0 }, {  43,   0 }, {   0,   0 }, {   0, 131 } },
  90.         { /* 14 */ {   8,   0 }, {   8,   0 }, { 127,   0 }, {   0,  14 } },
  91.         { /* 15 */ {   9,   0 }, {   0,  15 }, {   0, 148 }, {   0,  15 } },
  92.         { /* 16 */ { 113,   0 }, {  81,   0 }, {  17,   0 }, {   0,  16 } },
  93.         { /* 17 */ { 119,   0 }, {  87,   0 }, {  23,   0 }, {   0,  17 } },
  94.         { /* 18 */ { 101,   0 }, {  69,   0 }, {   5,   0 }, {   0,  18 } },
  95.         { /* 19 */ { 114,   0 }, {  82,   0 }, {  18,   0 }, {   0,  19 } },
  96.         { /* 20 */ { 116,   0 }, {  84,   0 }, {  20,   0 }, {   0,  20 } },
  97.         { /* 21 */ { 121,   0 }, {  89,   0 }, {  25,   0 }, {   0,  21 } },
  98.         { /* 22 */ { 117,   0 }, {  85,   0 }, {  21,   0 }, {   0,  22 } },
  99.         { /* 23 */ { 105,   0 }, {  73,   0 }, {   9,   0 }, {   0,  23 } },
  100.         { /* 24 */ { 111,   0 }, {  79,   0 }, {  15,   0 }, {   0,  24 } },
  101.         { /* 25 */ { 112,   0 }, {  80,   0 }, {  16,   0 }, {   0,  25 } },
  102.         { /* 26 */ {  91,   0 }, { 123,   0 }, {  27,   0 }, {   0,  26 } },
  103.         { /* 27 */ {  93,   0 }, { 125,   0 }, {  29,   0 }, {   0,  27 } },
  104.         { /* 28 */ {  13,   0 }, {  13,   0 }, {  10,   0 }, {   0,  28 } },
  105.  
  106.         /* padding */
  107.         { /* 29 */ {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
  108.  
  109.         { /* 30 */ {  97,   0 }, {  65,   0 }, {   1,   0 }, {   0,  30 } },
  110.         { /* 31 */ { 115,   0 }, {  83,   0 }, {  19,   0 }, {   0,  31 } },
  111.         { /* 32 */ { 100,   0 }, {  68,   0 }, {   4,   0 }, {   0,  32 } },
  112.         { /* 33 */ { 102,   0 }, {  70,   0 }, {   6,   0 }, {   0,  33 } },
  113.         { /* 34 */ { 103,   0 }, {  71,   0 }, {   7,   0 }, {   0,  34 } },
  114.         { /* 35 */ { 104,   0 }, {  72,   0 }, {   8,   0 }, {   0,  35 } },
  115.         { /* 36 */ { 106,   0 }, {  74,   0 }, {  10,   0 }, {   0,  36 } },
  116.         { /* 37 */ { 107,   0 }, {  75,   0 }, {  11,   0 }, {   0,  37 } },
  117.         { /* 38 */ { 108,   0 }, {  76,   0 }, {  12,   0 }, {   0,  38 } },
  118.         { /* 39 */ {  59,   0 }, {  58,   0 }, {   0,   0 }, {   0,  39 } },
  119.         { /* 40 */ {  39,   0 }, {  34,   0 }, {   0,   0 }, {   0,  40 } },
  120.         { /* 41 */ {  96,   0 }, { 126,   0 }, {   0,   0 }, {   0,  41 } },
  121.  
  122.         /* padding */
  123.         { /* 42 */ {    0,  0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
  124.  
  125.         { /* 43 */ {  92,   0 }, { 124,   0 }, {  28,   0 }, {   0,   0 } },
  126.         { /* 44 */ { 122,   0 }, {  90,   0 }, {  26,   0 }, {   0,  44 } },
  127.         { /* 45 */ { 120,   0 }, {  88,   0 }, {  24,   0 }, {   0,  45 } },
  128.         { /* 46 */ {  99,   0 }, {  67,   0 }, {   3,   0 }, {   0,  46 } },
  129.         { /* 47 */ { 118,   0 }, {  86,   0 }, {  22,   0 }, {   0,  47 } },
  130.         { /* 48 */ {  98,   0 }, {  66,   0 }, {   2,   0 }, {   0,  48 } },
  131.         { /* 49 */ { 110,   0 }, {  78,   0 }, {  14,   0 }, {   0,  49 } },
  132.         { /* 50 */ { 109,   0 }, {  77,   0 }, {  13,   0 }, {   0,  50 } },
  133.         { /* 51 */ {  44,   0 }, {  60,   0 }, {   0,   0 }, {   0,  51 } },
  134.         { /* 52 */ {  46,   0 }, {  62,   0 }, {   0,   0 }, {   0,  52 } },
  135.         { /* 53 */ {  47,   0 }, {  63,   0 }, {   0,   0 }, {   0,  53 } },
  136.  
  137.         /* padding */
  138.         { /* 54 */ {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
  139.  
  140.         { /* 55 */ {  42,   0 }, {   0,   0 }, { 114,   0 }, {   0,   0 } },
  141.  
  142.         /* padding */
  143.         { /* 56 */ {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
  144.  
  145.         { /* 57 */ {  32,   0 }, {  32,   0 }, {  32,   0 }, {  32,   0 } },
  146.  
  147.         /* padding */
  148.         { /* 58 */ {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
  149.  
  150.         { /* 59 */ {   0,  59 }, {   0,  84 }, {   0,  94 }, {   0, 104 } },
  151.         { /* 60 */ {   0,  60 }, {   0,  85 }, {   0,  95 }, {   0, 105 } },
  152.         { /* 61 */ {   0,  61 }, {   0,  86 }, {   0,  96 }, {   0, 106 } },
  153.         { /* 62 */ {   0,  62 }, {   0,  87 }, {   0,  97 }, {   0, 107 } },
  154.         { /* 63 */ {   0,  63 }, {   0,  88 }, {   0,  98 }, {   0, 108 } },
  155.         { /* 64 */ {   0,  64 }, {   0,  89 }, {   0,  99 }, {   0, 109 } },
  156.         { /* 65 */ {   0,  65 }, {   0,  90 }, {   0, 100 }, {   0, 110 } },
  157.         { /* 66 */ {   0,  66 }, {   0,  91 }, {   0, 101 }, {   0, 111 } },
  158.         { /* 67 */ {   0,  67 }, {   0,  92 }, {   0, 102 }, {   0, 112 } },
  159.         { /* 68 */ {   0,  68 }, {   0,  93 }, {   0, 103 }, {   0, 113 } },
  160.  
  161.         /* padding */
  162.         { /* 69 */ {    0,  0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
  163.         { /* 70 */ {    0,  0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
  164.  
  165.         { /* 71 */ {   0,  71 }, {  55,   0 }, {   0, 119 }, {   0,   0 } },
  166.         { /* 72 */ {   0,  72 }, {  56,   0 }, {   0, 141 }, {   0,   0 } },
  167.         { /* 73 */ {   0,  73 }, {  57,   0 }, {   0, 132 }, {   0,   0 } },
  168.         { /* 74 */ {   0,   0 }, {  45,   0 }, {   0,   0 }, {   0,   0 } },
  169.         { /* 75 */ {   0,  75 }, {  52,   0 }, {   0, 115 }, {   0,   0 } },
  170.         { /* 76 */ {   0,   0 }, {  53,   0 }, {   0,   0 }, {   0,   0 } },
  171.         { /* 77 */ {   0,  77 }, {  54,   0 }, {   0, 116 }, {   0,   0 } },
  172.         { /* 78 */ {   0,   0 }, {  43,   0 }, {   0,   0 }, {   0,   0 } },
  173.         { /* 79 */ {   0,  79 }, {  49,   0 }, {   0, 117 }, {   0,   0 } },
  174.         { /* 80 */ {   0,  80 }, {  50,   0 }, {   0, 145 }, {   0,   0 } },
  175.         { /* 81 */ {   0,  81 }, {  51,   0 }, {   0, 118 }, {   0,   0 } },
  176.         { /* 82 */ {   0,  82 }, {  48,   0 }, {   0, 146 }, {   0,   0 } },
  177.         { /* 83 */ {   0,  83 }, {  46,   0 }, {   0, 147 }, {   0,   0 } },
  178.  
  179.         /* padding */
  180.         { /* 84 */ {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
  181.         { /* 85 */ {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
  182.         { /* 86 */ {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
  183.  
  184.         { /* 87 */ { 224, 133 }, { 224, 135 }, { 224, 137 }, { 224, 139 } },
  185.         { /* 88 */ { 224, 134 }, { 224, 136 }, { 224, 138 }, { 224, 140 } }
  186.  
  187. };
  188.  
  189.  
  190. /*
  191.  * This is the one character push-back buffer used by _getch(), _getche()
  192.  * and _ungetch().
  193.  */
  194. static int chbuf = EOF;
  195.  
  196.  
  197. /*
  198.  * Declaration for console handle
  199.  */
  200. extern int _coninpfh;
  201.  
  202. /*
  203.  * Function that looks up the extended key code for a given event.
  204.  */
  205. static CharPair * __cdecl _getextendedkeycode(KEY_EVENT_RECORD *);
  206.  
  207.  
  208. /***
  209. *int _getch(), _getche() - read one char. from console (without and with echo)
  210. *
  211. *Purpose:
  212. *       If the "_ungetch()" push-back buffer is not empty (empty==-1) Then
  213. *           Mark it empty (-1) and RETURN the value that was in it
  214. *       Read a character using ReadConsole in RAW mode
  215. *       Return the Character Code
  216. *       _getche(): Same as _getch() except that the character value returned
  217. *       is echoed (via "_putch()")
  218. *
  219. *Entry:
  220. *       None, reads from console.
  221. *
  222. *Exit:
  223. *       If an error is returned from the API
  224. *           Then EOF
  225. *       Otherwise
  226. *            next byte from console
  227. *       Static variable "chbuf" may be altered
  228. *
  229. *Exceptions:
  230. *
  231. *******************************************************************************/
  232.  
  233. #ifdef _MT
  234.  
  235. int __cdecl _getch (
  236.         void
  237.         )
  238. {
  239.         int ch;
  240.  
  241.         _mlock(_CONIO_LOCK);            /* secure the console lock */
  242.         ch = _getch_lk();               /* input the character */
  243.         _munlock(_CONIO_LOCK);          /* release the console lock */
  244.  
  245.         return ch;
  246. }
  247.  
  248. int __cdecl _getche (
  249.         void
  250.         )
  251. {
  252.         int ch;
  253.  
  254.         _mlock(_CONIO_LOCK);            /* secure the console lock */
  255.         ch = _getche_lk();              /* input and echo the character */
  256.         _munlock(_CONIO_LOCK);          /* unlock the console */
  257.  
  258.         return ch;
  259. }
  260.  
  261. #endif  /* _MT */
  262.  
  263.  
  264. #ifdef _MT
  265. int __cdecl _getch_lk (
  266. #else  /* _MT */
  267. int __cdecl _getch (
  268. #endif  /* _MT */
  269.         void
  270.         )
  271. {
  272.         INPUT_RECORD ConInpRec;
  273.         DWORD NumRead;
  274.         CharPair *pCP;
  275.         int ch = 0;                     /* single character buffer */
  276.         DWORD oldstate;
  277.  
  278.         /*
  279.          * check pushback buffer (chbuf) a for character
  280.          */
  281.         if ( chbuf != EOF ) {
  282.             /*
  283.              * something there, clear buffer and return the character.
  284.              */
  285.             ch = (unsigned char)(chbuf & 0xFF);
  286.             chbuf = EOF;
  287.             return ch;
  288.         }
  289.  
  290.         if (_coninpfh == -1)
  291.             return EOF;
  292.  
  293.         /*
  294.          * _coninpfh, the handle to the console input, is created the first
  295.          * time that either _getch() or _cgets() or _kbhit() is called.
  296.          */
  297.  
  298.         if ( _coninpfh == -2 )
  299.             __initconin();
  300.  
  301.         /*
  302.          * Switch to raw mode (no line input, no echo input)
  303.          */
  304.         GetConsoleMode( (HANDLE)_coninpfh, &oldstate );
  305.         SetConsoleMode( (HANDLE)_coninpfh, 0L );
  306.  
  307.         for ( ; ; ) {
  308.  
  309.             /*
  310.              * Get a console input event.
  311.              */
  312.             if ( !ReadConsoleInput( (HANDLE)_coninpfh,
  313.                                     &ConInpRec,
  314.                                     1L,
  315.                                     &NumRead )
  316.                  || (NumRead == 0L) )
  317.             {
  318.                 ch = EOF;
  319.                 break;
  320.             }
  321.  
  322.             /*
  323.              * Look for, and decipher, key events.
  324.              */
  325.             if ( (ConInpRec.EventType == KEY_EVENT) &&
  326.                  ConInpRec.Event.KeyEvent.bKeyDown ) {
  327.                 /*
  328.                  * Easy case: if uChar.AsciiChar is non-zero, just stuff it
  329.                  * into ch and quit.
  330.                  */
  331.  
  332.                 if ( ch = (unsigned char)ConInpRec.Event.KeyEvent.uChar.AsciiChar )
  333.                     break;
  334.  
  335.                 /*
  336.                  * Hard case: either an extended code or an event which should
  337.                  * not be recognized. let _getextendedkeycode() do the work...
  338.                  */
  339.                 if ( pCP = _getextendedkeycode( &(ConInpRec.Event.KeyEvent) ) ) {
  340.                     ch = pCP->LeadChar;
  341.                     chbuf = pCP->SecondChar;
  342.                     break;
  343.                 }
  344.             }
  345.         }
  346.  
  347.  
  348.         /*
  349.          * Restore previous console mode.
  350.          */
  351.         SetConsoleMode( (HANDLE)_coninpfh, oldstate );
  352.  
  353.         return ch;
  354. }
  355.  
  356.  
  357. /*
  358.  * getche is just getch followed by a putch if no error occurred
  359.  */
  360.  
  361. #ifdef _MT
  362. int __cdecl _getche_lk (
  363. #else  /* _MT */
  364. int __cdecl _getche (
  365. #endif  /* _MT */
  366.         void
  367.         )
  368. {
  369.         int ch;                 /* character read */
  370.  
  371.         /*
  372.          * check pushback buffer (chbuf) a for character. if found, return
  373.          * it without echoing.
  374.          */
  375.         if ( chbuf != EOF ) {
  376.             /*
  377.              * something there, clear buffer and return the character.
  378.              */
  379.             ch = (unsigned char)(chbuf & 0xFF);
  380.             chbuf = EOF;
  381.             return ch;
  382.         }
  383.  
  384.         ch = _getch_lk();       /* read character */
  385.  
  386.         if (ch != EOF) {
  387.                 if (_putch_lk(ch) != EOF) {
  388.                         return ch;      /* if no error, return char */
  389.                 }
  390.         }
  391.         return EOF;                     /* get or put failed, return EOF */
  392. }
  393.  
  394.  
  395. /***
  396. *int _kbhit() - return flag if a keystroke is already waiting to be read
  397. *
  398. *Purpose:
  399. *       If the "_ungetch()" push-back buffer is not empty (empty==-1) Then
  400. *           Return TRUE
  401. *       Otherwise get the Keyboard Status (via DOSQUERYFHSTATE)
  402. *
  403. *Entry:
  404. *       None, tests console.
  405. *
  406. *Exit:
  407. *            returns 0 if no key waiting
  408. *                = !0 if key waiting
  409. *
  410. *Exceptions:
  411. *
  412. *******************************************************************************/
  413.  
  414. #ifdef _MT
  415.  
  416. int __cdecl _kbhit_lk(void);
  417.  
  418. int __cdecl _kbhit (
  419.         void
  420.         )
  421. {
  422.         int retval;
  423.  
  424.         _mlock(_CONIO_LOCK);            /* secure the console lock */
  425.         retval = _kbhit_lk();           /* determine if a key is waiting */
  426.         _munlock(_CONIO_LOCK);          /* release the console lock */
  427.  
  428.         return retval;
  429. }
  430.  
  431. int __cdecl _kbhit_lk (
  432.  
  433. #else  /* _MT */
  434.  
  435. int __cdecl _kbhit (
  436.  
  437. #endif  /* _MT */
  438.         void
  439.         )
  440. {
  441.         PINPUT_RECORD pIRBuf;
  442.         DWORD NumPending;
  443.         DWORD NumPeeked;
  444.  
  445.         /*
  446.          * if a character has been pushed back, return TRUE
  447.          */
  448.         if ( chbuf != -1 )
  449.             return TRUE;
  450.  
  451.         /*
  452.          * _coninpfh, the handle to the console input, is created the first
  453.          * time that either _getch() or _cgets() or _kbhit() is called.
  454.          */
  455.  
  456.         if ( _coninpfh == -2 )
  457.             __initconin();
  458.  
  459.         /*
  460.          * Peek all pending console events
  461.          */
  462.         if ( (_coninpfh == -1) ||
  463.  
  464.              !GetNumberOfConsoleInputEvents((HANDLE)_coninpfh, &NumPending) ||
  465.  
  466.              (NumPending == 0) ||
  467.  
  468.              ((pIRBuf = (PINPUT_RECORD)_alloca( NumPending *
  469.                sizeof(INPUT_RECORD) )) == NULL) )
  470.         {
  471.             return FALSE;
  472.         }
  473.  
  474.         if ( PeekConsoleInput( (HANDLE)_coninpfh,
  475.                                pIRBuf,
  476.                                NumPending,
  477.                                &NumPeeked ) &&
  478.  
  479.              (NumPeeked != 0L) &&
  480.  
  481.              (NumPeeked <= NumPending) )
  482.         {
  483.  
  484.             /*
  485.              * Scan all of the peeked events to determine if any is a key event
  486.              * which should be recognized.
  487.              */
  488.             for ( ; NumPeeked > 0 ; NumPeeked--, pIRBuf++ ) {
  489.  
  490.                 if ( (pIRBuf->EventType == KEY_EVENT) &&
  491.  
  492.                      (pIRBuf->Event.KeyEvent.bKeyDown) &&
  493.  
  494.                      ( pIRBuf->Event.KeyEvent.uChar.AsciiChar ||
  495.                        _getextendedkeycode( &(pIRBuf->Event.KeyEvent) ) ) )
  496.                 {
  497.                     /*
  498.                      * Key event corresponding to an ASCII character or an
  499.                      * extended code. In either case, success!
  500.                      */
  501.                     return TRUE;
  502.                 }
  503.             }
  504.         }
  505.  
  506.         return FALSE;
  507. }
  508.  
  509.  
  510. /***
  511. *int _ungetch(c) - push back one character for "_getch()" or "_getche()"
  512. *
  513. *Purpose:
  514. *       If the Push-back buffer "chbuf" is -1 Then
  515. *           Set "chbuf" to the argument and return the argument
  516. *       Else
  517. *           Return EOF to indicate an error
  518. *
  519. *Entry:
  520. *       int c - Character to be pushed back
  521. *
  522. *Exit:
  523. *       If successful
  524. *           returns character that was pushed back
  525. *       Else if error
  526. *           returns EOF
  527. *
  528. *Exceptions:
  529. *
  530. *******************************************************************************/
  531.  
  532. #ifdef _MT
  533.  
  534. int __cdecl _ungetch (
  535.         int c
  536.         )
  537. {
  538.         int retval;
  539.  
  540.         _mlock(_CONIO_LOCK);            /* lock the console */
  541.         retval = _ungetch_lk(c);        /* pushback character */
  542.         _munlock(_CONIO_LOCK);          /* unlock the console */
  543.  
  544.         return retval;
  545. }
  546. int __cdecl _ungetch_lk (
  547.  
  548. #else  /* _MT */
  549.  
  550. int __cdecl _ungetch (
  551.  
  552. #endif  /* _MT */
  553.         int c
  554.         )
  555. {
  556.         /*
  557.          * Fail if the char is EOF or the pushback buffer is non-empty
  558.          */
  559.         if ( (c == EOF) || (chbuf != EOF) )
  560.             return EOF;
  561.  
  562.         chbuf = (c & 0xFF);
  563.         return chbuf;
  564. }
  565.  
  566.  
  567.  
  568.  
  569. /***
  570. * static CharPair * _getextendedkeycode(pKE) - return extended code (if any)
  571. *       for key event.
  572. *
  573. *Purpose:
  574. *       Core function for _getch (and getche) and essential to _kbhit. This
  575. *       is the function that determines whether or not a key event NOT
  576. *       accompanied by an ASCII character has an extended code and returns
  577. *       that code.
  578. *
  579. *Entry:
  580. *       None, tests console.
  581. *
  582. *Exit:
  583. *       if successful, returns a pointer to a CharPair value holding the lead
  584. *       and second characters of the extended code.
  585. *
  586. *       if unsuccesful, returns NULL
  587. *
  588. *Exceptions:
  589. *
  590. *******************************************************************************/
  591.  
  592.  
  593. static CharPair * __cdecl _getextendedkeycode (
  594.         KEY_EVENT_RECORD *pKE
  595.         )
  596. {
  597.         DWORD CKS;              /* hold dwControlKeyState value */
  598.         CharPair *pCP;          /* pointer to CharPair containing extended
  599.                                    code */
  600.         int i;
  601.  
  602.         if ( (CKS = pKE->dwControlKeyState) & ENHANCED_KEY ) {
  603.  
  604.             /*
  605.              * Find the appropriate entry in EnhancedKeys[]
  606.              */
  607.             for ( pCP = NULL, i = 0 ; i < NUM_EKA_ELTS ; i++ ) {
  608.  
  609.                 if ( EnhancedKeys[i].ScanCode == pKE->wVirtualScanCode ) {
  610.  
  611.                     if ( CKS & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) )
  612.  
  613.                         pCP = &(EnhancedKeys[i].AltChars);
  614.  
  615.                     else if ( CKS & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) )
  616.  
  617.                         pCP = &(EnhancedKeys[i].CtrlChars);
  618.  
  619.                     else if ( CKS & SHIFT_PRESSED)
  620.  
  621.                         pCP = &(EnhancedKeys[i].ShiftChars);
  622.  
  623.                     else
  624.  
  625.                         pCP = &(EnhancedKeys[i].RegChars);
  626.  
  627.                     break;
  628.  
  629.                 }
  630.             }
  631.  
  632.         }
  633.  
  634.         else {
  635.  
  636.             /*
  637.              * Regular key or a keyboard event which shouldn't be recognized.
  638.              * Determine which by getting the proper field of the proper
  639.              * entry in NormalKeys[], and examining the extended code.
  640.              */
  641.             if ( CKS & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) )
  642.  
  643.                 pCP = &(NormalKeys[pKE->wVirtualScanCode].AltChars);
  644.  
  645.             else if ( CKS & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) )
  646.  
  647.                 pCP = &(NormalKeys[pKE->wVirtualScanCode].CtrlChars);
  648.  
  649.             else if ( CKS & SHIFT_PRESSED)
  650.  
  651.                 pCP = &(NormalKeys[pKE->wVirtualScanCode].ShiftChars);
  652.  
  653.             else
  654.  
  655.                 pCP = &(NormalKeys[pKE->wVirtualScanCode].RegChars);
  656.  
  657.             if ( ((pCP->LeadChar != 0) && (pCP->LeadChar != 224)) ||
  658.                  (pCP->SecondChar == 0) )
  659.                 /*
  660.                  * Must be a keyboard event which should not be recognized
  661.                  * (e.g., shift key was pressed)
  662.                  */
  663.                 pCP = NULL;
  664.  
  665.         }
  666.  
  667.         return(pCP);
  668. }
  669.