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