FancyZones and Shortcut Guide initial commit

Co-authored-by: Alexis Campailla <alexis@janeasystems.com>
Co-authored-by: Bret Anderson <bretan@microsoft.com>
Co-authored-by: Enrico Giordani <enrico.giordani@gmail.com>
Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
Co-authored-by: Jeff Bogdan <jeffbog@microsoft.com>
Co-authored-by: March Rogers <marchr@microsoft.com>
Co-authored-by: Mike Harsh <mharsh@microsoft.com>
Co-authored-by: Nachum Bundak <Nachum.Bundak@microsoft.com>
Co-authored-by: Oliver Jones <ojones@microsoft.com>
Co-authored-by: Patrick Little <plittle@microsoft.com>
This commit is contained in:
Bartosz Sosnowski
2019-09-04 18:26:26 +02:00
committed by Bartosz Sosnowski
parent 10c5396099
commit 8431b80e48
341 changed files with 54766 additions and 62 deletions

View File

@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{48804216-2A0E-4168-A6D8-9CD068D14227}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>fancyzones</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>fancyzones</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.190716.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.190716.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;FANCYZONES_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\;..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalDependencies>gdiplus.lib;dwmapi.lib;shlwapi.lib;uxtheme.lib;shcore.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>fancyzones.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;FANCYZONES_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\;..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalDependencies>gdiplus.lib;dwmapi.lib;shlwapi.lib;uxtheme.lib;shcore.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>fancyzones.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">pch.h</PrecompiledHeaderFile>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\common.vcxproj">
<Project>{74485049-c722-400f-abe5-86ac52d929b3}</Project>
</ProjectReference>
<ProjectReference Include="..\lib\FancyZonesLib.vcxproj">
<Project>{f9c68edf-ac74-4b77-9af1-005d9c9f6a99}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="fancyzones.def" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\lib\fancyzones.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.190716.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.190716.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="dllmain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{21926bf1-03b3-482d-8f60-8bc4fbfc6564}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{2f10207d-d8d1-4a42-8027-8ca597b3cb23}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="fancyzones.def" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\lib\fancyzones.rc" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,53 @@
# Introduction
Super FancyZones! Just like FancyZones except super.
# Getting Started
Grab FancyZones.exe from the bin directory or \\\\wexfs\users\bretan\proto\superfancyzones and run it
## Dragging windows
* While dragging a window around, zones will appear that the window can be dropped in. Dropping the window in a zone will position it in the zone.
* While dragging a window, you can hit number keys to cycle the active zone set. Eg, drag a window around and hit the '3' key will change to a zone set with 3 zones.
## Hotkeys
* Win+~ - opens the zone viewer/editor
* Win+ctrl+number - cycle through layouts with the corresponding number of zones (only if Override snap hotkeys setting is enabled)
* Win+left arrow, Win+right arrow - move foreground window between zones
## Zone Viewer/Editor (Win + ~)
* Hitting a number key cycles through layouts matching the number of zones (eg 3 cycles through layouts with 3 zones)
* R resets the focused monitor back to defaults
* C clears the current layout so you can start fresh
* W opens a dialog to choose wallpaper
* Left click moves the zone to the top
* Right click moves the zone to the bottom
### E enters editor mode (hit E or Escape to exit editor mode)
* Left/Right/Up/Down arrows adjust the grid spacing
* PgUp/PgDn adjust grid margins
* Ctrl+left click splits the clicked zone in half horizontally
* Ctrl+right click splits the clicked zone in half vertically
# Options
### Default Drag Mode
* None - don't do anything when dragging windows around (shift enters normal mode, ctrl enters adjusted mode)
* Normal - show zones when dragging windows around (shift disables, ctrl enters adjusted mode)
* Adjusted - show zones when dragging windows around with an accelerated cursor
### Display change
* Move windows - automatically move windows around when display changes
### Virtual Desktop change
* Move windows - automatically move windows around when virtual desktop changes
* Change wallpaper - use custom wallpaper per-monitor per-desktop
* Flash zones - flash zones on each monitor
### Miscellanious
* Override snap hotkeys - steal hotkeys normally used by shell (win+left/right, win+ctrl+num)
* Colorful zones - use colored zones in zone viewer
# Known issues
* See open bugs for full list of issues
* Win+left and Win+right don't move between monitors
* If you use Virtual Desktops, make sure to perform at least one virtual desktop switch before launching the fancyzones (it relies on a volatile regkey that explorer writes)
* Sometimes you have to click on a zone viewer window before it gets keyboard focus when opening views with Win+~
* Quickly switching virtual desktops with win+ctrl+arrow hotkeys can crash fancyzones

View File

@@ -0,0 +1,319 @@
#include "pch.h"
#include <common/settings_objects.h>
#include <interface/powertoy_module_interface.h>
#include <interface/lowlevel_keyboard_event_data.h>
#include <interface/win_hook_event_data.h>
#include <lib/ZoneSet.h>
#include <lib/RegistryHelpers.h>
extern "C" IMAGE_DOS_HEADER __ImageBase;
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
Trace::RegisterProvider();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
Trace::UnregisterProvider();
break;
}
return TRUE;
}
// TODO: multimon support, need to pass the HMONITOR from the editor to here instead
// of using MonitorFromPoint
// This function is exported and called from FancyZonesEditor.exe to save a layout from the editor.
STDAPI PersistZoneSet(
PCWSTR activeKey, // Registry key holding ActiveZoneSet
PCWSTR resolutionKey, // Registry key for screen resolution
WORD layoutId, // LayoutModel Id
int zoneCount, // Number of zones in zones
int zones[]) // Array of zones serialized in left/top/right/bottom chunks
{
// See if we have already persisted this layout we can update.
UUID id{GUID_NULL};
if (wil::unique_hkey key{ RegistryHelpers::OpenKey(resolutionKey) })
{
ZoneSetPersistedData data{};
DWORD dataSize = sizeof(data);
wchar_t value[256]{};
DWORD valueLength = ARRAYSIZE(value);
DWORD i = 0;
while (RegEnumValueW(key.get(), i++, value, &valueLength, nullptr, nullptr, reinterpret_cast<BYTE*>(&data), &dataSize) == ERROR_SUCCESS)
{
if (data.LayoutId == layoutId)
{
if (data.ZoneCount == zoneCount)
{
CLSIDFromString(value, &id);
break;
}
}
valueLength = ARRAYSIZE(value);
dataSize = sizeof(data);
}
}
if (id == GUID_NULL)
{
// No existing layout found so let's create a new one.
UuidCreate(&id);
}
if (id != GUID_NULL)
{
winrt::com_ptr<IZoneSet> zoneSet = MakeZoneSet(
ZoneSetConfig(
id,
layoutId,
MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY),
resolutionKey,
ZoneSetLayout::Custom,
0, 0, 0));
for (int i = 0; i < zoneCount; i++)
{
const int baseIndex = i * 4;
const int left = zones[baseIndex];
const int top = zones[baseIndex+1];
const int right = zones[baseIndex+2];
const int bottom = zones[baseIndex+3];
zoneSet->AddZone(MakeZone({ left, top, right, bottom }), false);
}
zoneSet->Save();
wil::unique_cotaskmem_string zoneSetId;
if (SUCCEEDED_LOG(StringFromCLSID(id, &zoneSetId)))
{
RegistryHelpers::SetString(activeKey, L"ActiveZoneSetId", zoneSetId.get());
}
return S_OK;
}
return E_FAIL;
}
class FancyZonesModule : public PowertoyModuleIface
{
public:
// Return the display name of the powertoy, this will be cached
virtual PCWSTR get_name() override
{
return L"FancyZones";
}
// Return array of the names of all events that this powertoy listens for, with
// nullptr as the last element of the array. Nullptr can also be retured for empty list.
virtual PCWSTR* get_events() override
{
static PCWSTR events[] = { ll_keyboard, win_hook_event, nullptr };
return events;
}
// Return JSON with the configuration options.
// These are the settings shown on the settings page along with their current values.
virtual bool get_config(_Out_ PWSTR buffer, _Out_ int *buffer_size) override
{
return m_settings->GetConfig(buffer, buffer_size);
}
// Passes JSON with the configuration settings for the powertoy.
// This is called when the user hits Save on the settings page.
virtual void set_config(PCWSTR config) override
{
m_settings->SetConfig(config);
}
// Signal from the Settings editor to call a custom action.
// This can be used to spawn more complex editors.
virtual void call_custom_action(const wchar_t* action) override
{
m_settings->CallCustomAction(action);
}
// Enable the powertoy
virtual void enable()
{
if (!m_app)
{
Trace::FancyZones::EnableFancyZones(true);
m_app = MakeFancyZones(reinterpret_cast<HINSTANCE>(&__ImageBase), m_settings.get());
if (m_app)
{
m_app->Run();
}
}
}
// Disable the powertoy
virtual void disable()
{
if (m_app)
{
Trace::FancyZones::EnableFancyZones(false);
m_app->Destroy();
m_app = nullptr;
}
}
// Returns if the powertoy is enabled
virtual bool is_enabled() override
{
return (m_app != nullptr);
}
// Handle incoming event, data is event-specific
virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override
{
if (m_app)
{
if (wcscmp(name, ll_keyboard) == 0)
{
// Return 1 if the keypress is to be suppressed (not forwarded to Windows), otherwise return 0.
return HandleKeyboardHookEvent(reinterpret_cast<LowlevelKeyboardEvent*>(data));
}
else if (wcscmp(name, win_hook_event) == 0)
{
// Return value is ignored
HandleWinHookEvent(reinterpret_cast<WinHookEvent*>(data));
}
}
return 0;
}
// Destroy the powertoy and free memory
virtual void destroy() override
{
disable();
delete this;
}
FancyZonesModule()
{
m_settings = MakeFancyZonesSettings(reinterpret_cast<HINSTANCE>(&__ImageBase), get_name());
}
private:
static bool IsInterestingWindow(HWND window)
{
auto style = GetWindowLongPtr(window, GWL_STYLE);
auto exStyle = GetWindowLongPtr(window, GWL_EXSTYLE);
return WI_IsFlagSet(style, WS_MAXIMIZEBOX) && WI_IsFlagClear(style, WS_CHILD) && WI_IsFlagClear(exStyle, WS_EX_TOOLWINDOW);
}
intptr_t HandleKeyboardHookEvent(LowlevelKeyboardEvent* data) noexcept;
void HandleWinHookEvent(WinHookEvent* data) noexcept;
void MoveSizeStart(HWND window, POINT const& ptScreen) noexcept;
void MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept;
void MoveSizeUpdate(POINT const& ptScreen) noexcept;
winrt::com_ptr<IFancyZones> m_app;
winrt::com_ptr<IFancyZonesSettings> m_settings;
};
intptr_t FancyZonesModule::HandleKeyboardHookEvent(LowlevelKeyboardEvent* data) noexcept
{
if (data->wParam == WM_KEYDOWN)
{
return m_app.as<IFancyZonesCallback>()->OnKeyDown(data->lParam) ? 1 : 0;
}
return 0;
}
void FancyZonesModule::HandleWinHookEvent(WinHookEvent* data) noexcept
{
POINT ptScreen;
GetPhysicalCursorPos(&ptScreen);
switch (data->event)
{
case EVENT_SYSTEM_MOVESIZESTART:
{
MoveSizeStart(data->hwnd, ptScreen);
}
break;
case EVENT_SYSTEM_MOVESIZEEND:
{
MoveSizeEnd(data->hwnd, ptScreen);
}
break;
case EVENT_OBJECT_LOCATIONCHANGE:
{
if (m_app.as<IFancyZonesCallback>()->InMoveSize())
{
MoveSizeUpdate(ptScreen);
}
}
break;
case EVENT_OBJECT_NAMECHANGE:
{
// The accessibility name of the desktop window changes whenever the user
// switches virtual desktops.
if (data->hwnd == GetDesktopWindow())
{
Trace::VirtualDesktopChanged();
m_app.as<IFancyZonesCallback>()->VirtualDesktopChanged();
}
}
break;
case EVENT_OBJECT_CREATE:
{
if (data->idObject == OBJID_WINDOW)
{
if (IsInterestingWindow(data->hwnd))
{
m_app.as<IFancyZonesCallback>()->WindowCreated(data->hwnd);
}
}
}
break;
default:
break;
}
}
void FancyZonesModule::MoveSizeStart(HWND window, POINT const& ptScreen) noexcept
{
if (IsInterestingWindow(window))
{
if (auto monitor = MonitorFromPoint(ptScreen, MONITOR_DEFAULTTONULL))
{
m_app.as<IFancyZonesCallback>()->MoveSizeStart(window, monitor, ptScreen);
}
}
}
void FancyZonesModule::MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept
{
if (IsInterestingWindow(window))
{
m_app.as<IFancyZonesCallback>()->MoveSizeEnd(window, ptScreen);
}
}
void FancyZonesModule::MoveSizeUpdate(POINT const& ptScreen) noexcept
{
if (auto monitor = MonitorFromPoint(ptScreen, MONITOR_DEFAULTTONULL))
{
m_app.as<IFancyZonesCallback>()->MoveSizeUpdate(monitor, ptScreen);
}
}
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
{
return new FancyZonesModule();
}

View File

@@ -0,0 +1,4 @@
LIBRARY fancyzones.dll
EXPORTS
PersistZoneSet PRIVATE

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.190716.2" targetFramework="native" />
</packages>

View File

@@ -0,0 +1 @@
#include "pch.h"

View File

@@ -0,0 +1,18 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <Unknwn.h>
#include <winrt/base.h>
#include <ProjectTelemetry.h>
#include <TraceLoggingActivity.h>
#include <wil\common.h>
#include <wil\result.h>
#include "lib\trace.h"
#include "lib\FancyZones.h"
#include "lib\Settings.h"
namespace winrt
{
using namespace ::winrt;
}

Binary file not shown.