mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-04 10:16:24 +02:00
[FancyZones] Editor multi monitor support (#6562)
Co-authored-by: Enrico Giordani <enrico.giordani@gmail.com> Co-authored-by: Enrico Giordani <enricogior@users.noreply.github.com>
This commit is contained in:
@@ -9,6 +9,8 @@
|
||||
#include <sstream>
|
||||
#include <complex>
|
||||
|
||||
#include <fancyzones/lib/FancyZonesDataTypes.h>
|
||||
|
||||
// Non-Localizable strings
|
||||
namespace NonLocalizable
|
||||
{
|
||||
@@ -40,7 +42,7 @@ namespace
|
||||
|
||||
namespace FancyZonesUtils
|
||||
{
|
||||
std::wstring ParseDeviceId(const std::wstring& deviceId)
|
||||
std::wstring TrimDeviceId(const std::wstring& deviceId)
|
||||
{
|
||||
// We're interested in the unique part between the first and last #'s
|
||||
// Example input: \\?\DISPLAY#DELA026#5&10a58c63&0&UID16777488#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
|
||||
@@ -63,7 +65,95 @@ namespace FancyZonesUtils
|
||||
return defaultDeviceId;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<FancyZonesDataTypes::DeviceIdData> ParseDeviceId(const std::wstring& str)
|
||||
{
|
||||
FancyZonesDataTypes::DeviceIdData data;
|
||||
|
||||
std::wstring temp;
|
||||
std::wstringstream wss(str);
|
||||
|
||||
/*
|
||||
Important fix for device info that contains a '_' in the name:
|
||||
1. first search for '#'
|
||||
2. Then split the remaining string by '_'
|
||||
*/
|
||||
|
||||
// Step 1: parse the name until the #, then to the '_'
|
||||
if (str.find(L'#') != std::string::npos)
|
||||
{
|
||||
std::getline(wss, temp, L'#');
|
||||
|
||||
data.deviceName = temp;
|
||||
|
||||
if (!std::getline(wss, temp, L'_'))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
data.deviceName += L"#" + temp;
|
||||
}
|
||||
else if(std::getline(wss, temp, L'_') && !temp.empty())
|
||||
{
|
||||
data.deviceName = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Step 2: parse the rest of the id
|
||||
std::vector<std::wstring> parts;
|
||||
while (std::getline(wss, temp, L'_'))
|
||||
{
|
||||
parts.push_back(temp);
|
||||
}
|
||||
|
||||
if (parts.size() != 3 && parts.size() != 4)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/*
|
||||
Refer to ZoneWindowUtils::GenerateUniqueId parts contain:
|
||||
1. monitor id [string]
|
||||
2. width of device [int]
|
||||
3. height of device [int]
|
||||
4. virtual desktop id (GUID) [string]
|
||||
*/
|
||||
try
|
||||
{
|
||||
for (const auto& c : parts[0])
|
||||
{
|
||||
std::stoi(std::wstring(&c));
|
||||
}
|
||||
|
||||
for (const auto& c : parts[1])
|
||||
{
|
||||
std::stoi(std::wstring(&c));
|
||||
}
|
||||
|
||||
data.width = std::stoi(parts[0]);
|
||||
data.height = std::stoi(parts[1]);
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!SUCCEEDED(CLSIDFromString(parts[2].c_str(), &data.virtualDesktopId)))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (parts.size() == 4)
|
||||
{
|
||||
data.monitorId = parts[3]; //could be empty
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
typedef BOOL(WINAPI* GetDpiForMonitorInternalFunc)(HMONITOR, UINT, UINT*, UINT*);
|
||||
UINT GetDpiForMonitor(HMONITOR monitor) noexcept
|
||||
{
|
||||
@@ -457,6 +547,71 @@ namespace FancyZonesUtils
|
||||
return true;
|
||||
}
|
||||
|
||||
std::wstring GenerateUniqueId(HMONITOR monitor, const std::wstring& deviceId, const std::wstring& virtualDesktopId)
|
||||
{
|
||||
MONITORINFOEXW mi;
|
||||
mi.cbSize = sizeof(mi);
|
||||
if (!virtualDesktopId.empty() && GetMonitorInfo(monitor, &mi))
|
||||
{
|
||||
Rect const monitorRect(mi.rcMonitor);
|
||||
// Unique identifier format: <parsed-device-id>_<width>_<height>_<virtual-desktop-id>
|
||||
return TrimDeviceId(deviceId) +
|
||||
L'_' +
|
||||
std::to_wstring(monitorRect.width()) +
|
||||
L'_' +
|
||||
std::to_wstring(monitorRect.height()) +
|
||||
L'_' +
|
||||
virtualDesktopId;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::wstring GenerateUniqueIdAllMonitorsArea(const std::wstring& virtualDesktopId)
|
||||
{
|
||||
std::wstring result{ ZonedWindowProperties::MultiMonitorDeviceID };
|
||||
|
||||
RECT combinedResolution = GetAllMonitorsCombinedRect<&MONITORINFO::rcMonitor>();
|
||||
|
||||
result += L'_';
|
||||
result += std::to_wstring(combinedResolution.right - combinedResolution.left);
|
||||
result += L'_';
|
||||
result += std::to_wstring(combinedResolution.bottom - combinedResolution.top);
|
||||
result += L'_';
|
||||
result += virtualDesktopId;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<std::wstring> GenerateMonitorId(MONITORINFOEX mi, HMONITOR monitor, const GUID& virtualDesktopId)
|
||||
{
|
||||
DISPLAY_DEVICE displayDevice = { sizeof(displayDevice) };
|
||||
PCWSTR deviceId = nullptr;
|
||||
|
||||
bool validMonitor = true;
|
||||
if (EnumDisplayDevices(mi.szDevice, 0, &displayDevice, 1))
|
||||
{
|
||||
if (displayDevice.DeviceID[0] != L'\0')
|
||||
{
|
||||
deviceId = displayDevice.DeviceID;
|
||||
}
|
||||
}
|
||||
|
||||
if (!deviceId)
|
||||
{
|
||||
deviceId = GetSystemMetrics(SM_REMOTESESSION) ?
|
||||
L"\\\\?\\DISPLAY#REMOTEDISPLAY#" :
|
||||
L"\\\\?\\DISPLAY#LOCALDISPLAY#";
|
||||
}
|
||||
|
||||
wil::unique_cotaskmem_string vdId;
|
||||
if (SUCCEEDED(StringFromCLSID(virtualDesktopId, &vdId)))
|
||||
{
|
||||
return GenerateUniqueId(monitor, deviceId, vdId.get());
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
size_t ChooseNextZoneByPosition(DWORD vkCode, RECT windowRect, const std::vector<RECT>& zoneRects) noexcept
|
||||
{
|
||||
using complex = std::complex<double>;
|
||||
|
||||
Reference in New Issue
Block a user