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 Ret = FALSE; 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 * - set default screen attributes, 392 * - grab the console size. 393 */ 394 ScmLoadDriver(L"Blue"); 395 396 ConsoleDeviceHandle = CreateFileW(L"\\\\.\\BlueScreen", 397 FILE_ALL_ACCESS, 398 0, NULL, 399 OPEN_EXISTING, 400 0, NULL); 401 if (ConsoleDeviceHandle == INVALID_HANDLE_VALUE) 402 { 403 DPRINT1("Failed to open BlueScreen.\n"); 404 return FALSE; 405 } 406 407 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_LOADFONT, 408 &OemCP, sizeof(OemCP), NULL, 0, 409 &BytesReturned, NULL)) 410 { 411 DPRINT1("Failed to load the font for codepage %d\n", OemCP); 412 /* Let's suppose the font is good enough to continue */ 413 } 414 415 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE, 416 &TextAttribute, sizeof(TextAttribute), NULL, 0, 417 &BytesReturned, NULL)) 418 { 419 DPRINT1("Failed to set text attribute\n"); 420 } 421 422 ActiveConsole = NULL; 423 InitializeListHead(&VirtConsList); 424 InitializeCriticalSection(&ActiveVirtConsLock); 425 426 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 427 NULL, 0, &ScrInfo, sizeof(ScrInfo), &BytesReturned, NULL)) 428 { 429 DPRINT1("Failed to get console info\n"); 430 Ret = FALSE; 431 goto Quit; 432 } 433 PhysicalConsoleSize = ScrInfo.dwSize; 434 435 /* Register the TUI notification window class */ 436 RtlZeroMemory(&wc, sizeof(WNDCLASSEXW)); 437 wc.cbSize = sizeof(WNDCLASSEXW); 438 wc.lpszClassName = TUI_CONSOLE_WINDOW_CLASS; 439 wc.lpfnWndProc = TuiConsoleWndProc; 440 wc.cbWndExtra = 0; 441 wc.hInstance = ConSrvDllInstance; 442 443 ConsoleClassAtom = RegisterClassExW(&wc); 444 if (ConsoleClassAtom == 0) 445 { 446 DPRINT1("Failed to register TUI console wndproc\n"); 447 Ret = FALSE; 448 } 449 else 450 { 451 Ret = TRUE; 452 } 453 454 Quit: 455 if (!Ret) 456 { 457 DeleteCriticalSection(&ActiveVirtConsLock); 458 CloseHandle(ConsoleDeviceHandle); 459 } 460 461 ConsInitialized = Ret; 462 return Ret; 463 } 464 465 466 467 /****************************************************************************** 468 * TUI Console Driver * 469 ******************************************************************************/ 470 471 static VOID NTAPI 472 TuiDeinitFrontEnd(IN OUT PFRONTEND This /*, 473 IN PCONSRV_CONSOLE Console */); 474 475 static NTSTATUS NTAPI 476 TuiInitFrontEnd(IN OUT PFRONTEND This, 477 IN PCONSRV_CONSOLE Console) 478 { 479 PTUI_CONSOLE_DATA TuiData; 480 HANDLE ThreadHandle; 481 482 if (This == NULL || Console == NULL) 483 return STATUS_INVALID_PARAMETER; 484 485 if (GetType(Console->ActiveBuffer) != TEXTMODE_BUFFER) 486 return STATUS_INVALID_PARAMETER; 487 488 TuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(TUI_CONSOLE_DATA)); 489 if (!TuiData) 490 { 491 DPRINT1("CONSRV: Failed to create TUI_CONSOLE_DATA\n"); 492 return STATUS_UNSUCCESSFUL; 493 } 494 // Console->FrontEndIFace.Context = (PVOID)TuiData; 495 TuiData->Console = Console; 496 TuiData->ActiveBuffer = Console->ActiveBuffer; 497 TuiData->hWindow = NULL; 498 499 InitializeCriticalSection(&TuiData->Lock); 500 501 /* 502 * HACK: Resize the console since we don't support for now changing 503 * the console size when we display it with the hardware. 504 */ 505 // Console->ConsoleSize = PhysicalConsoleSize; 506 // ConioResizeBuffer(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), PhysicalConsoleSize); 507 508 // /* The console cannot be resized anymore */ 509 // Console->FixedSize = TRUE; // MUST be placed AFTER the call to ConioResizeBuffer !! 510 // // TermResizeTerminal(Console); 511 512 /* 513 * Contrary to what we do in the GUI front-end, here we create 514 * an input thread for each console. It will dispatch all the 515 * input messages to the proper console (on the GUI it is done 516 * via the default GUI dispatch thread). 517 */ 518 ThreadHandle = CreateThread(NULL, 519 0, 520 TuiConsoleThread, 521 (PVOID)TuiData, 522 0, 523 NULL); 524 if (NULL == ThreadHandle) 525 { 526 DPRINT1("CONSRV: Unable to create console thread\n"); 527 // TuiDeinitFrontEnd(Console); 528 TuiDeinitFrontEnd(This); 529 return STATUS_UNSUCCESSFUL; 530 } 531 CloseHandle(ThreadHandle); 532 533 /* 534 * Insert the newly created console in the list of virtual consoles 535 * and activate it (give it the focus). 536 */ 537 EnterCriticalSection(&ActiveVirtConsLock); 538 InsertTailList(&VirtConsList, &TuiData->Entry); 539 ActiveConsole = TuiData; 540 LeaveCriticalSection(&ActiveVirtConsLock); 541 542 /* Finally, initialize the frontend structure */ 543 This->Context = TuiData; 544 This->Context2 = NULL; 545 546 return STATUS_SUCCESS; 547 } 548 549 static VOID NTAPI 550 TuiDeinitFrontEnd(IN OUT PFRONTEND This) 551 { 552 // PCONSRV_CONSOLE Console = This->Console; 553 PTUI_CONSOLE_DATA TuiData = This->Context; 554 555 /* Close the notification window */ 556 DestroyWindow(TuiData->hWindow); 557 558 /* 559 * Set the active console to the next one 560 * and remove the console from the list. 561 */ 562 EnterCriticalSection(&ActiveVirtConsLock); 563 ActiveConsole = GetNextConsole(TuiData); 564 RemoveEntryList(&TuiData->Entry); 565 566 // /* Switch to next console */ 567 // if (ActiveConsole == TuiData) 568 // if (ActiveConsole->Console == Console) 569 // { 570 // ActiveConsole = (TuiData->Entry.Flink != TuiData->Entry ? GetNextConsole(TuiData) : NULL); 571 // } 572 573 // if (GetNextConsole(TuiData) != TuiData) 574 // { 575 // TuiData->Entry.Blink->Flink = TuiData->Entry.Flink; 576 // TuiData->Entry.Flink->Blink = TuiData->Entry.Blink; 577 // } 578 579 LeaveCriticalSection(&ActiveVirtConsLock); 580 581 /* Switch to the next console */ 582 if (NULL != ActiveConsole) ConioDrawConsole(ActiveConsole->Console); 583 584 This->Context = NULL; 585 DeleteCriticalSection(&TuiData->Lock); 586 ConsoleFreeHeap(TuiData); 587 } 588 589 static VOID NTAPI 590 TuiDrawRegion(IN OUT PFRONTEND This, 591 SMALL_RECT* Region) 592 { 593 PTUI_CONSOLE_DATA TuiData = This->Context; 594 PCONSOLE_SCREEN_BUFFER Buff = TuiData->Console->ActiveBuffer; 595 PCONSOLE_DRAW ConsoleDraw; 596 DWORD BytesReturned; 597 UINT ConsoleDrawSize; 598 599 if (TuiData != ActiveConsole) return; 600 if (GetType(Buff) != TEXTMODE_BUFFER) return; 601 602 ConsoleDrawSize = sizeof(CONSOLE_DRAW) + 603 (ConioRectWidth(Region) * ConioRectHeight(Region)) * 2; 604 ConsoleDraw = ConsoleAllocHeap(0, ConsoleDrawSize); 605 if (NULL == ConsoleDraw) 606 { 607 DPRINT1("ConsoleAllocHeap failed\n"); 608 return; 609 } 610 ConsoleDraw->X = Region->Left; 611 ConsoleDraw->Y = Region->Top; 612 ConsoleDraw->SizeX = ConioRectWidth(Region); 613 ConsoleDraw->SizeY = ConioRectHeight(Region); 614 ConsoleDraw->CursorX = Buff->CursorPosition.X; 615 ConsoleDraw->CursorY = Buff->CursorPosition.Y; 616 617 TuiCopyRect((PCHAR)(ConsoleDraw + 1), (PTEXTMODE_SCREEN_BUFFER)Buff, Region); 618 619 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_DRAW, 620 NULL, 0, ConsoleDraw, ConsoleDrawSize, &BytesReturned, NULL)) 621 { 622 DPRINT1("Failed to draw console\n"); 623 ConsoleFreeHeap(ConsoleDraw); 624 return; 625 } 626 627 ConsoleFreeHeap(ConsoleDraw); 628 } 629 630 static VOID NTAPI 631 TuiWriteStream(IN OUT PFRONTEND This, 632 SMALL_RECT* Region, 633 SHORT CursorStartX, 634 SHORT CursorStartY, 635 UINT ScrolledLines, 636 PWCHAR Buffer, 637 UINT Length) 638 { 639 PTUI_CONSOLE_DATA TuiData = This->Context; 640 PCONSOLE_SCREEN_BUFFER Buff = TuiData->Console->ActiveBuffer; 641 PCHAR NewBuffer; 642 ULONG NewLength; 643 DWORD BytesWritten; 644 645 if (TuiData != ActiveConsole) return; 646 if (GetType(Buff) != TEXTMODE_BUFFER) return; 647 648 NewLength = WideCharToMultiByte(TuiData->Console->OutputCodePage, 0, 649 Buffer, Length, 650 NULL, 0, NULL, NULL); 651 NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewLength * sizeof(CHAR)); 652 if (!NewBuffer) return; 653 654 WideCharToMultiByte(TuiData->Console->OutputCodePage, 0, 655 Buffer, Length, 656 NewBuffer, NewLength, NULL, NULL); 657 658 if (!WriteFile(ConsoleDeviceHandle, NewBuffer, NewLength * sizeof(CHAR), &BytesWritten, NULL)) 659 { 660 DPRINT1("Error writing to BlueScreen\n"); 661 } 662 663 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer); 664 } 665 666 static VOID NTAPI 667 TuiRingBell(IN OUT PFRONTEND This) 668 { 669 Beep(800, 200); 670 } 671 672 static BOOL NTAPI 673 TuiSetCursorInfo(IN OUT PFRONTEND This, 674 PCONSOLE_SCREEN_BUFFER Buff) 675 { 676 PTUI_CONSOLE_DATA TuiData = This->Context; 677 CONSOLE_CURSOR_INFO Info; 678 DWORD BytesReturned; 679 680 if (TuiData != ActiveConsole) return TRUE; 681 if (TuiData->Console->ActiveBuffer != Buff) return TRUE; 682 if (GetType(Buff) != TEXTMODE_BUFFER) return FALSE; 683 684 Info.dwSize = ConioEffectiveCursorSize(TuiData->Console, 100); 685 Info.bVisible = Buff->CursorInfo.bVisible; 686 687 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_CURSOR_INFO, 688 &Info, sizeof(Info), NULL, 0, &BytesReturned, NULL)) 689 { 690 DPRINT1( "Failed to set cursor info\n" ); 691 return FALSE; 692 } 693 694 return TRUE; 695 } 696 697 static BOOL NTAPI 698 TuiSetScreenInfo(IN OUT PFRONTEND This, 699 PCONSOLE_SCREEN_BUFFER Buff, 700 SHORT OldCursorX, 701 SHORT OldCursorY) 702 { 703 PTUI_CONSOLE_DATA TuiData = This->Context; 704 CONSOLE_SCREEN_BUFFER_INFO Info; 705 DWORD BytesReturned; 706 707 if (TuiData != ActiveConsole) return TRUE; 708 if (TuiData->Console->ActiveBuffer != Buff) return TRUE; 709 if (GetType(Buff) != TEXTMODE_BUFFER) return FALSE; 710 711 Info.dwCursorPosition = Buff->CursorPosition; 712 Info.wAttributes = ((PTEXTMODE_SCREEN_BUFFER)Buff)->ScreenDefaultAttrib; 713 714 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, 715 &Info, sizeof(CONSOLE_SCREEN_BUFFER_INFO), NULL, 0, 716 &BytesReturned, NULL)) 717 { 718 DPRINT1( "Failed to set cursor position\n" ); 719 return FALSE; 720 } 721 722 return TRUE; 723 } 724 725 static VOID NTAPI 726 TuiResizeTerminal(IN OUT PFRONTEND This) 727 { 728 } 729 730 static VOID NTAPI 731 TuiSetActiveScreenBuffer(IN OUT PFRONTEND This) 732 { 733 // PGUI_CONSOLE_DATA GuiData = This->Context; 734 // PCONSOLE_SCREEN_BUFFER ActiveBuffer; 735 // HPALETTE hPalette; 736 737 // EnterCriticalSection(&GuiData->Lock); 738 // GuiData->WindowSizeLock = TRUE; 739 740 // InterlockedExchangePointer(&GuiData->ActiveBuffer, 741 // ConDrvGetActiveScreenBuffer(GuiData->Console)); 742 743 // GuiData->WindowSizeLock = FALSE; 744 // LeaveCriticalSection(&GuiData->Lock); 745 746 // ActiveBuffer = GuiData->ActiveBuffer; 747 748 // /* Change the current palette */ 749 // if (ActiveBuffer->PaletteHandle == NULL) 750 // { 751 // hPalette = GuiData->hSysPalette; 752 // } 753 // else 754 // { 755 // hPalette = ActiveBuffer->PaletteHandle; 756 // } 757 758 // DPRINT("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette); 759 760 // /* Set the new palette for the framebuffer */ 761 // SelectPalette(GuiData->hMemDC, hPalette, FALSE); 762 763 // /* Specify the use of the system palette for the framebuffer */ 764 // SetSystemPaletteUse(GuiData->hMemDC, ActiveBuffer->PaletteUsage); 765 766 // /* Realize the (logical) palette */ 767 // RealizePalette(GuiData->hMemDC); 768 769 // GuiResizeTerminal(This); 770 // // ConioDrawConsole(Console); 771 } 772 773 static VOID NTAPI 774 TuiReleaseScreenBuffer(IN OUT PFRONTEND This, 775 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer) 776 { 777 // PGUI_CONSOLE_DATA GuiData = This->Context; 778 779 // /* 780 // * If we were notified to release a screen buffer that is not actually 781 // * ours, then just ignore the notification... 782 // */ 783 // if (ScreenBuffer != GuiData->ActiveBuffer) return; 784 785 // /* 786 // * ... else, we must release our active buffer. Two cases are present: 787 // * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console 788 // * active screen buffer, then we can safely switch to it. 789 // * - If ScreenBuffer IS the console active screen buffer, we must release 790 // * it ONLY. 791 // */ 792 793 // /* Release the old active palette and set the default one */ 794 // if (GetCurrentObject(GuiData->hMemDC, OBJ_PAL) == ScreenBuffer->PaletteHandle) 795 // { 796 // /* Set the new palette */ 797 // SelectPalette(GuiData->hMemDC, GuiData->hSysPalette, FALSE); 798 // } 799 800 // /* Set the adequate active screen buffer */ 801 // if (ScreenBuffer != GuiData->Console->ActiveBuffer) 802 // { 803 // GuiSetActiveScreenBuffer(This); 804 // } 805 // else 806 // { 807 // EnterCriticalSection(&GuiData->Lock); 808 // GuiData->WindowSizeLock = TRUE; 809 810 // InterlockedExchangePointer(&GuiData->ActiveBuffer, NULL); 811 812 // GuiData->WindowSizeLock = FALSE; 813 // LeaveCriticalSection(&GuiData->Lock); 814 // } 815 } 816 817 static VOID NTAPI 818 TuiRefreshInternalInfo(IN OUT PFRONTEND This) 819 { 820 } 821 822 static VOID NTAPI 823 TuiChangeTitle(IN OUT PFRONTEND This) 824 { 825 } 826 827 static BOOL NTAPI 828 TuiChangeIcon(IN OUT PFRONTEND This, 829 HICON IconHandle) 830 { 831 return TRUE; 832 } 833 834 static HDESK NTAPI 835 TuiGetThreadConsoleDesktop(IN OUT PFRONTEND This) 836 { 837 // PTUI_CONSOLE_DATA TuiData = This->Context; 838 return NULL; 839 } 840 841 static HWND NTAPI 842 TuiGetConsoleWindowHandle(IN OUT PFRONTEND This) 843 { 844 PTUI_CONSOLE_DATA TuiData = This->Context; 845 return TuiData->hWindow; 846 } 847 848 static VOID NTAPI 849 TuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This, 850 PCOORD pSize) 851 { 852 if (!pSize) return; 853 *pSize = PhysicalConsoleSize; 854 } 855 856 static BOOL NTAPI 857 TuiGetSelectionInfo(IN OUT PFRONTEND This, 858 PCONSOLE_SELECTION_INFO pSelectionInfo) 859 { 860 return TRUE; 861 } 862 863 static BOOL NTAPI 864 TuiSetPalette(IN OUT PFRONTEND This, 865 HPALETTE PaletteHandle, 866 UINT PaletteUsage) 867 { 868 return TRUE; 869 } 870 871 static ULONG NTAPI 872 TuiGetDisplayMode(IN OUT PFRONTEND This) 873 { 874 return CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN; 875 } 876 877 static BOOL NTAPI 878 TuiSetDisplayMode(IN OUT PFRONTEND This, 879 ULONG NewMode) 880 { 881 // if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE)) 882 // return FALSE; 883 return TRUE; 884 } 885 886 static INT NTAPI 887 TuiShowMouseCursor(IN OUT PFRONTEND This, 888 BOOL Show) 889 { 890 return 0; 891 } 892 893 static BOOL NTAPI 894 TuiSetMouseCursor(IN OUT PFRONTEND This, 895 HCURSOR CursorHandle) 896 { 897 return TRUE; 898 } 899 900 static HMENU NTAPI 901 TuiMenuControl(IN OUT PFRONTEND This, 902 UINT CmdIdLow, 903 UINT CmdIdHigh) 904 { 905 return NULL; 906 } 907 908 static BOOL NTAPI 909 TuiSetMenuClose(IN OUT PFRONTEND This, 910 BOOL Enable) 911 { 912 return TRUE; 913 } 914 915 static FRONTEND_VTBL TuiVtbl = 916 { 917 TuiInitFrontEnd, 918 TuiDeinitFrontEnd, 919 TuiDrawRegion, 920 TuiWriteStream, 921 TuiRingBell, 922 TuiSetCursorInfo, 923 TuiSetScreenInfo, 924 TuiResizeTerminal, 925 TuiSetActiveScreenBuffer, 926 TuiReleaseScreenBuffer, 927 TuiRefreshInternalInfo, 928 TuiChangeTitle, 929 TuiChangeIcon, 930 TuiGetThreadConsoleDesktop, 931 TuiGetConsoleWindowHandle, 932 TuiGetLargestConsoleWindowSize, 933 TuiGetSelectionInfo, 934 TuiSetPalette, 935 TuiGetDisplayMode, 936 TuiSetDisplayMode, 937 TuiShowMouseCursor, 938 TuiSetMouseCursor, 939 TuiMenuControl, 940 TuiSetMenuClose, 941 }; 942 943 static BOOLEAN 944 IsConsoleMode(VOID) 945 { 946 return (BOOLEAN)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE); 947 } 948 949 NTSTATUS NTAPI 950 TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd, 951 IN OUT PCONSOLE_STATE_INFO ConsoleInfo, 952 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo, 953 IN HANDLE ConsoleLeaderProcessHandle) 954 { 955 if (FrontEnd == NULL || ConsoleInfo == NULL) 956 return STATUS_INVALID_PARAMETER; 957 958 /* We must be in console mode already */ 959 if (!IsConsoleMode()) return STATUS_UNSUCCESSFUL; 960 961 /* Initialize the TUI terminal emulator */ 962 if (!TuiInit(ConsoleInfo->CodePage)) return STATUS_UNSUCCESSFUL; 963 964 /* Finally, initialize the frontend structure */ 965 FrontEnd->Vtbl = &TuiVtbl; 966 FrontEnd->Context = NULL; 967 FrontEnd->Context2 = NULL; 968 969 return STATUS_SUCCESS; 970 } 971 972 NTSTATUS NTAPI 973 TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd) 974 { 975 if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER; 976 if (FrontEnd->Context) TuiDeinitFrontEnd(FrontEnd); 977 978 return STATUS_SUCCESS; 979 } 980 981 #endif 982 983 /* EOF */ 984