ReactOS  0.4.15-dev-1039-gb9754fa
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) \
38 do { \
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) \
44 do { \
45  ASSERT((ULONG_PTR)(dWChar) != (ULONG_PTR)(sChar)); \
46  MultiByteToWideChar((Console)->InputCodePage, 0, (sChar), 1, (dWChar), 1); \
47 } while (0)
48 
49 
50 typedef 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 
60 static 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 
73 static 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 
86 static 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 
145 static 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);
166 static 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 */
200 NTSTATUS
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 
238 static 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 
269 static NTSTATUS
270 ReadChars(IN PGET_INPUT_INFO InputInfo,
271  IN PCSR_API_MESSAGE ApiMessage,
272  IN BOOLEAN CreateWaitBlock OPTIONAL);
273 
274 // Wait function CSR_WAIT_FUNCTION
275 static BOOLEAN
276 NTAPI
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  {
312  Status = (InputHandle == InputInfo->HandleEntry ? STATUS_ALERTED
313  : STATUS_PENDING);
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 
323 Quit:
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,
337  OUT PVOID Buffer,
338  IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl,
340  IN ULONG NumCharsToRead,
341  OUT PULONG NumCharsRead OPTIONAL);
342 static 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 
354  PVOID Buffer;
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,
399  InputBuffer,
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 
433 static NTSTATUS
435  IN PCSR_API_MESSAGE ApiMessage,
436  IN BOOLEAN CreateWaitBlock OPTIONAL);
437 
438 // Wait function CSR_WAIT_FUNCTION
439 static BOOLEAN
440 NTAPI
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  {
476  Status = (InputHandle == InputInfo->HandleEntry ? STATUS_ALERTED
477  : STATUS_PENDING);
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 
487 Quit:
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);
505 static 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,
539  InputBuffer,
540  (GetInputRequest->Flags & CONSOLE_READ_KEEPEVENT) != 0,
541  (GetInputRequest->Flags & CONSOLE_READ_CONTINUE ) == 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 */
584 CON_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,
626  &InputBuffer,
627  &HandleEntry,
628  GENERIC_READ,
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 */
649 CON_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_KEEPEVENT | CONSOLE_READ_CONTINUE))
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,
691  &InputBuffer,
692  &HandleEntry,
693  GENERIC_READ,
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 */
724 CON_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  {
777  ConioInputEventToUnicode((PCONSOLE)Console, &InputRecord[i]);
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 */
807 CON_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 */
832 CON_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 
847  InputBuffer,
848  &GetNumInputEventsRequest->NumberOfEvents);
849 
851  return Status;
852 }
853 
854 /* EOF */
#define IN
Definition: typedefs.h:39
#define CsrGetClientThread()
Definition: csrsrv.h:77
ULONG NumRecords
Definition: conmsg.h:568
WCHAR UnicodeChar
Definition: wincon.h:245
USHORT MaximumLength
Definition: env_spec_w32.h:370
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
VOID ConioUnpause(PCONSRV_CONSOLE Console, UCHAR Flags)
Definition: console.c:866
PVOID HandleEntry
Definition: coninput.c:53
#define TRUE
Definition: types.h:120
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_THREAD_IS_TERMINATING
Definition: ntstatus.h:311
WORD vk
Definition: input.c:77
char CHAR
Definition: xmlstorage.h:175
struct _CONSOLE_API_MESSAGE * PCONSOLE_API_MESSAGE
ULONG ControlKeyState
Definition: conmsg.h:268
LONG NTSTATUS
Definition: precomp.h:26
BOOLEAN NTAPI CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage, IN PVOID *Buffer, IN ULONG ElementCount, IN ULONG ElementSize)
Definition: api.c:1426
#define PAUSED_FROM_KEYBOARD
Definition: conio_winsrv.h:107
struct _GET_INPUT_INFO GET_INPUT_INFO
#define ConsoleAllocHeap(Flags, Size)
Definition: heap.h:14
DWORD dwControlKeyState
Definition: wincon.h:248
#define CTRL_C_EVENT
Definition: wincon.h:68
PCSR_THREAD CallingThread
Definition: coninput.c:52
static VOID ConioInputEventToUnicode(PCONSOLE Console, PINPUT_RECORD InputEvent)
Definition: coninput.c:74
#define VK_LWIN
Definition: winuser.h:2210
uint16_t * PWCHAR
Definition: typedefs.h:56
_In_ PVOID Parameter
Definition: ldrtypes.h:241
#define STATUS_ALERTED
Definition: ntstatus.h:80
INPUT_RECORD RecordStaticBuffer[5]
Definition: conmsg.h:566
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
BOOLEAN NTAPI CsrNotifyWait(IN PLIST_ENTRY WaitList, IN BOOLEAN NotifyAll, IN PVOID WaitArgument1, IN PVOID WaitArgument2)
Definition: wait.c:388
CHAR StaticBuffer[80]
Definition: conmsg.h:260
CHAR InputBuffer[80]
Definition: conmgr.c:33
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
WORD wVirtualKeyCode
Definition: wincon.h:242
static VOID ConioInputEventToAnsi(PCONSOLE Console, PINPUT_RECORD InputEvent)
Definition: coninput.c:61
NTSTATUS NTAPI ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console, IN PCONSOLE_INPUT_BUFFER InputBuffer)
Definition: coninput.c:357
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
ULONG CtrlWakeupMask
Definition: conmsg.h:267
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
NTSTATUS NTAPI ConSrvConsoleProcessCtrlEvent(IN PCONSRV_CONSOLE Console, IN ULONG ProcessGroupId, IN ULONG CtrlEvent)
Definition: console.c:1402
unsigned int BOOL
Definition: ntddk_ex.h:94
#define GENERIC_WRITE
Definition: nt_native.h:90
#define KEY_EVENT
Definition: wincon.h:128
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
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
ULONG CaptureBufferSize
Definition: conmsg.h:264
#define GetConsoleInputBufferMode(Console)
Definition: conio.h:318
void DPRINT(...)
Definition: polytest.cpp:61
Definition: bufpool.h:45
#define ConsoleInputUnicodeToAnsiChar(Console, dChar, sWChar)
Definition: coninput.c:37
CON_API(SrvReadConsole, CONSOLE_READCONSOLE, ReadConsoleRequest)
Definition: coninput.c:584
#define LEFT_ALT_PRESSED
Definition: wincon.h:138
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
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
__wchar_t WCHAR
Definition: xmlstorage.h:180
static VOID PostprocessInput(PCONSRV_CONSOLE Console)
Definition: coninput.c:146
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
#define ConsoleInputAnsiToUnicodeChar(Console, dWChar, sChar)
Definition: coninput.c:43
ULONG InitialNumBytes
Definition: conmsg.h:266
KEY_EVENT_RECORD KeyEvent
Definition: wincon.h:278
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned long DWORD
Definition: ntddk_ex.h:95
PINPUT_RECORD RecordBufPtr
Definition: conmsg.h:567
#define ENABLE_LINE_INPUT
Definition: wincon.h:79
VOID NTAPI CsrDereferenceWait(IN PLIST_ENTRY WaitList)
Definition: wait.c:266
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define LEFT_CTRL_PRESSED
Definition: wincon.h:140
Status
Definition: gdiplustypes.h:24
static NTSTATUS ConioAddInputEvents(PCONSRV_CONSOLE Console, PINPUT_RECORD InputRecords, ULONG NumEventsToWrite, PULONG NumEventsWritten, BOOLEAN AppendToEnd)
Definition: coninput.c:167
#define GENERIC_READ
Definition: compat.h:135
Definition: typedefs.h:119
struct _CONSRV_CONSOLE * PCONSRV_CONSOLE
#define VK_RWIN
Definition: winuser.h:2211
unsigned char BYTE
Definition: xxhash.c:193
#define CONSOLE_READ_KEEPEVENT
Definition: wincon.h:122
struct _CONSOLE_READCONSOLE_CONTROL CONSOLE_READCONSOLE_CONTROL
#define ENABLE_PROCESSED_INPUT
Definition: wincon.h:78
BOOLEAN Unicode
Definition: conmsg.h:570
#define CONSOLE_READ_CONTINUE
Definition: wincon.h:123
HANDLE InputHandle
Definition: apc.c:9
#define VK_SCROLL
Definition: winuser.h:2255
#define VK_NUMLOCK
Definition: winuser.h:2254
#define ConSrvGetInputBufferAndHandleEntry(ProcessData, Handle, Ptr, Entry, Access, LockConsole)
Definition: coninput.c:23
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
#define VK_CAPITAL
Definition: winuser.h:2181
VOID ConioPause(PCONSRV_CONSOLE Console, UCHAR Flags)
Definition: console.c:859
unsigned int * PULONG
Definition: retypes.h:1
unsigned int UINT
Definition: ndis.h:50
CConsole Console
WORD EventType
Definition: wincon.h:276
#define DPRINT1
Definition: precomp.h:8
#define ConsoleFreeHeap(HeapBase)
Definition: heap.h:15
union _INPUT_RECORD::@3238 Event
#define VK_PAUSE
Definition: winuser.h:2180
#define OUT
Definition: typedefs.h:40
#define ConSrvGetInputBuffer(ProcessData, Handle, Ptr, Access, LockConsole)
Definition: coninput.c:19
unsigned int ULONG
Definition: retypes.h:1
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
PCONSOLE_INPUT_BUFFER InputBuffer
Definition: coninput.c:54
#define RIGHT_CTRL_PRESSED
Definition: wincon.h:139
NTSTATUS NTAPI ConDrvGetConsoleNumberOfInputEvents(IN PCONSOLE Console, IN PCONSOLE_INPUT_BUFFER InputBuffer, OUT PULONG NumberOfEvents)
Definition: coninput.c:374
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
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
return STATUS_SUCCESS
Definition: btrfs.c:3014
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
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
#define RIGHT_ALT_PRESSED
Definition: wincon.h:137
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
#define ConSrvReleaseInputBuffer(Buff, IsConsoleLocked)
Definition: coninput.c:27
union _KEY_EVENT_RECORD::@3237 uChar
struct _GET_INPUT_INFO * PGET_INPUT_INFO
static NTSTATUS ReadChars(IN PGET_INPUT_INFO InputInfo, IN PCSR_API_MESSAGE ApiMessage, IN BOOLEAN CreateWaitBlock OPTIONAL)
Definition: coninput.c:343
struct _INPUT_RECORD INPUT_RECORD
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68