[WIN32SS][WINSRV] Add CSR API_NUMBER info comments (#2192)
[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(PCONSRV_CONSOLE 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((PCONSOLE)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(PCONSRV_CONSOLE 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 PCONSRV_CONSOLE Console = (PCONSRV_CONSOLE)InputInfo->InputBuffer->Header.Console;
217
218 CapturedInputInfo = ConsoleAllocHeap(0, sizeof(GET_INPUT_INFO));
219 if (!CapturedInputInfo) return STATUS_NO_MEMORY;
220
221 RtlMoveMemory(CapturedInputInfo, InputInfo, sizeof(GET_INPUT_INFO));
222
223 if (!CsrCreateWait(&Console->ReadWaitQueue,
224 WaitFunction,
225 InputInfo->CallingThread,
226 ApiMessage,
227 CapturedInputInfo))
228 {
229 ConsoleFreeHeap(CapturedInputInfo);
230 return STATUS_NO_MEMORY;
231 }
232 }
233
234 /* Wait for input */
235 return STATUS_PENDING;
236 }
237
238 static NTSTATUS
239 ReadChars(IN PGET_INPUT_INFO InputInfo,
240 IN PCSR_API_MESSAGE ApiMessage,
241 IN BOOLEAN CreateWaitBlock OPTIONAL);
242
243 // Wait function CSR_WAIT_FUNCTION
244 static BOOLEAN
245 NTAPI
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,
252 IN ULONG WaitFlags)
253 {
254 NTSTATUS Status;
255 PGET_INPUT_INFO InputInfo = (PGET_INPUT_INFO)WaitContext;
256
257 PVOID InputHandle = WaitArgument2;
258
259 DPRINT("ReadCharsThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags);
260
261 /*
262 * If we are notified of the process termination via a call
263 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
264 * CsrDestroyThread, just return.
265 */
266 if (WaitFlags & CsrProcessTerminating)
267 {
268 Status = STATUS_THREAD_IS_TERMINATING;
269 goto Quit;
270 }
271
272 /*
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.
278 */
279 if (InputHandle != NULL)
280 {
281 Status = (InputHandle == InputInfo->HandleEntry ? STATUS_ALERTED
282 : STATUS_PENDING);
283 goto Quit;
284 }
285
286 /*
287 * If we go there, that means we are notified for some new input.
288 * The console is therefore already locked.
289 */
290 Status = ReadChars(InputInfo, WaitApiMessage, FALSE);
291
292 Quit:
293 if (Status != STATUS_PENDING)
294 {
295 WaitApiMessage->Status = Status;
296 ConsoleFreeHeap(InputInfo);
297 }
298
299 return (Status == STATUS_PENDING ? FALSE : TRUE);
300 }
301
302 NTSTATUS NTAPI
303 ConDrvReadConsole(IN PCONSOLE Console,
304 IN PCONSOLE_INPUT_BUFFER InputBuffer,
305 IN BOOLEAN Unicode,
306 OUT PVOID Buffer,
307 IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl,
308 IN PVOID Parameter OPTIONAL,
309 IN ULONG NumCharsToRead,
310 OUT PULONG NumCharsRead OPTIONAL);
311 static NTSTATUS
312 ReadChars(IN PGET_INPUT_INFO InputInfo,
313 IN PCSR_API_MESSAGE ApiMessage,
314 IN BOOLEAN CreateWaitBlock OPTIONAL)
315 {
316 NTSTATUS Status;
317 PCONSOLE_READCONSOLE ReadConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleRequest;
318 PCONSOLE_INPUT_BUFFER InputBuffer = InputInfo->InputBuffer;
319 CONSOLE_READCONSOLE_CONTROL ReadControl;
320
321 UNICODE_STRING ExeName;
322
323 PVOID Buffer;
324 ULONG NrCharactersRead = 0;
325 ULONG CharSize = (ReadConsoleRequest->Unicode ? sizeof(WCHAR) : sizeof(CHAR));
326
327 /* Retrieve the executable name, if needed */
328 if (ReadConsoleRequest->InitialNumBytes == 0 &&
329 ReadConsoleRequest->ExeLength <= sizeof(ReadConsoleRequest->StaticBuffer))
330 {
331 ExeName.Length = ExeName.MaximumLength = ReadConsoleRequest->ExeLength;
332 ExeName.Buffer = (PWCHAR)ReadConsoleRequest->StaticBuffer;
333 }
334 else
335 {
336 ExeName.Length = ExeName.MaximumLength = 0;
337 ExeName.Buffer = NULL;
338 }
339
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;
345
346 /*
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.
351 */
352 if (ReadConsoleRequest->CaptureBufferSize <= sizeof(ReadConsoleRequest->StaticBuffer))
353 {
354 /*
355 * Adjust the internal pointer, because its old value points to
356 * the static buffer in the original ApiMessage structure.
357 */
358 // ReadConsoleRequest->Buffer = ReadConsoleRequest->StaticBuffer;
359 Buffer = ReadConsoleRequest->StaticBuffer;
360 }
361 else
362 {
363 Buffer = ReadConsoleRequest->Buffer;
364 }
365
366 DPRINT("Calling ConDrvReadConsole(%wZ)\n", &ExeName);
367 Status = ConDrvReadConsole(InputBuffer->Header.Console,
368 InputBuffer,
369 ReadConsoleRequest->Unicode,
370 Buffer,
371 &ReadControl,
372 &ExeName,
373 ReadConsoleRequest->NumBytes / CharSize, // NrCharactersToRead
374 &NrCharactersRead);
375 DPRINT("ConDrvReadConsole returned (%d ; Status = 0x%08x)\n",
376 NrCharactersRead, Status);
377
378 // ReadConsoleRequest->ControlKeyState = ReadControl.dwControlKeyState;
379
380 if (Status == STATUS_PENDING)
381 {
382 /* We haven't completed a read, so start a wait */
383 return WaitBeforeReading(InputInfo,
384 ApiMessage,
385 ReadCharsThread,
386 CreateWaitBlock);
387 }
388 else
389 {
390 /*
391 * We read all what we wanted. Set the number of bytes read and
392 * return the error code we were given.
393 */
394 ReadConsoleRequest->NumBytes = NrCharactersRead * CharSize;
395 ReadConsoleRequest->ControlKeyState = ReadControl.dwControlKeyState;
396
397 return Status;
398 // return STATUS_SUCCESS;
399 }
400 }
401
402 static NTSTATUS
403 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo,
404 IN PCSR_API_MESSAGE ApiMessage,
405 IN BOOLEAN CreateWaitBlock OPTIONAL);
406
407 // Wait function CSR_WAIT_FUNCTION
408 static BOOLEAN
409 NTAPI
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,
416 IN ULONG WaitFlags)
417 {
418 NTSTATUS Status;
419 PGET_INPUT_INFO InputInfo = (PGET_INPUT_INFO)WaitContext;
420
421 PVOID InputHandle = WaitArgument2;
422
423 DPRINT("ReadInputBufferThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags);
424
425 /*
426 * If we are notified of the process termination via a call
427 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
428 * CsrDestroyThread, just return.
429 */
430 if (WaitFlags & CsrProcessTerminating)
431 {
432 Status = STATUS_THREAD_IS_TERMINATING;
433 goto Quit;
434 }
435
436 /*
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.
442 */
443 if (InputHandle != NULL)
444 {
445 Status = (InputHandle == InputInfo->HandleEntry ? STATUS_ALERTED
446 : STATUS_PENDING);
447 goto Quit;
448 }
449
450 /*
451 * If we go there, that means we are notified for some new input.
452 * The console is therefore already locked.
453 */
454 Status = ReadInputBuffer(InputInfo, WaitApiMessage, FALSE);
455
456 Quit:
457 if (Status != STATUS_PENDING)
458 {
459 WaitApiMessage->Status = Status;
460 ConsoleFreeHeap(InputInfo);
461 }
462
463 return (Status == STATUS_PENDING ? FALSE : TRUE);
464 }
465
466 NTSTATUS NTAPI
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);
474 static NTSTATUS
475 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo,
476 IN PCSR_API_MESSAGE ApiMessage,
477 IN BOOLEAN CreateWaitBlock OPTIONAL)
478 {
479 NTSTATUS Status;
480 PCONSOLE_GETINPUT GetInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetInputRequest;
481 PCONSOLE_INPUT_BUFFER InputBuffer = InputInfo->InputBuffer;
482 ULONG NumEventsRead;
483
484 PINPUT_RECORD InputRecord;
485
486 /*
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.
491 */
492 if (GetInputRequest->NumRecords <= sizeof(GetInputRequest->RecordStaticBuffer)/sizeof(INPUT_RECORD))
493 {
494 /*
495 * Adjust the internal pointer, because its old value points to
496 * the static buffer in the original ApiMessage structure.
497 */
498 // GetInputRequest->RecordBufPtr = GetInputRequest->RecordStaticBuffer;
499 InputRecord = GetInputRequest->RecordStaticBuffer;
500 }
501 else
502 {
503 InputRecord = GetInputRequest->RecordBufPtr;
504 }
505
506 NumEventsRead = 0;
507 Status = ConDrvGetConsoleInput(InputBuffer->Header.Console,
508 InputBuffer,
509 (GetInputRequest->Flags & CONSOLE_READ_KEEPEVENT) != 0,
510 (GetInputRequest->Flags & CONSOLE_READ_CONTINUE ) == 0,
511 InputRecord,
512 GetInputRequest->NumRecords,
513 &NumEventsRead);
514
515 if (Status == STATUS_PENDING)
516 {
517 /* We haven't completed a read, so start a wait */
518 return WaitBeforeReading(InputInfo,
519 ApiMessage,
520 ReadInputBufferThread,
521 CreateWaitBlock);
522 }
523 else
524 {
525 /*
526 * We read all what we wanted. Set the number of events read and
527 * return the error code we were given.
528 */
529 GetInputRequest->NumRecords = NumEventsRead;
530
531 if (NT_SUCCESS(Status))
532 {
533 /* Now translate everything to ANSI */
534 if (!GetInputRequest->Unicode)
535 {
536 for (; NumEventsRead > 0; --NumEventsRead)
537 {
538 ConioInputEventToAnsi(InputBuffer->Header.Console, --InputRecord);
539 }
540 }
541 }
542
543 return Status;
544 // return STATUS_SUCCESS;
545 }
546 }
547
548
549 /* PUBLIC SERVER APIS *********************************************************/
550
551 /* API_NUMBER: ConsolepReadConsole */
552 CSR_API(SrvReadConsole)
553 {
554 NTSTATUS Status;
555 PCONSOLE_READCONSOLE ReadConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadConsoleRequest;
556 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
557 PVOID HandleEntry;
558 PCONSOLE_INPUT_BUFFER InputBuffer;
559 GET_INPUT_INFO InputInfo;
560
561 DPRINT("SrvReadConsole\n");
562
563 /*
564 * For optimization purposes, Windows (and hence ReactOS, too, for
565 * compatibility reasons) uses a static buffer if no more than eighty
566 * bytes are read. Otherwise a new buffer is used.
567 * The client-side expects that we know this behaviour.
568 */
569 if (ReadConsoleRequest->CaptureBufferSize <= sizeof(ReadConsoleRequest->StaticBuffer))
570 {
571 /*
572 * Adjust the internal pointer, because its old value points to
573 * the static buffer in the original ApiMessage structure.
574 */
575 // ReadConsoleRequest->Buffer = ReadConsoleRequest->StaticBuffer;
576 }
577 else
578 {
579 if (!CsrValidateMessageBuffer(ApiMessage,
580 (PVOID*)&ReadConsoleRequest->Buffer,
581 ReadConsoleRequest->CaptureBufferSize,
582 sizeof(BYTE)))
583 {
584 return STATUS_INVALID_PARAMETER;
585 }
586 }
587
588 if (ReadConsoleRequest->InitialNumBytes > ReadConsoleRequest->NumBytes)
589 {
590 return STATUS_INVALID_PARAMETER;
591 }
592
593 Status = ConSrvGetInputBufferAndHandleEntry(ProcessData, ReadConsoleRequest->InputHandle, &InputBuffer, &HandleEntry, GENERIC_READ, TRUE);
594 if (!NT_SUCCESS(Status)) return Status;
595
596 InputInfo.CallingThread = CsrGetClientThread();
597 InputInfo.HandleEntry = HandleEntry;
598 InputInfo.InputBuffer = InputBuffer;
599
600 Status = ReadChars(&InputInfo, ApiMessage, TRUE);
601
602 ConSrvReleaseInputBuffer(InputBuffer, TRUE);
603
604 if (Status == STATUS_PENDING) *ReplyCode = CsrReplyPending;
605
606 return Status;
607 }
608
609 /* API_NUMBER: ConsolepGetConsoleInput */
610 CSR_API(SrvGetConsoleInput)
611 {
612 NTSTATUS Status;
613 PCONSOLE_GETINPUT GetInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetInputRequest;
614 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
615 PVOID HandleEntry;
616 PCONSOLE_INPUT_BUFFER InputBuffer;
617 GET_INPUT_INFO InputInfo;
618
619 DPRINT("SrvGetConsoleInput\n");
620
621 if (GetInputRequest->Flags & ~(CONSOLE_READ_KEEPEVENT | CONSOLE_READ_CONTINUE))
622 return STATUS_INVALID_PARAMETER;
623
624 /*
625 * For optimization purposes, Windows (and hence ReactOS, too, for
626 * compatibility reasons) uses a static buffer if no more than five
627 * input records are read. Otherwise a new buffer is used.
628 * The client-side expects that we know this behaviour.
629 */
630 if (GetInputRequest->NumRecords <= sizeof(GetInputRequest->RecordStaticBuffer)/sizeof(INPUT_RECORD))
631 {
632 /*
633 * Adjust the internal pointer, because its old value points to
634 * the static buffer in the original ApiMessage structure.
635 */
636 // GetInputRequest->RecordBufPtr = GetInputRequest->RecordStaticBuffer;
637 }
638 else
639 {
640 if (!CsrValidateMessageBuffer(ApiMessage,
641 (PVOID*)&GetInputRequest->RecordBufPtr,
642 GetInputRequest->NumRecords,
643 sizeof(INPUT_RECORD)))
644 {
645 return STATUS_INVALID_PARAMETER;
646 }
647 }
648
649 Status = ConSrvGetInputBufferAndHandleEntry(ProcessData, GetInputRequest->InputHandle, &InputBuffer, &HandleEntry, GENERIC_READ, TRUE);
650 if (!NT_SUCCESS(Status)) return Status;
651
652 InputInfo.CallingThread = CsrGetClientThread();
653 InputInfo.HandleEntry = HandleEntry;
654 InputInfo.InputBuffer = InputBuffer;
655
656 Status = ReadInputBuffer(&InputInfo, ApiMessage, TRUE);
657
658 ConSrvReleaseInputBuffer(InputBuffer, TRUE);
659
660 if (Status == STATUS_PENDING) *ReplyCode = CsrReplyPending;
661
662 return Status;
663 }
664
665 #if 0
666 NTSTATUS NTAPI
667 ConDrvWriteConsoleInput(IN PCONSOLE Console,
668 IN PCONSOLE_INPUT_BUFFER InputBuffer,
669 IN BOOLEAN AppendToEnd,
670 IN PINPUT_RECORD InputRecord,
671 IN ULONG NumEventsToWrite,
672 OUT PULONG NumEventsWritten OPTIONAL);
673 #endif
674
675 /* API_NUMBER: ConsolepWriteConsoleInput */
676 CSR_API(SrvWriteConsoleInput)
677 {
678 NTSTATUS Status;
679 PCONSOLE_WRITEINPUT WriteInputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteInputRequest;
680 PCONSOLE_INPUT_BUFFER InputBuffer;
681 ULONG NumEventsWritten;
682
683 PINPUT_RECORD InputRecord;
684
685 DPRINT("SrvWriteConsoleInput\n");
686
687 /*
688 * For optimization purposes, Windows (and hence ReactOS, too, for
689 * compatibility reasons) uses a static buffer if no more than five
690 * input records are written. Otherwise a new buffer is used.
691 * The client-side expects that we know this behaviour.
692 */
693 if (WriteInputRequest->NumRecords <= sizeof(WriteInputRequest->RecordStaticBuffer)/sizeof(INPUT_RECORD))
694 {
695 /*
696 * Adjust the internal pointer, because its old value points to
697 * the static buffer in the original ApiMessage structure.
698 */
699 // WriteInputRequest->RecordBufPtr = WriteInputRequest->RecordStaticBuffer;
700 InputRecord = WriteInputRequest->RecordStaticBuffer;
701 }
702 else
703 {
704 if (!CsrValidateMessageBuffer(ApiMessage,
705 (PVOID*)&WriteInputRequest->RecordBufPtr,
706 WriteInputRequest->NumRecords,
707 sizeof(INPUT_RECORD)))
708 {
709 return STATUS_INVALID_PARAMETER;
710 }
711
712 InputRecord = WriteInputRequest->RecordBufPtr;
713 }
714
715 Status = ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
716 WriteInputRequest->InputHandle,
717 &InputBuffer, GENERIC_WRITE, TRUE);
718 if (!NT_SUCCESS(Status))
719 {
720 WriteInputRequest->NumRecords = 0;
721 return Status;
722 }
723
724 /* First translate everything to UNICODE */
725 if (!WriteInputRequest->Unicode)
726 {
727 ULONG i;
728 for (i = 0; i < WriteInputRequest->NumRecords; ++i)
729 {
730 ConioInputEventToUnicode(InputBuffer->Header.Console, &InputRecord[i]);
731 }
732 }
733
734 /* Now, add the events */
735 NumEventsWritten = 0;
736 Status = ConioAddInputEvents((PCONSRV_CONSOLE)InputBuffer->Header.Console,
737 // InputBuffer,
738 InputRecord,
739 WriteInputRequest->NumRecords,
740 &NumEventsWritten,
741 WriteInputRequest->AppendToEnd);
742
743 // Status = ConDrvWriteConsoleInput(InputBuffer->Header.Console,
744 // InputBuffer,
745 // WriteInputRequest->AppendToEnd,
746 // InputRecord,
747 // WriteInputRequest->NumRecords,
748 // &NumEventsWritten);
749
750 WriteInputRequest->NumRecords = NumEventsWritten;
751
752 ConSrvReleaseInputBuffer(InputBuffer, TRUE);
753 return Status;
754 }
755
756 NTSTATUS NTAPI
757 ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console,
758 IN PCONSOLE_INPUT_BUFFER InputBuffer);
759 /* API_NUMBER: ConsolepFlushInputBuffer */
760 CSR_API(SrvFlushConsoleInputBuffer)
761 {
762 NTSTATUS Status;
763 PCONSOLE_FLUSHINPUTBUFFER FlushInputBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FlushInputBufferRequest;
764 PCONSOLE_INPUT_BUFFER InputBuffer;
765
766 DPRINT("SrvFlushConsoleInputBuffer\n");
767
768 Status = ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
769 FlushInputBufferRequest->InputHandle,
770 &InputBuffer, GENERIC_WRITE, TRUE);
771 if (!NT_SUCCESS(Status)) return Status;
772
773 Status = ConDrvFlushConsoleInputBuffer(InputBuffer->Header.Console,
774 InputBuffer);
775
776 ConSrvReleaseInputBuffer(InputBuffer, TRUE);
777 return Status;
778 }
779
780 NTSTATUS NTAPI
781 ConDrvGetConsoleNumberOfInputEvents(IN PCONSOLE Console,
782 IN PCONSOLE_INPUT_BUFFER InputBuffer,
783 OUT PULONG NumberOfEvents);
784 /* API_NUMBER: ConsolepGetNumberOfInputEvents */
785 CSR_API(SrvGetConsoleNumberOfInputEvents)
786 {
787 NTSTATUS Status;
788 PCONSOLE_GETNUMINPUTEVENTS GetNumInputEventsRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetNumInputEventsRequest;
789 PCONSOLE_INPUT_BUFFER InputBuffer;
790
791 DPRINT("SrvGetConsoleNumberOfInputEvents\n");
792
793 Status = ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
794 GetNumInputEventsRequest->InputHandle,
795 &InputBuffer, GENERIC_READ, TRUE);
796 if (!NT_SUCCESS(Status)) return Status;
797
798 Status = ConDrvGetConsoleNumberOfInputEvents(InputBuffer->Header.Console,
799 InputBuffer,
800 &GetNumInputEventsRequest->NumberOfEvents);
801
802 ConSrvReleaseInputBuffer(InputBuffer, TRUE);
803 return Status;
804 }
805
806 /* EOF */