From 0e32edb603e001a297fa64223a600bd15e1f5d17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Sto=C5=A1i=C4=87?= Date: Fri, 11 Sep 2020 11:32:45 +0200 Subject: [PATCH] [FancyZones] Use Ctrl+Win+Alt+arrows to Expand/shrink windows to adjacent zones (#6446) * Added an Alt key hook * Refactor a block of code into a method * Again refactored existing code * Apparently Win+Alt does not reach FancyZones * Using Ctrl+alt instead of Win+alt for now * It works * Fixed VD change * Remove unused member * Fix compilation error * Enable shrinking * Fixed comments in .h files * Remove newline * Refactored a function into two The next task is to simplify their code. * Updated a comment * Update a variable name * Reverted to the old implementation of directional move * More refactoring * Remove space * Fixed windows getting stuck * Changed function name --- src/modules/fancyzones/lib/FancyZones.cpp | 48 ++++-- .../fancyzones/lib/WindowMoveHandler.cpp | 23 ++- .../fancyzones/lib/WindowMoveHandler.h | 5 +- src/modules/fancyzones/lib/ZoneSet.cpp | 151 +++++++++++++++++- src/modules/fancyzones/lib/ZoneSet.h | 22 +++ src/modules/fancyzones/lib/ZoneWindow.cpp | 55 ++----- src/modules/fancyzones/lib/ZoneWindow.h | 19 ++- 7 files changed, 256 insertions(+), 67 deletions(-) diff --git a/src/modules/fancyzones/lib/FancyZones.cpp b/src/modules/fancyzones/lib/FancyZones.cpp index bf15e3f5b..9e70fccb1 100644 --- a/src/modules/fancyzones/lib/FancyZones.cpp +++ b/src/modules/fancyzones/lib/FancyZones.cpp @@ -207,6 +207,7 @@ private: bool OnSnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode) noexcept; bool OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept; bool OnSnapHotkey(DWORD vkCode) noexcept; + bool ProcessDirectedSnapHotkey(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept; void RegisterVirtualDesktopUpdates(std::vector& ids) noexcept; @@ -524,21 +525,23 @@ FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept // Return true to swallow the keyboard event bool const shift = GetAsyncKeyState(VK_SHIFT) & 0x8000; bool const win = GetAsyncKeyState(VK_LWIN) & 0x8000 || GetAsyncKeyState(VK_RWIN) & 0x8000; - if (win && !shift) + bool const alt = GetAsyncKeyState(VK_MENU) & 0x8000; + bool const ctrl = GetAsyncKeyState(VK_CONTROL) & 0x8000; + if ((win && !shift && !ctrl) || (win && ctrl && alt)) { - bool const ctrl = GetAsyncKeyState(VK_CONTROL) & 0x8000; - if (ctrl) - { - // Temporarily disable Win+Ctrl+Number functionality - //if ((info->vkCode >= '0') && (info->vkCode <= '9')) - //{ - // // Win+Ctrl+Number will cycle through ZoneSets - // Trace::FancyZones::OnKeyDown(info->vkCode, win, ctrl, false /*inMoveSize*/); - // CycleActiveZoneSet(info->vkCode); - // return true; - //} - } - else if ((info->vkCode == VK_RIGHT) || (info->vkCode == VK_LEFT) || (info->vkCode == VK_UP) || (info->vkCode == VK_DOWN)) + // Temporarily disable Win+Ctrl+Number functionality + // if (ctrl) + // { + // if ((info->vkCode >= '0') && (info->vkCode <= '9')) + // { + // // Win+Ctrl+Number will cycle through ZoneSets + // Trace::FancyZones::OnKeyDown(info->vkCode, win, ctrl, false /*inMoveSize*/); + // CycleActiveZoneSet(info->vkCode); + // return true; + // } + // } + // else + if ((info->vkCode == VK_RIGHT) || (info->vkCode == VK_LEFT) || (info->vkCode == VK_UP) || (info->vkCode == VK_DOWN)) { if (ShouldProcessSnapHotkey(info->vkCode)) { @@ -1142,7 +1145,7 @@ bool FancyZones::OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept { // Multi monitor environment. // First, try to stay on the same monitor - bool success = m_windowMoveHandler.MoveWindowIntoZoneByDirectionAndPosition(window, vkCode, false, m_workAreaHandler.GetWorkArea(m_currentDesktopId, current)); + bool success = ProcessDirectedSnapHotkey(window, vkCode, false, m_workAreaHandler.GetWorkArea(m_currentDesktopId, current)); if (success) { return true; @@ -1250,7 +1253,7 @@ bool FancyZones::OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept else { // Single monitor environment, or combined multi-monitor environment. - return m_windowMoveHandler.MoveWindowIntoZoneByDirectionAndPosition(window, vkCode, true, m_workAreaHandler.GetWorkArea(m_currentDesktopId, current)); + return ProcessDirectedSnapHotkey(window, vkCode, true, m_workAreaHandler.GetWorkArea(m_currentDesktopId, current)); } } @@ -1271,6 +1274,19 @@ bool FancyZones::OnSnapHotkey(DWORD vkCode) noexcept return false; } +bool FancyZones::ProcessDirectedSnapHotkey(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept +{ + // Check whether Alt is used in the shortcut key combination + if (GetAsyncKeyState(VK_MENU) & 0x8000) + { + return m_windowMoveHandler.ExtendWindowByDirectionAndPosition(window, vkCode, zoneWindow); + } + else + { + return m_windowMoveHandler.MoveWindowIntoZoneByDirectionAndPosition(window, vkCode, cycle, zoneWindow); + } +} + void FancyZones::RegisterVirtualDesktopUpdates(std::vector& ids) noexcept { std::unique_lock writeLock(m_lock); diff --git a/src/modules/fancyzones/lib/WindowMoveHandler.cpp b/src/modules/fancyzones/lib/WindowMoveHandler.cpp index c9cfc7ec1..9e59a116b 100644 --- a/src/modules/fancyzones/lib/WindowMoveHandler.cpp +++ b/src/modules/fancyzones/lib/WindowMoveHandler.cpp @@ -82,8 +82,9 @@ public: void MoveSizeEnd(HWND window, POINT const& ptScreen, const std::unordered_map>& zoneWindowMap) noexcept; void MoveWindowIntoZoneByIndexSet(HWND window, const std::vector& indexSet, winrt::com_ptr zoneWindow) noexcept; - bool MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow); - bool MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow); + bool MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept; + bool MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept; + bool ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode, winrt::com_ptr zoneWindow) noexcept; private: void WarnIfElevationIsRequired(HWND window) noexcept; @@ -160,16 +161,21 @@ void WindowMoveHandler::MoveWindowIntoZoneByIndexSet(HWND window, const std::vec pimpl->MoveWindowIntoZoneByIndexSet(window, indexSet, zoneWindow); } -bool WindowMoveHandler::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) +bool WindowMoveHandler::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept { return pimpl->MoveWindowIntoZoneByDirectionAndIndex(window, vkCode, cycle, zoneWindow); } -bool WindowMoveHandler::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) +bool WindowMoveHandler::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept { return pimpl->MoveWindowIntoZoneByDirectionAndPosition(window, vkCode, cycle, zoneWindow); } +bool WindowMoveHandler::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode, winrt::com_ptr zoneWindow) noexcept +{ + return pimpl->ExtendWindowByDirectionAndPosition(window, vkCode, zoneWindow); +} + void WindowMoveHandlerPrivate::MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::unordered_map>& zoneWindowMap) noexcept { if (!FancyZonesUtils::IsCandidateForZoning(window, m_settings->GetSettings()->excludedAppsArray) || WindowMoveHandlerUtils::IsCursorTypeIndicatingSizeEvent()) @@ -376,16 +382,21 @@ void WindowMoveHandlerPrivate::MoveWindowIntoZoneByIndexSet(HWND window, const s } } -bool WindowMoveHandlerPrivate::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) +bool WindowMoveHandlerPrivate::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept { return zoneWindow && zoneWindow->MoveWindowIntoZoneByDirectionAndIndex(window, vkCode, cycle); } -bool WindowMoveHandlerPrivate::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) +bool WindowMoveHandlerPrivate::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept { return zoneWindow && zoneWindow->MoveWindowIntoZoneByDirectionAndPosition(window, vkCode, cycle); } +bool WindowMoveHandlerPrivate::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode, winrt::com_ptr zoneWindow) noexcept +{ + return zoneWindow && zoneWindow->ExtendWindowByDirectionAndPosition(window, vkCode); +} + void WindowMoveHandlerPrivate::WarnIfElevationIsRequired(HWND window) noexcept { static bool warning_shown = false; diff --git a/src/modules/fancyzones/lib/WindowMoveHandler.h b/src/modules/fancyzones/lib/WindowMoveHandler.h index 5e1b870b0..c37d4150f 100644 --- a/src/modules/fancyzones/lib/WindowMoveHandler.h +++ b/src/modules/fancyzones/lib/WindowMoveHandler.h @@ -19,8 +19,9 @@ public: void MoveSizeEnd(HWND window, POINT const& ptScreen, const std::unordered_map>& zoneWindowMap) noexcept; void MoveWindowIntoZoneByIndexSet(HWND window, const std::vector& indexSet, winrt::com_ptr zoneWindow) noexcept; - bool MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow); - bool MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow); + bool MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept; + bool MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept; + bool ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode, winrt::com_ptr zoneWindow) noexcept; private: class WindowMoveHandlerPrivate* pimpl; diff --git a/src/modules/fancyzones/lib/ZoneSet.cpp b/src/modules/fancyzones/lib/ZoneSet.cpp index 44d0dcf3a..a82b82c81 100644 --- a/src/modules/fancyzones/lib/ZoneSet.cpp +++ b/src/modules/fancyzones/lib/ZoneSet.cpp @@ -143,12 +143,16 @@ public: MoveWindowIntoZoneByDirectionAndIndex(HWND window, HWND zoneWindow, DWORD vkCode, bool cycle) noexcept; IFACEMETHODIMP_(bool) MoveWindowIntoZoneByDirectionAndPosition(HWND window, HWND zoneWindow, DWORD vkCode, bool cycle) noexcept; + IFACEMETHODIMP_(bool) + ExtendWindowByDirectionAndPosition(HWND window, HWND windowZone, DWORD vkCode) noexcept; IFACEMETHODIMP_(void) MoveWindowIntoZoneByPoint(HWND window, HWND zoneWindow, POINT ptClient) noexcept; IFACEMETHODIMP_(bool) CalculateZones(RECT workArea, int zoneCount, int spacing) noexcept; IFACEMETHODIMP_(bool) IsZoneEmpty(int zoneIndex) noexcept; + IFACEMETHODIMP_(std::vector) + GetCombinedZoneRange(const std::vector& initialZones, const std::vector& finalZones) noexcept; private: bool CalculateFocusLayout(Rect workArea, int zoneCount) noexcept; @@ -161,6 +165,12 @@ private: std::vector> m_zones; std::map> m_windowIndexSet; + + // Needed for ExtendWindowByDirectionAndPosition + std::map> m_windowInitialIndexSet; + std::map m_windowFinalIndex; + bool m_inExtendWindow = false; + ZoneSetConfig m_config; }; @@ -276,6 +286,13 @@ ZoneSet::MoveWindowIntoZoneByIndexSet(HWND window, HWND windowZone, const std::v return; } + // Always clear the info related to SelectManyZones if it's not being used + if (!m_inExtendWindow) + { + m_windowFinalIndex.erase(window); + m_windowInitialIndexSet.erase(window); + } + RECT size; bool sizeEmpty = true; size_t bitmask = 0; @@ -410,12 +427,15 @@ ZoneSet::MoveWindowIntoZoneByDirectionAndPosition(HWND window, HWND windowZone, else if (cycle) { // Try again from the position off the screen in the opposite direction to vkCode + // Consider all zones as available + zoneRects.resize(zoneObjects.size()); + std::transform(zoneObjects.begin(), zoneObjects.end(), zoneRects.begin(), [](auto zone) { return zone->GetZoneRect(); }); windowRect = FancyZonesUtils::PrepareRectForCycling(windowRect, windowZoneRect, vkCode); result = FancyZonesUtils::ChooseNextZoneByPosition(vkCode, windowRect, zoneRects); if (result < zoneRects.size()) { - MoveWindowIntoZoneByIndex(window, windowZone, freeZoneIndices[result]); + MoveWindowIntoZoneByIndex(window, windowZone, result); return true; } } @@ -424,6 +444,93 @@ ZoneSet::MoveWindowIntoZoneByDirectionAndPosition(HWND window, HWND windowZone, return false; } +IFACEMETHODIMP_(bool) +ZoneSet::ExtendWindowByDirectionAndPosition(HWND window, HWND windowZone, DWORD vkCode) noexcept +{ + if (m_zones.empty()) + { + return false; + } + + RECT windowRect, windowZoneRect; + if (GetWindowRect(window, &windowRect) && GetWindowRect(windowZone, &windowZoneRect)) + { + auto zoneObjects = GetZones(); + auto oldZones = GetZoneIndexSetFromWindow(window); + std::vector usedZoneIndices(zoneObjects.size(), false); + std::vector zoneRects; + std::vector freeZoneIndices; + + // If selectManyZones = true for the second time, use the last zone into which we moved + // instead of the window rect and enable moving to all zones except the old one + auto finalIndexIt = m_windowFinalIndex.find(window); + if (finalIndexIt != m_windowFinalIndex.end()) + { + usedZoneIndices[finalIndexIt->second] = true; + windowRect = zoneObjects[finalIndexIt->second]->GetZoneRect(); + } + else + { + for (size_t idx : oldZones) + { + usedZoneIndices[idx] = true; + } + // Move to coordinates relative to windowZone + windowRect.top -= windowZoneRect.top; + windowRect.bottom -= windowZoneRect.top; + windowRect.left -= windowZoneRect.left; + windowRect.right -= windowZoneRect.left; + } + + for (size_t i = 0; i < zoneObjects.size(); i++) + { + if (!usedZoneIndices[i]) + { + zoneRects.emplace_back(zoneObjects[i]->GetZoneRect()); + freeZoneIndices.emplace_back(i); + } + } + + size_t result = FancyZonesUtils::ChooseNextZoneByPosition(vkCode, windowRect, zoneRects); + if (result < zoneRects.size()) + { + size_t targetZone = freeZoneIndices[result]; + std::vector resultIndexSet; + + // First time with selectManyZones = true for this window? + if (finalIndexIt == m_windowFinalIndex.end()) + { + // Already zoned? + if (oldZones.size()) + { + m_windowInitialIndexSet[window] = oldZones; + m_windowFinalIndex[window] = targetZone; + resultIndexSet = GetCombinedZoneRange(oldZones, { targetZone }); + } + else + { + m_windowInitialIndexSet[window] = { targetZone }; + m_windowFinalIndex[window] = targetZone; + resultIndexSet = { targetZone }; + } + } + else + { + auto deletethis = m_windowInitialIndexSet[window]; + m_windowFinalIndex[window] = targetZone; + resultIndexSet = GetCombinedZoneRange(m_windowInitialIndexSet[window], { targetZone }); + } + + m_inExtendWindow = true; + MoveWindowIntoZoneByIndexSet(window, windowZone, resultIndexSet); + m_inExtendWindow = false; + return true; + } + } + + return false; +} + IFACEMETHODIMP_(void) ZoneSet::MoveWindowIntoZoneByPoint(HWND window, HWND zoneWindow, POINT ptClient) noexcept { @@ -779,6 +886,48 @@ void ZoneSet::StampWindow(HWND window, size_t bitmask) noexcept SetProp(window, ZonedWindowProperties::PropertyMultipleZoneID, reinterpret_cast(bitmask)); } +std::vector ZoneSet::GetCombinedZoneRange(const std::vector& initialZones, const std::vector& finalZones) noexcept +{ + std::vector combinedZones, result; + std::set_union(begin(initialZones), end(initialZones), begin(finalZones), end(finalZones), std::back_inserter(combinedZones)); + + RECT boundingRect; + bool boundingRectEmpty = true; + auto zones = GetZones(); + + for (size_t zoneId : combinedZones) + { + RECT rect = zones[zoneId]->GetZoneRect(); + if (boundingRectEmpty) + { + boundingRect = rect; + boundingRectEmpty = false; + } + else + { + boundingRect.left = min(boundingRect.left, rect.left); + boundingRect.top = min(boundingRect.top, rect.top); + boundingRect.right = max(boundingRect.right, rect.right); + boundingRect.bottom = max(boundingRect.bottom, rect.bottom); + } + } + + if (!boundingRectEmpty) + { + for (size_t zoneId = 0; zoneId < zones.size(); zoneId++) + { + RECT rect = zones[zoneId]->GetZoneRect(); + if (boundingRect.left <= rect.left && rect.right <= boundingRect.right && + boundingRect.top <= rect.top && rect.bottom <= boundingRect.bottom) + { + result.push_back(zoneId); + } + } + } + + return result; +} + winrt::com_ptr MakeZoneSet(ZoneSetConfig const& config) noexcept { return winrt::make_self(config); diff --git a/src/modules/fancyzones/lib/ZoneSet.h b/src/modules/fancyzones/lib/ZoneSet.h index 6d40ef5b4..b9033bf58 100644 --- a/src/modules/fancyzones/lib/ZoneSet.h +++ b/src/modules/fancyzones/lib/ZoneSet.h @@ -91,6 +91,19 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet : * zones left in the zone layout in which window can move. */ IFACEMETHOD_(bool, MoveWindowIntoZoneByDirectionAndPosition)(HWND window, HWND zoneWindow, DWORD vkCode, bool cycle) = 0; + /** + * Extend or shrink the window to an adjacent zone based on direction (using CTRL+WIN+ALT + LEFT/RIGHT/UP/DOWN arrow), based on + * their on-screen position. + * + * @param window Handle of window which should be assigned to zone. + * @param zoneWindow The m_window of a ZoneWindow, it's a hidden window representing the + * current monitor desktop work area. + * @param vkCode Pressed arrow key. + * + * @returns Boolean indicating whether the window was rezoned. False could be returned when there are no more + * zones available in the given direction. + */ + IFACEMETHOD_(bool, ExtendWindowByDirectionAndPosition)(HWND window, HWND zoneWindow, DWORD vkCode) = 0; /** * Assign window to the zone based on cursor coordinates. * @@ -119,6 +132,15 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet : * @returns Boolean indicating whether the zone is empty. */ IFACEMETHOD_(bool, IsZoneEmpty)(int zoneIndex) = 0; + /** + * Returns all zones spanned by the minimum bounding rectangle containing the two given zone index sets. + * + * @param initialZones The indices of the first chosen zone (the anchor). + * @param finalZones The indices of the last chosen zone (the current window position). + * + * @returns A vector indicating describing the chosen zone index set. + */ + IFACEMETHOD_(std::vector, GetCombinedZoneRange)(const std::vector& initialZones, const std::vector& finalZones) = 0; }; struct ZoneSetConfig diff --git a/src/modules/fancyzones/lib/ZoneWindow.cpp b/src/modules/fancyzones/lib/ZoneWindow.cpp index d46902732..dfb4456a4 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.cpp +++ b/src/modules/fancyzones/lib/ZoneWindow.cpp @@ -79,6 +79,8 @@ public: MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle) noexcept; IFACEMETHODIMP_(bool) MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle) noexcept; + IFACEMETHODIMP_(bool) + ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noexcept; IFACEMETHODIMP_(void) CycleActiveZoneSet(DWORD vkCode) noexcept; IFACEMETHODIMP_(std::wstring) @@ -233,44 +235,7 @@ IFACEMETHODIMP ZoneWindow::MoveSizeUpdate(POINT const& ptScreen, bool dragEnable } else { - std::vector newHighlightZone; - std::set_union(begin(highlightZone), end(highlightZone), begin(m_initialHighlightZone), end(m_initialHighlightZone), std::back_inserter(newHighlightZone)); - - RECT boundingRect; - bool boundingRectEmpty = true; - auto zones = m_activeZoneSet->GetZones(); - - for (size_t zoneId : newHighlightZone) - { - RECT rect = zones[zoneId]->GetZoneRect(); - if (boundingRectEmpty) - { - boundingRect = rect; - boundingRectEmpty = false; - } - else - { - boundingRect.left = min(boundingRect.left, rect.left); - boundingRect.top = min(boundingRect.top, rect.top); - boundingRect.right = max(boundingRect.right, rect.right); - boundingRect.bottom = max(boundingRect.bottom, rect.bottom); - } - } - - highlightZone.clear(); - - if (!boundingRectEmpty) - { - for (size_t zoneId = 0; zoneId < zones.size(); zoneId++) - { - RECT rect = zones[zoneId]->GetZoneRect(); - if (boundingRect.left <= rect.left && rect.right <= boundingRect.right && - boundingRect.top <= rect.top && rect.bottom <= boundingRect.bottom) - { - highlightZone.push_back(zoneId); - } - } - } + highlightZone = m_activeZoneSet->GetCombinedZoneRange(m_initialHighlightZone, highlightZone); } } else @@ -367,6 +332,20 @@ ZoneWindow::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, return false; } +IFACEMETHODIMP_(bool) +ZoneWindow::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noexcept +{ + if (m_activeZoneSet) + { + if (m_activeZoneSet->ExtendWindowByDirectionAndPosition(window, m_window.get(), vkCode)) + { + SaveWindowProcessToZoneIndex(window); + return true; + } + } + return false; +} + IFACEMETHODIMP_(void) ZoneWindow::CycleActiveZoneSet(DWORD wparam) noexcept { diff --git a/src/modules/fancyzones/lib/ZoneWindow.h b/src/modules/fancyzones/lib/ZoneWindow.h index fc7f6adee..b4be8c5df 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.h +++ b/src/modules/fancyzones/lib/ZoneWindow.h @@ -29,10 +29,10 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow * @param dragEnabled Boolean indicating is giving hints about active zone layout enabled. * Hints are given while dragging window while holding SHIFT key. * @param selectManyZones When this parameter is true, the set of highlighted zones is computed - by finding the minimum bounding rectangle of the zone(s) from which the - user started dragging and the zone(s) above which the user is hovering - at the moment this function is called. Otherwise, highlight only the zone(s) - above which the user is currently hovering. + * by finding the minimum bounding rectangle of the zone(s) from which the + * user started dragging and the zone(s) above which the user is hovering + * at the moment this function is called. Otherwise, highlight only the zone(s) + * above which the user is currently hovering. */ IFACEMETHOD(MoveSizeUpdate)(POINT const& ptScreen, bool dragEnabled, bool selectManyZones) = 0; /** @@ -81,6 +81,17 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow * zones left in the zone layout in which window can move. */ IFACEMETHOD_(bool, MoveWindowIntoZoneByDirectionAndPosition)(HWND window, DWORD vkCode, bool cycle) = 0; + /** + * Extend or shrink the window to an adjacent zone based on direction (using CTRL+WIN+ALT + LEFT/RIGHT/UP/DOWN arrow), based on + * their on-screen position. + * + * @param window Handle of window which should be assigned to zone. + * @param vkCode Pressed arrow key. + * + * @returns Boolean indicating whether the window was rezoned. False could be returned when there are no more + * zones available in the given direction. + */ + IFACEMETHOD_(bool, ExtendWindowByDirectionAndPosition)(HWND window, DWORD vkCode) = 0; /** * Cycle through active zone layouts (giving hints about each layout). *