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