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