From: Denis Malikov Date: Tue, 15 Jan 2019 13:36:41 +0000 (+0700) Subject: [WIN32SS:NTUSER] Implement "Window Snap" feature (#1226) X-Git-Tag: 0.4.13-dev~708 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=7e396787ed00a3939031447725f79697a41878e1 [WIN32SS:NTUSER] Implement "Window Snap" feature (#1226) Implemented the following actions: stick the window on the left/right or maximize it, with the following shortcuts: - Win key + Arrows; - drag to left/right screen border; - double-click on top/bottom. CORE-12845 --- diff --git a/win32ss/user/ntuser/defwnd.c b/win32ss/user/ntuser/defwnd.c index eb7284150cc..d00d9aa853e 100644 --- a/win32ss/user/ntuser/defwnd.c +++ b/win32ss/user/ntuser/defwnd.c @@ -781,6 +781,92 @@ IntDefWindowProc( co_IntSendMessage(UserHMGetHandle(Wnd), WM_CONTEXTMENU, (WPARAM)UserHMGetHandle(Wnd), MAKELPARAM(-1, -1)); } } + if (IS_KEY_DOWN(gafAsyncKeyState, VK_LWIN) || IS_KEY_DOWN(gafAsyncKeyState, VK_RWIN)) + { + PWND topWnd = UserGetWindowObject(UserGetForegroundWindow()); + + if (topWnd) + { + if (wParam == VK_DOWN) + { + co_IntSendMessage(UserHMGetHandle(topWnd), WM_SYSCOMMAND, (topWnd->style & WS_MAXIMIZE) ? SC_RESTORE : SC_MINIMIZE, lParam); + } + else + if (wParam == VK_UP) + { + RECT currentRect = (topWnd->InternalPos.NormalRect.right == topWnd->InternalPos.NormalRect.left) || + (topWnd->InternalPos.NormalRect.top == topWnd->InternalPos.NormalRect.bottom) + ? topWnd->rcWindow + : topWnd->InternalPos.NormalRect; + co_IntSendMessage(UserHMGetHandle(topWnd), WM_SYSCOMMAND, SC_MAXIMIZE, 0); + + // save normal rect if maximazing snapped window + topWnd->InternalPos.NormalRect = currentRect; + } + else + if (wParam == VK_LEFT || wParam == VK_RIGHT) + { + RECT snapRect; + RECT normalRect; + RECT windowRect; + BOOL snapped = FALSE; + normalRect = topWnd->InternalPos.NormalRect; + snapped = (normalRect.left != 0 + && normalRect.right != 0 + && normalRect.top != 0 + && normalRect.bottom != 0); + + if (topWnd->style & WS_MAXIMIZE) + { + co_IntSendMessage(UserHMGetHandle(topWnd), WM_SYSCOMMAND, SC_RESTORE, lParam); + snapped = FALSE; + } + + windowRect = topWnd->rcWindow; + + UserSystemParametersInfo(SPI_GETWORKAREA, 0, &snapRect, 0); + if (wParam == VK_LEFT) + { + snapRect.right = (snapRect.right - snapRect.left) / 2 + snapRect.left; + } + else // VK_RIGHT + { + snapRect.left = (snapRect.right - snapRect.left) / 2 + snapRect.left; + } + + if (snapped) + { + // if window was snapped but moved to other location - restore normal size + if (snapRect.left != windowRect.left || + snapRect.right != windowRect.right || + snapRect.top != windowRect.top || + snapRect.bottom != windowRect.bottom) + { + RECT empty = {0, 0, 0, 0}; + co_WinPosSetWindowPos(topWnd, + 0, + normalRect.left, + normalRect.top, + normalRect.right - normalRect.left, + normalRect.bottom - normalRect.top, + 0); + topWnd->InternalPos.NormalRect = empty; + } + } + else + { + co_WinPosSetWindowPos(topWnd, + 0, + snapRect.left, + snapRect.top, + snapRect.right - snapRect.left, + snapRect.bottom - snapRect.top, + 0); + topWnd->InternalPos.NormalRect = windowRect; + } + } + } + } break; case WM_SYSKEYDOWN: diff --git a/win32ss/user/ntuser/hotkey.c b/win32ss/user/ntuser/hotkey.c index f393906b204..02b504fe668 100644 --- a/win32ss/user/ntuser/hotkey.c +++ b/win32ss/user/ntuser/hotkey.c @@ -250,6 +250,19 @@ co_UserProcessHotKeys(WORD wVk, BOOL bIsDown) return FALSE; } } + + if (pHotKey->id == IDHK_SNAP_LEFT || + pHotKey->id == IDHK_SNAP_RIGHT || + pHotKey->id == IDHK_SNAP_UP || + pHotKey->id == IDHK_SNAP_DOWN) + { + HWND topWnd = UserGetForegroundWindow(); + if (topWnd) + { + UserPostMessage(topWnd, WM_KEYDOWN, wVk, 0); + } + return TRUE; + } if (!pHotKey->pWnd) { diff --git a/win32ss/user/ntuser/hotkey.h b/win32ss/user/ntuser/hotkey.h index b9656774178..e86452204c6 100644 --- a/win32ss/user/ntuser/hotkey.h +++ b/win32ss/user/ntuser/hotkey.h @@ -16,6 +16,12 @@ typedef struct _HOT_KEY #define IDHK_WINKEY -7 #define IDHK_REACTOS -8 +/* Window Snap Hot Keys */ +#define IDHK_SNAP_LEFT -10 +#define IDHK_SNAP_RIGHT -11 +#define IDHK_SNAP_UP -12 +#define IDHK_SNAP_DOWN -13 + VOID FASTCALL UnregisterWindowHotKeys(PWND Window); VOID FASTCALL UnregisterThreadHotKeys(PTHREADINFO pti); BOOL NTAPI co_UserProcessHotKeys(WORD wVk, BOOL bIsDown); diff --git a/win32ss/user/ntuser/input.c b/win32ss/user/ntuser/input.c index e4dbbabba07..520ccca9ebb 100644 --- a/win32ss/user/ntuser/input.c +++ b/win32ss/user/ntuser/input.c @@ -202,6 +202,11 @@ RawInputThreadMain(VOID) UserEnterExclusive(); // Register the Window hotkey. UserRegisterHotKey(PWND_BOTTOM, IDHK_WINKEY, MOD_WIN, 0); + // Register the Window Snap hotkey. + UserRegisterHotKey(PWND_BOTTOM, IDHK_SNAP_LEFT, MOD_WIN, VK_LEFT); + UserRegisterHotKey(PWND_BOTTOM, IDHK_SNAP_RIGHT, MOD_WIN, VK_RIGHT); + UserRegisterHotKey(PWND_BOTTOM, IDHK_SNAP_UP, MOD_WIN, VK_UP); + UserRegisterHotKey(PWND_BOTTOM, IDHK_SNAP_DOWN, MOD_WIN, VK_DOWN); // Register the debug hotkeys. StartDebugHotKeys(); UserLeave(); diff --git a/win32ss/user/ntuser/nonclient.c b/win32ss/user/ntuser/nonclient.c index 8f455821423..7a5fcc445e8 100644 --- a/win32ss/user/ntuser/nonclient.c +++ b/win32ss/user/ntuser/nonclient.c @@ -391,10 +391,59 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam) if (!co_IntGetPeekMessage(&msg, 0, 0, 0, PM_REMOVE, TRUE)) break; if (IntCallMsgFilter( &msg, MSGF_SIZE )) continue; - /* Exit on button-up, Return, or Esc */ - if ((msg.message == WM_LBUTTONUP) || - ((msg.message == WM_KEYDOWN) && - ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break; + /* Exit on button-up */ + if (msg.message == WM_LBUTTONUP) + { + // check for snapping if was moved by caption + if (hittest == HTCAPTION) + { + RECT snapRect; + BOOL doSideSnap = FALSE; + UserSystemParametersInfo(SPI_GETWORKAREA, 0, &snapRect, 0); + + // snap to left + if (pt.x <= snapRect.left) + { + snapRect.right = (snapRect.right - snapRect.left) / 2 + snapRect.left; + doSideSnap = TRUE; + } + // snap to right + if (pt.x >= snapRect.right-1) + { + snapRect.left = (snapRect.right - snapRect.left) / 2 + snapRect.left; + doSideSnap = TRUE; + } + + if (doSideSnap) + { + co_WinPosSetWindowPos(pwnd, + 0, + snapRect.left, + snapRect.top, + snapRect.right - snapRect.left, + snapRect.bottom - snapRect.top, + 0); + pwnd->InternalPos.NormalRect = origRect; + } + else + { + // maximize if on dragged to top + if (pt.y <= snapRect.top) + { + co_IntSendMessage(UserHMGetHandle(pwnd), WM_SYSCOMMAND, SC_MAXIMIZE, 0); + pwnd->InternalPos.NormalRect = origRect; + } + } + } + break; + } + + /* Exit on Return or Esc */ + if (msg.message == WM_KEYDOWN && + (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE)) + { + break; + } if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE)) { @@ -1565,6 +1614,21 @@ NC_HandleNCLButtonDblClk(PWND pWnd, WPARAM wParam, LPARAM lParam) co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_CLOSE, lParam); break; } + case HTTOP: + case HTBOTTOM: + { + RECT sizingRect = pWnd->rcWindow, mouseRect; + UserSystemParametersInfo(SPI_GETWORKAREA, 0, &mouseRect, 0); + + co_WinPosSetWindowPos(pWnd, + 0, + sizingRect.left, + mouseRect.top, + sizingRect.right - sizingRect.left, + mouseRect.bottom - mouseRect.top, + 0); + break; + } default: return NC_HandleNCLButtonDown(pWnd, wParam, lParam); }