Compare commits

...

8 Commits

Author SHA1 Message Date
martinchrzan
4bb149718f Hiding remove context menu when there are no colors in the history (#8482)
(cherry picked from commit 08d84cbd6a)
2020-12-08 15:33:14 +01:00
martinchrzan
df5c513603 color picker freeze hotfix into stable (#8481)
* Fixing issue when color picker was frozen because other application was locking clipboard

(cherry picked from commit d9fc6e4c9b)

* Fixed another issue where holding activation keys constantly would trigger show color picker numberous times and it would cause some events to be attached multiple times

(cherry picked from commit f5388a7c87)
2020-12-08 15:32:48 +01:00
Ivan Stošić
047b455601 [FancyZones] Reduce VRAM use (#8469) 2020-12-08 14:21:20 +01:00
Andrey Nekrasov
da384d3d65 FZ: fix incorrect snapping zoning behavior caused by calling MessageBox from LLKBHook cb (#8476) 2020-12-08 15:15:57 +03:00
Andrey Nekrasov
e6879aa97c install: update the installed dotnet version (#8456) 2020-12-08 13:58:16 +03:00
Ivan Stošić
4ced84b46d Free render target 2020-12-08 11:52:55 +01:00
Seraphima Zykova
1240598635 [FancyZones] Obtain device id (#8453) 2020-12-07 19:07:41 +03:00
Seraphima Zykova
9d39952670 handle key events (#8281) 2020-11-30 18:42:47 +01:00
14 changed files with 175 additions and 102 deletions

View File

@@ -22,7 +22,7 @@ namespace updating
bool install_dotnet(const bool silent) bool install_dotnet(const bool silent)
{ {
const wchar_t DOTNET_DESKTOP_DOWNLOAD_LINK[] = L"https://download.visualstudio.microsoft.com/download/pr/3eb7efa1-96c6-4e97-bb9f-563ecf595f8a/7efd9c1cdd74df8fb0a34c288138a84f/windowsdesktop-runtime-3.1.6-win-x64.exe"; const wchar_t DOTNET_DESKTOP_DOWNLOAD_LINK[] = L"https://download.visualstudio.microsoft.com/download/pr/513acf37-8da2-497d-bdaa-84d6e33c1fee/eb7b010350df712c752f4ec4b615f89d/windowsdesktop-runtime-3.1.10-win-x64.exe";
const wchar_t DOTNET_DESKTOP_FILENAME[] = L"windowsdesktop-runtime.exe"; const wchar_t DOTNET_DESKTOP_FILENAME[] = L"windowsdesktop-runtime.exe";
auto dotnet_download_path = fs::temp_directory_path() / DOTNET_DESKTOP_FILENAME; auto dotnet_download_path = fs::temp_directory_path() / DOTNET_DESKTOP_FILENAME;

View File

@@ -14,6 +14,8 @@ namespace ColorPicker.Helpers
{ {
private readonly IColorEditorViewModel _colorEditorViewModel; private readonly IColorEditorViewModel _colorEditorViewModel;
private ColorEditorWindow _colorEditorWindow; private ColorEditorWindow _colorEditorWindow;
private bool _colorPickerShown;
private object _colorPickerVisibilityLock = new object();
[ImportingConstructor] [ImportingConstructor]
public AppStateHandler(IColorEditorViewModel colorEditorViewModel) public AppStateHandler(IColorEditorViewModel colorEditorViewModel)
@@ -30,16 +32,30 @@ namespace ColorPicker.Helpers
public void ShowColorPicker() public void ShowColorPicker()
{ {
AppShown?.Invoke(this, EventArgs.Empty); lock (_colorPickerVisibilityLock)
Application.Current.MainWindow.Opacity = 0; {
Application.Current.MainWindow.Visibility = Visibility.Visible; if (!_colorPickerShown)
{
AppShown?.Invoke(this, EventArgs.Empty);
Application.Current.MainWindow.Opacity = 0;
Application.Current.MainWindow.Visibility = Visibility.Visible;
_colorPickerShown = true;
}
}
} }
public void HideColorPicker() public void HideColorPicker()
{ {
Application.Current.MainWindow.Opacity = 0; lock (_colorPickerVisibilityLock)
Application.Current.MainWindow.Visibility = Visibility.Collapsed; {
AppHidden?.Invoke(this, EventArgs.Empty); if (_colorPickerShown)
{
Application.Current.MainWindow.Opacity = 0;
Application.Current.MainWindow.Visibility = Visibility.Collapsed;
AppHidden?.Invoke(this, EventArgs.Empty);
_colorPickerShown = false;
}
}
} }
public void ShowColorPickerEditor() public void ShowColorPickerEditor()

View File

@@ -3,7 +3,9 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Windows; using System.Windows;
using static ColorPicker.NativeMethods;
namespace ColorPicker.Helpers namespace ColorPicker.Helpers
{ {
@@ -23,15 +25,24 @@ namespace ColorPicker.Helpers
{ {
try try
{ {
Clipboard.SetText(colorRepresentationToCopy); Clipboard.SetDataObject(colorRepresentationToCopy);
break; break;
} }
catch (COMException ex) catch (COMException ex)
{ {
var hwnd = GetOpenClipboardWindow();
var sb = new StringBuilder(501);
_ = GetWindowText(hwnd.ToInt32(), sb, 500);
var applicationUsingClipboard = sb.ToString();
if ((uint)ex.ErrorCode != ErrorCodeClipboardCantOpen) if ((uint)ex.ErrorCode != ErrorCodeClipboardCantOpen)
{ {
Logger.LogError("Failed to set text into clipboard", ex); Logger.LogError("Failed to set text into clipboard", ex);
} }
else
{
Logger.LogError("Failed to set text into clipboard, application that is locking clipboard - " + applicationUsingClipboard, ex);
}
} }
System.Threading.Thread.Sleep(10); System.Threading.Thread.Sleep(10);

View File

@@ -5,6 +5,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.Composition; using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Windows.Input; using System.Windows.Input;
using ColorPicker.Helpers; using ColorPicker.Helpers;
using ColorPicker.Settings; using ColorPicker.Settings;
@@ -21,10 +22,12 @@ namespace ColorPicker.Keyboard
{ {
private readonly AppStateHandler _appStateHandler; private readonly AppStateHandler _appStateHandler;
private readonly IUserSettings _userSettings; private readonly IUserSettings _userSettings;
private List<string> _previouslyPressedKeys;
private List<string> _activationKeys = new List<string>(); private List<string> _activationKeys = new List<string>();
private GlobalKeyboardHook _keyboardHook; private GlobalKeyboardHook _keyboardHook;
private bool disposedValue; private bool disposedValue;
private bool _activationShortcutPressed;
[ImportingConstructor] [ImportingConstructor]
public KeyboardMonitor(AppStateHandler appStateHandler, IUserSettings userSettings) public KeyboardMonitor(AppStateHandler appStateHandler, IUserSettings userSettings)
@@ -80,26 +83,38 @@ namespace ColorPicker.Keyboard
// If the last key pressed is a modifier key, then currentlyPressedKeys cannot possibly match with _activationKeys // If the last key pressed is a modifier key, then currentlyPressedKeys cannot possibly match with _activationKeys
// because _activationKeys contains exactly 1 non-modifier key. Hence, there's no need to check if `name` is a // because _activationKeys contains exactly 1 non-modifier key. Hence, there's no need to check if `name` is a
// modifier key or to do any additional processing on it. // modifier key or to do any additional processing on it.
// Check pressed modifier keys.
AddModifierKeys(currentlyPressedKeys);
if (e.KeyboardState == GlobalKeyboardHook.KeyboardState.KeyDown || e.KeyboardState == GlobalKeyboardHook.KeyboardState.SysKeyDown) if (e.KeyboardState == GlobalKeyboardHook.KeyboardState.KeyDown || e.KeyboardState == GlobalKeyboardHook.KeyboardState.SysKeyDown)
{ {
// Check pressed modifier keys.
AddModifierKeys(currentlyPressedKeys);
currentlyPressedKeys.Add(name); currentlyPressedKeys.Add(name);
} }
currentlyPressedKeys.Sort(); currentlyPressedKeys.Sort();
if (currentlyPressedKeys.Count == 0 && _previouslyPressedKeys.Count != 0)
{
// no keys pressed, we can enable activation shortcut again
_activationShortcutPressed = false;
}
_previouslyPressedKeys = currentlyPressedKeys;
if (ArraysAreSame(currentlyPressedKeys, _activationKeys)) if (ArraysAreSame(currentlyPressedKeys, _activationKeys))
{ {
if (_userSettings.ActivationAction.Value == ColorPickerActivationAction.OpenEditor) // avoid triggering this action multiple times as this will be called nonstop while keys are pressed
if (!_activationShortcutPressed)
{ {
_appStateHandler.ShowColorPickerEditor(); _activationShortcutPressed = true;
} if (_userSettings.ActivationAction.Value == ColorPickerActivationAction.OpenEditor)
else {
{ _appStateHandler.ShowColorPickerEditor();
_appStateHandler.ShowColorPicker(); }
else
{
_appStateHandler.ShowColorPicker();
}
} }
} }
} }

View File

@@ -5,6 +5,7 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Versioning; using System.Runtime.Versioning;
using System.Text;
namespace ColorPicker namespace ColorPicker
{ {
@@ -161,5 +162,11 @@ namespace ColorPicker
/// </summary> /// </summary>
public IntPtr AdditionalInformation; public IntPtr AdditionalInformation;
} }
[DllImport("user32.dll")]
internal static extern IntPtr GetOpenClipboardWindow();
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern int GetWindowText(int hwnd, StringBuilder text, int count);
} }
} }

View File

@@ -28,7 +28,7 @@
SelectedIndex="{Binding SelectedColorIndex}" SelectedIndex="{Binding SelectedColorIndex}"
ItemContainerStyle="{DynamicResource ColorHistoryListViewStyle}"> ItemContainerStyle="{DynamicResource ColorHistoryListViewStyle}">
<ui:ListView.ContextMenu> <ui:ListView.ContextMenu>
<ContextMenu> <ContextMenu Visibility="{Binding ColorsHistory.Count, Converter={StaticResource numberToVisibilityConverter}}">
<MenuItem Header="{x:Static p:Resources.Remove}" <MenuItem Header="{x:Static p:Resources.Remove}"
Command="{Binding RemoveColorCommand}"> Command="{Binding RemoveColorCommand}">
<MenuItem.Icon> <MenuItem.Icon>

View File

@@ -91,6 +91,22 @@ namespace FancyZonesEditor
Overlay.Show(); Overlay.Show();
} }
public void App_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.LeftShift || e.Key == System.Windows.Input.Key.RightShift)
{
MainWindowSettings.IsShiftKeyPressed = false;
}
}
public void App_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.LeftShift || e.Key == System.Windows.Input.Key.RightShift)
{
MainWindowSettings.IsShiftKeyPressed = true;
}
}
public static void ShowExceptionMessageBox(string message, Exception exception = null) public static void ShowExceptionMessageBox(string message, Exception exception = null)
{ {
string fullMessage = FancyZonesEditor.Properties.Resources.Error_Report + PowerToysIssuesURL + " \n" + message; string fullMessage = FancyZonesEditor.Properties.Resources.Error_Report + PowerToysIssuesURL + " \n" + message;

View File

@@ -19,6 +19,7 @@ namespace FancyZonesEditor
InitializeComponent(); InitializeComponent();
KeyUp += GridEditorWindow_KeyUp; KeyUp += GridEditorWindow_KeyUp;
KeyDown += ((App)Application.Current).App_KeyDown;
_stashedModel = (GridLayoutModel)(App.Overlay.CurrentDataContext as GridLayoutModel).Clone(); _stashedModel = (GridLayoutModel)(App.Overlay.CurrentDataContext as GridLayoutModel).Clone();
} }
@@ -36,6 +37,8 @@ namespace FancyZonesEditor
{ {
OnCancel(sender, null); OnCancel(sender, null);
} }
((App)Application.Current).App_KeyUp(sender, e);
} }
private GridLayoutModel _stashedModel; private GridLayoutModel _stashedModel;

View File

@@ -5,6 +5,7 @@
using System; using System;
using System.Reflection; using System.Reflection;
using System.Windows; using System.Windows;
using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using FancyZonesEditor.Utils; using FancyZonesEditor.Utils;
@@ -32,6 +33,9 @@ namespace FancyZonesEditor.Models
Window.Background = (Brush)properties[milliseconds % properties.Length].GetValue(null, null); Window.Background = (Brush)properties[milliseconds % properties.Length].GetValue(null, null);
} }
Window.KeyUp += ((App)Application.Current).App_KeyUp;
Window.KeyDown += ((App)Application.Current).App_KeyDown;
Window.Left = workArea.X; Window.Left = workArea.X;
Window.Top = workArea.Y; Window.Top = workArea.Y;
Window.Width = workArea.Width; Window.Width = workArea.Width;

View File

@@ -634,53 +634,73 @@ void FancyZones::ToggleEditor() noexcept
const bool spanZonesAcrossMonitors = m_settings->GetSettings()->spanZonesAcrossMonitors; const bool spanZonesAcrossMonitors = m_settings->GetSettings()->spanZonesAcrossMonitors;
params += std::to_wstring(spanZonesAcrossMonitors) + divider; /* Span zones */ params += std::to_wstring(spanZonesAcrossMonitors) + divider; /* Span zones */
std::vector<std::pair<HMONITOR, MONITORINFOEX>> allMonitors; std::vector<std::pair<HMONITOR, MONITORINFOEX>> allMonitors;
allMonitors = FancyZonesUtils::GetAllMonitorInfo<&MONITORINFOEX::rcWork>(); allMonitors = FancyZonesUtils::GetAllMonitorInfo<&MONITORINFOEX::rcWork>();
// device id map
std::unordered_map<std::wstring, DWORD> displayDeviceIdxMap;
bool showDpiWarning = false; bool showDpiWarning = false;
int prevDpiX = -1, prevDpiY = -1; int prevDpiX = -1, prevDpiY = -1;
std::wstring monitorsData; std::wstring monitorsDataStr;
for (auto& monitor : allMonitors) for (auto& monitorData : allMonitors)
{ {
auto monitorId = FancyZonesUtils::GenerateMonitorId(monitor.second, monitor.first, m_currentDesktopId); HMONITOR monitor = monitorData.first;
if (monitor.first == targetMonitor) auto monitorInfo = monitorData.second;
std::wstring monitorId;
std::wstring deviceId = FancyZonesUtils::GetDisplayDeviceId(monitorInfo.szDevice, displayDeviceIdxMap);
wil::unique_cotaskmem_string virtualDesktopId;
if (SUCCEEDED(StringFromCLSID(m_currentDesktopId, &virtualDesktopId)))
{ {
params += *monitorId + divider; /* Monitor id where the Editor should be opened */ monitorId = FancyZonesUtils::GenerateUniqueId(monitor, deviceId, virtualDesktopId.get());
}
else
{
continue;
} }
if (monitorId.has_value()) if (monitor == targetMonitor)
{ {
monitorsData += std::move(*monitorId) + divider; /* Monitor id */ params += monitorId + divider; /* Monitor id where the Editor should be opened */
}
UINT dpiX = 0; monitorsDataStr += std::move(monitorId) + divider; /* Monitor id */
UINT dpiY = 0;
if (GetDpiForMonitor(monitor.first, MDT_EFFECTIVE_DPI, &dpiX, &dpiY) == S_OK) UINT dpiX = 0;
UINT dpiY = 0;
if (GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY) == S_OK)
{
monitorsDataStr += std::to_wstring(dpiX) + divider; /* DPI */
if (spanZonesAcrossMonitors && prevDpiX != -1 && (prevDpiX != dpiX || prevDpiY != dpiY))
{ {
monitorsData += std::to_wstring(dpiX) + divider; /* DPI */ showDpiWarning = true;
if (spanZonesAcrossMonitors && prevDpiX != -1 && (prevDpiX != dpiX || prevDpiY != dpiY))
{
showDpiWarning = true;
}
prevDpiX = dpiX;
prevDpiY = dpiY;
} }
monitorsData += std::to_wstring(monitor.second.rcMonitor.left) + divider; prevDpiX = dpiX;
monitorsData += std::to_wstring(monitor.second.rcMonitor.top) + divider; prevDpiY = dpiY;
} }
monitorsDataStr += std::to_wstring(monitorInfo.rcMonitor.left) + divider;
monitorsDataStr += std::to_wstring(monitorInfo.rcMonitor.top) + divider;
} }
params += std::to_wstring(allMonitors.size()) + divider; /* Monitors count */ params += std::to_wstring(allMonitors.size()) + divider; /* Monitors count */
params += monitorsData; params += monitorsDataStr;
if (showDpiWarning) if (showDpiWarning)
{ {
MessageBoxW(NULL, // We must show the message box in a separate thread, since this code is called from a low-level
GET_RESOURCE_STRING(IDS_SPAN_ACROSS_ZONES_WARNING).c_str(), // keyboard hook callback, and launching messageboxes from it has unexpected side effects,
GET_RESOURCE_STRING(IDS_POWERTOYS_FANCYZONES).c_str(), // like triggering EVENT_SYSTEM_MOVESIZEEND prematurely.
MB_OK | MB_ICONWARNING); // TODO: understand the root cause of this, until then it's commented out.
//std::thread{ [] {
// MessageBoxW(nullptr,
// GET_RESOURCE_STRING(IDS_SPAN_ACROSS_ZONES_WARNING).c_str(),
// GET_RESOURCE_STRING(IDS_POWERTOYS_FANCYZONES).c_str(),
// MB_OK | MB_ICONWARNING);
//} }.detach();
} }
const auto& fancyZonesData = FancyZonesDataInstance(); const auto& fancyZonesData = FancyZonesDataInstance();
@@ -951,30 +971,8 @@ void FancyZones::UpdateZoneWindows() noexcept
auto& displayDeviceIdxMap = *(params->displayDeviceIdx); auto& displayDeviceIdxMap = *(params->displayDeviceIdx);
FancyZones* fancyZones = params->fancyZones; FancyZones* fancyZones = params->fancyZones;
DISPLAY_DEVICE displayDevice{ .cb = sizeof(displayDevice) }; std::wstring deviceId = FancyZonesUtils::GetDisplayDeviceId(mi.szDevice, displayDeviceIdxMap);
std::wstring deviceId; fancyZones->AddZoneWindow(monitor, deviceId);
while (EnumDisplayDevicesW(mi.szDevice, displayDeviceIdxMap[mi.szDevice], &displayDevice, EDD_GET_DEVICE_INTERFACE_NAME))
{
++displayDeviceIdxMap[mi.szDevice];
// Only take active monitors (presented as being "on" by the respective GDI view) and monitors that don't
// represent a pseudo device used to mirror application drawing.
if (WI_IsFlagSet(displayDevice.StateFlags, DISPLAY_DEVICE_ACTIVE) &&
WI_IsFlagClear(displayDevice.StateFlags, DISPLAY_DEVICE_MIRRORING_DRIVER))
{
deviceId = displayDevice.DeviceID;
fancyZones->AddZoneWindow(monitor, deviceId);
break;
}
}
if (deviceId.empty())
{
deviceId = GetSystemMetrics(SM_REMOTESESSION) ?
L"\\\\?\\DISPLAY#REMOTEDISPLAY#" :
L"\\\\?\\DISPLAY#LOCALDISPLAY#";
fancyZones->AddZoneWindow(monitor, deviceId);
}
} }
return TRUE; return TRUE;
}; };

View File

@@ -120,8 +120,7 @@ bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monit
{ {
return false; return false;
} }
const UINT dpi = GetDpiForMonitor(m_monitor); workAreaRect = Rect(mi.rcWork);
workAreaRect = Rect(mi.rcWork, dpi);
} }
else else
{ {

View File

@@ -315,4 +315,9 @@ ZoneWindowDrawing::~ZoneWindowDrawing()
} }
m_cv.notify_all(); m_cv.notify_all();
m_renderThread.join(); m_renderThread.join();
if (m_renderTarget)
{
m_renderTarget->Release();
}
} }

View File

@@ -155,6 +155,34 @@ namespace FancyZonesUtils
} }
typedef BOOL(WINAPI* GetDpiForMonitorInternalFunc)(HMONITOR, UINT, UINT*, UINT*); typedef BOOL(WINAPI* GetDpiForMonitorInternalFunc)(HMONITOR, UINT, UINT*, UINT*);
std::wstring GetDisplayDeviceId(const std::wstring& device, std::unordered_map<std::wstring, DWORD>& displayDeviceIdxMap)
{
DISPLAY_DEVICE displayDevice{ .cb = sizeof(displayDevice) };
std::wstring deviceId;
while (EnumDisplayDevicesW(device.c_str(), displayDeviceIdxMap[device], &displayDevice, EDD_GET_DEVICE_INTERFACE_NAME))
{
++displayDeviceIdxMap[device];
// Only take active monitors (presented as being "on" by the respective GDI view) and monitors that don't
// represent a pseudo device used to mirror application drawing.
if (WI_IsFlagSet(displayDevice.StateFlags, DISPLAY_DEVICE_ACTIVE) &&
WI_IsFlagClear(displayDevice.StateFlags, DISPLAY_DEVICE_MIRRORING_DRIVER))
{
deviceId = displayDevice.DeviceID;
break;
}
}
if (deviceId.empty())
{
deviceId = GetSystemMetrics(SM_REMOTESESSION) ?
L"\\\\?\\DISPLAY#REMOTEDISPLAY#" :
L"\\\\?\\DISPLAY#LOCALDISPLAY#";
}
return deviceId;
}
UINT GetDpiForMonitor(HMONITOR monitor) noexcept UINT GetDpiForMonitor(HMONITOR monitor) noexcept
{ {
UINT dpi{}; UINT dpi{};
@@ -582,36 +610,6 @@ namespace FancyZonesUtils
return result; 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 size_t ChooseNextZoneByPosition(DWORD vkCode, RECT windowRect, const std::vector<RECT>& zoneRects) noexcept
{ {
using complex = std::complex<double>; using complex = std::complex<double>;

View File

@@ -184,6 +184,8 @@ namespace FancyZonesUtils
return result; return result;
} }
std::wstring GetDisplayDeviceId(const std::wstring& device, std::unordered_map<std::wstring, DWORD>& displayDeviceIdxMap);
UINT GetDpiForMonitor(HMONITOR monitor) noexcept; UINT GetDpiForMonitor(HMONITOR monitor) noexcept;
void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo); void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo);
void SizeWindowToRect(HWND window, RECT rect) noexcept; void SizeWindowToRect(HWND window, RECT rect) noexcept;
@@ -202,7 +204,6 @@ namespace FancyZonesUtils
std::wstring GenerateUniqueId(HMONITOR monitor, const std::wstring& devideId, const std::wstring& virtualDesktopId); std::wstring GenerateUniqueId(HMONITOR monitor, const std::wstring& devideId, const std::wstring& virtualDesktopId);
std::wstring GenerateUniqueIdAllMonitorsArea(const std::wstring& virtualDesktopId); std::wstring GenerateUniqueIdAllMonitorsArea(const std::wstring& virtualDesktopId);
std::optional<std::wstring> GenerateMonitorId(MONITORINFOEX mi, HMONITOR monitor, const GUID& virtualDesktopId);
std::wstring TrimDeviceId(const std::wstring& deviceId); std::wstring TrimDeviceId(const std::wstring& deviceId);
std::optional<FancyZonesDataTypes::DeviceIdData> ParseDeviceId(const std::wstring& deviceId); std::optional<FancyZonesDataTypes::DeviceIdData> ParseDeviceId(const std::wstring& deviceId);