93a3f658ffc8700cb94dea3c97f45418cbcc1177
[reactos.git] / win32ss / user / win32csr / coninput.c
1 /*
2 * reactos/subsys/csrss/win32csr/conio.c
3 *
4 * Console I/O functions
5 *
6 * ReactOS Operating System
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #define NDEBUG
12 #include "w32csr.h"
13 #include <debug.h>
14
15 /* GLOBALS *******************************************************************/
16
17 #define ConsoleInputUnicodeCharToAnsiChar(Console, dChar, sWChar) \
18 WideCharToMultiByte((Console)->CodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
19
20 #define ConsoleInputAnsiCharToUnicodeChar(Console, dWChar, sChar) \
21 MultiByteToWideChar((Console)->CodePage, 0, (sChar), 1, (dWChar), 1)
22
23 /* FUNCTIONS *****************************************************************/
24
25 CSR_API(CsrReadConsole)
26 {
27 PLIST_ENTRY CurrentEntry;
28 ConsoleInput *Input;
29 PCHAR Buffer;
30 PWCHAR UnicodeBuffer;
31 ULONG i = 0;
32 ULONG nNumberOfCharsToRead, CharSize;
33 PCSRSS_CONSOLE Console;
34 NTSTATUS Status;
35
36 DPRINT("CsrReadConsole\n");
37
38 CharSize = (Request->Data.ReadConsoleRequest.Unicode ? sizeof(WCHAR) : sizeof(CHAR));
39
40 nNumberOfCharsToRead = Request->Data.ReadConsoleRequest.NrCharactersToRead;
41
42 Buffer = (PCHAR)Request->Data.ReadConsoleRequest.Buffer;
43 UnicodeBuffer = (PWCHAR)Buffer;
44 if (!Win32CsrValidateBuffer(ProcessData, Buffer, nNumberOfCharsToRead, CharSize))
45 return STATUS_ACCESS_VIOLATION;
46
47 if (Request->Data.ReadConsoleRequest.NrCharactersRead * sizeof(WCHAR) > nNumberOfCharsToRead * CharSize)
48 return STATUS_INVALID_PARAMETER;
49
50 Status = ConioLockConsole(ProcessData, Request->Data.ReadConsoleRequest.ConsoleHandle,
51 &Console, GENERIC_READ);
52 if (! NT_SUCCESS(Status))
53 {
54 return Status;
55 }
56 Request->Data.ReadConsoleRequest.EventHandle = ProcessData->ConsoleEvent;
57
58 Status = STATUS_PENDING; /* we haven't read anything (yet) */
59 if (Console->Mode & ENABLE_LINE_INPUT)
60 {
61 if (Console->LineBuffer == NULL)
62 {
63 /* Starting a new line */
64 Console->LineMaxSize = max(256, nNumberOfCharsToRead);
65 Console->LineBuffer = HeapAlloc(Win32CsrApiHeap, 0, Console->LineMaxSize * sizeof(WCHAR));
66 if (Console->LineBuffer == NULL)
67 {
68 Status = STATUS_NO_MEMORY;
69 goto done;
70 }
71 Console->LineComplete = FALSE;
72 Console->LineUpPressed = FALSE;
73 Console->LineInsertToggle = 0;
74 Console->LineWakeupMask = Request->Data.ReadConsoleRequest.CtrlWakeupMask;
75 Console->LineSize = Request->Data.ReadConsoleRequest.NrCharactersRead;
76 Console->LinePos = Console->LineSize;
77 /* pre-filling the buffer is only allowed in the Unicode API,
78 * so we don't need to worry about conversion */
79 memcpy(Console->LineBuffer, Buffer, Console->LineSize * sizeof(WCHAR));
80 if (Console->LineSize == Console->LineMaxSize)
81 {
82 Console->LineComplete = TRUE;
83 Console->LinePos = 0;
84 }
85 }
86
87 /* If we don't have a complete line yet, process the pending input */
88 while (!Console->LineComplete && !IsListEmpty(&Console->InputEvents))
89 {
90 /* remove input event from queue */
91 CurrentEntry = RemoveHeadList(&Console->InputEvents);
92 if (IsListEmpty(&Console->InputEvents))
93 {
94 ResetEvent(Console->ActiveEvent);
95 }
96 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
97
98 /* only pay attention to key down */
99 if (KEY_EVENT == Input->InputEvent.EventType
100 && Input->InputEvent.Event.KeyEvent.bKeyDown)
101 {
102 LineInputKeyDown(Console, &Input->InputEvent.Event.KeyEvent);
103 Request->Data.ReadConsoleRequest.ControlKeyState = Input->InputEvent.Event.KeyEvent.dwControlKeyState;
104 }
105 HeapFree(Win32CsrApiHeap, 0, Input);
106 }
107
108 /* Check if we have a complete line to read from */
109 if (Console->LineComplete)
110 {
111 while (i < nNumberOfCharsToRead && Console->LinePos != Console->LineSize)
112 {
113 WCHAR Char = Console->LineBuffer[Console->LinePos++];
114 if (Request->Data.ReadConsoleRequest.Unicode)
115 UnicodeBuffer[i++] = Char;
116 else
117 ConsoleInputUnicodeCharToAnsiChar(Console, &Buffer[i++], &Char);
118 }
119 if (Console->LinePos == Console->LineSize)
120 {
121 /* Entire line has been read */
122 HeapFree(Win32CsrApiHeap, 0, Console->LineBuffer);
123 Console->LineBuffer = NULL;
124 }
125 Status = STATUS_SUCCESS;
126 }
127 }
128 else
129 {
130 /* Character input */
131 while (i < nNumberOfCharsToRead && !IsListEmpty(&Console->InputEvents))
132 {
133 /* remove input event from queue */
134 CurrentEntry = RemoveHeadList(&Console->InputEvents);
135 if (IsListEmpty(&Console->InputEvents))
136 {
137 ResetEvent(Console->ActiveEvent);
138 }
139 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
140
141 /* only pay attention to valid ascii chars, on key down */
142 if (KEY_EVENT == Input->InputEvent.EventType
143 && Input->InputEvent.Event.KeyEvent.bKeyDown
144 && Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar != L'\0')
145 {
146 WCHAR Char = Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar;
147 if (Request->Data.ReadConsoleRequest.Unicode)
148 UnicodeBuffer[i++] = Char;
149 else
150 ConsoleInputUnicodeCharToAnsiChar(Console, &Buffer[i++], &Char);
151 Status = STATUS_SUCCESS; /* did read something */
152 }
153 HeapFree(Win32CsrApiHeap, 0, Input);
154 }
155 }
156 done:
157 Request->Data.ReadConsoleRequest.NrCharactersRead = i;
158 ConioUnlockConsole(Console);
159
160 return Status;
161 }
162
163 static VOID FASTCALL
164 ConioInputEventToAnsi(PCSRSS_CONSOLE Console, PINPUT_RECORD InputEvent)
165 {
166 if (InputEvent->EventType == KEY_EVENT)
167 {
168 WCHAR UnicodeChar = InputEvent->Event.KeyEvent.uChar.UnicodeChar;
169 InputEvent->Event.KeyEvent.uChar.UnicodeChar = 0;
170 ConsoleInputUnicodeCharToAnsiChar(Console,
171 &InputEvent->Event.KeyEvent.uChar.AsciiChar,
172 &UnicodeChar);
173 }
174 }
175
176 static NTSTATUS FASTCALL
177 ConioProcessChar(PCSRSS_CONSOLE Console,
178 PINPUT_RECORD InputEvent)
179 {
180 ConsoleInput *ConInRec;
181
182 /* Check for pause or unpause */
183 if (InputEvent->EventType == KEY_EVENT && InputEvent->Event.KeyEvent.bKeyDown)
184 {
185 WORD vk = InputEvent->Event.KeyEvent.wVirtualKeyCode;
186 if (!(Console->PauseFlags & PAUSED_FROM_KEYBOARD))
187 {
188 DWORD cks = InputEvent->Event.KeyEvent.dwControlKeyState;
189 if (Console->Mode & ENABLE_LINE_INPUT &&
190 (vk == VK_PAUSE || (vk == 'S' &&
191 (cks & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) &&
192 !(cks & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)))))
193 {
194 ConioPause(Console, PAUSED_FROM_KEYBOARD);
195 return STATUS_SUCCESS;
196 }
197 }
198 else
199 {
200 if ((vk < VK_SHIFT || vk > VK_CAPITAL) && vk != VK_LWIN &&
201 vk != VK_RWIN && vk != VK_NUMLOCK && vk != VK_SCROLL)
202 {
203 ConioUnpause(Console, PAUSED_FROM_KEYBOARD);
204 return STATUS_SUCCESS;
205 }
206 }
207 }
208
209 /* add event to the queue */
210 ConInRec = RtlAllocateHeap(Win32CsrApiHeap, 0, sizeof(ConsoleInput));
211 if (ConInRec == NULL)
212 return STATUS_INSUFFICIENT_RESOURCES;
213 ConInRec->InputEvent = *InputEvent;
214 InsertTailList(&Console->InputEvents, &ConInRec->ListEntry);
215 SetEvent(Console->ActiveEvent);
216 return STATUS_SUCCESS;
217 }
218
219 static DWORD FASTCALL
220 ConioGetShiftState(PBYTE KeyState)
221 {
222 DWORD ssOut = 0;
223
224 if (KeyState[VK_CAPITAL] & 1)
225 ssOut |= CAPSLOCK_ON;
226
227 if (KeyState[VK_NUMLOCK] & 1)
228 ssOut |= NUMLOCK_ON;
229
230 if (KeyState[VK_SCROLL] & 1)
231 ssOut |= SCROLLLOCK_ON;
232
233 if (KeyState[VK_SHIFT] & 0x80)
234 ssOut |= SHIFT_PRESSED;
235
236 if (KeyState[VK_LCONTROL] & 0x80)
237 ssOut |= LEFT_CTRL_PRESSED;
238 if (KeyState[VK_RCONTROL] & 0x80)
239 ssOut |= RIGHT_CTRL_PRESSED;
240
241 if (KeyState[VK_LMENU] & 0x80)
242 ssOut |= LEFT_ALT_PRESSED;
243 if (KeyState[VK_RMENU] & 0x80)
244 ssOut |= RIGHT_ALT_PRESSED;
245
246 return ssOut;
247 }
248
249 VOID WINAPI
250 ConioProcessKey(MSG *msg, PCSRSS_CONSOLE Console, BOOL TextMode)
251 {
252 static BYTE KeyState[256] = { 0 };
253 /* MSDN mentions that you should use the last virtual key code received
254 * when putting a virtual key identity to a WM_CHAR message since multiple
255 * or translated keys may be involved. */
256 static UINT LastVirtualKey = 0;
257 DWORD ShiftState;
258 UINT RepeatCount;
259 WCHAR UnicodeChar;
260 UINT VirtualKeyCode;
261 UINT VirtualScanCode;
262 BOOL Down = FALSE;
263 INPUT_RECORD er;
264 BOOLEAN Fake; // synthesized, not a real event
265 BOOLEAN NotChar; // message should not be used to return a character
266
267 RepeatCount = 1;
268 VirtualScanCode = (msg->lParam >> 16) & 0xff;
269 Down = msg->message == WM_KEYDOWN || msg->message == WM_CHAR ||
270 msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSCHAR;
271
272 GetKeyboardState(KeyState);
273 ShiftState = ConioGetShiftState(KeyState);
274
275 if (msg->message == WM_CHAR || msg->message == WM_SYSCHAR)
276 {
277 VirtualKeyCode = LastVirtualKey;
278 UnicodeChar = msg->wParam;
279 }
280 else
281 {
282 WCHAR Chars[2];
283 INT RetChars = 0;
284
285 VirtualKeyCode = msg->wParam;
286 RetChars = ToUnicodeEx(VirtualKeyCode,
287 VirtualScanCode,
288 KeyState,
289 Chars,
290 2,
291 0,
292 0);
293 UnicodeChar = (1 == RetChars ? Chars[0] : 0);
294 }
295
296 er.EventType = KEY_EVENT;
297 er.Event.KeyEvent.bKeyDown = Down;
298 er.Event.KeyEvent.wRepeatCount = RepeatCount;
299 er.Event.KeyEvent.uChar.UnicodeChar = UnicodeChar;
300 er.Event.KeyEvent.dwControlKeyState = ShiftState;
301 er.Event.KeyEvent.wVirtualKeyCode = VirtualKeyCode;
302 er.Event.KeyEvent.wVirtualScanCode = VirtualScanCode;
303
304 if (TextMode)
305 {
306 if (0 != (ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
307 && VK_TAB == VirtualKeyCode)
308 {
309 if (Down)
310 {
311 TuiSwapConsole(ShiftState & SHIFT_PRESSED ? -1 : 1);
312 }
313
314 return;
315 }
316 else if (VK_MENU == VirtualKeyCode && ! Down)
317 {
318 if (TuiSwapConsole(0))
319 {
320 return;
321 }
322 }
323 }
324 else
325 {
326 if ((ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED) || KeyState[VK_MENU] & 0x80) &&
327 (VirtualKeyCode == VK_ESCAPE || VirtualKeyCode == VK_TAB || VirtualKeyCode == VK_SPACE))
328 {
329 DefWindowProcW( msg->hwnd, msg->message, msg->wParam, msg->lParam);
330 return;
331 }
332 }
333
334 if (NULL == Console)
335 {
336 DPRINT1("No Active Console!\n");
337 return;
338 }
339
340 Fake = UnicodeChar &&
341 (msg->message != WM_CHAR && msg->message != WM_SYSCHAR &&
342 msg->message != WM_KEYUP && msg->message != WM_SYSKEYUP);
343 NotChar = (msg->message != WM_CHAR && msg->message != WM_SYSCHAR);
344 if (NotChar)
345 LastVirtualKey = msg->wParam;
346
347 DPRINT ("csrss: %s %s %s %s %02x %02x '%lc' %04x\n",
348 Down ? "down" : "up ",
349 (msg->message == WM_CHAR || msg->message == WM_SYSCHAR) ?
350 "char" : "key ",
351 Fake ? "fake" : "real",
352 NotChar ? "notc" : "char",
353 VirtualScanCode,
354 VirtualKeyCode,
355 (UnicodeChar >= L' ') ? UnicodeChar : L'.',
356 ShiftState);
357
358 if (Fake)
359 return;
360
361 /* process Ctrl-C and Ctrl-Break */
362 if (Console->Mode & ENABLE_PROCESSED_INPUT &&
363 er.Event.KeyEvent.bKeyDown &&
364 ((er.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE) ||
365 (er.Event.KeyEvent.wVirtualKeyCode == 'C')) &&
366 (er.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) || KeyState[VK_CONTROL] & 0x80))
367 {
368 PCSR_PROCESS current;
369 PLIST_ENTRY current_entry;
370 DPRINT1("Console_Api Ctrl-C\n");
371 current_entry = Console->ProcessList.Flink;
372 while (current_entry != &Console->ProcessList)
373 {
374 current = CONTAINING_RECORD(current_entry, CSR_PROCESS, ConsoleLink);
375 current_entry = current_entry->Flink;
376 ConioConsoleCtrlEvent((DWORD)CTRL_C_EVENT, current);
377 }
378 if (Console->LineBuffer && !Console->LineComplete)
379 {
380 /* Line input is in progress; end it */
381 Console->LinePos = Console->LineSize = 0;
382 Console->LineComplete = TRUE;
383 }
384 return;
385 }
386
387 if (0 != (er.Event.KeyEvent.dwControlKeyState
388 & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
389 && (VK_UP == er.Event.KeyEvent.wVirtualKeyCode
390 || VK_DOWN == er.Event.KeyEvent.wVirtualKeyCode))
391 {
392 if (er.Event.KeyEvent.bKeyDown)
393 {
394 /* scroll up or down */
395 if (VK_UP == er.Event.KeyEvent.wVirtualKeyCode)
396 {
397 /* only scroll up if there is room to scroll up into */
398 if (Console->ActiveBuffer->CurrentY != Console->ActiveBuffer->MaxY - 1)
399 {
400 Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY +
401 Console->ActiveBuffer->MaxY - 1) %
402 Console->ActiveBuffer->MaxY;
403 Console->ActiveBuffer->CurrentY++;
404 }
405 }
406 else
407 {
408 /* only scroll down if there is room to scroll down into */
409 if (Console->ActiveBuffer->CurrentY != 0)
410 {
411 Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY + 1) %
412 Console->ActiveBuffer->MaxY;
413 Console->ActiveBuffer->CurrentY--;
414 }
415 }
416 ConioDrawConsole(Console);
417 }
418 return;
419 }
420 ConioProcessChar(Console, &er);
421 }
422
423 CSR_API(CsrReadInputEvent)
424 {
425 PLIST_ENTRY CurrentEntry;
426 PCSRSS_CONSOLE Console;
427 NTSTATUS Status;
428 BOOLEAN Done = FALSE;
429 ConsoleInput *Input;
430
431 DPRINT("CsrReadInputEvent\n");
432
433 Request->Data.ReadInputRequest.Event = ProcessData->ConsoleEvent;
434
435 Status = ConioLockConsole(ProcessData, Request->Data.ReadInputRequest.ConsoleHandle, &Console, GENERIC_READ);
436 if (! NT_SUCCESS(Status))
437 {
438 return Status;
439 }
440
441 /* only get input if there is any */
442 CurrentEntry = Console->InputEvents.Flink;
443 while (CurrentEntry != &Console->InputEvents)
444 {
445 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
446 CurrentEntry = CurrentEntry->Flink;
447
448 if (Done)
449 {
450 Request->Data.ReadInputRequest.MoreEvents = TRUE;
451 break;
452 }
453
454 RemoveEntryList(&Input->ListEntry);
455
456 if (!Done)
457 {
458 Request->Data.ReadInputRequest.Input = Input->InputEvent;
459 if (Request->Data.ReadInputRequest.Unicode == FALSE)
460 {
461 ConioInputEventToAnsi(Console, &Request->Data.ReadInputRequest.Input);
462 }
463 Done = TRUE;
464 }
465
466 HeapFree(Win32CsrApiHeap, 0, Input);
467 }
468
469 if (Done)
470 Status = STATUS_SUCCESS;
471 else
472 Status = STATUS_PENDING;
473
474 if (IsListEmpty(&Console->InputEvents))
475 {
476 ResetEvent(Console->ActiveEvent);
477 }
478
479 ConioUnlockConsole(Console);
480
481 return Status;
482 }
483
484 CSR_API(CsrFlushInputBuffer)
485 {
486 PLIST_ENTRY CurrentEntry;
487 PCSRSS_CONSOLE Console;
488 ConsoleInput* Input;
489 NTSTATUS Status;
490
491 DPRINT("CsrFlushInputBuffer\n");
492
493 Status = ConioLockConsole(ProcessData,
494 Request->Data.FlushInputBufferRequest.ConsoleInput,
495 &Console,
496 GENERIC_WRITE);
497 if(! NT_SUCCESS(Status))
498 {
499 return Status;
500 }
501
502 /* Discard all entries in the input event queue */
503 while (!IsListEmpty(&Console->InputEvents))
504 {
505 CurrentEntry = RemoveHeadList(&Console->InputEvents);
506 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
507 /* Destroy the event */
508 HeapFree(Win32CsrApiHeap, 0, Input);
509 }
510 ResetEvent(Console->ActiveEvent);
511
512 ConioUnlockConsole(Console);
513
514 return STATUS_SUCCESS;
515 }
516
517 CSR_API(CsrGetNumberOfConsoleInputEvents)
518 {
519 NTSTATUS Status;
520 PCSRSS_CONSOLE Console;
521 PLIST_ENTRY CurrentItem;
522 DWORD NumEvents;
523
524 DPRINT("CsrGetNumberOfConsoleInputEvents\n");
525
526 Status = ConioLockConsole(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, &Console, GENERIC_READ);
527 if (! NT_SUCCESS(Status))
528 {
529 return Status;
530 }
531
532 CurrentItem = Console->InputEvents.Flink;
533 NumEvents = 0;
534
535 /* If there are any events ... */
536 while (CurrentItem != &Console->InputEvents)
537 {
538 CurrentItem = CurrentItem->Flink;
539 NumEvents++;
540 }
541
542 ConioUnlockConsole(Console);
543
544 Request->Data.GetNumInputEventsRequest.NumInputEvents = NumEvents;
545
546 return STATUS_SUCCESS;
547 }
548
549 CSR_API(CsrPeekConsoleInput)
550 {
551 NTSTATUS Status;
552 PCSRSS_CONSOLE Console;
553 DWORD Length;
554 PLIST_ENTRY CurrentItem;
555 PINPUT_RECORD InputRecord;
556 ConsoleInput* Item;
557 UINT NumItems;
558
559 DPRINT("CsrPeekConsoleInput\n");
560
561 Status = ConioLockConsole(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, &Console, GENERIC_READ);
562 if(! NT_SUCCESS(Status))
563 {
564 return Status;
565 }
566
567 InputRecord = Request->Data.PeekConsoleInputRequest.InputRecord;
568 Length = Request->Data.PeekConsoleInputRequest.Length;
569
570 if (!Win32CsrValidateBuffer(ProcessData, InputRecord, Length, sizeof(INPUT_RECORD)))
571 {
572 ConioUnlockConsole(Console);
573 return STATUS_ACCESS_VIOLATION;
574 }
575
576 NumItems = 0;
577
578 if (! IsListEmpty(&Console->InputEvents))
579 {
580 CurrentItem = Console->InputEvents.Flink;
581
582 while (CurrentItem != &Console->InputEvents && NumItems < Length)
583 {
584 Item = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
585
586 ++NumItems;
587 *InputRecord = Item->InputEvent;
588
589 if (Request->Data.PeekConsoleInputRequest.Unicode == FALSE)
590 {
591 ConioInputEventToAnsi(Console, InputRecord);
592 }
593
594 InputRecord++;
595 CurrentItem = CurrentItem->Flink;
596 }
597 }
598
599 ConioUnlockConsole(Console);
600
601 Request->Data.PeekConsoleInputRequest.Length = NumItems;
602
603 return STATUS_SUCCESS;
604 }
605
606 CSR_API(CsrWriteConsoleInput)
607 {
608 PINPUT_RECORD InputRecord;
609 PCSRSS_CONSOLE Console;
610 NTSTATUS Status;
611 DWORD Length;
612 DWORD i;
613
614 DPRINT("CsrWriteConsoleInput\n");
615
616 Status = ConioLockConsole(ProcessData, Request->Data.WriteConsoleInputRequest.ConsoleHandle, &Console, GENERIC_WRITE);
617 if (! NT_SUCCESS(Status))
618 {
619 return Status;
620 }
621
622 InputRecord = Request->Data.WriteConsoleInputRequest.InputRecord;
623 Length = Request->Data.WriteConsoleInputRequest.Length;
624
625 if (!Win32CsrValidateBuffer(ProcessData, InputRecord, Length, sizeof(INPUT_RECORD)))
626 {
627 ConioUnlockConsole(Console);
628 return STATUS_ACCESS_VIOLATION;
629 }
630
631 for (i = 0; i < Length && NT_SUCCESS(Status); i++)
632 {
633 if (!Request->Data.WriteConsoleInputRequest.Unicode &&
634 InputRecord->EventType == KEY_EVENT)
635 {
636 CHAR AsciiChar = InputRecord->Event.KeyEvent.uChar.AsciiChar;
637 ConsoleInputAnsiCharToUnicodeChar(Console,
638 &InputRecord->Event.KeyEvent.uChar.UnicodeChar,
639 &AsciiChar);
640 }
641 Status = ConioProcessChar(Console, InputRecord++);
642 }
643
644 ConioUnlockConsole(Console);
645
646 Request->Data.WriteConsoleInputRequest.Length = i;
647
648 return Status;
649 }
650
651 /* EOF */