Source code of Windows XP (NT5)
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.

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