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