Sync with trunk r63887.
[reactos.git] / win32ss / user / winsrv / consrv / coninput.c
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 #define ConSrvGetInputBufferAndHandleEntry(ProcessData, Handle, Ptr, Entry, Access, LockConsole) \
23 ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), (Entry), \
24 (Access), (LockConsole), INPUT_BUFFER)
25 #define ConSrvReleaseInputBuffer(Buff, IsConsoleLocked) \
26 ConSrvReleaseObject(&(Buff)->Header, (IsConsoleLocked))
27
28
29 typedef struct _GET_INPUT_INFO
30 {
31 PCSR_THREAD CallingThread; // The thread which called the input API.
32 PVOID HandleEntry; // The handle data associated with the wait thread.
33 PCONSOLE_INPUT_BUFFER InputBuffer; // The input buffer corresponding to the handle.
34 } GET_INPUT_INFO, *PGET_INPUT_INFO;
35
36
37 /* PRIVATE FUNCTIONS **********************************************************/
38
39 /*
40 * This pre-processing code MUST be IN consrv ONLY
41 */
42 /* static */ ULONG
43 PreprocessInput(PCONSRV_CONSOLE Console,
44 PINPUT_RECORD InputEvent,
45 ULONG NumEventsToWrite)
46 {
47 ULONG NumEvents;
48
49 /*
50 * Loop each event, and for each, check for pause or unpause
51 * and perform adequate behaviour.
52 */
53 for (NumEvents = NumEventsToWrite; NumEvents > 0; --NumEvents)
54 {
55 /* Check for pause or unpause */
56 if (InputEvent->EventType == KEY_EVENT && InputEvent->Event.KeyEvent.bKeyDown)
57 {
58 WORD vk = InputEvent->Event.KeyEvent.wVirtualKeyCode;
59 if (!(Console->PauseFlags & PAUSED_FROM_KEYBOARD))
60 {
61 DWORD cks = InputEvent->Event.KeyEvent.dwControlKeyState;
62 if (Console->InputBuffer.Mode & ENABLE_LINE_INPUT &&
63 (vk == VK_PAUSE ||
64 (vk == 'S' && (cks & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) &&
65 !(cks & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)))))
66 {
67 ConioPause(Console, PAUSED_FROM_KEYBOARD);
68
69 /* Skip the event */
70 RtlMoveMemory(InputEvent,
71 InputEvent + 1,
72 (NumEvents - 1) * sizeof(INPUT_RECORD));
73 --NumEventsToWrite;
74 continue;
75 }
76 }
77 else
78 {
79 if ((vk < VK_SHIFT || vk > VK_CAPITAL) && vk != VK_LWIN &&
80 vk != VK_RWIN && vk != VK_NUMLOCK && vk != VK_SCROLL)
81 {
82 ConioUnpause(Console, PAUSED_FROM_KEYBOARD);
83
84 /* Skip the event */
85 RtlMoveMemory(InputEvent,
86 InputEvent + 1,
87 (NumEvents - 1) * sizeof(INPUT_RECORD));
88 --NumEventsToWrite;
89 continue;
90 }
91 }
92 }
93
94 /* Go to the next event */
95 ++InputEvent;
96 }
97
98 return NumEventsToWrite;
99 }
100
101 /*
102 * This post-processing code MUST be IN consrv ONLY
103 */
104 /* static */ VOID
105 PostprocessInput(PCONSRV_CONSOLE Console)
106 {
107 CsrNotifyWait(&Console->ReadWaitQueue,
108 FALSE,
109 NULL,
110 NULL);
111 if (!IsListEmpty(&Console->ReadWaitQueue))
112 {
113 CsrDereferenceWait(&Console->ReadWaitQueue);
114 }
115 }
116
117
118
119
120
121 static NTSTATUS
122 WaitBeforeReading(IN PGET_INPUT_INFO InputInfo,
123 IN PCSR_API_MESSAGE ApiMessage,
124 IN CSR_WAIT_FUNCTION WaitFunction OPTIONAL,
125 IN BOOLEAN CreateWaitBlock OPTIONAL)
126 {
127 if (CreateWaitBlock)
128 {
129 PGET_INPUT_INFO CapturedInputInfo;
130
131 CapturedInputInfo = ConsoleAllocHeap(0, sizeof(GET_INPUT_INFO));
132 if (!CapturedInputInfo) return STATUS_NO_MEMORY;
133
134 RtlMoveMemory(CapturedInputInfo, InputInfo, sizeof(GET_INPUT_INFO));
135
136 if (!CsrCreateWait(&InputInfo->InputBuffer->Header.Console->ReadWaitQueue,
137 WaitFunction,
138 InputInfo->CallingThread,
139 ApiMessage,
140 CapturedInputInfo))
141 {
142 ConsoleFreeHeap(CapturedInputInfo);
143 return STATUS_NO_MEMORY;
144 }
145 }
146
147 /* Wait for input */
148 return STATUS_PENDING;
149 }
150
151 static NTSTATUS
152 ReadChars(IN PGET_INPUT_INFO InputInfo,
153 IN PCSR_API_MESSAGE ApiMessage,
154 IN BOOLEAN CreateWaitBlock OPTIONAL);
155
156 // Wait function CSR_WAIT_FUNCTION
157 static BOOLEAN
158 NTAPI
159 ReadCharsThread(IN PLIST_ENTRY WaitList,
160 IN PCSR_THREAD WaitThread,
161 IN PCSR_API_MESSAGE WaitApiMessage,
162 IN PVOID WaitContext,
163 IN PVOID WaitArgument1,
164 IN PVOID WaitArgument2,
165 IN ULONG WaitFlags)
166 {
167 NTSTATUS Status;
168 PGET_INPUT_INFO InputInfo = (PGET_INPUT_INFO)WaitContext;
169
170 PVOID InputHandle = WaitArgument2;
171
172 DPRINT("ReadCharsThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags);
173
174 /*
175 * If we are notified of the process termination via a call
176 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
177 * CsrDestroyThread, just return.
178 */
179 if (WaitFlags & CsrProcessTerminating)
180 {
181 Status = STATUS_THREAD_IS_TERMINATING;
182 goto Quit;
183 }
184
185 /*
186 * Somebody is closing a handle to this input buffer,
187 * by calling ConSrvCloseHandleEntry.
188 * See whether we are linked to that handle (ie. we
189 * are a waiter for this handle), and if so, return.
190 * Otherwise, ignore the call and continue waiting.
191 */
192 if (InputHandle != NULL)
193 {
194 Status = (InputHandle == InputInfo->HandleEntry ? STATUS_ALERTED
195 : STATUS_PENDING);
196 goto Quit;
197 }
198
199 /*
200 * If we go there, that means we are notified for some new input.
201 * The console is therefore already locked.
202 */
203 Status = ReadChars(InputInfo, WaitApiMessage, FALSE);
204
205 Quit:
206 if (Status != STATUS_PENDING)
207 {
208 WaitApiMessage->Status = Status;
209 ConsoleFreeHeap(InputInfo);
210 }
211
212 return (Status == STATUS_PENDING ? FALSE : TRUE);
213 }
214
215 NTSTATUS NTAPI
216 ConDrvReadConsole(IN PCONSOLE Console,
217 IN PCONSOLE_INPUT_BUFFER InputBuffer,
218 /**/IN PUNICODE_STRING ExeName /**/OPTIONAL/**/,/**/
219 IN BOOLEAN Unicode,
220 OUT PVOID Buffer,
221 IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl,
222 IN ULONG NumCharsToRead,
223 OUT PULONG NumCharsRead OPTIONAL);
224 static NTSTATUS
225 ReadChars(IN PGET_INPUT_INFO InputInfo,
226 IN PCSR_API_MESSAGE ApiMessage,
227 IN BOOLEAN CreateWaitBlock OPTIONAL)
228 {
229 NTSTATUS Status;
230 PCONSOLE_READCONSOLE ReadConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleRequest;
231 PCONSOLE_INPUT_BUFFER InputBuffer = InputInfo->InputBuffer;
232 CONSOLE_READCONSOLE_CONTROL ReadControl;
233
234 UNICODE_STRING ExeName;
235
236 PVOID Buffer;
237 ULONG NrCharactersRead = 0;
238 ULONG CharSize = (ReadConsoleRequest->Unicode ? sizeof(WCHAR) : sizeof(CHAR));
239
240 /* Compute the executable name, if needed */
241 if (ReadConsoleRequest->InitialNumBytes == 0 &&
242 ReadConsoleRequest->ExeLength <= sizeof(ReadConsoleRequest->StaticBuffer))
243 {
244 ExeName.Length = ExeName.MaximumLength = ReadConsoleRequest->ExeLength;
245 ExeName.Buffer = (PWCHAR)ReadConsoleRequest->StaticBuffer;
246 }
247 else
248 {
249 ExeName.Length = ExeName.MaximumLength = 0;
250 ExeName.Buffer = NULL;
251 }
252
253 /* Build the ReadControl structure */
254 ReadControl.nLength = sizeof(CONSOLE_READCONSOLE_CONTROL);
255 ReadControl.nInitialChars = ReadConsoleRequest->InitialNumBytes / CharSize;
256 ReadControl.dwCtrlWakeupMask = ReadConsoleRequest->CtrlWakeupMask;
257 ReadControl.dwControlKeyState = ReadConsoleRequest->ControlKeyState;
258
259 /*
260 * For optimization purposes, Windows (and hence ReactOS, too, for
261 * compatibility reasons) uses a static buffer if no more than eighty
262 * bytes are read. Otherwise a new buffer is used.
263 * The client-side expects that we know this behaviour.
264 */
265 if (ReadConsoleRequest->CaptureBufferSize <= sizeof(ReadConsoleRequest->StaticBuffer))
266 {
267 /*
268 * Adjust the internal pointer, because its old value points to
269 * the static buffer in the original ApiMessage structure.
270 */
271 // ReadConsoleRequest->Buffer = ReadConsoleRequest->StaticBuffer;
272 Buffer = ReadConsoleRequest->StaticBuffer;
273 }
274 else
275 {
276 Buffer = ReadConsoleRequest->Buffer;
277 }
278
279 DPRINT1("Calling ConDrvReadConsole(%wZ)\n", &ExeName);
280 Status = ConDrvReadConsole(InputBuffer->Header.Console,
281 InputBuffer,
282 &ExeName,
283 ReadConsoleRequest->Unicode,
284 Buffer,
285 &ReadControl,
286 ReadConsoleRequest->NumBytes / CharSize, // NrCharactersToRead
287 &NrCharactersRead);
288 DPRINT1("ConDrvReadConsole returned (%d ; Status = 0x%08x)\n",
289 NrCharactersRead, Status);
290
291 // ReadConsoleRequest->ControlKeyState = ReadControl.dwControlKeyState;
292
293 if (Status == STATUS_PENDING)
294 {
295 /* We haven't completed a read, so start a wait */
296 return WaitBeforeReading(InputInfo,
297 ApiMessage,
298 ReadCharsThread,
299 CreateWaitBlock);
300 }
301 else
302 {
303 /*
304 * We read all what we wanted. Set the number of bytes read and
305 * return the error code we were given.
306 */
307 ReadConsoleRequest->NumBytes = NrCharactersRead * CharSize;
308 ReadConsoleRequest->ControlKeyState = ReadControl.dwControlKeyState;
309
310 return Status;
311 // return STATUS_SUCCESS;
312 }
313 }
314
315 static NTSTATUS
316 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo,
317 IN PCSR_API_MESSAGE ApiMessage,
318 IN BOOLEAN CreateWaitBlock OPTIONAL);
319
320 // Wait function CSR_WAIT_FUNCTION
321 static BOOLEAN
322 NTAPI
323 ReadInputBufferThread(IN PLIST_ENTRY WaitList,
324 IN PCSR_THREAD WaitThread,
325 IN PCSR_API_MESSAGE WaitApiMessage,
326 IN PVOID WaitContext,
327 IN PVOID WaitArgument1,
328 IN PVOID WaitArgument2,
329 IN ULONG WaitFlags)
330 {
331 NTSTATUS Status;
332 PGET_INPUT_INFO InputInfo = (PGET_INPUT_INFO)WaitContext;
333
334 PVOID InputHandle = WaitArgument2;
335
336 DPRINT("ReadInputBufferThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags);
337
338 /*
339 * If we are notified of the process termination via a call
340 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
341 * CsrDestroyThread, just return.
342 */
343 if (WaitFlags & CsrProcessTerminating)
344 {
345 Status = STATUS_THREAD_IS_TERMINATING;
346 goto Quit;
347 }
348
349 /*
350 * Somebody is closing a handle to this input buffer,
351 * by calling ConSrvCloseHandleEntry.
352 * See whether we are linked to that handle (ie. we
353 * are a waiter for this handle), and if so, return.
354 * Otherwise, ignore the call and continue waiting.
355 */
356 if (InputHandle != NULL)
357 {
358 Status = (InputHandle == InputInfo->HandleEntry ? STATUS_ALERTED
359 : STATUS_PENDING);
360 goto Quit;
361 }
362
363 /*
364 * If we go there, that means we are notified for some new input.
365 * The console is therefore already locked.
366 */
367 Status = ReadInputBuffer(InputInfo, WaitApiMessage, FALSE);
368
369 Quit:
370 if (Status != STATUS_PENDING)
371 {
372 WaitApiMessage->Status = Status;
373 ConsoleFreeHeap(InputInfo);
374 }
375
376 return (Status == STATUS_PENDING ? FALSE : TRUE);
377 }
378
379 NTSTATUS NTAPI
380 ConDrvGetConsoleInput(IN PCONSOLE Console,
381 IN PCONSOLE_INPUT_BUFFER InputBuffer,
382 IN BOOLEAN KeepEvents,
383 IN BOOLEAN WaitForMoreEvents,
384 IN BOOLEAN Unicode,
385 OUT PINPUT_RECORD InputRecord,
386 IN ULONG NumEventsToRead,
387 OUT PULONG NumEventsRead OPTIONAL);
388 static NTSTATUS
389 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo,
390 IN PCSR_API_MESSAGE ApiMessage,
391 IN BOOLEAN CreateWaitBlock OPTIONAL)
392 {
393 NTSTATUS Status;
394 PCONSOLE_GETINPUT GetInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetInputRequest;
395 PCONSOLE_INPUT_BUFFER InputBuffer = InputInfo->InputBuffer;
396 ULONG NumEventsRead;
397
398 PINPUT_RECORD InputRecord;
399
400 /*
401 * For optimization purposes, Windows (and hence ReactOS, too, for
402 * compatibility reasons) uses a static buffer if no more than five
403 * input records are read. Otherwise a new buffer is used.
404 * The client-side expects that we know this behaviour.
405 */
406 if (GetInputRequest->NumRecords <= sizeof(GetInputRequest->RecordStaticBuffer)/sizeof(INPUT_RECORD))
407 {
408 /*
409 * Adjust the internal pointer, because its old value points to
410 * the static buffer in the original ApiMessage structure.
411 */
412 // GetInputRequest->RecordBufPtr = GetInputRequest->RecordStaticBuffer;
413 InputRecord = GetInputRequest->RecordStaticBuffer;
414 }
415 else
416 {
417 InputRecord = GetInputRequest->RecordBufPtr;
418 }
419
420 NumEventsRead = 0;
421 Status = ConDrvGetConsoleInput(InputBuffer->Header.Console,
422 InputBuffer,
423 (GetInputRequest->Flags & CONSOLE_READ_KEEPEVENT) != 0,
424 (GetInputRequest->Flags & CONSOLE_READ_CONTINUE ) == 0,
425 GetInputRequest->Unicode,
426 InputRecord,
427 GetInputRequest->NumRecords,
428 &NumEventsRead);
429
430 if (Status == STATUS_PENDING)
431 {
432 /* We haven't completed a read, so start a wait */
433 return WaitBeforeReading(InputInfo,
434 ApiMessage,
435 ReadInputBufferThread,
436 CreateWaitBlock);
437 }
438 else
439 {
440 /*
441 * We read all what we wanted. Set the number of events read and
442 * return the error code we were given.
443 */
444 GetInputRequest->NumRecords = NumEventsRead;
445
446 return Status;
447 // return STATUS_SUCCESS;
448 }
449 }
450
451
452 /* PUBLIC SERVER APIS *********************************************************/
453
454 CSR_API(SrvReadConsole)
455 {
456 NTSTATUS Status;
457 PCONSOLE_READCONSOLE ReadConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleRequest;
458 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
459 PVOID HandleEntry;
460 PCONSOLE_INPUT_BUFFER InputBuffer;
461 GET_INPUT_INFO InputInfo;
462
463 DPRINT("SrvReadConsole\n");
464
465 /*
466 * For optimization purposes, Windows (and hence ReactOS, too, for
467 * compatibility reasons) uses a static buffer if no more than eighty
468 * bytes are read. Otherwise a new buffer is used.
469 * The client-side expects that we know this behaviour.
470 */
471 if (ReadConsoleRequest->CaptureBufferSize <= sizeof(ReadConsoleRequest->StaticBuffer))
472 {
473 /*
474 * Adjust the internal pointer, because its old value points to
475 * the static buffer in the original ApiMessage structure.
476 */
477 // ReadConsoleRequest->Buffer = ReadConsoleRequest->StaticBuffer;
478 }
479 else
480 {
481 if (!CsrValidateMessageBuffer(ApiMessage,
482 (PVOID*)&ReadConsoleRequest->Buffer,
483 ReadConsoleRequest->CaptureBufferSize,
484 sizeof(BYTE)))
485 {
486 return STATUS_INVALID_PARAMETER;
487 }
488 }
489
490 if (ReadConsoleRequest->InitialNumBytes > ReadConsoleRequest->NumBytes)
491 {
492 return STATUS_INVALID_PARAMETER;
493 }
494
495 Status = ConSrvGetInputBufferAndHandleEntry(ProcessData, ReadConsoleRequest->InputHandle, &InputBuffer, &HandleEntry, GENERIC_READ, TRUE);
496 if (!NT_SUCCESS(Status)) return Status;
497
498 InputInfo.CallingThread = CsrGetClientThread();
499 InputInfo.HandleEntry = HandleEntry;
500 InputInfo.InputBuffer = InputBuffer;
501
502 Status = ReadChars(&InputInfo, ApiMessage, TRUE);
503
504 ConSrvReleaseInputBuffer(InputBuffer, TRUE);
505
506 if (Status == STATUS_PENDING) *ReplyCode = CsrReplyPending;
507
508 return Status;
509 }
510
511 CSR_API(SrvGetConsoleInput)
512 {
513 NTSTATUS Status;
514 PCONSOLE_GETINPUT GetInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetInputRequest;
515 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
516 PVOID HandleEntry;
517 PCONSOLE_INPUT_BUFFER InputBuffer;
518 GET_INPUT_INFO InputInfo;
519
520 DPRINT("SrvGetConsoleInput\n");
521
522 if (GetInputRequest->Flags & ~(CONSOLE_READ_KEEPEVENT | CONSOLE_READ_CONTINUE))
523 return STATUS_INVALID_PARAMETER;
524
525 /*
526 * For optimization purposes, Windows (and hence ReactOS, too, for
527 * compatibility reasons) uses a static buffer if no more than five
528 * input records are read. Otherwise a new buffer is used.
529 * The client-side expects that we know this behaviour.
530 */
531 if (GetInputRequest->NumRecords <= sizeof(GetInputRequest->RecordStaticBuffer)/sizeof(INPUT_RECORD))
532 {
533 /*
534 * Adjust the internal pointer, because its old value points to
535 * the static buffer in the original ApiMessage structure.
536 */
537 // GetInputRequest->RecordBufPtr = GetInputRequest->RecordStaticBuffer;
538 }
539 else
540 {
541 if (!CsrValidateMessageBuffer(ApiMessage,
542 (PVOID*)&GetInputRequest->RecordBufPtr,
543 GetInputRequest->NumRecords,
544 sizeof(INPUT_RECORD)))
545 {
546 return STATUS_INVALID_PARAMETER;
547 }
548 }
549
550 Status = ConSrvGetInputBufferAndHandleEntry(ProcessData, GetInputRequest->InputHandle, &InputBuffer, &HandleEntry, GENERIC_READ, TRUE);
551 if (!NT_SUCCESS(Status)) return Status;
552
553 InputInfo.CallingThread = CsrGetClientThread();
554 InputInfo.HandleEntry = HandleEntry;
555 InputInfo.InputBuffer = InputBuffer;
556
557 Status = ReadInputBuffer(&InputInfo, ApiMessage, TRUE);
558
559 ConSrvReleaseInputBuffer(InputBuffer, TRUE);
560
561 if (Status == STATUS_PENDING) *ReplyCode = CsrReplyPending;
562
563 return Status;
564 }
565
566 NTSTATUS NTAPI
567 ConDrvWriteConsoleInput(IN PCONSOLE Console,
568 IN PCONSOLE_INPUT_BUFFER InputBuffer,
569 IN BOOLEAN Unicode,
570 IN BOOLEAN AppendToEnd,
571 IN PINPUT_RECORD InputRecord,
572 IN ULONG NumEventsToWrite,
573 OUT PULONG NumEventsWritten OPTIONAL);
574 CSR_API(SrvWriteConsoleInput)
575 {
576 NTSTATUS Status;
577 PCONSOLE_WRITEINPUT WriteInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteInputRequest;
578 PCONSOLE_INPUT_BUFFER InputBuffer;
579 ULONG NumEventsWritten;
580
581 PINPUT_RECORD InputRecord;
582
583 DPRINT("SrvWriteConsoleInput\n");
584
585 /*
586 * For optimization purposes, Windows (and hence ReactOS, too, for
587 * compatibility reasons) uses a static buffer if no more than five
588 * input records are written. Otherwise a new buffer is used.
589 * The client-side expects that we know this behaviour.
590 */
591 if (WriteInputRequest->NumRecords <= sizeof(WriteInputRequest->RecordStaticBuffer)/sizeof(INPUT_RECORD))
592 {
593 /*
594 * Adjust the internal pointer, because its old value points to
595 * the static buffer in the original ApiMessage structure.
596 */
597 // WriteInputRequest->RecordBufPtr = WriteInputRequest->RecordStaticBuffer;
598 InputRecord = WriteInputRequest->RecordStaticBuffer;
599 }
600 else
601 {
602 if (!CsrValidateMessageBuffer(ApiMessage,
603 (PVOID*)&WriteInputRequest->RecordBufPtr,
604 WriteInputRequest->NumRecords,
605 sizeof(INPUT_RECORD)))
606 {
607 return STATUS_INVALID_PARAMETER;
608 }
609
610 InputRecord = WriteInputRequest->RecordBufPtr;
611 }
612
613 Status = ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
614 WriteInputRequest->InputHandle,
615 &InputBuffer, GENERIC_WRITE, TRUE);
616 if (!NT_SUCCESS(Status))
617 {
618 WriteInputRequest->NumRecords = 0;
619 return Status;
620 }
621
622 NumEventsWritten = 0;
623 Status = ConDrvWriteConsoleInput(InputBuffer->Header.Console,
624 InputBuffer,
625 WriteInputRequest->Unicode,
626 WriteInputRequest->AppendToEnd,
627 InputRecord,
628 WriteInputRequest->NumRecords,
629 &NumEventsWritten);
630 WriteInputRequest->NumRecords = NumEventsWritten;
631
632 ConSrvReleaseInputBuffer(InputBuffer, TRUE);
633 return Status;
634 }
635
636 NTSTATUS NTAPI
637 ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console,
638 IN PCONSOLE_INPUT_BUFFER InputBuffer);
639 CSR_API(SrvFlushConsoleInputBuffer)
640 {
641 NTSTATUS Status;
642 PCONSOLE_FLUSHINPUTBUFFER FlushInputBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FlushInputBufferRequest;
643 PCONSOLE_INPUT_BUFFER InputBuffer;
644
645 DPRINT("SrvFlushConsoleInputBuffer\n");
646
647 Status = ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
648 FlushInputBufferRequest->InputHandle,
649 &InputBuffer, GENERIC_WRITE, TRUE);
650 if (!NT_SUCCESS(Status)) return Status;
651
652 Status = ConDrvFlushConsoleInputBuffer(InputBuffer->Header.Console,
653 InputBuffer);
654
655 ConSrvReleaseInputBuffer(InputBuffer, TRUE);
656 return Status;
657 }
658
659 NTSTATUS NTAPI
660 ConDrvGetConsoleNumberOfInputEvents(IN PCONSOLE Console,
661 IN PCONSOLE_INPUT_BUFFER InputBuffer,
662 OUT PULONG NumberOfEvents);
663 CSR_API(SrvGetConsoleNumberOfInputEvents)
664 {
665 NTSTATUS Status;
666 PCONSOLE_GETNUMINPUTEVENTS GetNumInputEventsRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetNumInputEventsRequest;
667 PCONSOLE_INPUT_BUFFER InputBuffer;
668
669 DPRINT("SrvGetConsoleNumberOfInputEvents\n");
670
671 Status = ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
672 GetNumInputEventsRequest->InputHandle,
673 &InputBuffer, GENERIC_READ, TRUE);
674 if (!NT_SUCCESS(Status)) return Status;
675
676 Status = ConDrvGetConsoleNumberOfInputEvents(InputBuffer->Header.Console,
677 InputBuffer,
678 &GetNumInputEventsRequest->NumberOfEvents);
679
680 ConSrvReleaseInputBuffer(InputBuffer, TRUE);
681 return Status;
682 }
683
684 /* EOF */