Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows snap hotkeys to move windows between screens #1603

Merged
merged 9 commits into from
Mar 24, 2020
93 changes: 84 additions & 9 deletions src/modules/fancyzones/lib/FancyZones.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ struct FancyZones : public winrt::implements<FancyZones, IFancyZones, IFancyZone

void OnEditorExitEvent() noexcept;

std::vector<HMONITOR> GetMonitorsSorted();
bool MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle);

const HINSTANCE m_hinstance{};

HKEY m_virtualDesktopsRegKey{ nullptr };
Expand Down Expand Up @@ -828,17 +831,43 @@ bool FancyZones::OnSnapHotkey(DWORD vkCode) noexcept
auto window = GetForegroundWindow();
if (IsInterestingWindow(window))
{
const HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
if (monitor)
const HMONITOR current = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
if (current)
{
std::shared_lock readLock(m_lock);

auto iter = m_zoneWindowMap.find(monitor);
if (iter != m_zoneWindowMap.end())
std::vector<HMONITOR> monitorInfo = GetMonitorsSorted();
if (monitorInfo.size() > 1)
{
const auto& zoneWindowPtr = iter->second;
zoneWindowPtr->MoveWindowIntoZoneByDirection(window, vkCode);
return true;
// Multi monitor environment.
auto currMonitorInfo = std::find(std::begin(monitorInfo), std::end(monitorInfo), current);
do
{
if (MoveWindowIntoZoneByDirection(*currMonitorInfo, window, vkCode, false /* cycle through zones */))
{
return true;
}
// We iterated through all zones in current monitor zone layout, move on to next one (or previous depending on direction).
if (vkCode == VK_RIGHT)
{
currMonitorInfo = std::next(currMonitorInfo);
if (currMonitorInfo == std::end(monitorInfo))
{
currMonitorInfo = std::begin(monitorInfo);
}
}
else if (vkCode == VK_LEFT)
{
if (currMonitorInfo == std::begin(monitorInfo))
{
currMonitorInfo = std::end(monitorInfo);
}
currMonitorInfo = std::prev(currMonitorInfo);
}
} while (*currMonitorInfo != current);
}
else
{
// Single monitor environment.
return MoveWindowIntoZoneByDirection(current, window, vkCode, true /* cycle through zones */);
}
}
}
Expand Down Expand Up @@ -1111,6 +1140,52 @@ void FancyZones::OnEditorExitEvent() noexcept
JSONHelpers::FancyZonesDataInstance().SaveFancyZonesData();
}

std::vector<HMONITOR> FancyZones::GetMonitorsSorted()
{
std::shared_lock readLock(m_lock);

std::vector<std::pair<HMONITOR, RECT>> monitorInfo;
for (const auto& [monitor, window] : m_zoneWindowMap)
{
if (window->ActiveZoneSet() != nullptr)
{
MONITORINFOEX mi;
mi.cbSize = sizeof(mi);
GetMonitorInfo(monitor, &mi);
monitorInfo.push_back({ monitor, mi.rcMonitor });
}
}

auto compare = [](const auto& a, const auto& b) {
vldmr11080 marked this conversation as resolved.
Show resolved Hide resolved
// Compare coordinates of top-left corner.
vldmr11080 marked this conversation as resolved.
Show resolved Hide resolved
if (a.second.left > b.second.left)
{
return true;
}
else if (a.second.left == b.second.left)
{
return a.second.top > b.second.top;
}
return false;
};
std::sort(std::begin(monitorInfo), std::end(monitorInfo), compare);

std::vector<HMONITOR> output;
std::transform(std::begin(monitorInfo), std::end(monitorInfo), std::back_inserter(output), [](const auto& info) { return info.first; });
return output;
}

bool FancyZones::MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle)
{
auto iter = m_zoneWindowMap.find(monitor);
if (iter != std::end(m_zoneWindowMap))
{
const auto& zoneWindowPtr = iter->second;
return zoneWindowPtr->MoveWindowIntoZoneByDirection(window, vkCode, cycle);
}
return false;
}

winrt::com_ptr<IFancyZones> MakeFancyZones(HINSTANCE hinstance, const winrt::com_ptr<IFancyZonesSettings>& settings) noexcept
{
if (!settings)
Expand Down
21 changes: 16 additions & 5 deletions src/modules/fancyzones/lib/ZoneSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ struct ZoneSet : winrt::implements<ZoneSet, IZoneSet>
GetZones() noexcept { return m_zones; }
IFACEMETHODIMP_(void)
MoveWindowIntoZoneByIndex(HWND window, HWND zoneWindow, int index) noexcept;
IFACEMETHODIMP_(void)
MoveWindowIntoZoneByDirection(HWND window, HWND zoneWindow, DWORD vkCode) noexcept;
IFACEMETHODIMP_(bool)
MoveWindowIntoZoneByDirection(HWND window, HWND zoneWindow, DWORD vkCode, bool cycle) noexcept;
IFACEMETHODIMP_(void)
MoveWindowIntoZoneByPoint(HWND window, HWND zoneWindow, POINT ptClient) noexcept;
IFACEMETHODIMP_(bool)
Expand Down Expand Up @@ -240,12 +240,12 @@ ZoneSet::MoveWindowIntoZoneByIndex(HWND window, HWND windowZone, int index) noex
}
}

IFACEMETHODIMP_(void)
ZoneSet::MoveWindowIntoZoneByDirection(HWND window, HWND windowZone, DWORD vkCode) noexcept
IFACEMETHODIMP_(bool)
ZoneSet::MoveWindowIntoZoneByDirection(HWND window, HWND windowZone, DWORD vkCode, bool cycle) noexcept
{
if (m_zones.empty())
{
return;
return false;
}

winrt::com_ptr<IZone> oldZone = nullptr;
Expand All @@ -262,6 +262,11 @@ ZoneSet::MoveWindowIntoZoneByDirection(HWND window, HWND windowZone, DWORD vkCod
{
if (iter == m_zones.begin())
{
if (!cycle)
{
oldZone->RemoveWindowFromZone(window, false);
return false;
}
iter = m_zones.end();
}
iter--;
Expand All @@ -271,6 +276,11 @@ ZoneSet::MoveWindowIntoZoneByDirection(HWND window, HWND windowZone, DWORD vkCod
iter++;
if (iter == m_zones.end())
{
if (!cycle)
{
oldZone->RemoveWindowFromZone(window, false);
return false;
}
iter = m_zones.begin();
}
}
Expand All @@ -284,6 +294,7 @@ ZoneSet::MoveWindowIntoZoneByDirection(HWND window, HWND windowZone, DWORD vkCod
}
newZone->AddWindowToZone(window, windowZone, true);
}
return true;
vldmr11080 marked this conversation as resolved.
Show resolved Hide resolved
}

IFACEMETHODIMP_(void)
Expand Down
9 changes: 7 additions & 2 deletions src/modules/fancyzones/lib/ZoneSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,12 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
* @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.
* @param cycle Whether we should move window to the first zone if we reached last zone in layout.
*
* @returns Boolean which is always true if cycle argument is set, otherwise indicating if there is more
* zones left in the zone layout in which window can move.
*/
IFACEMETHOD_(void, MoveWindowIntoZoneByDirection)(HWND window, HWND zoneWindow, DWORD vkCode) = 0;
IFACEMETHOD_(bool, MoveWindowIntoZoneByDirection)(HWND window, HWND zoneWindow, DWORD vkCode, bool cycle) = 0;
/**
* Assign window to the zone based on cursor coordinates.
*
Expand All @@ -75,7 +79,8 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
* @param monitorInfo Information about monitor on which zone layout is applied.
* @param zoneCount Number of zones inside zone layout.
* @param spacing Spacing between zones in pixels.
* @returns Boolean if calculation was successful.
*
* @returns Boolean indicating if calculation was successful.
*/
IFACEMETHOD_(bool, CalculateZones)(MONITORINFO monitorInfo, int zoneCount, int spacing) = 0;
};
Expand Down
16 changes: 10 additions & 6 deletions src/modules/fancyzones/lib/ZoneWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,8 @@ struct ZoneWindow : public winrt::implements<ZoneWindow, IZoneWindow>
IsDragEnabled() noexcept { return m_dragEnabled; }
IFACEMETHODIMP_(void)
MoveWindowIntoZoneByIndex(HWND window, int index) noexcept;
IFACEMETHODIMP_(void)
MoveWindowIntoZoneByDirection(HWND window, DWORD vkCode) noexcept;
IFACEMETHODIMP_(bool)
MoveWindowIntoZoneByDirection(HWND window, DWORD vkCode, bool cycle) noexcept;
IFACEMETHODIMP_(void)
CycleActiveZoneSet(DWORD vkCode) noexcept;
IFACEMETHODIMP_(std::wstring)
Expand Down Expand Up @@ -466,14 +466,18 @@ ZoneWindow::MoveWindowIntoZoneByIndex(HWND window, int index) noexcept
}
}

IFACEMETHODIMP_(void)
ZoneWindow::MoveWindowIntoZoneByDirection(HWND window, DWORD vkCode) noexcept
IFACEMETHODIMP_(bool)
ZoneWindow::MoveWindowIntoZoneByDirection(HWND window, DWORD vkCode, bool cycle) noexcept
{
if (m_activeZoneSet)
{
m_activeZoneSet->MoveWindowIntoZoneByDirection(window, m_window.get(), vkCode);
SaveWindowProcessToZoneIndex(window);
if (m_activeZoneSet->MoveWindowIntoZoneByDirection(window, m_window.get(), vkCode, cycle))
{
SaveWindowProcessToZoneIndex(window);
return true;
}
}
return false;
}

IFACEMETHODIMP_(void)
Expand Down
6 changes: 5 additions & 1 deletion src/modules/fancyzones/lib/ZoneWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,12 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow
*
* @param window Handle of window which should be assigned to zone.
* @param vkCode Pressed arrow key.
* @param cycle Whether we should move window to the first zone if we reached last zone in layout.
*
* @returns Boolean which is always true if cycle argument is set, otherwise indicating if there is more
* zones left in the zone layout in which window can move.
*/
IFACEMETHOD_(void, MoveWindowIntoZoneByDirection)(HWND window, DWORD vkCode) = 0;
IFACEMETHOD_(bool, MoveWindowIntoZoneByDirection)(HWND window, DWORD vkCode, bool cycle) = 0;
/**
* Cycle through active zone layouts (giving hints about each layout).
*
Expand Down
Loading