2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: frontends/gui/conwnd.c
5 * PURPOSE: GUI Console Window Class
6 * PROGRAMMERS: Gé van Geldorp
9 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
12 /* INCLUDES *******************************************************************/
25 /* GLOBALS ********************************************************************/
27 // #define PM_CREATE_CONSOLE (WM_APP + 1)
28 // #define PM_DESTROY_CONSOLE (WM_APP + 2)
31 #define CONGUI_MIN_WIDTH 10
32 #define CONGUI_MIN_HEIGHT 10
33 #define CONGUI_UPDATE_TIME 0
34 #define CONGUI_UPDATE_TIMER 1
36 #define CURSOR_BLINK_TIME 500
39 /**************************************************************\
40 \** Define the Console Leader Process for the console window **/
41 #define GWLP_CONWND_ALLOC (2 * sizeof(LONG_PTR))
42 #define GWLP_CONSOLE_LEADER_PID 0
43 #define GWLP_CONSOLE_LEADER_TID 4
46 SetConWndConsoleLeaderCID(IN PGUI_CONSOLE_DATA GuiData
)
48 PCONSOLE_PROCESS_DATA ProcessData
;
49 CLIENT_ID ConsoleLeaderCID
;
51 ProcessData
= ConDrvGetConsoleLeaderProcess(GuiData
->Console
);
52 ConsoleLeaderCID
= ProcessData
->Process
->ClientId
;
53 SetWindowLongPtrW(GuiData
->hWindow
, GWLP_CONSOLE_LEADER_PID
,
54 (LONG_PTR
)(ConsoleLeaderCID
.UniqueProcess
));
55 SetWindowLongPtrW(GuiData
->hWindow
, GWLP_CONSOLE_LEADER_TID
,
56 (LONG_PTR
)(ConsoleLeaderCID
.UniqueThread
));
58 /**************************************************************/
60 HICON ghDefaultIcon
= NULL
;
61 HICON ghDefaultIconSm
= NULL
;
62 HCURSOR ghDefaultCursor
= NULL
;
64 typedef struct _GUICONSOLE_MENUITEM
67 const struct _GUICONSOLE_MENUITEM
*SubMenu
;
69 } GUICONSOLE_MENUITEM
, *PGUICONSOLE_MENUITEM
;
71 static const GUICONSOLE_MENUITEM GuiConsoleEditMenuItems
[] =
73 { IDS_MARK
, NULL
, ID_SYSTEM_EDIT_MARK
},
74 { IDS_COPY
, NULL
, ID_SYSTEM_EDIT_COPY
},
75 { IDS_PASTE
, NULL
, ID_SYSTEM_EDIT_PASTE
},
76 { IDS_SELECTALL
, NULL
, ID_SYSTEM_EDIT_SELECTALL
},
77 { IDS_SCROLL
, NULL
, ID_SYSTEM_EDIT_SCROLL
},
78 { IDS_FIND
, NULL
, ID_SYSTEM_EDIT_FIND
},
80 { 0, NULL
, 0 } /* End of list */
83 static const GUICONSOLE_MENUITEM GuiConsoleMainMenuItems
[] =
85 { IDS_EDIT
, GuiConsoleEditMenuItems
, 0 },
86 { IDS_DEFAULTS
, NULL
, ID_SYSTEM_DEFAULTS
},
87 { IDS_PROPERTIES
, NULL
, ID_SYSTEM_PROPERTIES
},
89 { 0, NULL
, 0 } /* End of list */
93 * Default 16-color palette for foreground and background
94 * (corresponding flags in comments).
96 const COLORREF s_Colors
[16] =
98 RGB(0, 0, 0), // (Black)
99 RGB(0, 0, 128), // BLUE
100 RGB(0, 128, 0), // GREEN
101 RGB(0, 128, 128), // BLUE | GREEN
102 RGB(128, 0, 0), // RED
103 RGB(128, 0, 128), // BLUE | RED
104 RGB(128, 128, 0), // GREEN | RED
105 RGB(192, 192, 192), // BLUE | GREEN | RED
107 RGB(128, 128, 128), // (Grey) INTENSITY
108 RGB(0, 0, 255), // BLUE | INTENSITY
109 RGB(0, 255, 0), // GREEN | INTENSITY
110 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
111 RGB(255, 0, 0), // RED | INTENSITY
112 RGB(255, 0, 255), // BLUE | RED | INTENSITY
113 RGB(255, 255, 0), // GREEN | RED | INTENSITY
114 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
117 /* FUNCTIONS ******************************************************************/
119 static LRESULT CALLBACK
120 ConWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
123 RegisterConWndClass(IN HINSTANCE hInstance
)
125 WNDCLASSEXW WndClass
;
128 ghDefaultIcon
= LoadImageW(hInstance
,
129 MAKEINTRESOURCEW(IDI_TERMINAL
),
131 GetSystemMetrics(SM_CXICON
),
132 GetSystemMetrics(SM_CYICON
),
134 ghDefaultIconSm
= LoadImageW(hInstance
,
135 MAKEINTRESOURCEW(IDI_TERMINAL
),
137 GetSystemMetrics(SM_CXSMICON
),
138 GetSystemMetrics(SM_CYSMICON
),
140 ghDefaultCursor
= LoadCursorW(NULL
, IDC_ARROW
);
142 WndClass
.cbSize
= sizeof(WNDCLASSEXW
);
143 WndClass
.lpszClassName
= GUI_CONWND_CLASS
;
144 WndClass
.lpfnWndProc
= ConWndProc
;
145 WndClass
.style
= CS_DBLCLKS
/* | CS_HREDRAW | CS_VREDRAW */;
146 WndClass
.hInstance
= hInstance
;
147 WndClass
.hIcon
= ghDefaultIcon
;
148 WndClass
.hIconSm
= ghDefaultIconSm
;
149 WndClass
.hCursor
= ghDefaultCursor
;
150 WndClass
.hbrBackground
= (HBRUSH
)GetStockObject(BLACK_BRUSH
); // The color of a terminal when it is switched off.
151 WndClass
.lpszMenuName
= NULL
;
152 WndClass
.cbClsExtra
= 0;
153 WndClass
.cbWndExtra
= GWLP_CONWND_ALLOC
;
155 WndClassAtom
= RegisterClassExW(&WndClass
);
156 if (WndClassAtom
== 0)
158 DPRINT1("Failed to register GUI console class\n");
162 NtUserConsoleControl(GuiConsoleWndClassAtom
, &WndClassAtom
, sizeof(ATOM
));
165 return (WndClassAtom
!= 0);
169 UnRegisterConWndClass(HINSTANCE hInstance
)
171 return !!UnregisterClassW(GUI_CONWND_CLASS
, hInstance
);
177 GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer
,
178 IN PGUI_CONSOLE_DATA GuiData
,
180 OUT PUINT HeightUnit
)
182 if (Buffer
== NULL
|| GuiData
== NULL
||
183 WidthUnit
== NULL
|| HeightUnit
== NULL
)
188 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
190 *WidthUnit
= GuiData
->CharWidth
;
191 *HeightUnit
= GuiData
->CharHeight
;
193 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
201 AppendMenuItems(HMENU hMenu
,
202 const GUICONSOLE_MENUITEM
*Items
)
205 WCHAR szMenuString
[255];
210 if (Items
[i
].uID
!= (UINT
)-1)
212 if (LoadStringW(ConSrvDllInstance
,
215 sizeof(szMenuString
) / sizeof(szMenuString
[0])) > 0)
217 if (Items
[i
].SubMenu
!= NULL
)
219 hSubMenu
= CreatePopupMenu();
220 if (hSubMenu
!= NULL
)
222 AppendMenuItems(hSubMenu
, Items
[i
].SubMenu
);
224 if (!AppendMenuW(hMenu
,
225 MF_STRING
| MF_POPUP
,
229 DestroyMenu(hSubMenu
);
250 } while (!(Items
[i
].uID
== 0 && Items
[i
].SubMenu
== NULL
&& Items
[i
].wCmdID
== 0));
254 CreateSysMenu(HWND hWnd
)
257 WCHAR szMenuStringBack
[255];
259 HMENU hMenu
= GetSystemMenu(hWnd
, FALSE
);
262 mii
.cbSize
= sizeof(mii
);
263 mii
.fMask
= MIIM_STRING
;
264 mii
.dwTypeData
= szMenuStringBack
;
265 mii
.cch
= sizeof(szMenuStringBack
)/sizeof(WCHAR
);
267 GetMenuItemInfoW(hMenu
, SC_CLOSE
, FALSE
, &mii
);
269 ptrTab
= wcschr(szMenuStringBack
, '\t');
273 mii
.cch
= wcslen(szMenuStringBack
);
275 SetMenuItemInfoW(hMenu
, SC_CLOSE
, FALSE
, &mii
);
278 AppendMenuItems(hMenu
, GuiConsoleMainMenuItems
);
284 SendMenuEvent(PCONSOLE Console
, UINT CmdId
)
288 DPRINT1("Menu item ID: %d\n", CmdId
);
290 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
292 er
.EventType
= MENU_EVENT
;
293 er
.Event
.MenuEvent
.dwCommandId
= CmdId
;
294 ConioProcessInputEvent(Console
, &er
);
296 LeaveCriticalSection(&Console
->Lock
);
300 Copy(PGUI_CONSOLE_DATA GuiData
);
302 Paste(PGUI_CONSOLE_DATA GuiData
);
304 UpdateSelection(PGUI_CONSOLE_DATA GuiData
,
305 PCOORD SelectionAnchor OPTIONAL
,
309 Mark(PGUI_CONSOLE_DATA GuiData
)
311 PCONSOLE_SCREEN_BUFFER ActiveBuffer
= GuiData
->ActiveBuffer
;
313 /* Clear the old selection */
314 GuiData
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
316 /* Restart a new selection */
317 GuiData
->dwSelectionCursor
= ActiveBuffer
->ViewOrigin
;
318 UpdateSelection(GuiData
,
319 &GuiData
->dwSelectionCursor
,
320 &GuiData
->dwSelectionCursor
);
324 SelectAll(PGUI_CONSOLE_DATA GuiData
)
326 PCONSOLE_SCREEN_BUFFER ActiveBuffer
= GuiData
->ActiveBuffer
;
327 COORD SelectionAnchor
;
329 /* Clear the old selection */
330 GuiData
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
333 * The selection area extends to the whole screen buffer's width.
335 SelectionAnchor
.X
= SelectionAnchor
.Y
= 0;
336 GuiData
->dwSelectionCursor
.X
= ActiveBuffer
->ScreenBufferSize
.X
- 1;
339 * Determine whether the selection must extend to just some part
340 * (for text-mode screen buffers) or to all of the screen buffer's
341 * height (for graphics ones).
343 if (GetType(ActiveBuffer
) == TEXTMODE_BUFFER
)
346 * We select all the characters from the first line
347 * to the line where the cursor is positioned.
349 GuiData
->dwSelectionCursor
.Y
= ActiveBuffer
->CursorPosition
.Y
;
351 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
354 * We select all the screen buffer area.
356 GuiData
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
359 /* Restart a new selection */
360 GuiData
->Selection
.dwFlags
|= CONSOLE_MOUSE_SELECTION
;
361 UpdateSelection(GuiData
, &SelectionAnchor
, &GuiData
->dwSelectionCursor
);
365 OnCommand(PGUI_CONSOLE_DATA GuiData
, WPARAM wParam
, LPARAM lParam
)
368 PCONSOLE Console
= GuiData
->Console
;
371 * In case the selected menu item belongs to the user-reserved menu id range,
372 * send to him a menu event and return directly. The user must handle those
373 * reserved menu commands...
375 if (GuiData
->CmdIdLow
<= (UINT
)wParam
&& (UINT
)wParam
<= GuiData
->CmdIdHigh
)
377 SendMenuEvent(Console
, (UINT
)wParam
);
381 /* ... otherwise, perform actions. */
384 case ID_SYSTEM_EDIT_MARK
:
388 case ID_SYSTEM_EDIT_COPY
:
392 case ID_SYSTEM_EDIT_PASTE
:
396 case ID_SYSTEM_EDIT_SELECTALL
:
400 case ID_SYSTEM_EDIT_SCROLL
:
401 DPRINT1("Scrolling is not handled yet\n");
404 case ID_SYSTEM_EDIT_FIND
:
405 DPRINT1("Finding is not handled yet\n");
408 case ID_SYSTEM_DEFAULTS
:
409 GuiConsoleShowConsoleProperties(GuiData
, TRUE
);
412 case ID_SYSTEM_PROPERTIES
:
413 GuiConsoleShowConsoleProperties(GuiData
, FALSE
);
423 Ret
= DefWindowProcW(GuiData
->hWindow
, WM_SYSCOMMAND
, wParam
, lParam
);
428 static PGUI_CONSOLE_DATA
429 GuiGetGuiData(HWND hWnd
)
431 /* This function ensures that the console pointer is not NULL */
432 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
433 return ( ((GuiData
== NULL
) || (GuiData
->hWindow
== hWnd
&& GuiData
->Console
!= NULL
)) ? GuiData
: NULL
);
437 ResizeConWnd(PGUI_CONSOLE_DATA GuiData
, DWORD WidthUnit
, DWORD HeightUnit
)
439 PCONSOLE_SCREEN_BUFFER Buff
= GuiData
->ActiveBuffer
;
444 Width
= Buff
->ViewSize
.X
* WidthUnit
+
445 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
446 Height
= Buff
->ViewSize
.Y
* HeightUnit
+
447 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
449 /* Set scrollbar sizes */
450 sInfo
.cbSize
= sizeof(SCROLLINFO
);
451 sInfo
.fMask
= SIF_RANGE
| SIF_PAGE
| SIF_POS
;
453 if (Buff
->ScreenBufferSize
.Y
> Buff
->ViewSize
.Y
)
455 sInfo
.nMax
= Buff
->ScreenBufferSize
.Y
- 1;
456 sInfo
.nPage
= Buff
->ViewSize
.Y
;
457 sInfo
.nPos
= Buff
->ViewOrigin
.Y
;
458 SetScrollInfo(GuiData
->hWindow
, SB_VERT
, &sInfo
, TRUE
);
459 Width
+= GetSystemMetrics(SM_CXVSCROLL
);
460 ShowScrollBar(GuiData
->hWindow
, SB_VERT
, TRUE
);
464 ShowScrollBar(GuiData
->hWindow
, SB_VERT
, FALSE
);
467 if (Buff
->ScreenBufferSize
.X
> Buff
->ViewSize
.X
)
469 sInfo
.nMax
= Buff
->ScreenBufferSize
.X
- 1;
470 sInfo
.nPage
= Buff
->ViewSize
.X
;
471 sInfo
.nPos
= Buff
->ViewOrigin
.X
;
472 SetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &sInfo
, TRUE
);
473 Height
+= GetSystemMetrics(SM_CYHSCROLL
);
474 ShowScrollBar(GuiData
->hWindow
, SB_HORZ
, TRUE
);
478 ShowScrollBar(GuiData
->hWindow
, SB_HORZ
, FALSE
);
481 /* Resize the window */
482 SetWindowPos(GuiData
->hWindow
, NULL
, 0, 0, Width
, Height
,
483 SWP_NOZORDER
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOCOPYBITS
);
484 // NOTE: The SWP_NOCOPYBITS flag can be replaced by a subsequent call
485 // to: InvalidateRect(GuiData->hWindow, NULL, TRUE);
489 OnNcCreate(HWND hWnd
, LPCREATESTRUCTW Create
)
491 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)Create
->lpCreateParams
;
500 DPRINT1("GuiConsoleNcCreate: No GUI data\n");
504 Console
= GuiData
->Console
;
506 GuiData
->hWindow
= hWnd
;
508 GuiData
->Font
= CreateFontW(LOWORD(GuiData
->GuiInfo
.FontSize
),
509 0, // HIWORD(GuiData->GuiInfo.FontSize),
512 GuiData
->GuiInfo
.FontWeight
,
519 NONANTIALIASED_QUALITY
,
520 FIXED_PITCH
| GuiData
->GuiInfo
.FontFamily
/* FF_DONTCARE */,
521 GuiData
->GuiInfo
.FaceName
);
523 if (NULL
== GuiData
->Font
)
525 DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
526 GuiData
->hWindow
= NULL
;
527 SetEvent(GuiData
->hGuiInitEvent
);
530 hDC
= GetDC(GuiData
->hWindow
);
533 DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
534 DeleteObject(GuiData
->Font
);
535 GuiData
->hWindow
= NULL
;
536 SetEvent(GuiData
->hGuiInitEvent
);
539 OldFont
= SelectObject(hDC
, GuiData
->Font
);
542 DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
543 ReleaseDC(GuiData
->hWindow
, hDC
);
544 DeleteObject(GuiData
->Font
);
545 GuiData
->hWindow
= NULL
;
546 SetEvent(GuiData
->hGuiInitEvent
);
549 if (!GetTextMetricsW(hDC
, &Metrics
))
551 DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
552 SelectObject(hDC
, OldFont
);
553 ReleaseDC(GuiData
->hWindow
, hDC
);
554 DeleteObject(GuiData
->Font
);
555 GuiData
->hWindow
= NULL
;
556 SetEvent(GuiData
->hGuiInitEvent
);
559 GuiData
->CharWidth
= Metrics
.tmMaxCharWidth
;
560 GuiData
->CharHeight
= Metrics
.tmHeight
+ Metrics
.tmExternalLeading
;
562 /* Measure real char width more precisely if possible. */
563 if (GetTextExtentPoint32W(hDC
, L
"R", 1, &CharSize
))
564 GuiData
->CharWidth
= CharSize
.cx
;
566 SelectObject(hDC
, OldFont
);
568 ReleaseDC(GuiData
->hWindow
, hDC
);
570 /* Initialize the terminal framebuffer */
571 GuiData
->hMemDC
= CreateCompatibleDC(NULL
);
572 GuiData
->hBitmap
= NULL
;
573 GuiData
->hSysPalette
= NULL
; /* Original system palette */
575 /* Update the icons of the window */
576 if (GuiData
->hIcon
!= ghDefaultIcon
)
578 DefWindowProcW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
579 DefWindowProcW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
582 // FIXME: Keep these instructions here ? ///////////////////////////////////
583 Console
->ActiveBuffer
->CursorBlinkOn
= TRUE
;
584 Console
->ActiveBuffer
->ForceCursorOff
= FALSE
;
585 ////////////////////////////////////////////////////////////////////////////
587 SetWindowLongPtrW(GuiData
->hWindow
, GWLP_USERDATA
, (DWORD_PTR
)GuiData
);
589 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
590 CreateSysMenu(GuiData
->hWindow
);
592 DPRINT("OnNcCreate - setting start event\n");
593 SetEvent(GuiData
->hGuiInitEvent
);
595 return (BOOL
)DefWindowProcW(GuiData
->hWindow
, WM_NCCREATE
, 0, (LPARAM
)Create
);
600 EnterFullScreen(PGUI_CONSOLE_DATA GuiData
);
602 LeaveFullScreen(PGUI_CONSOLE_DATA GuiData
);
604 SwitchFullScreen(PGUI_CONSOLE_DATA GuiData
, BOOL FullScreen
);
606 GuiConsoleSwitchFullScreen(PGUI_CONSOLE_DATA GuiData
);
609 OnActivate(PGUI_CONSOLE_DATA GuiData
, WPARAM wParam
)
611 PCONSOLE Console
= GuiData
->Console
;
612 WORD ActivationState
= LOWORD(wParam
);
614 DPRINT1("WM_ACTIVATE - ActivationState = %d\n");
616 if ( ActivationState
== WA_ACTIVE
||
617 ActivationState
== WA_CLICKACTIVE
)
619 if (GuiData
->GuiInfo
.FullScreen
)
621 EnterFullScreen(GuiData
);
622 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
623 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
626 else // if (ActivationState == WA_INACTIVE)
628 if (GuiData
->GuiInfo
.FullScreen
)
630 SendMessageW(GuiData
->hWindow
, WM_SYSCOMMAND
, SC_MINIMIZE
, 0);
631 LeaveFullScreen(GuiData
);
632 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
633 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
638 * When we are in QuickEdit mode, ignore the next mouse signal
639 * when we are going to be enabled again via the mouse, in order
640 * to prevent e.g. an erroneous right-click from the user which
641 * would have as an effect to paste some unwanted text...
643 if (Console
->QuickEdit
&& (ActivationState
== WA_CLICKACTIVE
))
644 GuiData
->IgnoreNextMouseSignal
= TRUE
;
648 OnFocus(PGUI_CONSOLE_DATA GuiData
, BOOL SetFocus
)
650 PCONSOLE Console
= GuiData
->Console
;
653 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
655 er
.EventType
= FOCUS_EVENT
;
656 er
.Event
.FocusEvent
.bSetFocus
= SetFocus
;
657 ConioProcessInputEvent(Console
, &er
);
659 LeaveCriticalSection(&Console
->Lock
);
662 DPRINT1("TODO: Create console caret\n");
664 DPRINT1("TODO: Destroy console caret\n");
668 SmallRectToRect(PGUI_CONSOLE_DATA GuiData
, PRECT Rect
, PSMALL_RECT SmallRect
)
670 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
671 UINT WidthUnit
, HeightUnit
;
673 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
675 Rect
->left
= (SmallRect
->Left
- Buffer
->ViewOrigin
.X
) * WidthUnit
;
676 Rect
->top
= (SmallRect
->Top
- Buffer
->ViewOrigin
.Y
) * HeightUnit
;
677 Rect
->right
= (SmallRect
->Right
+ 1 - Buffer
->ViewOrigin
.X
) * WidthUnit
;
678 Rect
->bottom
= (SmallRect
->Bottom
+ 1 - Buffer
->ViewOrigin
.Y
) * HeightUnit
;
682 GetSelectionBeginEnd(PCOORD Begin
, PCOORD End
,
683 PCOORD SelectionAnchor
,
684 PSMALL_RECT SmallRect
)
686 if (Begin
== NULL
|| End
== NULL
) return;
688 *Begin
= *SelectionAnchor
;
689 End
->X
= (SelectionAnchor
->X
== SmallRect
->Left
) ? SmallRect
->Right
690 /* Case X != Left, must be == Right */ : SmallRect
->Left
;
691 End
->Y
= (SelectionAnchor
->Y
== SmallRect
->Top
) ? SmallRect
->Bottom
692 /* Case Y != Top, must be == Bottom */ : SmallRect
->Top
;
694 /* Exchange Begin / End if Begin > End lexicographically */
695 if (Begin
->Y
> End
->Y
|| (Begin
->Y
== End
->Y
&& Begin
->X
> End
->X
))
699 // End->X = InterlockedExchange16(&Begin->X, End->X);
704 // End->Y = InterlockedExchange16(&Begin->Y, End->Y);
712 CreateSelectionRgn(PGUI_CONSOLE_DATA GuiData
,
714 PCOORD SelectionAnchor
,
715 PSMALL_RECT SmallRect
)
720 SmallRectToRect(GuiData
, &rect
, SmallRect
);
721 return CreateRectRgnIndirect(&rect
);
728 GetSelectionBeginEnd(&Begin
, &End
, SelectionAnchor
, SmallRect
);
730 if (Begin
.Y
== End
.Y
)
740 // Debug thingie to see whether I can put this corner case
741 // together with the previous one.
742 if (SmallRect
->Left
!= sr
.Left
||
743 SmallRect
->Top
!= sr
.Top
||
744 SmallRect
->Right
!= sr
.Right
||
745 SmallRect
->Bottom
!= sr
.Bottom
)
748 "SmallRect = (%d, %d, %d, %d)\n"
749 "sr = (%d, %d, %d, %d)\n"
751 SmallRect
->Left
, SmallRect
->Top
, SmallRect
->Right
, SmallRect
->Bottom
,
752 sr
.Left
, sr
.Top
, sr
.Right
, sr
.Bottom
);
755 SmallRectToRect(GuiData
, &r
, &sr
);
756 SelRgn
= CreateRectRgnIndirect(&r
);
760 PCONSOLE_SCREEN_BUFFER ActiveBuffer
= GuiData
->ActiveBuffer
;
763 SMALL_RECT sr1
, sr2
, sr3
;
768 sr1
.Right
= ActiveBuffer
->ScreenBufferSize
.X
- 1;
769 sr1
.Bottom
= Begin
.Y
;
772 sr2
.Top
= Begin
.Y
+ 1;
773 sr2
.Right
= ActiveBuffer
->ScreenBufferSize
.X
- 1;
774 sr2
.Bottom
= End
.Y
- 1;
781 SmallRectToRect(GuiData
, &r1
, &sr1
);
782 SmallRectToRect(GuiData
, &r2
, &sr2
);
783 SmallRectToRect(GuiData
, &r3
, &sr3
);
785 rg1
= CreateRectRgnIndirect(&r1
);
786 rg2
= CreateRectRgnIndirect(&r2
);
787 rg3
= CreateRectRgnIndirect(&r3
);
789 CombineRgn(rg1
, rg1
, rg2
, RGN_XOR
);
790 CombineRgn(rg1
, rg1
, rg3
, RGN_XOR
);
802 PaintSelectionRect(PGUI_CONSOLE_DATA GuiData
, PPAINTSTRUCT pps
)
804 HRGN rgnPaint
= CreateRectRgnIndirect(&pps
->rcPaint
);
805 HRGN rgnSel
= CreateSelectionRgn(GuiData
, GuiData
->LineSelection
,
806 &GuiData
->Selection
.dwSelectionAnchor
,
807 &GuiData
->Selection
.srSelection
);
809 /* Invert the selection */
811 int ErrorCode
= CombineRgn(rgnPaint
, rgnPaint
, rgnSel
, RGN_AND
);
812 if (ErrorCode
!= ERROR
&& ErrorCode
!= NULLREGION
)
814 InvertRgn(pps
->hdc
, rgnPaint
);
817 DeleteObject(rgnSel
);
818 DeleteObject(rgnPaint
);
822 UpdateSelection(PGUI_CONSOLE_DATA GuiData
,
823 PCOORD SelectionAnchor OPTIONAL
,
826 PCONSOLE Console
= GuiData
->Console
;
827 HRGN oldRgn
= CreateSelectionRgn(GuiData
, GuiData
->LineSelection
,
828 &GuiData
->Selection
.dwSelectionAnchor
,
829 &GuiData
->Selection
.srSelection
);
831 /* Update the anchor if needed (use the old one if NULL) */
833 GuiData
->Selection
.dwSelectionAnchor
= *SelectionAnchor
;
841 * Pressing the Control key while selecting text, allows us to enter
842 * into line-selection mode, the selection mode of *nix terminals.
844 BOOL OldLineSel
= GuiData
->LineSelection
;
845 GuiData
->LineSelection
= !!(GetKeyState(VK_CONTROL
) & 0x8000);
847 /* Exchange left/top with right/bottom if required */
848 rc
.Left
= min(GuiData
->Selection
.dwSelectionAnchor
.X
, coord
->X
);
849 rc
.Top
= min(GuiData
->Selection
.dwSelectionAnchor
.Y
, coord
->Y
);
850 rc
.Right
= max(GuiData
->Selection
.dwSelectionAnchor
.X
, coord
->X
);
851 rc
.Bottom
= max(GuiData
->Selection
.dwSelectionAnchor
.Y
, coord
->Y
);
853 newRgn
= CreateSelectionRgn(GuiData
, GuiData
->LineSelection
,
854 &GuiData
->Selection
.dwSelectionAnchor
,
857 if (GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
859 if (OldLineSel
!= GuiData
->LineSelection
||
860 memcmp(&rc
, &GuiData
->Selection
.srSelection
, sizeof(SMALL_RECT
)) != 0)
862 /* Calculate the region that needs to be updated */
863 if (oldRgn
&& newRgn
&& CombineRgn(newRgn
, newRgn
, oldRgn
, RGN_XOR
) != ERROR
)
865 InvalidateRgn(GuiData
->hWindow
, newRgn
, FALSE
);
871 InvalidateRgn(GuiData
->hWindow
, newRgn
, FALSE
);
874 DeleteObject(newRgn
);
876 GuiData
->Selection
.dwFlags
|= CONSOLE_SELECTION_NOT_EMPTY
;
877 GuiData
->Selection
.srSelection
= rc
;
878 GuiData
->dwSelectionCursor
= *coord
;
880 if ((GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) == 0)
882 LPWSTR SelTypeStr
= NULL
, WindowTitle
= NULL
;
883 SIZE_T SelTypeStrLength
= 0, Length
= 0;
885 /* Clear the old selection */
886 if (GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
888 InvalidateRgn(GuiData
->hWindow
, oldRgn
, FALSE
);
892 * When passing a zero-length buffer size, LoadString(...) returns
893 * a read-only pointer buffer to the program's resource string.
896 LoadStringW(ConSrvDllInstance
,
897 (GuiData
->Selection
.dwFlags
& CONSOLE_MOUSE_SELECTION
)
898 ? IDS_SELECT_TITLE
: IDS_MARK_TITLE
,
899 (LPWSTR
)&SelTypeStr
, 0);
902 * Prepend the selection type string to the current console title
903 * if we succeeded in retrieving a valid localized string.
907 // 3 for " - " and 1 for NULL
908 Length
= Console
->Title
.Length
+ (SelTypeStrLength
+ 3 + 1) * sizeof(WCHAR
);
909 WindowTitle
= ConsoleAllocHeap(0, Length
);
911 wcsncpy(WindowTitle
, SelTypeStr
, SelTypeStrLength
);
912 WindowTitle
[SelTypeStrLength
] = L
'\0';
913 wcscat(WindowTitle
, L
" - ");
914 wcscat(WindowTitle
, Console
->Title
.Buffer
);
916 SetWindowText(GuiData
->hWindow
, WindowTitle
);
917 ConsoleFreeHeap(WindowTitle
);
920 GuiData
->Selection
.dwFlags
|= CONSOLE_SELECTION_IN_PROGRESS
;
921 ConioPause(Console
, PAUSED_FROM_SELECTION
);
926 /* Clear the selection */
927 if (GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
929 InvalidateRgn(GuiData
->hWindow
, oldRgn
, FALSE
);
932 GuiData
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
933 ConioUnpause(Console
, PAUSED_FROM_SELECTION
);
935 /* Restore the console title */
936 SetWindowText(GuiData
->hWindow
, Console
->Title
.Buffer
);
939 DeleteObject(oldRgn
);
944 GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
,
945 PGUI_CONSOLE_DATA GuiData
,
947 PRECT rcFramebuffer
);
949 GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
,
950 PGUI_CONSOLE_DATA GuiData
,
952 PRECT rcFramebuffer
);
955 OnPaint(PGUI_CONSOLE_DATA GuiData
)
957 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
961 ActiveBuffer
= GuiData
->ActiveBuffer
;
963 BeginPaint(GuiData
->hWindow
, &ps
);
964 if (ps
.hdc
!= NULL
&&
965 ps
.rcPaint
.left
< ps
.rcPaint
.right
&&
966 ps
.rcPaint
.top
< ps
.rcPaint
.bottom
)
968 EnterCriticalSection(&GuiData
->Lock
);
970 /* Compose the current screen-buffer on-memory */
971 if (GetType(ActiveBuffer
) == TEXTMODE_BUFFER
)
973 GuiPaintTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)ActiveBuffer
,
974 GuiData
, &ps
.rcPaint
, &rcPaint
);
976 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
978 GuiPaintGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)ActiveBuffer
,
979 GuiData
, &ps
.rcPaint
, &rcPaint
);
982 /* Send it to screen */
986 rcPaint
.right
- rcPaint
.left
,
987 rcPaint
.bottom
- rcPaint
.top
,
993 /* Draw the selection region if needed */
994 if (GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
996 PaintSelectionRect(GuiData
, &ps
);
999 LeaveCriticalSection(&GuiData
->Lock
);
1001 EndPaint(GuiData
->hWindow
, &ps
);
1007 OnPaletteChanged(PGUI_CONSOLE_DATA GuiData
)
1009 PCONSOLE_SCREEN_BUFFER ActiveBuffer
= GuiData
->ActiveBuffer
;
1011 // See WM_PALETTECHANGED message
1012 // if ((HWND)wParam == hWnd) break;
1014 // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER)
1015 if (ActiveBuffer
->PaletteHandle
)
1017 DPRINT("WM_PALETTECHANGED changing palette\n");
1019 /* Specify the use of the system palette for the framebuffer */
1020 SetSystemPaletteUse(GuiData
->hMemDC
, ActiveBuffer
->PaletteUsage
);
1022 /* Realize the (logical) palette */
1023 RealizePalette(GuiData
->hMemDC
);
1028 IsSystemKey(WORD VirtualKeyCode
)
1030 switch (VirtualKeyCode
)
1032 /* From MSDN, "Virtual-Key Codes" */
1051 OnKey(PGUI_CONSOLE_DATA GuiData
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1053 PCONSOLE Console
= GuiData
->Console
;
1054 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
1056 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
1058 ActiveBuffer
= GuiData
->ActiveBuffer
;
1060 if (GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
)
1062 WORD VirtualKeyCode
= LOWORD(wParam
);
1064 if (msg
!= WM_KEYDOWN
) goto Quit
;
1066 if (VirtualKeyCode
== VK_RETURN
)
1068 /* Copy (and clear) selection if ENTER is pressed */
1072 else if ( VirtualKeyCode
== VK_ESCAPE
||
1073 (VirtualKeyCode
== 'C' && (GetKeyState(VK_CONTROL
) & 0x8000)) )
1075 /* Cancel selection if ESC or Ctrl-C are pressed */
1076 UpdateSelection(GuiData
, NULL
, NULL
);
1080 if ((GuiData
->Selection
.dwFlags
& CONSOLE_MOUSE_SELECTION
) == 0)
1082 /* Keyboard selection mode */
1083 BOOL Interpreted
= FALSE
;
1084 BOOL MajPressed
= !!(GetKeyState(VK_SHIFT
) & 0x8000);
1086 switch (VirtualKeyCode
)
1091 if (GuiData
->dwSelectionCursor
.X
> 0)
1092 GuiData
->dwSelectionCursor
.X
--;
1100 if (GuiData
->dwSelectionCursor
.X
< ActiveBuffer
->ScreenBufferSize
.X
- 1)
1101 GuiData
->dwSelectionCursor
.X
++;
1109 if (GuiData
->dwSelectionCursor
.Y
> 0)
1110 GuiData
->dwSelectionCursor
.Y
--;
1118 if (GuiData
->dwSelectionCursor
.Y
< ActiveBuffer
->ScreenBufferSize
.Y
- 1)
1119 GuiData
->dwSelectionCursor
.Y
++;
1127 GuiData
->dwSelectionCursor
.X
= 0;
1128 GuiData
->dwSelectionCursor
.Y
= 0;
1135 GuiData
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
1142 GuiData
->dwSelectionCursor
.Y
-= ActiveBuffer
->ViewSize
.Y
;
1143 if (GuiData
->dwSelectionCursor
.Y
< 0)
1144 GuiData
->dwSelectionCursor
.Y
= 0;
1152 GuiData
->dwSelectionCursor
.Y
+= ActiveBuffer
->ViewSize
.Y
;
1153 if (GuiData
->dwSelectionCursor
.Y
>= ActiveBuffer
->ScreenBufferSize
.Y
)
1154 GuiData
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
1165 UpdateSelection(GuiData
,
1166 !MajPressed
? &GuiData
->dwSelectionCursor
: NULL
,
1167 &GuiData
->dwSelectionCursor
);
1169 else if (!IsSystemKey(VirtualKeyCode
))
1171 /* Emit an error beep sound */
1172 SendNotifyMessage(GuiData
->hWindow
, PM_CONSOLE_BEEP
, 0, 0);
1179 /* Mouse selection mode */
1181 if (!IsSystemKey(VirtualKeyCode
))
1183 /* Clear the selection and send the key into the input buffer */
1184 UpdateSelection(GuiData
, NULL
, NULL
);
1193 if ((GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) == 0)
1197 Message
.hwnd
= GuiData
->hWindow
;
1198 Message
.message
= msg
;
1199 Message
.wParam
= wParam
;
1200 Message
.lParam
= lParam
;
1202 ConioProcessKey(Console
, &Message
);
1206 LeaveCriticalSection(&Console
->Lock
);
1210 // FIXME: Remove after fixing OnTimer
1212 InvalidateCell(PGUI_CONSOLE_DATA GuiData
,
1216 OnTimer(PGUI_CONSOLE_DATA GuiData
)
1218 PCONSOLE Console
= GuiData
->Console
;
1219 PCONSOLE_SCREEN_BUFFER Buff
;
1221 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CURSOR_BLINK_TIME
, NULL
);
1223 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
1225 Buff
= GuiData
->ActiveBuffer
;
1227 if (GetType(Buff
) == TEXTMODE_BUFFER
)
1229 InvalidateCell(GuiData
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
1230 Buff
->CursorBlinkOn
= !Buff
->CursorBlinkOn
;
1232 if ((GuiData
->OldCursor
.x
!= Buff
->CursorPosition
.X
) ||
1233 (GuiData
->OldCursor
.y
!= Buff
->CursorPosition
.Y
))
1236 int OldScrollX
= -1, OldScrollY
= -1;
1237 int NewScrollX
= -1, NewScrollY
= -1;
1239 xScroll
.cbSize
= sizeof(SCROLLINFO
);
1240 xScroll
.fMask
= SIF_POS
;
1241 // Capture the original position of the scroll bars and save them.
1242 if (GetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &xScroll
)) OldScrollX
= xScroll
.nPos
;
1243 if (GetScrollInfo(GuiData
->hWindow
, SB_VERT
, &xScroll
)) OldScrollY
= xScroll
.nPos
;
1245 // If we successfully got the info for the horizontal scrollbar
1246 if (OldScrollX
>= 0)
1248 if ((Buff
->CursorPosition
.X
< Buff
->ViewOrigin
.X
) ||
1249 (Buff
->CursorPosition
.X
>= (Buff
->ViewOrigin
.X
+ Buff
->ViewSize
.X
)))
1251 // Handle the horizontal scroll bar
1252 if (Buff
->CursorPosition
.X
>= Buff
->ViewSize
.X
)
1253 NewScrollX
= Buff
->CursorPosition
.X
- Buff
->ViewSize
.X
+ 1;
1259 NewScrollX
= OldScrollX
;
1262 // If we successfully got the info for the vertical scrollbar
1263 if (OldScrollY
>= 0)
1265 if ((Buff
->CursorPosition
.Y
< Buff
->ViewOrigin
.Y
) ||
1266 (Buff
->CursorPosition
.Y
>= (Buff
->ViewOrigin
.Y
+ Buff
->ViewSize
.Y
)))
1268 // Handle the vertical scroll bar
1269 if (Buff
->CursorPosition
.Y
>= Buff
->ViewSize
.Y
)
1270 NewScrollY
= Buff
->CursorPosition
.Y
- Buff
->ViewSize
.Y
+ 1;
1276 NewScrollY
= OldScrollY
;
1280 // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area
1281 // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar
1282 // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling)
1283 // and their associated scrollbar is left alone.
1284 if ((OldScrollX
!= NewScrollX
) || (OldScrollY
!= NewScrollY
))
1286 Buff
->ViewOrigin
.X
= NewScrollX
;
1287 Buff
->ViewOrigin
.Y
= NewScrollY
;
1288 ScrollWindowEx(GuiData
->hWindow
,
1289 (OldScrollX
- NewScrollX
) * GuiData
->CharWidth
,
1290 (OldScrollY
- NewScrollY
) * GuiData
->CharHeight
,
1296 if (NewScrollX
>= 0)
1298 xScroll
.nPos
= NewScrollX
;
1299 SetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &xScroll
, TRUE
);
1301 if (NewScrollY
>= 0)
1303 xScroll
.nPos
= NewScrollY
;
1304 SetScrollInfo(GuiData
->hWindow
, SB_VERT
, &xScroll
, TRUE
);
1306 UpdateWindow(GuiData
->hWindow
);
1307 // InvalidateRect(GuiData->hWindow, NULL, FALSE);
1308 GuiData
->OldCursor
.x
= Buff
->CursorPosition
.X
;
1309 GuiData
->OldCursor
.y
= Buff
->CursorPosition
.Y
;
1313 else /* if (GetType(Buff) == GRAPHICS_BUFFER) */
1317 LeaveCriticalSection(&Console
->Lock
);
1321 OnClose(PGUI_CONSOLE_DATA GuiData
)
1323 PCONSOLE Console
= GuiData
->Console
;
1325 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1328 // TODO: Prompt for termination ? (Warn the user about possible apps running in this console)
1331 * FIXME: Windows will wait up to 5 seconds for the thread to exit.
1332 * We shouldn't wait here, though, since the console lock is entered.
1333 * A copy of the thread list probably needs to be made.
1335 ConDrvConsoleProcessCtrlEvent(Console
, 0, CTRL_CLOSE_EVENT
);
1337 LeaveCriticalSection(&Console
->Lock
);
1342 OnNcDestroy(HWND hWnd
)
1344 PGUI_CONSOLE_DATA GuiData
= GuiGetGuiData(hWnd
);
1346 KillTimer(hWnd
, CONGUI_UPDATE_TIMER
);
1347 GetSystemMenu(hWnd
, TRUE
);
1351 /* Free the terminal framebuffer */
1352 if (GuiData
->hMemDC
) DeleteDC(GuiData
->hMemDC
);
1353 if (GuiData
->hBitmap
) DeleteObject(GuiData
->hBitmap
);
1354 // if (GuiData->hSysPalette) DeleteObject(GuiData->hSysPalette);
1355 if (GuiData
->Font
) DeleteObject(GuiData
->Font
);
1358 /* Free the GuiData registration */
1359 SetWindowLongPtrW(hWnd
, GWLP_USERDATA
, (DWORD_PTR
)NULL
);
1361 return DefWindowProcW(hWnd
, WM_NCDESTROY
, 0, 0);
1365 PointToCoord(PGUI_CONSOLE_DATA GuiData
, LPARAM lParam
)
1367 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1369 UINT WidthUnit
, HeightUnit
;
1371 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
1373 Coord
.X
= Buffer
->ViewOrigin
.X
+ ((SHORT
)LOWORD(lParam
) / (int)WidthUnit
);
1374 Coord
.Y
= Buffer
->ViewOrigin
.Y
+ ((SHORT
)HIWORD(lParam
) / (int)HeightUnit
);
1376 /* Clip coordinate to ensure it's inside buffer */
1379 else if (Coord
.X
>= Buffer
->ScreenBufferSize
.X
)
1380 Coord
.X
= Buffer
->ScreenBufferSize
.X
- 1;
1384 else if (Coord
.Y
>= Buffer
->ScreenBufferSize
.Y
)
1385 Coord
.Y
= Buffer
->ScreenBufferSize
.Y
- 1;
1391 OnMouse(PGUI_CONSOLE_DATA GuiData
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1394 PCONSOLE Console
= GuiData
->Console
;
1396 if (GuiData
->IgnoreNextMouseSignal
)
1398 if (msg
!= WM_LBUTTONDOWN
&&
1399 msg
!= WM_MBUTTONDOWN
&&
1400 msg
!= WM_RBUTTONDOWN
&&
1401 msg
!= WM_MOUSEMOVE
)
1404 * If this mouse signal is not a button-down action or a move,
1405 * then it is the last signal being ignored.
1407 GuiData
->IgnoreNextMouseSignal
= FALSE
;
1412 * This mouse signal is a button-down action or a move.
1413 * Ignore it and perform default action.
1420 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1426 if ( (GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) ||
1427 (Console
->QuickEdit
) )
1431 case WM_LBUTTONDOWN
:
1433 /* Clear the old selection */
1434 GuiData
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
1436 /* Restart a new selection */
1437 GuiData
->dwSelectionCursor
= PointToCoord(GuiData
, lParam
);
1438 SetCapture(GuiData
->hWindow
);
1439 GuiData
->Selection
.dwFlags
|= CONSOLE_MOUSE_SELECTION
| CONSOLE_MOUSE_DOWN
;
1440 UpdateSelection(GuiData
,
1441 &GuiData
->dwSelectionCursor
,
1442 &GuiData
->dwSelectionCursor
);
1449 if (!(GuiData
->Selection
.dwFlags
& CONSOLE_MOUSE_DOWN
)) break;
1451 // GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
1452 GuiData
->Selection
.dwFlags
&= ~CONSOLE_MOUSE_DOWN
;
1453 // UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor);
1459 case WM_LBUTTONDBLCLK
:
1461 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1463 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
1465 #define IS_WORD_SEP(c) \
1466 ((c) == L'\0' || (c) == L' ' || (c) == L'\t' || (c) == L'\r' || (c) == L'\n')
1468 PTEXTMODE_SCREEN_BUFFER TextBuffer
= (PTEXTMODE_SCREEN_BUFFER
)Buffer
;
1470 PCHAR_INFO ptrL
, ptrR
;
1472 /* Starting point */
1473 cL
= cR
= PointToCoord(GuiData
, lParam
);
1474 ptrL
= ptrR
= ConioCoordToPointer(TextBuffer
, cL
.X
, cL
.Y
);
1476 /* Enlarge the selection by checking for whitespace */
1477 while ((0 < cL
.X
) && !IS_WORD_SEP(ptrL
->Char
.UnicodeChar
)
1478 && !IS_WORD_SEP((ptrL
-1)->Char
.UnicodeChar
))
1483 while ((cR
.X
< TextBuffer
->ScreenBufferSize
.X
- 1) &&
1484 !IS_WORD_SEP(ptrR
->Char
.UnicodeChar
) &&
1485 !IS_WORD_SEP((ptrR
+1)->Char
.UnicodeChar
))
1492 * Update the selection started with the single
1493 * left-click that preceded this double-click.
1495 GuiData
->Selection
.dwFlags
|= CONSOLE_MOUSE_SELECTION
| CONSOLE_MOUSE_DOWN
;
1496 UpdateSelection(GuiData
, &cL
, &cR
);
1498 /* Ignore the next mouse move signal */
1499 GuiData
->IgnoreNextMouseSignal
= TRUE
;
1505 case WM_RBUTTONDOWN
:
1506 case WM_RBUTTONDBLCLK
:
1508 if (!(GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
))
1517 /* Ignore the next mouse move signal */
1518 GuiData
->IgnoreNextMouseSignal
= TRUE
;
1524 if (!(wParam
& MK_LBUTTON
)) break;
1525 if (!(GuiData
->Selection
.dwFlags
& CONSOLE_MOUSE_DOWN
)) break;
1527 // TODO: Scroll buffer to bring SelectionCursor into view
1528 GuiData
->dwSelectionCursor
= PointToCoord(GuiData
, lParam
);
1529 UpdateSelection(GuiData
, NULL
, &GuiData
->dwSelectionCursor
);
1535 Err
= FALSE
; // TRUE;
1539 else if (Console
->InputBuffer
.Mode
& ENABLE_MOUSE_INPUT
)
1542 WORD wKeyState
= GET_KEYSTATE_WPARAM(wParam
);
1543 DWORD dwButtonState
= 0;
1544 DWORD dwControlKeyState
= 0;
1545 DWORD dwEventFlags
= 0;
1549 case WM_LBUTTONDOWN
:
1550 SetCapture(GuiData
->hWindow
);
1551 dwButtonState
= FROM_LEFT_1ST_BUTTON_PRESSED
;
1555 case WM_MBUTTONDOWN
:
1556 SetCapture(GuiData
->hWindow
);
1557 dwButtonState
= FROM_LEFT_2ND_BUTTON_PRESSED
;
1561 case WM_RBUTTONDOWN
:
1562 SetCapture(GuiData
->hWindow
);
1563 dwButtonState
= RIGHTMOST_BUTTON_PRESSED
;
1585 case WM_LBUTTONDBLCLK
:
1586 dwButtonState
= FROM_LEFT_1ST_BUTTON_PRESSED
;
1587 dwEventFlags
= DOUBLE_CLICK
;
1590 case WM_MBUTTONDBLCLK
:
1591 dwButtonState
= FROM_LEFT_2ND_BUTTON_PRESSED
;
1592 dwEventFlags
= DOUBLE_CLICK
;
1595 case WM_RBUTTONDBLCLK
:
1596 dwButtonState
= RIGHTMOST_BUTTON_PRESSED
;
1597 dwEventFlags
= DOUBLE_CLICK
;
1602 dwEventFlags
= MOUSE_MOVED
;
1606 dwButtonState
= GET_WHEEL_DELTA_WPARAM(wParam
) << 16;
1607 dwEventFlags
= MOUSE_WHEELED
;
1610 case WM_MOUSEHWHEEL
:
1611 dwButtonState
= GET_WHEEL_DELTA_WPARAM(wParam
) << 16;
1612 dwEventFlags
= MOUSE_HWHEELED
;
1622 if (wKeyState
& MK_LBUTTON
)
1623 dwButtonState
|= FROM_LEFT_1ST_BUTTON_PRESSED
;
1624 if (wKeyState
& MK_MBUTTON
)
1625 dwButtonState
|= FROM_LEFT_2ND_BUTTON_PRESSED
;
1626 if (wKeyState
& MK_RBUTTON
)
1627 dwButtonState
|= RIGHTMOST_BUTTON_PRESSED
;
1629 if (GetKeyState(VK_RMENU
) & 0x8000)
1630 dwControlKeyState
|= RIGHT_ALT_PRESSED
;
1631 if (GetKeyState(VK_LMENU
) & 0x8000)
1632 dwControlKeyState
|= LEFT_ALT_PRESSED
;
1633 if (GetKeyState(VK_RCONTROL
) & 0x8000)
1634 dwControlKeyState
|= RIGHT_CTRL_PRESSED
;
1635 if (GetKeyState(VK_LCONTROL
) & 0x8000)
1636 dwControlKeyState
|= LEFT_CTRL_PRESSED
;
1637 if (GetKeyState(VK_SHIFT
) & 0x8000)
1638 dwControlKeyState
|= SHIFT_PRESSED
;
1639 if (GetKeyState(VK_NUMLOCK
) & 0x0001)
1640 dwControlKeyState
|= NUMLOCK_ON
;
1641 if (GetKeyState(VK_SCROLL
) & 0x0001)
1642 dwControlKeyState
|= SCROLLLOCK_ON
;
1643 if (GetKeyState(VK_CAPITAL
) & 0x0001)
1644 dwControlKeyState
|= CAPSLOCK_ON
;
1645 /* See WM_CHAR MSDN documentation for instance */
1646 if (lParam
& 0x01000000)
1647 dwControlKeyState
|= ENHANCED_KEY
;
1649 er
.EventType
= MOUSE_EVENT
;
1650 er
.Event
.MouseEvent
.dwMousePosition
= PointToCoord(GuiData
, lParam
);
1651 er
.Event
.MouseEvent
.dwButtonState
= dwButtonState
;
1652 er
.Event
.MouseEvent
.dwControlKeyState
= dwControlKeyState
;
1653 er
.Event
.MouseEvent
.dwEventFlags
= dwEventFlags
;
1655 ConioProcessInputEvent(Console
, &er
);
1663 LeaveCriticalSection(&Console
->Lock
);
1667 return DefWindowProcW(GuiData
->hWindow
, msg
, wParam
, lParam
);
1673 GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
,
1674 PGUI_CONSOLE_DATA GuiData
);
1676 GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
,
1677 PGUI_CONSOLE_DATA GuiData
);
1680 Copy(PGUI_CONSOLE_DATA GuiData
)
1682 if (OpenClipboard(GuiData
->hWindow
) == TRUE
)
1684 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1686 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
1688 GuiCopyFromTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)Buffer
, GuiData
);
1690 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1692 GuiCopyFromGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)Buffer
, GuiData
);
1698 /* Clear the selection */
1699 UpdateSelection(GuiData
, NULL
, NULL
);
1703 GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
,
1704 PGUI_CONSOLE_DATA GuiData
);
1706 GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
,
1707 PGUI_CONSOLE_DATA GuiData
);
1710 Paste(PGUI_CONSOLE_DATA GuiData
)
1712 if (OpenClipboard(GuiData
->hWindow
) == TRUE
)
1714 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1716 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
1718 GuiPasteToTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)Buffer
, GuiData
);
1720 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1722 GuiPasteToGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)Buffer
, GuiData
);
1730 OnGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData
, PMINMAXINFO minMaxInfo
)
1732 PCONSOLE Console
= GuiData
->Console
;
1733 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
1735 UINT WidthUnit
, HeightUnit
;
1737 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
1739 ActiveBuffer
= GuiData
->ActiveBuffer
;
1741 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
1743 windx
= CONGUI_MIN_WIDTH
* WidthUnit
+ 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
1744 windy
= CONGUI_MIN_HEIGHT
* HeightUnit
+ 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
1746 minMaxInfo
->ptMinTrackSize
.x
= windx
;
1747 minMaxInfo
->ptMinTrackSize
.y
= windy
;
1749 windx
= (ActiveBuffer
->ScreenBufferSize
.X
) * WidthUnit
+ 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
1750 windy
= (ActiveBuffer
->ScreenBufferSize
.Y
) * HeightUnit
+ 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
1752 if (ActiveBuffer
->ViewSize
.X
< ActiveBuffer
->ScreenBufferSize
.X
) windy
+= GetSystemMetrics(SM_CYHSCROLL
); // window currently has a horizontal scrollbar
1753 if (ActiveBuffer
->ViewSize
.Y
< ActiveBuffer
->ScreenBufferSize
.Y
) windx
+= GetSystemMetrics(SM_CXVSCROLL
); // window currently has a vertical scrollbar
1755 minMaxInfo
->ptMaxTrackSize
.x
= windx
;
1756 minMaxInfo
->ptMaxTrackSize
.y
= windy
;
1758 LeaveCriticalSection(&Console
->Lock
);
1762 OnSize(PGUI_CONSOLE_DATA GuiData
, WPARAM wParam
, LPARAM lParam
)
1764 PCONSOLE Console
= GuiData
->Console
;
1766 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
1768 if ((GuiData
->WindowSizeLock
== FALSE
) &&
1769 (wParam
== SIZE_RESTORED
|| wParam
== SIZE_MAXIMIZED
|| wParam
== SIZE_MINIMIZED
))
1771 PCONSOLE_SCREEN_BUFFER Buff
= GuiData
->ActiveBuffer
;
1772 DWORD windx
, windy
, charx
, chary
;
1773 UINT WidthUnit
, HeightUnit
;
1775 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
1777 GuiData
->WindowSizeLock
= TRUE
;
1779 windx
= LOWORD(lParam
);
1780 windy
= HIWORD(lParam
);
1782 // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar)
1783 if (Buff
->ViewSize
.X
< Buff
->ScreenBufferSize
.X
) windy
+= GetSystemMetrics(SM_CYHSCROLL
); // window currently has a horizontal scrollbar
1784 if (Buff
->ViewSize
.Y
< Buff
->ScreenBufferSize
.Y
) windx
+= GetSystemMetrics(SM_CXVSCROLL
); // window currently has a vertical scrollbar
1786 charx
= windx
/ (int)WidthUnit
;
1787 chary
= windy
/ (int)HeightUnit
;
1789 // Character alignment (round size up or down)
1790 if ((windx
% WidthUnit
) >= (WidthUnit
/ 2)) ++charx
;
1791 if ((windy
% HeightUnit
) >= (HeightUnit
/ 2)) ++chary
;
1793 // Compensate for added scroll bars in new window
1794 if (charx
< Buff
->ScreenBufferSize
.X
) windy
-= GetSystemMetrics(SM_CYHSCROLL
); // new window will have a horizontal scroll bar
1795 if (chary
< Buff
->ScreenBufferSize
.Y
) windx
-= GetSystemMetrics(SM_CXVSCROLL
); // new window will have a vertical scroll bar
1797 charx
= windx
/ (int)WidthUnit
;
1798 chary
= windy
/ (int)HeightUnit
;
1800 // Character alignment (round size up or down)
1801 if ((windx
% WidthUnit
) >= (WidthUnit
/ 2)) ++charx
;
1802 if ((windy
% HeightUnit
) >= (HeightUnit
/ 2)) ++chary
;
1805 if ((charx
!= Buff
->ViewSize
.X
) || (chary
!= Buff
->ViewSize
.Y
))
1807 Buff
->ViewSize
.X
= (charx
<= Buff
->ScreenBufferSize
.X
) ? charx
: Buff
->ScreenBufferSize
.X
;
1808 Buff
->ViewSize
.Y
= (chary
<= Buff
->ScreenBufferSize
.Y
) ? chary
: Buff
->ScreenBufferSize
.Y
;
1811 ResizeConWnd(GuiData
, WidthUnit
, HeightUnit
);
1813 // Adjust the start of the visible area if we are attempting to show nonexistent areas
1814 if ((Buff
->ScreenBufferSize
.X
- Buff
->ViewOrigin
.X
) < Buff
->ViewSize
.X
) Buff
->ViewOrigin
.X
= Buff
->ScreenBufferSize
.X
- Buff
->ViewSize
.X
;
1815 if ((Buff
->ScreenBufferSize
.Y
- Buff
->ViewOrigin
.Y
) < Buff
->ViewSize
.Y
) Buff
->ViewOrigin
.Y
= Buff
->ScreenBufferSize
.Y
- Buff
->ViewSize
.Y
;
1816 InvalidateRect(GuiData
->hWindow
, NULL
, TRUE
);
1818 GuiData
->WindowSizeLock
= FALSE
;
1821 LeaveCriticalSection(&Console
->Lock
);
1825 OnMove(PGUI_CONSOLE_DATA GuiData
)
1829 // TODO: Simplify the code.
1830 // See: GuiConsoleNotifyWndProc() PM_CREATE_CONSOLE.
1832 /* Retrieve our real position */
1833 GetWindowRect(GuiData
->hWindow
, &rcWnd
);
1834 GuiData
->GuiInfo
.WindowOrigin
.x
= rcWnd
.left
;
1835 GuiData
->GuiInfo
.WindowOrigin
.y
= rcWnd
.top
;
1839 // HACK: This functionality is standard for general scrollbars. Don't add it by hand.
1843 GuiConsoleHandleScrollbarMenu(VOID)
1847 hMenu = CreatePopupMenu();
1850 DPRINT("CreatePopupMenu failed\n");
1854 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE);
1855 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1856 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP);
1857 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM);
1858 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1859 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP);
1860 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN);
1861 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1862 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP);
1863 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN);
1868 OnScroll(PGUI_CONSOLE_DATA GuiData
, UINT uMsg
, WPARAM wParam
)
1870 PCONSOLE Console
= GuiData
->Console
;
1871 PCONSOLE_SCREEN_BUFFER Buff
;
1874 int old_pos
, Maximum
;
1877 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return 0;
1879 Buff
= GuiData
->ActiveBuffer
;
1881 if (uMsg
== WM_HSCROLL
)
1884 Maximum
= Buff
->ScreenBufferSize
.X
- Buff
->ViewSize
.X
;
1885 pShowXY
= &Buff
->ViewOrigin
.X
;
1890 Maximum
= Buff
->ScreenBufferSize
.Y
- Buff
->ViewSize
.Y
;
1891 pShowXY
= &Buff
->ViewOrigin
.Y
;
1894 /* set scrollbar sizes */
1895 sInfo
.cbSize
= sizeof(SCROLLINFO
);
1896 sInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
| SIF_TRACKPOS
;
1898 if (!GetScrollInfo(GuiData
->hWindow
, fnBar
, &sInfo
)) goto Quit
;
1900 old_pos
= sInfo
.nPos
;
1902 switch (LOWORD(wParam
))
1913 sInfo
.nPos
-= sInfo
.nPage
;
1917 sInfo
.nPos
+= sInfo
.nPage
;
1921 sInfo
.nPos
= sInfo
.nTrackPos
;
1922 ConioPause(Console
, PAUSED_FROM_SCROLLBAR
);
1925 case SB_THUMBPOSITION
:
1926 ConioUnpause(Console
, PAUSED_FROM_SCROLLBAR
);
1930 sInfo
.nPos
= sInfo
.nMin
;
1934 sInfo
.nPos
= sInfo
.nMax
;
1941 sInfo
.nPos
= max(sInfo
.nPos
, 0);
1942 sInfo
.nPos
= min(sInfo
.nPos
, Maximum
);
1944 if (old_pos
!= sInfo
.nPos
)
1946 USHORT OldX
= Buff
->ViewOrigin
.X
;
1947 USHORT OldY
= Buff
->ViewOrigin
.Y
;
1948 UINT WidthUnit
, HeightUnit
;
1950 *pShowXY
= sInfo
.nPos
;
1952 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
1954 ScrollWindowEx(GuiData
->hWindow
,
1955 (OldX
- Buff
->ViewOrigin
.X
) * WidthUnit
,
1956 (OldY
- Buff
->ViewOrigin
.Y
) * HeightUnit
,
1963 sInfo
.fMask
= SIF_POS
;
1964 SetScrollInfo(GuiData
->hWindow
, fnBar
, &sInfo
, TRUE
);
1966 UpdateWindow(GuiData
->hWindow
);
1967 // InvalidateRect(GuiData->hWindow, NULL, FALSE);
1971 LeaveCriticalSection(&Console
->Lock
);
1976 static LRESULT CALLBACK
1977 ConWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1980 PGUI_CONSOLE_DATA GuiData
= NULL
;
1981 PCONSOLE Console
= NULL
;
1984 * - If it's the first time we create a window for the terminal,
1985 * just initialize it and return.
1987 * - If we are destroying the window, just do it and return.
1989 if (msg
== WM_NCCREATE
)
1991 return (LRESULT
)OnNcCreate(hWnd
, (LPCREATESTRUCTW
)lParam
);
1993 else if (msg
== WM_NCDESTROY
)
1995 return OnNcDestroy(hWnd
);
1999 * Now the terminal window is initialized.
2000 * Get the terminal data via the window's data.
2001 * If there is no data, just go away.
2003 GuiData
= GuiGetGuiData(hWnd
);
2004 if (GuiData
== NULL
) return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
2006 // TEMPORARY HACK until all of the functions can deal with a NULL GuiData->ActiveBuffer ...
2007 if (GuiData
->ActiveBuffer
== NULL
) return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
2010 * Just retrieve a pointer to the console in case somebody needs it.
2011 * It is not NULL because it was checked in GuiGetGuiData.
2012 * Each helper function which needs the console has to validate and lock it.
2014 Console
= GuiData
->Console
;
2016 /* We have a console, start message dispatching */
2020 OnActivate(GuiData
, wParam
);
2024 if (OnClose(GuiData
)) goto Default
;
2035 case WM_PALETTECHANGED
:
2037 DPRINT("WM_PALETTECHANGED called\n");
2040 * Protects against infinite loops:
2041 * "... A window that receives this message must not realize
2042 * its palette, unless it determines that wParam does not contain
2043 * its own window handle." (WM_PALETTECHANGED description - MSDN)
2045 * This message is sent to all windows, including the one that
2046 * changed the system palette and caused this message to be sent.
2047 * The wParam of this message contains the handle of the window
2048 * that caused the system palette to change. To avoid an infinite
2049 * loop, care must be taken to check that the wParam of this message
2050 * does not match the window's handle.
2052 if ((HWND
)wParam
== hWnd
) break;
2054 DPRINT("WM_PALETTECHANGED ok\n");
2055 OnPaletteChanged(GuiData
);
2056 DPRINT("WM_PALETTECHANGED quit\n");
2067 case WM_SYSDEADCHAR
:
2069 /* Detect Alt-Enter presses and switch back and forth to fullscreen mode */
2070 if (msg
== WM_SYSKEYDOWN
&& (HIWORD(lParam
) & KF_ALTDOWN
) && wParam
== VK_RETURN
)
2072 /* Switch only at first Alt-Enter press, and ignore subsequent key repetitions */
2073 if ((HIWORD(lParam
) & (KF_UP
| KF_REPEAT
)) != KF_REPEAT
)
2074 GuiConsoleSwitchFullScreen(GuiData
);
2078 /* Detect Alt-Esc/Space/Tab presses defer to DefWindowProc */
2079 if ( (HIWORD(lParam
) & KF_ALTDOWN
) && (wParam
== VK_ESCAPE
|| wParam
== VK_SPACE
|| wParam
== VK_TAB
))
2081 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
2084 OnKey(GuiData
, msg
, wParam
, lParam
);
2091 * The message was sent because we are manually triggering a change.
2092 * Check whether the mouse is indeed present on this console window
2093 * and take appropriate decisions.
2095 if (wParam
== -1 && lParam
== -1)
2100 /* Get the placement of the mouse */
2101 GetCursorPos(&mouseCoords
);
2103 /* On which window is placed the mouse ? */
2104 hWndHit
= WindowFromPoint(mouseCoords
);
2106 /* It's our window. Perform the hit-test to be used later on. */
2107 if (hWndHit
== hWnd
)
2109 wParam
= (WPARAM
)hWnd
;
2110 lParam
= DefWindowProcW(hWndHit
, WM_NCHITTEST
, 0,
2111 MAKELPARAM(mouseCoords
.x
, mouseCoords
.y
));
2115 /* Set the mouse cursor only when we are in the client area */
2116 if ((HWND
)wParam
== hWnd
&& LOWORD(lParam
) == HTCLIENT
)
2118 if (GuiData
->MouseCursorRefCount
>= 0)
2120 /* Show the cursor */
2121 SetCursor(GuiData
->hCursor
);
2125 /* Hide the cursor if the reference count is negative */
2136 case WM_LBUTTONDOWN
:
2137 case WM_MBUTTONDOWN
:
2138 case WM_RBUTTONDOWN
:
2142 case WM_LBUTTONDBLCLK
:
2143 case WM_MBUTTONDBLCLK
:
2144 case WM_RBUTTONDBLCLK
:
2147 case WM_MOUSEHWHEEL
:
2149 Result
= OnMouse(GuiData
, msg
, wParam
, lParam
);
2156 Result
= OnScroll(GuiData
, msg
, wParam
);
2160 case WM_CONTEXTMENU
:
2162 if (DefWindowProcW(hWnd
/*GuiData->hWindow*/, WM_NCHITTEST
, 0, lParam
) == HTCLIENT
)
2164 HMENU hMenu
= CreatePopupMenu();
2167 AppendMenuItems(hMenu
, GuiConsoleEditMenuItems
);
2168 TrackPopupMenuEx(hMenu
,
2170 GET_X_LPARAM(lParam
),
2171 GET_Y_LPARAM(lParam
),
2186 HMENU hMenu
= (HMENU
)wParam
;
2189 /* Enable or disable the Close menu item */
2190 EnableMenuItem(hMenu
, SC_CLOSE
, MF_BYCOMMAND
|
2191 (GuiData
->IsCloseButtonEnabled
? MF_ENABLED
: MF_GRAYED
));
2193 /* Enable or disable the Copy and Paste items */
2194 EnableMenuItem(hMenu
, ID_SYSTEM_EDIT_COPY
, MF_BYCOMMAND
|
2195 ((GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) &&
2196 (GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
) ? MF_ENABLED
: MF_GRAYED
));
2197 // FIXME: Following whether the active screen buffer is text-mode
2198 // or graphics-mode, search for CF_UNICODETEXT or CF_BITMAP formats.
2199 EnableMenuItem(hMenu
, ID_SYSTEM_EDIT_PASTE
, MF_BYCOMMAND
|
2200 (!(GuiData
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) &&
2201 IsClipboardFormatAvailable(CF_UNICODETEXT
) ? MF_ENABLED
: MF_GRAYED
));
2204 SendMenuEvent(Console
, WM_INITMENU
);
2210 if (HIWORD(wParam
) == 0xFFFF) // Allow all the menu flags
2212 SendMenuEvent(Console
, WM_MENUSELECT
);
2220 Result
= OnCommand(GuiData
, wParam
, lParam
);
2226 OnFocus(GuiData
, (msg
== WM_SETFOCUS
));
2229 case WM_GETMINMAXINFO
:
2230 OnGetMinMaxInfo(GuiData
, (PMINMAXINFO
)lParam
);
2237 #if 0 // This code is here to prepare & control dynamic console SB resizing.
2240 PRECT dragRect
= (PRECT
)lParam
;
2244 DPRINT1("WMSZ_LEFT\n");
2247 DPRINT1("WMSZ_RIGHT\n");
2250 DPRINT1("WMSZ_TOP\n");
2253 DPRINT1("WMSZ_TOPLEFT\n");
2256 DPRINT1("WMSZ_TOPRIGHT\n");
2259 DPRINT1("WMSZ_BOTTOM\n");
2261 case WMSZ_BOTTOMLEFT
:
2262 DPRINT1("WMSZ_BOTTOMLEFT\n");
2264 case WMSZ_BOTTOMRIGHT
:
2265 DPRINT1("WMSZ_BOTTOMRIGHT\n");
2268 DPRINT1("wParam = %d\n", wParam
);
2271 DPRINT1("dragRect = {.left = %d ; .top = %d ; .right = %d ; .bottom = %d}\n",
2272 dragRect
->left
, dragRect
->top
, dragRect
->right
, dragRect
->bottom
);
2278 OnSize(GuiData
, wParam
, lParam
);
2281 case PM_RESIZE_TERMINAL
:
2283 PCONSOLE_SCREEN_BUFFER Buff
= GuiData
->ActiveBuffer
;
2287 DWORD Width
, Height
;
2288 UINT WidthUnit
, HeightUnit
;
2290 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
2292 Width
= Buff
->ScreenBufferSize
.X
* WidthUnit
;
2293 Height
= Buff
->ScreenBufferSize
.Y
* HeightUnit
;
2295 /* Recreate the framebuffer */
2296 hDC
= GetDC(GuiData
->hWindow
);
2297 hnew
= CreateCompatibleBitmap(hDC
, Width
, Height
);
2298 ReleaseDC(GuiData
->hWindow
, hDC
);
2299 hold
= SelectObject(GuiData
->hMemDC
, hnew
);
2300 if (GuiData
->hBitmap
)
2302 if (hold
== GuiData
->hBitmap
) DeleteObject(GuiData
->hBitmap
);
2304 GuiData
->hBitmap
= hnew
;
2306 /* Resize the window to the user's values */
2307 GuiData
->WindowSizeLock
= TRUE
;
2308 ResizeConWnd(GuiData
, WidthUnit
, HeightUnit
);
2309 GuiData
->WindowSizeLock
= FALSE
;
2313 case PM_APPLY_CONSOLE_INFO
:
2315 GuiApplyUserSettings(GuiData
, (HANDLE
)wParam
, (BOOL
)lParam
);
2319 case PM_CONSOLE_BEEP
:
2320 DPRINT1("Beep !!\n");
2324 // case PM_CONSOLE_SET_TITLE:
2325 // SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
2329 Result
= DefWindowProcW(hWnd
, msg
, wParam
, lParam
);