2021-05-20 15:07:34 +03:00
|
|
|
// dllmain.cpp : Defines the entry point for the DLL application.
|
|
|
|
|
#include "pch.h"
|
|
|
|
|
|
|
|
|
|
#include <mutex>
|
|
|
|
|
#include <common/SettingsAPI/settings_helpers.h>
|
|
|
|
|
#include <common/utils/winapi_error.h>
|
|
|
|
|
#include <common/utils/logger_helper.h>
|
|
|
|
|
#include <common/interop/shared_constants.h>
|
|
|
|
|
|
|
|
|
|
#include "../interface/powertoy_module_interface.h"
|
|
|
|
|
#include "Generated Files/resource.h"
|
|
|
|
|
#include <common/SettingsAPI/settings_objects.h>
|
|
|
|
|
|
2022-11-09 14:41:14 +00:00
|
|
|
BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD /*ul_reason_for_call*/, LPVOID /*lpReserved*/)
|
2021-05-20 15:07:34 +03:00
|
|
|
{
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class ShortcutGuideModule : public PowertoyModuleIface
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
ShortcutGuideModule()
|
|
|
|
|
{
|
|
|
|
|
app_name = GET_RESOURCE_STRING(IDS_SHORTCUT_GUIDE);
|
|
|
|
|
app_key = L"Shortcut Guide";
|
|
|
|
|
LoggerHelpers::init_logger(app_key, L"ModuleInterface", LogSettings::shortcutGuideLoggerName);
|
|
|
|
|
|
|
|
|
|
std::filesystem::path oldLogPath(PTSettingsHelper::get_module_save_folder_location(app_key));
|
|
|
|
|
oldLogPath.append("ShortcutGuideLogs");
|
|
|
|
|
LoggerHelpers::delete_old_log_folder(oldLogPath);
|
|
|
|
|
|
|
|
|
|
exitEvent = CreateEvent(nullptr, false, false, CommonSharedConstants::SHORTCUT_GUIDE_EXIT_EVENT);
|
|
|
|
|
if (!exitEvent)
|
|
|
|
|
{
|
|
|
|
|
Logger::warn(L"Failed to create {} event. {}", CommonSharedConstants::SHORTCUT_GUIDE_EXIT_EVENT, get_last_error_or_default(GetLastError()));
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-31 00:00:11 +01:00
|
|
|
triggerEvent = CreateEvent(nullptr, false, false, CommonSharedConstants::SHORTCUT_GUIDE_TRIGGER_EVENT);
|
Shortcut Guide: Replace dual windows with single transparent overlay and add holding windows button (#48683)
## Summary
Refactors Shortcut Guide from two separate `WindowEx` instances
(`MainWindow` + `TaskbarWindow`) into a single full-monitor transparent
`OverlayWindow` that hosts both surfaces as XAML UserControls. This
enables shared animations and a more polished visual experience, and
makes the taskbar shortcut indicators **edge-aware** for Windows 11's
top/bottom/left/right taskbar positioning.
https://github.com/user-attachments/assets/e40a25f6-4ab3-4073-b1a8-906ef7782877
<img width="507" height="968" alt="image"
src="https://github.com/user-attachments/assets/2e06a3d9-32d9-482e-90fe-1f0f8a7d7598"
/>
## Changes
Closes: #48435
Closes #48491
Closes: #49200
Closes: #48552 (theme flash on Light/System theme + shortcut-list scroll
flutter)
Closes: #48773
### Architecture
- **OverlayWindow**: Single transparent host covering the full monitor
work area, using `TransparentTintBackdrop`
- **MainPaneControl**: The shortcut list pseudo-window, reusing the
shared `TransientSurface` control for chrome (acrylic backdrop, theme
shadow, rounded corners)
- **TaskbarPaneControl + TaskbarIndicator**: Tooltip-style indicators
with triangle tails, positioned above taskbar buttons
### Edge-aware taskbar indicators (Windows 11 top/bottom/left/right)
- Detects the taskbar edge via the public, documented `SHAppBarMessage`
/ `ABM_GETTASKBARPOS` API (the same API CmdPal Dock uses)
- Indicators lay out along the correct axis — horizontally for a
top/bottom taskbar, vertically for a left/right taskbar — with the
triangle tail always pointing toward the taskbar (4-direction tail +
per-edge slide-in animation)
- For a left/right taskbar, the main pane is inset so the order reads
**taskbar | indicators | pane**
- **Adaptive sizing**: each indicator's body size is derived from the
actual measured UIA taskbar button rect, so the bubbles shrink when
Windows uses small icons or combines buttons (many apps open). Uses the
smallest button slot (clamped to a readable range) so neighbouring
bubbles never overlap; the font scales with it
### Visual polish
- Windows 11 system flyout entry/exit animations (slide + fade, ~367ms
entrance / ~200ms exit with cubic easing)
- Animation direction is position-aware (slides from left when
left-aligned, from right when right-aligned)
- Taskbar indicators slide in from the taskbar edge with the same timing
- Close button on the main flyout title bar
### Robustness
- Multi-monitor DPI handling via WM_DPICHANGED suppression (prevents
double-scaling on cross-monitor moves)
- Win11 phantom border elimination (comprehensive DWM/style stripping)
- Click-outside-to-close with animated exit transition
- Process lifetime fix (`Application.Current.Exit()` on close)
## Validation
- Build clean (x64 Debug, exit 0, empty errors log)
- Tested on multi-monitor mixed-DPI setup (150% + 100%)
- Tested with the taskbar docked to each edge (top/bottom/left/right)
and with small/combined taskbar icons
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Noraa Junker <noraa.junker@outlook.com>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-27 12:21:35 +02:00
|
|
|
if (!triggerEvent)
|
|
|
|
|
{
|
|
|
|
|
Logger::warn(L"Failed to create {} event. {}", CommonSharedConstants::SHORTCUT_GUIDE_TRIGGER_EVENT, get_last_error_or_default(GetLastError()));
|
|
|
|
|
}
|
2023-01-31 00:00:11 +01:00
|
|
|
|
2021-05-20 15:07:34 +03:00
|
|
|
InitSettings();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual const wchar_t* get_name() override
|
|
|
|
|
{
|
|
|
|
|
return app_name.c_str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual const wchar_t* get_key() override
|
|
|
|
|
{
|
|
|
|
|
return app_key.c_str();
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-26 14:02:31 +01:00
|
|
|
// Return the configured status for the gpo policy for the module
|
|
|
|
|
virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override
|
|
|
|
|
{
|
|
|
|
|
return powertoys_gpo::getConfiguredShortcutGuideEnabledValue();
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-20 15:07:34 +03:00
|
|
|
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
|
|
|
|
|
{
|
|
|
|
|
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
|
|
|
|
PowerToysSettings::Settings settings(hinstance, get_name());
|
|
|
|
|
return settings.serialize_to_buffer(buffer, buffer_size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void set_config(const wchar_t* config) override
|
|
|
|
|
{
|
|
|
|
|
Logger::trace("set_config()");
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// Parse the input JSON string.
|
|
|
|
|
PowerToysSettings::PowerToyValues values =
|
|
|
|
|
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
|
|
|
|
|
2021-09-23 14:23:22 +01:00
|
|
|
ParseSettings(values);
|
2021-05-20 15:07:34 +03:00
|
|
|
}
|
2022-09-11 19:50:13 +03:00
|
|
|
catch (std::exception& ex)
|
2021-05-20 15:07:34 +03:00
|
|
|
{
|
|
|
|
|
Logger::error("Failed to parse settings. {}", ex.what());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void enable() override
|
|
|
|
|
{
|
|
|
|
|
Logger::info("Shortcut Guide is enabling");
|
|
|
|
|
|
|
|
|
|
if (!_enabled)
|
|
|
|
|
{
|
|
|
|
|
_enabled = true;
|
Shortcut Guide: Replace dual windows with single transparent overlay and add holding windows button (#48683)
## Summary
Refactors Shortcut Guide from two separate `WindowEx` instances
(`MainWindow` + `TaskbarWindow`) into a single full-monitor transparent
`OverlayWindow` that hosts both surfaces as XAML UserControls. This
enables shared animations and a more polished visual experience, and
makes the taskbar shortcut indicators **edge-aware** for Windows 11's
top/bottom/left/right taskbar positioning.
https://github.com/user-attachments/assets/e40a25f6-4ab3-4073-b1a8-906ef7782877
<img width="507" height="968" alt="image"
src="https://github.com/user-attachments/assets/2e06a3d9-32d9-482e-90fe-1f0f8a7d7598"
/>
## Changes
Closes: #48435
Closes #48491
Closes: #49200
Closes: #48552 (theme flash on Light/System theme + shortcut-list scroll
flutter)
Closes: #48773
### Architecture
- **OverlayWindow**: Single transparent host covering the full monitor
work area, using `TransparentTintBackdrop`
- **MainPaneControl**: The shortcut list pseudo-window, reusing the
shared `TransientSurface` control for chrome (acrylic backdrop, theme
shadow, rounded corners)
- **TaskbarPaneControl + TaskbarIndicator**: Tooltip-style indicators
with triangle tails, positioned above taskbar buttons
### Edge-aware taskbar indicators (Windows 11 top/bottom/left/right)
- Detects the taskbar edge via the public, documented `SHAppBarMessage`
/ `ABM_GETTASKBARPOS` API (the same API CmdPal Dock uses)
- Indicators lay out along the correct axis — horizontally for a
top/bottom taskbar, vertically for a left/right taskbar — with the
triangle tail always pointing toward the taskbar (4-direction tail +
per-edge slide-in animation)
- For a left/right taskbar, the main pane is inset so the order reads
**taskbar | indicators | pane**
- **Adaptive sizing**: each indicator's body size is derived from the
actual measured UIA taskbar button rect, so the bubbles shrink when
Windows uses small icons or combines buttons (many apps open). Uses the
smallest button slot (clamped to a readable range) so neighbouring
bubbles never overlap; the font scales with it
### Visual polish
- Windows 11 system flyout entry/exit animations (slide + fade, ~367ms
entrance / ~200ms exit with cubic easing)
- Animation direction is position-aware (slides from left when
left-aligned, from right when right-aligned)
- Taskbar indicators slide in from the taskbar edge with the same timing
- Close button on the main flyout title bar
### Robustness
- Multi-monitor DPI handling via WM_DPICHANGED suppression (prevents
double-scaling on cross-monitor moves)
- Win11 phantom border elimination (comprehensive DWM/style stripping)
- Click-outside-to-close with animated exit transition
- Process lifetime fix (`Application.Current.Exit()` on close)
## Validation
- Build clean (x64 Debug, exit 0, empty errors log)
- Tested on multi-monitor mixed-DPI setup (150% + 100%)
- Tested with the taskbar docked to each edge (top/bottom/left/right)
and with small/combined taskbar icons
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Noraa Junker <noraa.junker@outlook.com>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-27 12:21:35 +02:00
|
|
|
StartProcess();
|
2021-05-20 15:07:34 +03:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Logger::warn("Shortcut guide is already enabled");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void disable() override
|
|
|
|
|
{
|
|
|
|
|
Logger::info("ShortcutGuideModule::disable()");
|
|
|
|
|
if (_enabled)
|
|
|
|
|
{
|
|
|
|
|
_enabled = false;
|
2026-05-21 17:27:52 +02:00
|
|
|
if (IsProcessActive())
|
|
|
|
|
{
|
|
|
|
|
TerminateProcess(m_hProcess, 0);
|
|
|
|
|
}
|
2021-05-20 15:07:34 +03:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Logger::warn("Shortcut Guide is already disabled");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool is_enabled() override
|
|
|
|
|
{
|
|
|
|
|
return _enabled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void destroy() override
|
|
|
|
|
{
|
|
|
|
|
this->disable();
|
|
|
|
|
if (exitEvent)
|
|
|
|
|
{
|
|
|
|
|
CloseHandle(exitEvent);
|
|
|
|
|
}
|
Shortcut Guide: Replace dual windows with single transparent overlay and add holding windows button (#48683)
## Summary
Refactors Shortcut Guide from two separate `WindowEx` instances
(`MainWindow` + `TaskbarWindow`) into a single full-monitor transparent
`OverlayWindow` that hosts both surfaces as XAML UserControls. This
enables shared animations and a more polished visual experience, and
makes the taskbar shortcut indicators **edge-aware** for Windows 11's
top/bottom/left/right taskbar positioning.
https://github.com/user-attachments/assets/e40a25f6-4ab3-4073-b1a8-906ef7782877
<img width="507" height="968" alt="image"
src="https://github.com/user-attachments/assets/2e06a3d9-32d9-482e-90fe-1f0f8a7d7598"
/>
## Changes
Closes: #48435
Closes #48491
Closes: #49200
Closes: #48552 (theme flash on Light/System theme + shortcut-list scroll
flutter)
Closes: #48773
### Architecture
- **OverlayWindow**: Single transparent host covering the full monitor
work area, using `TransparentTintBackdrop`
- **MainPaneControl**: The shortcut list pseudo-window, reusing the
shared `TransientSurface` control for chrome (acrylic backdrop, theme
shadow, rounded corners)
- **TaskbarPaneControl + TaskbarIndicator**: Tooltip-style indicators
with triangle tails, positioned above taskbar buttons
### Edge-aware taskbar indicators (Windows 11 top/bottom/left/right)
- Detects the taskbar edge via the public, documented `SHAppBarMessage`
/ `ABM_GETTASKBARPOS` API (the same API CmdPal Dock uses)
- Indicators lay out along the correct axis — horizontally for a
top/bottom taskbar, vertically for a left/right taskbar — with the
triangle tail always pointing toward the taskbar (4-direction tail +
per-edge slide-in animation)
- For a left/right taskbar, the main pane is inset so the order reads
**taskbar | indicators | pane**
- **Adaptive sizing**: each indicator's body size is derived from the
actual measured UIA taskbar button rect, so the bubbles shrink when
Windows uses small icons or combines buttons (many apps open). Uses the
smallest button slot (clamped to a readable range) so neighbouring
bubbles never overlap; the font scales with it
### Visual polish
- Windows 11 system flyout entry/exit animations (slide + fade, ~367ms
entrance / ~200ms exit with cubic easing)
- Animation direction is position-aware (slides from left when
left-aligned, from right when right-aligned)
- Taskbar indicators slide in from the taskbar edge with the same timing
- Close button on the main flyout title bar
### Robustness
- Multi-monitor DPI handling via WM_DPICHANGED suppression (prevents
double-scaling on cross-monitor moves)
- Win11 phantom border elimination (comprehensive DWM/style stripping)
- Click-outside-to-close with animated exit transition
- Process lifetime fix (`Application.Current.Exit()` on close)
## Validation
- Build clean (x64 Debug, exit 0, empty errors log)
- Tested on multi-monitor mixed-DPI setup (150% + 100%)
- Tested with the taskbar docked to each edge (top/bottom/left/right)
and with small/combined taskbar icons
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Noraa Junker <noraa.junker@outlook.com>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-27 12:21:35 +02:00
|
|
|
if (triggerEvent)
|
|
|
|
|
{
|
|
|
|
|
CloseHandle(triggerEvent);
|
|
|
|
|
}
|
2021-05-20 15:07:34 +03:00
|
|
|
|
|
|
|
|
delete this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual std::optional<HotkeyEx> GetHotkeyEx() override
|
|
|
|
|
{
|
|
|
|
|
Logger::trace("GetHotkeyEx()");
|
|
|
|
|
return m_hotkey;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void OnHotkeyEx() override
|
|
|
|
|
{
|
|
|
|
|
Logger::trace("OnHotkeyEx()");
|
|
|
|
|
if (!_enabled)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
Shortcut Guide: Replace dual windows with single transparent overlay and add holding windows button (#48683)
## Summary
Refactors Shortcut Guide from two separate `WindowEx` instances
(`MainWindow` + `TaskbarWindow`) into a single full-monitor transparent
`OverlayWindow` that hosts both surfaces as XAML UserControls. This
enables shared animations and a more polished visual experience, and
makes the taskbar shortcut indicators **edge-aware** for Windows 11's
top/bottom/left/right taskbar positioning.
https://github.com/user-attachments/assets/e40a25f6-4ab3-4073-b1a8-906ef7782877
<img width="507" height="968" alt="image"
src="https://github.com/user-attachments/assets/2e06a3d9-32d9-482e-90fe-1f0f8a7d7598"
/>
## Changes
Closes: #48435
Closes #48491
Closes: #49200
Closes: #48552 (theme flash on Light/System theme + shortcut-list scroll
flutter)
Closes: #48773
### Architecture
- **OverlayWindow**: Single transparent host covering the full monitor
work area, using `TransparentTintBackdrop`
- **MainPaneControl**: The shortcut list pseudo-window, reusing the
shared `TransientSurface` control for chrome (acrylic backdrop, theme
shadow, rounded corners)
- **TaskbarPaneControl + TaskbarIndicator**: Tooltip-style indicators
with triangle tails, positioned above taskbar buttons
### Edge-aware taskbar indicators (Windows 11 top/bottom/left/right)
- Detects the taskbar edge via the public, documented `SHAppBarMessage`
/ `ABM_GETTASKBARPOS` API (the same API CmdPal Dock uses)
- Indicators lay out along the correct axis — horizontally for a
top/bottom taskbar, vertically for a left/right taskbar — with the
triangle tail always pointing toward the taskbar (4-direction tail +
per-edge slide-in animation)
- For a left/right taskbar, the main pane is inset so the order reads
**taskbar | indicators | pane**
- **Adaptive sizing**: each indicator's body size is derived from the
actual measured UIA taskbar button rect, so the bubbles shrink when
Windows uses small icons or combines buttons (many apps open). Uses the
smallest button slot (clamped to a readable range) so neighbouring
bubbles never overlap; the font scales with it
### Visual polish
- Windows 11 system flyout entry/exit animations (slide + fade, ~367ms
entrance / ~200ms exit with cubic easing)
- Animation direction is position-aware (slides from left when
left-aligned, from right when right-aligned)
- Taskbar indicators slide in from the taskbar edge with the same timing
- Close button on the main flyout title bar
### Robustness
- Multi-monitor DPI handling via WM_DPICHANGED suppression (prevents
double-scaling on cross-monitor moves)
- Win11 phantom border elimination (comprehensive DWM/style stripping)
- Click-outside-to-close with animated exit transition
- Process lifetime fix (`Application.Current.Exit()` on close)
## Validation
- Build clean (x64 Debug, exit 0, empty errors log)
- Tested on multi-monitor mixed-DPI setup (150% + 100%)
- Tested with the taskbar docked to each edge (top/bottom/left/right)
and with small/combined taskbar icons
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Noraa Junker <noraa.junker@outlook.com>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-27 12:21:35 +02:00
|
|
|
if (!IsProcessActive())
|
2021-05-20 15:07:34 +03:00
|
|
|
{
|
Shortcut Guide: Replace dual windows with single transparent overlay and add holding windows button (#48683)
## Summary
Refactors Shortcut Guide from two separate `WindowEx` instances
(`MainWindow` + `TaskbarWindow`) into a single full-monitor transparent
`OverlayWindow` that hosts both surfaces as XAML UserControls. This
enables shared animations and a more polished visual experience, and
makes the taskbar shortcut indicators **edge-aware** for Windows 11's
top/bottom/left/right taskbar positioning.
https://github.com/user-attachments/assets/e40a25f6-4ab3-4073-b1a8-906ef7782877
<img width="507" height="968" alt="image"
src="https://github.com/user-attachments/assets/2e06a3d9-32d9-482e-90fe-1f0f8a7d7598"
/>
## Changes
Closes: #48435
Closes #48491
Closes: #49200
Closes: #48552 (theme flash on Light/System theme + shortcut-list scroll
flutter)
Closes: #48773
### Architecture
- **OverlayWindow**: Single transparent host covering the full monitor
work area, using `TransparentTintBackdrop`
- **MainPaneControl**: The shortcut list pseudo-window, reusing the
shared `TransientSurface` control for chrome (acrylic backdrop, theme
shadow, rounded corners)
- **TaskbarPaneControl + TaskbarIndicator**: Tooltip-style indicators
with triangle tails, positioned above taskbar buttons
### Edge-aware taskbar indicators (Windows 11 top/bottom/left/right)
- Detects the taskbar edge via the public, documented `SHAppBarMessage`
/ `ABM_GETTASKBARPOS` API (the same API CmdPal Dock uses)
- Indicators lay out along the correct axis — horizontally for a
top/bottom taskbar, vertically for a left/right taskbar — with the
triangle tail always pointing toward the taskbar (4-direction tail +
per-edge slide-in animation)
- For a left/right taskbar, the main pane is inset so the order reads
**taskbar | indicators | pane**
- **Adaptive sizing**: each indicator's body size is derived from the
actual measured UIA taskbar button rect, so the bubbles shrink when
Windows uses small icons or combines buttons (many apps open). Uses the
smallest button slot (clamped to a readable range) so neighbouring
bubbles never overlap; the font scales with it
### Visual polish
- Windows 11 system flyout entry/exit animations (slide + fade, ~367ms
entrance / ~200ms exit with cubic easing)
- Animation direction is position-aware (slides from left when
left-aligned, from right when right-aligned)
- Taskbar indicators slide in from the taskbar edge with the same timing
- Close button on the main flyout title bar
### Robustness
- Multi-monitor DPI handling via WM_DPICHANGED suppression (prevents
double-scaling on cross-monitor moves)
- Win11 phantom border elimination (comprehensive DWM/style stripping)
- Click-outside-to-close with animated exit transition
- Process lifetime fix (`Application.Current.Exit()` on close)
## Validation
- Build clean (x64 Debug, exit 0, empty errors log)
- Tested on multi-monitor mixed-DPI setup (150% + 100%)
- Tested with the taskbar docked to each edge (top/bottom/left/right)
and with small/combined taskbar icons
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Noraa Junker <noraa.junker@outlook.com>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-27 12:21:35 +02:00
|
|
|
StartProcess();
|
2021-05-20 15:07:34 +03:00
|
|
|
}
|
|
|
|
|
|
Shortcut Guide: Replace dual windows with single transparent overlay and add holding windows button (#48683)
## Summary
Refactors Shortcut Guide from two separate `WindowEx` instances
(`MainWindow` + `TaskbarWindow`) into a single full-monitor transparent
`OverlayWindow` that hosts both surfaces as XAML UserControls. This
enables shared animations and a more polished visual experience, and
makes the taskbar shortcut indicators **edge-aware** for Windows 11's
top/bottom/left/right taskbar positioning.
https://github.com/user-attachments/assets/e40a25f6-4ab3-4073-b1a8-906ef7782877
<img width="507" height="968" alt="image"
src="https://github.com/user-attachments/assets/2e06a3d9-32d9-482e-90fe-1f0f8a7d7598"
/>
## Changes
Closes: #48435
Closes #48491
Closes: #49200
Closes: #48552 (theme flash on Light/System theme + shortcut-list scroll
flutter)
Closes: #48773
### Architecture
- **OverlayWindow**: Single transparent host covering the full monitor
work area, using `TransparentTintBackdrop`
- **MainPaneControl**: The shortcut list pseudo-window, reusing the
shared `TransientSurface` control for chrome (acrylic backdrop, theme
shadow, rounded corners)
- **TaskbarPaneControl + TaskbarIndicator**: Tooltip-style indicators
with triangle tails, positioned above taskbar buttons
### Edge-aware taskbar indicators (Windows 11 top/bottom/left/right)
- Detects the taskbar edge via the public, documented `SHAppBarMessage`
/ `ABM_GETTASKBARPOS` API (the same API CmdPal Dock uses)
- Indicators lay out along the correct axis — horizontally for a
top/bottom taskbar, vertically for a left/right taskbar — with the
triangle tail always pointing toward the taskbar (4-direction tail +
per-edge slide-in animation)
- For a left/right taskbar, the main pane is inset so the order reads
**taskbar | indicators | pane**
- **Adaptive sizing**: each indicator's body size is derived from the
actual measured UIA taskbar button rect, so the bubbles shrink when
Windows uses small icons or combines buttons (many apps open). Uses the
smallest button slot (clamped to a readable range) so neighbouring
bubbles never overlap; the font scales with it
### Visual polish
- Windows 11 system flyout entry/exit animations (slide + fade, ~367ms
entrance / ~200ms exit with cubic easing)
- Animation direction is position-aware (slides from left when
left-aligned, from right when right-aligned)
- Taskbar indicators slide in from the taskbar edge with the same timing
- Close button on the main flyout title bar
### Robustness
- Multi-monitor DPI handling via WM_DPICHANGED suppression (prevents
double-scaling on cross-monitor moves)
- Win11 phantom border elimination (comprehensive DWM/style stripping)
- Click-outside-to-close with animated exit transition
- Process lifetime fix (`Application.Current.Exit()` on close)
## Validation
- Build clean (x64 Debug, exit 0, empty errors log)
- Tested on multi-monitor mixed-DPI setup (150% + 100%)
- Tested with the taskbar docked to each edge (top/bottom/left/right)
and with small/combined taskbar icons
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Noraa Junker <noraa.junker@outlook.com>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-27 12:21:35 +02:00
|
|
|
SetEvent(triggerEvent);
|
2021-05-20 15:07:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void send_settings_telemetry() override
|
|
|
|
|
{
|
|
|
|
|
Logger::trace("Send settings telemetry");
|
|
|
|
|
if (!StartProcess(L"telemetry"))
|
|
|
|
|
{
|
|
|
|
|
Logger::error("Failed to create a process to send settings telemetry");
|
|
|
|
|
}
|
|
|
|
|
}
|
Shortcut Guide: Replace dual windows with single transparent overlay and add holding windows button (#48683)
## Summary
Refactors Shortcut Guide from two separate `WindowEx` instances
(`MainWindow` + `TaskbarWindow`) into a single full-monitor transparent
`OverlayWindow` that hosts both surfaces as XAML UserControls. This
enables shared animations and a more polished visual experience, and
makes the taskbar shortcut indicators **edge-aware** for Windows 11's
top/bottom/left/right taskbar positioning.
https://github.com/user-attachments/assets/e40a25f6-4ab3-4073-b1a8-906ef7782877
<img width="507" height="968" alt="image"
src="https://github.com/user-attachments/assets/2e06a3d9-32d9-482e-90fe-1f0f8a7d7598"
/>
## Changes
Closes: #48435
Closes #48491
Closes: #49200
Closes: #48552 (theme flash on Light/System theme + shortcut-list scroll
flutter)
Closes: #48773
### Architecture
- **OverlayWindow**: Single transparent host covering the full monitor
work area, using `TransparentTintBackdrop`
- **MainPaneControl**: The shortcut list pseudo-window, reusing the
shared `TransientSurface` control for chrome (acrylic backdrop, theme
shadow, rounded corners)
- **TaskbarPaneControl + TaskbarIndicator**: Tooltip-style indicators
with triangle tails, positioned above taskbar buttons
### Edge-aware taskbar indicators (Windows 11 top/bottom/left/right)
- Detects the taskbar edge via the public, documented `SHAppBarMessage`
/ `ABM_GETTASKBARPOS` API (the same API CmdPal Dock uses)
- Indicators lay out along the correct axis — horizontally for a
top/bottom taskbar, vertically for a left/right taskbar — with the
triangle tail always pointing toward the taskbar (4-direction tail +
per-edge slide-in animation)
- For a left/right taskbar, the main pane is inset so the order reads
**taskbar | indicators | pane**
- **Adaptive sizing**: each indicator's body size is derived from the
actual measured UIA taskbar button rect, so the bubbles shrink when
Windows uses small icons or combines buttons (many apps open). Uses the
smallest button slot (clamped to a readable range) so neighbouring
bubbles never overlap; the font scales with it
### Visual polish
- Windows 11 system flyout entry/exit animations (slide + fade, ~367ms
entrance / ~200ms exit with cubic easing)
- Animation direction is position-aware (slides from left when
left-aligned, from right when right-aligned)
- Taskbar indicators slide in from the taskbar edge with the same timing
- Close button on the main flyout title bar
### Robustness
- Multi-monitor DPI handling via WM_DPICHANGED suppression (prevents
double-scaling on cross-monitor moves)
- Win11 phantom border elimination (comprehensive DWM/style stripping)
- Click-outside-to-close with animated exit transition
- Process lifetime fix (`Application.Current.Exit()` on close)
## Validation
- Build clean (x64 Debug, exit 0, empty errors log)
- Tested on multi-monitor mixed-DPI setup (150% + 100%)
- Tested with the taskbar docked to each edge (top/bottom/left/right)
and with small/combined taskbar icons
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Noraa Junker <noraa.junker@outlook.com>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-27 12:21:35 +02:00
|
|
|
virtual bool keep_track_of_pressed_win_key() override { return true; }
|
|
|
|
|
virtual UINT milliseconds_win_key_must_be_pressed() override { return 900; }
|
2021-05-20 15:07:34 +03:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::wstring app_name;
|
|
|
|
|
//contains the non localized key of the powertoy
|
|
|
|
|
std::wstring app_key;
|
|
|
|
|
bool _enabled = false;
|
|
|
|
|
HANDLE m_hProcess = nullptr;
|
2022-11-09 14:41:14 +00:00
|
|
|
|
2021-05-20 15:07:34 +03:00
|
|
|
// Hotkey to invoke the module
|
|
|
|
|
HotkeyEx m_hotkey;
|
2021-09-23 14:23:22 +01:00
|
|
|
|
|
|
|
|
// If the module should be activated through the legacy pressing windows key behavior.
|
2022-11-18 22:22:40 +08:00
|
|
|
const UINT DEFAULT_MILLISECONDS_WIN_KEY_PRESS_TIME_FOR_GLOBAL_WINDOWS_SHORTCUTS = 900;
|
|
|
|
|
const UINT DEFAULT_MILLISECONDS_WIN_KEY_PRESS_TIME_FOR_TASKBAR_ICON_SHORTCUTS = 900;
|
|
|
|
|
UINT m_millisecondsWinKeyPressTimeForGlobalWindowsShortcuts = DEFAULT_MILLISECONDS_WIN_KEY_PRESS_TIME_FOR_GLOBAL_WINDOWS_SHORTCUTS;
|
|
|
|
|
UINT m_millisecondsWinKeyPressTimeForTaskbarIconShortcuts = DEFAULT_MILLISECONDS_WIN_KEY_PRESS_TIME_FOR_TASKBAR_ICON_SHORTCUTS;
|
2021-09-23 14:23:22 +01:00
|
|
|
|
2023-01-31 00:00:11 +01:00
|
|
|
HANDLE triggerEvent;
|
2021-05-20 15:07:34 +03:00
|
|
|
HANDLE exitEvent;
|
|
|
|
|
|
|
|
|
|
bool StartProcess(std::wstring args = L"")
|
|
|
|
|
{
|
|
|
|
|
if (exitEvent)
|
|
|
|
|
{
|
|
|
|
|
ResetEvent(exitEvent);
|
|
|
|
|
}
|
|
|
|
|
|
Shortcut Guide: Replace dual windows with single transparent overlay and add holding windows button (#48683)
## Summary
Refactors Shortcut Guide from two separate `WindowEx` instances
(`MainWindow` + `TaskbarWindow`) into a single full-monitor transparent
`OverlayWindow` that hosts both surfaces as XAML UserControls. This
enables shared animations and a more polished visual experience, and
makes the taskbar shortcut indicators **edge-aware** for Windows 11's
top/bottom/left/right taskbar positioning.
https://github.com/user-attachments/assets/e40a25f6-4ab3-4073-b1a8-906ef7782877
<img width="507" height="968" alt="image"
src="https://github.com/user-attachments/assets/2e06a3d9-32d9-482e-90fe-1f0f8a7d7598"
/>
## Changes
Closes: #48435
Closes #48491
Closes: #49200
Closes: #48552 (theme flash on Light/System theme + shortcut-list scroll
flutter)
Closes: #48773
### Architecture
- **OverlayWindow**: Single transparent host covering the full monitor
work area, using `TransparentTintBackdrop`
- **MainPaneControl**: The shortcut list pseudo-window, reusing the
shared `TransientSurface` control for chrome (acrylic backdrop, theme
shadow, rounded corners)
- **TaskbarPaneControl + TaskbarIndicator**: Tooltip-style indicators
with triangle tails, positioned above taskbar buttons
### Edge-aware taskbar indicators (Windows 11 top/bottom/left/right)
- Detects the taskbar edge via the public, documented `SHAppBarMessage`
/ `ABM_GETTASKBARPOS` API (the same API CmdPal Dock uses)
- Indicators lay out along the correct axis — horizontally for a
top/bottom taskbar, vertically for a left/right taskbar — with the
triangle tail always pointing toward the taskbar (4-direction tail +
per-edge slide-in animation)
- For a left/right taskbar, the main pane is inset so the order reads
**taskbar | indicators | pane**
- **Adaptive sizing**: each indicator's body size is derived from the
actual measured UIA taskbar button rect, so the bubbles shrink when
Windows uses small icons or combines buttons (many apps open). Uses the
smallest button slot (clamped to a readable range) so neighbouring
bubbles never overlap; the font scales with it
### Visual polish
- Windows 11 system flyout entry/exit animations (slide + fade, ~367ms
entrance / ~200ms exit with cubic easing)
- Animation direction is position-aware (slides from left when
left-aligned, from right when right-aligned)
- Taskbar indicators slide in from the taskbar edge with the same timing
- Close button on the main flyout title bar
### Robustness
- Multi-monitor DPI handling via WM_DPICHANGED suppression (prevents
double-scaling on cross-monitor moves)
- Win11 phantom border elimination (comprehensive DWM/style stripping)
- Click-outside-to-close with animated exit transition
- Process lifetime fix (`Application.Current.Exit()` on close)
## Validation
- Build clean (x64 Debug, exit 0, empty errors log)
- Tested on multi-monitor mixed-DPI setup (150% + 100%)
- Tested with the taskbar docked to each edge (top/bottom/left/right)
and with small/combined taskbar icons
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Noraa Junker <noraa.junker@outlook.com>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-27 12:21:35 +02:00
|
|
|
if (triggerEvent)
|
|
|
|
|
{
|
|
|
|
|
ResetEvent(triggerEvent);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-20 15:07:34 +03:00
|
|
|
unsigned long powertoys_pid = GetCurrentProcessId();
|
|
|
|
|
std::wstring executable_args = L"";
|
|
|
|
|
executable_args.append(std::to_wstring(powertoys_pid));
|
|
|
|
|
if (!args.empty())
|
|
|
|
|
{
|
|
|
|
|
executable_args.append(L" ");
|
|
|
|
|
executable_args.append(args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
|
|
|
|
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
|
2026-05-21 17:27:52 +02:00
|
|
|
sei.lpFile = L"WinUI3Apps\\PowerToys.ShortcutGuide.exe";
|
2021-05-20 15:07:34 +03:00
|
|
|
sei.nShow = SW_SHOWNORMAL;
|
|
|
|
|
sei.lpParameters = executable_args.data();
|
|
|
|
|
if (ShellExecuteExW(&sei) == false)
|
|
|
|
|
{
|
|
|
|
|
Logger::error(L"Failed to start SG process. {}", get_last_error_or_default(GetLastError()));
|
|
|
|
|
auto message = get_last_error_message(GetLastError());
|
|
|
|
|
if (message.has_value())
|
|
|
|
|
{
|
|
|
|
|
Logger::error(message.value());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Logger::trace(L"Started SG process with pid={}", GetProcessId(sei.hProcess));
|
|
|
|
|
m_hProcess = sei.hProcess;
|
2022-11-09 14:41:14 +00:00
|
|
|
return true;
|
2021-05-20 15:07:34 +03:00
|
|
|
}
|
|
|
|
|
|
2026-05-21 17:27:52 +02:00
|
|
|
bool IsProcessActive()
|
2021-05-20 15:07:34 +03:00
|
|
|
{
|
2026-05-21 17:27:52 +02:00
|
|
|
if (!m_hProcess)
|
2021-05-20 15:07:34 +03:00
|
|
|
{
|
2026-05-21 17:27:52 +02:00
|
|
|
return false;
|
2021-05-20 15:07:34 +03:00
|
|
|
}
|
2026-05-21 17:27:52 +02:00
|
|
|
auto result = WaitForSingleObject(m_hProcess, 0);
|
|
|
|
|
if (result == WAIT_FAILED)
|
|
|
|
|
{
|
|
|
|
|
Logger::error("Failed to wait for SG process.");
|
|
|
|
|
}
|
|
|
|
|
return result == WAIT_TIMEOUT;
|
2021-05-20 15:07:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InitSettings()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
PowerToysSettings::PowerToyValues settings =
|
|
|
|
|
PowerToysSettings::PowerToyValues::load_from_settings_file(app_key);
|
|
|
|
|
|
2021-09-23 14:23:22 +01:00
|
|
|
ParseSettings(settings);
|
2021-05-20 15:07:34 +03:00
|
|
|
}
|
2022-09-11 19:50:13 +03:00
|
|
|
catch (std::exception& ex)
|
2021-05-20 15:07:34 +03:00
|
|
|
{
|
|
|
|
|
Logger::error("Failed to init settings. {}", ex.what());
|
|
|
|
|
}
|
2022-11-09 14:41:14 +00:00
|
|
|
catch (...)
|
2021-05-20 15:07:34 +03:00
|
|
|
{
|
|
|
|
|
Logger::error("Failed to init settings");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-23 14:23:22 +01:00
|
|
|
void ParseSettings(PowerToysSettings::PowerToyValues& settings)
|
2021-05-20 15:07:34 +03:00
|
|
|
{
|
|
|
|
|
auto settingsObject = settings.get_raw_json();
|
|
|
|
|
if (settingsObject.GetView().Size())
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2021-09-23 14:23:22 +01:00
|
|
|
// Parse HotKey
|
2021-05-20 15:07:34 +03:00
|
|
|
auto jsonHotkeyObject = settingsObject.GetNamedObject(L"properties").GetNamedObject(L"open_shortcutguide");
|
|
|
|
|
auto hotkey = PowerToysSettings::HotkeyObject::from_json(jsonHotkeyObject);
|
|
|
|
|
m_hotkey = HotkeyEx();
|
|
|
|
|
if (hotkey.win_pressed())
|
|
|
|
|
{
|
|
|
|
|
m_hotkey.modifiersMask |= MOD_WIN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hotkey.ctrl_pressed())
|
|
|
|
|
{
|
|
|
|
|
m_hotkey.modifiersMask |= MOD_CONTROL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hotkey.shift_pressed())
|
|
|
|
|
{
|
|
|
|
|
m_hotkey.modifiersMask |= MOD_SHIFT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hotkey.alt_pressed())
|
|
|
|
|
{
|
|
|
|
|
m_hotkey.modifiersMask |= MOD_ALT;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-17 16:24:56 +00:00
|
|
|
m_hotkey.vkCode = static_cast<WORD>(hotkey.get_code());
|
2021-05-20 15:07:34 +03:00
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
Logger::warn("Failed to initialize Shortcut Guide start shortcut");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Logger::info("Shortcut Guide settings are empty");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_hotkey.modifiersMask)
|
|
|
|
|
{
|
|
|
|
|
Logger::info("Shortcut Guide is going to use default shortcut");
|
|
|
|
|
m_hotkey.modifiersMask = MOD_SHIFT | MOD_WIN;
|
|
|
|
|
m_hotkey.vkCode = VK_OEM_2;
|
|
|
|
|
}
|
|
|
|
|
}
|
Shortcut Guide: Replace dual windows with single transparent overlay and add holding windows button (#48683)
## Summary
Refactors Shortcut Guide from two separate `WindowEx` instances
(`MainWindow` + `TaskbarWindow`) into a single full-monitor transparent
`OverlayWindow` that hosts both surfaces as XAML UserControls. This
enables shared animations and a more polished visual experience, and
makes the taskbar shortcut indicators **edge-aware** for Windows 11's
top/bottom/left/right taskbar positioning.
https://github.com/user-attachments/assets/e40a25f6-4ab3-4073-b1a8-906ef7782877
<img width="507" height="968" alt="image"
src="https://github.com/user-attachments/assets/2e06a3d9-32d9-482e-90fe-1f0f8a7d7598"
/>
## Changes
Closes: #48435
Closes #48491
Closes: #49200
Closes: #48552 (theme flash on Light/System theme + shortcut-list scroll
flutter)
Closes: #48773
### Architecture
- **OverlayWindow**: Single transparent host covering the full monitor
work area, using `TransparentTintBackdrop`
- **MainPaneControl**: The shortcut list pseudo-window, reusing the
shared `TransientSurface` control for chrome (acrylic backdrop, theme
shadow, rounded corners)
- **TaskbarPaneControl + TaskbarIndicator**: Tooltip-style indicators
with triangle tails, positioned above taskbar buttons
### Edge-aware taskbar indicators (Windows 11 top/bottom/left/right)
- Detects the taskbar edge via the public, documented `SHAppBarMessage`
/ `ABM_GETTASKBARPOS` API (the same API CmdPal Dock uses)
- Indicators lay out along the correct axis — horizontally for a
top/bottom taskbar, vertically for a left/right taskbar — with the
triangle tail always pointing toward the taskbar (4-direction tail +
per-edge slide-in animation)
- For a left/right taskbar, the main pane is inset so the order reads
**taskbar | indicators | pane**
- **Adaptive sizing**: each indicator's body size is derived from the
actual measured UIA taskbar button rect, so the bubbles shrink when
Windows uses small icons or combines buttons (many apps open). Uses the
smallest button slot (clamped to a readable range) so neighbouring
bubbles never overlap; the font scales with it
### Visual polish
- Windows 11 system flyout entry/exit animations (slide + fade, ~367ms
entrance / ~200ms exit with cubic easing)
- Animation direction is position-aware (slides from left when
left-aligned, from right when right-aligned)
- Taskbar indicators slide in from the taskbar edge with the same timing
- Close button on the main flyout title bar
### Robustness
- Multi-monitor DPI handling via WM_DPICHANGED suppression (prevents
double-scaling on cross-monitor moves)
- Win11 phantom border elimination (comprehensive DWM/style stripping)
- Click-outside-to-close with animated exit transition
- Process lifetime fix (`Application.Current.Exit()` on close)
## Validation
- Build clean (x64 Debug, exit 0, empty errors log)
- Tested on multi-monitor mixed-DPI setup (150% + 100%)
- Tested with the taskbar docked to each edge (top/bottom/left/right)
and with small/combined taskbar icons
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Noraa Junker <noraa.junker@outlook.com>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-27 12:21:35 +02:00
|
|
|
|
|
|
|
|
void WindowsKeyPressBehavior()
|
|
|
|
|
{
|
|
|
|
|
if (IsProcessActive())
|
|
|
|
|
{
|
|
|
|
|
TerminateProcess(m_hProcess, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-05-20 15:07:34 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
|
|
|
|
{
|
|
|
|
|
return new ShortcutGuideModule();
|
|
|
|
|
}
|