mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-06-11 12:14:53 +08:00
FZ: warn w/ a toast if an elevated window cannot be dragged and offer learning more
This commit is contained in:
parent
c2e219b446
commit
60fa6071b9
@ -31,6 +31,12 @@
|
|||||||
<Application Id="PowerToys" Executable="PowerToys.exe" EntryPoint="Windows.FullTrustApplication">
|
<Application Id="PowerToys" Executable="PowerToys.exe" EntryPoint="Windows.FullTrustApplication">
|
||||||
<uap:VisualElements DisplayName="PowerToys (Experimental)" Description="Windows system utilities to maximize productivity" Square150x150Logo="Images\logo150.png" Square44x44Logo="Images\logo44.png" BackgroundColor="transparent" />
|
<uap:VisualElements DisplayName="PowerToys (Experimental)" Description="Windows system utilities to maximize productivity" Square150x150Logo="Images\logo150.png" Square44x44Logo="Images\logo44.png" BackgroundColor="transparent" />
|
||||||
<Extensions>
|
<Extensions>
|
||||||
|
<uap:Extension Category="windows.protocol">
|
||||||
|
<uap:Protocol Name="powertoys">
|
||||||
|
<uap:Logo>images\logo.png</uap:Logo>
|
||||||
|
<uap:DisplayName>Powertoys custom protocol</uap:DisplayName>
|
||||||
|
</uap:Protocol>
|
||||||
|
</uap:Extension>
|
||||||
<uap5:Extension Category="windows.startupTask" Executable="PowerToys.exe" EntryPoint="Windows.FullTrustApplication">
|
<uap5:Extension Category="windows.startupTask" Executable="PowerToys.exe" EntryPoint="Windows.FullTrustApplication">
|
||||||
<uap5:StartupTask TaskId="PowerToysStartupTaskID" Enabled="true" DisplayName="PowerToys" />
|
<uap5:StartupTask TaskId="PowerToysStartupTaskID" Enabled="true" DisplayName="PowerToys" />
|
||||||
</uap5:Extension>
|
</uap5:Extension>
|
||||||
|
@ -236,8 +236,20 @@
|
|||||||
</Shortcut>
|
</Shortcut>
|
||||||
</File>
|
</File>
|
||||||
|
|
||||||
|
<RegistryKey Root="HKCR" Key="powertoys" Action="createAndRemoveOnUninstall">
|
||||||
|
<RegistryValue Type="string" Name="URL Protocol" Value=""/>
|
||||||
|
<RegistryValue Type="string" Value="URL:PowerToys custom internal URI protocol"/>
|
||||||
|
<RegistryKey Key="DefaultIcon">
|
||||||
|
<RegistryValue Type="string" Value="PowerToys.exe" />
|
||||||
|
</RegistryKey>
|
||||||
|
<RegistryKey Key="shell\open\command">
|
||||||
|
<RegistryValue Type="string" Value=""[INSTALLFOLDER]PowerToys.exe" "%1"" />
|
||||||
|
</RegistryKey>
|
||||||
|
</RegistryKey>
|
||||||
|
|
||||||
<RemoveFolder Id="DeleteShortcutFolder" Directory="ApplicationProgramsFolder" On="uninstall" />
|
<RemoveFolder Id="DeleteShortcutFolder" Directory="ApplicationProgramsFolder" On="uninstall" />
|
||||||
</Component>
|
</Component>
|
||||||
|
|
||||||
<Component Id="settings_exe" Guid="A5A461A9-7097-4CBA-9D39-3DBBB6B7B80C" Win64="yes">
|
<Component Id="settings_exe" Guid="A5A461A9-7097-4CBA-9D39-3DBBB6B7B80C" Win64="yes">
|
||||||
<File Id="PowerToysSettings.exe" KeyPath="yes" Checksum="yes" />
|
<File Id="PowerToysSettings.exe" KeyPath="yes" Checksum="yes" />
|
||||||
</Component>
|
</Component>
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
<ProjectName>common</ProjectName>
|
<ProjectName>common</ProjectName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<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>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
@ -164,7 +167,16 @@
|
|||||||
<ClCompile Include="window_helpers.cpp" />
|
<ClCompile Include="window_helpers.cpp" />
|
||||||
<ClCompile Include="winstore.cpp" />
|
<ClCompile Include="winstore.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
<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>
|
</Project>
|
@ -145,10 +145,10 @@ void notifications::register_background_toast_handler()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void notifications::show_toast(std::wstring_view message)
|
void notifications::show_toast(std::wstring message, toast_params params)
|
||||||
{
|
{
|
||||||
// The toast won't be actually activated in the background, since it doesn't have any buttons
|
// The toast won't be actually activated in the background, since it doesn't have any buttons
|
||||||
show_toast_with_activations(message, {}, {});
|
show_toast_with_activations(std::move(message), {}, {}, std::move(params));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void xml_escape(std::wstring data)
|
inline void xml_escape(std::wstring data)
|
||||||
@ -182,13 +182,13 @@ inline void xml_escape(std::wstring data)
|
|||||||
data.swap(buffer);
|
data.swap(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void notifications::show_toast_with_activations(std::wstring_view message, std::wstring_view background_handler_id, std::vector<button_t> buttons)
|
void notifications::show_toast_with_activations(std::wstring message, std::wstring_view background_handler_id, std::vector<action_t> actions, toast_params params)
|
||||||
{
|
{
|
||||||
// DO NOT LOCALIZE any string in this function, because they're XML tags and a subject to
|
// DO NOT LOCALIZE any string in this function, because they're XML tags and a subject to
|
||||||
// https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/toast-xml-schema
|
// https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/toast-xml-schema
|
||||||
|
|
||||||
std::wstring toast_xml;
|
std::wstring toast_xml;
|
||||||
toast_xml.reserve(1024);
|
toast_xml.reserve(2048);
|
||||||
std::wstring title{ L"PowerToys" };
|
std::wstring title{ L"PowerToys" };
|
||||||
if (winstore::running_as_packaged())
|
if (winstore::running_as_packaged())
|
||||||
{
|
{
|
||||||
@ -200,28 +200,78 @@ void notifications::show_toast_with_activations(std::wstring_view message, std::
|
|||||||
toast_xml += L"</text><text>";
|
toast_xml += L"</text><text>";
|
||||||
toast_xml += message;
|
toast_xml += message;
|
||||||
toast_xml += L"</text></binding></visual><actions>";
|
toast_xml += L"</text></binding></visual><actions>";
|
||||||
|
for (size_t i = 0; i < size(actions); ++i)
|
||||||
|
{
|
||||||
|
std::visit(overloaded{
|
||||||
|
[&](const snooze_button& b) {
|
||||||
|
const bool has_durations = !b.durations.empty() && size(b.durations) <= 5;
|
||||||
|
std::wstring selection_id = L"snoozeTime";
|
||||||
|
selection_id += static_cast<wchar_t>(L'0' + i);
|
||||||
|
if (has_durations)
|
||||||
|
{
|
||||||
|
toast_xml += LR"(<input id=")";
|
||||||
|
toast_xml += selection_id;
|
||||||
|
toast_xml += LR"(" type="selection" defaultInput=")";
|
||||||
|
toast_xml += std::to_wstring(b.durations[0].minutes);
|
||||||
|
toast_xml += LR"(">)";
|
||||||
|
for (const auto& duration : b.durations)
|
||||||
|
{
|
||||||
|
toast_xml += LR"(<selection id=")";
|
||||||
|
toast_xml += std::to_wstring(duration.minutes);
|
||||||
|
toast_xml += LR"(" content=")";
|
||||||
|
toast_xml += duration.label;
|
||||||
|
toast_xml += LR"("/>)";
|
||||||
|
}
|
||||||
|
toast_xml += LR"(</input>)";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[](const auto&) {} },
|
||||||
|
actions[i]);
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < size(buttons); ++i)
|
for (size_t i = 0; i < size(actions); ++i)
|
||||||
{
|
{
|
||||||
std::visit(overloaded{
|
std::visit(overloaded{
|
||||||
[&](const link_button& b) {
|
[&](const link_button& b) {
|
||||||
toast_xml += LR"(<action activationType="protocol" arguments=")";
|
toast_xml += LR"(<action activationType="protocol" )";
|
||||||
|
if (b.context_menu)
|
||||||
|
{
|
||||||
|
toast_xml += LR"(placement="contextMenu" )";
|
||||||
|
}
|
||||||
|
toast_xml += LR"(arguments=")";
|
||||||
toast_xml += b.url;
|
toast_xml += b.url;
|
||||||
toast_xml += LR"(" content=")";
|
toast_xml += LR"(" content=")";
|
||||||
toast_xml += b.label;
|
toast_xml += b.label;
|
||||||
toast_xml += LR"("/>)";
|
toast_xml += LR"(" />)";
|
||||||
},
|
},
|
||||||
[&](const background_activated_button& b) {
|
[&](const background_activated_button& b) {
|
||||||
toast_xml += LR"(<action activationType="background" arguments=")";
|
toast_xml += LR"(<action activationType="background" )";
|
||||||
|
if (b.context_menu)
|
||||||
|
{
|
||||||
|
toast_xml += LR"(placement="contextMenu" )";
|
||||||
|
}
|
||||||
|
toast_xml += LR"(arguments=")";
|
||||||
toast_xml += L"button_id=" + std::to_wstring(i); // pass the button ID
|
toast_xml += L"button_id=" + std::to_wstring(i); // pass the button ID
|
||||||
toast_xml += L"&handler=";
|
toast_xml += L"&handler=";
|
||||||
toast_xml += background_handler_id;
|
toast_xml += background_handler_id;
|
||||||
toast_xml += LR"(" content=")";
|
toast_xml += LR"(" content=")";
|
||||||
toast_xml += b.label;
|
toast_xml += b.label;
|
||||||
toast_xml += LR"("/>)";
|
toast_xml += LR"(" />)";
|
||||||
},
|
},
|
||||||
},
|
[&](const snooze_button& b) {
|
||||||
buttons[i]);
|
const bool has_durations = !b.durations.empty() && size(b.durations) <= 5;
|
||||||
|
std::wstring selection_id = L"snoozeTime";
|
||||||
|
selection_id += static_cast<wchar_t>(L'0' + i);
|
||||||
|
toast_xml += LR"(<action activationType="system" arguments="snooze" )";
|
||||||
|
if (has_durations)
|
||||||
|
{
|
||||||
|
toast_xml += LR"(hint-inputId=")";
|
||||||
|
toast_xml += selection_id;
|
||||||
|
toast_xml += '"';
|
||||||
|
}
|
||||||
|
toast_xml += LR"( content="" />)";
|
||||||
|
} },
|
||||||
|
actions[i]);
|
||||||
}
|
}
|
||||||
toast_xml += L"</actions></toast>";
|
toast_xml += L"</actions></toast>";
|
||||||
|
|
||||||
@ -232,5 +282,22 @@ void notifications::show_toast_with_activations(std::wstring_view message, std::
|
|||||||
|
|
||||||
const auto notifier = winstore::running_as_packaged() ? ToastNotificationManager::ToastNotificationManager::CreateToastNotifier() :
|
const auto notifier = winstore::running_as_packaged() ? ToastNotificationManager::ToastNotificationManager::CreateToastNotifier() :
|
||||||
ToastNotificationManager::ToastNotificationManager::CreateToastNotifier(WIN32_AUMID);
|
ToastNotificationManager::ToastNotificationManager::CreateToastNotifier(WIN32_AUMID);
|
||||||
|
|
||||||
|
// Set a tag-related params if it has a valid length
|
||||||
|
if (params.tag.has_value() && params.tag->length() < 64)
|
||||||
|
{
|
||||||
|
notification.Tag(*params.tag);
|
||||||
|
if (!params.resend_if_scheduled)
|
||||||
|
{
|
||||||
|
for (const auto& scheduled_toast : notifier.GetScheduledToastNotifications())
|
||||||
|
{
|
||||||
|
if (scheduled_toast.Tag() == *params.tag)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
notifier.Show(notification);
|
notifier.Show(notification);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace notifications
|
namespace notifications
|
||||||
{
|
{
|
||||||
@ -12,19 +14,38 @@ namespace notifications
|
|||||||
|
|
||||||
void run_desktop_app_activator_loop();
|
void run_desktop_app_activator_loop();
|
||||||
|
|
||||||
|
struct snooze_duration
|
||||||
|
{
|
||||||
|
std::wstring label;
|
||||||
|
int minutes;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct snooze_button
|
||||||
|
{
|
||||||
|
std::vector<snooze_duration> durations;
|
||||||
|
};
|
||||||
|
|
||||||
struct link_button
|
struct link_button
|
||||||
{
|
{
|
||||||
std::wstring_view label;
|
std::wstring label;
|
||||||
std::wstring_view url;
|
std::wstring url;
|
||||||
|
bool context_menu = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct background_activated_button
|
struct background_activated_button
|
||||||
{
|
{
|
||||||
std::wstring_view label;
|
std::wstring label;
|
||||||
|
bool context_menu = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
using button_t = std::variant<link_button, background_activated_button>;
|
struct toast_params
|
||||||
|
{
|
||||||
|
std::optional<std::wstring_view> tag;
|
||||||
|
bool resend_if_scheduled = true;
|
||||||
|
};
|
||||||
|
|
||||||
void show_toast(std::wstring_view plaintext_message);
|
using action_t = std::variant<link_button, background_activated_button, snooze_button>;
|
||||||
void show_toast_with_activations(std::wstring_view plaintext_message, std::wstring_view background_handler_id, std::vector<button_t> buttons);
|
|
||||||
|
void show_toast(std::wstring plaintext_message, toast_params params = {});
|
||||||
|
void show_toast_with_activations(std::wstring plaintext_message, std::wstring_view background_handler_id, std::vector<action_t> actions, toast_params params = {});
|
||||||
}
|
}
|
||||||
|
71
src/common/notifications/fancyzones_notifications.h
Normal file
71
src/common/notifications/fancyzones_notifications.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#include "../timeutil.h"
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
const inline wchar_t CANT_DRAG_ELEVATED_DONT_SHOW_AGAIN_REGISTRY_PATH[] = LR"(SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\DontShowMeThisDialogAgain\{e16ea82f-6d94-4f30-bb02-d6d911588afd})";
|
||||||
|
const inline int64_t disable_interval_in_days = 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool disable_cant_drag_elevated_warning()
|
||||||
|
{
|
||||||
|
HKEY key{};
|
||||||
|
if (RegCreateKeyExW(HKEY_CURRENT_USER,
|
||||||
|
CANT_DRAG_ELEVATED_DONT_SHOW_AGAIN_REGISTRY_PATH,
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
REG_OPTION_NON_VOLATILE,
|
||||||
|
KEY_ALL_ACCESS,
|
||||||
|
nullptr,
|
||||||
|
&key,
|
||||||
|
nullptr) != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto now = timeutil::now();
|
||||||
|
const size_t buf_size = sizeof(now);
|
||||||
|
if (RegSetValueExW(key, nullptr, 0, REG_QWORD, reinterpret_cast<const BYTE*>(&now), sizeof(now)) != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
RegCloseKey(key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
RegCloseKey(key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_cant_drag_elevated_warning_disabled()
|
||||||
|
{
|
||||||
|
HKEY key{};
|
||||||
|
if (RegOpenKeyExW(HKEY_CURRENT_USER,
|
||||||
|
CANT_DRAG_ELEVATED_DONT_SHOW_AGAIN_REGISTRY_PATH,
|
||||||
|
0,
|
||||||
|
KEY_READ,
|
||||||
|
&key) != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::wstring buffer(std::numeric_limits<time_t>::digits10 + 2, L'\0');
|
||||||
|
time_t last_disabled_time{};
|
||||||
|
DWORD time_size = static_cast<DWORD>(sizeof(last_disabled_time));
|
||||||
|
if (RegGetValueW(
|
||||||
|
key,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
RRF_RT_REG_QWORD,
|
||||||
|
nullptr,
|
||||||
|
&last_disabled_time,
|
||||||
|
&time_size) != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
RegCloseKey(key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
RegCloseKey(key);
|
||||||
|
return timeutil::diff::in_days(timeutil::now(), last_disabled_time) < disable_interval_in_days;
|
||||||
|
return false;
|
||||||
|
}
|
4
src/common/packages.config
Normal file
4
src/common/packages.config
Normal 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>
|
@ -1,5 +1,7 @@
|
|||||||
#include "window_helpers.h"
|
#include "window_helpers.h"
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
|
#include <wil/Resource.h>
|
||||||
|
|
||||||
|
|
||||||
HWND CreateMsgWindow(_In_ HINSTANCE hInst, _In_ WNDPROC pfnWndProc, _In_ void* p)
|
HWND CreateMsgWindow(_In_ HINSTANCE hInst, _In_ WNDPROC pfnWndProc, _In_ void* p)
|
||||||
{
|
{
|
||||||
@ -27,4 +29,32 @@ HWND CreateMsgWindow(_In_ HINSTANCE hInst, _In_ WNDPROC pfnWndProc, _In_ void* p
|
|||||||
}
|
}
|
||||||
|
|
||||||
return hwnd;
|
return hwnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsProcessOfWindowElevated(HWND window)
|
||||||
|
{
|
||||||
|
DWORD pid = 0;
|
||||||
|
GetWindowThreadProcessId(window, &pid);
|
||||||
|
if (!pid)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wil::unique_handle hProcess{ OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,
|
||||||
|
FALSE,
|
||||||
|
pid) };
|
||||||
|
|
||||||
|
wil::unique_handle token;
|
||||||
|
bool elevated = false;
|
||||||
|
|
||||||
|
if (OpenProcessToken(hProcess.get(), TOKEN_QUERY, &token))
|
||||||
|
{
|
||||||
|
TOKEN_ELEVATION elevation;
|
||||||
|
DWORD size;
|
||||||
|
if (GetTokenInformation(token.get(), TokenElevation, &elevation, sizeof(elevation), &size))
|
||||||
|
{
|
||||||
|
return elevation.TokenIsElevated != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
HWND CreateMsgWindow(_In_ HINSTANCE hInst, _In_ WNDPROC pfnWndProc, _In_ void* p);
|
HWND CreateMsgWindow(_In_ HINSTANCE hInst, _In_ WNDPROC pfnWndProc, _In_ void* p);
|
||||||
|
|
||||||
|
// If HWND is already dead, we assume it wasn't elevated
|
||||||
|
bool IsProcessOfWindowElevated(HWND window);
|
@ -12,9 +12,13 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <common/common.h>
|
#include <common/common.h>
|
||||||
#include <lib\util.h>
|
#include <common/window_helpers.h>
|
||||||
|
#include <common/notifications.h>
|
||||||
|
#include <lib/util.h>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
|
#include <common/notifications/fancyzones_notifications.h>
|
||||||
|
|
||||||
enum class DisplayChangeType
|
enum class DisplayChangeType
|
||||||
{
|
{
|
||||||
WorkArea,
|
WorkArea,
|
||||||
@ -24,6 +28,8 @@ enum class DisplayChangeType
|
|||||||
Initialization
|
Initialization
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||||
|
|
||||||
namespace std
|
namespace std
|
||||||
{
|
{
|
||||||
template<>
|
template<>
|
||||||
@ -176,7 +182,7 @@ private:
|
|||||||
bool IsInterestingWindow(HWND window) noexcept;
|
bool IsInterestingWindow(HWND window) noexcept;
|
||||||
void UpdateZoneWindows() noexcept;
|
void UpdateZoneWindows() noexcept;
|
||||||
void MoveWindowsOnDisplayChange() noexcept;
|
void MoveWindowsOnDisplayChange() noexcept;
|
||||||
void UpdateDragState(require_write_lock) noexcept;
|
void UpdateDragState(HWND window, require_write_lock) noexcept;
|
||||||
void CycleActiveZoneSet(DWORD vkCode) noexcept;
|
void CycleActiveZoneSet(DWORD vkCode) noexcept;
|
||||||
bool OnSnapHotkey(DWORD vkCode) noexcept;
|
bool OnSnapHotkey(DWORD vkCode) noexcept;
|
||||||
void MoveSizeStartInternal(HWND window, HMONITOR monitor, POINT const& ptScreen, require_write_lock) noexcept;
|
void MoveSizeStartInternal(HWND window, HMONITOR monitor, POINT const& ptScreen, require_write_lock) noexcept;
|
||||||
@ -807,7 +813,7 @@ void FancyZones::MoveWindowsOnDisplayChange() noexcept
|
|||||||
EnumWindows(callback, reinterpret_cast<LPARAM>(this));
|
EnumWindows(callback, reinterpret_cast<LPARAM>(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FancyZones::UpdateDragState(require_write_lock) noexcept
|
void FancyZones::UpdateDragState(HWND window, require_write_lock) noexcept
|
||||||
{
|
{
|
||||||
const bool shift = GetAsyncKeyState(VK_SHIFT) & 0x8000;
|
const bool shift = GetAsyncKeyState(VK_SHIFT) & 0x8000;
|
||||||
const bool mouseL = GetAsyncKeyState(VK_LBUTTON) & 0x8000;
|
const bool mouseL = GetAsyncKeyState(VK_LBUTTON) & 0x8000;
|
||||||
@ -836,6 +842,23 @@ void FancyZones::UpdateDragState(require_write_lock) noexcept
|
|||||||
{
|
{
|
||||||
m_dragEnabled = !(shift | mouse);
|
m_dragEnabled = !(shift | mouse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool windowElevated = IsProcessOfWindowElevated(window);
|
||||||
|
static const bool meElevated = is_process_elevated();
|
||||||
|
static bool warning_shown = false;
|
||||||
|
if (windowElevated && !meElevated)
|
||||||
|
{
|
||||||
|
m_dragEnabled = false;
|
||||||
|
if (!warning_shown && !is_cant_drag_elevated_warning_disabled())
|
||||||
|
{
|
||||||
|
std::vector<notifications::action_t> actions = {
|
||||||
|
notifications::link_button{ GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_LEARN_MORE), L"https://aka.ms/powertoysDetectedElevatedHelp" },
|
||||||
|
notifications::link_button{ GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN), L"powertoys://cant_drag_elevated_disable/" }
|
||||||
|
};
|
||||||
|
notifications::show_toast_with_activations(GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED), {}, std::move(actions));
|
||||||
|
warning_shown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FancyZones::CycleActiveZoneSet(DWORD vkCode) noexcept
|
void FancyZones::CycleActiveZoneSet(DWORD vkCode) noexcept
|
||||||
@ -936,7 +959,7 @@ void FancyZones::MoveSizeStartInternal(HWND window, HMONITOR monitor, POINT cons
|
|||||||
m_windowMoveSize = window;
|
m_windowMoveSize = window;
|
||||||
|
|
||||||
// This updates m_dragEnabled depending on if the shift key is being held down.
|
// This updates m_dragEnabled depending on if the shift key is being held down.
|
||||||
UpdateDragState(writeLock);
|
UpdateDragState(window, writeLock);
|
||||||
|
|
||||||
if (m_dragEnabled)
|
if (m_dragEnabled)
|
||||||
{
|
{
|
||||||
@ -1019,7 +1042,7 @@ void FancyZones::MoveSizeUpdateInternal(HMONITOR monitor, POINT const& ptScreen,
|
|||||||
if (m_inMoveSize)
|
if (m_inMoveSize)
|
||||||
{
|
{
|
||||||
// This updates m_dragEnabled depending on if the shift key is being held down.
|
// This updates m_dragEnabled depending on if the shift key is being held down.
|
||||||
UpdateDragState(writeLock);
|
UpdateDragState(m_windowMoveSize, writeLock);
|
||||||
|
|
||||||
if (m_zoneWindowMoveSize)
|
if (m_zoneWindowMoveSize)
|
||||||
{
|
{
|
||||||
@ -1226,4 +1249,4 @@ winrt::com_ptr<IFancyZones> MakeFancyZones(HINSTANCE hinstance, const winrt::com
|
|||||||
}
|
}
|
||||||
|
|
||||||
return winrt::make_self<FancyZones>(hinstance, settings);
|
return winrt::make_self<FancyZones>(hinstance, settings);
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,10 @@ BEGIN
|
|||||||
IDS_SETTING_EXCLCUDED_APPS_DESCRIPTION "To exclude an application from snapping to zones add its name here (one per line). Excluded apps will react to the Windows Snap regardless of all other settings."
|
IDS_SETTING_EXCLCUDED_APPS_DESCRIPTION "To exclude an application from snapping to zones add its name here (one per line). Excluded apps will react to the Windows Snap regardless of all other settings."
|
||||||
IDS_SETTINGS_HIGHLIGHT_OPACITY "Zone opacity (%)"
|
IDS_SETTINGS_HIGHLIGHT_OPACITY "Zone opacity (%)"
|
||||||
IDS_FANCYZONES L"FancyZones"
|
IDS_FANCYZONES L"FancyZones"
|
||||||
|
IDS_CANT_DRAG_ELEVATED L"We've detected an application running with administrator privileges. This blocks some functionality in PowerToys. Visit our wiki page to learn more."
|
||||||
|
IDS_CANT_DRAG_ELEVATED_LEARN_MORE L"Learn more"
|
||||||
|
IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN L"Don't show again"
|
||||||
|
|
||||||
END
|
END
|
||||||
|
|
||||||
1 VERSIONINFO
|
1 VERSIONINFO
|
||||||
|
@ -19,3 +19,6 @@
|
|||||||
#define IDS_SETTING_EXCLCUDED_APPS_DESCRIPTION 119
|
#define IDS_SETTING_EXCLCUDED_APPS_DESCRIPTION 119
|
||||||
#define IDS_SETTINGS_HIGHLIGHT_OPACITY 120
|
#define IDS_SETTINGS_HIGHLIGHT_OPACITY 120
|
||||||
#define IDS_FANCYZONES 121
|
#define IDS_FANCYZONES 121
|
||||||
|
#define IDS_CANT_DRAG_ELEVATED 122
|
||||||
|
#define IDS_CANT_DRAG_ELEVATED_LEARN_MORE 123
|
||||||
|
#define IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN 124
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#if _DEBUG && _WIN64
|
#if _DEBUG && _WIN64
|
||||||
#include "unhandled_exception_handler.h"
|
#include "unhandled_exception_handler.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include <common/notifications/fancyzones_notifications.h>
|
||||||
|
|
||||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||||
|
|
||||||
@ -39,6 +40,8 @@ namespace
|
|||||||
{
|
{
|
||||||
const wchar_t MSI_VERSION_MUTEX_NAME[] = L"Local\\PowerToyRunMutex";
|
const wchar_t MSI_VERSION_MUTEX_NAME[] = L"Local\\PowerToyRunMutex";
|
||||||
const wchar_t MSIX_VERSION_MUTEX_NAME[] = L"Local\\PowerToyMSIXRunMutex";
|
const wchar_t MSIX_VERSION_MUTEX_NAME[] = L"Local\\PowerToyMSIXRunMutex";
|
||||||
|
|
||||||
|
const wchar_t PT_URI_PROTOCOL_SCHEME[] = L"powertoys://";
|
||||||
}
|
}
|
||||||
|
|
||||||
void chdir_current_executable()
|
void chdir_current_executable()
|
||||||
@ -116,7 +119,7 @@ std::future<void> check_github_updates()
|
|||||||
std::wstring contents = GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT;
|
std::wstring contents = GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT;
|
||||||
contents += new_version->version_string;
|
contents += new_version->version_string;
|
||||||
contents += L'.';
|
contents += L'.';
|
||||||
notifications::show_toast_with_activations(contents, {}, { notifications::link_button{ GITHUB_NEW_VERSION_AGREE, new_version->release_page_uri.ToString() } });
|
notifications::show_toast_with_activations(std::move(contents), {}, { notifications::link_button{ GITHUB_NEW_VERSION_AGREE, new_version->release_page_uri.ToString().c_str() } });
|
||||||
}
|
}
|
||||||
|
|
||||||
void github_update_checking_worker()
|
void github_update_checking_worker()
|
||||||
@ -228,17 +231,22 @@ int runner(bool isProcessElevated)
|
|||||||
enum class SpecialMode
|
enum class SpecialMode
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
Win32ToastNotificationCOMServer
|
Win32ToastNotificationCOMServer,
|
||||||
|
ToastNotificationHandler
|
||||||
};
|
};
|
||||||
|
|
||||||
SpecialMode should_run_in_special_mode()
|
SpecialMode should_run_in_special_mode(const int n_cmd_args, LPWSTR* cmd_arg_list)
|
||||||
{
|
{
|
||||||
int nArgs;
|
for (size_t i = 1; i < n_cmd_args; ++i)
|
||||||
LPWSTR* szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
|
|
||||||
for (size_t i = 1; i < nArgs; ++i)
|
|
||||||
{
|
{
|
||||||
if (!wcscmp(notifications::TOAST_ACTIVATED_LAUNCH_ARG, szArglist[i]))
|
if (!wcscmp(notifications::TOAST_ACTIVATED_LAUNCH_ARG, cmd_arg_list[i]))
|
||||||
|
{
|
||||||
return SpecialMode::Win32ToastNotificationCOMServer;
|
return SpecialMode::Win32ToastNotificationCOMServer;
|
||||||
|
}
|
||||||
|
else if (n_cmd_args == 2 && !wcsncmp(PT_URI_PROTOCOL_SCHEME, cmd_arg_list[i], wcslen(PT_URI_PROTOCOL_SCHEME)))
|
||||||
|
{
|
||||||
|
return SpecialMode::ToastNotificationHandler;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SpecialMode::None;
|
return SpecialMode::None;
|
||||||
@ -250,14 +258,42 @@ int win32_toast_notification_COM_server_mode()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class toast_notification_handler_result
|
||||||
|
{
|
||||||
|
exit_success,
|
||||||
|
exit_error
|
||||||
|
};
|
||||||
|
|
||||||
|
toast_notification_handler_result toast_notification_handler(const std::wstring_view param)
|
||||||
|
{
|
||||||
|
if (param == L"cant_drag_elevated_disable/")
|
||||||
|
{
|
||||||
|
return disable_cant_drag_elevated_warning() ? toast_notification_handler_result::exit_success : toast_notification_handler_result::exit_error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return toast_notification_handler_result::exit_error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
||||||
{
|
{
|
||||||
winrt::init_apartment();
|
winrt::init_apartment();
|
||||||
|
|
||||||
switch (should_run_in_special_mode())
|
int n_cmd_args = 0;
|
||||||
|
LPWSTR* cmd_arg_list = CommandLineToArgvW(GetCommandLineW(), &n_cmd_args);
|
||||||
|
switch (should_run_in_special_mode(n_cmd_args, cmd_arg_list))
|
||||||
{
|
{
|
||||||
case SpecialMode::Win32ToastNotificationCOMServer:
|
case SpecialMode::Win32ToastNotificationCOMServer:
|
||||||
return win32_toast_notification_COM_server_mode();
|
return win32_toast_notification_COM_server_mode();
|
||||||
|
case SpecialMode::ToastNotificationHandler:
|
||||||
|
switch (toast_notification_handler(cmd_arg_list[1] + wcslen(PT_URI_PROTOCOL_SCHEME)))
|
||||||
|
{
|
||||||
|
case toast_notification_handler_result::exit_error:
|
||||||
|
return 1;
|
||||||
|
case toast_notification_handler_result::exit_success:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
case SpecialMode::None:
|
case SpecialMode::None:
|
||||||
// continue as usual
|
// continue as usual
|
||||||
break;
|
break;
|
||||||
@ -339,12 +375,12 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
|
|
||||||
auto general_settings = load_general_settings();
|
auto general_settings = load_general_settings();
|
||||||
int rvalue = 0;
|
int rvalue = 0;
|
||||||
bool isProcessElevated = is_process_elevated();
|
const bool elevated = is_process_elevated();
|
||||||
if (isProcessElevated ||
|
if ((elevated ||
|
||||||
general_settings.GetNamedBoolean(L"run_elevated", false) == false ||
|
general_settings.GetNamedBoolean(L"run_elevated", false) == false ||
|
||||||
strcmp(lpCmdLine, "--dont-elevate") == 0)
|
strcmp(lpCmdLine, "--dont-elevate") == 0))
|
||||||
{
|
{
|
||||||
result = runner(isProcessElevated);
|
result = runner(elevated);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user