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