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