xref: /reactos/sdk/lib/ucrt/conio/getch.cpp (revision e98e9000)
1 //
2 // getch.cpp
3 //
4 //      Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // Defines _getch(), _getche(), and _ungetch(), which get and unget
7 // characters directly from the console.
8 //
9 #include <conio.h>
10 #include <corecrt_internal_lowio.h>
11 #include <limits.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 
15 
16 
17 namespace
18 {
19     struct CharPair
20     {
21         unsigned char LeadChar;
22         unsigned char SecondChar;
23     };
24 
25     struct EnhKeyVals
26     {
27         unsigned short ScanCode;
28         CharPair RegChars;
29         CharPair ShiftChars;
30         CharPair CtrlChars;
31         CharPair AltChars;
32     };
33 
34     struct NormKeyVals
35     {
36         CharPair RegChars;
37         CharPair ShiftChars;
38         CharPair CtrlChars;
39         CharPair AltChars;
40     };
41 }
42 
43 
44 
45 // Table of enhanced key values:
46 static EnhKeyVals const EnhancedKeys[] =
47 {
48     { 28, {  13,   0 }, {  13,   0 }, {  10,   0 }, {   0, 166 } },
49     { 53, {  47,   0 }, {  63,   0 }, {   0, 149 }, {   0, 164 } },
50     { 71, { 224,  71 }, { 224,  71 }, { 224, 119 }, {   0, 151 } },
51     { 72, { 224,  72 }, { 224,  72 }, { 224, 141 }, {   0, 152 } },
52     { 73, { 224,  73 }, { 224,  73 }, { 224, 134 }, {   0, 153 } },
53     { 75, { 224,  75 }, { 224,  75 }, { 224, 115 }, {   0, 155 } },
54     { 77, { 224,  77 }, { 224,  77 }, { 224, 116 }, {   0, 157 } },
55     { 79, { 224,  79 }, { 224,  79 }, { 224, 117 }, {   0, 159 } },
56     { 80, { 224,  80 }, { 224,  80 }, { 224, 145 }, {   0, 160 } },
57     { 81, { 224,  81 }, { 224,  81 }, { 224, 118 }, {   0, 161 } },
58     { 82, { 224,  82 }, { 224,  82 }, { 224, 146 }, {   0, 162 } },
59     { 83, { 224,  83 }, { 224,  83 }, { 224, 147 }, {   0, 163 } }
60 };
61 
62 // The number of elements in EnhancedKeys:
63 #define NUM_EKA_ELTS (sizeof(EnhancedKeys) / sizeof(EnhKeyVals))
64 
65 
66 
67 // Table of key values for normal keys.  Note that the table is padded so that
68 // the key scan code serves as an index into the table.
69 static NormKeyVals const NormalKeys[] =
70 {
71     /* padding */
72     { /*  0 */ {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
73 
74     { /*  1 */ {  27,   0 }, {  27,   0 }, {  27,   0 }, {   0,   1 } },
75     { /*  2 */ {  49,   0 }, {  33,   0 }, {   0,   0 }, {   0, 120 } },
76     { /*  3 */ {  50,   0 }, {  64,   0 }, {   0,   3 }, {   0, 121 } },
77     { /*  4 */ {  51,   0 }, {  35,   0 }, {   0,   0 }, {   0, 122 } },
78     { /*  5 */ {  52,   0 }, {  36,   0 }, {   0,   0 }, {   0, 123 } },
79     { /*  6 */ {  53,   0 }, {  37,   0 }, {   0,   0 }, {   0, 124 } },
80     { /*  7 */ {  54,   0 }, {  94,   0 }, {  30,   0 }, {   0, 125 } },
81     { /*  8 */ {  55,   0 }, {  38,   0 }, {   0,   0 }, {   0, 126 } },
82     { /*  9 */ {  56,   0 }, {  42,   0 }, {   0,   0 }, {   0, 127 } },
83     { /* 10 */ {  57,   0 }, {  40,   0 }, {   0,   0 }, {   0, 128 } },
84     { /* 11 */ {  48,   0 }, {  41,   0 }, {   0,   0 }, {   0, 129 } },
85     { /* 12 */ {  45,   0 }, {  95,   0 }, {  31,   0 }, {   0, 130 } },
86     { /* 13 */ {  61,   0 }, {  43,   0 }, {   0,   0 }, {   0, 131 } },
87     { /* 14 */ {   8,   0 }, {   8,   0 }, { 127,   0 }, {   0,  14 } },
88     { /* 15 */ {   9,   0 }, {   0,  15 }, {   0, 148 }, {   0,  15 } },
89     { /* 16 */ { 113,   0 }, {  81,   0 }, {  17,   0 }, {   0,  16 } },
90     { /* 17 */ { 119,   0 }, {  87,   0 }, {  23,   0 }, {   0,  17 } },
91     { /* 18 */ { 101,   0 }, {  69,   0 }, {   5,   0 }, {   0,  18 } },
92     { /* 19 */ { 114,   0 }, {  82,   0 }, {  18,   0 }, {   0,  19 } },
93     { /* 20 */ { 116,   0 }, {  84,   0 }, {  20,   0 }, {   0,  20 } },
94     { /* 21 */ { 121,   0 }, {  89,   0 }, {  25,   0 }, {   0,  21 } },
95     { /* 22 */ { 117,   0 }, {  85,   0 }, {  21,   0 }, {   0,  22 } },
96     { /* 23 */ { 105,   0 }, {  73,   0 }, {   9,   0 }, {   0,  23 } },
97     { /* 24 */ { 111,   0 }, {  79,   0 }, {  15,   0 }, {   0,  24 } },
98     { /* 25 */ { 112,   0 }, {  80,   0 }, {  16,   0 }, {   0,  25 } },
99     { /* 26 */ {  91,   0 }, { 123,   0 }, {  27,   0 }, {   0,  26 } },
100     { /* 27 */ {  93,   0 }, { 125,   0 }, {  29,   0 }, {   0,  27 } },
101     { /* 28 */ {  13,   0 }, {  13,   0 }, {  10,   0 }, {   0,  28 } },
102 
103     /* padding */
104     { /* 29 */ {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
105 
106     { /* 30 */ {  97,   0 }, {  65,   0 }, {   1,   0 }, {   0,  30 } },
107     { /* 31 */ { 115,   0 }, {  83,   0 }, {  19,   0 }, {   0,  31 } },
108     { /* 32 */ { 100,   0 }, {  68,   0 }, {   4,   0 }, {   0,  32 } },
109     { /* 33 */ { 102,   0 }, {  70,   0 }, {   6,   0 }, {   0,  33 } },
110     { /* 34 */ { 103,   0 }, {  71,   0 }, {   7,   0 }, {   0,  34 } },
111     { /* 35 */ { 104,   0 }, {  72,   0 }, {   8,   0 }, {   0,  35 } },
112     { /* 36 */ { 106,   0 }, {  74,   0 }, {  10,   0 }, {   0,  36 } },
113     { /* 37 */ { 107,   0 }, {  75,   0 }, {  11,   0 }, {   0,  37 } },
114     { /* 38 */ { 108,   0 }, {  76,   0 }, {  12,   0 }, {   0,  38 } },
115     { /* 39 */ {  59,   0 }, {  58,   0 }, {   0,   0 }, {   0,  39 } },
116     { /* 40 */ {  39,   0 }, {  34,   0 }, {   0,   0 }, {   0,  40 } },
117     { /* 41 */ {  96,   0 }, { 126,   0 }, {   0,   0 }, {   0,  41 } },
118 
119     /* padding */
120     { /* 42 */ {    0,  0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
121 
122     { /* 43 */ {  92,   0 }, { 124,   0 }, {  28,   0 }, {   0,   0 } },
123     { /* 44 */ { 122,   0 }, {  90,   0 }, {  26,   0 }, {   0,  44 } },
124     { /* 45 */ { 120,   0 }, {  88,   0 }, {  24,   0 }, {   0,  45 } },
125     { /* 46 */ {  99,   0 }, {  67,   0 }, {   3,   0 }, {   0,  46 } },
126     { /* 47 */ { 118,   0 }, {  86,   0 }, {  22,   0 }, {   0,  47 } },
127     { /* 48 */ {  98,   0 }, {  66,   0 }, {   2,   0 }, {   0,  48 } },
128     { /* 49 */ { 110,   0 }, {  78,   0 }, {  14,   0 }, {   0,  49 } },
129     { /* 50 */ { 109,   0 }, {  77,   0 }, {  13,   0 }, {   0,  50 } },
130     { /* 51 */ {  44,   0 }, {  60,   0 }, {   0,   0 }, {   0,  51 } },
131     { /* 52 */ {  46,   0 }, {  62,   0 }, {   0,   0 }, {   0,  52 } },
132     { /* 53 */ {  47,   0 }, {  63,   0 }, {   0,   0 }, {   0,  53 } },
133 
134     /* padding */
135     { /* 54 */ {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
136 
137     { /* 55 */ {  42,   0 }, {   0,   0 }, { 114,   0 }, {   0,   0 } },
138 
139     /* padding */
140     { /* 56 */ {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
141 
142     { /* 57 */ {  32,   0 }, {  32,   0 }, {  32,   0 }, {  32,   0 } },
143 
144     /* padding */
145     { /* 58 */ {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
146 
147     { /* 59 */ {   0,  59 }, {   0,  84 }, {   0,  94 }, {   0, 104 } },
148     { /* 60 */ {   0,  60 }, {   0,  85 }, {   0,  95 }, {   0, 105 } },
149     { /* 61 */ {   0,  61 }, {   0,  86 }, {   0,  96 }, {   0, 106 } },
150     { /* 62 */ {   0,  62 }, {   0,  87 }, {   0,  97 }, {   0, 107 } },
151     { /* 63 */ {   0,  63 }, {   0,  88 }, {   0,  98 }, {   0, 108 } },
152     { /* 64 */ {   0,  64 }, {   0,  89 }, {   0,  99 }, {   0, 109 } },
153     { /* 65 */ {   0,  65 }, {   0,  90 }, {   0, 100 }, {   0, 110 } },
154     { /* 66 */ {   0,  66 }, {   0,  91 }, {   0, 101 }, {   0, 111 } },
155     { /* 67 */ {   0,  67 }, {   0,  92 }, {   0, 102 }, {   0, 112 } },
156     { /* 68 */ {   0,  68 }, {   0,  93 }, {   0, 103 }, {   0, 113 } },
157 
158     /* padding */
159     { /* 69 */ {    0,  0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
160     { /* 70 */ {    0,  0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
161 
162     { /* 71 */ {   0,  71 }, {  55,   0 }, {   0, 119 }, {   0,   0 } },
163     { /* 72 */ {   0,  72 }, {  56,   0 }, {   0, 141 }, {   0,   0 } },
164     { /* 73 */ {   0,  73 }, {  57,   0 }, {   0, 132 }, {   0,   0 } },
165     { /* 74 */ {   0,   0 }, {  45,   0 }, {   0,   0 }, {   0,   0 } },
166     { /* 75 */ {   0,  75 }, {  52,   0 }, {   0, 115 }, {   0,   0 } },
167     { /* 76 */ {   0,   0 }, {  53,   0 }, {   0,   0 }, {   0,   0 } },
168     { /* 77 */ {   0,  77 }, {  54,   0 }, {   0, 116 }, {   0,   0 } },
169     { /* 78 */ {   0,   0 }, {  43,   0 }, {   0,   0 }, {   0,   0 } },
170     { /* 79 */ {   0,  79 }, {  49,   0 }, {   0, 117 }, {   0,   0 } },
171     { /* 80 */ {   0,  80 }, {  50,   0 }, {   0, 145 }, {   0,   0 } },
172     { /* 81 */ {   0,  81 }, {  51,   0 }, {   0, 118 }, {   0,   0 } },
173     { /* 82 */ {   0,  82 }, {  48,   0 }, {   0, 146 }, {   0,   0 } },
174     { /* 83 */ {   0,  83 }, {  46,   0 }, {   0, 147 }, {   0,   0 } },
175 
176     /* padding */
177     { /* 84 */ {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
178     { /* 85 */ {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
179     { /* 86 */ {   0,   0 }, {   0,   0 }, {   0,   0 }, {   0,   0 } },
180 
181     { /* 87 */ { 224, 133 }, { 224, 135 }, { 224, 137 }, { 224, 139 } },
182     { /* 88 */ { 224, 134 }, { 224, 136 }, { 224, 138 }, { 224, 140 } }
183 };
184 
185 // The primary purpose of the pushback buffer is so that if a
186 // multi-byte character or extended key code is read, we can return
187 // the first byte and store the rest of the data in the buffer for
188 // subsequent calls. UTF-8 characters can be up to 4 bytes long, so
189 // the pushback buffer must be able to store the 3 remaining bytes.
190 size_t const getch_pushback_buffer_capacity = 3;
191 
192 static int getch_pushback_buffer[getch_pushback_buffer_capacity];
193 static int getch_pushback_buffer_index = 0;
194 static int getch_pushback_buffer_current_size = 0;
195 
is_getch_pushback_buffer_full()196 static bool is_getch_pushback_buffer_full()
197 {
198     return getch_pushback_buffer_current_size >= getch_pushback_buffer_capacity;
199 }
200 
add_to_getch_pushback_buffer(int const c)201 static void add_to_getch_pushback_buffer(int const c)
202 {
203     _ASSERTE(!is_getch_pushback_buffer_full());
204     getch_pushback_buffer[getch_pushback_buffer_current_size++] = c;
205 }
206 
peek_next_getch_pushback_buffer()207 static int peek_next_getch_pushback_buffer()
208 {
209     if (getch_pushback_buffer_current_size == 0) {
210         return EOF;
211     }
212 
213     return getch_pushback_buffer[getch_pushback_buffer_index];
214 }
215 
get_next_getch_pushback_buffer()216 static int get_next_getch_pushback_buffer()
217 {
218     if (getch_pushback_buffer_current_size == 0) {
219         return EOF;
220     }
221 
222     int const ret_val = getch_pushback_buffer[getch_pushback_buffer_index++];
223 
224     if (getch_pushback_buffer_index == getch_pushback_buffer_current_size) {
225         getch_pushback_buffer_index = 0;
226         getch_pushback_buffer_current_size = 0;
227     }
228 
229     return ret_val;
230 }
231 
232 extern "C" intptr_t __dcrt_lowio_console_input_handle;
233 
234 extern "C" CharPair const* __cdecl _getextendedkeycode(KEY_EVENT_RECORD*);
235 extern "C" int __cdecl _kbhit_nolock();
236 
237 
238 
239 // These functions read a single character from the console.  _getch() does not
240 // echo the character; _getche() does echo the character.  If the push-back
241 // buffer is nonempty, the buffered character is returned immediately, without
242 // being echoed.
243 //
244 // On success, the read character is returned; on failure, EOF is returned.
_getch()245 extern "C" int __cdecl _getch()
246 {
247     __acrt_lock(__acrt_conio_lock);
248     int result = 0;
249     __try
250     {
251         result = _getch_nolock();
252     }
253     __finally
254     {
255         __acrt_unlock(__acrt_conio_lock);
256     }
257     __endtry
258     return result;
259 }
260 
_getche()261 extern "C" int __cdecl _getche()
262 {
263     __acrt_lock(__acrt_conio_lock);
264     int result = 0;
265     __try
266     {
267         result = _getche_nolock();
268     }
269     __finally
270     {
271         __acrt_unlock(__acrt_conio_lock);
272     }
273     __endtry
274     return result;
275 }
276 
_getch_nolock()277 extern "C" int __cdecl _getch_nolock()
278 {
279     // Check the pushback buffer for a character.  If one is present, return it:
280     int const pushback = get_next_getch_pushback_buffer();
281     if (pushback != EOF)
282     {
283         return pushback;
284     }
285 
286     if (__dcrt_lowio_ensure_console_input_initialized() == FALSE) {
287         return EOF;
288     }
289 
290     // Switch console to raw mode:
291     DWORD old_console_mode;
292     __dcrt_get_input_console_mode(&old_console_mode);
293     __dcrt_set_input_console_mode(0);
294 
295     int result = 0;
296 
297     __try
298     {
299         for ( ; ; )
300         {
301             // Get a console input event:
302             INPUT_RECORD input_record;
303             DWORD num_read;
304 
305             if (__dcrt_read_console_input(&input_record, 1, &num_read) == FALSE || num_read == 0)
306             {
307                 result = EOF;
308                 __leave;
309             }
310 
311             // Look for, and decipher, key events.
312             if (input_record.EventType == KEY_EVENT && input_record.Event.KeyEvent.bKeyDown)
313             {
314                 // Simple case:  if UnicodeChar is non-zero, we can convert it to char and return it.
315                 wchar_t const c = input_record.Event.KeyEvent.uChar.UnicodeChar;
316                 if (c != 0)
317                 {
318                     wchar_t const c_buffer[2] = {c, L'\0'};
319                     char mb_chars[4];
320 
321                     size_t const amount_written = __acrt_wcs_to_mbs_cp_array(
322                         c_buffer,
323                         mb_chars,
324                         GetConsoleCP()
325                         );
326 
327                     // Mask with 0xFF to just get lowest byte
328                     if (amount_written >= 1) {
329                         result = mb_chars[0] & 0xFF;
330                     }
331 
332                     if (amount_written >= 2) {
333                         for (size_t i = 1; i < amount_written; ++i) {
334                             add_to_getch_pushback_buffer(mb_chars[i] & 0xFF);
335                         }
336                     }
337                     __leave;
338                 }
339 
340                 // Hard case:  either it is an extended code or an event which
341                 // should not be recognized.  Let _getextendedkeycode do the work:
342                 CharPair const* const cp = _getextendedkeycode(&input_record.Event.KeyEvent);
343                 if (cp != nullptr)
344                 {
345                     // Mask with 0xFF to just get lowest byte
346                     add_to_getch_pushback_buffer(cp->SecondChar & 0xFF);
347                     result = cp->LeadChar & 0xFF;
348                     __leave;
349                 }
350             }
351         }
352     }
353     __finally
354     {
355         // Restore the previous console mode:
356         __dcrt_set_input_console_mode(old_console_mode);
357     }
358     __endtry
359     return result;
360 }
361 
362 
363 
_getche_nolock()364 extern "C" int __cdecl _getche_nolock()
365 {
366     // Check the pushback buffer for a character.  If one is present, return
367     // it without echoing:
368     int const pushback = get_next_getch_pushback_buffer();
369     if (pushback != EOF)
370     {
371         return pushback;
372     }
373 
374     // Otherwise, read the next character from the console and echo it:
375     int const c = _getch_nolock();
376     if (c == EOF)
377         return EOF;
378 
379     if (_putch_nolock(c) == EOF)
380         return EOF;
381 
382     return c;
383 }
384 
385 
386 
387 // Returns nonzero if a keystroke is waiting to be read; otherwise returns zero.
_kbhit()388 extern "C" int __cdecl _kbhit()
389 {
390     __acrt_lock(__acrt_conio_lock);
391     int result = 0;
392     __try
393     {
394         result = _kbhit_nolock();
395     }
396     __finally
397     {
398         __acrt_unlock(__acrt_conio_lock);
399     }
400     __endtry
401     return result;
402 }
403 
404 
405 
_kbhit_nolock()406 extern "C" int __cdecl _kbhit_nolock()
407 {
408     // If a character has been pushed back, return TRUE:
409     if (peek_next_getch_pushback_buffer() != EOF) {
410         return TRUE;
411     }
412 
413     if (__dcrt_lowio_ensure_console_input_initialized() == FALSE) {
414         return FALSE;
415     }
416 
417     // Peek at all pending console events:
418     DWORD num_pending;
419     if (__dcrt_get_number_of_console_input_events(&num_pending) == FALSE) {
420         return FALSE;
421     }
422 
423     if (num_pending == 0) {
424         return FALSE;
425     }
426 
427     __crt_scoped_stack_ptr<INPUT_RECORD> const input_buffer(_malloca_crt_t(INPUT_RECORD, num_pending));
428     if (input_buffer.get() == nullptr) {
429         return FALSE;
430     }
431 
432     DWORD num_peeked;
433     // AsciiChar is not read, so using the narrow Win32 API is permitted.
434     if (__dcrt_peek_console_input_a(input_buffer.get(), num_pending, &num_peeked) == FALSE) {
435         return FALSE;
436     }
437 
438     if (num_peeked == 0 || num_peeked > num_pending) {
439         return FALSE;
440     }
441 
442     // Scan all of the peeked events to determine if any is a key event
443     // that should be recognized:
444     for (INPUT_RECORD* p = input_buffer.get(); num_peeked > 0; --num_peeked, ++p)
445     {
446         if (p->EventType != KEY_EVENT)
447             continue;
448 
449         if (!p->Event.KeyEvent.bKeyDown)
450             continue;
451 
452         if (p->Event.KeyEvent.uChar.AsciiChar == 0 &&
453             _getextendedkeycode(&p->Event.KeyEvent) == nullptr)
454             continue;
455 
456         return TRUE;
457     }
458 
459     return FALSE;
460 }
461 
462 
463 
464 // Pushes back ("ungets") one character to be read next by _getwch() or
465 // _getwche().  On success, returns the character that was pushed back; on
466 // failure, returns EOF.
_ungetch(int const c)467 extern "C" int __cdecl _ungetch(int const c)
468 {
469     __acrt_lock(__acrt_conio_lock);
470     int result = 0;
471     __try
472     {
473         result = _ungetch_nolock(c);
474     }
475     __finally
476     {
477         __acrt_unlock(__acrt_conio_lock);
478     }
479     __endtry
480     return result;
481 }
482 
483 
484 
_ungetch_nolock(int const c)485 extern "C" int __cdecl _ungetch_nolock(int const c)
486 {
487     // Fail if the character is EOF or the pusback buffer is nonempty:
488     if (c == EOF || is_getch_pushback_buffer_full()) {
489         return EOF;
490     }
491 
492     add_to_getch_pushback_buffer(c);
493     return c;
494 }
495 
496 
497 
498 // Returns the extended code (if there is one) for a key event.  This is the
499 // core function for the _getch() and _getche() functions and their wide
500 // character equivalents, and is essential to _kbhit().  This is the function
501 // that determines whether or not a key event NOT accompanied by an ASCII
502 // character has an extended code and returns that code.
503 //
504 // On success, a pointer to a CharPair value holding the lead and second
505 // characters of the extended code is returned.  On failure, nullptr is returned.
_getextendedkeycode(KEY_EVENT_RECORD * const pKE)506 extern "C" CharPair const* __cdecl _getextendedkeycode(KEY_EVENT_RECORD* const pKE)
507 {
508     DWORD const CKS = pKE->dwControlKeyState;
509 
510     if (CKS & ENHANCED_KEY)
511     {
512         // Find the appropriate entry in EnhancedKeys[]:
513         for (int i = 0 ; i < NUM_EKA_ELTS; ++i)
514         {
515             if (EnhancedKeys[i].ScanCode != pKE->wVirtualScanCode)
516             {
517                 continue;
518             }
519 
520             // We found a match!  Determine which pair to return:
521             if (CKS & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
522             {
523                 return &EnhancedKeys[i].AltChars;
524             }
525             else if (CKS & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
526             {
527                 return &EnhancedKeys[i].CtrlChars;
528             }
529             else if (CKS & SHIFT_PRESSED)
530             {
531                 return &EnhancedKeys[i].ShiftChars;
532             }
533             else
534             {
535                 return &EnhancedKeys[i].RegChars;
536             }
537         }
538 
539         return nullptr;
540     }
541     else
542     {
543         // Regular key or keyboard event which shouldn't be recognized.
544         // Determine which by getting the proper field of the proper entry in
545         // NormalKeys[] and examining the extended code.
546         CharPair const* pCP;
547 
548         if (CKS & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
549         {
550             pCP = &NormalKeys[pKE->wVirtualScanCode].AltChars;
551         }
552         else if (CKS & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
553         {
554             pCP = &NormalKeys[pKE->wVirtualScanCode].CtrlChars;
555         }
556         else if (CKS & SHIFT_PRESSED)
557         {
558             pCP = &NormalKeys[pKE->wVirtualScanCode].ShiftChars;
559         }
560         else
561         {
562             pCP = &NormalKeys[pKE->wVirtualScanCode].RegChars;
563         }
564 
565         // Make sure it wasn't a keyboard event which should not be recognized
566         // (e.g. the shift key was pressed):
567         if ((pCP->LeadChar != 0 && pCP->LeadChar != 224) || pCP->SecondChar == 0)
568         {
569             return nullptr;
570         }
571 
572         return pCP;
573     }
574 }
575