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