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