ReactOS 0.4.15-dev-7788-g1ad9096
coninput.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/consrv/coninput.c
5 * PURPOSE: Console Input functions
6 * PROGRAMMERS: Jeffrey Morlan
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10/* INCLUDES *******************************************************************/
11
12#include "consrv.h"
13
14#define NDEBUG
15#include <debug.h>
16
17/* GLOBALS ********************************************************************/
18
19#define ConSrvGetInputBuffer(ProcessData, Handle, Ptr, Access, LockConsole) \
20 ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), NULL, \
21 (Access), (LockConsole), INPUT_BUFFER)
22
23#define ConSrvGetInputBufferAndHandleEntry(ProcessData, Handle, Ptr, Entry, Access, LockConsole) \
24 ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), (Entry), \
25 (Access), (LockConsole), INPUT_BUFFER)
26
27#define ConSrvReleaseInputBuffer(Buff, IsConsoleLocked) \
28 ConSrvReleaseObject(&(Buff)->Header, (IsConsoleLocked))
29
30
31/*
32 * From MSDN:
33 * "The lpMultiByteStr and lpWideCharStr pointers must not be the same.
34 * If they are the same, the function fails, and GetLastError returns
35 * ERROR_INVALID_PARAMETER."
36 */
37#define ConsoleInputUnicodeToAnsiChar(Console, dChar, sWChar) \
38do { \
39 ASSERT((ULONG_PTR)(dChar) != (ULONG_PTR)(sWChar)); \
40 WideCharToMultiByte((Console)->InputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL); \
41} while (0)
42
43#define ConsoleInputAnsiToUnicodeChar(Console, dWChar, sChar) \
44do { \
45 ASSERT((ULONG_PTR)(dWChar) != (ULONG_PTR)(sChar)); \
46 MultiByteToWideChar((Console)->InputCodePage, 0, (sChar), 1, (dWChar), 1); \
47} while (0)
48
49
50typedef struct _GET_INPUT_INFO
51{
52 PCSR_THREAD CallingThread; // The thread which called the input API.
53 PVOID HandleEntry; // The handle data associated with the wait thread.
54 PCONSOLE_INPUT_BUFFER InputBuffer; // The input buffer corresponding to the handle.
56
57
58/* PRIVATE FUNCTIONS **********************************************************/
59
60static VOID
62{
63 if (InputEvent->EventType == KEY_EVENT)
64 {
65 WCHAR UnicodeChar = InputEvent->Event.KeyEvent.uChar.UnicodeChar;
66 InputEvent->Event.KeyEvent.uChar.UnicodeChar = 0;
68 &InputEvent->Event.KeyEvent.uChar.AsciiChar,
69 &UnicodeChar);
70 }
71}
72
73static VOID
75{
76 if (InputEvent->EventType == KEY_EVENT)
77 {
78 CHAR AsciiChar = InputEvent->Event.KeyEvent.uChar.AsciiChar;
79 InputEvent->Event.KeyEvent.uChar.AsciiChar = 0;
81 &InputEvent->Event.KeyEvent.uChar.UnicodeChar,
82 &AsciiChar);
83 }
84}
85
86static ULONG
88 PINPUT_RECORD InputEvent,
89 ULONG NumEventsToWrite)
90{
91 ULONG NumEvents;
92
93 /*
94 * Loop each event, and for each, check for pause or unpause
95 * and perform adequate behaviour.
96 */
97 for (NumEvents = NumEventsToWrite; NumEvents > 0; --NumEvents)
98 {
99 /* Check for pause or unpause */
100 if (InputEvent->EventType == KEY_EVENT && InputEvent->Event.KeyEvent.bKeyDown)
101 {
102 WORD vk = InputEvent->Event.KeyEvent.wVirtualKeyCode;
103 if (!(Console->PauseFlags & PAUSED_FROM_KEYBOARD))
104 {
105 DWORD cks = InputEvent->Event.KeyEvent.dwControlKeyState;
106 if (Console->InputBuffer.Mode & ENABLE_LINE_INPUT &&
107 (vk == VK_PAUSE ||
108 (vk == 'S' && (cks & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) &&
109 !(cks & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)))))
110 {
112
113 /* Skip the event */
114 RtlMoveMemory(InputEvent,
115 InputEvent + 1,
116 (NumEvents - 1) * sizeof(INPUT_RECORD));
117 --NumEventsToWrite;
118 continue;
119 }
120 }
121 else
122 {
123 if ((vk < VK_SHIFT || vk > VK_CAPITAL) && vk != VK_LWIN &&
124 vk != VK_RWIN && vk != VK_NUMLOCK && vk != VK_SCROLL)
125 {
127
128 /* Skip the event */
129 RtlMoveMemory(InputEvent,
130 InputEvent + 1,
131 (NumEvents - 1) * sizeof(INPUT_RECORD));
132 --NumEventsToWrite;
133 continue;
134 }
135 }
136 }
137
138 /* Go to the next event */
139 ++InputEvent;
140 }
141
142 return NumEventsToWrite;
143}
144
145static VOID
147{
148 CsrNotifyWait(&Console->ReadWaitQueue,
149 FALSE,
150 NULL,
151 NULL);
152 if (!IsListEmpty(&Console->ReadWaitQueue))
153 {
154 CsrDereferenceWait(&Console->ReadWaitQueue);
155 }
156}
157
158
162 IN BOOLEAN AppendToEnd,
163 IN PINPUT_RECORD InputRecord,
164 IN ULONG NumEventsToWrite,
165 OUT PULONG NumEventsWritten OPTIONAL);
166static NTSTATUS
168 PINPUT_RECORD InputRecords, // InputEvent
169 ULONG NumEventsToWrite,
170 PULONG NumEventsWritten,
171 BOOLEAN AppendToEnd)
172{
174
175 if (NumEventsWritten) *NumEventsWritten = 0;
176
177 NumEventsToWrite = PreprocessInput(Console, InputRecords, NumEventsToWrite);
178 if (NumEventsToWrite == 0) return STATUS_SUCCESS;
179
180 // Status = ConDrvAddInputEvents(Console,
181 // InputRecords,
182 // NumEventsToWrite,
183 // NumEventsWritten,
184 // AppendToEnd);
185
187 &Console->InputBuffer,
188 AppendToEnd,
189 InputRecords,
190 NumEventsToWrite,
191 NumEventsWritten);
192
193 // if (NT_SUCCESS(Status))
195
196 return Status;
197}
198
199/* FIXME: This function can be called by CONDRV, in ConioResizeBuffer() in text.c */
202 PINPUT_RECORD InputEvent)
203{
204 ULONG NumEventsWritten;
205
206 if (InputEvent->EventType == KEY_EVENT)
207 {
208 BOOL Down = InputEvent->Event.KeyEvent.bKeyDown;
209 UINT VirtualKeyCode = InputEvent->Event.KeyEvent.wVirtualKeyCode;
210 DWORD ShiftState = InputEvent->Event.KeyEvent.dwControlKeyState;
211
212 /* Process Ctrl-C and Ctrl-Break */
214 Down && (VirtualKeyCode == VK_PAUSE || VirtualKeyCode == 'C') &&
215 (ShiftState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) )
216 {
217 DPRINT1("Console_Api Ctrl-C\n");
219
220 if (Console->LineBuffer && !Console->LineComplete)
221 {
222 /* Line input is in progress; end it */
223 Console->LinePos = Console->LineSize = 0;
224 Console->LineComplete = TRUE;
225 }
226 return STATUS_SUCCESS; // STATUS_CONTROL_C_EXIT;
227 }
228 }
229
231 InputEvent,
232 1,
233 &NumEventsWritten,
234 TRUE);
235}
236
237
238static NTSTATUS
240 IN PCSR_API_MESSAGE ApiMessage,
241 IN CSR_WAIT_FUNCTION WaitFunction OPTIONAL,
242 IN BOOLEAN CreateWaitBlock OPTIONAL)
243{
244 if (CreateWaitBlock)
245 {
246 PGET_INPUT_INFO CapturedInputInfo;
247 PCONSRV_CONSOLE Console = (PCONSRV_CONSOLE)InputInfo->InputBuffer->Header.Console;
248
249 CapturedInputInfo = ConsoleAllocHeap(0, sizeof(GET_INPUT_INFO));
250 if (!CapturedInputInfo) return STATUS_NO_MEMORY;
251
252 RtlMoveMemory(CapturedInputInfo, InputInfo, sizeof(GET_INPUT_INFO));
253
254 if (!CsrCreateWait(&Console->ReadWaitQueue,
255 WaitFunction,
256 InputInfo->CallingThread,
257 ApiMessage,
258 CapturedInputInfo))
259 {
260 ConsoleFreeHeap(CapturedInputInfo);
261 return STATUS_NO_MEMORY;
262 }
263 }
264
265 /* Wait for input */
266 return STATUS_PENDING;
267}
268
269static NTSTATUS
271 IN PCSR_API_MESSAGE ApiMessage,
272 IN BOOLEAN CreateWaitBlock OPTIONAL);
273
274// Wait function CSR_WAIT_FUNCTION
275static BOOLEAN
276NTAPI
278 IN PCSR_THREAD WaitThread,
279 IN PCSR_API_MESSAGE WaitApiMessage,
280 IN PVOID WaitContext,
281 IN PVOID WaitArgument1,
282 IN PVOID WaitArgument2,
283 IN ULONG WaitFlags)
284{
286 PGET_INPUT_INFO InputInfo = (PGET_INPUT_INFO)WaitContext;
287
288 PVOID InputHandle = WaitArgument2;
289
290 DPRINT("ReadCharsThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags);
291
292 /*
293 * If we are notified of the process termination via a call
294 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
295 * CsrDestroyThread, just return.
296 */
297 if (WaitFlags & CsrProcessTerminating)
298 {
300 goto Quit;
301 }
302
303 /*
304 * Somebody is closing a handle to this input buffer,
305 * by calling ConSrvCloseHandleEntry.
306 * See whether we are linked to that handle (ie. we
307 * are a waiter for this handle), and if so, return.
308 * Otherwise, ignore the call and continue waiting.
309 */
310 if (InputHandle != NULL)
311 {
314 goto Quit;
315 }
316
317 /*
318 * If we go there, that means we are notified for some new input.
319 * The console is therefore already locked.
320 */
321 Status = ReadChars(InputInfo, WaitApiMessage, FALSE);
322
323Quit:
324 if (Status != STATUS_PENDING)
325 {
326 WaitApiMessage->Status = Status;
327 ConsoleFreeHeap(InputInfo);
328 }
329
330 return (Status == STATUS_PENDING ? FALSE : TRUE);
331}
332
336 IN BOOLEAN Unicode,
340 IN ULONG NumCharsToRead,
341 OUT PULONG NumCharsRead OPTIONAL);
342static NTSTATUS
344 IN PCSR_API_MESSAGE ApiMessage,
345 IN BOOLEAN CreateWaitBlock OPTIONAL)
346{
348 PCONSOLE_READCONSOLE ReadConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleRequest;
349 PCONSOLE_INPUT_BUFFER InputBuffer = InputInfo->InputBuffer;
350 CONSOLE_READCONSOLE_CONTROL ReadControl;
351
352 UNICODE_STRING ExeName;
353
355 ULONG NrCharactersRead = 0;
356 ULONG CharSize = (ReadConsoleRequest->Unicode ? sizeof(WCHAR) : sizeof(CHAR));
357
358 /* Retrieve the executable name, if needed */
359 if (ReadConsoleRequest->InitialNumBytes == 0 &&
360 ReadConsoleRequest->ExeLength <= sizeof(ReadConsoleRequest->StaticBuffer))
361 {
362 ExeName.Length = ExeName.MaximumLength = ReadConsoleRequest->ExeLength;
363 ExeName.Buffer = (PWCHAR)ReadConsoleRequest->StaticBuffer;
364 }
365 else
366 {
367 ExeName.Length = ExeName.MaximumLength = 0;
368 ExeName.Buffer = NULL;
369 }
370
371 /* Build the ReadControl structure */
372 ReadControl.nLength = sizeof(CONSOLE_READCONSOLE_CONTROL);
373 ReadControl.nInitialChars = ReadConsoleRequest->InitialNumBytes / CharSize;
374 ReadControl.dwCtrlWakeupMask = ReadConsoleRequest->CtrlWakeupMask;
375 ReadControl.dwControlKeyState = ReadConsoleRequest->ControlKeyState;
376
377 /*
378 * For optimization purposes, Windows (and hence ReactOS, too, for
379 * compatibility reasons) uses a static buffer if no more than eighty
380 * bytes are read. Otherwise a new buffer is used.
381 * The client-side expects that we know this behaviour.
382 */
383 if (ReadConsoleRequest->CaptureBufferSize <= sizeof(ReadConsoleRequest->StaticBuffer))
384 {
385 /*
386 * Adjust the internal pointer, because its old value points to
387 * the static buffer in the original ApiMessage structure.
388 */
389 // ReadConsoleRequest->Buffer = ReadConsoleRequest->StaticBuffer;
390 Buffer = ReadConsoleRequest->StaticBuffer;
391 }
392 else
393 {
394 Buffer = ReadConsoleRequest->Buffer;
395 }
396
397 DPRINT("Calling ConDrvReadConsole(%wZ)\n", &ExeName);
398 Status = ConDrvReadConsole(InputBuffer->Header.Console,
400 ReadConsoleRequest->Unicode,
401 Buffer,
402 &ReadControl,
403 &ExeName,
404 ReadConsoleRequest->NumBytes / CharSize, // NrCharactersToRead
405 &NrCharactersRead);
406 DPRINT("ConDrvReadConsole returned (%d ; Status = 0x%08x)\n",
407 NrCharactersRead, Status);
408
409 // ReadConsoleRequest->ControlKeyState = ReadControl.dwControlKeyState;
410
411 if (Status == STATUS_PENDING)
412 {
413 /* We haven't completed a read, so start a wait */
414 return WaitBeforeReading(InputInfo,
415 ApiMessage,
417 CreateWaitBlock);
418 }
419 else
420 {
421 /*
422 * We read all what we wanted. Set the number of bytes read and
423 * return the error code we were given.
424 */
425 ReadConsoleRequest->NumBytes = NrCharactersRead * CharSize;
426 ReadConsoleRequest->ControlKeyState = ReadControl.dwControlKeyState;
427
428 return Status;
429 // return STATUS_SUCCESS;
430 }
431}
432
433static NTSTATUS
435 IN PCSR_API_MESSAGE ApiMessage,
436 IN BOOLEAN CreateWaitBlock OPTIONAL);
437
438// Wait function CSR_WAIT_FUNCTION
439static BOOLEAN
440NTAPI
442 IN PCSR_THREAD WaitThread,
443 IN PCSR_API_MESSAGE WaitApiMessage,
444 IN PVOID WaitContext,
445 IN PVOID WaitArgument1,
446 IN PVOID WaitArgument2,
447 IN ULONG WaitFlags)
448{
450 PGET_INPUT_INFO InputInfo = (PGET_INPUT_INFO)WaitContext;
451
452 PVOID InputHandle = WaitArgument2;
453
454 DPRINT("ReadInputBufferThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags);
455
456 /*
457 * If we are notified of the process termination via a call
458 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
459 * CsrDestroyThread, just return.
460 */
461 if (WaitFlags & CsrProcessTerminating)
462 {
464 goto Quit;
465 }
466
467 /*
468 * Somebody is closing a handle to this input buffer,
469 * by calling ConSrvCloseHandleEntry.
470 * See whether we are linked to that handle (ie. we
471 * are a waiter for this handle), and if so, return.
472 * Otherwise, ignore the call and continue waiting.
473 */
474 if (InputHandle != NULL)
475 {
478 goto Quit;
479 }
480
481 /*
482 * If we go there, that means we are notified for some new input.
483 * The console is therefore already locked.
484 */
485 Status = ReadInputBuffer(InputInfo, WaitApiMessage, FALSE);
486
487Quit:
488 if (Status != STATUS_PENDING)
489 {
490 WaitApiMessage->Status = Status;
491 ConsoleFreeHeap(InputInfo);
492 }
493
494 return (Status == STATUS_PENDING ? FALSE : TRUE);
495}
496
500 IN BOOLEAN KeepEvents,
501 IN BOOLEAN WaitForMoreEvents,
502 OUT PINPUT_RECORD InputRecord,
503 IN ULONG NumEventsToRead,
504 OUT PULONG NumEventsRead OPTIONAL);
505static NTSTATUS
507 IN PCSR_API_MESSAGE ApiMessage,
508 IN BOOLEAN CreateWaitBlock OPTIONAL)
509{
511 PCONSOLE_GETINPUT GetInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetInputRequest;
512 PCONSOLE_INPUT_BUFFER InputBuffer = InputInfo->InputBuffer;
513 ULONG NumEventsRead;
514
515 PINPUT_RECORD InputRecord;
516
517 /*
518 * For optimization purposes, Windows (and hence ReactOS, too, for
519 * compatibility reasons) uses a static buffer if no more than five
520 * input records are read. Otherwise a new buffer is used.
521 * The client-side expects that we know this behaviour.
522 */
523 if (GetInputRequest->NumRecords <= sizeof(GetInputRequest->RecordStaticBuffer)/sizeof(INPUT_RECORD))
524 {
525 /*
526 * Adjust the internal pointer, because its old value points to
527 * the static buffer in the original ApiMessage structure.
528 */
529 // GetInputRequest->RecordBufPtr = GetInputRequest->RecordStaticBuffer;
530 InputRecord = GetInputRequest->RecordStaticBuffer;
531 }
532 else
533 {
534 InputRecord = GetInputRequest->RecordBufPtr;
535 }
536
537 NumEventsRead = 0;
538 Status = ConDrvGetConsoleInput(InputBuffer->Header.Console,
540 (GetInputRequest->Flags & CONSOLE_READ_NOREMOVE) != 0,
541 (GetInputRequest->Flags & CONSOLE_READ_NOWAIT ) == 0,
542 InputRecord,
543 GetInputRequest->NumRecords,
544 &NumEventsRead);
545
546 if (Status == STATUS_PENDING)
547 {
548 /* We haven't completed a read, so start a wait */
549 return WaitBeforeReading(InputInfo,
550 ApiMessage,
552 CreateWaitBlock);
553 }
554 else
555 {
556 /*
557 * We read all what we wanted. Set the number of events read and
558 * return the error code we were given.
559 */
560 GetInputRequest->NumRecords = NumEventsRead;
561
562 if (NT_SUCCESS(Status))
563 {
564 /* Now translate everything to ANSI */
565 if (!GetInputRequest->Unicode)
566 {
567 ULONG i;
568 for (i = 0; i < NumEventsRead; ++i)
569 {
570 ConioInputEventToAnsi(InputBuffer->Header.Console, &InputRecord[i]);
571 }
572 }
573 }
574
575 return Status;
576 // return STATUS_SUCCESS;
577 }
578}
579
580
581/* PUBLIC SERVER APIS *********************************************************/
582
583/* API_NUMBER: ConsolepReadConsole */
584CON_API(SrvReadConsole,
585 CONSOLE_READCONSOLE, ReadConsoleRequest)
586{
588 PVOID HandleEntry;
590 GET_INPUT_INFO InputInfo;
591
592 DPRINT("SrvReadConsole\n");
593
594 /*
595 * For optimization purposes, Windows (and hence ReactOS, too, for
596 * compatibility reasons) uses a static buffer if no more than eighty
597 * bytes are read. Otherwise a new buffer is used.
598 * The client-side expects that we know this behaviour.
599 */
600 if (ReadConsoleRequest->CaptureBufferSize <= sizeof(ReadConsoleRequest->StaticBuffer))
601 {
602 /*
603 * Adjust the internal pointer, because its old value points to
604 * the static buffer in the original ApiMessage structure.
605 */
606 // ReadConsoleRequest->Buffer = ReadConsoleRequest->StaticBuffer;
607 }
608 else
609 {
610 if (!CsrValidateMessageBuffer(ApiMessage,
611 (PVOID*)&ReadConsoleRequest->Buffer,
612 ReadConsoleRequest->CaptureBufferSize,
613 sizeof(BYTE)))
614 {
616 }
617 }
618
619 if (ReadConsoleRequest->InitialNumBytes > ReadConsoleRequest->NumBytes)
620 {
622 }
623
625 ReadConsoleRequest->InputHandle,
627 &HandleEntry,
629 TRUE);
630 if (!NT_SUCCESS(Status))
631 return Status;
632
633 ASSERT((PCONSOLE)Console == InputBuffer->Header.Console);
634
635 InputInfo.CallingThread = CsrGetClientThread();
636 InputInfo.HandleEntry = HandleEntry;
637 InputInfo.InputBuffer = InputBuffer;
638
639 Status = ReadChars(&InputInfo, ApiMessage, TRUE);
640
642
643 if (Status == STATUS_PENDING) *ReplyCode = CsrReplyPending;
644
645 return Status;
646}
647
648/* API_NUMBER: ConsolepGetConsoleInput */
649CON_API(SrvGetConsoleInput,
650 CONSOLE_GETINPUT, GetInputRequest)
651{
653 PVOID HandleEntry;
655 GET_INPUT_INFO InputInfo;
656
657 DPRINT("SrvGetConsoleInput\n");
658
659 if (GetInputRequest->Flags & ~(CONSOLE_READ_NOREMOVE | CONSOLE_READ_NOWAIT))
660 {
662 }
663
664 /*
665 * For optimization purposes, Windows (and hence ReactOS, too, for
666 * compatibility reasons) uses a static buffer if no more than five
667 * input records are read. Otherwise a new buffer is used.
668 * The client-side expects that we know this behaviour.
669 */
670 if (GetInputRequest->NumRecords <= sizeof(GetInputRequest->RecordStaticBuffer)/sizeof(INPUT_RECORD))
671 {
672 /*
673 * Adjust the internal pointer, because its old value points to
674 * the static buffer in the original ApiMessage structure.
675 */
676 // GetInputRequest->RecordBufPtr = GetInputRequest->RecordStaticBuffer;
677 }
678 else
679 {
680 if (!CsrValidateMessageBuffer(ApiMessage,
681 (PVOID*)&GetInputRequest->RecordBufPtr,
682 GetInputRequest->NumRecords,
683 sizeof(INPUT_RECORD)))
684 {
686 }
687 }
688
690 GetInputRequest->InputHandle,
692 &HandleEntry,
694 TRUE);
695 if (!NT_SUCCESS(Status))
696 return Status;
697
698 ASSERT((PCONSOLE)Console == InputBuffer->Header.Console);
699
700 InputInfo.CallingThread = CsrGetClientThread();
701 InputInfo.HandleEntry = HandleEntry;
702 InputInfo.InputBuffer = InputBuffer;
703
704 Status = ReadInputBuffer(&InputInfo, ApiMessage, TRUE);
705
707
708 if (Status == STATUS_PENDING) *ReplyCode = CsrReplyPending;
709
710 return Status;
711}
712
713#if 0
717 IN BOOLEAN AppendToEnd,
718 IN PINPUT_RECORD InputRecord,
719 IN ULONG NumEventsToWrite,
720 OUT PULONG NumEventsWritten OPTIONAL);
721#endif
722
723/* API_NUMBER: ConsolepWriteConsoleInput */
724CON_API(SrvWriteConsoleInput,
725 CONSOLE_WRITEINPUT, WriteInputRequest)
726{
729 ULONG NumEventsWritten;
730 PINPUT_RECORD InputRecord;
731
732 /*
733 * For optimization purposes, Windows (and hence ReactOS, too, for
734 * compatibility reasons) uses a static buffer if no more than five
735 * input records are written. Otherwise a new buffer is used.
736 * The client-side expects that we know this behaviour.
737 */
738 if (WriteInputRequest->NumRecords <= sizeof(WriteInputRequest->RecordStaticBuffer)/sizeof(INPUT_RECORD))
739 {
740 /*
741 * Adjust the internal pointer, because its old value points to
742 * the static buffer in the original ApiMessage structure.
743 */
744 // WriteInputRequest->RecordBufPtr = WriteInputRequest->RecordStaticBuffer;
745 InputRecord = WriteInputRequest->RecordStaticBuffer;
746 }
747 else
748 {
749 if (!CsrValidateMessageBuffer(ApiMessage,
750 (PVOID*)&WriteInputRequest->RecordBufPtr,
751 WriteInputRequest->NumRecords,
752 sizeof(INPUT_RECORD)))
753 {
755 }
756
757 InputRecord = WriteInputRequest->RecordBufPtr;
758 }
759
760 Status = ConSrvGetInputBuffer(ProcessData,
761 WriteInputRequest->InputHandle,
763 if (!NT_SUCCESS(Status))
764 {
765 WriteInputRequest->NumRecords = 0;
766 return Status;
767 }
768
769 ASSERT((PCONSOLE)Console == InputBuffer->Header.Console);
770
771 /* First translate everything to UNICODE */
772 if (!WriteInputRequest->Unicode)
773 {
774 ULONG i;
775 for (i = 0; i < WriteInputRequest->NumRecords; ++i)
776 {
778 }
779 }
780
781 /* Now, add the events */
782 NumEventsWritten = 0;
784 // InputBuffer,
785 InputRecord,
786 WriteInputRequest->NumRecords,
787 &NumEventsWritten,
788 WriteInputRequest->AppendToEnd);
789
790 // Status = ConDrvWriteConsoleInput((PCONSOLE)Console,
791 // InputBuffer,
792 // WriteInputRequest->AppendToEnd,
793 // InputRecord,
794 // WriteInputRequest->NumRecords,
795 // &NumEventsWritten);
796
797 WriteInputRequest->NumRecords = NumEventsWritten;
798
800 return Status;
801}
802
806/* API_NUMBER: ConsolepFlushInputBuffer */
807CON_API(SrvFlushConsoleInputBuffer,
808 CONSOLE_FLUSHINPUTBUFFER, FlushInputBufferRequest)
809{
812
813 Status = ConSrvGetInputBuffer(ProcessData,
814 FlushInputBufferRequest->InputHandle,
816 if (!NT_SUCCESS(Status))
817 return Status;
818
819 ASSERT((PCONSOLE)Console == InputBuffer->Header.Console);
820
822
824 return Status;
825}
826
830 OUT PULONG NumberOfEvents);
831/* API_NUMBER: ConsolepGetNumberOfInputEvents */
832CON_API(SrvGetConsoleNumberOfInputEvents,
833 CONSOLE_GETNUMINPUTEVENTS, GetNumInputEventsRequest)
834{
837
838 Status = ConSrvGetInputBuffer(ProcessData,
839 GetNumInputEventsRequest->InputHandle,
841 if (!NT_SUCCESS(Status))
842 return Status;
843
844 ASSERT((PCONSOLE)Console == InputBuffer->Header.Console);
845
848 &GetNumInputEventsRequest->NumberOfEvents);
849
851 return Status;
852}
853
854/* EOF */
unsigned char BOOLEAN
CConsole Console
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
Definition: bufpool.h:45
NTSTATUS NTAPI ConDrvReadConsole(IN PCONSOLE Console, IN PCONSOLE_INPUT_BUFFER InputBuffer, IN BOOLEAN Unicode, OUT PVOID Buffer, IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl, IN PVOID Parameter OPTIONAL, IN ULONG NumCharsToRead, OUT PULONG NumCharsRead OPTIONAL)
Definition: coninput.c:231
NTSTATUS NTAPI ConDrvGetConsoleInput(IN PCONSOLE Console, IN PCONSOLE_INPUT_BUFFER InputBuffer, IN BOOLEAN KeepEvents, IN BOOLEAN WaitForMoreEvents, OUT PINPUT_RECORD InputRecord, IN ULONG NumEventsToRead, OUT PULONG NumEventsRead OPTIONAL)
Definition: coninput.c:264
NTSTATUS NTAPI ConDrvGetConsoleNumberOfInputEvents(IN PCONSOLE Console, IN PCONSOLE_INPUT_BUFFER InputBuffer, OUT PULONG NumberOfEvents)
Definition: coninput.c:374
NTSTATUS NTAPI ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console, IN PCONSOLE_INPUT_BUFFER InputBuffer)
Definition: coninput.c:357
NTSTATUS NTAPI ConDrvWriteConsoleInput(IN PCONSOLE Console, IN PCONSOLE_INPUT_BUFFER InputBuffer, IN BOOLEAN AppendToEnd, IN PINPUT_RECORD InputRecord, IN ULONG NumEventsToWrite, OUT PULONG NumEventsWritten OPTIONAL)
Definition: coninput.c:330
#define ConSrvReleaseInputBuffer(Buff, IsConsoleLocked)
Definition: coninput.c:27
static NTSTATUS ReadInputBuffer(IN PGET_INPUT_INFO InputInfo, IN PCSR_API_MESSAGE ApiMessage, IN BOOLEAN CreateWaitBlock OPTIONAL)
Definition: coninput.c:506
NTSTATUS ConioProcessInputEvent(PCONSRV_CONSOLE Console, PINPUT_RECORD InputEvent)
Definition: coninput.c:201
static NTSTATUS ConioAddInputEvents(PCONSRV_CONSOLE Console, PINPUT_RECORD InputRecords, ULONG NumEventsToWrite, PULONG NumEventsWritten, BOOLEAN AppendToEnd)
Definition: coninput.c:167
static VOID ConioInputEventToUnicode(PCONSOLE Console, PINPUT_RECORD InputEvent)
Definition: coninput.c:74
#define ConsoleInputUnicodeToAnsiChar(Console, dChar, sWChar)
Definition: coninput.c:37
#define ConSrvGetInputBuffer(ProcessData, Handle, Ptr, Access, LockConsole)
Definition: coninput.c:19
static VOID PostprocessInput(PCONSRV_CONSOLE Console)
Definition: coninput.c:146
#define ConSrvGetInputBufferAndHandleEntry(ProcessData, Handle, Ptr, Entry, Access, LockConsole)
Definition: coninput.c:23
static VOID ConioInputEventToAnsi(PCONSOLE Console, PINPUT_RECORD InputEvent)
Definition: coninput.c:61
static NTSTATUS WaitBeforeReading(IN PGET_INPUT_INFO InputInfo, IN PCSR_API_MESSAGE ApiMessage, IN CSR_WAIT_FUNCTION WaitFunction OPTIONAL, IN BOOLEAN CreateWaitBlock OPTIONAL)
Definition: coninput.c:239
static NTSTATUS ReadChars(IN PGET_INPUT_INFO InputInfo, IN PCSR_API_MESSAGE ApiMessage, IN BOOLEAN CreateWaitBlock OPTIONAL)
Definition: coninput.c:343
static BOOLEAN NTAPI ReadInputBufferThread(IN PLIST_ENTRY WaitList, IN PCSR_THREAD WaitThread, IN PCSR_API_MESSAGE WaitApiMessage, IN PVOID WaitContext, IN PVOID WaitArgument1, IN PVOID WaitArgument2, IN ULONG WaitFlags)
Definition: coninput.c:441
static ULONG PreprocessInput(PCONSRV_CONSOLE Console, PINPUT_RECORD InputEvent, ULONG NumEventsToWrite)
Definition: coninput.c:87
static BOOLEAN NTAPI ReadCharsThread(IN PLIST_ENTRY WaitList, IN PCSR_THREAD WaitThread, IN PCSR_API_MESSAGE WaitApiMessage, IN PVOID WaitContext, IN PVOID WaitArgument1, IN PVOID WaitArgument2, IN ULONG WaitFlags)
Definition: coninput.c:277
#define ConsoleInputAnsiToUnicodeChar(Console, dWChar, sChar)
Definition: coninput.c:43
struct _GET_INPUT_INFO * PGET_INPUT_INFO
struct _GET_INPUT_INFO GET_INPUT_INFO
struct _CONSRV_CONSOLE * PCONSRV_CONSOLE
#define PAUSED_FROM_KEYBOARD
Definition: conio_winsrv.h:109
struct _CONSOLE_API_MESSAGE * PCONSOLE_API_MESSAGE
BOOLEAN NTAPI CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage, IN PVOID *Buffer, IN ULONG ElementCount, IN ULONG ElementSize)
Definition: api.c:1430
#define CsrGetClientThread()
Definition: csrsrv.h:77
VOID NTAPI CsrDereferenceWait(IN PLIST_ENTRY WaitList)
Definition: wait.c:266
BOOLEAN(NTAPI * CSR_WAIT_FUNCTION)(IN PLIST_ENTRY WaitList, IN PCSR_THREAD WaitThread, IN PCSR_API_MESSAGE WaitApiMessage, IN PVOID WaitContext, IN PVOID WaitArgument1, IN PVOID WaitArgument2, IN ULONG WaitFlags)
Definition: csrsrv.h:145
@ CsrProcessTerminating
Definition: csrsrv.h:85
@ CsrReplyPending
Definition: csrsrv.h:132
BOOLEAN NTAPI CsrCreateWait(IN PLIST_ENTRY WaitList, IN CSR_WAIT_FUNCTION WaitFunction, IN PCSR_THREAD CsrWaitThread, IN OUT PCSR_API_MESSAGE WaitApiMessage, IN PVOID WaitContext)
Definition: wait.c:209
BOOLEAN NTAPI CsrNotifyWait(IN PLIST_ENTRY WaitList, IN BOOLEAN NotifyAll, IN PVOID WaitArgument1, IN PVOID WaitArgument2)
Definition: wait.c:388
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define GENERIC_READ
Definition: compat.h:135
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned short WORD
Definition: ntddk_ex.h:93
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define ASSERT(a)
Definition: mode.c:44
HANDLE InputHandle
Definition: apc.c:9
WORD vk
Definition: input.c:77
unsigned int UINT
Definition: ndis.h:50
#define GENERIC_WRITE
Definition: nt_native.h:90
#define STATUS_ALERTED
Definition: ntstatus.h:80
#define STATUS_THREAD_IS_TERMINATING
Definition: ntstatus.h:311
#define STATUS_PENDING
Definition: ntstatus.h:82
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:71
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
ULONG NumRecords
Definition: conmsg.h:568
PINPUT_RECORD RecordBufPtr
Definition: conmsg.h:567
BOOLEAN Unicode
Definition: conmsg.h:570
INPUT_RECORD RecordStaticBuffer[5]
Definition: conmsg.h:566
ULONG CtrlWakeupMask
Definition: conmsg.h:267
ULONG ControlKeyState
Definition: conmsg.h:268
ULONG CaptureBufferSize
Definition: conmsg.h:264
CHAR StaticBuffer[80]
Definition: conmsg.h:260
ULONG InitialNumBytes
Definition: conmsg.h:266
PCONSOLE_INPUT_BUFFER InputBuffer
Definition: coninput.c:54
PCSR_THREAD CallingThread
Definition: coninput.c:52
PVOID HandleEntry
Definition: coninput.c:53
union _INPUT_RECORD::@3287 Event
WORD EventType
Definition: wincon.h:273
KEY_EVENT_RECORD KeyEvent
Definition: wincon.h:275
DWORD dwControlKeyState
Definition: wincon.h:248
WORD wVirtualKeyCode
Definition: wincon.h:242
union _KEY_EVENT_RECORD::@3286 uChar
WCHAR UnicodeChar
Definition: wincon.h:245
Definition: typedefs.h:120
USHORT MaximumLength
Definition: env_spec_w32.h:370
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
#define IN
Definition: typedefs.h:39
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
uint16_t * PWCHAR
Definition: typedefs.h:56
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR InputBuffer
Definition: wdfiotarget.h:953
#define CON_API(Name, TYPE, RequestName)
Definition: api.h:80
VOID ConioUnpause(PCONSRV_CONSOLE Console, UCHAR Flags)
Definition: console.c:866
NTSTATUS NTAPI ConSrvConsoleProcessCtrlEvent(IN PCONSRV_CONSOLE Console, IN ULONG ProcessGroupId, IN ULONG CtrlEvent)
Definition: console.c:1402
VOID ConioPause(PCONSRV_CONSOLE Console, UCHAR Flags)
Definition: console.c:859
#define ConsoleAllocHeap(Flags, Size)
Definition: heap.h:14
#define ConsoleFreeHeap(HeapBase)
Definition: heap.h:15
#define GetConsoleInputBufferMode(Console)
Definition: conio.h:320
#define CTRL_C_EVENT
Definition: wincon.h:68
#define LEFT_CTRL_PRESSED
Definition: wincon.h:140
#define KEY_EVENT
Definition: wincon.h:128
#define RIGHT_CTRL_PRESSED
Definition: wincon.h:139
struct _INPUT_RECORD INPUT_RECORD
#define RIGHT_ALT_PRESSED
Definition: wincon.h:137
#define CONSOLE_READ_NOREMOVE
Definition: wincon.h:122
struct _CONSOLE_READCONSOLE_CONTROL CONSOLE_READCONSOLE_CONTROL
#define LEFT_ALT_PRESSED
Definition: wincon.h:138
#define ENABLE_LINE_INPUT
Definition: wincon.h:79
#define ENABLE_PROCESSED_INPUT
Definition: wincon.h:78
#define CONSOLE_READ_NOWAIT
Definition: wincon.h:123
#define VK_CAPITAL
Definition: winuser.h:2206
#define VK_SCROLL
Definition: winuser.h:2280
#define VK_PAUSE
Definition: winuser.h:2205
#define VK_LWIN
Definition: winuser.h:2235
#define VK_NUMLOCK
Definition: winuser.h:2279
#define VK_RWIN
Definition: winuser.h:2236
_Inout_opt_ PVOID Parameter
Definition: rtltypes.h:323
__wchar_t WCHAR
Definition: xmlstorage.h:180
char CHAR
Definition: xmlstorage.h:175
unsigned char BYTE
Definition: xxhash.c:193