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