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)
23 #define ConSrvGetInputBufferAndHandleEntry(ProcessData, Handle, Ptr, Entry, Access, LockConsole) \
24 ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), (Entry), \
25 (Access), (LockConsole), INPUT_BUFFER)
27 #define ConSrvReleaseInputBuffer(Buff, IsConsoleLocked) \
28 ConSrvReleaseObject(&(Buff)->Header, (IsConsoleLocked))
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."
37 #define ConsoleInputUnicodeToAnsiChar(Console, dChar, sWChar) \
39 ASSERT((ULONG_PTR)(dChar) != (ULONG_PTR)(sWChar)); \
40 WideCharToMultiByte((Console)->InputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL); \
43 #define ConsoleInputAnsiToUnicodeChar(Console, dWChar, sChar) \
45 ASSERT((ULONG_PTR)(dWChar) != (ULONG_PTR)(sChar)); \
46 MultiByteToWideChar((Console)->InputCodePage, 0, (sChar), 1, (dWChar), 1); \
50 typedef struct _GET_INPUT_INFO
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.
55 } GET_INPUT_INFO
, *PGET_INPUT_INFO
;
58 /* PRIVATE FUNCTIONS **********************************************************/
61 ConioInputEventToAnsi(PCONSOLE Console
, PINPUT_RECORD InputEvent
)
63 if (InputEvent
->EventType
== KEY_EVENT
)
65 WCHAR UnicodeChar
= InputEvent
->Event
.KeyEvent
.uChar
.UnicodeChar
;
66 InputEvent
->Event
.KeyEvent
.uChar
.UnicodeChar
= 0;
67 ConsoleInputUnicodeToAnsiChar(Console
,
68 &InputEvent
->Event
.KeyEvent
.uChar
.AsciiChar
,
74 ConioInputEventToUnicode(PCONSOLE Console
, PINPUT_RECORD InputEvent
)
76 if (InputEvent
->EventType
== KEY_EVENT
)
78 CHAR AsciiChar
= InputEvent
->Event
.KeyEvent
.uChar
.AsciiChar
;
79 InputEvent
->Event
.KeyEvent
.uChar
.AsciiChar
= 0;
80 ConsoleInputAnsiToUnicodeChar(Console
,
81 &InputEvent
->Event
.KeyEvent
.uChar
.UnicodeChar
,
87 PreprocessInput(PCONSRV_CONSOLE Console
,
88 PINPUT_RECORD InputEvent
,
89 ULONG NumEventsToWrite
)
94 * Loop each event, and for each, check for pause or unpause
95 * and perform adequate behaviour.
97 for (NumEvents
= NumEventsToWrite
; NumEvents
> 0; --NumEvents
)
99 /* Check for pause or unpause */
100 if (InputEvent
->EventType
== KEY_EVENT
&& InputEvent
->Event
.KeyEvent
.bKeyDown
)
102 WORD vk
= InputEvent
->Event
.KeyEvent
.wVirtualKeyCode
;
103 if (!(Console
->PauseFlags
& PAUSED_FROM_KEYBOARD
))
105 DWORD cks
= InputEvent
->Event
.KeyEvent
.dwControlKeyState
;
106 if (Console
->InputBuffer
.Mode
& ENABLE_LINE_INPUT
&&
108 (vk
== 'S' && (cks
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
)) &&
109 !(cks
& (LEFT_ALT_PRESSED
| RIGHT_ALT_PRESSED
)))))
111 ConioPause(Console
, PAUSED_FROM_KEYBOARD
);
114 RtlMoveMemory(InputEvent
,
116 (NumEvents
- 1) * sizeof(INPUT_RECORD
));
123 if ((vk
< VK_SHIFT
|| vk
> VK_CAPITAL
) && vk
!= VK_LWIN
&&
124 vk
!= VK_RWIN
&& vk
!= VK_NUMLOCK
&& vk
!= VK_SCROLL
)
126 ConioUnpause(Console
, PAUSED_FROM_KEYBOARD
);
129 RtlMoveMemory(InputEvent
,
131 (NumEvents
- 1) * sizeof(INPUT_RECORD
));
138 /* Go to the next event */
142 return NumEventsToWrite
;
146 PostprocessInput(PCONSRV_CONSOLE Console
)
148 CsrNotifyWait(&Console
->ReadWaitQueue
,
152 if (!IsListEmpty(&Console
->ReadWaitQueue
))
154 CsrDereferenceWait(&Console
->ReadWaitQueue
);
160 ConDrvWriteConsoleInput(IN PCONSOLE Console
,
161 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
162 IN BOOLEAN AppendToEnd
,
163 IN PINPUT_RECORD InputRecord
,
164 IN ULONG NumEventsToWrite
,
165 OUT PULONG NumEventsWritten OPTIONAL
);
167 ConioAddInputEvents(PCONSRV_CONSOLE Console
,
168 PINPUT_RECORD InputRecords
, // InputEvent
169 ULONG NumEventsToWrite
,
170 PULONG NumEventsWritten
,
173 NTSTATUS Status
= STATUS_SUCCESS
;
175 if (NumEventsWritten
) *NumEventsWritten
= 0;
177 NumEventsToWrite
= PreprocessInput(Console
, InputRecords
, NumEventsToWrite
);
178 if (NumEventsToWrite
== 0) return STATUS_SUCCESS
;
180 // Status = ConDrvAddInputEvents(Console,
186 Status
= ConDrvWriteConsoleInput((PCONSOLE
)Console
,
187 &Console
->InputBuffer
,
193 // if (NT_SUCCESS(Status))
194 if (Status
== STATUS_SUCCESS
) PostprocessInput(Console
);
199 /* FIXME: This function can be called by CONDRV, in ConioResizeBuffer() in text.c */
201 ConioProcessInputEvent(PCONSRV_CONSOLE Console
,
202 PINPUT_RECORD InputEvent
)
204 ULONG NumEventsWritten
;
206 if (InputEvent
->EventType
== KEY_EVENT
)
208 BOOL Down
= InputEvent
->Event
.KeyEvent
.bKeyDown
;
209 UINT VirtualKeyCode
= InputEvent
->Event
.KeyEvent
.wVirtualKeyCode
;
210 DWORD ShiftState
= InputEvent
->Event
.KeyEvent
.dwControlKeyState
;
212 /* Process Ctrl-C and Ctrl-Break */
213 if ( (GetConsoleInputBufferMode(Console
) & ENABLE_PROCESSED_INPUT
) &&
214 Down
&& (VirtualKeyCode
== VK_PAUSE
|| VirtualKeyCode
== 'C') &&
215 (ShiftState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
)) )
217 DPRINT1("Console_Api Ctrl-C\n");
218 ConSrvConsoleProcessCtrlEvent(Console
, 0, CTRL_C_EVENT
);
220 if (Console
->LineBuffer
&& !Console
->LineComplete
)
222 /* Line input is in progress; end it */
223 Console
->LinePos
= Console
->LineSize
= 0;
224 Console
->LineComplete
= TRUE
;
226 return STATUS_SUCCESS
; // STATUS_CONTROL_C_EXIT;
230 return ConioAddInputEvents(Console
,
239 WaitBeforeReading(IN PGET_INPUT_INFO InputInfo
,
240 IN PCSR_API_MESSAGE ApiMessage
,
241 IN CSR_WAIT_FUNCTION WaitFunction OPTIONAL
,
242 IN BOOLEAN CreateWaitBlock OPTIONAL
)
246 PGET_INPUT_INFO CapturedInputInfo
;
247 PCONSRV_CONSOLE Console
= (PCONSRV_CONSOLE
)InputInfo
->InputBuffer
->Header
.Console
;
249 CapturedInputInfo
= ConsoleAllocHeap(0, sizeof(GET_INPUT_INFO
));
250 if (!CapturedInputInfo
) return STATUS_NO_MEMORY
;
252 RtlMoveMemory(CapturedInputInfo
, InputInfo
, sizeof(GET_INPUT_INFO
));
254 if (!CsrCreateWait(&Console
->ReadWaitQueue
,
256 InputInfo
->CallingThread
,
260 ConsoleFreeHeap(CapturedInputInfo
);
261 return STATUS_NO_MEMORY
;
266 return STATUS_PENDING
;
270 ReadChars(IN PGET_INPUT_INFO InputInfo
,
271 IN PCSR_API_MESSAGE ApiMessage
,
272 IN BOOLEAN CreateWaitBlock OPTIONAL
);
274 // Wait function CSR_WAIT_FUNCTION
277 ReadCharsThread(IN PLIST_ENTRY WaitList
,
278 IN PCSR_THREAD WaitThread
,
279 IN PCSR_API_MESSAGE WaitApiMessage
,
280 IN PVOID WaitContext
,
281 IN PVOID WaitArgument1
,
282 IN PVOID WaitArgument2
,
286 PGET_INPUT_INFO InputInfo
= (PGET_INPUT_INFO
)WaitContext
;
288 PVOID InputHandle
= WaitArgument2
;
290 DPRINT("ReadCharsThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
293 * If we are notified of the process termination via a call
294 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
295 * CsrDestroyThread, just return.
297 if (WaitFlags
& CsrProcessTerminating
)
299 Status
= STATUS_THREAD_IS_TERMINATING
;
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.
310 if (InputHandle
!= NULL
)
312 Status
= (InputHandle
== InputInfo
->HandleEntry
? STATUS_ALERTED
318 * If we go there, that means we are notified for some new input.
319 * The console is therefore already locked.
321 Status
= ReadChars(InputInfo
, WaitApiMessage
, FALSE
);
324 if (Status
!= STATUS_PENDING
)
326 WaitApiMessage
->Status
= Status
;
327 ConsoleFreeHeap(InputInfo
);
330 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
334 ConDrvReadConsole(IN PCONSOLE Console
,
335 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
338 IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl
,
339 IN PVOID Parameter OPTIONAL
,
340 IN ULONG NumCharsToRead
,
341 OUT PULONG NumCharsRead OPTIONAL
);
343 ReadChars(IN PGET_INPUT_INFO InputInfo
,
344 IN PCSR_API_MESSAGE ApiMessage
,
345 IN BOOLEAN CreateWaitBlock OPTIONAL
)
348 PCONSOLE_READCONSOLE ReadConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadConsoleRequest
;
349 PCONSOLE_INPUT_BUFFER InputBuffer
= InputInfo
->InputBuffer
;
350 CONSOLE_READCONSOLE_CONTROL ReadControl
;
352 UNICODE_STRING ExeName
;
355 ULONG NrCharactersRead
= 0;
356 ULONG CharSize
= (ReadConsoleRequest
->Unicode
? sizeof(WCHAR
) : sizeof(CHAR
));
358 /* Retrieve the executable name, if needed */
359 if (ReadConsoleRequest
->InitialNumBytes
== 0 &&
360 ReadConsoleRequest
->ExeLength
<= sizeof(ReadConsoleRequest
->StaticBuffer
))
362 ExeName
.Length
= ExeName
.MaximumLength
= ReadConsoleRequest
->ExeLength
;
363 ExeName
.Buffer
= (PWCHAR
)ReadConsoleRequest
->StaticBuffer
;
367 ExeName
.Length
= ExeName
.MaximumLength
= 0;
368 ExeName
.Buffer
= NULL
;
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
;
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.
383 if (ReadConsoleRequest
->CaptureBufferSize
<= sizeof(ReadConsoleRequest
->StaticBuffer
))
386 * Adjust the internal pointer, because its old value points to
387 * the static buffer in the original ApiMessage structure.
389 // ReadConsoleRequest->Buffer = ReadConsoleRequest->StaticBuffer;
390 Buffer
= ReadConsoleRequest
->StaticBuffer
;
394 Buffer
= ReadConsoleRequest
->Buffer
;
397 DPRINT("Calling ConDrvReadConsole(%wZ)\n", &ExeName
);
398 Status
= ConDrvReadConsole(InputBuffer
->Header
.Console
,
400 ReadConsoleRequest
->Unicode
,
404 ReadConsoleRequest
->NumBytes
/ CharSize
, // NrCharactersToRead
406 DPRINT("ConDrvReadConsole returned (%d ; Status = 0x%08x)\n",
407 NrCharactersRead
, Status
);
409 // ReadConsoleRequest->ControlKeyState = ReadControl.dwControlKeyState;
411 if (Status
== STATUS_PENDING
)
413 /* We haven't completed a read, so start a wait */
414 return WaitBeforeReading(InputInfo
,
422 * We read all what we wanted. Set the number of bytes read and
423 * return the error code we were given.
425 ReadConsoleRequest
->NumBytes
= NrCharactersRead
* CharSize
;
426 ReadConsoleRequest
->ControlKeyState
= ReadControl
.dwControlKeyState
;
429 // return STATUS_SUCCESS;
434 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo
,
435 IN PCSR_API_MESSAGE ApiMessage
,
436 IN BOOLEAN CreateWaitBlock OPTIONAL
);
438 // Wait function CSR_WAIT_FUNCTION
441 ReadInputBufferThread(IN PLIST_ENTRY WaitList
,
442 IN PCSR_THREAD WaitThread
,
443 IN PCSR_API_MESSAGE WaitApiMessage
,
444 IN PVOID WaitContext
,
445 IN PVOID WaitArgument1
,
446 IN PVOID WaitArgument2
,
450 PGET_INPUT_INFO InputInfo
= (PGET_INPUT_INFO
)WaitContext
;
452 PVOID InputHandle
= WaitArgument2
;
454 DPRINT("ReadInputBufferThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
457 * If we are notified of the process termination via a call
458 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
459 * CsrDestroyThread, just return.
461 if (WaitFlags
& CsrProcessTerminating
)
463 Status
= STATUS_THREAD_IS_TERMINATING
;
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.
474 if (InputHandle
!= NULL
)
476 Status
= (InputHandle
== InputInfo
->HandleEntry
? STATUS_ALERTED
482 * If we go there, that means we are notified for some new input.
483 * The console is therefore already locked.
485 Status
= ReadInputBuffer(InputInfo
, WaitApiMessage
, FALSE
);
488 if (Status
!= STATUS_PENDING
)
490 WaitApiMessage
->Status
= Status
;
491 ConsoleFreeHeap(InputInfo
);
494 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
498 ConDrvGetConsoleInput(IN PCONSOLE Console
,
499 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
500 IN BOOLEAN KeepEvents
,
501 IN BOOLEAN WaitForMoreEvents
,
502 OUT PINPUT_RECORD InputRecord
,
503 IN ULONG NumEventsToRead
,
504 OUT PULONG NumEventsRead OPTIONAL
);
506 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo
,
507 IN PCSR_API_MESSAGE ApiMessage
,
508 IN BOOLEAN CreateWaitBlock OPTIONAL
)
511 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetInputRequest
;
512 PCONSOLE_INPUT_BUFFER InputBuffer
= InputInfo
->InputBuffer
;
515 PINPUT_RECORD InputRecord
;
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.
523 if (GetInputRequest
->NumRecords
<= sizeof(GetInputRequest
->RecordStaticBuffer
)/sizeof(INPUT_RECORD
))
526 * Adjust the internal pointer, because its old value points to
527 * the static buffer in the original ApiMessage structure.
529 // GetInputRequest->RecordBufPtr = GetInputRequest->RecordStaticBuffer;
530 InputRecord
= GetInputRequest
->RecordStaticBuffer
;
534 InputRecord
= GetInputRequest
->RecordBufPtr
;
538 Status
= ConDrvGetConsoleInput(InputBuffer
->Header
.Console
,
540 (GetInputRequest
->Flags
& CONSOLE_READ_NOREMOVE
) != 0,
541 (GetInputRequest
->Flags
& CONSOLE_READ_NOWAIT
) == 0,
543 GetInputRequest
->NumRecords
,
546 if (Status
== STATUS_PENDING
)
548 /* We haven't completed a read, so start a wait */
549 return WaitBeforeReading(InputInfo
,
551 ReadInputBufferThread
,
557 * We read all what we wanted. Set the number of events read and
558 * return the error code we were given.
560 GetInputRequest
->NumRecords
= NumEventsRead
;
562 if (NT_SUCCESS(Status
))
564 /* Now translate everything to ANSI */
565 if (!GetInputRequest
->Unicode
)
568 for (i
= 0; i
< NumEventsRead
; ++i
)
570 ConioInputEventToAnsi(InputBuffer
->Header
.Console
, &InputRecord
[i
]);
576 // return STATUS_SUCCESS;
581 /* PUBLIC SERVER APIS *********************************************************/
583 /* API_NUMBER: ConsolepReadConsole */
584 CON_API(SrvReadConsole
,
585 CONSOLE_READCONSOLE
, ReadConsoleRequest
)
589 PCONSOLE_INPUT_BUFFER InputBuffer
;
590 GET_INPUT_INFO InputInfo
;
592 DPRINT("SrvReadConsole\n");
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.
600 if (ReadConsoleRequest
->CaptureBufferSize
<= sizeof(ReadConsoleRequest
->StaticBuffer
))
603 * Adjust the internal pointer, because its old value points to
604 * the static buffer in the original ApiMessage structure.
606 // ReadConsoleRequest->Buffer = ReadConsoleRequest->StaticBuffer;
610 if (!CsrValidateMessageBuffer(ApiMessage
,
611 (PVOID
*)&ReadConsoleRequest
->Buffer
,
612 ReadConsoleRequest
->CaptureBufferSize
,
615 return STATUS_INVALID_PARAMETER
;
619 if (ReadConsoleRequest
->InitialNumBytes
> ReadConsoleRequest
->NumBytes
)
621 return STATUS_INVALID_PARAMETER
;
624 Status
= ConSrvGetInputBufferAndHandleEntry(ProcessData
,
625 ReadConsoleRequest
->InputHandle
,
630 if (!NT_SUCCESS(Status
))
633 ASSERT((PCONSOLE
)Console
== InputBuffer
->Header
.Console
);
635 InputInfo
.CallingThread
= CsrGetClientThread();
636 InputInfo
.HandleEntry
= HandleEntry
;
637 InputInfo
.InputBuffer
= InputBuffer
;
639 Status
= ReadChars(&InputInfo
, ApiMessage
, TRUE
);
641 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
643 if (Status
== STATUS_PENDING
) *ReplyCode
= CsrReplyPending
;
648 /* API_NUMBER: ConsolepGetConsoleInput */
649 CON_API(SrvGetConsoleInput
,
650 CONSOLE_GETINPUT
, GetInputRequest
)
654 PCONSOLE_INPUT_BUFFER InputBuffer
;
655 GET_INPUT_INFO InputInfo
;
657 DPRINT("SrvGetConsoleInput\n");
659 if (GetInputRequest
->Flags
& ~(CONSOLE_READ_NOREMOVE
| CONSOLE_READ_NOWAIT
))
661 return STATUS_INVALID_PARAMETER
;
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.
670 if (GetInputRequest
->NumRecords
<= sizeof(GetInputRequest
->RecordStaticBuffer
)/sizeof(INPUT_RECORD
))
673 * Adjust the internal pointer, because its old value points to
674 * the static buffer in the original ApiMessage structure.
676 // GetInputRequest->RecordBufPtr = GetInputRequest->RecordStaticBuffer;
680 if (!CsrValidateMessageBuffer(ApiMessage
,
681 (PVOID
*)&GetInputRequest
->RecordBufPtr
,
682 GetInputRequest
->NumRecords
,
683 sizeof(INPUT_RECORD
)))
685 return STATUS_INVALID_PARAMETER
;
689 Status
= ConSrvGetInputBufferAndHandleEntry(ProcessData
,
690 GetInputRequest
->InputHandle
,
695 if (!NT_SUCCESS(Status
))
698 ASSERT((PCONSOLE
)Console
== InputBuffer
->Header
.Console
);
700 InputInfo
.CallingThread
= CsrGetClientThread();
701 InputInfo
.HandleEntry
= HandleEntry
;
702 InputInfo
.InputBuffer
= InputBuffer
;
704 Status
= ReadInputBuffer(&InputInfo
, ApiMessage
, TRUE
);
706 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
708 if (Status
== STATUS_PENDING
) *ReplyCode
= CsrReplyPending
;
715 ConDrvWriteConsoleInput(IN PCONSOLE Console
,
716 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
717 IN BOOLEAN AppendToEnd
,
718 IN PINPUT_RECORD InputRecord
,
719 IN ULONG NumEventsToWrite
,
720 OUT PULONG NumEventsWritten OPTIONAL
);
723 /* API_NUMBER: ConsolepWriteConsoleInput */
724 CON_API(SrvWriteConsoleInput
,
725 CONSOLE_WRITEINPUT
, WriteInputRequest
)
728 PCONSOLE_INPUT_BUFFER InputBuffer
;
729 ULONG NumEventsWritten
;
730 PINPUT_RECORD InputRecord
;
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.
738 if (WriteInputRequest
->NumRecords
<= sizeof(WriteInputRequest
->RecordStaticBuffer
)/sizeof(INPUT_RECORD
))
741 * Adjust the internal pointer, because its old value points to
742 * the static buffer in the original ApiMessage structure.
744 // WriteInputRequest->RecordBufPtr = WriteInputRequest->RecordStaticBuffer;
745 InputRecord
= WriteInputRequest
->RecordStaticBuffer
;
749 if (!CsrValidateMessageBuffer(ApiMessage
,
750 (PVOID
*)&WriteInputRequest
->RecordBufPtr
,
751 WriteInputRequest
->NumRecords
,
752 sizeof(INPUT_RECORD
)))
754 return STATUS_INVALID_PARAMETER
;
757 InputRecord
= WriteInputRequest
->RecordBufPtr
;
760 Status
= ConSrvGetInputBuffer(ProcessData
,
761 WriteInputRequest
->InputHandle
,
762 &InputBuffer
, GENERIC_WRITE
, TRUE
);
763 if (!NT_SUCCESS(Status
))
765 WriteInputRequest
->NumRecords
= 0;
769 ASSERT((PCONSOLE
)Console
== InputBuffer
->Header
.Console
);
771 /* First translate everything to UNICODE */
772 if (!WriteInputRequest
->Unicode
)
775 for (i
= 0; i
< WriteInputRequest
->NumRecords
; ++i
)
777 ConioInputEventToUnicode((PCONSOLE
)Console
, &InputRecord
[i
]);
781 /* Now, add the events */
782 NumEventsWritten
= 0;
783 Status
= ConioAddInputEvents(Console
,
786 WriteInputRequest
->NumRecords
,
788 WriteInputRequest
->AppendToEnd
);
790 // Status = ConDrvWriteConsoleInput((PCONSOLE)Console,
792 // WriteInputRequest->AppendToEnd,
794 // WriteInputRequest->NumRecords,
795 // &NumEventsWritten);
797 WriteInputRequest
->NumRecords
= NumEventsWritten
;
799 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
804 ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console
,
805 IN PCONSOLE_INPUT_BUFFER InputBuffer
);
806 /* API_NUMBER: ConsolepFlushInputBuffer */
807 CON_API(SrvFlushConsoleInputBuffer
,
808 CONSOLE_FLUSHINPUTBUFFER
, FlushInputBufferRequest
)
811 PCONSOLE_INPUT_BUFFER InputBuffer
;
813 Status
= ConSrvGetInputBuffer(ProcessData
,
814 FlushInputBufferRequest
->InputHandle
,
815 &InputBuffer
, GENERIC_WRITE
, TRUE
);
816 if (!NT_SUCCESS(Status
))
819 ASSERT((PCONSOLE
)Console
== InputBuffer
->Header
.Console
);
821 Status
= ConDrvFlushConsoleInputBuffer((PCONSOLE
)Console
, InputBuffer
);
823 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
828 ConDrvGetConsoleNumberOfInputEvents(IN PCONSOLE Console
,
829 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
830 OUT PULONG NumberOfEvents
);
831 /* API_NUMBER: ConsolepGetNumberOfInputEvents */
832 CON_API(SrvGetConsoleNumberOfInputEvents
,
833 CONSOLE_GETNUMINPUTEVENTS
, GetNumInputEventsRequest
)
836 PCONSOLE_INPUT_BUFFER InputBuffer
;
838 Status
= ConSrvGetInputBuffer(ProcessData
,
839 GetNumInputEventsRequest
->InputHandle
,
840 &InputBuffer
, GENERIC_READ
, TRUE
);
841 if (!NT_SUCCESS(Status
))
844 ASSERT((PCONSOLE
)Console
== InputBuffer
->Header
.Console
);
846 Status
= ConDrvGetConsoleNumberOfInputEvents((PCONSOLE
)Console
,
848 &GetNumInputEventsRequest
->NumberOfEvents
);
850 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);