Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

341 lines
9.2 KiB

  1. /***
  2. *getwch.c - contains _getwch(), _getwche(), _ungetwch() for Win32
  3. *
  4. * Copyright (c) 1989-2001, 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. *Revision History:
  15. * 04-19-00 GB Module created based on getch.c
  16. * 05-17-00 GB Use ERROR_CALL_NOT_IMPLEMENTED for existance of W API
  17. * 04-29-02 GB Added try-finally arounds lock-unlock.
  18. *
  19. *******************************************************************************/
  20. #include <cruntime.h>
  21. #include <oscalls.h>
  22. #include <conio.h>
  23. #include <internal.h>
  24. #include <mtdll.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <dbgint.h>
  28. #include <malloc.h>
  29. #include <wchar.h>
  30. #include <string.h>
  31. typedef struct {
  32. unsigned char LeadChar;
  33. unsigned char SecondChar;
  34. } CharPair;
  35. /*
  36. * This is the one character push-back buffer used by _getwch(), _getwche()
  37. * and _ungetwch().
  38. */
  39. static wint_t wchbuf = WEOF;
  40. static int bUseW = 2;
  41. /*
  42. * Declaration for console handle
  43. */
  44. extern intptr_t _coninpfh;
  45. /*
  46. * Function that looks up the extended key code for a given event.
  47. */
  48. const CharPair * __cdecl _getextendedkeycode(KEY_EVENT_RECORD *);
  49. /***
  50. *wint_t _getwch(), _getwche() - read one char. from console (without and with
  51. * echo)
  52. *
  53. *Purpose:
  54. * If the "_ungetwch()" push-back buffer is not empty (empty==-1) Then
  55. * Mark it empty (-1) and RETURN the value that was in it
  56. * Read a character using ReadConsole in RAW mode
  57. * Return the Character Code
  58. * _getwche(): Same as _getwch() except that the character value returned
  59. * is echoed (via "_putwch()")
  60. *
  61. *Entry:
  62. * None, reads from console.
  63. *
  64. *Exit:
  65. * If an error is returned from the API
  66. * Then WEOF
  67. * Otherwise
  68. * next byte from console
  69. * Static variable "wchbuf" may be altered
  70. *
  71. *Exceptions:
  72. *
  73. *******************************************************************************/
  74. #ifdef _MT
  75. wint_t __cdecl _getwch (
  76. void
  77. )
  78. {
  79. wchar_t wch;
  80. _mlock(_CONIO_LOCK); /* secure the console lock */
  81. __TRY
  82. wch = _getwch_lk(); /* input the character */
  83. __FINALLY
  84. _munlock(_CONIO_LOCK); /* release the console lock */
  85. __END_TRY_FINALLY
  86. return wch;
  87. }
  88. wint_t __cdecl _getwche (
  89. void
  90. )
  91. {
  92. wchar_t wch;
  93. _mlock(_CONIO_LOCK); /* secure the console lock */
  94. __TRY
  95. wch = _getwche_lk(); /* input and echo the character */
  96. __FINALLY
  97. _munlock(_CONIO_LOCK); /* unlock the console */
  98. __END_TRY_FINALLY
  99. return wch;
  100. }
  101. #endif /* _MT */
  102. #ifdef _MT
  103. wint_t __cdecl _getwch_lk (
  104. #else
  105. wint_t __cdecl _getwch (
  106. #endif
  107. void
  108. )
  109. {
  110. INPUT_RECORD ConInpRec;
  111. DWORD NumRead;
  112. const CharPair *pCP;
  113. wchar_t wch = 0; /* single character buffer */
  114. DWORD oldstate;
  115. char ch;
  116. /*
  117. * check pushback buffer (wchbuf) a for character
  118. */
  119. if ( wchbuf != WEOF ) {
  120. /*
  121. * something there, clear buffer and return the character.
  122. */
  123. wch = (wchar_t)(wchbuf & 0xFFFF);
  124. wchbuf = WEOF;
  125. return wch;
  126. }
  127. if (_coninpfh == -1)
  128. return WEOF;
  129. /*
  130. * _coninpfh, the handle to the console input, is created the first
  131. * time that either _getwch() or _cgetws() or _kbhit() is called.
  132. */
  133. if ( _coninpfh == -2 )
  134. __initconin();
  135. /*
  136. * Switch to raw mode (no line input, no echo input)
  137. */
  138. GetConsoleMode( (HANDLE)_coninpfh, &oldstate );
  139. SetConsoleMode( (HANDLE)_coninpfh, 0L );
  140. for ( ; ; ) {
  141. /*
  142. * Get a console input event.
  143. */
  144. if ( bUseW ) {
  145. if ( !ReadConsoleInputW( (HANDLE)_coninpfh,
  146. &ConInpRec,
  147. 1L,
  148. &NumRead)) {
  149. if ( bUseW == 2 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
  150. bUseW = FALSE;
  151. else {
  152. wch = WEOF;
  153. break;
  154. }
  155. }
  156. else
  157. bUseW = TRUE;
  158. if ( NumRead == 0) {
  159. wch = WEOF;
  160. break;
  161. }
  162. }
  163. if ( !bUseW) {
  164. if ( !ReadConsoleInputA( (HANDLE) _coninpfh,
  165. &ConInpRec,
  166. 1L,
  167. &NumRead )
  168. || (NumRead == 0)) {
  169. wch = WEOF;
  170. break;
  171. }
  172. }
  173. /*
  174. * Look for, and decipher, key events.
  175. */
  176. if ( (ConInpRec.EventType == KEY_EVENT) &&
  177. ConInpRec.Event.KeyEvent.bKeyDown ) {
  178. /*
  179. * Easy case: if uChar.AsciiChar is non-zero, just stuff it
  180. * into wch and quit.
  181. */
  182. if (bUseW) {
  183. if ( wch = (wchar_t)ConInpRec.Event.KeyEvent.uChar.UnicodeChar )
  184. break;
  185. }
  186. else {
  187. if ( ch = ConInpRec.Event.KeyEvent.uChar.AsciiChar ) {
  188. MultiByteToWideChar(GetConsoleCP(),
  189. 0,
  190. &ch,
  191. 1,
  192. &wch,
  193. 1);
  194. break;
  195. }
  196. }
  197. /*
  198. * Hard case: either an extended code or an event which should
  199. * not be recognized. let _getextendedkeycode() do the work...
  200. */
  201. if ( pCP = _getextendedkeycode( &(ConInpRec.Event.KeyEvent) ) ) {
  202. wch = pCP->LeadChar;
  203. wchbuf = pCP->SecondChar;
  204. break;
  205. }
  206. }
  207. }
  208. /*
  209. * Restore previous console mode.
  210. */
  211. SetConsoleMode( (HANDLE)_coninpfh, oldstate );
  212. return wch;
  213. }
  214. /*
  215. * getwche is just getwch followed by a putch if no error occurred
  216. */
  217. #ifdef _MT
  218. wint_t __cdecl _getwche_lk (
  219. #else
  220. wint_t __cdecl _getwche (
  221. #endif
  222. void
  223. )
  224. {
  225. wchar_t wch; /* character read */
  226. /*
  227. * check pushback buffer (wchbuf) a for character. if found, return
  228. * it without echoing.
  229. */
  230. if ( wchbuf != WEOF ) {
  231. /*
  232. * something there, clear buffer and return the character.
  233. */
  234. wch = (wchar_t)(wchbuf & 0xFFFF);
  235. wchbuf = WEOF;
  236. return wch;
  237. }
  238. wch = _getwch_lk(); /* read character */
  239. if (wch != WEOF) {
  240. if (_putwch_lk(wch) != WEOF) {
  241. return wch; /* if no error, return char */
  242. }
  243. }
  244. return WEOF; /* get or put failed, return EOF */
  245. }
  246. /***
  247. *wint_t _ungetwch(c) - push back one character for "_getwch()" or "_getwche()"
  248. *
  249. *Purpose:
  250. * If the Push-back buffer "wchbuf" is -1 Then
  251. * Set "wchbuf" to the argument and return the argument
  252. * Else
  253. * Return EOF to indicate an error
  254. *
  255. *Entry:
  256. * int c - Character to be pushed back
  257. *
  258. *Exit:
  259. * If successful
  260. * returns character that was pushed back
  261. * Else if error
  262. * returns EOF
  263. *
  264. *Exceptions:
  265. *
  266. *******************************************************************************/
  267. #ifdef _MT
  268. wint_t __cdecl _ungetwch (
  269. wint_t c
  270. )
  271. {
  272. wchar_t retval;
  273. _mlock(_CONIO_LOCK); /* lock the console */
  274. __TRY
  275. retval = _ungetwch_lk(c); /* pushback character */
  276. __FINALLY
  277. _munlock(_CONIO_LOCK); /* unlock the console */
  278. __END_TRY_FINALLY
  279. return retval;
  280. }
  281. wint_t __cdecl _ungetwch_lk (
  282. #else
  283. wint_t __cdecl _ungetwch (
  284. #endif
  285. wint_t c
  286. )
  287. {
  288. /*
  289. * Fail if the char is EOF or the pushback buffer is non-empty
  290. */
  291. if ( (c == WEOF) || (wchbuf != WEOF) )
  292. return EOF;
  293. wchbuf = (c & 0xFF);
  294. return wchbuf;
  295. }