mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 19:57:57 +01:00
disable apps for shortcut guide (#10123)
This commit is contained in:
committed by
GitHub
parent
6561290bde
commit
bc28a3f5e3
@@ -14,8 +14,10 @@
|
|||||||
#include <common/logger/logger.h>
|
#include <common/logger/logger.h>
|
||||||
#include <common/utils/process_path.h>
|
#include <common/utils/process_path.h>
|
||||||
#include <common/utils/resources.h>
|
#include <common/utils/resources.h>
|
||||||
|
#include <common/utils/string_utils.h>
|
||||||
#include <common/utils/winapi_error.h>
|
#include <common/utils/winapi_error.h>
|
||||||
#include <common/utils/window.h>
|
#include <common/utils/window.h>
|
||||||
|
#include <Psapi.h>
|
||||||
// TODO: refactor singleton
|
// TODO: refactor singleton
|
||||||
OverlayWindow* instance = nullptr;
|
OverlayWindow* instance = nullptr;
|
||||||
|
|
||||||
@@ -41,6 +43,7 @@ namespace
|
|||||||
{
|
{
|
||||||
HWND hwnd = nullptr; // Handle to the top-level foreground window or nullptr if there is no such window
|
HWND hwnd = nullptr; // Handle to the top-level foreground window or nullptr if there is no such window
|
||||||
bool snappable = false; // True, if the window can react to Windows Snap keys
|
bool snappable = false; // True, if the window can react to Windows Snap keys
|
||||||
|
bool disabled = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
ShortcutGuideWindowInfo GetShortcutGuideWindowInfo()
|
ShortcutGuideWindowInfo GetShortcutGuideWindowInfo()
|
||||||
@@ -52,6 +55,18 @@ namespace
|
|||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WCHAR exePath[MAX_PATH] = L"";
|
||||||
|
instance->get_exe_path(active_window, exePath);
|
||||||
|
if (wcslen(exePath) > 0)
|
||||||
|
{
|
||||||
|
result.disabled = instance->is_disabled_app(exePath);
|
||||||
|
if (result.disabled)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto style = GetWindowLong(active_window, GWL_STYLE);
|
auto style = GetWindowLong(active_window, GWL_STYLE);
|
||||||
auto exStyle = GetWindowLong(active_window, GWL_EXSTYLE);
|
auto exStyle = GetWindowLong(active_window, GWL_EXSTYLE);
|
||||||
if ((style & WS_CHILD) == WS_CHILD ||
|
if ((style & WS_CHILD) == WS_CHILD ||
|
||||||
@@ -193,6 +208,11 @@ void OverlayWindow::set_config(const wchar_t* config)
|
|||||||
winkey_popup->set_theme(theme.value);
|
winkey_popup->set_theme(theme.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (auto val = _values.get_string_value(disabledApps.name))
|
||||||
|
{
|
||||||
|
disabledApps.value = std::move(*val);
|
||||||
|
update_disabled_apps();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
@@ -343,6 +363,11 @@ intptr_t OverlayWindow::signal_event(LowlevelKeyboardEvent* event)
|
|||||||
void OverlayWindow::on_held()
|
void OverlayWindow::on_held()
|
||||||
{
|
{
|
||||||
auto windowInfo = GetShortcutGuideWindowInfo();
|
auto windowInfo = GetShortcutGuideWindowInfo();
|
||||||
|
if (windowInfo.disabled)
|
||||||
|
{
|
||||||
|
target_state->was_hidden();
|
||||||
|
return;
|
||||||
|
}
|
||||||
winkey_popup->show(windowInfo.hwnd, windowInfo.snappable);
|
winkey_popup->show(windowInfo.hwnd, windowInfo.snappable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,9 +416,72 @@ void OverlayWindow::init_settings()
|
|||||||
{
|
{
|
||||||
theme.value = std::move(*val);
|
theme.value = std::move(*val);
|
||||||
}
|
}
|
||||||
|
if (auto val = settings.get_string_value(disabledApps.name))
|
||||||
|
{
|
||||||
|
disabledApps.value = std::move(*val);
|
||||||
|
update_disabled_apps();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception&)
|
catch (std::exception&)
|
||||||
{
|
{
|
||||||
// Error while loading from the settings file. Just let default values stay as they are.
|
// Error while loading from the settings file. Just let default values stay as they are.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OverlayWindow::is_disabled_app(wchar_t* exePath)
|
||||||
|
{
|
||||||
|
if (exePath == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto exePathUpper = std::wstring(exePath);
|
||||||
|
CharUpperBuffW(exePathUpper.data(), (DWORD)exePathUpper.length());
|
||||||
|
|
||||||
|
for (const auto& row : disabled_apps_array)
|
||||||
|
{
|
||||||
|
const auto pos = exePathUpper.rfind(row);
|
||||||
|
const auto last_slash = exePathUpper.rfind('\\');
|
||||||
|
// Check that row occurs in disabled_apps_array, and its last occurrence contains in itself the first character after the last backslash.
|
||||||
|
if (pos != std::wstring::npos && pos <= last_slash + 1 && pos + row.length() > last_slash)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayWindow::update_disabled_apps()
|
||||||
|
{
|
||||||
|
disabled_apps_array.clear();
|
||||||
|
auto disabledUppercase = disabledApps.value;
|
||||||
|
CharUpperBuffW(disabledUppercase.data(), (DWORD)disabledUppercase.length());
|
||||||
|
std::wstring_view view(disabledUppercase);
|
||||||
|
view = trim(view);
|
||||||
|
while (!view.empty())
|
||||||
|
{
|
||||||
|
auto pos = (std::min)(view.find_first_of(L"\r\n"), view.length());
|
||||||
|
disabled_apps_array.emplace_back(view.substr(0, pos));
|
||||||
|
view.remove_prefix(pos);
|
||||||
|
view = trim(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayWindow::get_exe_path(HWND window, wchar_t* path)
|
||||||
|
{
|
||||||
|
if (disabled_apps_array.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD pid = 0;
|
||||||
|
GetWindowThreadProcessId(window, &pid);
|
||||||
|
if (pid != 0)
|
||||||
|
{
|
||||||
|
HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
|
||||||
|
if (processHandle && GetProcessImageFileName(processHandle, path, MAX_PATH) > 0)
|
||||||
|
{
|
||||||
|
CloseHandle(processHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ public:
|
|||||||
|
|
||||||
bool overlay_visible() const;
|
bool overlay_visible() const;
|
||||||
|
|
||||||
|
bool is_disabled_app(wchar_t* exePath);
|
||||||
|
|
||||||
|
void get_exe_path(HWND window, wchar_t* exePath);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::wstring app_name;
|
std::wstring app_name;
|
||||||
//contains the non localized key of the powertoy
|
//contains the non localized key of the powertoy
|
||||||
@@ -46,9 +50,11 @@ private:
|
|||||||
bool _enabled = false;
|
bool _enabled = false;
|
||||||
HHOOK hook_handle;
|
HHOOK hook_handle;
|
||||||
std::unique_ptr<NativeEventWaiter> event_waiter;
|
std::unique_ptr<NativeEventWaiter> event_waiter;
|
||||||
|
std::vector<std::wstring> disabled_apps_array;
|
||||||
|
|
||||||
void init_settings();
|
void init_settings();
|
||||||
void disable(bool trace_event);
|
void disable(bool trace_event);
|
||||||
|
void update_disabled_apps();
|
||||||
|
|
||||||
struct PressTime
|
struct PressTime
|
||||||
{
|
{
|
||||||
@@ -75,4 +81,10 @@ private:
|
|||||||
{ L"dark", IDS_SETTING_DESCRIPTION_THEME_DARK }
|
{ L"dark", IDS_SETTING_DESCRIPTION_THEME_DARK }
|
||||||
};
|
};
|
||||||
} theme;
|
} theme;
|
||||||
|
|
||||||
|
struct DisabledApps
|
||||||
|
{
|
||||||
|
PCWSTR name = L"disabled_apps";
|
||||||
|
std::wstring value = L"";
|
||||||
|
} disabledApps;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
OverlayOpacity = new IntProperty(90);
|
OverlayOpacity = new IntProperty(90);
|
||||||
PressTime = new IntProperty(900);
|
PressTime = new IntProperty(900);
|
||||||
Theme = new StringProperty("system");
|
Theme = new StringProperty("system");
|
||||||
|
DisabledApps = new StringProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonPropertyName("overlay_opacity")]
|
[JsonPropertyName("overlay_opacity")]
|
||||||
@@ -23,5 +24,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
|
|
||||||
[JsonPropertyName("theme")]
|
[JsonPropertyName("theme")]
|
||||||
public StringProperty Theme { get; set; }
|
public StringProperty Theme { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("disabled_apps")]
|
||||||
|
public StringProperty DisabledApps { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
|||||||
private Func<string, int> SendConfigMSG { get; }
|
private Func<string, int> SendConfigMSG { get; }
|
||||||
|
|
||||||
private string _settingsConfigFileFolder = string.Empty;
|
private string _settingsConfigFileFolder = string.Empty;
|
||||||
|
private string _disabledApps;
|
||||||
|
|
||||||
public ShortcutGuideViewModel(ISettingsRepository<GeneralSettings> settingsRepository, ISettingsRepository<ShortcutGuideSettings> moduleSettingsRepository, Func<string, int> ipcMSGCallBackFunc, string configFileSubfolder = "")
|
public ShortcutGuideViewModel(ISettingsRepository<GeneralSettings> settingsRepository, ISettingsRepository<ShortcutGuideSettings> moduleSettingsRepository, Func<string, int> ipcMSGCallBackFunc, string configFileSubfolder = "")
|
||||||
{
|
{
|
||||||
@@ -49,6 +50,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
|||||||
_isEnabled = GeneralSettingsConfig.Enabled.ShortcutGuide;
|
_isEnabled = GeneralSettingsConfig.Enabled.ShortcutGuide;
|
||||||
_pressTime = Settings.Properties.PressTime.Value;
|
_pressTime = Settings.Properties.PressTime.Value;
|
||||||
_opacity = Settings.Properties.OverlayOpacity.Value;
|
_opacity = Settings.Properties.OverlayOpacity.Value;
|
||||||
|
_disabledApps = Settings.Properties.DisabledApps.Value;
|
||||||
|
|
||||||
string theme = Settings.Properties.Theme.Value;
|
string theme = Settings.Properties.Theme.Value;
|
||||||
|
|
||||||
@@ -170,6 +172,24 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string DisabledApps
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _disabledApps;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value != _disabledApps)
|
||||||
|
{
|
||||||
|
_disabledApps = value;
|
||||||
|
Settings.Properties.DisabledApps.Value = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string GetSettingsSubPath()
|
public string GetSettingsSubPath()
|
||||||
{
|
{
|
||||||
return _settingsConfigFileFolder + "\\" + ModuleName;
|
return _settingsConfigFileFolder + "\\" + ModuleName;
|
||||||
|
|||||||
@@ -491,6 +491,16 @@
|
|||||||
<data name="ShortcutGuide_OverlayOpacity.Header" xml:space="preserve">
|
<data name="ShortcutGuide_OverlayOpacity.Header" xml:space="preserve">
|
||||||
<value>Opacity of background</value>
|
<value>Opacity of background</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ShortcutGuide_DisabledApps.Text" xml:space="preserve">
|
||||||
|
<value>Disable for apps</value>
|
||||||
|
</data>
|
||||||
|
<data name="ShortcutGuide_DisabledApps_TextBoxControl.Header" xml:space="preserve">
|
||||||
|
<value>Turn off Shortcut Guide when these applications have focus. Add one application name per line.</value>
|
||||||
|
</data>
|
||||||
|
<data name="ShortcutGuide_DisabledApps_TextBoxControl.PlaceholderText" xml:space="preserve">
|
||||||
|
<value>Example: outlook.exe</value>
|
||||||
|
<comment>Don't translate outlook.exe</comment>
|
||||||
|
</data>
|
||||||
<data name="ImageResizer_CustomSizes.Text" xml:space="preserve">
|
<data name="ImageResizer_CustomSizes.Text" xml:space="preserve">
|
||||||
<value>Image sizes</value>
|
<value>Image sizes</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -793,6 +803,7 @@
|
|||||||
</data>
|
</data>
|
||||||
<data name="FancyZones_ExcludeApps_TextBoxControl.PlaceholderText" xml:space="preserve">
|
<data name="FancyZones_ExcludeApps_TextBoxControl.PlaceholderText" xml:space="preserve">
|
||||||
<value>Example: outlook.exe</value>
|
<value>Example: outlook.exe</value>
|
||||||
|
<comment>Don't translate outlook.exe</comment>
|
||||||
</data>
|
</data>
|
||||||
<data name="ImageResizer_FilenameFormatPlaceholder.PlaceholderText" xml:space="preserve">
|
<data name="ImageResizer_FilenameFormatPlaceholder.PlaceholderText" xml:space="preserve">
|
||||||
<value>Example: %1 (%2)</value>
|
<value>Example: %1 (%2)</value>
|
||||||
|
|||||||
@@ -111,6 +111,23 @@
|
|||||||
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}">
|
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}">
|
||||||
<TextBlock x:Uid="Windows_Color_Settings" />
|
<TextBlock x:Uid="Windows_Color_Settings" />
|
||||||
</HyperlinkButton>
|
</HyperlinkButton>
|
||||||
|
|
||||||
|
<TextBlock x:Uid="ShortcutGuide_DisabledApps"
|
||||||
|
Style="{StaticResource SettingsGroupTitleStyle}"
|
||||||
|
Foreground="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
|
||||||
|
|
||||||
|
<TextBox x:Uid="ShortcutGuide_DisabledApps_TextBoxControl"
|
||||||
|
Margin="{StaticResource SmallTopMargin}"
|
||||||
|
Text="{x:Bind Mode=TwoWay, Path=ViewModel.DisabledApps}"
|
||||||
|
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"
|
||||||
|
ScrollViewer.VerticalScrollBarVisibility ="Visible"
|
||||||
|
ScrollViewer.VerticalScrollMode="Enabled"
|
||||||
|
ScrollViewer.IsVerticalRailEnabled="True"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
AcceptsReturn="True"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
MinWidth="240"
|
||||||
|
MinHeight="160" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<RelativePanel x:Name="SidePanel"
|
<RelativePanel x:Name="SidePanel"
|
||||||
|
|||||||
Reference in New Issue
Block a user