disable apps for shortcut guide (#10123)

This commit is contained in:
Davide Giacometti
2021-04-02 16:29:48 +02:00
committed by GitHub
parent 6561290bde
commit bc28a3f5e3
6 changed files with 152 additions and 0 deletions

View File

@@ -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);
}
}
}

View File

@@ -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;
}; };

View File

@@ -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; }
} }
} }

View File

@@ -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;

View File

@@ -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>

View File

@@ -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"