1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Console Server DLL 4 * FILE: win32ss/user/winsrv/consrv/frontends/gui/conwnd.c 5 * PURPOSE: GUI Console Window Class 6 * PROGRAMMERS: G� van Geldorp 7 * Johannes Anderwald 8 * Jeffrey Morlan 9 * Hermes Belusca-Maito (hermes.belusca@sfr.fr) 10 * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 11 */ 12 13 /* INCLUDES *******************************************************************/ 14 15 #include <consrv.h> 16 #include <intrin.h> 17 #include <windowsx.h> 18 #include <shellapi.h> 19 20 #define NDEBUG 21 #include <debug.h> 22 23 #include "font.h" 24 #include "guiterm.h" 25 #include "resource.h" 26 27 /* GLOBALS ********************************************************************/ 28 29 // #define PM_CREATE_CONSOLE (WM_APP + 1) 30 // #define PM_DESTROY_CONSOLE (WM_APP + 2) 31 32 // See guiterm.c 33 #define CONGUI_MIN_WIDTH 10 34 #define CONGUI_MIN_HEIGHT 10 35 #define CONGUI_UPDATE_TIME 0 36 #define CONGUI_UPDATE_TIMER 1 37 38 #define CURSOR_BLINK_TIME 500 39 40 41 /**************************************************************\ 42 \** Define the Console Leader Process for the console window **/ 43 #define GWLP_CONWND_ALLOC (2 * sizeof(LONG_PTR)) 44 #define GWLP_CONSOLE_LEADER_PID 0 45 #define GWLP_CONSOLE_LEADER_TID 4 46 47 VOID 48 SetConWndConsoleLeaderCID(IN PGUI_CONSOLE_DATA GuiData) 49 { 50 PCONSOLE_PROCESS_DATA ProcessData; 51 CLIENT_ID ConsoleLeaderCID; 52 53 ProcessData = ConSrvGetConsoleLeaderProcess(GuiData->Console); 54 ConsoleLeaderCID = ProcessData->Process->ClientId; 55 SetWindowLongPtrW(GuiData->hWindow, GWLP_CONSOLE_LEADER_PID, 56 (LONG_PTR)(ConsoleLeaderCID.UniqueProcess)); 57 SetWindowLongPtrW(GuiData->hWindow, GWLP_CONSOLE_LEADER_TID, 58 (LONG_PTR)(ConsoleLeaderCID.UniqueThread)); 59 } 60 /**************************************************************/ 61 62 HICON ghDefaultIcon = NULL; 63 HICON ghDefaultIconSm = NULL; 64 HCURSOR ghDefaultCursor = NULL; 65 66 typedef struct _GUICONSOLE_MENUITEM 67 { 68 UINT uID; 69 const struct _GUICONSOLE_MENUITEM *SubMenu; 70 WORD wCmdID; 71 } GUICONSOLE_MENUITEM, *PGUICONSOLE_MENUITEM; 72 73 static const GUICONSOLE_MENUITEM GuiConsoleEditMenuItems[] = 74 { 75 { IDS_MARK, NULL, ID_SYSTEM_EDIT_MARK }, 76 { IDS_COPY, NULL, ID_SYSTEM_EDIT_COPY }, 77 { IDS_PASTE, NULL, ID_SYSTEM_EDIT_PASTE }, 78 { IDS_SELECTALL, NULL, ID_SYSTEM_EDIT_SELECTALL }, 79 { IDS_SCROLL, NULL, ID_SYSTEM_EDIT_SCROLL }, 80 { IDS_FIND, NULL, ID_SYSTEM_EDIT_FIND }, 81 82 { 0, NULL, 0 } /* End of list */ 83 }; 84 85 static const GUICONSOLE_MENUITEM GuiConsoleMainMenuItems[] = 86 { 87 { IDS_EDIT, GuiConsoleEditMenuItems, 0 }, 88 { IDS_DEFAULTS, NULL, ID_SYSTEM_DEFAULTS }, 89 { IDS_PROPERTIES, NULL, ID_SYSTEM_PROPERTIES }, 90 91 { 0, NULL, 0 } /* End of list */ 92 }; 93 94 /* 95 * Default 16-color palette for foreground and background 96 * (corresponding flags in comments). 97 */ 98 const COLORREF s_Colors[16] = 99 { 100 RGB(0, 0, 0), // (Black) 101 RGB(0, 0, 128), // BLUE 102 RGB(0, 128, 0), // GREEN 103 RGB(0, 128, 128), // BLUE | GREEN 104 RGB(128, 0, 0), // RED 105 RGB(128, 0, 128), // BLUE | RED 106 RGB(128, 128, 0), // GREEN | RED 107 RGB(192, 192, 192), // BLUE | GREEN | RED 108 109 RGB(128, 128, 128), // (Grey) INTENSITY 110 RGB(0, 0, 255), // BLUE | INTENSITY 111 RGB(0, 255, 0), // GREEN | INTENSITY 112 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY 113 RGB(255, 0, 0), // RED | INTENSITY 114 RGB(255, 0, 255), // BLUE | RED | INTENSITY 115 RGB(255, 255, 0), // GREEN | RED | INTENSITY 116 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY 117 }; 118 119 /* FUNCTIONS ******************************************************************/ 120 121 static LRESULT CALLBACK 122 ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 123 124 BOOLEAN 125 RegisterConWndClass(IN HINSTANCE hInstance) 126 { 127 WNDCLASSEXW WndClass; 128 ATOM WndClassAtom; 129 130 ghDefaultIcon = LoadImageW(hInstance, 131 MAKEINTRESOURCEW(IDI_TERMINAL), 132 IMAGE_ICON, 133 GetSystemMetrics(SM_CXICON), 134 GetSystemMetrics(SM_CYICON), 135 LR_SHARED); 136 ghDefaultIconSm = LoadImageW(hInstance, 137 MAKEINTRESOURCEW(IDI_TERMINAL), 138 IMAGE_ICON, 139 GetSystemMetrics(SM_CXSMICON), 140 GetSystemMetrics(SM_CYSMICON), 141 LR_SHARED); 142 ghDefaultCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_ARROW)); 143 144 WndClass.cbSize = sizeof(WNDCLASSEXW); 145 WndClass.lpszClassName = GUI_CONWND_CLASS; 146 WndClass.lpfnWndProc = ConWndProc; 147 WndClass.style = CS_DBLCLKS /* | CS_HREDRAW | CS_VREDRAW */; 148 WndClass.hInstance = hInstance; 149 WndClass.hIcon = ghDefaultIcon; 150 WndClass.hIconSm = ghDefaultIconSm; 151 WndClass.hCursor = ghDefaultCursor; 152 WndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // The color of a terminal when it is switched off. 153 WndClass.lpszMenuName = NULL; 154 WndClass.cbClsExtra = 0; 155 WndClass.cbWndExtra = GWLP_CONWND_ALLOC; 156 157 WndClassAtom = RegisterClassExW(&WndClass); 158 if (WndClassAtom == 0) 159 { 160 DPRINT1("Failed to register GUI console class\n"); 161 } 162 else 163 { 164 NtUserConsoleControl(GuiConsoleWndClassAtom, &WndClassAtom, sizeof(ATOM)); 165 } 166 167 return (WndClassAtom != 0); 168 } 169 170 BOOLEAN 171 UnRegisterConWndClass(HINSTANCE hInstance) 172 { 173 return !!UnregisterClassW(GUI_CONWND_CLASS, hInstance); 174 } 175 176 static VOID 177 AppendMenuItems(HMENU hMenu, 178 const GUICONSOLE_MENUITEM *Items) 179 { 180 UINT i = 0; 181 WCHAR szMenuString[255]; 182 HMENU hSubMenu; 183 184 do 185 { 186 if (Items[i].uID != (UINT)-1) 187 { 188 if (LoadStringW(ConSrvDllInstance, 189 Items[i].uID, 190 szMenuString, 191 ARRAYSIZE(szMenuString)) > 0) 192 { 193 if (Items[i].SubMenu != NULL) 194 { 195 hSubMenu = CreatePopupMenu(); 196 if (hSubMenu != NULL) 197 { 198 AppendMenuItems(hSubMenu, Items[i].SubMenu); 199 200 if (!AppendMenuW(hMenu, 201 MF_STRING | MF_POPUP, 202 (UINT_PTR)hSubMenu, 203 szMenuString)) 204 { 205 DestroyMenu(hSubMenu); 206 } 207 } 208 } 209 else 210 { 211 AppendMenuW(hMenu, 212 MF_STRING, 213 Items[i].wCmdID, 214 szMenuString); 215 } 216 } 217 } 218 else 219 { 220 AppendMenuW(hMenu, 221 MF_SEPARATOR, 222 0, 223 NULL); 224 } 225 i++; 226 } while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0)); 227 } 228 229 //static 230 VOID 231 CreateSysMenu(HWND hWnd) 232 { 233 MENUITEMINFOW mii; 234 WCHAR szMenuStringBack[255]; 235 WCHAR *ptrTab; 236 HMENU hMenu = GetSystemMenu(hWnd, FALSE); 237 if (hMenu != NULL) 238 { 239 mii.cbSize = sizeof(mii); 240 mii.fMask = MIIM_STRING; 241 mii.dwTypeData = szMenuStringBack; 242 mii.cch = sizeof(szMenuStringBack)/sizeof(WCHAR); 243 244 GetMenuItemInfoW(hMenu, SC_CLOSE, FALSE, &mii); 245 246 ptrTab = wcschr(szMenuStringBack, '\t'); 247 if (ptrTab) 248 { 249 *ptrTab = '\0'; 250 mii.cch = wcslen(szMenuStringBack); 251 252 SetMenuItemInfoW(hMenu, SC_CLOSE, FALSE, &mii); 253 } 254 255 AppendMenuItems(hMenu, GuiConsoleMainMenuItems); 256 DrawMenuBar(hWnd); 257 } 258 } 259 260 static VOID 261 SendMenuEvent(PCONSRV_CONSOLE Console, UINT CmdId) 262 { 263 INPUT_RECORD er; 264 265 DPRINT("Menu item ID: %d\n", CmdId); 266 267 if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return; 268 269 /* Send a menu event */ 270 er.EventType = MENU_EVENT; 271 er.Event.MenuEvent.dwCommandId = CmdId; 272 ConioProcessInputEvent(Console, &er); 273 274 LeaveCriticalSection(&Console->Lock); 275 } 276 277 static VOID 278 Copy(PGUI_CONSOLE_DATA GuiData); 279 static VOID 280 Paste(PGUI_CONSOLE_DATA GuiData); 281 static VOID 282 UpdateSelection(PGUI_CONSOLE_DATA GuiData, 283 PCOORD SelectionAnchor OPTIONAL, 284 PCOORD coord); 285 286 static VOID 287 Mark(PGUI_CONSOLE_DATA GuiData) 288 { 289 PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer; 290 291 /* Clear the old selection */ 292 GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION; 293 294 /* Restart a new selection */ 295 GuiData->dwSelectionCursor = ActiveBuffer->ViewOrigin; 296 UpdateSelection(GuiData, 297 &GuiData->dwSelectionCursor, 298 &GuiData->dwSelectionCursor); 299 } 300 301 static VOID 302 SelectAll(PGUI_CONSOLE_DATA GuiData) 303 { 304 PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer; 305 COORD SelectionAnchor; 306 307 /* Clear the old selection */ 308 GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION; 309 310 /* 311 * The selection area extends to the whole screen buffer's width. 312 */ 313 SelectionAnchor.X = SelectionAnchor.Y = 0; 314 GuiData->dwSelectionCursor.X = ActiveBuffer->ScreenBufferSize.X - 1; 315 316 /* 317 * Determine whether the selection must extend to just some part 318 * (for text-mode screen buffers) or to all of the screen buffer's 319 * height (for graphics ones). 320 */ 321 if (GetType(ActiveBuffer) == TEXTMODE_BUFFER) 322 { 323 /* 324 * We select all the characters from the first line 325 * to the line where the cursor is positioned. 326 */ 327 GuiData->dwSelectionCursor.Y = ActiveBuffer->CursorPosition.Y; 328 } 329 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */ 330 { 331 /* 332 * We select all the screen buffer area. 333 */ 334 GuiData->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1; 335 } 336 337 /* Restart a new selection */ 338 GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION; 339 UpdateSelection(GuiData, &SelectionAnchor, &GuiData->dwSelectionCursor); 340 } 341 342 static LRESULT 343 OnCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam) 344 { 345 LRESULT Ret = TRUE; 346 PCONSRV_CONSOLE Console = GuiData->Console; 347 348 /* 349 * In case the selected menu item belongs to the user-reserved menu id range, 350 * send to him a menu event and return directly. The user must handle those 351 * reserved menu commands... 352 */ 353 if (GuiData->CmdIdLow <= (UINT)wParam && (UINT)wParam <= GuiData->CmdIdHigh) 354 { 355 SendMenuEvent(Console, (UINT)wParam); 356 goto Quit; 357 } 358 359 /* ... otherwise, perform actions. */ 360 switch (wParam) 361 { 362 case ID_SYSTEM_EDIT_MARK: 363 Mark(GuiData); 364 break; 365 366 case ID_SYSTEM_EDIT_COPY: 367 Copy(GuiData); 368 break; 369 370 case ID_SYSTEM_EDIT_PASTE: 371 Paste(GuiData); 372 break; 373 374 case ID_SYSTEM_EDIT_SELECTALL: 375 SelectAll(GuiData); 376 break; 377 378 case ID_SYSTEM_EDIT_SCROLL: 379 DPRINT1("Scrolling is not handled yet\n"); 380 break; 381 382 case ID_SYSTEM_EDIT_FIND: 383 DPRINT1("Finding is not handled yet\n"); 384 break; 385 386 case ID_SYSTEM_DEFAULTS: 387 GuiConsoleShowConsoleProperties(GuiData, TRUE); 388 break; 389 390 case ID_SYSTEM_PROPERTIES: 391 GuiConsoleShowConsoleProperties(GuiData, FALSE); 392 break; 393 394 default: 395 Ret = FALSE; 396 break; 397 } 398 399 Quit: 400 if (!Ret) 401 Ret = DefWindowProcW(GuiData->hWindow, WM_SYSCOMMAND, wParam, lParam); 402 403 return Ret; 404 } 405 406 static PGUI_CONSOLE_DATA 407 GuiGetGuiData(HWND hWnd) 408 { 409 /* This function ensures that the console pointer is not NULL */ 410 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)GetWindowLongPtrW(hWnd, GWLP_USERDATA); 411 return ( ((GuiData == NULL) || (GuiData->hWindow == hWnd && GuiData->Console != NULL)) ? GuiData : NULL ); 412 } 413 414 static VOID 415 ResizeConWnd(PGUI_CONSOLE_DATA GuiData, DWORD WidthUnit, DWORD HeightUnit) 416 { 417 PCONSOLE_SCREEN_BUFFER Buff = GuiData->ActiveBuffer; 418 SCROLLINFO sInfo; 419 420 DWORD Width, Height; 421 422 Width = Buff->ViewSize.X * WidthUnit + 423 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)); 424 Height = Buff->ViewSize.Y * HeightUnit + 425 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION); 426 427 /* Set scrollbar sizes */ 428 sInfo.cbSize = sizeof(sInfo); 429 sInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; 430 sInfo.nMin = 0; 431 if (Buff->ScreenBufferSize.Y > Buff->ViewSize.Y) 432 { 433 sInfo.nMax = Buff->ScreenBufferSize.Y - 1; 434 sInfo.nPage = Buff->ViewSize.Y; 435 sInfo.nPos = Buff->ViewOrigin.Y; 436 SetScrollInfo(GuiData->hWindow, SB_VERT, &sInfo, TRUE); 437 Width += GetSystemMetrics(SM_CXVSCROLL); 438 ShowScrollBar(GuiData->hWindow, SB_VERT, TRUE); 439 } 440 else 441 { 442 ShowScrollBar(GuiData->hWindow, SB_VERT, FALSE); 443 } 444 445 if (Buff->ScreenBufferSize.X > Buff->ViewSize.X) 446 { 447 sInfo.nMax = Buff->ScreenBufferSize.X - 1; 448 sInfo.nPage = Buff->ViewSize.X; 449 sInfo.nPos = Buff->ViewOrigin.X; 450 SetScrollInfo(GuiData->hWindow, SB_HORZ, &sInfo, TRUE); 451 Height += GetSystemMetrics(SM_CYHSCROLL); 452 ShowScrollBar(GuiData->hWindow, SB_HORZ, TRUE); 453 } 454 else 455 { 456 ShowScrollBar(GuiData->hWindow, SB_HORZ, FALSE); 457 } 458 459 /* Resize the window */ 460 SetWindowPos(GuiData->hWindow, NULL, 0, 0, Width, Height, 461 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS); 462 // NOTE: The SWP_NOCOPYBITS flag can be replaced by a subsequent call 463 // to: InvalidateRect(GuiData->hWindow, NULL, TRUE); 464 } 465 466 467 VOID 468 DeleteFonts(PGUI_CONSOLE_DATA GuiData) 469 { 470 ULONG i; 471 for (i = 0; i < ARRAYSIZE(GuiData->Font); ++i) 472 { 473 if (GuiData->Font[i] != NULL) DeleteObject(GuiData->Font[i]); 474 GuiData->Font[i] = NULL; 475 } 476 } 477 478 static HFONT 479 CreateDerivedFont(HFONT OrgFont, 480 // COORD FontSize, 481 ULONG FontWeight, 482 // BOOLEAN bItalic, 483 BOOLEAN bUnderline, 484 BOOLEAN bStrikeOut) 485 { 486 LOGFONTW lf; 487 488 /* Initialize the LOGFONT structure */ 489 RtlZeroMemory(&lf, sizeof(lf)); 490 491 /* Retrieve the details of the current font */ 492 if (GetObjectW(OrgFont, sizeof(lf), &lf) == 0) 493 return NULL; 494 495 /* Change the font attributes */ 496 // lf.lfHeight = FontSize.Y; 497 // lf.lfWidth = FontSize.X; 498 lf.lfWeight = FontWeight; 499 // lf.lfItalic = bItalic; 500 lf.lfUnderline = bUnderline; 501 lf.lfStrikeOut = bStrikeOut; 502 503 /* Build a new font */ 504 return CreateFontIndirectW(&lf); 505 } 506 507 BOOL 508 InitFonts(PGUI_CONSOLE_DATA GuiData, 509 LPWSTR FaceName, // Points to a WCHAR array of LF_FACESIZE elements. 510 ULONG FontFamily, 511 COORD FontSize, 512 ULONG FontWeight) 513 { 514 HDC hDC; 515 HFONT hFont; 516 517 /* 518 * Initialize a new NORMAL font and get its character cell size. 519 */ 520 /* NOTE: FontSize is always in cell height/width units (pixels) */ 521 hFont = CreateConsoleFontEx((LONG)(ULONG)FontSize.Y, 522 (LONG)(ULONG)FontSize.X, 523 FaceName, 524 FontFamily, 525 FontWeight, 526 GuiData->Console->OutputCodePage); 527 if (hFont == NULL) 528 { 529 DPRINT1("InitFonts: CreateConsoleFontEx failed\n"); 530 return FALSE; 531 } 532 533 hDC = GetDC(GuiData->hWindow); 534 if (!GetFontCellSize(hDC, hFont, &GuiData->CharHeight, &GuiData->CharWidth)) 535 { 536 DPRINT1("InitFonts: GetFontCellSize failed\n"); 537 ReleaseDC(GuiData->hWindow, hDC); 538 DeleteObject(hFont); 539 return FALSE; 540 } 541 ReleaseDC(GuiData->hWindow, hDC); 542 543 /* 544 * Initialization succeeded. 545 */ 546 // Delete all the old fonts first. 547 DeleteFonts(GuiData); 548 GuiData->Font[FONT_NORMAL] = hFont; 549 550 /* 551 * Now build the other fonts (bold, underlined, mixed). 552 */ 553 GuiData->Font[FONT_BOLD] = 554 CreateDerivedFont(GuiData->Font[FONT_NORMAL], 555 FontWeight < FW_BOLD ? FW_BOLD : FontWeight, 556 FALSE, 557 FALSE); 558 GuiData->Font[FONT_UNDERLINE] = 559 CreateDerivedFont(GuiData->Font[FONT_NORMAL], 560 FontWeight, 561 TRUE, 562 FALSE); 563 GuiData->Font[FONT_BOLD | FONT_UNDERLINE] = 564 CreateDerivedFont(GuiData->Font[FONT_NORMAL], 565 FontWeight < FW_BOLD ? FW_BOLD : FontWeight, 566 TRUE, 567 FALSE); 568 569 /* 570 * Save the settings. 571 */ 572 if (FaceName != GuiData->GuiInfo.FaceName) 573 { 574 StringCchCopyNW(GuiData->GuiInfo.FaceName, ARRAYSIZE(GuiData->GuiInfo.FaceName), 575 FaceName, LF_FACESIZE); 576 } 577 GuiData->GuiInfo.FontFamily = FontFamily; 578 GuiData->GuiInfo.FontSize = FontSize; 579 GuiData->GuiInfo.FontWeight = FontWeight; 580 581 return TRUE; 582 } 583 584 585 static BOOL 586 OnNcCreate(HWND hWnd, LPCREATESTRUCTW Create) 587 { 588 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)Create->lpCreateParams; 589 PCONSRV_CONSOLE Console; 590 591 if (GuiData == NULL) 592 { 593 DPRINT1("GuiConsoleNcCreate: No GUI data\n"); 594 return FALSE; 595 } 596 597 Console = GuiData->Console; 598 599 GuiData->hWindow = hWnd; 600 601 /* Initialize the fonts */ 602 if (!InitFonts(GuiData, 603 GuiData->GuiInfo.FaceName, 604 GuiData->GuiInfo.FontFamily, 605 GuiData->GuiInfo.FontSize, 606 GuiData->GuiInfo.FontWeight)) 607 { 608 DPRINT1("GuiConsoleNcCreate: InitFonts failed\n"); 609 GuiData->hWindow = NULL; 610 NtSetEvent(GuiData->hGuiInitEvent, NULL); 611 return FALSE; 612 } 613 614 /* Initialize the terminal framebuffer */ 615 GuiData->hMemDC = CreateCompatibleDC(NULL); 616 GuiData->hBitmap = NULL; 617 GuiData->hSysPalette = NULL; /* Original system palette */ 618 619 /* Update the icons of the window */ 620 if (GuiData->hIcon != ghDefaultIcon) 621 { 622 DefWindowProcW(GuiData->hWindow, WM_SETICON, ICON_BIG , (LPARAM)GuiData->hIcon ); 623 DefWindowProcW(GuiData->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)GuiData->hIconSm); 624 } 625 626 // FIXME: Keep these instructions here ? /////////////////////////////////// 627 Console->ActiveBuffer->CursorBlinkOn = TRUE; 628 Console->ActiveBuffer->ForceCursorOff = FALSE; 629 //////////////////////////////////////////////////////////////////////////// 630 631 SetWindowLongPtrW(GuiData->hWindow, GWLP_USERDATA, (DWORD_PTR)GuiData); 632 633 if (GuiData->IsWindowVisible) 634 { 635 SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL); 636 } 637 638 // FIXME: HACK: Potential HACK for CORE-8129; see revision 63595. 639 //CreateSysMenu(GuiData->hWindow); 640 641 DPRINT("OnNcCreate - setting start event\n"); 642 NtSetEvent(GuiData->hGuiInitEvent, NULL); 643 644 /* We accept dropped files */ 645 DragAcceptFiles(GuiData->hWindow, TRUE); 646 647 return (BOOL)DefWindowProcW(GuiData->hWindow, WM_NCCREATE, 0, (LPARAM)Create); 648 } 649 650 static VOID 651 OnActivate(PGUI_CONSOLE_DATA GuiData, WPARAM wParam) 652 { 653 WORD ActivationState = LOWORD(wParam); 654 655 DPRINT("WM_ACTIVATE - ActivationState = %d\n", ActivationState); 656 657 if ( ActivationState == WA_ACTIVE || 658 ActivationState == WA_CLICKACTIVE ) 659 { 660 if (GuiData->GuiInfo.FullScreen) 661 { 662 EnterFullScreen(GuiData); 663 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0); 664 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0); 665 } 666 } 667 else // if (ActivationState == WA_INACTIVE) 668 { 669 if (GuiData->GuiInfo.FullScreen) 670 { 671 SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0); 672 LeaveFullScreen(GuiData); 673 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0); 674 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0); 675 } 676 } 677 678 /* 679 * Ignore the next mouse signal when we are going to be enabled again via 680 * the mouse, in order to prevent, e.g. when we are in Edit mode, erroneous 681 * mouse actions from the user that could spoil text selection or copy/pastes. 682 */ 683 if (ActivationState == WA_CLICKACTIVE) 684 GuiData->IgnoreNextMouseSignal = TRUE; 685 } 686 687 static VOID 688 OnFocus(PGUI_CONSOLE_DATA GuiData, BOOL SetFocus) 689 { 690 PCONSRV_CONSOLE Console = GuiData->Console; 691 INPUT_RECORD er; 692 693 if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return; 694 695 /* Set console focus state */ 696 Console->HasFocus = SetFocus; 697 698 /* 699 * Set the priority of the processes of this console 700 * in accordance with the console focus state. 701 */ 702 ConSrvSetConsoleProcessFocus(Console, SetFocus); 703 704 /* Send a focus event */ 705 er.EventType = FOCUS_EVENT; 706 er.Event.FocusEvent.bSetFocus = SetFocus; 707 ConioProcessInputEvent(Console, &er); 708 709 LeaveCriticalSection(&Console->Lock); 710 711 if (SetFocus) 712 DPRINT("TODO: Create console caret\n"); 713 else 714 DPRINT("TODO: Destroy console caret\n"); 715 } 716 717 VOID 718 GetSelectionBeginEnd(PCOORD Begin, PCOORD End, 719 PCOORD SelectionAnchor, 720 PSMALL_RECT SmallRect) 721 { 722 if (Begin == NULL || End == NULL) return; 723 724 *Begin = *SelectionAnchor; 725 End->X = (SelectionAnchor->X == SmallRect->Left) ? SmallRect->Right 726 /* Case X != Left, must be == Right */ : SmallRect->Left; 727 End->Y = (SelectionAnchor->Y == SmallRect->Top ) ? SmallRect->Bottom 728 /* Case Y != Top, must be == Bottom */ : SmallRect->Top; 729 730 /* Exchange Begin / End if Begin > End lexicographically */ 731 if (Begin->Y > End->Y || (Begin->Y == End->Y && Begin->X > End->X)) 732 { 733 End->X = _InterlockedExchange16(&Begin->X, End->X); 734 End->Y = _InterlockedExchange16(&Begin->Y, End->Y); 735 } 736 } 737 738 static HRGN 739 CreateSelectionRgn(PGUI_CONSOLE_DATA GuiData, 740 BOOL LineSelection, 741 PCOORD SelectionAnchor, 742 PSMALL_RECT SmallRect) 743 { 744 if (!LineSelection) 745 { 746 RECT rect; 747 SmallRectToRect(GuiData, &rect, SmallRect); 748 return CreateRectRgnIndirect(&rect); 749 } 750 else 751 { 752 HRGN SelRgn; 753 COORD Begin, End; 754 755 GetSelectionBeginEnd(&Begin, &End, SelectionAnchor, SmallRect); 756 757 if (Begin.Y == End.Y) 758 { 759 SMALL_RECT sr; 760 RECT r ; 761 762 sr.Left = Begin.X; 763 sr.Top = Begin.Y; 764 sr.Right = End.X; 765 sr.Bottom = End.Y; 766 767 // Debug thingie to see whether I can put this corner case 768 // together with the previous one. 769 if (SmallRect->Left != sr.Left || 770 SmallRect->Top != sr.Top || 771 SmallRect->Right != sr.Right || 772 SmallRect->Bottom != sr.Bottom) 773 { 774 DPRINT1("\n" 775 "SmallRect = (%d, %d, %d, %d)\n" 776 "sr = (%d, %d, %d, %d)\n" 777 "\n", 778 SmallRect->Left, SmallRect->Top, SmallRect->Right, SmallRect->Bottom, 779 sr.Left, sr.Top, sr.Right, sr.Bottom); 780 } 781 782 SmallRectToRect(GuiData, &r, &sr); 783 SelRgn = CreateRectRgnIndirect(&r); 784 } 785 else 786 { 787 PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer; 788 789 HRGN rg1, rg2, rg3; 790 SMALL_RECT sr1, sr2, sr3; 791 RECT r1 , r2 , r3 ; 792 793 sr1.Left = Begin.X; 794 sr1.Top = Begin.Y; 795 sr1.Right = ActiveBuffer->ScreenBufferSize.X - 1; 796 sr1.Bottom = Begin.Y; 797 798 sr2.Left = 0; 799 sr2.Top = Begin.Y + 1; 800 sr2.Right = ActiveBuffer->ScreenBufferSize.X - 1; 801 sr2.Bottom = End.Y - 1; 802 803 sr3.Left = 0; 804 sr3.Top = End.Y; 805 sr3.Right = End.X; 806 sr3.Bottom = End.Y; 807 808 SmallRectToRect(GuiData, &r1, &sr1); 809 SmallRectToRect(GuiData, &r2, &sr2); 810 SmallRectToRect(GuiData, &r3, &sr3); 811 812 rg1 = CreateRectRgnIndirect(&r1); 813 rg2 = CreateRectRgnIndirect(&r2); 814 rg3 = CreateRectRgnIndirect(&r3); 815 816 CombineRgn(rg1, rg1, rg2, RGN_XOR); 817 CombineRgn(rg1, rg1, rg3, RGN_XOR); 818 DeleteObject(rg3); 819 DeleteObject(rg2); 820 821 SelRgn = rg1; 822 } 823 824 return SelRgn; 825 } 826 } 827 828 static VOID 829 PaintSelectionRect(PGUI_CONSOLE_DATA GuiData, PPAINTSTRUCT pps) 830 { 831 HRGN rgnPaint = CreateRectRgnIndirect(&pps->rcPaint); 832 HRGN rgnSel = CreateSelectionRgn(GuiData, GuiData->LineSelection, 833 &GuiData->Selection.dwSelectionAnchor, 834 &GuiData->Selection.srSelection); 835 836 /* Invert the selection */ 837 838 int ErrorCode = CombineRgn(rgnPaint, rgnPaint, rgnSel, RGN_AND); 839 if (ErrorCode != ERROR && ErrorCode != NULLREGION) 840 { 841 InvertRgn(pps->hdc, rgnPaint); 842 } 843 844 DeleteObject(rgnSel); 845 DeleteObject(rgnPaint); 846 } 847 848 static VOID 849 UpdateSelection(PGUI_CONSOLE_DATA GuiData, 850 PCOORD SelectionAnchor OPTIONAL, 851 PCOORD coord) 852 { 853 PCONSRV_CONSOLE Console = GuiData->Console; 854 HRGN oldRgn = CreateSelectionRgn(GuiData, GuiData->LineSelection, 855 &GuiData->Selection.dwSelectionAnchor, 856 &GuiData->Selection.srSelection); 857 858 /* Update the anchor if needed (use the old one if NULL) */ 859 if (SelectionAnchor) 860 GuiData->Selection.dwSelectionAnchor = *SelectionAnchor; 861 862 // TODO: Scroll buffer to bring 'coord' into view 863 864 if (coord != NULL) 865 { 866 SMALL_RECT rc; 867 HRGN newRgn; 868 869 /* 870 * Pressing the Control key while selecting text, allows us to enter 871 * into line-selection mode, the selection mode of *nix terminals. 872 */ 873 BOOL OldLineSel = GuiData->LineSelection; 874 GuiData->LineSelection = !!(GetKeyState(VK_CONTROL) & KEY_PRESSED); 875 876 /* Exchange left/top with right/bottom if required */ 877 rc.Left = min(GuiData->Selection.dwSelectionAnchor.X, coord->X); 878 rc.Top = min(GuiData->Selection.dwSelectionAnchor.Y, coord->Y); 879 rc.Right = max(GuiData->Selection.dwSelectionAnchor.X, coord->X); 880 rc.Bottom = max(GuiData->Selection.dwSelectionAnchor.Y, coord->Y); 881 882 newRgn = CreateSelectionRgn(GuiData, GuiData->LineSelection, 883 &GuiData->Selection.dwSelectionAnchor, 884 &rc); 885 886 if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY) 887 { 888 if (OldLineSel != GuiData->LineSelection || 889 memcmp(&rc, &GuiData->Selection.srSelection, sizeof(SMALL_RECT)) != 0) 890 { 891 /* Calculate the region that needs to be updated */ 892 if (oldRgn && newRgn && CombineRgn(newRgn, newRgn, oldRgn, RGN_XOR) != ERROR) 893 { 894 InvalidateRgn(GuiData->hWindow, newRgn, FALSE); 895 } 896 } 897 } 898 else 899 { 900 InvalidateRgn(GuiData->hWindow, newRgn, FALSE); 901 } 902 903 DeleteObject(newRgn); 904 905 GuiData->Selection.dwFlags |= CONSOLE_SELECTION_NOT_EMPTY; 906 GuiData->Selection.srSelection = rc; 907 GuiData->dwSelectionCursor = *coord; 908 909 if ((GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) == 0) 910 { 911 LPWSTR SelTypeStr = NULL , WindowTitle = NULL; 912 SIZE_T SelTypeStrLength = 0, Length = 0; 913 914 /* Clear the old selection */ 915 if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY) 916 { 917 InvalidateRgn(GuiData->hWindow, oldRgn, FALSE); 918 } 919 920 /* 921 * When passing a zero-length buffer size, LoadString(...) returns 922 * a read-only pointer buffer to the program's resource string. 923 */ 924 SelTypeStrLength = 925 LoadStringW(ConSrvDllInstance, 926 (GuiData->Selection.dwFlags & CONSOLE_MOUSE_SELECTION) 927 ? IDS_SELECT_TITLE : IDS_MARK_TITLE, 928 (LPWSTR)&SelTypeStr, 0); 929 930 /* 931 * Prepend the selection type string to the current console title 932 * if we succeeded in retrieving a valid localized string. 933 */ 934 if (SelTypeStr) 935 { 936 // 3 for " - " and 1 for NULL 937 Length = Console->Title.Length + (SelTypeStrLength + 3 + 1) * sizeof(WCHAR); 938 WindowTitle = ConsoleAllocHeap(0, Length); 939 940 wcsncpy(WindowTitle, SelTypeStr, SelTypeStrLength); 941 WindowTitle[SelTypeStrLength] = UNICODE_NULL; 942 wcscat(WindowTitle, L" - "); 943 wcscat(WindowTitle, Console->Title.Buffer); 944 945 SetWindowTextW(GuiData->hWindow, WindowTitle); 946 ConsoleFreeHeap(WindowTitle); 947 } 948 949 GuiData->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS; 950 ConioPause(Console, PAUSED_FROM_SELECTION); 951 } 952 } 953 else 954 { 955 /* Clear the selection */ 956 if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY) 957 { 958 InvalidateRgn(GuiData->hWindow, oldRgn, FALSE); 959 } 960 961 GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION; 962 ConioUnpause(Console, PAUSED_FROM_SELECTION); 963 964 /* Restore the console title */ 965 SetWindowTextW(GuiData->hWindow, Console->Title.Buffer); 966 } 967 968 DeleteObject(oldRgn); 969 } 970 971 static VOID 972 OnPaint(PGUI_CONSOLE_DATA GuiData) 973 { 974 PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer; 975 PAINTSTRUCT ps; 976 RECT rcPaint; 977 978 /* Do nothing if the window is hidden */ 979 if (!GuiData->IsWindowVisible) return; 980 981 BeginPaint(GuiData->hWindow, &ps); 982 if (ps.hdc != NULL && 983 ps.rcPaint.left < ps.rcPaint.right && 984 ps.rcPaint.top < ps.rcPaint.bottom) 985 { 986 EnterCriticalSection(&GuiData->Lock); 987 988 /* Compose the current screen-buffer on-memory */ 989 if (GetType(ActiveBuffer) == TEXTMODE_BUFFER) 990 { 991 GuiPaintTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)ActiveBuffer, 992 GuiData, &ps.rcPaint, &rcPaint); 993 } 994 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */ 995 { 996 GuiPaintGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)ActiveBuffer, 997 GuiData, &ps.rcPaint, &rcPaint); 998 } 999 1000 /* Send it to screen */ 1001 BitBlt(ps.hdc, 1002 ps.rcPaint.left, 1003 ps.rcPaint.top, 1004 rcPaint.right - rcPaint.left, 1005 rcPaint.bottom - rcPaint.top, 1006 GuiData->hMemDC, 1007 rcPaint.left, 1008 rcPaint.top, 1009 SRCCOPY); 1010 1011 /* Draw the selection region if needed */ 1012 if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY) 1013 { 1014 PaintSelectionRect(GuiData, &ps); 1015 } 1016 1017 LeaveCriticalSection(&GuiData->Lock); 1018 } 1019 EndPaint(GuiData->hWindow, &ps); 1020 1021 return; 1022 } 1023 1024 static VOID 1025 OnPaletteChanged(PGUI_CONSOLE_DATA GuiData) 1026 { 1027 PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer; 1028 1029 /* Do nothing if the window is hidden */ 1030 if (!GuiData->IsWindowVisible) return; 1031 1032 // See WM_PALETTECHANGED message 1033 // if ((HWND)wParam == hWnd) break; 1034 1035 // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) 1036 if (ActiveBuffer->PaletteHandle) 1037 { 1038 DPRINT("WM_PALETTECHANGED changing palette\n"); 1039 1040 /* Specify the use of the system palette for the framebuffer */ 1041 SetSystemPaletteUse(GuiData->hMemDC, ActiveBuffer->PaletteUsage); 1042 1043 /* Realize the (logical) palette */ 1044 RealizePalette(GuiData->hMemDC); 1045 } 1046 } 1047 1048 static BOOL 1049 IsSystemKey(WORD VirtualKeyCode) 1050 { 1051 switch (VirtualKeyCode) 1052 { 1053 /* From MSDN, "Virtual-Key Codes" */ 1054 case VK_RETURN: 1055 case VK_SHIFT: 1056 case VK_CONTROL: 1057 case VK_MENU: 1058 case VK_PAUSE: 1059 case VK_CAPITAL: 1060 case VK_ESCAPE: 1061 case VK_LWIN: 1062 case VK_RWIN: 1063 case VK_NUMLOCK: 1064 case VK_SCROLL: 1065 return TRUE; 1066 default: 1067 return FALSE; 1068 } 1069 } 1070 1071 static VOID 1072 OnKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam) 1073 { 1074 PCONSRV_CONSOLE Console = GuiData->Console; 1075 PCONSOLE_SCREEN_BUFFER ActiveBuffer; 1076 1077 if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return; 1078 1079 ActiveBuffer = GuiData->ActiveBuffer; 1080 1081 if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) 1082 { 1083 WORD VirtualKeyCode = LOWORD(wParam); 1084 1085 if (msg != WM_KEYDOWN) goto Quit; 1086 1087 if (VirtualKeyCode == VK_RETURN) 1088 { 1089 /* Copy (and clear) selection if ENTER is pressed */ 1090 Copy(GuiData); 1091 goto Quit; 1092 } 1093 else if ( VirtualKeyCode == VK_ESCAPE || 1094 (VirtualKeyCode == 'C' && (GetKeyState(VK_CONTROL) & KEY_PRESSED)) ) 1095 { 1096 /* Cancel selection if ESC or Ctrl-C are pressed */ 1097 UpdateSelection(GuiData, NULL, NULL); 1098 goto Quit; 1099 } 1100 1101 if ((GuiData->Selection.dwFlags & CONSOLE_MOUSE_SELECTION) == 0) 1102 { 1103 /* Keyboard selection mode */ 1104 BOOL Interpreted = FALSE; 1105 BOOL MajPressed = !!(GetKeyState(VK_SHIFT) & KEY_PRESSED); 1106 1107 switch (VirtualKeyCode) 1108 { 1109 case VK_LEFT: 1110 { 1111 Interpreted = TRUE; 1112 if (GuiData->dwSelectionCursor.X > 0) 1113 GuiData->dwSelectionCursor.X--; 1114 1115 break; 1116 } 1117 1118 case VK_RIGHT: 1119 { 1120 Interpreted = TRUE; 1121 if (GuiData->dwSelectionCursor.X < ActiveBuffer->ScreenBufferSize.X - 1) 1122 GuiData->dwSelectionCursor.X++; 1123 1124 break; 1125 } 1126 1127 case VK_UP: 1128 { 1129 Interpreted = TRUE; 1130 if (GuiData->dwSelectionCursor.Y > 0) 1131 GuiData->dwSelectionCursor.Y--; 1132 1133 break; 1134 } 1135 1136 case VK_DOWN: 1137 { 1138 Interpreted = TRUE; 1139 if (GuiData->dwSelectionCursor.Y < ActiveBuffer->ScreenBufferSize.Y - 1) 1140 GuiData->dwSelectionCursor.Y++; 1141 1142 break; 1143 } 1144 1145 case VK_HOME: 1146 { 1147 Interpreted = TRUE; 1148 GuiData->dwSelectionCursor.X = 0; 1149 GuiData->dwSelectionCursor.Y = 0; 1150 break; 1151 } 1152 1153 case VK_END: 1154 { 1155 Interpreted = TRUE; 1156 GuiData->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1; 1157 break; 1158 } 1159 1160 case VK_PRIOR: 1161 { 1162 Interpreted = TRUE; 1163 GuiData->dwSelectionCursor.Y -= ActiveBuffer->ViewSize.Y; 1164 if (GuiData->dwSelectionCursor.Y < 0) 1165 GuiData->dwSelectionCursor.Y = 0; 1166 1167 break; 1168 } 1169 1170 case VK_NEXT: 1171 { 1172 Interpreted = TRUE; 1173 GuiData->dwSelectionCursor.Y += ActiveBuffer->ViewSize.Y; 1174 if (GuiData->dwSelectionCursor.Y >= ActiveBuffer->ScreenBufferSize.Y) 1175 GuiData->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1; 1176 1177 break; 1178 } 1179 1180 default: 1181 break; 1182 } 1183 1184 if (Interpreted) 1185 { 1186 UpdateSelection(GuiData, 1187 !MajPressed ? &GuiData->dwSelectionCursor : NULL, 1188 &GuiData->dwSelectionCursor); 1189 } 1190 else if (!IsSystemKey(VirtualKeyCode)) 1191 { 1192 /* Emit an error beep sound */ 1193 SendNotifyMessage(GuiData->hWindow, PM_CONSOLE_BEEP, 0, 0); 1194 } 1195 1196 goto Quit; 1197 } 1198 else 1199 { 1200 /* Mouse selection mode */ 1201 1202 if (!IsSystemKey(VirtualKeyCode)) 1203 { 1204 /* Clear the selection and send the key into the input buffer */ 1205 UpdateSelection(GuiData, NULL, NULL); 1206 } 1207 else 1208 { 1209 goto Quit; 1210 } 1211 } 1212 } 1213 1214 if ((GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) == 0) 1215 { 1216 MSG Message; 1217 1218 Message.hwnd = GuiData->hWindow; 1219 Message.message = msg; 1220 Message.wParam = wParam; 1221 Message.lParam = lParam; 1222 1223 ConioProcessKey(Console, &Message); 1224 } 1225 1226 Quit: 1227 LeaveCriticalSection(&Console->Lock); 1228 } 1229 1230 1231 // FIXME: Remove after fixing OnTimer 1232 VOID 1233 InvalidateCell(PGUI_CONSOLE_DATA GuiData, 1234 SHORT x, SHORT y); 1235 1236 static VOID 1237 OnTimer(PGUI_CONSOLE_DATA GuiData) 1238 { 1239 PCONSRV_CONSOLE Console = GuiData->Console; 1240 PCONSOLE_SCREEN_BUFFER Buff; 1241 1242 /* Do nothing if the window is hidden */ 1243 if (!GuiData->IsWindowVisible) return; 1244 1245 SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CURSOR_BLINK_TIME, NULL); 1246 1247 if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return; 1248 1249 Buff = GuiData->ActiveBuffer; 1250 1251 if (GetType(Buff) == TEXTMODE_BUFFER) 1252 { 1253 InvalidateCell(GuiData, Buff->CursorPosition.X, Buff->CursorPosition.Y); 1254 Buff->CursorBlinkOn = !Buff->CursorBlinkOn; 1255 1256 if ((GuiData->OldCursor.x != Buff->CursorPosition.X) || 1257 (GuiData->OldCursor.y != Buff->CursorPosition.Y)) 1258 { 1259 SCROLLINFO sInfo; 1260 int OldScrollX = -1, OldScrollY = -1; 1261 int NewScrollX = -1, NewScrollY = -1; 1262 1263 sInfo.cbSize = sizeof(sInfo); 1264 sInfo.fMask = SIF_POS; 1265 // Capture the original position of the scroll bars and save them. 1266 if (GetScrollInfo(GuiData->hWindow, SB_HORZ, &sInfo)) OldScrollX = sInfo.nPos; 1267 if (GetScrollInfo(GuiData->hWindow, SB_VERT, &sInfo)) OldScrollY = sInfo.nPos; 1268 1269 // If we successfully got the info for the horizontal scrollbar 1270 if (OldScrollX >= 0) 1271 { 1272 if ((Buff->CursorPosition.X < Buff->ViewOrigin.X) || 1273 (Buff->CursorPosition.X >= (Buff->ViewOrigin.X + Buff->ViewSize.X))) 1274 { 1275 // Handle the horizontal scroll bar 1276 if (Buff->CursorPosition.X >= Buff->ViewSize.X) 1277 NewScrollX = Buff->CursorPosition.X - Buff->ViewSize.X + 1; 1278 else 1279 NewScrollX = 0; 1280 } 1281 else 1282 { 1283 NewScrollX = OldScrollX; 1284 } 1285 } 1286 // If we successfully got the info for the vertical scrollbar 1287 if (OldScrollY >= 0) 1288 { 1289 if ((Buff->CursorPosition.Y < Buff->ViewOrigin.Y) || 1290 (Buff->CursorPosition.Y >= (Buff->ViewOrigin.Y + Buff->ViewSize.Y))) 1291 { 1292 // Handle the vertical scroll bar 1293 if (Buff->CursorPosition.Y >= Buff->ViewSize.Y) 1294 NewScrollY = Buff->CursorPosition.Y - Buff->ViewSize.Y + 1; 1295 else 1296 NewScrollY = 0; 1297 } 1298 else 1299 { 1300 NewScrollY = OldScrollY; 1301 } 1302 } 1303 1304 // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area 1305 // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar 1306 // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling) 1307 // and their associated scrollbar is left alone. 1308 if ((OldScrollX != NewScrollX) || (OldScrollY != NewScrollY)) 1309 { 1310 Buff->ViewOrigin.X = NewScrollX; 1311 Buff->ViewOrigin.Y = NewScrollY; 1312 ScrollWindowEx(GuiData->hWindow, 1313 (OldScrollX - NewScrollX) * GuiData->CharWidth, 1314 (OldScrollY - NewScrollY) * GuiData->CharHeight, 1315 NULL, 1316 NULL, 1317 NULL, 1318 NULL, 1319 SW_INVALIDATE); 1320 if (NewScrollX >= 0) 1321 { 1322 sInfo.nPos = NewScrollX; 1323 SetScrollInfo(GuiData->hWindow, SB_HORZ, &sInfo, TRUE); 1324 } 1325 if (NewScrollY >= 0) 1326 { 1327 sInfo.nPos = NewScrollY; 1328 SetScrollInfo(GuiData->hWindow, SB_VERT, &sInfo, TRUE); 1329 } 1330 UpdateWindow(GuiData->hWindow); 1331 // InvalidateRect(GuiData->hWindow, NULL, FALSE); 1332 GuiData->OldCursor.x = Buff->CursorPosition.X; 1333 GuiData->OldCursor.y = Buff->CursorPosition.Y; 1334 } 1335 } 1336 } 1337 else /* if (GetType(Buff) == GRAPHICS_BUFFER) */ 1338 { 1339 } 1340 1341 LeaveCriticalSection(&Console->Lock); 1342 } 1343 1344 static BOOL 1345 OnClose(PGUI_CONSOLE_DATA GuiData) 1346 { 1347 PCONSRV_CONSOLE Console = GuiData->Console; 1348 1349 if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) 1350 return TRUE; 1351 1352 // TODO: Prompt for termination ? (Warn the user about possible apps running in this console) 1353 1354 /* 1355 * FIXME: Windows will wait up to 5 seconds for the thread to exit. 1356 * We shouldn't wait here, though, since the console lock is entered. 1357 * A copy of the thread list probably needs to be made. 1358 */ 1359 ConSrvConsoleProcessCtrlEvent(Console, 0, CTRL_CLOSE_EVENT); 1360 1361 LeaveCriticalSection(&Console->Lock); 1362 return FALSE; 1363 } 1364 1365 static LRESULT 1366 OnNcDestroy(HWND hWnd) 1367 { 1368 PGUI_CONSOLE_DATA GuiData = GuiGetGuiData(hWnd); 1369 1370 /* Free the GuiData registration */ 1371 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (DWORD_PTR)NULL); 1372 1373 GetSystemMenu(hWnd, TRUE); 1374 1375 if (GuiData) 1376 { 1377 if (GuiData->IsWindowVisible) 1378 KillTimer(hWnd, CONGUI_UPDATE_TIMER); 1379 1380 /* Free the terminal framebuffer */ 1381 if (GuiData->hMemDC ) DeleteDC(GuiData->hMemDC); 1382 if (GuiData->hBitmap) DeleteObject(GuiData->hBitmap); 1383 // if (GuiData->hSysPalette) DeleteObject(GuiData->hSysPalette); 1384 DeleteFonts(GuiData); 1385 } 1386 1387 return DefWindowProcW(hWnd, WM_NCDESTROY, 0, 0); 1388 } 1389 1390 static VOID 1391 OnScroll(PGUI_CONSOLE_DATA GuiData, INT nBar, WORD sbCode) 1392 { 1393 PCONSRV_CONSOLE Console = GuiData->Console; 1394 PCONSOLE_SCREEN_BUFFER Buff; 1395 SCROLLINFO sInfo; 1396 INT oldPos, Maximum; 1397 PSHORT pOriginXY; 1398 1399 ASSERT(nBar == SB_HORZ || nBar == SB_VERT); 1400 1401 if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return; 1402 1403 Buff = GuiData->ActiveBuffer; 1404 1405 if (nBar == SB_HORZ) 1406 { 1407 Maximum = Buff->ScreenBufferSize.X - Buff->ViewSize.X; 1408 pOriginXY = &Buff->ViewOrigin.X; 1409 } 1410 else // if (nBar == SB_VERT) 1411 { 1412 Maximum = Buff->ScreenBufferSize.Y - Buff->ViewSize.Y; 1413 pOriginXY = &Buff->ViewOrigin.Y; 1414 } 1415 1416 /* Set scrollbar sizes */ 1417 sInfo.cbSize = sizeof(sInfo); 1418 sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS; 1419 1420 if (!GetScrollInfo(GuiData->hWindow, nBar, &sInfo)) goto Quit; 1421 1422 oldPos = sInfo.nPos; 1423 1424 switch (sbCode) 1425 { 1426 case SB_LINEUP: // SB_LINELEFT: 1427 sInfo.nPos--; 1428 break; 1429 1430 case SB_LINEDOWN: // SB_LINERIGHT: 1431 sInfo.nPos++; 1432 break; 1433 1434 case SB_PAGEUP: // SB_PAGELEFT: 1435 sInfo.nPos -= sInfo.nPage; 1436 break; 1437 1438 case SB_PAGEDOWN: // SB_PAGERIGHT: 1439 sInfo.nPos += sInfo.nPage; 1440 break; 1441 1442 case SB_THUMBTRACK: 1443 sInfo.nPos = sInfo.nTrackPos; 1444 ConioPause(Console, PAUSED_FROM_SCROLLBAR); 1445 break; 1446 1447 case SB_THUMBPOSITION: 1448 sInfo.nPos = sInfo.nTrackPos; 1449 ConioUnpause(Console, PAUSED_FROM_SCROLLBAR); 1450 break; 1451 1452 case SB_TOP: // SB_LEFT: 1453 sInfo.nPos = sInfo.nMin; 1454 break; 1455 1456 case SB_BOTTOM: // SB_RIGHT: 1457 sInfo.nPos = sInfo.nMax; 1458 break; 1459 1460 default: 1461 break; 1462 } 1463 1464 sInfo.nPos = min(max(sInfo.nPos, 0), Maximum); 1465 1466 if (oldPos != sInfo.nPos) 1467 { 1468 USHORT OldX = Buff->ViewOrigin.X; 1469 USHORT OldY = Buff->ViewOrigin.Y; 1470 UINT WidthUnit, HeightUnit; 1471 1472 /* We now modify Buff->ViewOrigin */ 1473 *pOriginXY = sInfo.nPos; 1474 1475 GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit); 1476 1477 ScrollWindowEx(GuiData->hWindow, 1478 (OldX - Buff->ViewOrigin.X) * WidthUnit , 1479 (OldY - Buff->ViewOrigin.Y) * HeightUnit, 1480 NULL, 1481 NULL, 1482 NULL, 1483 NULL, 1484 SW_INVALIDATE); 1485 1486 sInfo.fMask = SIF_POS; 1487 SetScrollInfo(GuiData->hWindow, nBar, &sInfo, TRUE); 1488 1489 UpdateWindow(GuiData->hWindow); 1490 // InvalidateRect(GuiData->hWindow, NULL, FALSE); 1491 } 1492 1493 Quit: 1494 LeaveCriticalSection(&Console->Lock); 1495 return; 1496 } 1497 1498 static COORD 1499 PointToCoord(PGUI_CONSOLE_DATA GuiData, LPARAM lParam) 1500 { 1501 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer; 1502 COORD Coord; 1503 UINT WidthUnit, HeightUnit; 1504 1505 GetScreenBufferSizeUnits(Buffer, GuiData, &WidthUnit, &HeightUnit); 1506 1507 Coord.X = Buffer->ViewOrigin.X + ((SHORT)LOWORD(lParam) / (int)WidthUnit ); 1508 Coord.Y = Buffer->ViewOrigin.Y + ((SHORT)HIWORD(lParam) / (int)HeightUnit); 1509 1510 /* Clip coordinate to ensure it's inside buffer */ 1511 if (Coord.X < 0) 1512 Coord.X = 0; 1513 else if (Coord.X >= Buffer->ScreenBufferSize.X) 1514 Coord.X = Buffer->ScreenBufferSize.X - 1; 1515 1516 if (Coord.Y < 0) 1517 Coord.Y = 0; 1518 else if (Coord.Y >= Buffer->ScreenBufferSize.Y) 1519 Coord.Y = Buffer->ScreenBufferSize.Y - 1; 1520 1521 return Coord; 1522 } 1523 1524 static LRESULT 1525 OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam) 1526 { 1527 BOOL DoDefault = FALSE; 1528 PCONSRV_CONSOLE Console = GuiData->Console; 1529 1530 /* 1531 * HACK FOR CORE-8394 (Part 2): 1532 * 1533 * Check whether we should ignore the next mouse move event. 1534 * In either case we reset the HACK flag. 1535 * 1536 * See Part 1 of this hack below. 1537 */ 1538 if (GuiData->HackCORE8394IgnoreNextMove && msg == WM_MOUSEMOVE) 1539 { 1540 GuiData->HackCORE8394IgnoreNextMove = FALSE; 1541 goto Quit; 1542 } 1543 GuiData->HackCORE8394IgnoreNextMove = FALSE; 1544 1545 // FIXME: It's here that we need to check whether we have focus or not 1546 // and whether we are or not in edit mode, in order to know if we need 1547 // to deal with the mouse. 1548 1549 if (GuiData->IgnoreNextMouseSignal) 1550 { 1551 if (msg != WM_LBUTTONDOWN && 1552 msg != WM_MBUTTONDOWN && 1553 msg != WM_RBUTTONDOWN && 1554 msg != WM_XBUTTONDOWN) 1555 { 1556 /* 1557 * If this mouse signal is not a button-down action 1558 * then this is the last one being ignored. 1559 */ 1560 GuiData->IgnoreNextMouseSignal = FALSE; 1561 } 1562 else 1563 { 1564 /* 1565 * This mouse signal is a button-down action. 1566 * Ignore it and perform default action. 1567 */ 1568 DoDefault = TRUE; 1569 } 1570 goto Quit; 1571 } 1572 1573 if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) 1574 { 1575 DoDefault = TRUE; 1576 goto Quit; 1577 } 1578 1579 if ( (GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) || 1580 (Console->QuickEdit) ) 1581 { 1582 switch (msg) 1583 { 1584 case WM_LBUTTONDOWN: 1585 { 1586 /* Check for selection state */ 1587 if ( (GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) && 1588 (GuiData->Selection.dwFlags & CONSOLE_MOUSE_SELECTION) && 1589 (GetKeyState(VK_SHIFT) & KEY_PRESSED) ) 1590 { 1591 /* 1592 * A mouse selection is currently in progress and the user 1593 * has pressed the SHIFT key and clicked somewhere, update 1594 * the selection. 1595 */ 1596 GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam); 1597 UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor); 1598 } 1599 else 1600 { 1601 /* Clear the old selection */ 1602 GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION; 1603 1604 /* Restart a new selection */ 1605 GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam); 1606 SetCapture(GuiData->hWindow); 1607 GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN; 1608 UpdateSelection(GuiData, 1609 &GuiData->dwSelectionCursor, 1610 &GuiData->dwSelectionCursor); 1611 } 1612 1613 break; 1614 } 1615 1616 case WM_LBUTTONUP: 1617 { 1618 if (!(GuiData->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break; 1619 1620 // GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam); 1621 GuiData->Selection.dwFlags &= ~CONSOLE_MOUSE_DOWN; 1622 // UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor); 1623 ReleaseCapture(); 1624 1625 break; 1626 } 1627 1628 case WM_LBUTTONDBLCLK: 1629 { 1630 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer; 1631 1632 if (GetType(Buffer) == TEXTMODE_BUFFER) 1633 { 1634 #define IS_WORD_SEP(c) \ 1635 ((c) == L'\0' || (c) == L' ' || (c) == L'\t' || (c) == L'\r' || (c) == L'\n') 1636 1637 PTEXTMODE_SCREEN_BUFFER TextBuffer = (PTEXTMODE_SCREEN_BUFFER)Buffer; 1638 COORD cL, cR; 1639 PCHAR_INFO ptrL, ptrR; 1640 1641 /* Starting point */ 1642 cL = cR = PointToCoord(GuiData, lParam); 1643 ptrL = ptrR = ConioCoordToPointer(TextBuffer, cL.X, cL.Y); 1644 1645 /* Enlarge the selection by checking for whitespace */ 1646 while ((0 < cL.X) && !IS_WORD_SEP(ptrL->Char.UnicodeChar) 1647 && !IS_WORD_SEP((ptrL-1)->Char.UnicodeChar)) 1648 { 1649 --cL.X; 1650 --ptrL; 1651 } 1652 while ((cR.X < TextBuffer->ScreenBufferSize.X - 1) && 1653 !IS_WORD_SEP(ptrR->Char.UnicodeChar) && 1654 !IS_WORD_SEP((ptrR+1)->Char.UnicodeChar)) 1655 { 1656 ++cR.X; 1657 ++ptrR; 1658 } 1659 1660 /* 1661 * Update the selection started with the single 1662 * left-click that preceded this double-click. 1663 */ 1664 GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN; 1665 UpdateSelection(GuiData, &cL, &cR); 1666 1667 /* Ignore the next mouse move signal */ 1668 GuiData->IgnoreNextMouseSignal = TRUE; 1669 #undef IS_WORD_SEP 1670 } 1671 1672 break; 1673 } 1674 1675 case WM_RBUTTONDOWN: 1676 case WM_RBUTTONDBLCLK: 1677 { 1678 if (!(GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)) 1679 { 1680 Paste(GuiData); 1681 } 1682 else 1683 { 1684 Copy(GuiData); 1685 } 1686 1687 /* Ignore the next mouse move signal */ 1688 GuiData->IgnoreNextMouseSignal = TRUE; 1689 break; 1690 } 1691 1692 case WM_MOUSEMOVE: 1693 { 1694 if (!(GET_KEYSTATE_WPARAM(wParam) & MK_LBUTTON)) break; 1695 if (!(GuiData->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break; 1696 1697 GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam); 1698 UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor); 1699 break; 1700 } 1701 1702 default: 1703 DoDefault = TRUE; // FALSE; 1704 break; 1705 } 1706 } 1707 else if (Console->InputBuffer.Mode & ENABLE_MOUSE_INPUT) 1708 { 1709 INPUT_RECORD er; 1710 WORD wKeyState = GET_KEYSTATE_WPARAM(wParam); 1711 DWORD dwButtonState = 0; 1712 DWORD dwControlKeyState = 0; 1713 DWORD dwEventFlags = 0; 1714 1715 switch (msg) 1716 { 1717 case WM_LBUTTONDOWN: 1718 SetCapture(GuiData->hWindow); 1719 dwButtonState = FROM_LEFT_1ST_BUTTON_PRESSED; 1720 dwEventFlags = 0; 1721 break; 1722 1723 case WM_MBUTTONDOWN: 1724 SetCapture(GuiData->hWindow); 1725 dwButtonState = FROM_LEFT_2ND_BUTTON_PRESSED; 1726 dwEventFlags = 0; 1727 break; 1728 1729 case WM_RBUTTONDOWN: 1730 SetCapture(GuiData->hWindow); 1731 dwButtonState = RIGHTMOST_BUTTON_PRESSED; 1732 dwEventFlags = 0; 1733 break; 1734 1735 case WM_XBUTTONDOWN: 1736 { 1737 /* Get which X-button was pressed */ 1738 WORD wButton = GET_XBUTTON_WPARAM(wParam); 1739 1740 /* Check for X-button validity */ 1741 if (wButton & ~(XBUTTON1 | XBUTTON2)) 1742 { 1743 DPRINT1("X-button 0x%04x invalid\n", wButton); 1744 DoDefault = TRUE; 1745 break; 1746 } 1747 1748 SetCapture(GuiData->hWindow); 1749 dwButtonState = (wButton == XBUTTON1 ? FROM_LEFT_3RD_BUTTON_PRESSED 1750 : FROM_LEFT_4TH_BUTTON_PRESSED); 1751 dwEventFlags = 0; 1752 break; 1753 } 1754 1755 case WM_LBUTTONUP: 1756 ReleaseCapture(); 1757 dwButtonState = 0; 1758 dwEventFlags = 0; 1759 break; 1760 1761 case WM_MBUTTONUP: 1762 ReleaseCapture(); 1763 dwButtonState = 0; 1764 dwEventFlags = 0; 1765 break; 1766 1767 case WM_RBUTTONUP: 1768 ReleaseCapture(); 1769 dwButtonState = 0; 1770 dwEventFlags = 0; 1771 break; 1772 1773 case WM_XBUTTONUP: 1774 { 1775 /* Get which X-button was released */ 1776 WORD wButton = GET_XBUTTON_WPARAM(wParam); 1777 1778 /* Check for X-button validity */ 1779 if (wButton & ~(XBUTTON1 | XBUTTON2)) 1780 { 1781 DPRINT1("X-button 0x%04x invalid\n", wButton); 1782 /* Ok, just release the button anyway... */ 1783 } 1784 1785 ReleaseCapture(); 1786 dwButtonState = 0; 1787 dwEventFlags = 0; 1788 break; 1789 } 1790 1791 case WM_LBUTTONDBLCLK: 1792 dwButtonState = FROM_LEFT_1ST_BUTTON_PRESSED; 1793 dwEventFlags = DOUBLE_CLICK; 1794 break; 1795 1796 case WM_MBUTTONDBLCLK: 1797 dwButtonState = FROM_LEFT_2ND_BUTTON_PRESSED; 1798 dwEventFlags = DOUBLE_CLICK; 1799 break; 1800 1801 case WM_RBUTTONDBLCLK: 1802 dwButtonState = RIGHTMOST_BUTTON_PRESSED; 1803 dwEventFlags = DOUBLE_CLICK; 1804 break; 1805 1806 case WM_XBUTTONDBLCLK: 1807 { 1808 /* Get which X-button was double-clicked */ 1809 WORD wButton = GET_XBUTTON_WPARAM(wParam); 1810 1811 /* Check for X-button validity */ 1812 if (wButton & ~(XBUTTON1 | XBUTTON2)) 1813 { 1814 DPRINT1("X-button 0x%04x invalid\n", wButton); 1815 DoDefault = TRUE; 1816 break; 1817 } 1818 1819 dwButtonState = (wButton == XBUTTON1 ? FROM_LEFT_3RD_BUTTON_PRESSED 1820 : FROM_LEFT_4TH_BUTTON_PRESSED); 1821 dwEventFlags = DOUBLE_CLICK; 1822 break; 1823 } 1824 1825 case WM_MOUSEMOVE: 1826 dwButtonState = 0; 1827 dwEventFlags = MOUSE_MOVED; 1828 break; 1829 1830 case WM_MOUSEWHEEL: 1831 dwButtonState = GET_WHEEL_DELTA_WPARAM(wParam) << 16; 1832 dwEventFlags = MOUSE_WHEELED; 1833 break; 1834 1835 case WM_MOUSEHWHEEL: 1836 dwButtonState = GET_WHEEL_DELTA_WPARAM(wParam) << 16; 1837 dwEventFlags = MOUSE_HWHEELED; 1838 break; 1839 1840 default: 1841 DoDefault = TRUE; 1842 break; 1843 } 1844 1845 /* 1846 * HACK FOR CORE-8394 (Part 1): 1847 * 1848 * It appears that depending on which VM ReactOS runs, the next mouse 1849 * signal coming after a button-down action can be a mouse-move (e.g. 1850 * on VBox, whereas on QEMU it is not the case). However it is NOT a 1851 * rule, so that we cannot use the IgnoreNextMouseSignal flag to just 1852 * "ignore" the next mouse event, thinking it would always be a mouse- 1853 * move signal. 1854 * 1855 * To work around this problem (that should really be fixed in Win32k), 1856 * we use a second flag to ignore this possible next mouse move signal. 1857 */ 1858 switch (msg) 1859 { 1860 case WM_LBUTTONDOWN: 1861 case WM_MBUTTONDOWN: 1862 case WM_RBUTTONDOWN: 1863 case WM_XBUTTONDOWN: 1864 GuiData->HackCORE8394IgnoreNextMove = TRUE; 1865 default: 1866 break; 1867 } 1868 1869 if (!DoDefault) 1870 { 1871 if (wKeyState & MK_LBUTTON) 1872 dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED; 1873 if (wKeyState & MK_MBUTTON) 1874 dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED; 1875 if (wKeyState & MK_RBUTTON) 1876 dwButtonState |= RIGHTMOST_BUTTON_PRESSED; 1877 if (wKeyState & MK_XBUTTON1) 1878 dwButtonState |= FROM_LEFT_3RD_BUTTON_PRESSED; 1879 if (wKeyState & MK_XBUTTON2) 1880 dwButtonState |= FROM_LEFT_4TH_BUTTON_PRESSED; 1881 1882 if (GetKeyState(VK_RMENU) & KEY_PRESSED) 1883 dwControlKeyState |= RIGHT_ALT_PRESSED; 1884 if (GetKeyState(VK_LMENU) & KEY_PRESSED) 1885 dwControlKeyState |= LEFT_ALT_PRESSED; 1886 if (GetKeyState(VK_RCONTROL) & KEY_PRESSED) 1887 dwControlKeyState |= RIGHT_CTRL_PRESSED; 1888 if (GetKeyState(VK_LCONTROL) & KEY_PRESSED) 1889 dwControlKeyState |= LEFT_CTRL_PRESSED; 1890 if (GetKeyState(VK_SHIFT) & KEY_PRESSED) 1891 dwControlKeyState |= SHIFT_PRESSED; 1892 if (GetKeyState(VK_NUMLOCK) & KEY_TOGGLED) 1893 dwControlKeyState |= NUMLOCK_ON; 1894 if (GetKeyState(VK_SCROLL) & KEY_TOGGLED) 1895 dwControlKeyState |= SCROLLLOCK_ON; 1896 if (GetKeyState(VK_CAPITAL) & KEY_TOGGLED) 1897 dwControlKeyState |= CAPSLOCK_ON; 1898 /* See WM_CHAR MSDN documentation for instance */ 1899 if (lParam & 0x01000000) 1900 dwControlKeyState |= ENHANCED_KEY; 1901 1902 /* Send a mouse event */ 1903 er.EventType = MOUSE_EVENT; 1904 er.Event.MouseEvent.dwMousePosition = PointToCoord(GuiData, lParam); 1905 er.Event.MouseEvent.dwButtonState = dwButtonState; 1906 er.Event.MouseEvent.dwControlKeyState = dwControlKeyState; 1907 er.Event.MouseEvent.dwEventFlags = dwEventFlags; 1908 1909 ConioProcessInputEvent(Console, &er); 1910 } 1911 } 1912 else 1913 { 1914 DoDefault = TRUE; 1915 } 1916 1917 LeaveCriticalSection(&Console->Lock); 1918 1919 Quit: 1920 if (!DoDefault) 1921 return 0; 1922 1923 if (msg == WM_MOUSEWHEEL || msg == WM_MOUSEHWHEEL) 1924 { 1925 INT nBar; 1926 WORD sbCode; 1927 // WORD wKeyState = GET_KEYSTATE_WPARAM(wParam); 1928 SHORT wDelta = GET_WHEEL_DELTA_WPARAM(wParam); 1929 1930 if (msg == WM_MOUSEWHEEL) 1931 nBar = SB_VERT; 1932 else // if (msg == WM_MOUSEHWHEEL) 1933 nBar = SB_HORZ; 1934 1935 // NOTE: We currently do not support zooming... 1936 // if (wKeyState & MK_CONTROL) 1937 1938 // FIXME: For some reason our win32k does not set the key states 1939 // when sending WM_MOUSEWHEEL or WM_MOUSEHWHEEL ... 1940 // if (wKeyState & MK_SHIFT) 1941 if (GetKeyState(VK_SHIFT) & KEY_PRESSED) 1942 sbCode = (wDelta >= 0 ? SB_PAGEUP : SB_PAGEDOWN); 1943 else 1944 sbCode = (wDelta >= 0 ? SB_LINEUP : SB_LINEDOWN); 1945 1946 OnScroll(GuiData, nBar, sbCode); 1947 } 1948 1949 return DefWindowProcW(GuiData->hWindow, msg, wParam, lParam); 1950 } 1951 1952 1953 static VOID 1954 Copy(PGUI_CONSOLE_DATA GuiData) 1955 { 1956 if (OpenClipboard(GuiData->hWindow)) 1957 { 1958 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer; 1959 1960 if (GetType(Buffer) == TEXTMODE_BUFFER) 1961 { 1962 GuiCopyFromTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)Buffer, GuiData); 1963 } 1964 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */ 1965 { 1966 GuiCopyFromGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)Buffer, GuiData); 1967 } 1968 1969 CloseClipboard(); 1970 } 1971 1972 /* Clear the selection */ 1973 UpdateSelection(GuiData, NULL, NULL); 1974 } 1975 1976 static VOID 1977 Paste(PGUI_CONSOLE_DATA GuiData) 1978 { 1979 if (OpenClipboard(GuiData->hWindow)) 1980 { 1981 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer; 1982 1983 if (GetType(Buffer) == TEXTMODE_BUFFER) 1984 { 1985 GuiPasteToTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)Buffer, GuiData); 1986 } 1987 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */ 1988 { 1989 GuiPasteToGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)Buffer, GuiData); 1990 } 1991 1992 CloseClipboard(); 1993 } 1994 } 1995 1996 static VOID 1997 OnGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo) 1998 { 1999 PCONSRV_CONSOLE Console = GuiData->Console; 2000 PCONSOLE_SCREEN_BUFFER ActiveBuffer; 2001 DWORD windx, windy; 2002 UINT WidthUnit, HeightUnit; 2003 2004 if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return; 2005 2006 ActiveBuffer = GuiData->ActiveBuffer; 2007 2008 GetScreenBufferSizeUnits(ActiveBuffer, GuiData, &WidthUnit, &HeightUnit); 2009 2010 windx = CONGUI_MIN_WIDTH * WidthUnit + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)); 2011 windy = CONGUI_MIN_HEIGHT * HeightUnit + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION); 2012 2013 minMaxInfo->ptMinTrackSize.x = windx; 2014 minMaxInfo->ptMinTrackSize.y = windy; 2015 2016 windx = (ActiveBuffer->ScreenBufferSize.X) * WidthUnit + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)); 2017 windy = (ActiveBuffer->ScreenBufferSize.Y) * HeightUnit + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION); 2018 2019 if (ActiveBuffer->ViewSize.X < ActiveBuffer->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // Window currently has a horizontal scrollbar 2020 if (ActiveBuffer->ViewSize.Y < ActiveBuffer->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // Window currently has a vertical scrollbar 2021 2022 minMaxInfo->ptMaxTrackSize.x = windx; 2023 minMaxInfo->ptMaxTrackSize.y = windy; 2024 2025 LeaveCriticalSection(&Console->Lock); 2026 } 2027 2028 static VOID 2029 OnSize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam) 2030 { 2031 PCONSRV_CONSOLE Console = GuiData->Console; 2032 2033 /* Do nothing if the window is hidden */ 2034 if (!GuiData->IsWindowVisible) return; 2035 2036 if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return; 2037 2038 if (!GuiData->WindowSizeLock && 2039 (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED)) 2040 { 2041 PCONSOLE_SCREEN_BUFFER Buff = GuiData->ActiveBuffer; 2042 DWORD windx, windy, charx, chary; 2043 UINT WidthUnit, HeightUnit; 2044 2045 GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit); 2046 2047 GuiData->WindowSizeLock = TRUE; 2048 2049 windx = LOWORD(lParam); 2050 windy = HIWORD(lParam); 2051 2052 /* Compensate for existing scroll bars (because lParam values do not accommodate scroll bar) */ 2053 if (Buff->ViewSize.X < Buff->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // Window currently has a horizontal scrollbar 2054 if (Buff->ViewSize.Y < Buff->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // Window currently has a vertical scrollbar 2055 2056 charx = windx / (int)WidthUnit ; 2057 chary = windy / (int)HeightUnit; 2058 2059 /* Character alignment (round size up or down) */ 2060 if ((windx % WidthUnit ) >= (WidthUnit / 2)) ++charx; 2061 if ((windy % HeightUnit) >= (HeightUnit / 2)) ++chary; 2062 2063 /* Compensate for added scroll bars in window */ 2064 if (charx < (DWORD)Buff->ScreenBufferSize.X) windy -= GetSystemMetrics(SM_CYHSCROLL); // Window will have a horizontal scroll bar 2065 if (chary < (DWORD)Buff->ScreenBufferSize.Y) windx -= GetSystemMetrics(SM_CXVSCROLL); // Window will have a vertical scroll bar 2066 2067 charx = windx / (int)WidthUnit ; 2068 chary = windy / (int)HeightUnit; 2069 2070 /* Character alignment (round size up or down) */ 2071 if ((windx % WidthUnit ) >= (WidthUnit / 2)) ++charx; 2072 if ((windy % HeightUnit) >= (HeightUnit / 2)) ++chary; 2073 2074 /* Resize window */ 2075 if ((charx != Buff->ViewSize.X) || (chary != Buff->ViewSize.Y)) 2076 { 2077 Buff->ViewSize.X = (charx <= (DWORD)Buff->ScreenBufferSize.X) ? charx : Buff->ScreenBufferSize.X; 2078 Buff->ViewSize.Y = (chary <= (DWORD)Buff->ScreenBufferSize.Y) ? chary : Buff->ScreenBufferSize.Y; 2079 } 2080 2081 ResizeConWnd(GuiData, WidthUnit, HeightUnit); 2082 2083 /* Adjust the start of the visible area if we are attempting to show nonexistent areas */ 2084 if ((Buff->ScreenBufferSize.X - Buff->ViewOrigin.X) < Buff->ViewSize.X) Buff->ViewOrigin.X = Buff->ScreenBufferSize.X - Buff->ViewSize.X; 2085 if ((Buff->ScreenBufferSize.Y - Buff->ViewOrigin.Y) < Buff->ViewSize.Y) Buff->ViewOrigin.Y = Buff->ScreenBufferSize.Y - Buff->ViewSize.Y; 2086 InvalidateRect(GuiData->hWindow, NULL, TRUE); 2087 2088 GuiData->WindowSizeLock = FALSE; 2089 } 2090 2091 LeaveCriticalSection(&Console->Lock); 2092 } 2093 2094 static VOID 2095 OnMove(PGUI_CONSOLE_DATA GuiData) 2096 { 2097 RECT rcWnd; 2098 2099 // TODO: Simplify the code. 2100 // See: GuiConsoleNotifyWndProc() PM_CREATE_CONSOLE. 2101 2102 /* Retrieve our real position */ 2103 GetWindowRect(GuiData->hWindow, &rcWnd); 2104 GuiData->GuiInfo.WindowOrigin.x = rcWnd.left; 2105 GuiData->GuiInfo.WindowOrigin.y = rcWnd.top; 2106 } 2107 2108 static VOID 2109 OnDropFiles(PCONSRV_CONSOLE Console, HDROP hDrop) 2110 { 2111 LPWSTR pszPath; 2112 WCHAR szPath[MAX_PATH + 2]; 2113 2114 szPath[0] = L'"'; 2115 2116 DragQueryFileW(hDrop, 0, &szPath[1], ARRAYSIZE(szPath) - 1); 2117 DragFinish(hDrop); 2118 2119 if (wcschr(&szPath[1], L' ') != NULL) 2120 { 2121 StringCchCatW(szPath, ARRAYSIZE(szPath), L"\""); 2122 pszPath = szPath; 2123 } 2124 else 2125 { 2126 pszPath = &szPath[1]; 2127 } 2128 2129 PasteText(Console, pszPath, wcslen(pszPath)); 2130 } 2131 2132 /* 2133 // HACK: This functionality is standard for general scrollbars. Don't add it by hand. 2134 2135 VOID 2136 GuiConsoleHandleScrollbarMenu(VOID) 2137 { 2138 HMENU hMenu; 2139 2140 hMenu = CreatePopupMenu(); 2141 if (hMenu == NULL) 2142 { 2143 DPRINT("CreatePopupMenu failed\n"); 2144 return; 2145 } 2146 2147 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE); 2148 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1); 2149 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP); 2150 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM); 2151 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1); 2152 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP); 2153 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN); 2154 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1); 2155 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP); 2156 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN); 2157 } 2158 */ 2159 2160 static LRESULT CALLBACK 2161 ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 2162 { 2163 LRESULT Result = 0; 2164 PGUI_CONSOLE_DATA GuiData = NULL; 2165 PCONSRV_CONSOLE Console = NULL; 2166 2167 /* 2168 * - If it's the first time we create a window for the terminal, 2169 * just initialize it and return. 2170 * 2171 * - If we are destroying the window, just do it and return. 2172 */ 2173 if (msg == WM_NCCREATE) 2174 { 2175 return (LRESULT)OnNcCreate(hWnd, (LPCREATESTRUCTW)lParam); 2176 } 2177 else if (msg == WM_NCDESTROY) 2178 { 2179 return OnNcDestroy(hWnd); 2180 } 2181 2182 /* 2183 * Now the terminal window is initialized. 2184 * Get the terminal data via the window's data. 2185 * If there is no data, just go away. 2186 */ 2187 GuiData = GuiGetGuiData(hWnd); 2188 if (GuiData == NULL) return DefWindowProcW(hWnd, msg, wParam, lParam); 2189 2190 // TEMPORARY HACK until all of the functions can deal with a NULL GuiData->ActiveBuffer ... 2191 if (GuiData->ActiveBuffer == NULL) return DefWindowProcW(hWnd, msg, wParam, lParam); 2192 2193 /* 2194 * Just retrieve a pointer to the console in case somebody needs it. 2195 * It is not NULL because it was checked in GuiGetGuiData. 2196 * Each helper function which needs the console has to validate and lock it. 2197 */ 2198 Console = GuiData->Console; 2199 2200 /* We have a console, start message dispatching */ 2201 switch (msg) 2202 { 2203 case WM_ACTIVATE: 2204 OnActivate(GuiData, wParam); 2205 break; 2206 2207 case WM_CLOSE: 2208 if (OnClose(GuiData)) goto Default; 2209 break; 2210 2211 case WM_PAINT: 2212 OnPaint(GuiData); 2213 break; 2214 2215 case WM_TIMER: 2216 OnTimer(GuiData); 2217 break; 2218 2219 case WM_PALETTECHANGED: 2220 { 2221 DPRINT("WM_PALETTECHANGED called\n"); 2222 2223 /* 2224 * Protects against infinite loops: 2225 * "... A window that receives this message must not realize 2226 * its palette, unless it determines that wParam does not contain 2227 * its own window handle." (WM_PALETTECHANGED description - MSDN) 2228 * 2229 * This message is sent to all windows, including the one that 2230 * changed the system palette and caused this message to be sent. 2231 * The wParam of this message contains the handle of the window 2232 * that caused the system palette to change. To avoid an infinite 2233 * loop, care must be taken to check that the wParam of this message 2234 * does not match the window's handle. 2235 */ 2236 if ((HWND)wParam == hWnd) break; 2237 2238 DPRINT("WM_PALETTECHANGED ok\n"); 2239 OnPaletteChanged(GuiData); 2240 DPRINT("WM_PALETTECHANGED quit\n"); 2241 break; 2242 } 2243 2244 case WM_KEYDOWN: 2245 case WM_KEYUP: 2246 case WM_CHAR: 2247 case WM_DEADCHAR: 2248 case WM_SYSKEYDOWN: 2249 case WM_SYSKEYUP: 2250 case WM_SYSCHAR: 2251 case WM_SYSDEADCHAR: 2252 { 2253 /* Detect Alt-Enter presses and switch back and forth to fullscreen mode */ 2254 if (msg == WM_SYSKEYDOWN && (HIWORD(lParam) & KF_ALTDOWN) && wParam == VK_RETURN) 2255 { 2256 /* Switch only at first Alt-Enter press, and ignore subsequent key repetitions */ 2257 if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) != KF_REPEAT) 2258 GuiConsoleSwitchFullScreen(GuiData); 2259 2260 break; 2261 } 2262 /* Detect Alt-Esc/Space/Tab presses defer to DefWindowProc */ 2263 if ( (HIWORD(lParam) & KF_ALTDOWN) && (wParam == VK_ESCAPE || wParam == VK_SPACE || wParam == VK_TAB)) 2264 { 2265 return DefWindowProcW(hWnd, msg, wParam, lParam); 2266 } 2267 2268 OnKey(GuiData, msg, wParam, lParam); 2269 break; 2270 } 2271 2272 case WM_SETCURSOR: 2273 { 2274 /* Do nothing if the window is hidden */ 2275 if (!GuiData->IsWindowVisible) goto Default; 2276 2277 /* 2278 * The message was sent because we are manually triggering a change. 2279 * Check whether the mouse is indeed present on this console window 2280 * and take appropriate decisions. 2281 */ 2282 if (wParam == -1 && lParam == -1) 2283 { 2284 POINT mouseCoords; 2285 HWND hWndHit; 2286 2287 /* Get the placement of the mouse */ 2288 GetCursorPos(&mouseCoords); 2289 2290 /* On which window is placed the mouse ? */ 2291 hWndHit = WindowFromPoint(mouseCoords); 2292 2293 /* It's our window. Perform the hit-test to be used later on. */ 2294 if (hWndHit == hWnd) 2295 { 2296 wParam = (WPARAM)hWnd; 2297 lParam = DefWindowProcW(hWndHit, WM_NCHITTEST, 0, 2298 MAKELPARAM(mouseCoords.x, mouseCoords.y)); 2299 } 2300 } 2301 2302 /* Set the mouse cursor only when we are in the client area */ 2303 if ((HWND)wParam == hWnd && LOWORD(lParam) == HTCLIENT) 2304 { 2305 if (GuiData->MouseCursorRefCount >= 0) 2306 { 2307 /* Show the cursor */ 2308 SetCursor(GuiData->hCursor); 2309 } 2310 else 2311 { 2312 /* Hide the cursor if the reference count is negative */ 2313 SetCursor(NULL); 2314 } 2315 return TRUE; 2316 } 2317 else 2318 { 2319 goto Default; 2320 } 2321 } 2322 2323 case WM_LBUTTONDOWN: 2324 case WM_MBUTTONDOWN: 2325 case WM_RBUTTONDOWN: 2326 case WM_XBUTTONDOWN: 2327 case WM_LBUTTONUP: 2328 case WM_MBUTTONUP: 2329 case WM_RBUTTONUP: 2330 case WM_XBUTTONUP: 2331 case WM_LBUTTONDBLCLK: 2332 case WM_MBUTTONDBLCLK: 2333 case WM_RBUTTONDBLCLK: 2334 case WM_XBUTTONDBLCLK: 2335 case WM_MOUSEMOVE: 2336 case WM_MOUSEWHEEL: 2337 case WM_MOUSEHWHEEL: 2338 { 2339 Result = OnMouse(GuiData, msg, wParam, lParam); 2340 break; 2341 } 2342 2343 case WM_HSCROLL: 2344 OnScroll(GuiData, SB_HORZ, LOWORD(wParam)); 2345 break; 2346 2347 case WM_VSCROLL: 2348 OnScroll(GuiData, SB_VERT, LOWORD(wParam)); 2349 break; 2350 2351 case WM_CONTEXTMENU: 2352 { 2353 /* Do nothing if the window is hidden */ 2354 if (!GuiData->IsWindowVisible) break; 2355 2356 if (DefWindowProcW(hWnd /*GuiData->hWindow*/, WM_NCHITTEST, 0, lParam) == HTCLIENT) 2357 { 2358 HMENU hMenu = CreatePopupMenu(); 2359 if (hMenu != NULL) 2360 { 2361 AppendMenuItems(hMenu, GuiConsoleEditMenuItems); 2362 TrackPopupMenuEx(hMenu, 2363 TPM_RIGHTBUTTON, 2364 GET_X_LPARAM(lParam), 2365 GET_Y_LPARAM(lParam), 2366 hWnd, 2367 NULL); 2368 DestroyMenu(hMenu); 2369 } 2370 break; 2371 } 2372 else 2373 { 2374 goto Default; 2375 } 2376 } 2377 2378 case WM_INITMENU: 2379 { 2380 HMENU hMenu = (HMENU)wParam; 2381 if (hMenu != NULL) 2382 { 2383 /* Enable or disable the Close menu item */ 2384 EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | 2385 (GuiData->IsCloseButtonEnabled ? MF_ENABLED : MF_GRAYED)); 2386 2387 /* Enable or disable the Copy and Paste items */ 2388 EnableMenuItem(hMenu, ID_SYSTEM_EDIT_COPY , MF_BYCOMMAND | 2389 ((GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) && 2390 (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY) ? MF_ENABLED : MF_GRAYED)); 2391 // FIXME: Following whether the active screen buffer is text-mode 2392 // or graphics-mode, search for CF_UNICODETEXT or CF_BITMAP formats. 2393 EnableMenuItem(hMenu, ID_SYSTEM_EDIT_PASTE, MF_BYCOMMAND | 2394 (!(GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) && 2395 IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED)); 2396 } 2397 2398 SendMenuEvent(Console, WM_INITMENU); 2399 break; 2400 } 2401 2402 case WM_MENUSELECT: 2403 { 2404 if (HIWORD(wParam) == 0xFFFF) // Allow all the menu flags 2405 { 2406 SendMenuEvent(Console, WM_MENUSELECT); 2407 } 2408 break; 2409 } 2410 2411 case WM_COMMAND: 2412 case WM_SYSCOMMAND: 2413 { 2414 Result = OnCommand(GuiData, wParam, lParam); 2415 break; 2416 } 2417 2418 case WM_DROPFILES: 2419 OnDropFiles(Console, (HDROP)wParam); 2420 break; 2421 2422 case WM_SETFOCUS: 2423 case WM_KILLFOCUS: 2424 OnFocus(GuiData, (msg == WM_SETFOCUS)); 2425 break; 2426 2427 case WM_GETMINMAXINFO: 2428 OnGetMinMaxInfo(GuiData, (PMINMAXINFO)lParam); 2429 break; 2430 2431 case WM_MOVE: 2432 OnMove(GuiData); 2433 break; 2434 2435 #if 0 // This code is here to prepare & control dynamic console SB resizing. 2436 case WM_SIZING: 2437 { 2438 PRECT dragRect = (PRECT)lParam; 2439 switch (wParam) 2440 { 2441 case WMSZ_LEFT: 2442 DPRINT1("WMSZ_LEFT\n"); 2443 break; 2444 case WMSZ_RIGHT: 2445 DPRINT1("WMSZ_RIGHT\n"); 2446 break; 2447 case WMSZ_TOP: 2448 DPRINT1("WMSZ_TOP\n"); 2449 break; 2450 case WMSZ_TOPLEFT: 2451 DPRINT1("WMSZ_TOPLEFT\n"); 2452 break; 2453 case WMSZ_TOPRIGHT: 2454 DPRINT1("WMSZ_TOPRIGHT\n"); 2455 break; 2456 case WMSZ_BOTTOM: 2457 DPRINT1("WMSZ_BOTTOM\n"); 2458 break; 2459 case WMSZ_BOTTOMLEFT: 2460 DPRINT1("WMSZ_BOTTOMLEFT\n"); 2461 break; 2462 case WMSZ_BOTTOMRIGHT: 2463 DPRINT1("WMSZ_BOTTOMRIGHT\n"); 2464 break; 2465 default: 2466 DPRINT1("wParam = %d\n", wParam); 2467 break; 2468 } 2469 DPRINT1("dragRect = {.left = %d ; .top = %d ; .right = %d ; .bottom = %d}\n", 2470 dragRect->left, dragRect->top, dragRect->right, dragRect->bottom); 2471 break; 2472 } 2473 #endif 2474 2475 case WM_SIZE: 2476 OnSize(GuiData, wParam, lParam); 2477 break; 2478 2479 case PM_RESIZE_TERMINAL: 2480 { 2481 PCONSOLE_SCREEN_BUFFER Buff = GuiData->ActiveBuffer; 2482 HDC hDC; 2483 HBITMAP hnew, hold; 2484 2485 DWORD Width, Height; 2486 UINT WidthUnit, HeightUnit; 2487 2488 /* Do nothing if the window is hidden */ 2489 if (!GuiData->IsWindowVisible) break; 2490 2491 GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit); 2492 2493 Width = Buff->ScreenBufferSize.X * WidthUnit ; 2494 Height = Buff->ScreenBufferSize.Y * HeightUnit; 2495 2496 /* Recreate the framebuffer */ 2497 hDC = GetDC(GuiData->hWindow); 2498 hnew = CreateCompatibleBitmap(hDC, Width, Height); 2499 ReleaseDC(GuiData->hWindow, hDC); 2500 hold = SelectObject(GuiData->hMemDC, hnew); 2501 if (GuiData->hBitmap) 2502 { 2503 if (hold == GuiData->hBitmap) DeleteObject(GuiData->hBitmap); 2504 } 2505 GuiData->hBitmap = hnew; 2506 2507 /* Resize the window to the user's values */ 2508 GuiData->WindowSizeLock = TRUE; 2509 ResizeConWnd(GuiData, WidthUnit, HeightUnit); 2510 GuiData->WindowSizeLock = FALSE; 2511 break; 2512 } 2513 2514 /* 2515 * Undocumented message sent by Windows' console.dll for applying console info. 2516 * See http://www.catch22.net/sites/default/source/files/setconsoleinfo.c 2517 * and http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf 2518 * for more information. 2519 */ 2520 case WM_SETCONSOLEINFO: 2521 { 2522 GuiApplyUserSettings(GuiData, (HANDLE)wParam); 2523 break; 2524 } 2525 2526 case PM_CONSOLE_BEEP: 2527 DPRINT1("Beep\n"); 2528 Beep(800, 200); 2529 break; 2530 2531 case PM_CONSOLE_SET_TITLE: 2532 SetWindowTextW(GuiData->hWindow, GuiData->Console->Title.Buffer); 2533 break; 2534 2535 default: Default: 2536 Result = DefWindowProcW(hWnd, msg, wParam, lParam); 2537 break; 2538 } 2539 2540 return Result; 2541 } 2542 2543 /* EOF */ 2544