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))
31 * "The lpMultiByteStr and lpWideCharStr pointers must not be the same.
32 * If they are the same, the function fails, and GetLastError returns
33 * ERROR_INVALID_PARAMETER."
35 #define ConsoleInputUnicodeToAnsiChar(Console, dChar, sWChar) \
36 ASSERT((ULONG_PTR)dChar != (ULONG_PTR)sWChar); \
37 WideCharToMultiByte((Console)->InputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
39 #define ConsoleInputAnsiToUnicodeChar(Console, dWChar, sChar) \
40 ASSERT((ULONG_PTR)dWChar != (ULONG_PTR)sChar); \
41 MultiByteToWideChar((Console)->InputCodePage, 0, (sChar), 1, (dWChar), 1)
44 typedef struct _GET_INPUT_INFO
46 PCSR_THREAD CallingThread
; // The thread which called the input API.
47 PVOID HandleEntry
; // The handle data associated with the wait thread.
48 PCONSOLE_INPUT_BUFFER InputBuffer
; // The input buffer corresponding to the handle.
49 } GET_INPUT_INFO
, *PGET_INPUT_INFO
;
52 /* PRIVATE FUNCTIONS **********************************************************/
55 ConioInputEventToAnsi(PCONSOLE Console
, PINPUT_RECORD InputEvent
)
57 if (InputEvent
->EventType
== KEY_EVENT
)
59 WCHAR UnicodeChar
= InputEvent
->Event
.KeyEvent
.uChar
.UnicodeChar
;
60 InputEvent
->Event
.KeyEvent
.uChar
.UnicodeChar
= 0;
61 ConsoleInputUnicodeToAnsiChar(Console
,
62 &InputEvent
->Event
.KeyEvent
.uChar
.AsciiChar
,
68 ConioInputEventToUnicode(PCONSOLE Console
, PINPUT_RECORD InputEvent
)
70 if (InputEvent
->EventType
== KEY_EVENT
)
72 CHAR AsciiChar
= InputEvent
->Event
.KeyEvent
.uChar
.AsciiChar
;
73 InputEvent
->Event
.KeyEvent
.uChar
.AsciiChar
= 0;
74 ConsoleInputAnsiToUnicodeChar(Console
,
75 &InputEvent
->Event
.KeyEvent
.uChar
.UnicodeChar
,
81 PreprocessInput(PCONSRV_CONSOLE Console
,
82 PINPUT_RECORD InputEvent
,
83 ULONG NumEventsToWrite
)
88 * Loop each event, and for each, check for pause or unpause
89 * and perform adequate behaviour.
91 for (NumEvents
= NumEventsToWrite
; NumEvents
> 0; --NumEvents
)
93 /* Check for pause or unpause */
94 if (InputEvent
->EventType
== KEY_EVENT
&& InputEvent
->Event
.KeyEvent
.bKeyDown
)
96 WORD vk
= InputEvent
->Event
.KeyEvent
.wVirtualKeyCode
;
97 if (!(Console
->PauseFlags
& PAUSED_FROM_KEYBOARD
))
99 DWORD cks
= InputEvent
->Event
.KeyEvent
.dwControlKeyState
;
100 if (Console
->InputBuffer
.Mode
& ENABLE_LINE_INPUT
&&
102 (vk
== 'S' && (cks
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
)) &&
103 !(cks
& (LEFT_ALT_PRESSED
| RIGHT_ALT_PRESSED
)))))
105 ConioPause(Console
, PAUSED_FROM_KEYBOARD
);
108 RtlMoveMemory(InputEvent
,
110 (NumEvents
- 1) * sizeof(INPUT_RECORD
));
117 if ((vk
< VK_SHIFT
|| vk
> VK_CAPITAL
) && vk
!= VK_LWIN
&&
118 vk
!= VK_RWIN
&& vk
!= VK_NUMLOCK
&& vk
!= VK_SCROLL
)
120 ConioUnpause(Console
, PAUSED_FROM_KEYBOARD
);
123 RtlMoveMemory(InputEvent
,
125 (NumEvents
- 1) * sizeof(INPUT_RECORD
));
132 /* Go to the next event */
136 return NumEventsToWrite
;
140 PostprocessInput(PCONSRV_CONSOLE Console
)
142 CsrNotifyWait(&Console
->ReadWaitQueue
,
146 if (!IsListEmpty(&Console
->ReadWaitQueue
))
148 CsrDereferenceWait(&Console
->ReadWaitQueue
);
154 ConDrvWriteConsoleInput(IN PCONSOLE Console
,
155 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
156 IN BOOLEAN AppendToEnd
,
157 IN PINPUT_RECORD InputRecord
,
158 IN ULONG NumEventsToWrite
,
159 OUT PULONG NumEventsWritten OPTIONAL
);
161 ConioAddInputEvents(PCONSRV_CONSOLE Console
,
162 PINPUT_RECORD InputRecords
, // InputEvent
163 ULONG NumEventsToWrite
,
164 PULONG NumEventsWritten
,
167 NTSTATUS Status
= STATUS_SUCCESS
;
169 if (NumEventsWritten
) *NumEventsWritten
= 0;
171 NumEventsToWrite
= PreprocessInput(Console
, InputRecords
, NumEventsToWrite
);
172 if (NumEventsToWrite
== 0) return STATUS_SUCCESS
;
174 // Status = ConDrvAddInputEvents(Console,
180 Status
= ConDrvWriteConsoleInput((PCONSOLE
)Console
,
181 &Console
->InputBuffer
,
187 // if (NT_SUCCESS(Status))
188 if (Status
== STATUS_SUCCESS
) PostprocessInput(Console
);
193 /* FIXME: This function can be called by CONDRV, in ConioResizeBuffer() in text.c */
195 ConioProcessInputEvent(PCONSRV_CONSOLE Console
,
196 PINPUT_RECORD InputEvent
)
198 ULONG NumEventsWritten
;
199 return ConioAddInputEvents(Console
,
208 WaitBeforeReading(IN PGET_INPUT_INFO InputInfo
,
209 IN PCSR_API_MESSAGE ApiMessage
,
210 IN CSR_WAIT_FUNCTION WaitFunction OPTIONAL
,
211 IN BOOLEAN CreateWaitBlock OPTIONAL
)
215 PGET_INPUT_INFO CapturedInputInfo
;
216 PCONSRV_CONSOLE Console
= (PCONSRV_CONSOLE
)InputInfo
->InputBuffer
->Header
.Console
;
218 CapturedInputInfo
= ConsoleAllocHeap(0, sizeof(GET_INPUT_INFO
));
219 if (!CapturedInputInfo
) return STATUS_NO_MEMORY
;
221 RtlMoveMemory(CapturedInputInfo
, InputInfo
, sizeof(GET_INPUT_INFO
));
223 if (!CsrCreateWait(&Console
->ReadWaitQueue
,
225 InputInfo
->CallingThread
,
229 ConsoleFreeHeap(CapturedInputInfo
);
230 return STATUS_NO_MEMORY
;
235 return STATUS_PENDING
;
239 ReadChars(IN PGET_INPUT_INFO InputInfo
,
240 IN PCSR_API_MESSAGE ApiMessage
,
241 IN BOOLEAN CreateWaitBlock OPTIONAL
);
243 // Wait function CSR_WAIT_FUNCTION
246 ReadCharsThread(IN PLIST_ENTRY WaitList
,
247 IN PCSR_THREAD WaitThread
,
248 IN PCSR_API_MESSAGE WaitApiMessage
,
249 IN PVOID WaitContext
,
250 IN PVOID WaitArgument1
,
251 IN PVOID WaitArgument2
,
255 PGET_INPUT_INFO InputInfo
= (PGET_INPUT_INFO
)WaitContext
;
257 PVOID InputHandle
= WaitArgument2
;
259 DPRINT("ReadCharsThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
262 * If we are notified of the process termination via a call
263 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
264 * CsrDestroyThread, just return.
266 if (WaitFlags
& CsrProcessTerminating
)
268 Status
= STATUS_THREAD_IS_TERMINATING
;
273 * Somebody is closing a handle to this input buffer,
274 * by calling ConSrvCloseHandleEntry.
275 * See whether we are linked to that handle (ie. we
276 * are a waiter for this handle), and if so, return.
277 * Otherwise, ignore the call and continue waiting.
279 if (InputHandle
!= NULL
)
281 Status
= (InputHandle
== InputInfo
->HandleEntry
? STATUS_ALERTED
287 * If we go there, that means we are notified for some new input.
288 * The console is therefore already locked.
290 Status
= ReadChars(InputInfo
, WaitApiMessage
, FALSE
);
293 if (Status
!= STATUS_PENDING
)
295 WaitApiMessage
->Status
= Status
;
296 ConsoleFreeHeap(InputInfo
);
299 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
303 ConDrvReadConsole(IN PCONSOLE Console
,
304 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
305 /**/IN PUNICODE_STRING ExeName
/**/OPTIONAL
/**/,/**/
308 IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl
,
309 IN ULONG NumCharsToRead
,
310 OUT PULONG NumCharsRead OPTIONAL
);
312 ReadChars(IN PGET_INPUT_INFO InputInfo
,
313 IN PCSR_API_MESSAGE ApiMessage
,
314 IN BOOLEAN CreateWaitBlock OPTIONAL
)
317 PCONSOLE_READCONSOLE ReadConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadConsoleRequest
;
318 PCONSOLE_INPUT_BUFFER InputBuffer
= InputInfo
->InputBuffer
;
319 CONSOLE_READCONSOLE_CONTROL ReadControl
;
321 UNICODE_STRING ExeName
;
324 ULONG NrCharactersRead
= 0;
325 ULONG CharSize
= (ReadConsoleRequest
->Unicode
? sizeof(WCHAR
) : sizeof(CHAR
));
327 /* Compute the executable name, if needed */
328 if (ReadConsoleRequest
->InitialNumBytes
== 0 &&
329 ReadConsoleRequest
->ExeLength
<= sizeof(ReadConsoleRequest
->StaticBuffer
))
331 ExeName
.Length
= ExeName
.MaximumLength
= ReadConsoleRequest
->ExeLength
;
332 ExeName
.Buffer
= (PWCHAR
)ReadConsoleRequest
->StaticBuffer
;
336 ExeName
.Length
= ExeName
.MaximumLength
= 0;
337 ExeName
.Buffer
= NULL
;
340 /* Build the ReadControl structure */
341 ReadControl
.nLength
= sizeof(CONSOLE_READCONSOLE_CONTROL
);
342 ReadControl
.nInitialChars
= ReadConsoleRequest
->InitialNumBytes
/ CharSize
;
343 ReadControl
.dwCtrlWakeupMask
= ReadConsoleRequest
->CtrlWakeupMask
;
344 ReadControl
.dwControlKeyState
= ReadConsoleRequest
->ControlKeyState
;
347 * For optimization purposes, Windows (and hence ReactOS, too, for
348 * compatibility reasons) uses a static buffer if no more than eighty
349 * bytes are read. Otherwise a new buffer is used.
350 * The client-side expects that we know this behaviour.
352 if (ReadConsoleRequest
->CaptureBufferSize
<= sizeof(ReadConsoleRequest
->StaticBuffer
))
355 * Adjust the internal pointer, because its old value points to
356 * the static buffer in the original ApiMessage structure.
358 // ReadConsoleRequest->Buffer = ReadConsoleRequest->StaticBuffer;
359 Buffer
= ReadConsoleRequest
->StaticBuffer
;
363 Buffer
= ReadConsoleRequest
->Buffer
;
366 DPRINT1("Calling ConDrvReadConsole(%wZ)\n", &ExeName
);
367 Status
= ConDrvReadConsole(InputBuffer
->Header
.Console
,
370 ReadConsoleRequest
->Unicode
,
373 ReadConsoleRequest
->NumBytes
/ CharSize
, // NrCharactersToRead
375 DPRINT1("ConDrvReadConsole returned (%d ; Status = 0x%08x)\n",
376 NrCharactersRead
, Status
);
378 // ReadConsoleRequest->ControlKeyState = ReadControl.dwControlKeyState;
380 if (Status
== STATUS_PENDING
)
382 /* We haven't completed a read, so start a wait */
383 return WaitBeforeReading(InputInfo
,
391 * We read all what we wanted. Set the number of bytes read and
392 * return the error code we were given.
394 ReadConsoleRequest
->NumBytes
= NrCharactersRead
* CharSize
;
395 ReadConsoleRequest
->ControlKeyState
= ReadControl
.dwControlKeyState
;
398 // return STATUS_SUCCESS;
403 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo
,
404 IN PCSR_API_MESSAGE ApiMessage
,
405 IN BOOLEAN CreateWaitBlock OPTIONAL
);
407 // Wait function CSR_WAIT_FUNCTION
410 ReadInputBufferThread(IN PLIST_ENTRY WaitList
,
411 IN PCSR_THREAD WaitThread
,
412 IN PCSR_API_MESSAGE WaitApiMessage
,
413 IN PVOID WaitContext
,
414 IN PVOID WaitArgument1
,
415 IN PVOID WaitArgument2
,
419 PGET_INPUT_INFO InputInfo
= (PGET_INPUT_INFO
)WaitContext
;
421 PVOID InputHandle
= WaitArgument2
;
423 DPRINT("ReadInputBufferThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
426 * If we are notified of the process termination via a call
427 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
428 * CsrDestroyThread, just return.
430 if (WaitFlags
& CsrProcessTerminating
)
432 Status
= STATUS_THREAD_IS_TERMINATING
;
437 * Somebody is closing a handle to this input buffer,
438 * by calling ConSrvCloseHandleEntry.
439 * See whether we are linked to that handle (ie. we
440 * are a waiter for this handle), and if so, return.
441 * Otherwise, ignore the call and continue waiting.
443 if (InputHandle
!= NULL
)
445 Status
= (InputHandle
== InputInfo
->HandleEntry
? STATUS_ALERTED
451 * If we go there, that means we are notified for some new input.
452 * The console is therefore already locked.
454 Status
= ReadInputBuffer(InputInfo
, WaitApiMessage
, FALSE
);
457 if (Status
!= STATUS_PENDING
)
459 WaitApiMessage
->Status
= Status
;
460 ConsoleFreeHeap(InputInfo
);
463 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
467 ConDrvGetConsoleInput(IN PCONSOLE Console
,
468 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
469 IN BOOLEAN KeepEvents
,
470 IN BOOLEAN WaitForMoreEvents
,
471 OUT PINPUT_RECORD InputRecord
,
472 IN ULONG NumEventsToRead
,
473 OUT PULONG NumEventsRead OPTIONAL
);
475 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo
,
476 IN PCSR_API_MESSAGE ApiMessage
,
477 IN BOOLEAN CreateWaitBlock OPTIONAL
)
480 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetInputRequest
;
481 PCONSOLE_INPUT_BUFFER InputBuffer
= InputInfo
->InputBuffer
;
484 PINPUT_RECORD InputRecord
;
487 * For optimization purposes, Windows (and hence ReactOS, too, for
488 * compatibility reasons) uses a static buffer if no more than five
489 * input records are read. Otherwise a new buffer is used.
490 * The client-side expects that we know this behaviour.
492 if (GetInputRequest
->NumRecords
<= sizeof(GetInputRequest
->RecordStaticBuffer
)/sizeof(INPUT_RECORD
))
495 * Adjust the internal pointer, because its old value points to
496 * the static buffer in the original ApiMessage structure.
498 // GetInputRequest->RecordBufPtr = GetInputRequest->RecordStaticBuffer;
499 InputRecord
= GetInputRequest
->RecordStaticBuffer
;
503 InputRecord
= GetInputRequest
->RecordBufPtr
;
507 Status
= ConDrvGetConsoleInput(InputBuffer
->Header
.Console
,
509 (GetInputRequest
->Flags
& CONSOLE_READ_KEEPEVENT
) != 0,
510 (GetInputRequest
->Flags
& CONSOLE_READ_CONTINUE
) == 0,
512 GetInputRequest
->NumRecords
,
515 if (Status
== STATUS_PENDING
)
517 /* We haven't completed a read, so start a wait */
518 return WaitBeforeReading(InputInfo
,
520 ReadInputBufferThread
,
526 * We read all what we wanted. Set the number of events read and
527 * return the error code we were given.
529 GetInputRequest
->NumRecords
= NumEventsRead
;
531 if (NT_SUCCESS(Status
))
533 /* Now translate everything to ANSI */
534 if (!GetInputRequest
->Unicode
)
536 for (; NumEventsRead
> 0; --NumEventsRead
)
538 ConioInputEventToAnsi(InputBuffer
->Header
.Console
, --InputRecord
);
544 // return STATUS_SUCCESS;
549 /* PUBLIC SERVER APIS *********************************************************/
551 CSR_API(SrvReadConsole
)
554 PCONSOLE_READCONSOLE ReadConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadConsoleRequest
;
555 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
557 PCONSOLE_INPUT_BUFFER InputBuffer
;
558 GET_INPUT_INFO InputInfo
;
560 DPRINT("SrvReadConsole\n");
563 * For optimization purposes, Windows (and hence ReactOS, too, for
564 * compatibility reasons) uses a static buffer if no more than eighty
565 * bytes are read. Otherwise a new buffer is used.
566 * The client-side expects that we know this behaviour.
568 if (ReadConsoleRequest
->CaptureBufferSize
<= sizeof(ReadConsoleRequest
->StaticBuffer
))
571 * Adjust the internal pointer, because its old value points to
572 * the static buffer in the original ApiMessage structure.
574 // ReadConsoleRequest->Buffer = ReadConsoleRequest->StaticBuffer;
578 if (!CsrValidateMessageBuffer(ApiMessage
,
579 (PVOID
*)&ReadConsoleRequest
->Buffer
,
580 ReadConsoleRequest
->CaptureBufferSize
,
583 return STATUS_INVALID_PARAMETER
;
587 if (ReadConsoleRequest
->InitialNumBytes
> ReadConsoleRequest
->NumBytes
)
589 return STATUS_INVALID_PARAMETER
;
592 Status
= ConSrvGetInputBufferAndHandleEntry(ProcessData
, ReadConsoleRequest
->InputHandle
, &InputBuffer
, &HandleEntry
, GENERIC_READ
, TRUE
);
593 if (!NT_SUCCESS(Status
)) return Status
;
595 InputInfo
.CallingThread
= CsrGetClientThread();
596 InputInfo
.HandleEntry
= HandleEntry
;
597 InputInfo
.InputBuffer
= InputBuffer
;
599 Status
= ReadChars(&InputInfo
, ApiMessage
, TRUE
);
601 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
603 if (Status
== STATUS_PENDING
) *ReplyCode
= CsrReplyPending
;
608 CSR_API(SrvGetConsoleInput
)
611 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetInputRequest
;
612 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
614 PCONSOLE_INPUT_BUFFER InputBuffer
;
615 GET_INPUT_INFO InputInfo
;
617 DPRINT("SrvGetConsoleInput\n");
619 if (GetInputRequest
->Flags
& ~(CONSOLE_READ_KEEPEVENT
| CONSOLE_READ_CONTINUE
))
620 return STATUS_INVALID_PARAMETER
;
623 * For optimization purposes, Windows (and hence ReactOS, too, for
624 * compatibility reasons) uses a static buffer if no more than five
625 * input records are read. Otherwise a new buffer is used.
626 * The client-side expects that we know this behaviour.
628 if (GetInputRequest
->NumRecords
<= sizeof(GetInputRequest
->RecordStaticBuffer
)/sizeof(INPUT_RECORD
))
631 * Adjust the internal pointer, because its old value points to
632 * the static buffer in the original ApiMessage structure.
634 // GetInputRequest->RecordBufPtr = GetInputRequest->RecordStaticBuffer;
638 if (!CsrValidateMessageBuffer(ApiMessage
,
639 (PVOID
*)&GetInputRequest
->RecordBufPtr
,
640 GetInputRequest
->NumRecords
,
641 sizeof(INPUT_RECORD
)))
643 return STATUS_INVALID_PARAMETER
;
647 Status
= ConSrvGetInputBufferAndHandleEntry(ProcessData
, GetInputRequest
->InputHandle
, &InputBuffer
, &HandleEntry
, GENERIC_READ
, TRUE
);
648 if (!NT_SUCCESS(Status
)) return Status
;
650 InputInfo
.CallingThread
= CsrGetClientThread();
651 InputInfo
.HandleEntry
= HandleEntry
;
652 InputInfo
.InputBuffer
= InputBuffer
;
654 Status
= ReadInputBuffer(&InputInfo
, ApiMessage
, TRUE
);
656 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
658 if (Status
== STATUS_PENDING
) *ReplyCode
= CsrReplyPending
;
665 ConDrvWriteConsoleInput(IN PCONSOLE Console
,
666 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
667 IN BOOLEAN AppendToEnd
,
668 IN PINPUT_RECORD InputRecord
,
669 IN ULONG NumEventsToWrite
,
670 OUT PULONG NumEventsWritten OPTIONAL
);
672 CSR_API(SrvWriteConsoleInput
)
675 PCONSOLE_WRITEINPUT WriteInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.WriteInputRequest
;
676 PCONSOLE_INPUT_BUFFER InputBuffer
;
677 ULONG NumEventsWritten
;
679 PINPUT_RECORD InputRecord
;
681 DPRINT("SrvWriteConsoleInput\n");
684 * For optimization purposes, Windows (and hence ReactOS, too, for
685 * compatibility reasons) uses a static buffer if no more than five
686 * input records are written. Otherwise a new buffer is used.
687 * The client-side expects that we know this behaviour.
689 if (WriteInputRequest
->NumRecords
<= sizeof(WriteInputRequest
->RecordStaticBuffer
)/sizeof(INPUT_RECORD
))
692 * Adjust the internal pointer, because its old value points to
693 * the static buffer in the original ApiMessage structure.
695 // WriteInputRequest->RecordBufPtr = WriteInputRequest->RecordStaticBuffer;
696 InputRecord
= WriteInputRequest
->RecordStaticBuffer
;
700 if (!CsrValidateMessageBuffer(ApiMessage
,
701 (PVOID
*)&WriteInputRequest
->RecordBufPtr
,
702 WriteInputRequest
->NumRecords
,
703 sizeof(INPUT_RECORD
)))
705 return STATUS_INVALID_PARAMETER
;
708 InputRecord
= WriteInputRequest
->RecordBufPtr
;
711 Status
= ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
712 WriteInputRequest
->InputHandle
,
713 &InputBuffer
, GENERIC_WRITE
, TRUE
);
714 if (!NT_SUCCESS(Status
))
716 WriteInputRequest
->NumRecords
= 0;
720 /* First translate everything to UNICODE */
721 if (!WriteInputRequest
->Unicode
)
724 for (i
= 0; i
< WriteInputRequest
->NumRecords
; ++i
)
726 ConioInputEventToUnicode(InputBuffer
->Header
.Console
, &InputRecord
[i
]);
730 /* Now, add the events */
731 NumEventsWritten
= 0;
732 Status
= ConioAddInputEvents((PCONSRV_CONSOLE
)InputBuffer
->Header
.Console
,
735 WriteInputRequest
->NumRecords
,
737 WriteInputRequest
->AppendToEnd
);
739 // Status = ConDrvWriteConsoleInput(InputBuffer->Header.Console,
741 // WriteInputRequest->AppendToEnd,
743 // WriteInputRequest->NumRecords,
744 // &NumEventsWritten);
746 WriteInputRequest
->NumRecords
= NumEventsWritten
;
748 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
753 ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console
,
754 IN PCONSOLE_INPUT_BUFFER InputBuffer
);
755 CSR_API(SrvFlushConsoleInputBuffer
)
758 PCONSOLE_FLUSHINPUTBUFFER FlushInputBufferRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.FlushInputBufferRequest
;
759 PCONSOLE_INPUT_BUFFER InputBuffer
;
761 DPRINT("SrvFlushConsoleInputBuffer\n");
763 Status
= ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
764 FlushInputBufferRequest
->InputHandle
,
765 &InputBuffer
, GENERIC_WRITE
, TRUE
);
766 if (!NT_SUCCESS(Status
)) return Status
;
768 Status
= ConDrvFlushConsoleInputBuffer(InputBuffer
->Header
.Console
,
771 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
776 ConDrvGetConsoleNumberOfInputEvents(IN PCONSOLE Console
,
777 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
778 OUT PULONG NumberOfEvents
);
779 CSR_API(SrvGetConsoleNumberOfInputEvents
)
782 PCONSOLE_GETNUMINPUTEVENTS GetNumInputEventsRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetNumInputEventsRequest
;
783 PCONSOLE_INPUT_BUFFER InputBuffer
;
785 DPRINT("SrvGetConsoleNumberOfInputEvents\n");
787 Status
= ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
788 GetNumInputEventsRequest
->InputHandle
,
789 &InputBuffer
, GENERIC_READ
, TRUE
);
790 if (!NT_SUCCESS(Status
)) return Status
;
792 Status
= ConDrvGetConsoleNumberOfInputEvents(InputBuffer
->Header
.Console
,
794 &GetNumInputEventsRequest
->NumberOfEvents
);
796 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);