[FancyZones Editor] Quick layout switch hotkeys (#10437)

Co-authored-by: Ivan Stošić <ivan100sic@gmail.com>
This commit is contained in:
Seraphima Zykova
2021-03-25 15:44:55 +03:00
committed by GitHub
parent 7ba03ed24f
commit 13c4c188fa
34 changed files with 986 additions and 376 deletions

View File

@@ -34,6 +34,30 @@ enum class DisplayChangeType
namespace
{
constexpr int CUSTOM_POSITIONING_LEFT_TOP_PADDING = 16;
struct require_read_lock
{
template<typename T>
require_read_lock(const std::shared_lock<T>& lock)
{
lock;
}
template<typename T>
require_read_lock(const std::unique_lock<T>& lock)
{
lock;
}
};
struct require_write_lock
{
template<typename T>
require_write_lock(const std::unique_lock<T>& lock)
{
lock;
}
};
}
// Non-localizable strings
@@ -184,40 +208,16 @@ public:
}
LRESULT WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
void OnDisplayChange(DisplayChangeType changeType) noexcept;
void AddZoneWindow(HMONITOR monitor, const std::wstring& deviceId) noexcept;
void OnDisplayChange(DisplayChangeType changeType, require_write_lock) noexcept;
void AddZoneWindow(HMONITOR monitor, const std::wstring& deviceId, require_write_lock) noexcept;
protected:
static LRESULT CALLBACK s_WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
private:
struct require_read_lock
{
template<typename T>
require_read_lock(const std::shared_lock<T>& lock)
{
lock;
}
template<typename T>
require_read_lock(const std::unique_lock<T>& lock)
{
lock;
}
};
struct require_write_lock
{
template<typename T>
require_write_lock(const std::unique_lock<T>& lock)
{
lock;
}
};
void UpdateZoneWindows() noexcept;
void UpdateWindowsPositions() noexcept;
void CycleActiveZoneSet(DWORD vkCode) noexcept;
void UpdateZoneWindows(require_write_lock) noexcept;
void UpdateWindowsPositions(require_write_lock) noexcept;
bool OnSnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode) noexcept;
bool OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept;
bool OnSnapHotkey(DWORD vkCode) noexcept;
@@ -232,12 +232,15 @@ private:
std::pair<winrt::com_ptr<IZoneWindow>, std::vector<size_t>> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, bool isPrimaryMonitor) noexcept;
void MoveWindowIntoZone(HWND window, winrt::com_ptr<IZoneWindow> zoneWindow, const std::vector<size_t>& zoneIndexSet) noexcept;
void OnEditorExitEvent() noexcept;
void UpdateZoneSets() noexcept;
void OnEditorExitEvent(require_write_lock) noexcept;
void UpdateZoneSets(require_write_lock) noexcept;
bool ShouldProcessSnapHotkey(DWORD vkCode) noexcept;
void ApplyQuickLayout(int key) noexcept;
void FlashZones(require_write_lock) noexcept;
std::vector<std::pair<HMONITOR, RECT>> GetRawMonitorData() noexcept;
std::vector<HMONITOR> GetMonitorsSorted() noexcept;
HMONITOR WorkAreaKeyFromWindow(HWND window) noexcept;
const HINSTANCE m_hinstance{};
@@ -266,6 +269,7 @@ private:
static UINT WM_PRIV_FILE_UPDATE; // Scheduled when the a watched file is updated
static UINT WM_PRIV_SNAP_HOTKEY; // Scheduled when we receive a snap hotkey key down press
static UINT WM_PRIV_QUICK_LAYOUT_KEY; // Scheduled when we receive a key down press to quickly apply a layout
// Did we terminate the editor or was it closed cleanly?
enum class EditorExitKind : byte
@@ -283,6 +287,7 @@ UINT FancyZones::WM_PRIV_VD_UPDATE = RegisterWindowMessage(L"{b8b72b46-f42f-4c26
UINT FancyZones::WM_PRIV_EDITOR = RegisterWindowMessage(L"{87543824-7080-4e91-9d9c-0404642fc7b6}");
UINT FancyZones::WM_PRIV_FILE_UPDATE = RegisterWindowMessage(L"{632f17a9-55a7-45f1-a4db-162e39271d92}");
UINT FancyZones::WM_PRIV_SNAP_HOTKEY = RegisterWindowMessage(L"{763c03a3-03d9-4cde-8d71-f0358b0b4b52}");
UINT FancyZones::WM_PRIV_QUICK_LAYOUT_KEY = RegisterWindowMessage(L"{72f4fd8e-23f1-43ab-bbbc-029363df9a84}");
// IFancyZones
IFACEMETHODIMP_(void)
@@ -553,18 +558,6 @@ FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept
bool const ctrl = GetAsyncKeyState(VK_CONTROL) & 0x8000;
if ((win && !shift && !ctrl) || (win && ctrl && alt))
{
// 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))
@@ -576,14 +569,34 @@ FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept
}
}
}
// Temporarily disable Win+Ctrl+Number functionality
//else if (m_inMoveSize && (info->vkCode >= '0') && (info->vkCode <= '9'))
//{
// // This allows you to cycle through ZoneSets while dragging a window
// Trace::FancyZones::OnKeyDown(info->vkCode, win, false /*control*/, true /*inMoveSize*/);
// CycleActiveZoneSet(info->vkCode);
// return false;
//}
if (m_settings->GetSettings()->quickLayoutSwitch)
{
int digitPressed = -1;
if ('0' <= info->vkCode && info->vkCode <= '9')
{
digitPressed = info->vkCode - '0';
}
else if (VK_NUMPAD0 <= info->vkCode && info->vkCode <= VK_NUMPAD9)
{
digitPressed = info->vkCode - VK_NUMPAD0;
}
bool dragging = m_windowMoveHandler.InMoveSize();
bool changeLayoutWhileNotDragging = !dragging && !shift && win && ctrl && alt && digitPressed != -1;
bool changeLayoutWhileDragging = dragging && digitPressed != -1;
if (changeLayoutWhileNotDragging || changeLayoutWhileDragging)
{
auto quickKeysMap = FancyZonesDataInstance().GetLayoutQuickKeys();
if (std::any_of(quickKeysMap.begin(), quickKeysMap.end(), [=](auto item) { return item.second == digitPressed; }))
{
PostMessageW(m_window, WM_PRIV_QUICK_LAYOUT_KEY, 0, static_cast<LPARAM>(digitPressed));
Trace::FancyZones::QuickLayoutSwitched(changeLayoutWhileNotDragging);
return true;
}
}
}
if (m_windowMoveHandler.IsDragEnabled() && shift)
{
@@ -755,13 +768,16 @@ void FancyZones::ToggleEditor() noexcept
void FancyZones::SettingsChanged() noexcept
{
_TRACER_;
std::unique_lock writeLock(m_lock);
// Update the hotkey
UnregisterHotKey(m_window, 1);
RegisterHotKey(m_window, 1, m_settings->GetSettings()->editorHotkey.get_modifiers(), m_settings->GetSettings()->editorHotkey.get_code());
// Needed if we toggled spanZonesAcrossMonitors
m_workAreaHandler.Clear();
OnDisplayChange(DisplayChangeType::Initialization);
OnDisplayChange(DisplayChangeType::Initialization, writeLock);
}
// IZoneWindowHost
@@ -770,7 +786,8 @@ FancyZones::MoveWindowsOnActiveZoneSetChange() noexcept
{
if (m_settings->GetSettings()->zoneSetChange_moveWindows)
{
UpdateWindowsPositions();
std::unique_lock writeLock(m_lock);
UpdateWindowsPositions(writeLock);
}
}
@@ -793,8 +810,9 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
{
// Changes in taskbar position resulted in different size of work area.
// Invalidate cached work-areas so they can be recreated with latest information.
std::unique_lock writeLock(m_lock);
m_workAreaHandler.Clear();
OnDisplayChange(DisplayChangeType::WorkArea);
OnDisplayChange(DisplayChangeType::WorkArea, writeLock);
}
}
break;
@@ -802,8 +820,9 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
case WM_DISPLAYCHANGE:
{
// Display resolution changed. Invalidate cached work-areas so they can be recreated with latest information.
std::unique_lock writeLock(m_lock);
m_workAreaHandler.Clear();
OnDisplayChange(DisplayChangeType::DisplayChange);
OnDisplayChange(DisplayChangeType::DisplayChange, writeLock);
}
break;
@@ -818,11 +837,13 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
}
else if (message == WM_PRIV_VD_INIT)
{
OnDisplayChange(DisplayChangeType::Initialization);
std::unique_lock writeLock(m_lock);
OnDisplayChange(DisplayChangeType::Initialization, writeLock);
}
else if (message == WM_PRIV_VD_SWITCH)
{
OnDisplayChange(DisplayChangeType::VirtualDesktop);
std::unique_lock writeLock(m_lock);
OnDisplayChange(DisplayChangeType::VirtualDesktop, writeLock);
}
else if (message == WM_PRIV_VD_UPDATE)
{
@@ -836,7 +857,8 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
{
if (lparam == static_cast<LPARAM>(EditorExitKind::Exit))
{
OnEditorExitEvent();
std::unique_lock writeLock(m_lock);
OnEditorExitEvent(writeLock);
}
{
@@ -873,7 +895,12 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
else if (message == WM_PRIV_FILE_UPDATE)
{
FancyZonesDataInstance().LoadFancyZonesData();
UpdateZoneSets();
std::unique_lock writeLock(m_lock);
UpdateZoneSets(writeLock);
}
else if (message == WM_PRIV_QUICK_LAYOUT_KEY)
{
ApplyQuickLayout(static_cast<int>(lparam));
}
else
{
@@ -885,7 +912,7 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
return 0;
}
void FancyZones::OnDisplayChange(DisplayChangeType changeType) noexcept
void FancyZones::OnDisplayChange(DisplayChangeType changeType, require_write_lock lock) noexcept
{
_TRACER_;
if (changeType == DisplayChangeType::VirtualDesktop ||
@@ -912,22 +939,20 @@ void FancyZones::OnDisplayChange(DisplayChangeType changeType) noexcept
}
}
UpdateZoneWindows();
UpdateZoneWindows(lock);
if ((changeType == DisplayChangeType::WorkArea) || (changeType == DisplayChangeType::DisplayChange))
{
if (m_settings->GetSettings()->displayChange_moveWindows)
{
UpdateWindowsPositions();
UpdateWindowsPositions(lock);
}
}
}
void FancyZones::AddZoneWindow(HMONITOR monitor, const std::wstring& deviceId) noexcept
void FancyZones::AddZoneWindow(HMONITOR monitor, const std::wstring& deviceId, require_write_lock) noexcept
{
_TRACER_;
std::unique_lock writeLock(m_lock);
if (m_workAreaHandler.IsNewWorkArea(m_currentDesktopId, monitor))
{
wil::unique_cotaskmem_string virtualDesktopId;
@@ -974,7 +999,7 @@ LRESULT CALLBACK FancyZones::s_WndProc(HWND window, UINT message, WPARAM wparam,
DefWindowProc(window, message, wparam, lparam);
}
void FancyZones::UpdateZoneWindows() noexcept
void FancyZones::UpdateZoneWindows(require_write_lock lock) noexcept
{
// Mapping between display device name and device index (operating system identifies each display device with an index value).
std::unordered_map<std::wstring, DWORD> displayDeviceIdxMap;
@@ -982,6 +1007,7 @@ void FancyZones::UpdateZoneWindows() noexcept
{
FancyZones* fancyZones;
std::unordered_map<std::wstring, DWORD>* displayDeviceIdx;
require_write_lock lock;
};
auto callback = [](HMONITOR monitor, HDC, RECT*, LPARAM data) -> BOOL {
@@ -993,27 +1019,25 @@ void FancyZones::UpdateZoneWindows() noexcept
FancyZones* fancyZones = params->fancyZones;
std::wstring deviceId = FancyZonesUtils::GetDisplayDeviceId(mi.szDevice, displayDeviceIdxMap);
fancyZones->AddZoneWindow(monitor, deviceId);
fancyZones->AddZoneWindow(monitor, deviceId, params->lock);
}
return TRUE;
};
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{
AddZoneWindow(nullptr, {});
AddZoneWindow(nullptr, {}, lock);
}
else
{
capture capture{ this, &displayDeviceIdxMap };
capture capture{ this, &displayDeviceIdxMap, lock };
EnumDisplayMonitors(nullptr, nullptr, callback, reinterpret_cast<LPARAM>(&capture));
}
}
void FancyZones::UpdateWindowsPositions() noexcept
void FancyZones::UpdateWindowsPositions(require_write_lock) noexcept
{
_TRACER_;
auto callback = [](HWND window, LPARAM data) -> BOOL {
_TRACER_;
size_t bitmask = reinterpret_cast<size_t>(::GetProp(window, ZonedWindowProperties::PropertyMultipleZoneID));
if (bitmask != 0)
@@ -1028,7 +1052,6 @@ void FancyZones::UpdateWindowsPositions() noexcept
}
auto strongThis = reinterpret_cast<FancyZones*>(data);
std::unique_lock writeLock(strongThis->m_lock);
auto zoneWindow = strongThis->m_workAreaHandler.GetWorkArea(window);
if (zoneWindow)
{
@@ -1040,39 +1063,10 @@ void FancyZones::UpdateWindowsPositions() noexcept
EnumWindows(callback, reinterpret_cast<LPARAM>(this));
}
void FancyZones::CycleActiveZoneSet(DWORD vkCode) noexcept
{
_TRACER_;
auto window = GetForegroundWindow();
if (FancyZonesUtils::IsCandidateForZoning(window, m_settings->GetSettings()->excludedAppsArray))
{
const HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
if (monitor)
{
std::shared_lock readLock(m_lock);
auto zoneWindow = m_workAreaHandler.GetWorkArea(m_currentDesktopId, monitor);
if (zoneWindow)
{
zoneWindow->CycleActiveZoneSet(vkCode);
}
}
}
}
bool FancyZones::OnSnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode) noexcept
{
_TRACER_;
HMONITOR current;
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{
current = NULL;
}
else
{
current = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
}
HMONITOR current = WorkAreaKeyFromWindow(window);
std::vector<HMONITOR> monitorInfo = GetMonitorsSorted();
if (current && monitorInfo.size() > 1 && m_settings->GetSettings()->moveWindowAcrossMonitors)
@@ -1130,16 +1124,7 @@ bool FancyZones::OnSnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode) noexce
bool FancyZones::OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept
{
HMONITOR current;
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{
current = NULL;
}
else
{
current = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
}
HMONITOR current = WorkAreaKeyFromWindow(window);
auto allMonitors = FancyZonesUtils::GetAllMonitorRects<&MONITORINFOEX::rcWork>();
@@ -1316,14 +1301,14 @@ bool FancyZones::IsSplashScreen(HWND window)
return wcscmp(NonLocalizable::SplashClassName, className) == 0;
}
void FancyZones::OnEditorExitEvent() noexcept
void FancyZones::OnEditorExitEvent(require_write_lock lock) noexcept
{
// Collect information about changes in zone layout after editor exited.
FancyZonesDataInstance().LoadFancyZonesData();
UpdateZoneSets();
UpdateZoneSets(lock);
}
void FancyZones::UpdateZoneSets() noexcept
void FancyZones::UpdateZoneSets(require_write_lock lock) noexcept
{
for (auto workArea : m_workAreaHandler.GetAllWorkAreas())
{
@@ -1331,7 +1316,7 @@ void FancyZones::UpdateZoneSets() noexcept
}
if (m_settings->GetSettings()->zoneSetChange_moveWindows)
{
UpdateWindowsPositions();
UpdateWindowsPositions(lock);
}
}
@@ -1340,15 +1325,7 @@ bool FancyZones::ShouldProcessSnapHotkey(DWORD vkCode) noexcept
auto window = GetForegroundWindow();
if (m_settings->GetSettings()->overrideSnapHotkeys && FancyZonesUtils::IsCandidateForZoning(window, m_settings->GetSettings()->excludedAppsArray))
{
HMONITOR monitor;
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{
monitor = NULL;
}
else
{
monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
}
HMONITOR monitor = WorkAreaKeyFromWindow(window);
auto zoneWindow = m_workAreaHandler.GetWorkArea(m_currentDesktopId, monitor);
if (zoneWindow && zoneWindow->ActiveZoneSet() && zoneWindow->ActiveZoneSet()->LayoutType() != FancyZonesDataTypes::ZoneSetLayoutType::Blank)
@@ -1366,6 +1343,47 @@ bool FancyZones::ShouldProcessSnapHotkey(DWORD vkCode) noexcept
return false;
}
void FancyZones::ApplyQuickLayout(int key) noexcept
{
std::unique_lock writeLock(m_lock);
std::wstring uuid;
for (auto [zoneUuid, hotkey] : FancyZonesDataInstance().GetLayoutQuickKeys())
{
if (hotkey == key)
{
uuid = zoneUuid;
}
}
auto workArea = m_workAreaHandler.GetWorkAreaFromCursor(m_currentDesktopId);
// Find a custom zone set with this uuid and apply it
auto customZoneSets = FancyZonesDataInstance().GetCustomZoneSetsMap();
if (!customZoneSets.contains(uuid))
{
return;
}
FancyZonesDataTypes::ZoneSetData data{ .uuid = uuid, .type = FancyZonesDataTypes::ZoneSetLayoutType::Custom };
FancyZonesDataInstance().SetActiveZoneSet(workArea->UniqueId(), data);
FancyZonesDataInstance().SaveZoneSettings();
UpdateZoneSets(writeLock);
FlashZones(writeLock);
}
void FancyZones::FlashZones(require_write_lock) noexcept
{
if (m_settings->GetSettings()->flashZonesOnQuickSwitch && !m_windowMoveHandler.IsDragEnabled())
{
for (auto [monitor, workArea] : m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId))
{
workArea->FlashZones();
}
}
}
std::vector<HMONITOR> FancyZones::GetMonitorsSorted() noexcept
{
std::shared_lock readLock(m_lock);
@@ -1397,6 +1415,18 @@ std::vector<std::pair<HMONITOR, RECT>> FancyZones::GetRawMonitorData() noexcept
return monitorInfo;
}
HMONITOR FancyZones::WorkAreaKeyFromWindow(HWND window) noexcept
{
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{
return NULL;
}
else
{
return MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
}
}
winrt::com_ptr<IFancyZones> MakeFancyZones(HINSTANCE hinstance,
const winrt::com_ptr<IFancyZonesSettings>& settings,
std::function<void()> disableCallback) noexcept

View File

@@ -511,10 +511,33 @@ bool FancyZonesData::SetAppLastZones(HWND window, const std::wstring& deviceId,
void FancyZonesData::SetActiveZoneSet(const std::wstring& deviceId, const FancyZonesDataTypes::ZoneSetData& data)
{
std::scoped_lock lock{ dataLock };
auto it = deviceInfoMap.find(deviceId);
if (it != deviceInfoMap.end())
auto deviceIt = deviceInfoMap.find(deviceId);
if (deviceIt == deviceInfoMap.end())
{
it->second.activeZoneSet = data;
return;
}
deviceIt->second.activeZoneSet = data;
// If the zone set is custom, we need to copy its properties to the device
auto zonesetIt = customZoneSetsMap.find(data.uuid);
if (zonesetIt != customZoneSetsMap.end())
{
if (zonesetIt->second.type == FancyZonesDataTypes::CustomLayoutType::Grid)
{
auto layoutInfo = std::get<FancyZonesDataTypes::GridLayoutInfo>(zonesetIt->second.info);
deviceIt->second.sensitivityRadius = layoutInfo.sensitivityRadius();
deviceIt->second.showSpacing = layoutInfo.showSpacing();
deviceIt->second.spacing = layoutInfo.spacing();
deviceIt->second.zoneCount = layoutInfo.zoneCount();
}
else if (zonesetIt->second.type == FancyZonesDataTypes::CustomLayoutType::Canvas)
{
auto layoutInfo = std::get<FancyZonesDataTypes::CanvasLayoutInfo>(zonesetIt->second.info);
deviceIt->second.sensitivityRadius = layoutInfo.sensitivityRadius;
deviceIt->second.zoneCount = (int)layoutInfo.zones.size();
}
}
}
@@ -536,6 +559,7 @@ void FancyZonesData::LoadFancyZonesData()
appZoneHistoryMap = JSONHelpers::ParseAppZoneHistory(fancyZonesDataJSON);
deviceInfoMap = JSONHelpers::ParseDeviceInfos(fancyZonesDataJSON);
customZoneSetsMap = JSONHelpers::ParseCustomZoneSets(fancyZonesDataJSON);
quickKeysMap = JSONHelpers::ParseQuickKeys(fancyZonesDataJSON);
}
}
@@ -549,7 +573,7 @@ void FancyZonesData::SaveZoneSettings() const
{
_TRACER_;
std::scoped_lock lock{ dataLock };
JSONHelpers::SaveZoneSettings(zonesSettingsFileName, deviceInfoMap, customZoneSetsMap);
JSONHelpers::SaveZoneSettings(zonesSettingsFileName, deviceInfoMap, customZoneSetsMap, quickKeysMap);
}
void FancyZonesData::SaveAppZoneHistory() const

View File

@@ -48,6 +48,12 @@ public:
const std::unordered_map<std::wstring, std::vector<FancyZonesDataTypes::AppZoneHistoryData>>& GetAppZoneHistoryMap() const;
inline const JSONHelpers::TLayoutQuickKeysMap& GetLayoutQuickKeys() const
{
std::scoped_lock lock{ dataLock };
return quickKeysMap;
}
inline const std::wstring& GetZonesSettingsFileName() const
{
return zonesSettingsFileName;
@@ -121,6 +127,8 @@ private:
JSONHelpers::TDeviceInfoMap deviceInfoMap{};
// Maps custom zoneset UUID to it's data
JSONHelpers::TCustomZoneSetsMap customZoneSetsMap{};
// Maps zoneset UUID with quick access keys
JSONHelpers::TLayoutQuickKeysMap quickKeysMap{};
std::wstring zonesSettingsFileName;
std::wstring appZoneHistoryFileName;

View File

@@ -112,4 +112,18 @@ namespace FancyZonesDataTypes
cellRow.resize(m_columns, 0);
}
}
int GridLayoutInfo::zoneCount() const
{
int high = 0;
for (const auto& row : m_cellChildMap)
{
for (int val : row)
{
high = max(high, val);
}
}
return high + 1;
}
}

View File

@@ -86,6 +86,8 @@ namespace FancyZonesDataTypes
inline int spacing() const { return m_spacing; }
inline int sensitivityRadius() const { return m_sensitivityRadius; }
int zoneCount() const;
int m_rows;
int m_columns;
std::vector<int> m_rowsPercents;

View File

@@ -35,6 +35,9 @@ namespace NonLocalizable
const wchar_t HistoryStr[] = L"history";
const wchar_t InfoStr[] = L"info";
const wchar_t NameStr[] = L"name";
const wchar_t QuickAccessKey[] = L"key";
const wchar_t QuickAccessUuid[] = L"uuid";
const wchar_t QuickLayoutKeys[] = L"quick-layout-keys";
const wchar_t RefHeightStr[] = L"ref-height";
const wchar_t RefWidthStr[] = L"ref-width";
const wchar_t RowsPercentageStr[] = L"rows-percentage";
@@ -471,6 +474,38 @@ namespace JSONHelpers
}
}
json::JsonObject LayoutQuickKeyJSON::ToJson(const LayoutQuickKeyJSON& layoutQuickKey)
{
json::JsonObject result{};
result.SetNamedValue(NonLocalizable::QuickAccessUuid, json::value(layoutQuickKey.layoutUuid));
result.SetNamedValue(NonLocalizable::QuickAccessKey, json::value(layoutQuickKey.key));
return result;
}
std::optional<LayoutQuickKeyJSON> LayoutQuickKeyJSON::FromJson(const json::JsonObject& layoutQuickKey)
{
try
{
LayoutQuickKeyJSON result;
result.layoutUuid = layoutQuickKey.GetNamedString(NonLocalizable::QuickAccessUuid);
if (!FancyZonesUtils::IsValidGuid(result.layoutUuid))
{
return std::nullopt;
}
result.key = static_cast<int>(layoutQuickKey.GetNamedNumber(NonLocalizable::QuickAccessKey));
return result;
}
catch (const winrt::hresult_error&)
{
return std::nullopt;
}
}
json::JsonObject MonitorInfo::ToJson(const MonitorInfo& monitor)
{
json::JsonObject result{};
@@ -527,7 +562,7 @@ namespace JSONHelpers
}
}
void SaveZoneSettings(const std::wstring& zonesSettingsFileName, const TDeviceInfoMap& deviceInfoMap, const TCustomZoneSetsMap& customZoneSetsMap)
void SaveZoneSettings(const std::wstring& zonesSettingsFileName, const TDeviceInfoMap& deviceInfoMap, const TCustomZoneSetsMap& customZoneSetsMap, const TLayoutQuickKeysMap& quickKeysMap)
{
auto before = json::from_file(zonesSettingsFileName);
@@ -549,6 +584,7 @@ namespace JSONHelpers
root.SetNamedValue(NonLocalizable::DevicesStr, JSONHelpers::SerializeDeviceInfos(deviceInfoMap));
root.SetNamedValue(NonLocalizable::CustomZoneSetsStr, JSONHelpers::SerializeCustomZoneSets(customZoneSetsMap));
root.SetNamedValue(NonLocalizable::Templates, templates);
root.SetNamedValue(NonLocalizable::QuickLayoutKeys, JSONHelpers::SerializeQuickKeys(quickKeysMap));
if (!before.has_value() || before.value().Stringify() != root.Stringify())
{
@@ -675,4 +711,40 @@ namespace JSONHelpers
return customZoneSetsJSON;
}
TLayoutQuickKeysMap ParseQuickKeys(const json::JsonObject& fancyZonesDataJSON)
{
try
{
TLayoutQuickKeysMap quickKeysMap{};
auto quickKeys = fancyZonesDataJSON.GetNamedArray(NonLocalizable::QuickLayoutKeys);
for (uint32_t i = 0; i < quickKeys.Size(); ++i)
{
if (auto quickKey = LayoutQuickKeyJSON::FromJson(quickKeys.GetObjectAt(i)); quickKey.has_value())
{
quickKeysMap[quickKey->layoutUuid] = std::move(quickKey->key);
}
}
return std::move(quickKeysMap);
}
catch (const winrt::hresult_error& e)
{
Logger::error(L"Parsing quick keys error: {}", e.message());
return {};
}
}
json::JsonArray SerializeQuickKeys(const TLayoutQuickKeysMap& quickKeysMap)
{
json::JsonArray quickKeysJSON{};
for (const auto& [uuid, key] : quickKeysMap)
{
quickKeysJSON.Append(LayoutQuickKeyJSON::ToJson(LayoutQuickKeyJSON{ uuid, key }));
}
return quickKeysJSON;
}
}

View File

@@ -55,9 +55,19 @@ namespace JSONHelpers
static std::optional<DeviceInfoJSON> FromJson(const json::JsonObject& device);
};
struct LayoutQuickKeyJSON
{
std::wstring layoutUuid;
int key;
static json::JsonObject ToJson(const LayoutQuickKeyJSON& device);
static std::optional<LayoutQuickKeyJSON> FromJson(const json::JsonObject& device);
};
using TAppZoneHistoryMap = std::unordered_map<std::wstring, std::vector<FancyZonesDataTypes::AppZoneHistoryData>>;
using TDeviceInfoMap = std::unordered_map<std::wstring, FancyZonesDataTypes::DeviceInfoData>;
using TCustomZoneSetsMap = std::unordered_map<std::wstring, FancyZonesDataTypes::CustomZoneSetData>;
using TLayoutQuickKeysMap = std::unordered_map<std::wstring, int>;
struct MonitorInfo
{
@@ -81,7 +91,7 @@ namespace JSONHelpers
json::JsonObject GetPersistFancyZonesJSON(const std::wstring& zonesSettingsFileName, const std::wstring& appZoneHistoryFileName);
void SaveZoneSettings(const std::wstring& zonesSettingsFileName, const TDeviceInfoMap& deviceInfoMap, const TCustomZoneSetsMap& customZoneSetsMap);
void SaveZoneSettings(const std::wstring& zonesSettingsFileName, const TDeviceInfoMap& deviceInfoMap, const TCustomZoneSetsMap& customZoneSetsMap, const TLayoutQuickKeysMap& quickKeysMap);
void SaveAppZoneHistory(const std::wstring& appZoneHistoryFileName, const TAppZoneHistoryMap& appZoneHistoryMap);
TAppZoneHistoryMap ParseAppZoneHistory(const json::JsonObject& fancyZonesDataJSON);
@@ -92,4 +102,7 @@ namespace JSONHelpers
TCustomZoneSetsMap ParseCustomZoneSets(const json::JsonObject& fancyZonesDataJSON);
json::JsonArray SerializeCustomZoneSets(const TCustomZoneSetsMap& customZoneSetsMap);
TLayoutQuickKeysMap ParseQuickKeys(const json::JsonObject& fancyZonesDataJSON);
json::JsonArray SerializeQuickKeys(const TLayoutQuickKeysMap& quickKeysMap);
}

View File

@@ -17,6 +17,27 @@ winrt::com_ptr<IZoneWindow> MonitorWorkAreaHandler::GetWorkArea(const GUID& desk
return nullptr;
}
winrt::com_ptr<IZoneWindow> MonitorWorkAreaHandler::GetWorkAreaFromCursor(const GUID& desktopId)
{
auto allMonitorsWorkArea = GetWorkArea(desktopId, NULL);
if (allMonitorsWorkArea)
{
// First, check if there's a work area spanning all monitors (signalled by the NULL monitor handle)
return allMonitorsWorkArea;
}
else
{
// Otherwise, look for the work area based on cursor position
POINT cursorPoint;
if (!GetCursorPos(&cursorPoint))
{
return nullptr;
}
return GetWorkArea(desktopId, MonitorFromPoint(cursorPoint, MONITOR_DEFAULTTONULL));
}
}
winrt::com_ptr<IZoneWindow> MonitorWorkAreaHandler::GetWorkArea(HWND window)
{
GUID desktopId{};

View File

@@ -29,6 +29,16 @@ public:
*/
winrt::com_ptr<IZoneWindow> GetWorkArea(const GUID& desktopId, HMONITOR monitor);
/**
* Get work area based on virtual desktop id and the current cursor position.
*
* @param[in] desktopId Virtual desktop identifier.
*
* @returns Object representing single work area, interface to all actions available on work area
* (e.g. moving windows through zone layout specified for that work area).
*/
winrt::com_ptr<IZoneWindow> GetWorkAreaFromCursor(const GUID& desktopId);
/**
* Get work area on which specified window is located.
*

View File

@@ -247,4 +247,10 @@
<value>Failed to save the FancyZones settings. Please retry again later, if the problem persists report the bug to</value>
<comment>"Report bug to" will have a URL after. FancyZone is a product name, keep as is.</comment>
</data>
<data name="Setting_Description_QuickLayoutSwitch" xml:space="preserve">
<value>Enable quick layout switch</value>
</data>
<data name="Setting_Description_FlashZonesOnQuickSwitch" xml:space="preserve">
<value>Flash zones when switching layout</value>
</data>
</root>

View File

@@ -21,6 +21,8 @@ namespace NonLocalizable
const wchar_t AppLastZoneMoveWindowsID[] = L"fancyzones_appLastZone_moveWindows";
const wchar_t OpenWindowOnActiveMonitorID[] = L"fancyzones_openWindowOnActiveMonitor";
const wchar_t RestoreSizeID[] = L"fancyzones_restoreSize";
const wchar_t QuickLayoutSwitch[] = L"fancyzones_quickLayoutSwitch";
const wchar_t FlashZonesOnQuickSwitch[] = L"fancyzones_flashZonesOnQuickSwitch";
const wchar_t UseCursorPosEditorStartupScreenID[] = L"use_cursorpos_editor_startupscreen";
const wchar_t ShowOnAllMonitorsID[] = L"fancyzones_show_on_all_monitors";
const wchar_t SpanZonesAcrossMonitorsID[] = L"fancyzones_span_zones_across_monitors";
@@ -80,7 +82,7 @@ private:
PCWSTR name;
bool* value;
int resourceId;
} m_configBools[14] = {
} m_configBools[16] = {
{ NonLocalizable::ShiftDragID, &m_settings.shiftDrag, IDS_SETTING_DESCRIPTION_SHIFTDRAG },
{ NonLocalizable::MouseSwitchID, &m_settings.mouseSwitch, IDS_SETTING_DESCRIPTION_MOUSESWITCH },
{ NonLocalizable::OverrideSnapHotKeysID, &m_settings.overrideSnapHotkeys, IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS },
@@ -91,6 +93,8 @@ private:
{ NonLocalizable::AppLastZoneMoveWindowsID, &m_settings.appLastZone_moveWindows, IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS },
{ NonLocalizable::OpenWindowOnActiveMonitorID, &m_settings.openWindowOnActiveMonitor, IDS_SETTING_DESCRIPTION_OPEN_WINDOW_ON_ACTIVE_MONITOR },
{ NonLocalizable::RestoreSizeID, &m_settings.restoreSize, IDS_SETTING_DESCRIPTION_RESTORESIZE },
{ NonLocalizable::QuickLayoutSwitch, &m_settings.quickLayoutSwitch, IDS_SETTING_DESCRIPTION_QUICKLAYOUTSWITCH },
{ NonLocalizable::FlashZonesOnQuickSwitch, &m_settings.flashZonesOnQuickSwitch, IDS_SETTING_DESCRIPTION_FLASHZONESONQUICKSWITCH },
{ NonLocalizable::UseCursorPosEditorStartupScreenID, &m_settings.use_cursorpos_editor_startupscreen, IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN },
{ NonLocalizable::ShowOnAllMonitorsID, &m_settings.showZonesOnAllMonitors, IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS },
{ NonLocalizable::SpanZonesAcrossMonitorsID, &m_settings.spanZonesAcrossMonitors, IDS_SETTING_DESCRIPTION_SPAN_ZONES_ACROSS_MONITORS },

View File

@@ -34,6 +34,8 @@ struct Settings
bool appLastZone_moveWindows = false;
bool openWindowOnActiveMonitor = false;
bool restoreSize = false;
bool quickLayoutSwitch = true;
bool flashZonesOnQuickSwitch = true;
bool use_cursorpos_editor_startupscreen = true;
bool showZonesOnAllMonitors = false;
bool spanZonesAcrossMonitors = false;

View File

@@ -124,8 +124,6 @@ public:
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)
UniqueId() noexcept { return { m_uniqueId }; }
IFACEMETHODIMP_(void)
@@ -140,6 +138,8 @@ public:
UpdateActiveZoneSet() noexcept;
IFACEMETHODIMP_(void)
ClearSelectedZones() noexcept;
IFACEMETHODIMP_(void)
FlashZones() noexcept;
protected:
static LRESULT CALLBACK s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept;
@@ -149,9 +149,8 @@ private:
void CalculateZoneSet() noexcept;
void UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept;
LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept;
void OnKeyUp(WPARAM wparam) noexcept;
std::vector<size_t> ZonesFromPoint(POINT pt) noexcept;
void CycleActiveZoneSetInternal(DWORD wparam, Trace::ZoneWindow::InputMode mode) noexcept;
void SetAsTopmostWindow() noexcept;
winrt::com_ptr<IZoneWindowHost> m_host;
HMONITOR m_monitor{};
@@ -165,7 +164,7 @@ private:
WPARAM m_keyLast{};
size_t m_keyCycle{};
static const UINT m_showAnimationDuration = 200; // ms
static const UINT m_flashDuration = 700; // ms
static const UINT m_flashDuration = 1000; // ms
std::unique_ptr<ZoneWindowDrawing> m_zoneWindowDrawing;
};
@@ -359,17 +358,6 @@ ZoneWindow::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noexce
return false;
}
IFACEMETHODIMP_(void)
ZoneWindow::CycleActiveZoneSet(DWORD wparam) noexcept
{
CycleActiveZoneSetInternal(wparam, Trace::ZoneWindow::InputMode::Keyboard);
if (m_windowMoveSize)
{
InvalidateRect(m_window, nullptr, true);
}
}
IFACEMETHODIMP_(void)
ZoneWindow::SaveWindowProcessToZoneIndex(HWND window) noexcept
{
@@ -392,23 +380,12 @@ ZoneWindow::SaveWindowProcessToZoneIndex(HWND window) noexcept
IFACEMETHODIMP_(void)
ZoneWindow::ShowZoneWindow() noexcept
{
auto window = m_window;
if (!window)
if (m_window)
{
return;
SetAsTopmostWindow();
m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host);
m_zoneWindowDrawing->Show(m_showAnimationDuration);
}
UINT flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE;
HWND windowInsertAfter = m_windowMoveSize;
if (windowInsertAfter == nullptr)
{
windowInsertAfter = HWND_TOPMOST;
}
SetWindowPos(window, windowInsertAfter, 0, 0, 0, 0, flags);
m_zoneWindowDrawing->Show(m_showAnimationDuration);
m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host);
}
IFACEMETHODIMP_(void)
@@ -427,6 +404,10 @@ IFACEMETHODIMP_(void)
ZoneWindow::UpdateActiveZoneSet() noexcept
{
CalculateZoneSet();
if (m_window)
{
m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host);
}
}
IFACEMETHODIMP_(void)
@@ -439,6 +420,17 @@ ZoneWindow::ClearSelectedZones() noexcept
}
}
IFACEMETHODIMP_(void)
ZoneWindow::FlashZones() noexcept
{
if (m_window)
{
SetAsTopmostWindow();
m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), {}, m_host);
m_zoneWindowDrawing->Flash(m_flashDuration);
}
}
#pragma region private
void ZoneWindow::InitializeZoneSets(const std::wstring& parentUniqueId) noexcept
@@ -541,12 +533,6 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
case WM_ERASEBKGND:
return 1;
case WM_PAINT:
{
m_zoneWindowDrawing->ForceRender();
break;
}
default:
{
return DefWindowProc(m_window, message, wparam, lparam);
@@ -555,18 +541,6 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
return 0;
}
void ZoneWindow::OnKeyUp(WPARAM wparam) noexcept
{
bool fRedraw = false;
Trace::ZoneWindow::KeyUp(wparam);
if ((wparam >= '0') && (wparam <= '9'))
{
CycleActiveZoneSetInternal(static_cast<DWORD>(wparam), Trace::ZoneWindow::InputMode::Keyboard);
m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host);
}
}
std::vector<size_t> ZoneWindow::ZonesFromPoint(POINT pt) noexcept
{
if (m_activeZoneSet)
@@ -576,52 +550,22 @@ std::vector<size_t> ZoneWindow::ZonesFromPoint(POINT pt) noexcept
return {};
}
void ZoneWindow::CycleActiveZoneSetInternal(DWORD wparam, Trace::ZoneWindow::InputMode mode) noexcept
void ZoneWindow::SetAsTopmostWindow() noexcept
{
Trace::ZoneWindow::CycleActiveZoneSet(m_activeZoneSet, mode);
if (m_keyLast != wparam)
if (!m_window)
{
m_keyCycle = 0;
return;
}
m_keyLast = wparam;
UINT flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE;
bool loopAround = true;
size_t const val = static_cast<size_t>(wparam - L'0');
size_t i = 0;
for (auto zoneSet : m_zoneSets)
HWND windowInsertAfter = m_windowMoveSize;
if (windowInsertAfter == nullptr)
{
if (zoneSet->GetZones().size() == val)
{
if (i < m_keyCycle)
{
i++;
}
else
{
UpdateActiveZoneSet(zoneSet.get());
loopAround = false;
break;
}
}
windowInsertAfter = HWND_TOPMOST;
}
if ((m_keyCycle > 0) && loopAround)
{
// Cycling through a non-empty group and hit the end
m_keyCycle = 0;
OnKeyUp(wparam);
}
else
{
m_keyCycle++;
}
if (m_host)
{
m_host->MoveWindowsOnActiveZoneSetChange();
}
m_highlightZone = {};
SetWindowPos(m_window, windowInsertAfter, 0, 0, 0, 0, flags);
}
#pragma endregion

View File

@@ -86,13 +86,6 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow
* zones available in the given direction.
*/
IFACEMETHOD_(bool, ExtendWindowByDirectionAndPosition)(HWND window, DWORD vkCode) = 0;
/**
* Cycle through active zone layouts (giving hints about each layout).
*
* @param vkCode Pressed key representing layout index.
*/
IFACEMETHOD_(void, CycleActiveZoneSet)(DWORD vkCode) = 0;
/**
* Save information about zone in which window was assigned, when closing the window.
* Used once we open same window again to assign it to its previous zone.
@@ -118,6 +111,10 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow
* Clear the selected zones when this ZoneWindow loses focus.
*/
IFACEMETHOD_(void, ClearSelectedZones)() = 0;
/*
* Display the layout on the screen and then hide it.
*/
IFACEMETHOD_(void, FlashZones)() = 0;
};
winrt::com_ptr<IZoneWindow> MakeZoneWindow(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor,

View File

@@ -19,18 +19,21 @@ float ZoneWindowDrawing::GetAnimationAlpha()
// Lock is being held
if (!m_animation)
{
return 1.f;
return 0.f;
}
auto tNow = std::chrono::steady_clock().now();
auto alpha = (tNow - m_animation->tStart).count() / (1e6f * m_animation->duration);
if (alpha < 1.f)
if (m_animation->fadeIn)
{
return alpha;
// Return a positive value to avoid hiding
return std::clamp(alpha, 0.001f, 1.f);
}
else
{
return 1.f;
// Quadratic function looks better
return std::clamp(1.f - alpha * alpha, 0.f, 1.f);
}
}
@@ -100,28 +103,7 @@ ZoneWindowDrawing::ZoneWindowDrawing(HWND window)
return;
}
m_renderThread = std::thread([this]() {
while (!m_abortThread)
{
// Force repeated rendering while in the animation loop.
// Yield if low latency locking was requested
if (!m_lowLatencyLock)
{
float animationAlpha;
{
std::unique_lock lock(m_mutex);
animationAlpha = GetAnimationAlpha();
}
if (animationAlpha < 1.f)
{
m_shouldRender = true;
}
}
Render();
}
});
m_renderThread = std::thread([this]() { RenderLoop(); });
}
void ZoneWindowDrawing::Render()
@@ -133,11 +115,14 @@ void ZoneWindowDrawing::Render()
return;
}
m_cv.wait(lock, [this]() { return (bool)m_shouldRender; });
float animationAlpha = GetAnimationAlpha();
if (animationAlpha <= 0.f)
{
return;
}
m_renderTarget->BeginDraw();
float animationAlpha = GetAnimationAlpha();
// Draw backdrop
m_renderTarget->Clear(D2D1::ColorF(0.f, 0.f, 0.f, 0.f));
@@ -197,20 +182,49 @@ void ZoneWindowDrawing::Render()
textBrush->Release();
}
// The lock must be released here, as EndDraw() will wait for vertical sync
lock.unlock();
m_renderTarget->EndDraw();
m_shouldRender = false;
}
void ZoneWindowDrawing::RenderLoop()
{
while (!m_abortThread)
{
float animationAlpha;
{
// The lock must be held by the caller when calling GetAnimationAlpha
std::unique_lock lock(m_mutex);
animationAlpha = GetAnimationAlpha();
}
// Check whether the animation expired and we need to hide the window
if (animationAlpha <= 0.f)
{
Hide();
}
{
// Wait here while rendering is disabled
std::unique_lock lock(m_mutex);
m_cv.wait(lock, [this]() { return (bool)m_shouldRender; });
}
Render();
}
}
void ZoneWindowDrawing::Hide()
{
_TRACER_;
m_lowLatencyLock = true;
std::unique_lock lock(m_mutex);
m_lowLatencyLock = false;
if (m_animation)
m_animation.reset();
if (m_shouldRender)
{
m_animation.reset();
m_shouldRender = false;
ShowWindow(m_window, SW_HIDE);
}
}
@@ -218,20 +232,40 @@ void ZoneWindowDrawing::Hide()
void ZoneWindowDrawing::Show(unsigned animationMillis)
{
_TRACER_;
m_lowLatencyLock = true;
std::unique_lock lock(m_mutex);
m_lowLatencyLock = false;
if (!m_animation)
if (!m_shouldRender)
{
ShowWindow(m_window, SW_SHOWNA);
if (animationMillis > 0)
{
m_animation.emplace(AnimationInfo{ std::chrono::steady_clock().now(), animationMillis });
}
m_shouldRender = true;
m_cv.notify_all();
}
animationMillis = max(animationMillis, 1);
if (!m_animation || !m_animation->fadeIn)
{
m_animation.emplace(AnimationInfo{ std::chrono::steady_clock().now(), animationMillis, true });
}
m_shouldRender = true;
m_cv.notify_all();
}
void ZoneWindowDrawing::Flash(unsigned animationMillis)
{
_TRACER_;
std::unique_lock lock(m_mutex);
if (!m_shouldRender)
{
ShowWindow(m_window, SW_SHOWNA);
}
animationMillis = max(animationMillis, 1);
m_animation.emplace(AnimationInfo{ std::chrono::steady_clock().now(), animationMillis, false });
m_shouldRender = true;
m_cv.notify_all();
}
void ZoneWindowDrawing::DrawActiveZoneSet(const IZoneSet::ZonesMap& zones,
@@ -239,9 +273,7 @@ void ZoneWindowDrawing::DrawActiveZoneSet(const IZoneSet::ZonesMap& zones,
winrt::com_ptr<IZoneWindowHost> host)
{
_TRACER_;
m_lowLatencyLock = true;
std::unique_lock lock(m_mutex);
m_lowLatencyLock = false;
m_sceneRects = {};
@@ -299,18 +331,6 @@ void ZoneWindowDrawing::DrawActiveZoneSet(const IZoneSet::ZonesMap& zones,
m_sceneRects.push_back(drawableRect);
}
}
m_shouldRender = true;
m_cv.notify_all();
}
void ZoneWindowDrawing::ForceRender()
{
m_lowLatencyLock = true;
std::unique_lock lock(m_mutex);
m_lowLatencyLock = false;
m_shouldRender = true;
m_cv.notify_all();
}
ZoneWindowDrawing::~ZoneWindowDrawing()

View File

@@ -26,6 +26,7 @@ class ZoneWindowDrawing
{
std::chrono::steady_clock::time_point tStart;
unsigned duration;
bool fadeIn;
};
HWND m_window = nullptr;
@@ -42,10 +43,10 @@ class ZoneWindowDrawing
static D2D1_COLOR_F ConvertColor(COLORREF color);
static D2D1_RECT_F ConvertRect(RECT rect);
void Render();
void RenderLoop();
std::atomic<bool> m_shouldRender = false;
std::atomic<bool> m_abortThread = false;
std::atomic<bool> m_lowLatencyLock = false;
std::condition_variable m_cv;
std::thread m_renderThread;
@@ -55,7 +56,7 @@ public:
ZoneWindowDrawing(HWND window);
void Hide();
void Show(unsigned animationMillis);
void ForceRender();
void Flash(unsigned animationMillis);
void DrawActiveZoneSet(const IZoneSet::ZonesMap& zones,
const std::vector<size_t>& highlightZones,
winrt::com_ptr<IZoneWindowHost> host);

View File

@@ -17,6 +17,7 @@
#define EventZoneWindowKeyUpKey "FancyZones_ZoneWindowKeyUp"
#define EventMoveSizeEndKey "FancyZones_MoveSizeEnd"
#define EventCycleActiveZoneSetKey "FancyZones_CycleActiveZoneSet"
#define EventQuickLayoutSwitchKey "FancyZones_QuickLayoutSwitch"
#define EventEnabledKey "Enabled"
#define PressedKeyCodeKey "Hotkey"
@@ -25,6 +26,7 @@
#define MoveSizeActionKey "InMoveSize"
#define AppsInHistoryCountKey "AppsInHistoryCount"
#define CustomZoneSetCountKey "CustomZoneSetCount"
#define LayoutUsingQuickKeyCountKey "LayoutUsingQuickKeyCount"
#define NumberOfZonesForEachCustomZoneSetKey "NumberOfZonesForEachCustomZoneSet"
#define ActiveZoneSetsCountKey "ActiveZoneSetsCount"
#define ActiveZoneSetsListKey "ActiveZoneSetsList"
@@ -40,6 +42,8 @@
#define MoveWindowsToLastZoneOnAppOpeningKey "MoveWindowsToLastZoneOnAppOpening"
#define OpenWindowOnActiveMonitorKey "OpenWindowOnActiveMonitor"
#define RestoreSizeKey "RestoreSize"
#define QuickLayoutSwitchKey "QuickLayoutSwitch"
#define FlashZonesOnQuickSwitchKey "FlashZonesOnQuickSwitch"
#define UseCursorPosOnEditorStartupKey "UseCursorPosOnEditorStartup"
#define ShowZonesOnAllMonitorsKey "ShowZonesOnAllMonitors"
#define SpanZonesAcrossMonitorsKey "SpanZonesAcrossMonitors"
@@ -56,6 +60,7 @@
#define NumberOfWindowsKey "NumberOfWindows"
#define InputModeKey "InputMode"
#define OverlappingZonesAlgorithmKey "OverlappingZonesAlgorithm"
#define QuickLayoutSwitchedWithShortcutUsed "ShortcutUsed"
TRACELOGGING_DEFINE_PROVIDER(
g_hProvider,
@@ -128,6 +133,7 @@ void Trace::FancyZones::DataChanged() noexcept
int appsHistorySize = static_cast<int>(data.GetAppZoneHistoryMap().size());
const auto& customZones = data.GetCustomZoneSetsMap();
const auto& devices = data.GetDeviceInfoMap();
const auto& quickKeys = data.GetLayoutQuickKeys();
std::unique_ptr<INT32[]> customZonesArray(new (std::nothrow) INT32[customZones.size()]);
if (!customZonesArray)
@@ -149,7 +155,7 @@ void Trace::FancyZones::DataChanged() noexcept
return 0;
};
//NumberOfZonesForEachCustomZoneSet
// NumberOfZonesForEachCustomZoneSet
int i = 0;
for (const auto& [id, customZoneSetData] : customZones)
{
@@ -157,7 +163,7 @@ void Trace::FancyZones::DataChanged() noexcept
i++;
}
//ActiveZoneSetsList
// ActiveZoneSetsList
std::wstring activeZoneSetInfo;
for (const auto& [id, device] : devices)
{
@@ -201,7 +207,8 @@ void Trace::FancyZones::DataChanged() noexcept
TraceLoggingInt32(static_cast<int>(customZones.size()), CustomZoneSetCountKey),
TraceLoggingInt32Array(customZonesArray.get(), static_cast<int>(customZones.size()), NumberOfZonesForEachCustomZoneSetKey),
TraceLoggingInt32(static_cast<int>(devices.size()), ActiveZoneSetsCountKey),
TraceLoggingWideString(activeZoneSetInfo.c_str(), ActiveZoneSetsListKey));
TraceLoggingWideString(activeZoneSetInfo.c_str(), ActiveZoneSetsListKey),
TraceLoggingInt32(static_cast<int>(quickKeys.size()), LayoutUsingQuickKeyCountKey));
}
void Trace::FancyZones::EditorLaunched(int value) noexcept
@@ -227,6 +234,16 @@ void Trace::FancyZones::Error(const DWORD errorCode, std::wstring errorMessage,
TraceLoggingValue(errorMessage.c_str(), "ErrorMessage"));
}
void Trace::FancyZones::QuickLayoutSwitched(bool shortcutUsed) noexcept
{
TraceLoggingWrite(
g_hProvider,
EventQuickLayoutSwitchKey,
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
TraceLoggingBoolean(shortcutUsed, QuickLayoutSwitchedWithShortcutUsed));
}
void Trace::SettingsChanged(const Settings& settings) noexcept
{
const auto& editorHotkey = settings.editorHotkey;
@@ -253,6 +270,8 @@ void Trace::SettingsChanged(const Settings& settings) noexcept
TraceLoggingBoolean(settings.appLastZone_moveWindows, MoveWindowsToLastZoneOnAppOpeningKey),
TraceLoggingBoolean(settings.openWindowOnActiveMonitor, OpenWindowOnActiveMonitorKey),
TraceLoggingBoolean(settings.restoreSize, RestoreSizeKey),
TraceLoggingBoolean(settings.quickLayoutSwitch, QuickLayoutSwitchKey),
TraceLoggingBoolean(settings.flashZonesOnQuickSwitch, FlashZonesOnQuickSwitchKey),
TraceLoggingBoolean(settings.use_cursorpos_editor_startupscreen, UseCursorPosOnEditorStartupKey),
TraceLoggingBoolean(settings.showZonesOnAllMonitors, ShowZonesOnAllMonitorsKey),
TraceLoggingBoolean(settings.spanZonesAcrossMonitors, SpanZonesAcrossMonitorsKey),

View File

@@ -17,6 +17,7 @@ public:
static void DataChanged() noexcept;
static void EditorLaunched(int value) noexcept;
static void Error(const DWORD errorCode, std::wstring errorMessage, std::wstring methodName) noexcept;
static void QuickLayoutSwitched(bool shortcutUsed) noexcept;
};
static void SettingsChanged(const Settings& settings) noexcept;