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)
10 /* INCLUDES *******************************************************************/
17 /* GLOBALS ********************************************************************/
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))
29 typedef struct _GET_INPUT_INFO
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
;
37 /* PRIVATE FUNCTIONS **********************************************************/
40 * This pre-processing code MUST be IN consrv ONLY
43 PreprocessInput(PCONSOLE Console
,
44 PINPUT_RECORD InputEvent
,
45 ULONG NumEventsToWrite
)
50 * Loop each event, and for each, check for pause or unpause
51 * and perform adequate behaviour.
53 for (NumEvents
= NumEventsToWrite
; NumEvents
> 0; --NumEvents
)
55 /* Check for pause or unpause */
56 if (InputEvent
->EventType
== KEY_EVENT
&& InputEvent
->Event
.KeyEvent
.bKeyDown
)
58 WORD vk
= InputEvent
->Event
.KeyEvent
.wVirtualKeyCode
;
59 if (!(Console
->PauseFlags
& PAUSED_FROM_KEYBOARD
))
61 DWORD cks
= InputEvent
->Event
.KeyEvent
.dwControlKeyState
;
62 if (Console
->InputBuffer
.Mode
& ENABLE_LINE_INPUT
&&
64 (vk
== 'S' && (cks
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
)) &&
65 !(cks
& (LEFT_ALT_PRESSED
| RIGHT_ALT_PRESSED
)))))
67 ConioPause(Console
, PAUSED_FROM_KEYBOARD
);
70 RtlMoveMemory(InputEvent
,
72 (NumEvents
- 1) * sizeof(INPUT_RECORD
));
79 if ((vk
< VK_SHIFT
|| vk
> VK_CAPITAL
) && vk
!= VK_LWIN
&&
80 vk
!= VK_RWIN
&& vk
!= VK_NUMLOCK
&& vk
!= VK_SCROLL
)
82 ConioUnpause(Console
, PAUSED_FROM_KEYBOARD
);
85 RtlMoveMemory(InputEvent
,
87 (NumEvents
- 1) * sizeof(INPUT_RECORD
));
94 /* Go to the next event */
98 return NumEventsToWrite
;
102 * This post-processing code MUST be IN consrv ONLY
105 PostprocessInput(PCONSOLE Console
)
107 CsrNotifyWait(&Console
->ReadWaitQueue
,
111 if (!IsListEmpty(&Console
->ReadWaitQueue
))
113 CsrDereferenceWait(&Console
->ReadWaitQueue
);
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
)
129 PGET_INPUT_INFO CapturedInputInfo
;
131 CapturedInputInfo
= ConsoleAllocHeap(0, sizeof(GET_INPUT_INFO
));
132 if (!CapturedInputInfo
) return STATUS_NO_MEMORY
;
134 RtlMoveMemory(CapturedInputInfo
, InputInfo
, sizeof(GET_INPUT_INFO
));
136 if (!CsrCreateWait(&InputInfo
->InputBuffer
->Header
.Console
->ReadWaitQueue
,
138 InputInfo
->CallingThread
,
142 ConsoleFreeHeap(CapturedInputInfo
);
143 return STATUS_NO_MEMORY
;
148 return STATUS_PENDING
;
152 ReadChars(IN PGET_INPUT_INFO InputInfo
,
153 IN PCSR_API_MESSAGE ApiMessage
,
154 IN BOOLEAN CreateWaitBlock OPTIONAL
);
156 // Wait function CSR_WAIT_FUNCTION
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
,
168 PGET_INPUT_INFO InputInfo
= (PGET_INPUT_INFO
)WaitContext
;
170 PVOID InputHandle
= WaitArgument2
;
172 DPRINT("ReadCharsThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
175 * If we are notified of the process termination via a call
176 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
177 * CsrDestroyThread, just return.
179 if (WaitFlags
& CsrProcessTerminating
)
181 Status
= STATUS_THREAD_IS_TERMINATING
;
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.
192 if (InputHandle
!= NULL
)
194 Status
= (InputHandle
== InputInfo
->HandleEntry
? STATUS_ALERTED
200 * If we go there, that means we are notified for some new input.
201 * The console is therefore already locked.
203 Status
= ReadChars(InputInfo
, WaitApiMessage
, FALSE
);
206 if (Status
!= STATUS_PENDING
)
208 WaitApiMessage
->Status
= Status
;
209 ConsoleFreeHeap(InputInfo
);
212 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
216 ConDrvReadConsole(IN PCONSOLE Console
,
217 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
218 /**/IN PUNICODE_STRING ExeName
/**/OPTIONAL
/**/,/**/
221 IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl
,
222 IN ULONG NumCharsToRead
,
223 OUT PULONG NumCharsRead OPTIONAL
);
225 ReadChars(IN PGET_INPUT_INFO InputInfo
,
226 IN PCSR_API_MESSAGE ApiMessage
,
227 IN BOOLEAN CreateWaitBlock OPTIONAL
)
230 PCONSOLE_READCONSOLE ReadConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadConsoleRequest
;
231 PCONSOLE_INPUT_BUFFER InputBuffer
= InputInfo
->InputBuffer
;
232 CONSOLE_READCONSOLE_CONTROL ReadControl
;
234 UNICODE_STRING ExeName
;
237 ULONG NrCharactersRead
= 0;
238 ULONG CharSize
= (ReadConsoleRequest
->Unicode
? sizeof(WCHAR
) : sizeof(CHAR
));
240 /* Compute the executable name, if needed */
241 if (ReadConsoleRequest
->InitialNumBytes
== 0 &&
242 ReadConsoleRequest
->ExeLength
<= sizeof(ReadConsoleRequest
->StaticBuffer
))
244 ExeName
.Length
= ExeName
.MaximumLength
= ReadConsoleRequest
->ExeLength
;
245 ExeName
.Buffer
= (PWCHAR
)ReadConsoleRequest
->StaticBuffer
;
249 ExeName
.Length
= ExeName
.MaximumLength
= 0;
250 ExeName
.Buffer
= NULL
;
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
;
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.
265 if (ReadConsoleRequest
->CaptureBufferSize
<= sizeof(ReadConsoleRequest
->StaticBuffer
))
268 * Adjust the internal pointer, because its old value points to
269 * the static buffer in the original ApiMessage structure.
271 // ReadConsoleRequest->Buffer = ReadConsoleRequest->StaticBuffer;
272 Buffer
= ReadConsoleRequest
->StaticBuffer
;
276 Buffer
= ReadConsoleRequest
->Buffer
;
279 DPRINT1("Calling ConDrvReadConsole(%wZ)\n", &ExeName
);
280 Status
= ConDrvReadConsole(InputBuffer
->Header
.Console
,
283 ReadConsoleRequest
->Unicode
,
286 ReadConsoleRequest
->NumBytes
/ CharSize
, // NrCharactersToRead
288 DPRINT1("ConDrvReadConsole returned (%d ; Status = 0x%08x)\n",
289 NrCharactersRead
, Status
);
291 // ReadConsoleRequest->ControlKeyState = ReadControl.dwControlKeyState;
293 if (Status
== STATUS_PENDING
)
295 /* We haven't completed a read, so start a wait */
296 return WaitBeforeReading(InputInfo
,
304 * We read all what we wanted. Set the number of bytes read and
305 * return the error code we were given.
307 ReadConsoleRequest
->NumBytes
= NrCharactersRead
* CharSize
;
308 ReadConsoleRequest
->ControlKeyState
= ReadControl
.dwControlKeyState
;
311 // return STATUS_SUCCESS;
316 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo
,
317 IN PCSR_API_MESSAGE ApiMessage
,
318 IN BOOLEAN CreateWaitBlock OPTIONAL
);
320 // Wait function CSR_WAIT_FUNCTION
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
,
332 PGET_INPUT_INFO InputInfo
= (PGET_INPUT_INFO
)WaitContext
;
334 PVOID InputHandle
= WaitArgument2
;
336 DPRINT("ReadInputBufferThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
339 * If we are notified of the process termination via a call
340 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
341 * CsrDestroyThread, just return.
343 if (WaitFlags
& CsrProcessTerminating
)
345 Status
= STATUS_THREAD_IS_TERMINATING
;
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.
356 if (InputHandle
!= NULL
)
358 Status
= (InputHandle
== InputInfo
->HandleEntry
? STATUS_ALERTED
364 * If we go there, that means we are notified for some new input.
365 * The console is therefore already locked.
367 Status
= ReadInputBuffer(InputInfo
, WaitApiMessage
, FALSE
);
370 if (Status
!= STATUS_PENDING
)
372 WaitApiMessage
->Status
= Status
;
373 ConsoleFreeHeap(InputInfo
);
376 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
380 ConDrvGetConsoleInput(IN PCONSOLE Console
,
381 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
382 IN BOOLEAN KeepEvents
,
383 IN BOOLEAN WaitForMoreEvents
,
385 OUT PINPUT_RECORD InputRecord
,
386 IN ULONG NumEventsToRead
,
387 OUT PULONG NumEventsRead OPTIONAL
);
389 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo
,
390 IN PCSR_API_MESSAGE ApiMessage
,
391 IN BOOLEAN CreateWaitBlock OPTIONAL
)
394 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetInputRequest
;
395 PCONSOLE_INPUT_BUFFER InputBuffer
= InputInfo
->InputBuffer
;
398 PINPUT_RECORD InputRecord
;
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.
406 if (GetInputRequest
->NumRecords
<= sizeof(GetInputRequest
->RecordStaticBuffer
)/sizeof(INPUT_RECORD
))
409 * Adjust the internal pointer, because its old value points to
410 * the static buffer in the original ApiMessage structure.
412 // GetInputRequest->RecordBufPtr = GetInputRequest->RecordStaticBuffer;
413 InputRecord
= GetInputRequest
->RecordStaticBuffer
;
417 InputRecord
= GetInputRequest
->RecordBufPtr
;
421 Status
= ConDrvGetConsoleInput(InputBuffer
->Header
.Console
,
423 (GetInputRequest
->Flags
& CONSOLE_READ_KEEPEVENT
) != 0,
424 (GetInputRequest
->Flags
& CONSOLE_READ_CONTINUE
) == 0,
425 GetInputRequest
->Unicode
,
427 GetInputRequest
->NumRecords
,
430 if (Status
== STATUS_PENDING
)
432 /* We haven't completed a read, so start a wait */
433 return WaitBeforeReading(InputInfo
,
435 ReadInputBufferThread
,
441 * We read all what we wanted. Set the number of events read and
442 * return the error code we were given.
444 GetInputRequest
->NumRecords
= NumEventsRead
;
447 // return STATUS_SUCCESS;
452 /* PUBLIC SERVER APIS *********************************************************/
454 CSR_API(SrvReadConsole
)
457 PCONSOLE_READCONSOLE ReadConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadConsoleRequest
;
458 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
460 PCONSOLE_INPUT_BUFFER InputBuffer
;
461 GET_INPUT_INFO InputInfo
;
463 DPRINT("SrvReadConsole\n");
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.
471 if (ReadConsoleRequest
->CaptureBufferSize
<= sizeof(ReadConsoleRequest
->StaticBuffer
))
474 * Adjust the internal pointer, because its old value points to
475 * the static buffer in the original ApiMessage structure.
477 // ReadConsoleRequest->Buffer = ReadConsoleRequest->StaticBuffer;
481 if (!CsrValidateMessageBuffer(ApiMessage
,
482 (PVOID
*)&ReadConsoleRequest
->Buffer
,
483 ReadConsoleRequest
->CaptureBufferSize
,
486 return STATUS_INVALID_PARAMETER
;
490 if (ReadConsoleRequest
->InitialNumBytes
> ReadConsoleRequest
->NumBytes
)
492 return STATUS_INVALID_PARAMETER
;
495 Status
= ConSrvGetInputBufferAndHandleEntry(ProcessData
, ReadConsoleRequest
->InputHandle
, &InputBuffer
, &HandleEntry
, GENERIC_READ
, TRUE
);
496 if (!NT_SUCCESS(Status
)) return Status
;
498 InputInfo
.CallingThread
= CsrGetClientThread();
499 InputInfo
.HandleEntry
= HandleEntry
;
500 InputInfo
.InputBuffer
= InputBuffer
;
502 Status
= ReadChars(&InputInfo
, ApiMessage
, TRUE
);
504 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
506 if (Status
== STATUS_PENDING
) *ReplyCode
= CsrReplyPending
;
511 CSR_API(SrvGetConsoleInput
)
514 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetInputRequest
;
515 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
517 PCONSOLE_INPUT_BUFFER InputBuffer
;
518 GET_INPUT_INFO InputInfo
;
520 DPRINT("SrvGetConsoleInput\n");
522 if (GetInputRequest
->Flags
& ~(CONSOLE_READ_KEEPEVENT
| CONSOLE_READ_CONTINUE
))
523 return STATUS_INVALID_PARAMETER
;
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.
531 if (GetInputRequest
->NumRecords
<= sizeof(GetInputRequest
->RecordStaticBuffer
)/sizeof(INPUT_RECORD
))
534 * Adjust the internal pointer, because its old value points to
535 * the static buffer in the original ApiMessage structure.
537 // GetInputRequest->RecordBufPtr = GetInputRequest->RecordStaticBuffer;
541 if (!CsrValidateMessageBuffer(ApiMessage
,
542 (PVOID
*)&GetInputRequest
->RecordBufPtr
,
543 GetInputRequest
->NumRecords
,
544 sizeof(INPUT_RECORD
)))
546 return STATUS_INVALID_PARAMETER
;
550 Status
= ConSrvGetInputBufferAndHandleEntry(ProcessData
, GetInputRequest
->InputHandle
, &InputBuffer
, &HandleEntry
, GENERIC_READ
, TRUE
);
551 if (!NT_SUCCESS(Status
)) return Status
;
553 InputInfo
.CallingThread
= CsrGetClientThread();
554 InputInfo
.HandleEntry
= HandleEntry
;
555 InputInfo
.InputBuffer
= InputBuffer
;
557 Status
= ReadInputBuffer(&InputInfo
, ApiMessage
, TRUE
);
559 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
561 if (Status
== STATUS_PENDING
) *ReplyCode
= CsrReplyPending
;
567 ConDrvWriteConsoleInput(IN PCONSOLE Console
,
568 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
570 IN BOOLEAN AppendToEnd
,
571 IN PINPUT_RECORD InputRecord
,
572 IN ULONG NumEventsToWrite
,
573 OUT PULONG NumEventsWritten OPTIONAL
);
574 CSR_API(SrvWriteConsoleInput
)
577 PCONSOLE_WRITEINPUT WriteInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.WriteInputRequest
;
578 PCONSOLE_INPUT_BUFFER InputBuffer
;
579 ULONG NumEventsWritten
;
581 PINPUT_RECORD InputRecord
;
583 DPRINT("SrvWriteConsoleInput\n");
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.
591 if (WriteInputRequest
->NumRecords
<= sizeof(WriteInputRequest
->RecordStaticBuffer
)/sizeof(INPUT_RECORD
))
594 * Adjust the internal pointer, because its old value points to
595 * the static buffer in the original ApiMessage structure.
597 // WriteInputRequest->RecordBufPtr = WriteInputRequest->RecordStaticBuffer;
598 InputRecord
= WriteInputRequest
->RecordStaticBuffer
;
602 if (!CsrValidateMessageBuffer(ApiMessage
,
603 (PVOID
*)&WriteInputRequest
->RecordBufPtr
,
604 WriteInputRequest
->NumRecords
,
605 sizeof(INPUT_RECORD
)))
607 return STATUS_INVALID_PARAMETER
;
610 InputRecord
= WriteInputRequest
->RecordBufPtr
;
613 Status
= ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
614 WriteInputRequest
->InputHandle
,
615 &InputBuffer
, GENERIC_WRITE
, TRUE
);
616 if (!NT_SUCCESS(Status
))
618 WriteInputRequest
->NumRecords
= 0;
622 NumEventsWritten
= 0;
623 Status
= ConDrvWriteConsoleInput(InputBuffer
->Header
.Console
,
625 WriteInputRequest
->Unicode
,
626 WriteInputRequest
->AppendToEnd
,
628 WriteInputRequest
->NumRecords
,
630 WriteInputRequest
->NumRecords
= NumEventsWritten
;
632 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
637 ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console
,
638 IN PCONSOLE_INPUT_BUFFER InputBuffer
);
639 CSR_API(SrvFlushConsoleInputBuffer
)
642 PCONSOLE_FLUSHINPUTBUFFER FlushInputBufferRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.FlushInputBufferRequest
;
643 PCONSOLE_INPUT_BUFFER InputBuffer
;
645 DPRINT("SrvFlushConsoleInputBuffer\n");
647 Status
= ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
648 FlushInputBufferRequest
->InputHandle
,
649 &InputBuffer
, GENERIC_WRITE
, TRUE
);
650 if (!NT_SUCCESS(Status
)) return Status
;
652 Status
= ConDrvFlushConsoleInputBuffer(InputBuffer
->Header
.Console
,
655 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
660 ConDrvGetConsoleNumberOfInputEvents(IN PCONSOLE Console
,
661 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
662 OUT PULONG NumberOfEvents
);
663 CSR_API(SrvGetConsoleNumberOfInputEvents
)
666 PCONSOLE_GETNUMINPUTEVENTS GetNumInputEventsRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetNumInputEventsRequest
;
667 PCONSOLE_INPUT_BUFFER InputBuffer
;
669 DPRINT("SrvGetConsoleNumberOfInputEvents\n");
671 Status
= ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
672 GetNumInputEventsRequest
->InputHandle
,
673 &InputBuffer
, GENERIC_READ
, TRUE
);
674 if (!NT_SUCCESS(Status
)) return Status
;
676 Status
= ConDrvGetConsoleNumberOfInputEvents(InputBuffer
->Header
.Console
,
678 &GetNumInputEventsRequest
->NumberOfEvents
);
680 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);