1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Console Server DLL 4 * FILE: win32ss/user/winsrv/consrv/frontends/terminal.c 5 * PURPOSE: ConSrv terminal. 6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr) 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include <consrv.h> 12 13 // #include "frontends/gui/guiterm.h" 14 #ifdef TUITERM_COMPILE 15 #include "frontends/tui/tuiterm.h" 16 #endif 17 18 #define NDEBUG 19 #include <debug.h> 20 21 22 23 24 25 /********** HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK ************/ 26 27 /* GLOBALS ********************************************************************/ 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 ConsoleInputUnicodeCharToAnsiChar(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 ConsoleInputAnsiCharToUnicodeChar(Console, dWChar, sChar) \ 40 ASSERT((ULONG_PTR)dWChar != (ULONG_PTR)sChar); \ 41 MultiByteToWideChar((Console)->InputCodePage, 0, (sChar), 1, (dWChar), 1) 42 43 /* PRIVATE FUNCTIONS **********************************************************/ 44 45 #if 0 46 47 static VOID 48 ConioInputEventToAnsi(PCONSOLE Console, PINPUT_RECORD InputEvent) 49 { 50 if (InputEvent->EventType == KEY_EVENT) 51 { 52 WCHAR UnicodeChar = InputEvent->Event.KeyEvent.uChar.UnicodeChar; 53 InputEvent->Event.KeyEvent.uChar.UnicodeChar = 0; 54 ConsoleInputUnicodeCharToAnsiChar(Console, 55 &InputEvent->Event.KeyEvent.uChar.AsciiChar, 56 &UnicodeChar); 57 } 58 } 59 60 static VOID 61 ConioInputEventToUnicode(PCONSOLE Console, PINPUT_RECORD InputEvent) 62 { 63 if (InputEvent->EventType == KEY_EVENT) 64 { 65 CHAR AsciiChar = InputEvent->Event.KeyEvent.uChar.AsciiChar; 66 InputEvent->Event.KeyEvent.uChar.AsciiChar = 0; 67 ConsoleInputAnsiCharToUnicodeChar(Console, 68 &InputEvent->Event.KeyEvent.uChar.UnicodeChar, 69 &AsciiChar); 70 } 71 } 72 73 #endif 74 75 /********** HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK ************/ 76 77 78 79 80 81 82 83 84 /* CONSRV TERMINAL FRONTENDS INTERFACE ****************************************/ 85 86 /***************/ 87 #ifdef TUITERM_COMPILE 88 NTSTATUS NTAPI 89 TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd, 90 IN OUT PCONSOLE_STATE_INFO ConsoleInfo, 91 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo, 92 IN HANDLE ConsoleLeaderProcessHandle); 93 NTSTATUS NTAPI 94 TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd); 95 #endif 96 97 NTSTATUS NTAPI 98 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd, 99 IN OUT PCONSOLE_STATE_INFO ConsoleInfo, 100 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo, 101 IN HANDLE ConsoleLeaderProcessHandle); 102 NTSTATUS NTAPI 103 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd); 104 /***************/ 105 106 typedef 107 NTSTATUS (NTAPI *FRONTEND_LOAD)(IN OUT PFRONTEND FrontEnd, 108 IN OUT PCONSOLE_STATE_INFO ConsoleInfo, 109 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo, 110 IN HANDLE ConsoleLeaderProcessHandle); 111 112 typedef 113 NTSTATUS (NTAPI *FRONTEND_UNLOAD)(IN OUT PFRONTEND FrontEnd); 114 115 /* 116 * If we are not in GUI-mode, start the text-mode terminal emulator. 117 * If we fail, try to start the GUI-mode terminal emulator. 118 * 119 * Try to open the GUI-mode terminal emulator. Two cases are possible: 120 * - We are in GUI-mode, therefore GuiMode == TRUE, the previous test-case 121 * failed and we start GUI-mode terminal emulator. 122 * - We are in text-mode, therefore GuiMode == FALSE, the previous test-case 123 * succeeded BUT we failed at starting text-mode terminal emulator. 124 * Then GuiMode was switched to TRUE in order to try to open the GUI-mode 125 * terminal emulator (Win32k will automatically switch to graphical mode, 126 * therefore no additional code is needed). 127 */ 128 129 /* 130 * NOTE: Each entry of the table should be retrieved when loading a front-end 131 * (examples of the CSR servers which register some data for CSRSS). 132 */ 133 static struct 134 { 135 CHAR FrontEndName[80]; 136 FRONTEND_LOAD FrontEndLoad; 137 FRONTEND_UNLOAD FrontEndUnload; 138 } FrontEndLoadingMethods[] = 139 { 140 #ifdef TUITERM_COMPILE 141 {"TUI", TuiLoadFrontEnd, TuiUnloadFrontEnd}, 142 #endif 143 {"GUI", GuiLoadFrontEnd, GuiUnloadFrontEnd}, 144 145 // {"Not found", 0, NULL} 146 }; 147 148 static NTSTATUS 149 ConSrvLoadFrontEnd(IN OUT PFRONTEND FrontEnd, 150 IN OUT PCONSOLE_STATE_INFO ConsoleInfo, 151 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo, 152 IN HANDLE ConsoleLeaderProcessHandle) 153 { 154 NTSTATUS Status = STATUS_SUCCESS; 155 ULONG i; 156 157 /* 158 * Choose an adequate terminal front-end to load, and load it 159 */ 160 for (i = 0; i < ARRAYSIZE(FrontEndLoadingMethods); ++i) 161 { 162 DPRINT("CONSRV: Trying to load %s frontend...\n", 163 FrontEndLoadingMethods[i].FrontEndName); 164 Status = FrontEndLoadingMethods[i].FrontEndLoad(FrontEnd, 165 ConsoleInfo, 166 ConsoleInitInfo, 167 ConsoleLeaderProcessHandle); 168 if (NT_SUCCESS(Status)) 169 { 170 /* Save the unload callback */ 171 FrontEnd->UnloadFrontEnd = FrontEndLoadingMethods[i].FrontEndUnload; 172 173 DPRINT("CONSRV: %s frontend loaded successfully\n", 174 FrontEndLoadingMethods[i].FrontEndName); 175 break; 176 } 177 else 178 { 179 DPRINT1("CONSRV: Loading %s frontend failed, Status = 0x%08lx , continuing...\n", 180 FrontEndLoadingMethods[i].FrontEndName, Status); 181 } 182 } 183 184 return Status; 185 } 186 187 static NTSTATUS 188 ConSrvUnloadFrontEnd(IN PFRONTEND FrontEnd) 189 { 190 if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER; 191 // return FrontEnd->Vtbl->UnloadFrontEnd(FrontEnd); 192 return FrontEnd->UnloadFrontEnd(FrontEnd); 193 } 194 195 // See after... 196 static TERMINAL_VTBL ConSrvTermVtbl; 197 198 NTSTATUS NTAPI 199 ConSrvInitTerminal(IN OUT PTERMINAL Terminal, 200 IN OUT PCONSOLE_STATE_INFO ConsoleInfo, 201 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo, 202 IN HANDLE ConsoleLeaderProcessHandle) 203 { 204 NTSTATUS Status; 205 PFRONTEND FrontEnd; 206 207 /* Load a suitable frontend for the ConSrv terminal */ 208 FrontEnd = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*FrontEnd)); 209 if (!FrontEnd) return STATUS_NO_MEMORY; 210 211 Status = ConSrvLoadFrontEnd(FrontEnd, 212 ConsoleInfo, 213 ConsoleInitInfo, 214 ConsoleLeaderProcessHandle); 215 if (!NT_SUCCESS(Status)) 216 { 217 DPRINT1("CONSRV: Failed to initialize a frontend, Status = 0x%08lx\n", Status); 218 ConsoleFreeHeap(FrontEnd); 219 return Status; 220 } 221 DPRINT("CONSRV: Frontend initialized\n"); 222 223 /* Initialize the ConSrv terminal */ 224 Terminal->Vtbl = &ConSrvTermVtbl; 225 // Terminal->Console will be initialized by ConDrvAttachTerminal 226 Terminal->Context = FrontEnd; /* We store the frontend pointer in the terminal private context */ 227 228 return STATUS_SUCCESS; 229 } 230 231 NTSTATUS NTAPI 232 ConSrvDeinitTerminal(IN OUT PTERMINAL Terminal) 233 { 234 NTSTATUS Status = STATUS_SUCCESS; 235 PFRONTEND FrontEnd = Terminal->Context; 236 237 /* Reset the ConSrv terminal */ 238 Terminal->Context = NULL; 239 Terminal->Vtbl = NULL; 240 241 /* Unload the frontend */ 242 if (FrontEnd != NULL) 243 { 244 Status = ConSrvUnloadFrontEnd(FrontEnd); 245 ConsoleFreeHeap(FrontEnd); 246 } 247 248 return Status; 249 } 250 251 252 /* CONSRV TERMINAL INTERFACE **************************************************/ 253 254 static NTSTATUS NTAPI 255 ConSrvTermInitTerminal(IN OUT PTERMINAL This, 256 IN PCONSOLE Console) 257 { 258 NTSTATUS Status; 259 PFRONTEND FrontEnd = This->Context; 260 261 /* Initialize the console pointer for our frontend */ 262 FrontEnd->Console = Console; 263 264 /** HACK HACK!! Copy FrontEnd into the console!! **/ 265 DPRINT("Using FrontEndIFace HACK(1), should be removed after proper implementation!\n"); 266 Console->FrontEndIFace = *FrontEnd; 267 268 Status = FrontEnd->Vtbl->InitFrontEnd(FrontEnd, FrontEnd->Console); 269 if (!NT_SUCCESS(Status)) 270 DPRINT1("InitFrontEnd failed, Status = 0x%08lx\n", Status); 271 272 /** HACK HACK!! Be sure FrontEndIFace is correctly updated in the console!! **/ 273 DPRINT("Using FrontEndIFace HACK(2), should be removed after proper implementation!\n"); 274 Console->FrontEndIFace = *FrontEnd; 275 276 return Status; 277 } 278 279 static VOID NTAPI 280 ConSrvTermDeinitTerminal(IN OUT PTERMINAL This) 281 { 282 PFRONTEND FrontEnd = This->Context; 283 FrontEnd->Vtbl->DeinitFrontEnd(FrontEnd); 284 } 285 286 287 288 /************ Line discipline ***************/ 289 290 static NTSTATUS NTAPI 291 ConSrvTermReadStream(IN OUT PTERMINAL This, 292 IN BOOLEAN Unicode, 293 /**PWCHAR Buffer,**/ 294 OUT PVOID Buffer, 295 IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl, 296 IN PVOID Parameter OPTIONAL, 297 IN ULONG NumCharsToRead, 298 OUT PULONG NumCharsRead OPTIONAL) 299 { 300 PFRONTEND FrontEnd = This->Context; 301 PCONSRV_CONSOLE Console = FrontEnd->Console; 302 PCONSOLE_INPUT_BUFFER InputBuffer = &Console->InputBuffer; 303 PUNICODE_STRING ExeName = Parameter; 304 305 // STATUS_PENDING : Wait if more to read ; STATUS_SUCCESS : Don't wait. 306 NTSTATUS Status = STATUS_PENDING; 307 308 PLIST_ENTRY CurrentEntry; 309 ConsoleInput *Input; 310 ULONG i = 0; 311 312 /* Validity checks */ 313 // ASSERT(Console == InputBuffer->Header.Console); 314 ASSERT((Buffer != NULL) || (Buffer == NULL && NumCharsToRead == 0)); 315 316 /* We haven't read anything (yet) */ 317 318 if (InputBuffer->Mode & ENABLE_LINE_INPUT) 319 { 320 /* COOKED mode, call the line discipline */ 321 322 if (Console->LineBuffer == NULL) 323 { 324 /* Start a new line */ 325 Console->LineMaxSize = max(256, NumCharsToRead); 326 327 /* 328 * Fixup ReadControl->nInitialChars in case the number of initial 329 * characters is bigger than the number of characters to be read. 330 * It will always be, lesser than or equal to Console->LineMaxSize. 331 */ 332 ReadControl->nInitialChars = min(ReadControl->nInitialChars, NumCharsToRead); 333 334 Console->LineBuffer = ConsoleAllocHeap(0, Console->LineMaxSize * sizeof(WCHAR)); 335 if (Console->LineBuffer == NULL) return STATUS_NO_MEMORY; 336 337 Console->LinePos = Console->LineSize = ReadControl->nInitialChars; 338 Console->LineComplete = Console->LineUpPressed = FALSE; 339 Console->LineInsertToggle = Console->InsertMode; 340 Console->LineWakeupMask = ReadControl->dwCtrlWakeupMask; 341 342 /* 343 * Pre-fill the buffer with the nInitialChars from the user buffer. 344 * Since pre-filling is only allowed in Unicode, we don't need to 345 * worry about ANSI <-> Unicode conversion. 346 */ 347 memcpy(Console->LineBuffer, Buffer, Console->LineSize * sizeof(WCHAR)); 348 if (Console->LineSize >= Console->LineMaxSize) 349 { 350 Console->LineComplete = TRUE; 351 Console->LinePos = 0; 352 } 353 } 354 355 /* If we don't have a complete line yet, process the pending input */ 356 while (!Console->LineComplete && !IsListEmpty(&InputBuffer->InputEvents)) 357 { 358 /* Remove an input event from the queue */ 359 CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents); 360 if (IsListEmpty(&InputBuffer->InputEvents)) 361 { 362 ResetEvent(InputBuffer->ActiveEvent); 363 } 364 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry); 365 366 /* Only pay attention to key down */ 367 if (Input->InputEvent.EventType == KEY_EVENT && 368 Input->InputEvent.Event.KeyEvent.bKeyDown) 369 { 370 LineInputKeyDown(Console, ExeName, 371 &Input->InputEvent.Event.KeyEvent); 372 ReadControl->dwControlKeyState = Input->InputEvent.Event.KeyEvent.dwControlKeyState; 373 } 374 ConsoleFreeHeap(Input); 375 } 376 377 /* Check if we have a complete line to read from */ 378 if (Console->LineComplete) 379 { 380 /* 381 * Console->LinePos keeps the next position of the character to read 382 * in the line buffer across the different calls of the function, 383 * so that the line buffer can be read by chunks after all the input 384 * has been buffered. 385 */ 386 387 while (i < NumCharsToRead && Console->LinePos < Console->LineSize) 388 { 389 WCHAR Char = Console->LineBuffer[Console->LinePos++]; 390 391 if (Unicode) 392 { 393 ((PWCHAR)Buffer)[i] = Char; 394 } 395 else 396 { 397 ConsoleInputUnicodeCharToAnsiChar(Console, &((PCHAR)Buffer)[i], &Char); 398 } 399 ++i; 400 } 401 402 if (Console->LinePos >= Console->LineSize) 403 { 404 /* The entire line has been read */ 405 ConsoleFreeHeap(Console->LineBuffer); 406 Console->LineBuffer = NULL; 407 Console->LinePos = Console->LineMaxSize = Console->LineSize = 0; 408 // Console->LineComplete = Console->LineUpPressed = FALSE; 409 Console->LineComplete = FALSE; 410 } 411 412 Status = STATUS_SUCCESS; 413 } 414 } 415 else 416 { 417 /* RAW mode */ 418 419 /* Character input */ 420 while (i < NumCharsToRead && !IsListEmpty(&InputBuffer->InputEvents)) 421 { 422 /* Remove an input event from the queue */ 423 CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents); 424 if (IsListEmpty(&InputBuffer->InputEvents)) 425 { 426 ResetEvent(InputBuffer->ActiveEvent); 427 } 428 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry); 429 430 /* Only pay attention to valid characters, on key down */ 431 if (Input->InputEvent.EventType == KEY_EVENT && 432 Input->InputEvent.Event.KeyEvent.bKeyDown && 433 Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar != L'\0') 434 { 435 WCHAR Char = Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar; 436 437 if (Unicode) 438 { 439 ((PWCHAR)Buffer)[i] = Char; 440 } 441 else 442 { 443 ConsoleInputUnicodeCharToAnsiChar(Console, &((PCHAR)Buffer)[i], &Char); 444 } 445 ++i; 446 447 /* Did read something */ 448 Status = STATUS_SUCCESS; 449 } 450 ConsoleFreeHeap(Input); 451 } 452 } 453 454 // FIXME: Only set if Status == STATUS_SUCCESS ??? 455 if (NumCharsRead) *NumCharsRead = i; 456 457 return Status; 458 } 459 460 461 462 463 /* GLOBALS ********************************************************************/ 464 465 #define TAB_WIDTH 8 466 467 // See condrv/text.c 468 /*static*/ VOID 469 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff); 470 471 static VOID 472 ConioNextLine(PTEXTMODE_SCREEN_BUFFER Buff, PSMALL_RECT UpdateRect, PUINT ScrolledLines) 473 { 474 /* If we hit bottom, slide the viewable screen */ 475 if (++Buff->CursorPosition.Y == Buff->ScreenBufferSize.Y) 476 { 477 Buff->CursorPosition.Y--; 478 if (++Buff->VirtualY == Buff->ScreenBufferSize.Y) 479 { 480 Buff->VirtualY = 0; 481 } 482 (*ScrolledLines)++; 483 ClearLineBuffer(Buff); 484 if (UpdateRect->Top != 0) 485 { 486 UpdateRect->Top--; 487 } 488 } 489 UpdateRect->Left = 0; 490 UpdateRect->Right = Buff->ScreenBufferSize.X - 1; 491 UpdateRect->Bottom = Buff->CursorPosition.Y; 492 } 493 494 static NTSTATUS 495 ConioWriteConsole(PFRONTEND FrontEnd, 496 PTEXTMODE_SCREEN_BUFFER Buff, 497 PWCHAR Buffer, 498 DWORD Length, 499 BOOL Attrib) 500 { 501 PCONSRV_CONSOLE Console = FrontEnd->Console; 502 503 UINT i; 504 PCHAR_INFO Ptr; 505 SMALL_RECT UpdateRect; 506 SHORT CursorStartX, CursorStartY; 507 UINT ScrolledLines; 508 509 CursorStartX = Buff->CursorPosition.X; 510 CursorStartY = Buff->CursorPosition.Y; 511 UpdateRect.Left = Buff->ScreenBufferSize.X; 512 UpdateRect.Top = Buff->CursorPosition.Y; 513 UpdateRect.Right = -1; 514 UpdateRect.Bottom = Buff->CursorPosition.Y; 515 ScrolledLines = 0; 516 517 for (i = 0; i < Length; i++) 518 { 519 /* 520 * If we are in processed mode, interpret special characters and 521 * display them correctly. Otherwise, just put them into the buffer. 522 */ 523 if (Buff->Mode & ENABLE_PROCESSED_OUTPUT) 524 { 525 /* --- CR --- */ 526 if (Buffer[i] == L'\r') 527 { 528 Buff->CursorPosition.X = 0; 529 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); 530 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X); 531 continue; 532 } 533 /* --- LF --- */ 534 else if (Buffer[i] == L'\n') 535 { 536 Buff->CursorPosition.X = 0; 537 ConioNextLine(Buff, &UpdateRect, &ScrolledLines); 538 continue; 539 } 540 /* --- BS --- */ 541 else if (Buffer[i] == L'\b') 542 { 543 /* Only handle BS if we're not on the first pos of the first line */ 544 if (0 != Buff->CursorPosition.X || 0 != Buff->CursorPosition.Y) 545 { 546 if (0 == Buff->CursorPosition.X) 547 { 548 /* slide virtual position up */ 549 Buff->CursorPosition.X = Buff->ScreenBufferSize.X - 1; 550 Buff->CursorPosition.Y--; 551 UpdateRect.Top = min(UpdateRect.Top, Buff->CursorPosition.Y); 552 } 553 else 554 { 555 Buff->CursorPosition.X--; 556 } 557 Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y); 558 Ptr->Char.UnicodeChar = L' '; 559 Ptr->Attributes = Buff->ScreenDefaultAttrib; 560 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); 561 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X); 562 } 563 continue; 564 } 565 /* --- TAB --- */ 566 else if (Buffer[i] == L'\t') 567 { 568 UINT EndX; 569 570 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); 571 EndX = (Buff->CursorPosition.X + TAB_WIDTH) & ~(TAB_WIDTH - 1); 572 EndX = min(EndX, (UINT)Buff->ScreenBufferSize.X); 573 Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y); 574 while ((UINT)Buff->CursorPosition.X < EndX) 575 { 576 Ptr->Char.UnicodeChar = L' '; 577 Ptr->Attributes = Buff->ScreenDefaultAttrib; 578 ++Ptr; 579 Buff->CursorPosition.X++; 580 } 581 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X - 1); 582 if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X) 583 { 584 if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT) 585 { 586 Buff->CursorPosition.X = 0; 587 ConioNextLine(Buff, &UpdateRect, &ScrolledLines); 588 } 589 else 590 { 591 Buff->CursorPosition.X--; 592 } 593 } 594 continue; 595 } 596 /* --- BEL ---*/ 597 else if (Buffer[i] == L'\a') 598 { 599 FrontEnd->Vtbl->RingBell(FrontEnd); 600 continue; 601 } 602 } 603 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X); 604 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X); 605 606 Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y); 607 Ptr->Char.UnicodeChar = Buffer[i]; 608 if (Attrib) Ptr->Attributes = Buff->ScreenDefaultAttrib; 609 610 Buff->CursorPosition.X++; 611 if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X) 612 { 613 if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT) 614 { 615 Buff->CursorPosition.X = 0; 616 ConioNextLine(Buff, &UpdateRect, &ScrolledLines); 617 } 618 else 619 { 620 Buff->CursorPosition.X = CursorStartX; 621 } 622 } 623 } 624 625 if (!ConioIsRectEmpty(&UpdateRect) && (PCONSOLE_SCREEN_BUFFER)Buff == Console->ActiveBuffer) 626 { 627 // TermWriteStream(Console, &UpdateRect, CursorStartX, CursorStartY, 628 // ScrolledLines, Buffer, Length); 629 FrontEnd->Vtbl->WriteStream(FrontEnd, 630 &UpdateRect, 631 CursorStartX, 632 CursorStartY, 633 ScrolledLines, 634 Buffer, 635 Length); 636 } 637 638 return STATUS_SUCCESS; 639 } 640 641 642 643 static NTSTATUS NTAPI 644 ConSrvTermWriteStream(IN OUT PTERMINAL This, 645 PTEXTMODE_SCREEN_BUFFER Buff, 646 PWCHAR Buffer, 647 DWORD Length, 648 BOOL Attrib) 649 { 650 PFRONTEND FrontEnd = This->Context; 651 return ConioWriteConsole(FrontEnd, 652 Buff, 653 Buffer, 654 Length, 655 Attrib); 656 } 657 658 /************ Line discipline ***************/ 659 660 661 662 VOID 663 ConioDrawConsole(PCONSRV_CONSOLE Console) 664 { 665 SMALL_RECT Region; 666 PCONSOLE_SCREEN_BUFFER ActiveBuffer = Console->ActiveBuffer; 667 668 if (!ActiveBuffer) return; 669 670 ConioInitRect(&Region, 0, 0, 671 ActiveBuffer->ViewSize.Y - 1, 672 ActiveBuffer->ViewSize.X - 1); 673 TermDrawRegion(Console, &Region); 674 // Console->FrontEndIFace.Vtbl->DrawRegion(&Console->FrontEndIFace, &Region); 675 } 676 677 static VOID NTAPI 678 ConSrvTermDrawRegion(IN OUT PTERMINAL This, 679 SMALL_RECT* Region) 680 { 681 PFRONTEND FrontEnd = This->Context; 682 FrontEnd->Vtbl->DrawRegion(FrontEnd, Region); 683 } 684 685 static BOOL NTAPI 686 ConSrvTermSetCursorInfo(IN OUT PTERMINAL This, 687 PCONSOLE_SCREEN_BUFFER ScreenBuffer) 688 { 689 PFRONTEND FrontEnd = This->Context; 690 return FrontEnd->Vtbl->SetCursorInfo(FrontEnd, ScreenBuffer); 691 } 692 693 static BOOL NTAPI 694 ConSrvTermSetScreenInfo(IN OUT PTERMINAL This, 695 PCONSOLE_SCREEN_BUFFER ScreenBuffer, 696 SHORT OldCursorX, 697 SHORT OldCursorY) 698 { 699 PFRONTEND FrontEnd = This->Context; 700 return FrontEnd->Vtbl->SetScreenInfo(FrontEnd, 701 ScreenBuffer, 702 OldCursorX, 703 OldCursorY); 704 } 705 706 static VOID NTAPI 707 ConSrvTermResizeTerminal(IN OUT PTERMINAL This) 708 { 709 PFRONTEND FrontEnd = This->Context; 710 FrontEnd->Vtbl->ResizeTerminal(FrontEnd); 711 } 712 713 static VOID NTAPI 714 ConSrvTermSetActiveScreenBuffer(IN OUT PTERMINAL This) 715 { 716 PFRONTEND FrontEnd = This->Context; 717 FrontEnd->Vtbl->SetActiveScreenBuffer(FrontEnd); 718 } 719 720 static VOID NTAPI 721 ConSrvTermReleaseScreenBuffer(IN OUT PTERMINAL This, 722 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer) 723 { 724 PFRONTEND FrontEnd = This->Context; 725 FrontEnd->Vtbl->ReleaseScreenBuffer(FrontEnd, ScreenBuffer); 726 } 727 728 static VOID NTAPI 729 ConSrvTermGetLargestConsoleWindowSize(IN OUT PTERMINAL This, 730 PCOORD pSize) 731 { 732 PFRONTEND FrontEnd = This->Context; 733 FrontEnd->Vtbl->GetLargestConsoleWindowSize(FrontEnd, pSize); 734 } 735 736 static BOOL NTAPI 737 ConSrvTermSetPalette(IN OUT PTERMINAL This, 738 HPALETTE PaletteHandle, 739 UINT PaletteUsage) 740 { 741 PFRONTEND FrontEnd = This->Context; 742 return FrontEnd->Vtbl->SetPalette(FrontEnd, PaletteHandle, PaletteUsage); 743 } 744 745 static INT NTAPI 746 ConSrvTermShowMouseCursor(IN OUT PTERMINAL This, 747 BOOL Show) 748 { 749 PFRONTEND FrontEnd = This->Context; 750 return FrontEnd->Vtbl->ShowMouseCursor(FrontEnd, Show); 751 } 752 753 static TERMINAL_VTBL ConSrvTermVtbl = 754 { 755 ConSrvTermInitTerminal, 756 ConSrvTermDeinitTerminal, 757 758 ConSrvTermReadStream, 759 ConSrvTermWriteStream, 760 761 ConSrvTermDrawRegion, 762 ConSrvTermSetCursorInfo, 763 ConSrvTermSetScreenInfo, 764 ConSrvTermResizeTerminal, 765 ConSrvTermSetActiveScreenBuffer, 766 ConSrvTermReleaseScreenBuffer, 767 ConSrvTermGetLargestConsoleWindowSize, 768 ConSrvTermSetPalette, 769 ConSrvTermShowMouseCursor, 770 }; 771 772 #if 0 773 VOID 774 ResetFrontEnd(IN PCONSOLE Console) 775 { 776 if (!Console) return; 777 778 /* Reinitialize the frontend interface */ 779 RtlZeroMemory(&Console->FrontEndIFace, sizeof(Console->FrontEndIFace)); 780 Console->FrontEndIFace.Vtbl = &ConSrvTermVtbl; 781 } 782 #endif 783 784 /* EOF */ 785