Sync to trunk head (r47736)
[reactos.git] / subsystems / win32 / csrss / 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 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
42 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
43
44 Buffer = (PCHAR)Request->Data.ReadConsoleRequest.Buffer;
45 UnicodeBuffer = (PWCHAR)Buffer;
46 if (!Win32CsrValidateBuffer(ProcessData, Buffer, nNumberOfCharsToRead, CharSize))
47 return STATUS_ACCESS_VIOLATION;
48
49 if (Request->Data.ReadConsoleRequest.NrCharactersRead * sizeof(WCHAR) > nNumberOfCharsToRead * CharSize)
50 return STATUS_INVALID_PARAMETER;
51
52 Status = ConioLockConsole(ProcessData, Request->Data.ReadConsoleRequest.ConsoleHandle,
53 &Console, GENERIC_READ);
54 if (! NT_SUCCESS(Status))
55 {
56 return Status;
57 }
58 Request->Data.ReadConsoleRequest.EventHandle = ProcessData->ConsoleEvent;
59
60 Status = STATUS_PENDING; /* we haven't read anything (yet) */
61 if (Console->Mode & ENABLE_LINE_INPUT)
62 {
63 if (Console->LineBuffer == NULL)
64 {
65 /* Starting a new line */
66 Console->LineMaxSize = max(256, nNumberOfCharsToRead);
67 Console->LineBuffer = HeapAlloc(Win32CsrApiHeap, 0, Console->LineMaxSize * sizeof(WCHAR));
68 if (Console->LineBuffer == NULL)
69 {
70 Status = STATUS_NO_MEMORY;
71 goto done;
72 }
73 Console->LineComplete = FALSE;
74 Console->LineUpPressed = FALSE;
75 Console->LineInsertToggle = 0;
76 Console->LineWakeupMask = Request->Data.ReadConsoleRequest.CtrlWakeupMask;
77 Console->LineSize = Request->Data.ReadConsoleRequest.NrCharactersRead;
78 Console->LinePos = Console->LineSize;
79 /* pre-filling the buffer is only allowed in the Unicode API,
80 * so we don't need to worry about conversion */
81 memcpy(Console->LineBuffer, Buffer, Console->LineSize * sizeof(WCHAR));
82 if (Console->LineSize == Console->LineMaxSize)
83 {
84 Console->LineComplete = TRUE;
85 Console->LinePos = 0;
86 }
87 }
88
89 /* If we don't have a complete line yet, process the pending input */
90 while (!Console->LineComplete && !IsListEmpty(&Console->InputEvents))
91 {
92 /* remove input event from queue */
93 CurrentEntry = RemoveHeadList(&Console->InputEvents);
94 if (IsListEmpty(&Console->InputEvents))
95 {
96 ResetEvent(Console->ActiveEvent);
97 }
98 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
99
100 /* only pay attention to key down */
101 if (KEY_EVENT == Input->InputEvent.EventType
102 && Input->InputEvent.Event.KeyEvent.bKeyDown)
103 {
104 LineInputKeyDown(Console, &Input->InputEvent.Event.KeyEvent);
105 Request->Data.ReadConsoleRequest.ControlKeyState = Input->InputEvent.Event.KeyEvent.dwControlKeyState;
106 }
107 HeapFree(Win32CsrApiHeap, 0, Input);
108 }
109
110 /* Check if we have a complete line to read from */
111 if (Console->LineComplete)
112 {
113 while (i < nNumberOfCharsToRead && Console->LinePos != Console->LineSize)
114 {
115 WCHAR Char = Console->LineBuffer[Console->LinePos++];
116 if (Request->Data.ReadConsoleRequest.Unicode)
117 UnicodeBuffer[i++] = Char;
118 else
119 ConsoleInputUnicodeCharToAnsiChar(Console, &Buffer[i++], &Char);
120 }
121 if (Console->LinePos == Console->LineSize)
122 {
123 /* Entire line has been read */
124 HeapFree(Win32CsrApiHeap, 0, Console->LineBuffer);
125 Console->LineBuffer = NULL;
126 }
127 Status = STATUS_SUCCESS;
128 }
129 }
130 else
131 {
132 /* Character input */
133 while (i < nNumberOfCharsToRead && !IsListEmpty(&Console->InputEvents))
134 {
135 /* remove input event from queue */
136 CurrentEntry = RemoveHeadList(&Console->InputEvents);
137 if (IsListEmpty(&Console->InputEvents))
138 {
139 ResetEvent(Console->ActiveEvent);
140 }
141 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
142
143 /* only pay attention to valid ascii chars, on key down */
144 if (KEY_EVENT == Input->InputEvent.EventType
145 && Input->InputEvent.Event.KeyEvent.bKeyDown
146 && Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar != L'\0')
147 {
148 WCHAR Char = Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar;
149 if (Request->Data.ReadConsoleRequest.Unicode)
150 UnicodeBuffer[i++] = Char;
151 else
152 ConsoleInputUnicodeCharToAnsiChar(Console, &Buffer[i++], &Char);
153 Status = STATUS_SUCCESS; /* did read something */
154 }
155 HeapFree(Win32CsrApiHeap, 0, Input);
156 }
157 }
158 done:
159 Request->Data.ReadConsoleRequest.NrCharactersRead = i;
160 ConioUnlockConsole(Console);
161
162 return Status;
163 }
164
165 static VOID FASTCALL
166 ConioInputEventToAnsi(PCSRSS_CONSOLE Console, PINPUT_RECORD InputEvent)
167 {
168 if (InputEvent->EventType == KEY_EVENT)
169 {
170 WCHAR UnicodeChar = InputEvent->Event.KeyEvent.uChar.UnicodeChar;
171 InputEvent->Event.KeyEvent.uChar.UnicodeChar = 0;
172 ConsoleInputUnicodeCharToAnsiChar(Console,
173 &InputEvent->Event.KeyEvent.uChar.AsciiChar,
174 &UnicodeChar);
175 }
176 }
177
178 static NTSTATUS FASTCALL
179 ConioProcessChar(PCSRSS_CONSOLE Console,
180 PINPUT_RECORD InputEvent)
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 ConsoleInput *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
325 if (NULL == Console)
326 {
327 DPRINT1("No Active Console!\n");
328 return;
329 }
330
331 Fake = UnicodeChar &&
332 (msg->message != WM_CHAR && msg->message != WM_SYSCHAR &&
333 msg->message != WM_KEYUP && msg->message != WM_SYSKEYUP);
334 NotChar = (msg->message != WM_CHAR && msg->message != WM_SYSCHAR);
335 if (NotChar)
336 LastVirtualKey = msg->wParam;
337
338 DPRINT ("csrss: %s %s %s %s %02x %02x '%lc' %04x\n",
339 Down ? "down" : "up ",
340 (msg->message == WM_CHAR || msg->message == WM_SYSCHAR) ?
341 "char" : "key ",
342 Fake ? "fake" : "real",
343 NotChar ? "notc" : "char",
344 VirtualScanCode,
345 VirtualKeyCode,
346 (UnicodeChar >= L' ') ? UnicodeChar : L'.',
347 ShiftState);
348
349 if (Fake)
350 return;
351
352 /* process Ctrl-C and Ctrl-Break */
353 if (Console->Mode & ENABLE_PROCESSED_INPUT &&
354 er.Event.KeyEvent.bKeyDown &&
355 ((er.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE) ||
356 (er.Event.KeyEvent.wVirtualKeyCode == 'C')) &&
357 (er.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)))
358 {
359 PCSRSS_PROCESS_DATA current;
360 PLIST_ENTRY current_entry;
361 DPRINT1("Console_Api Ctrl-C\n");
362 current_entry = Console->ProcessList.Flink;
363 while (current_entry != &Console->ProcessList)
364 {
365 current = CONTAINING_RECORD(current_entry, CSRSS_PROCESS_DATA, ProcessEntry);
366 current_entry = current_entry->Flink;
367 ConioConsoleCtrlEvent((DWORD)CTRL_C_EVENT, current);
368 }
369 if (Console->LineBuffer && !Console->LineComplete)
370 {
371 /* Line input is in progress; end it */
372 Console->LinePos = Console->LineSize = 0;
373 Console->LineComplete = TRUE;
374 }
375 return;
376 }
377
378 if (0 != (er.Event.KeyEvent.dwControlKeyState
379 & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
380 && (VK_UP == er.Event.KeyEvent.wVirtualKeyCode
381 || VK_DOWN == er.Event.KeyEvent.wVirtualKeyCode))
382 {
383 if (er.Event.KeyEvent.bKeyDown)
384 {
385 /* scroll up or down */
386 if (VK_UP == er.Event.KeyEvent.wVirtualKeyCode)
387 {
388 /* only scroll up if there is room to scroll up into */
389 if (Console->ActiveBuffer->CurrentY != Console->ActiveBuffer->MaxY - 1)
390 {
391 Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY +
392 Console->ActiveBuffer->MaxY - 1) %
393 Console->ActiveBuffer->MaxY;
394 Console->ActiveBuffer->CurrentY++;
395 }
396 }
397 else
398 {
399 /* only scroll down if there is room to scroll down into */
400 if (Console->ActiveBuffer->CurrentY != 0)
401 {
402 Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY + 1) %
403 Console->ActiveBuffer->MaxY;
404 Console->ActiveBuffer->CurrentY--;
405 }
406 }
407 ConioDrawConsole(Console);
408 }
409 return;
410 }
411 ConioProcessChar(Console, &er);
412 }
413
414 CSR_API(CsrReadInputEvent)
415 {
416 PLIST_ENTRY CurrentEntry;
417 PCSRSS_CONSOLE Console;
418 NTSTATUS Status;
419 BOOLEAN Done = FALSE;
420 ConsoleInput *Input;
421
422 DPRINT("CsrReadInputEvent\n");
423
424 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
425 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
426 Request->Data.ReadInputRequest.Event = ProcessData->ConsoleEvent;
427
428 Status = ConioLockConsole(ProcessData, Request->Data.ReadInputRequest.ConsoleHandle, &Console, GENERIC_READ);
429 if (! NT_SUCCESS(Status))
430 {
431 return Status;
432 }
433
434 /* only get input if there is any */
435 CurrentEntry = Console->InputEvents.Flink;
436 while (CurrentEntry != &Console->InputEvents)
437 {
438 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
439 CurrentEntry = CurrentEntry->Flink;
440
441 if (Done)
442 {
443 Request->Data.ReadInputRequest.MoreEvents = TRUE;
444 break;
445 }
446
447 RemoveEntryList(&Input->ListEntry);
448
449 if (!Done)
450 {
451 Request->Data.ReadInputRequest.Input = Input->InputEvent;
452 if (Request->Data.ReadInputRequest.Unicode == FALSE)
453 {
454 ConioInputEventToAnsi(Console, &Request->Data.ReadInputRequest.Input);
455 }
456 Done = TRUE;
457 }
458
459 HeapFree(Win32CsrApiHeap, 0, Input);
460 }
461
462 if (Done)
463 Status = STATUS_SUCCESS;
464 else
465 Status = STATUS_PENDING;
466
467 if (IsListEmpty(&Console->InputEvents))
468 {
469 ResetEvent(Console->ActiveEvent);
470 }
471
472 ConioUnlockConsole(Console);
473
474 return Status;
475 }
476
477 CSR_API(CsrFlushInputBuffer)
478 {
479 PLIST_ENTRY CurrentEntry;
480 PCSRSS_CONSOLE Console;
481 ConsoleInput* Input;
482 NTSTATUS Status;
483
484 DPRINT("CsrFlushInputBuffer\n");
485
486 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
487 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
488 Status = ConioLockConsole(ProcessData,
489 Request->Data.FlushInputBufferRequest.ConsoleInput,
490 &Console,
491 GENERIC_WRITE);
492 if(! NT_SUCCESS(Status))
493 {
494 return Status;
495 }
496
497 /* Discard all entries in the input event queue */
498 while (!IsListEmpty(&Console->InputEvents))
499 {
500 CurrentEntry = RemoveHeadList(&Console->InputEvents);
501 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
502 /* Destroy the event */
503 HeapFree(Win32CsrApiHeap, 0, Input);
504 }
505 ResetEvent(Console->ActiveEvent);
506
507 ConioUnlockConsole(Console);
508
509 return STATUS_SUCCESS;
510 }
511
512 CSR_API(CsrGetNumberOfConsoleInputEvents)
513 {
514 NTSTATUS Status;
515 PCSRSS_CONSOLE Console;
516 PLIST_ENTRY CurrentItem;
517 DWORD NumEvents;
518
519 DPRINT("CsrGetNumberOfConsoleInputEvents\n");
520
521 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
522 Request->Header.u1.s1.DataLength = Request->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
523
524 Status = ConioLockConsole(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, &Console, GENERIC_READ);
525 if (! NT_SUCCESS(Status))
526 {
527 return Status;
528 }
529
530 CurrentItem = Console->InputEvents.Flink;
531 NumEvents = 0;
532
533 /* If there are any events ... */
534 while (CurrentItem != &Console->InputEvents)
535 {
536 CurrentItem = CurrentItem->Flink;
537 NumEvents++;
538 }
539
540 ConioUnlockConsole(Console);
541
542 Request->Data.GetNumInputEventsRequest.NumInputEvents = NumEvents;
543
544 return STATUS_SUCCESS;
545 }
546
547 CSR_API(CsrPeekConsoleInput)
548 {
549 NTSTATUS Status;
550 PCSRSS_CONSOLE Console;
551 DWORD Length;
552 PLIST_ENTRY CurrentItem;
553 PINPUT_RECORD InputRecord;
554 ConsoleInput* Item;
555 UINT NumItems;
556
557 DPRINT("CsrPeekConsoleInput\n");
558
559 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
560 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
561
562 Status = ConioLockConsole(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, &Console, GENERIC_READ);
563 if(! NT_SUCCESS(Status))
564 {
565 return Status;
566 }
567
568 InputRecord = Request->Data.PeekConsoleInputRequest.InputRecord;
569 Length = Request->Data.PeekConsoleInputRequest.Length;
570
571 if (!Win32CsrValidateBuffer(ProcessData, InputRecord, Length, sizeof(INPUT_RECORD)))
572 {
573 ConioUnlockConsole(Console);
574 return STATUS_ACCESS_VIOLATION;
575 }
576
577 NumItems = 0;
578
579 if (! IsListEmpty(&Console->InputEvents))
580 {
581 CurrentItem = Console->InputEvents.Flink;
582
583 while (CurrentItem != &Console->InputEvents && NumItems < Length)
584 {
585 Item = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
586
587 ++NumItems;
588 *InputRecord = Item->InputEvent;
589
590 if (Request->Data.PeekConsoleInputRequest.Unicode == FALSE)
591 {
592 ConioInputEventToAnsi(Console, InputRecord);
593 }
594
595 InputRecord++;
596 CurrentItem = CurrentItem->Flink;
597 }
598 }
599
600 ConioUnlockConsole(Console);
601
602 Request->Data.PeekConsoleInputRequest.Length = NumItems;
603
604 return STATUS_SUCCESS;
605 }
606
607 CSR_API(CsrWriteConsoleInput)
608 {
609 PINPUT_RECORD InputRecord;
610 PCSRSS_CONSOLE Console;
611 NTSTATUS Status;
612 DWORD Length;
613 DWORD i;
614
615 DPRINT("CsrWriteConsoleInput\n");
616
617 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
618 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
619
620 Status = ConioLockConsole(ProcessData, Request->Data.WriteConsoleInputRequest.ConsoleHandle, &Console, GENERIC_WRITE);
621 if (! NT_SUCCESS(Status))
622 {
623 return Status;
624 }
625
626 InputRecord = Request->Data.WriteConsoleInputRequest.InputRecord;
627 Length = Request->Data.WriteConsoleInputRequest.Length;
628
629 if (!Win32CsrValidateBuffer(ProcessData, InputRecord, Length, sizeof(INPUT_RECORD)))
630 {
631 ConioUnlockConsole(Console);
632 return STATUS_ACCESS_VIOLATION;
633 }
634
635 for (i = 0; i < Length && NT_SUCCESS(Status); i++)
636 {
637 if (!Request->Data.WriteConsoleInputRequest.Unicode &&
638 InputRecord->EventType == KEY_EVENT)
639 {
640 CHAR AsciiChar = InputRecord->Event.KeyEvent.uChar.AsciiChar;
641 ConsoleInputAnsiCharToUnicodeChar(Console,
642 &InputRecord->Event.KeyEvent.uChar.UnicodeChar,
643 &AsciiChar);
644 }
645 Status = ConioProcessChar(Console, InputRecord++);
646 }
647
648 ConioUnlockConsole(Console);
649
650 Request->Data.WriteConsoleInputRequest.Length = i;
651
652 return Status;
653 }
654
655 /* EOF */