1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Console Server DLL 4 * FILE: win32ss/user/winsrv/consrv/frontends/tui/tuiterm.c 5 * PURPOSE: TUI Terminal Front-End - Virtual Consoles... 6 * PROGRAMMERS: David Welch 7 * G� van Geldorp 8 * Jeffrey Morlan 9 * Hermes Belusca-Maito (hermes.belusca@sfr.fr) 10 */ 11 12 #ifdef TUITERM_COMPILE 13 14 #include <consrv.h> 15 16 // #include "include/conio.h" 17 #include "include/console.h" 18 #include "include/settings.h" 19 #include "tuiterm.h" 20 21 #include <ndk/iofuncs.h> 22 #include <ndk/setypes.h> 23 #include <drivers/blue/ntddblue.h> 24 25 #define NDEBUG 26 #include <debug.h> 27 28 29 /* GLOBALS ********************************************************************/ 30 31 #define ConsoleOutputUnicodeToAnsiChar(Console, dChar, sWChar) \ 32 ASSERT((ULONG_PTR)dChar != (ULONG_PTR)sWChar); \ 33 WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL) 34 35 /* TUI Console Window Class name */ 36 #define TUI_CONSOLE_WINDOW_CLASS L"TuiConsoleWindowClass" 37 38 typedef struct _TUI_CONSOLE_DATA 39 { 40 CRITICAL_SECTION Lock; 41 LIST_ENTRY Entry; /* Entry in the list of virtual consoles */ 42 // HANDLE hTuiInitEvent; 43 // HANDLE hTuiTermEvent; 44 45 HWND hWindow; /* Handle to the console's window (used for the window's procedure) */ 46 47 PCONSRV_CONSOLE Console; /* Pointer to the owned console */ 48 PCONSOLE_SCREEN_BUFFER ActiveBuffer; /* Pointer to the active screen buffer (then maybe the previous Console member is redundant?? Or not...) */ 49 // TUI_CONSOLE_INFO TuiInfo; /* TUI terminal settings */ 50 } TUI_CONSOLE_DATA, *PTUI_CONSOLE_DATA; 51 52 #define GetNextConsole(Console) \ 53 CONTAINING_RECORD(Console->Entry.Flink, TUI_CONSOLE_DATA, Entry) 54 55 #define GetPrevConsole(Console) \ 56 CONTAINING_RECORD(Console->Entry.Blink, TUI_CONSOLE_DATA, Entry) 57 58 59 /* List of the maintained virtual consoles and its lock */ 60 static LIST_ENTRY VirtConsList; 61 static PTUI_CONSOLE_DATA ActiveConsole; /* The active console on screen */ 62 static CRITICAL_SECTION ActiveVirtConsLock; 63 64 static COORD PhysicalConsoleSize; 65 static HANDLE ConsoleDeviceHandle; 66 67 static BOOL ConsInitialized = FALSE; 68 69 /******************************************************************************\ 70 |** BlueScreen Driver management **| 71 \**/ 72 /* Code taken and adapted from base/system/services/driver.c */ 73 static DWORD 74 ScmLoadDriver(LPCWSTR lpServiceName) 75 { 76 NTSTATUS Status = STATUS_SUCCESS; 77 BOOLEAN WasPrivilegeEnabled = FALSE; 78 PWSTR pszDriverPath; 79 UNICODE_STRING DriverPath; 80 81 /* Build the driver path */ 82 /* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */ 83 pszDriverPath = ConsoleAllocHeap(HEAP_ZERO_MEMORY, 84 (52 + wcslen(lpServiceName) + 1) * sizeof(WCHAR)); 85 if (pszDriverPath == NULL) 86 return ERROR_NOT_ENOUGH_MEMORY; 87 88 wcscpy(pszDriverPath, 89 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); 90 wcscat(pszDriverPath, 91 lpServiceName); 92 93 RtlInitUnicodeString(&DriverPath, 94 pszDriverPath); 95 96 DPRINT(" Path: %wZ\n", &DriverPath); 97 98 /* Acquire driver-loading privilege */ 99 Status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, 100 TRUE, 101 FALSE, 102 &WasPrivilegeEnabled); 103 if (!NT_SUCCESS(Status)) 104 { 105 /* We encountered a failure, exit properly */ 106 DPRINT1("CONSRV: Cannot acquire driver-loading privilege, Status = 0x%08lx\n", Status); 107 goto done; 108 } 109 110 Status = NtLoadDriver(&DriverPath); 111 112 /* Release driver-loading privilege */ 113 RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, 114 WasPrivilegeEnabled, 115 FALSE, 116 &WasPrivilegeEnabled); 117 118 done: 119 ConsoleFreeHeap(pszDriverPath); 120 return RtlNtStatusToDosError(Status); 121 } 122 123 #ifdef BLUESCREEN_DRIVER_UNLOADING 124 static DWORD 125 ScmUnloadDriver(LPCWSTR lpServiceName) 126 { 127 NTSTATUS Status = STATUS_SUCCESS; 128 BOOLEAN WasPrivilegeEnabled = FALSE; 129 PWSTR pszDriverPath; 130 UNICODE_STRING DriverPath; 131 132 /* Build the driver path */ 133 /* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */ 134 pszDriverPath = ConsoleAllocHeap(HEAP_ZERO_MEMORY, 135 (52 + wcslen(lpServiceName) + 1) * sizeof(WCHAR)); 136 if (pszDriverPath == NULL) 137 return ERROR_NOT_ENOUGH_MEMORY; 138 139 wcscpy(pszDriverPath, 140 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); 141 wcscat(pszDriverPath, 142 lpServiceName); 143 144 RtlInitUnicodeString(&DriverPath, 145 pszDriverPath); 146 147 DPRINT(" Path: %wZ\n", &DriverPath); 148 149 /* Acquire driver-unloading privilege */ 150 Status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, 151 TRUE, 152 FALSE, 153 &WasPrivilegeEnabled); 154 if (!NT_SUCCESS(Status)) 155 { 156 /* We encountered a failure, exit properly */ 157 DPRINT1("CONSRV: Cannot acquire driver-unloading privilege, Status = 0x%08lx\n", Status); 158 goto done; 159 } 160 161 Status = NtUnloadDriver(&DriverPath); 162 163 /* Release driver-unloading privilege */ 164 RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, 165 WasPrivilegeEnabled, 166 FALSE, 167 &WasPrivilegeEnabled); 168 169 done: 170 ConsoleFreeHeap(pszDriverPath); 171 return RtlNtStatusToDosError(Status); 172 } 173 #endif 174 /**\ 175 \******************************************************************************/ 176 177 #if 0 178 static BOOL 179 TuiSwapConsole(INT Next) 180 { 181 static PTUI_CONSOLE_DATA SwapConsole = NULL; /* Console we are thinking about swapping with */ 182 DWORD BytesReturned; 183 ANSI_STRING Title; 184 PVOID Buffer; 185 PCOORD pos; 186 187 if (0 != Next) 188 { 189 /* 190 * Alt-Tab, swap consoles. 191 * move SwapConsole to next console, and print its title. 192 */ 193 EnterCriticalSection(&ActiveVirtConsLock); 194 if (!SwapConsole) SwapConsole = ActiveConsole; 195 196 SwapConsole = (0 < Next ? GetNextConsole(SwapConsole) : GetPrevConsole(SwapConsole)); 197 Title.MaximumLength = RtlUnicodeStringToAnsiSize(&SwapConsole->Console->Title); 198 Title.Length = 0; 199 Buffer = ConsoleAllocHeap(0, sizeof(COORD) + Title.MaximumLength); 200 pos = (PCOORD)Buffer; 201 Title.Buffer = (PVOID)((ULONG_PTR)Buffer + sizeof(COORD)); 202 203 RtlUnicodeStringToAnsiString(&Title, &SwapConsole->Console->Title, FALSE); 204 pos->X = (PhysicalConsoleSize.X - Title.Length) / 2; 205 pos->Y = PhysicalConsoleSize.Y / 2; 206 /* Redraw the console to clear off old title */ 207 ConioDrawConsole(ActiveConsole->Console); 208 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER, 209 NULL, 0, Buffer, sizeof(COORD) + Title.Length, 210 &BytesReturned, NULL)) 211 { 212 DPRINT1( "Error writing to console\n" ); 213 } 214 ConsoleFreeHeap(Buffer); 215 LeaveCriticalSection(&ActiveVirtConsLock); 216 217 return TRUE; 218 } 219 else if (NULL != SwapConsole) 220 { 221 EnterCriticalSection(&ActiveVirtConsLock); 222 if (SwapConsole != ActiveConsole) 223 { 224 /* First remove swapconsole from the list */ 225 SwapConsole->Entry.Blink->Flink = SwapConsole->Entry.Flink; 226 SwapConsole->Entry.Flink->Blink = SwapConsole->Entry.Blink; 227 /* Now insert before activeconsole */ 228 SwapConsole->Entry.Flink = &ActiveConsole->Entry; 229 SwapConsole->Entry.Blink = ActiveConsole->Entry.Blink; 230 ActiveConsole->Entry.Blink->Flink = &SwapConsole->Entry; 231 ActiveConsole->Entry.Blink = &SwapConsole->Entry; 232 } 233 ActiveConsole = SwapConsole; 234 SwapConsole = NULL; 235 ConioDrawConsole(ActiveConsole->Console); 236 LeaveCriticalSection(&ActiveVirtConsLock); 237 return TRUE; 238 } 239 else 240 { 241 return FALSE; 242 } 243 } 244 #endif 245 246 static VOID 247 TuiCopyRect(PCHAR Dest, PTEXTMODE_SCREEN_BUFFER Buff, SMALL_RECT* Region) 248 { 249 UINT SrcDelta, DestDelta; 250 LONG i; 251 PCHAR_INFO Src, SrcEnd; 252 253 Src = ConioCoordToPointer(Buff, Region->Left, Region->Top); 254 SrcDelta = Buff->ScreenBufferSize.X * sizeof(CHAR_INFO); 255 SrcEnd = Buff->Buffer + Buff->ScreenBufferSize.Y * Buff->ScreenBufferSize.X * sizeof(CHAR_INFO); 256 DestDelta = ConioRectWidth(Region) * 2 /* 2 == sizeof(CHAR) + sizeof(BYTE) */; 257 for (i = Region->Top; i <= Region->Bottom; i++) 258 { 259 ConsoleOutputUnicodeToAnsiChar(Buff->Header.Console, (PCHAR)Dest, &Src->Char.UnicodeChar); 260 *(PBYTE)(Dest + 1) = (BYTE)Src->Attributes; 261 262 Src += SrcDelta; 263 if (SrcEnd <= Src) 264 { 265 Src -= Buff->ScreenBufferSize.Y * Buff->ScreenBufferSize.X * sizeof(CHAR_INFO); 266 } 267 Dest += DestDelta; 268 } 269 } 270 271 static LRESULT CALLBACK 272 TuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 273 { 274 /* 275 PTUI_CONSOLE_DATA TuiData = NULL; 276 PCONSRV_CONSOLE Console = NULL; 277 278 TuiData = TuiGetGuiData(hWnd); 279 if (TuiData == NULL) return 0; 280 */ 281 282 switch (msg) 283 { 284 case WM_CHAR: 285 case WM_SYSCHAR: 286 case WM_KEYDOWN: 287 case WM_SYSKEYDOWN: 288 case WM_KEYUP: 289 case WM_SYSKEYUP: 290 { 291 #if 0 292 if ((HIWORD(lParam) & KF_ALTDOWN) && wParam == VK_TAB) 293 { 294 // if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) != KF_REPEAT) 295 TuiSwapConsole(ShiftState & SHIFT_PRESSED ? -1 : 1); 296 297 break; 298 } 299 else if (wParam == VK_MENU /* && !Down */) 300 { 301 TuiSwapConsole(0); 302 break; 303 } 304 #endif 305 306 if (ConDrvValidateConsoleUnsafe((PCONSOLE)ActiveConsole->Console, CONSOLE_RUNNING, TRUE)) 307 { 308 MSG Message; 309 Message.hwnd = hWnd; 310 Message.message = msg; 311 Message.wParam = wParam; 312 Message.lParam = lParam; 313 314 ConioProcessKey(ActiveConsole->Console, &Message); 315 LeaveCriticalSection(&ActiveConsole->Console->Lock); 316 } 317 break; 318 } 319 320 case WM_ACTIVATE: 321 { 322 if (ConDrvValidateConsoleUnsafe((PCONSOLE)ActiveConsole->Console, CONSOLE_RUNNING, TRUE)) 323 { 324 if (LOWORD(wParam) != WA_INACTIVE) 325 { 326 SetFocus(hWnd); 327 ConioDrawConsole(ActiveConsole->Console); 328 } 329 LeaveCriticalSection(&ActiveConsole->Console->Lock); 330 } 331 break; 332 } 333 334 default: 335 break; 336 } 337 338 return DefWindowProcW(hWnd, msg, wParam, lParam); 339 } 340 341 static DWORD NTAPI 342 TuiConsoleThread(PVOID Param) 343 { 344 PTUI_CONSOLE_DATA TuiData = (PTUI_CONSOLE_DATA)Param; 345 PCONSRV_CONSOLE Console = TuiData->Console; 346 HWND NewWindow; 347 MSG msg; 348 349 NewWindow = CreateWindowW(TUI_CONSOLE_WINDOW_CLASS, 350 Console->Title.Buffer, 351 0, 352 -32000, -32000, 0, 0, 353 NULL, NULL, 354 ConSrvDllInstance, 355 (PVOID)Console); 356 if (NULL == NewWindow) 357 { 358 DPRINT1("CONSRV: Unable to create console window\n"); 359 return 1; 360 } 361 TuiData->hWindow = NewWindow; 362 363 SetForegroundWindow(TuiData->hWindow); 364 NtUserConsoleControl(ConsoleAcquireDisplayOwnership, NULL, 0); 365 366 while (GetMessageW(&msg, NULL, 0, 0)) 367 { 368 TranslateMessage(&msg); 369 DispatchMessageW(&msg); 370 } 371 372 return 0; 373 } 374 375 static BOOL 376 TuiInit(DWORD OemCP) 377 { 378 BOOL Success; 379 CONSOLE_SCREEN_BUFFER_INFO ScrInfo; 380 DWORD BytesReturned; 381 WNDCLASSEXW wc; 382 ATOM ConsoleClassAtom; 383 USHORT TextAttribute = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; 384 385 /* Exit if we were already initialized */ 386 if (ConsInitialized) return TRUE; 387 388 /* 389 * Initialize the TUI front-end: 390 * - load the console driver, 391 * - open BlueScreen device and enable it, 392 * - set default screen attributes, 393 * - grab the console size. 394 */ 395 ScmLoadDriver(L"Blue"); 396 397 ConsoleDeviceHandle = CreateFileW(L"\\\\.\\BlueScreen", 398 FILE_ALL_ACCESS, 399 0, NULL, 400 OPEN_EXISTING, 401 0, NULL); 402 if (ConsoleDeviceHandle == INVALID_HANDLE_VALUE) 403 { 404 DPRINT1("Failed to open BlueScreen.\n"); 405 return FALSE; 406 } 407 408 Success = TRUE; 409 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_RESET_SCREEN, 410 &Success, sizeof(Success), NULL, 0, 411 &BytesReturned, NULL)) 412 { 413 DPRINT1("Failed to enable the screen.\n"); 414 CloseHandle(ConsoleDeviceHandle); 415 return FALSE; 416 } 417 418 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_LOADFONT, 419 &OemCP, sizeof(OemCP), NULL, 0, 420 &BytesReturned, NULL)) 421 { 422 DPRINT1("Failed to load the font for codepage %d\n", OemCP); 423 /* Let's suppose the font is good enough to continue */ 424 } 425 426 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE, 427 &TextAttribute, sizeof(TextAttribute), NULL, 0, 428 &BytesReturned, NULL)) 429 { 430 DPRINT1("Failed to set text attribute.\n"); 431 } 432 433 ActiveConsole = NULL; 434 InitializeListHead(&VirtConsList); 435 InitializeCriticalSection(&ActiveVirtConsLock); 436 437 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 438 NULL, 0, &ScrInfo, sizeof(ScrInfo), &BytesReturned, NULL)) 439 { 440 DPRINT1("Failed to get console info.\n"); 441 Success = FALSE; 442 goto Quit; 443 } 444 PhysicalConsoleSize = ScrInfo.dwSize; 445 446 /* Register the TUI notification window class */ 447 RtlZeroMemory(&wc, sizeof(WNDCLASSEXW)); 448 wc.cbSize = sizeof(WNDCLASSEXW); 449 wc.lpszClassName = TUI_CONSOLE_WINDOW_CLASS; 450 wc.lpfnWndProc = TuiConsoleWndProc; 451 wc.cbWndExtra = 0; 452 wc.hInstance = ConSrvDllInstance; 453 454 ConsoleClassAtom = RegisterClassExW(&wc); 455 if (ConsoleClassAtom == 0) 456 { 457 DPRINT1("Failed to register TUI console wndproc.\n"); 458 Success = FALSE; 459 } 460 else 461 { 462 Success = TRUE; 463 } 464 465 Quit: 466 if (!Success) 467 { 468 DeleteCriticalSection(&ActiveVirtConsLock); 469 CloseHandle(ConsoleDeviceHandle); 470 } 471 472 ConsInitialized = Success; 473 return Success; 474 } 475 476 477 478 /****************************************************************************** 479 * TUI Console Driver * 480 ******************************************************************************/ 481 482 static VOID NTAPI 483 TuiDeinitFrontEnd(IN OUT PFRONTEND This /*, 484 IN PCONSRV_CONSOLE Console */); 485 486 static NTSTATUS NTAPI 487 TuiInitFrontEnd(IN OUT PFRONTEND This, 488 IN PCONSRV_CONSOLE Console) 489 { 490 PTUI_CONSOLE_DATA TuiData; 491 HANDLE ThreadHandle; 492 493 if (This == NULL || Console == NULL) 494 return STATUS_INVALID_PARAMETER; 495 496 if (GetType(Console->ActiveBuffer) != TEXTMODE_BUFFER) 497 return STATUS_INVALID_PARAMETER; 498 499 TuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(TUI_CONSOLE_DATA)); 500 if (!TuiData) 501 { 502 DPRINT1("CONSRV: Failed to create TUI_CONSOLE_DATA\n"); 503 return STATUS_UNSUCCESSFUL; 504 } 505 // Console->FrontEndIFace.Context = (PVOID)TuiData; 506 TuiData->Console = Console; 507 TuiData->ActiveBuffer = Console->ActiveBuffer; 508 TuiData->hWindow = NULL; 509 510 InitializeCriticalSection(&TuiData->Lock); 511 512 /* 513 * HACK: Resize the console since we don't support for now changing 514 * the console size when we display it with the hardware. 515 */ 516 // Console->ConsoleSize = PhysicalConsoleSize; 517 // ConioResizeBuffer(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), PhysicalConsoleSize); 518 519 // /* The console cannot be resized anymore */ 520 // Console->FixedSize = TRUE; // MUST be placed AFTER the call to ConioResizeBuffer !! 521 // // TermResizeTerminal(Console); 522 523 /* 524 * Contrary to what we do in the GUI front-end, here we create 525 * an input thread for each console. It will dispatch all the 526 * input messages to the proper console (on the GUI it is done 527 * via the default GUI dispatch thread). 528 */ 529 ThreadHandle = CreateThread(NULL, 530 0, 531 TuiConsoleThread, 532 (PVOID)TuiData, 533 0, 534 NULL); 535 if (NULL == ThreadHandle) 536 { 537 DPRINT1("CONSRV: Unable to create console thread\n"); 538 // TuiDeinitFrontEnd(Console); 539 TuiDeinitFrontEnd(This); 540 return STATUS_UNSUCCESSFUL; 541 } 542 CloseHandle(ThreadHandle); 543 544 /* 545 * Insert the newly created console in the list of virtual consoles 546 * and activate it (give it the focus). 547 */ 548 EnterCriticalSection(&ActiveVirtConsLock); 549 InsertTailList(&VirtConsList, &TuiData->Entry); 550 ActiveConsole = TuiData; 551 LeaveCriticalSection(&ActiveVirtConsLock); 552 553 /* Finally, initialize the frontend structure */ 554 This->Context = TuiData; 555 This->Context2 = NULL; 556 557 return STATUS_SUCCESS; 558 } 559 560 static VOID NTAPI 561 TuiDeinitFrontEnd(IN OUT PFRONTEND This) 562 { 563 // PCONSRV_CONSOLE Console = This->Console; 564 PTUI_CONSOLE_DATA TuiData = This->Context; 565 566 /* Close the notification window */ 567 DestroyWindow(TuiData->hWindow); 568 569 /* 570 * Set the active console to the next one 571 * and remove the console from the list. 572 */ 573 EnterCriticalSection(&ActiveVirtConsLock); 574 ActiveConsole = GetNextConsole(TuiData); 575 RemoveEntryList(&TuiData->Entry); 576 577 // /* Switch to next console */ 578 // if (ActiveConsole == TuiData) 579 // if (ActiveConsole->Console == Console) 580 // { 581 // ActiveConsole = (TuiData->Entry.Flink != TuiData->Entry ? GetNextConsole(TuiData) : NULL); 582 // } 583 584 // if (GetNextConsole(TuiData) != TuiData) 585 // { 586 // TuiData->Entry.Blink->Flink = TuiData->Entry.Flink; 587 // TuiData->Entry.Flink->Blink = TuiData->Entry.Blink; 588 // } 589 590 LeaveCriticalSection(&ActiveVirtConsLock); 591 592 /* Switch to the next console */ 593 if (NULL != ActiveConsole) ConioDrawConsole(ActiveConsole->Console); 594 595 This->Context = NULL; 596 DeleteCriticalSection(&TuiData->Lock); 597 ConsoleFreeHeap(TuiData); 598 } 599 600 static VOID NTAPI 601 TuiDrawRegion(IN OUT PFRONTEND This, 602 SMALL_RECT* Region) 603 { 604 PTUI_CONSOLE_DATA TuiData = This->Context; 605 PCONSOLE_SCREEN_BUFFER Buff = TuiData->Console->ActiveBuffer; 606 PCONSOLE_DRAW ConsoleDraw; 607 DWORD BytesReturned; 608 UINT ConsoleDrawSize; 609 610 if (TuiData != ActiveConsole) return; 611 if (GetType(Buff) != TEXTMODE_BUFFER) return; 612 613 ConsoleDrawSize = sizeof(CONSOLE_DRAW) + 614 (ConioRectWidth(Region) * ConioRectHeight(Region)) * 2; 615 ConsoleDraw = ConsoleAllocHeap(0, ConsoleDrawSize); 616 if (NULL == ConsoleDraw) 617 { 618 DPRINT1("ConsoleAllocHeap failed\n"); 619 return; 620 } 621 ConsoleDraw->X = Region->Left; 622 ConsoleDraw->Y = Region->Top; 623 ConsoleDraw->SizeX = ConioRectWidth(Region); 624 ConsoleDraw->SizeY = ConioRectHeight(Region); 625 ConsoleDraw->CursorX = Buff->CursorPosition.X; 626 ConsoleDraw->CursorY = Buff->CursorPosition.Y; 627 628 TuiCopyRect((PCHAR)(ConsoleDraw + 1), (PTEXTMODE_SCREEN_BUFFER)Buff, Region); 629 630 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_DRAW, 631 NULL, 0, ConsoleDraw, ConsoleDrawSize, &BytesReturned, NULL)) 632 { 633 DPRINT1("Failed to draw console\n"); 634 ConsoleFreeHeap(ConsoleDraw); 635 return; 636 } 637 638 ConsoleFreeHeap(ConsoleDraw); 639 } 640 641 static VOID NTAPI 642 TuiWriteStream(IN OUT PFRONTEND This, 643 SMALL_RECT* Region, 644 SHORT CursorStartX, 645 SHORT CursorStartY, 646 UINT ScrolledLines, 647 PWCHAR Buffer, 648 UINT Length) 649 { 650 PTUI_CONSOLE_DATA TuiData = This->Context; 651 PCONSOLE_SCREEN_BUFFER Buff = TuiData->Console->ActiveBuffer; 652 PCHAR NewBuffer; 653 ULONG NewLength; 654 DWORD BytesWritten; 655 656 if (TuiData != ActiveConsole) return; 657 if (GetType(Buff) != TEXTMODE_BUFFER) return; 658 659 NewLength = WideCharToMultiByte(TuiData->Console->OutputCodePage, 0, 660 Buffer, Length, 661 NULL, 0, NULL, NULL); 662 NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewLength * sizeof(CHAR)); 663 if (!NewBuffer) return; 664 665 WideCharToMultiByte(TuiData->Console->OutputCodePage, 0, 666 Buffer, Length, 667 NewBuffer, NewLength, NULL, NULL); 668 669 if (!WriteFile(ConsoleDeviceHandle, NewBuffer, NewLength * sizeof(CHAR), &BytesWritten, NULL)) 670 { 671 DPRINT1("Error writing to BlueScreen\n"); 672 } 673 674 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer); 675 } 676 677 static VOID NTAPI 678 TuiRingBell(IN OUT PFRONTEND This) 679 { 680 Beep(800, 200); 681 } 682 683 static BOOL NTAPI 684 TuiSetCursorInfo(IN OUT PFRONTEND This, 685 PCONSOLE_SCREEN_BUFFER Buff) 686 { 687 PTUI_CONSOLE_DATA TuiData = This->Context; 688 CONSOLE_CURSOR_INFO Info; 689 DWORD BytesReturned; 690 691 if (TuiData != ActiveConsole) return TRUE; 692 if (TuiData->Console->ActiveBuffer != Buff) return TRUE; 693 if (GetType(Buff) != TEXTMODE_BUFFER) return FALSE; 694 695 Info.dwSize = ConioEffectiveCursorSize(TuiData->Console, 100); 696 Info.bVisible = Buff->CursorInfo.bVisible; 697 698 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_CURSOR_INFO, 699 &Info, sizeof(Info), NULL, 0, &BytesReturned, NULL)) 700 { 701 DPRINT1( "Failed to set cursor info\n" ); 702 return FALSE; 703 } 704 705 return TRUE; 706 } 707 708 static BOOL NTAPI 709 TuiSetScreenInfo(IN OUT PFRONTEND This, 710 PCONSOLE_SCREEN_BUFFER Buff, 711 SHORT OldCursorX, 712 SHORT OldCursorY) 713 { 714 PTUI_CONSOLE_DATA TuiData = This->Context; 715 CONSOLE_SCREEN_BUFFER_INFO Info; 716 DWORD BytesReturned; 717 718 if (TuiData != ActiveConsole) return TRUE; 719 if (TuiData->Console->ActiveBuffer != Buff) return TRUE; 720 if (GetType(Buff) != TEXTMODE_BUFFER) return FALSE; 721 722 Info.dwCursorPosition = Buff->CursorPosition; 723 Info.wAttributes = ((PTEXTMODE_SCREEN_BUFFER)Buff)->ScreenDefaultAttrib; 724 725 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, 726 &Info, sizeof(CONSOLE_SCREEN_BUFFER_INFO), NULL, 0, 727 &BytesReturned, NULL)) 728 { 729 DPRINT1( "Failed to set cursor position\n" ); 730 return FALSE; 731 } 732 733 return TRUE; 734 } 735 736 static VOID NTAPI 737 TuiResizeTerminal(IN OUT PFRONTEND This) 738 { 739 } 740 741 static VOID NTAPI 742 TuiSetActiveScreenBuffer(IN OUT PFRONTEND This) 743 { 744 // PGUI_CONSOLE_DATA GuiData = This->Context; 745 // PCONSOLE_SCREEN_BUFFER ActiveBuffer; 746 // HPALETTE hPalette; 747 748 // EnterCriticalSection(&GuiData->Lock); 749 // GuiData->WindowSizeLock = TRUE; 750 751 // InterlockedExchangePointer(&GuiData->ActiveBuffer, 752 // ConDrvGetActiveScreenBuffer(GuiData->Console)); 753 754 // GuiData->WindowSizeLock = FALSE; 755 // LeaveCriticalSection(&GuiData->Lock); 756 757 // ActiveBuffer = GuiData->ActiveBuffer; 758 759 // /* Change the current palette */ 760 // if (ActiveBuffer->PaletteHandle == NULL) 761 // { 762 // hPalette = GuiData->hSysPalette; 763 // } 764 // else 765 // { 766 // hPalette = ActiveBuffer->PaletteHandle; 767 // } 768 769 // DPRINT("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette); 770 771 // /* Set the new palette for the framebuffer */ 772 // SelectPalette(GuiData->hMemDC, hPalette, FALSE); 773 774 // /* Specify the use of the system palette for the framebuffer */ 775 // SetSystemPaletteUse(GuiData->hMemDC, ActiveBuffer->PaletteUsage); 776 777 // /* Realize the (logical) palette */ 778 // RealizePalette(GuiData->hMemDC); 779 780 // GuiResizeTerminal(This); 781 // // ConioDrawConsole(Console); 782 } 783 784 static VOID NTAPI 785 TuiReleaseScreenBuffer(IN OUT PFRONTEND This, 786 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer) 787 { 788 // PGUI_CONSOLE_DATA GuiData = This->Context; 789 790 // /* 791 // * If we were notified to release a screen buffer that is not actually 792 // * ours, then just ignore the notification... 793 // */ 794 // if (ScreenBuffer != GuiData->ActiveBuffer) return; 795 796 // /* 797 // * ... else, we must release our active buffer. Two cases are present: 798 // * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console 799 // * active screen buffer, then we can safely switch to it. 800 // * - If ScreenBuffer IS the console active screen buffer, we must release 801 // * it ONLY. 802 // */ 803 804 // /* Release the old active palette and set the default one */ 805 // if (GetCurrentObject(GuiData->hMemDC, OBJ_PAL) == ScreenBuffer->PaletteHandle) 806 // { 807 // /* Set the new palette */ 808 // SelectPalette(GuiData->hMemDC, GuiData->hSysPalette, FALSE); 809 // } 810 811 // /* Set the adequate active screen buffer */ 812 // if (ScreenBuffer != GuiData->Console->ActiveBuffer) 813 // { 814 // GuiSetActiveScreenBuffer(This); 815 // } 816 // else 817 // { 818 // EnterCriticalSection(&GuiData->Lock); 819 // GuiData->WindowSizeLock = TRUE; 820 821 // InterlockedExchangePointer(&GuiData->ActiveBuffer, NULL); 822 823 // GuiData->WindowSizeLock = FALSE; 824 // LeaveCriticalSection(&GuiData->Lock); 825 // } 826 } 827 828 static VOID NTAPI 829 TuiRefreshInternalInfo(IN OUT PFRONTEND This) 830 { 831 } 832 833 static VOID NTAPI 834 TuiChangeTitle(IN OUT PFRONTEND This) 835 { 836 } 837 838 static BOOL NTAPI 839 TuiChangeIcon(IN OUT PFRONTEND This, 840 HICON IconHandle) 841 { 842 return TRUE; 843 } 844 845 static HDESK NTAPI 846 TuiGetThreadConsoleDesktop(IN OUT PFRONTEND This) 847 { 848 // PTUI_CONSOLE_DATA TuiData = This->Context; 849 return NULL; 850 } 851 852 static HWND NTAPI 853 TuiGetConsoleWindowHandle(IN OUT PFRONTEND This) 854 { 855 PTUI_CONSOLE_DATA TuiData = This->Context; 856 return TuiData->hWindow; 857 } 858 859 static VOID NTAPI 860 TuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This, 861 PCOORD pSize) 862 { 863 if (!pSize) return; 864 *pSize = PhysicalConsoleSize; 865 } 866 867 static BOOL NTAPI 868 TuiGetSelectionInfo(IN OUT PFRONTEND This, 869 PCONSOLE_SELECTION_INFO pSelectionInfo) 870 { 871 return TRUE; 872 } 873 874 static BOOL NTAPI 875 TuiSetPalette(IN OUT PFRONTEND This, 876 HPALETTE PaletteHandle, 877 UINT PaletteUsage) 878 { 879 return TRUE; 880 } 881 882 static ULONG NTAPI 883 TuiGetDisplayMode(IN OUT PFRONTEND This) 884 { 885 return CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN; 886 } 887 888 static BOOL NTAPI 889 TuiSetDisplayMode(IN OUT PFRONTEND This, 890 ULONG NewMode) 891 { 892 // if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE)) 893 // return FALSE; 894 return TRUE; 895 } 896 897 static INT NTAPI 898 TuiShowMouseCursor(IN OUT PFRONTEND This, 899 BOOL Show) 900 { 901 return 0; 902 } 903 904 static BOOL NTAPI 905 TuiSetMouseCursor(IN OUT PFRONTEND This, 906 HCURSOR CursorHandle) 907 { 908 return TRUE; 909 } 910 911 static HMENU NTAPI 912 TuiMenuControl(IN OUT PFRONTEND This, 913 UINT CmdIdLow, 914 UINT CmdIdHigh) 915 { 916 return NULL; 917 } 918 919 static BOOL NTAPI 920 TuiSetMenuClose(IN OUT PFRONTEND This, 921 BOOL Enable) 922 { 923 return TRUE; 924 } 925 926 static FRONTEND_VTBL TuiVtbl = 927 { 928 TuiInitFrontEnd, 929 TuiDeinitFrontEnd, 930 TuiDrawRegion, 931 TuiWriteStream, 932 TuiRingBell, 933 TuiSetCursorInfo, 934 TuiSetScreenInfo, 935 TuiResizeTerminal, 936 TuiSetActiveScreenBuffer, 937 TuiReleaseScreenBuffer, 938 TuiRefreshInternalInfo, 939 TuiChangeTitle, 940 TuiChangeIcon, 941 TuiGetThreadConsoleDesktop, 942 TuiGetConsoleWindowHandle, 943 TuiGetLargestConsoleWindowSize, 944 TuiGetSelectionInfo, 945 TuiSetPalette, 946 TuiGetDisplayMode, 947 TuiSetDisplayMode, 948 TuiShowMouseCursor, 949 TuiSetMouseCursor, 950 TuiMenuControl, 951 TuiSetMenuClose, 952 }; 953 954 static BOOLEAN 955 IsConsoleMode(VOID) 956 { 957 return (BOOLEAN)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE); 958 } 959 960 NTSTATUS NTAPI 961 TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd, 962 IN OUT PCONSOLE_STATE_INFO ConsoleInfo, 963 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo, 964 IN HANDLE ConsoleLeaderProcessHandle) 965 { 966 if (FrontEnd == NULL || ConsoleInfo == NULL) 967 return STATUS_INVALID_PARAMETER; 968 969 /* We must be in console mode already */ 970 if (!IsConsoleMode()) return STATUS_UNSUCCESSFUL; 971 972 /* Initialize the TUI terminal emulator */ 973 if (!TuiInit(ConsoleInfo->CodePage)) return STATUS_UNSUCCESSFUL; 974 975 /* Finally, initialize the frontend structure */ 976 FrontEnd->Vtbl = &TuiVtbl; 977 FrontEnd->Context = NULL; 978 FrontEnd->Context2 = NULL; 979 980 return STATUS_SUCCESS; 981 } 982 983 NTSTATUS NTAPI 984 TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd) 985 { 986 if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER; 987 if (FrontEnd->Context) TuiDeinitFrontEnd(FrontEnd); 988 989 return STATUS_SUCCESS; 990 } 991 992 #endif 993 994 /* EOF */ 995