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 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 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 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 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 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 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 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 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 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 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 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_KEEPEVENT) != 0, 541 (GetInputRequest->Flags & CONSOLE_READ_CONTINUE ) == 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 */ 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 */ 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_KEEPEVENT | CONSOLE_READ_CONTINUE)) 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 */ 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 */ 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 */ 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