Reactos
at master 205 lines 5.1 kB view raw
1// 2// getwch.cpp 3// 4// Copyright (c) Microsoft Corporation. All rights reserved. 5// 6// Defines _getwch(), _getwche(), and _ungetwch(), which get and unget 7// characters directly from the console. 8// 9#include <conio.h> 10#include <corecrt_internal_lowio.h> 11#include <stdio.h> 12#include <stdlib.h> 13#include <string.h> 14#include <wchar.h> 15 16 17 18namespace 19{ 20 struct CharPair 21 { 22 unsigned char LeadChar; 23 unsigned char SecondChar; 24 }; 25} 26 27 28static wint_t wchbuf = WEOF; // The push-back buffer 29 30extern "C" intptr_t __dcrt_lowio_console_input_handle; 31 32extern "C" CharPair const* __cdecl _getextendedkeycode(KEY_EVENT_RECORD*); 33 34 35 36// Reads one character directly from the console. The _getwche() form also 37// echoes the character back to the console. If the push-back buffer is 38// nonempty, then its value is returned and the push-back buffer is marked as 39// empty. 40// 41// Returns the character that is read on success; returns WEOF on failure. 42extern "C" wint_t __cdecl _getwch() 43{ 44 __acrt_lock(__acrt_conio_lock); 45 wint_t result = 0; 46 __try 47 { 48 result = _getwch_nolock(); 49 } 50 __finally 51 { 52 __acrt_unlock(__acrt_conio_lock); 53 } 54 __endtry 55 return result; 56} 57 58 59extern "C" wint_t __cdecl _getwche() 60{ 61 __acrt_lock(__acrt_conio_lock); 62 wint_t result = 0; 63 __try 64 { 65 result = _getwche_nolock(); 66 } 67 __finally 68 { 69 __acrt_unlock(__acrt_conio_lock); 70 } 71 __endtry 72 return result; 73} 74 75 76 77extern "C" wint_t __cdecl _getwch_nolock() 78{ 79 // First check the pushback buffer for a character. If it has one, return 80 // it without echoing and reset the buffer: 81 if (wchbuf != WEOF) 82 { 83 wchar_t const buffered_wchar = static_cast<wchar_t>(wchbuf & 0xFFFF); 84 wchbuf = WEOF; 85 return buffered_wchar; 86 } 87 88 // The console input handle is created the first time that _getwch(), 89 // _cgetws(), or _kbhit() is called: 90 if (__dcrt_lowio_ensure_console_input_initialized() == FALSE) 91 return WEOF; 92 93 // Switch to raw mode (no line input, no echo input): 94 DWORD old_console_mode; 95 __dcrt_get_input_console_mode(&old_console_mode); 96 __dcrt_set_input_console_mode(0); 97 wint_t result = 0; 98 __try 99 { 100 for ( ; ; ) 101 { 102 // Get a console input event: 103 INPUT_RECORD input_record; 104 DWORD num_read; 105 if (__dcrt_read_console_input(&input_record, 1, &num_read) == FALSE) 106 { 107 result = WEOF; 108 __leave; 109 } 110 111 if (num_read == 0) 112 { 113 result = WEOF; 114 __leave; 115 } 116 117 // Look for, and decipher, key events. 118 if (input_record.EventType == KEY_EVENT && input_record.Event.KeyEvent.bKeyDown) 119 { 120 // Easy case: if UnicodeChar is non-zero, we can just return it: 121 wchar_t const c = static_cast<wchar_t>(input_record.Event.KeyEvent.uChar.UnicodeChar); 122 if (c != 0) 123 { 124 result = c; 125 __leave; 126 } 127 128 // Hard case: either it is an extended code or an event which 129 // should not be recognized. Let _getextendedkeycode do the work: 130 CharPair const* const cp = _getextendedkeycode(&input_record.Event.KeyEvent); 131 if (cp != nullptr) 132 { 133 wchbuf = cp->SecondChar; 134 result = cp->LeadChar; 135 __leave; 136 } 137 } 138 } 139 } 140 __finally 141 { 142 // Restore the previous console mode: 143 __dcrt_set_input_console_mode(old_console_mode); 144 } 145 __endtry 146 return result; 147} 148 149 150 151extern "C" wint_t __cdecl _getwche_nolock() 152{ 153 // First check the pushback buffer for a character. If it has one, return 154 // it without echoing and reset the buffer: 155 if (wchbuf != WEOF) 156 { 157 wchar_t const buffered_wchar = static_cast<wchar_t>(wchbuf & 0xFFFF); 158 wchbuf = WEOF; 159 return buffered_wchar; 160 } 161 162 // Othwrwise, read the character, echo it, and return it. If anything fails, 163 // we immediately return WEOF. 164 wchar_t const gotten_wchar = _getwch_nolock(); 165 if (gotten_wchar == WEOF) 166 return WEOF; 167 168 if (_putwch_nolock(gotten_wchar) == WEOF) 169 return WEOF; 170 171 return gotten_wchar; 172} 173 174 175 176// Pushes back ("ungets") one character to be read next by _getwch() or 177// _getwche(). On success, returns the character that was pushed back; on 178// failure, returns EOF. 179extern "C" wint_t __cdecl _ungetwch(wint_t const c) 180{ 181 __acrt_lock(__acrt_conio_lock); 182 wint_t result = 0; 183 __try 184 { 185 result = _ungetwch_nolock(c); 186 } 187 __finally 188 { 189 __acrt_unlock(__acrt_conio_lock); 190 } 191 __endtry 192 return result; 193} 194 195 196 197extern "C" wint_t __cdecl _ungetwch_nolock(wint_t const c) 198{ 199 // Fail if the char is EOF or the pushback buffer is non-empty: 200 if (c == WEOF || wchbuf != WEOF) 201 return static_cast<wint_t>(EOF); 202 203 wchbuf = (c & 0xFF); 204 return wchbuf; 205}