mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 18:57:19 +02:00
PowerAccent-21531: support excluded apps (#22004)
This commit is contained in:
@@ -56,6 +56,9 @@ public class SettingsService
|
||||
InputTime = settings.Properties.InputTime.Value;
|
||||
_keyboardListener.UpdateInputTime(InputTime);
|
||||
|
||||
ExcludedApps = settings.Properties.ExcludedApps.Value;
|
||||
_keyboardListener.UpdateExcludedApps(ExcludedApps);
|
||||
|
||||
SelectedLang = Enum.TryParse(settings.Properties.SelectedLang.Value, out Language selectedLangValue) ? selectedLangValue : Language.ALL;
|
||||
|
||||
switch (settings.Properties.ToolbarPosition.Value)
|
||||
@@ -143,6 +146,21 @@ public class SettingsService
|
||||
}
|
||||
}
|
||||
|
||||
private string _excludedApps;
|
||||
|
||||
public string ExcludedApps
|
||||
{
|
||||
get
|
||||
{
|
||||
return _excludedApps;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_excludedApps = value;
|
||||
}
|
||||
}
|
||||
|
||||
private Language _selectedLang;
|
||||
|
||||
public Language SelectedLang
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include <common/utils/string_utils.h>
|
||||
#include <common/utils/process_path.h>
|
||||
#include <common/utils/excluded_apps.h>
|
||||
|
||||
namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
||||
{
|
||||
@@ -87,12 +90,64 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
||||
m_settings.inputTime = std::chrono::milliseconds(inputTime);
|
||||
}
|
||||
|
||||
void KeyboardListener::UpdateExcludedApps(std::wstring_view excludedAppsView)
|
||||
{
|
||||
std::vector<std::wstring> excludedApps;
|
||||
auto excludedUppercase = std::wstring(excludedAppsView);
|
||||
CharUpperBuffW(excludedUppercase.data(), (DWORD)excludedUppercase.length());
|
||||
std::wstring_view view(excludedUppercase);
|
||||
view = left_trim<wchar_t>(trim<wchar_t>(view));
|
||||
|
||||
while (!view.empty())
|
||||
{
|
||||
auto pos = (std::min)(view.find_first_of(L"\r\n"), view.length());
|
||||
excludedApps.emplace_back(view.substr(0, pos));
|
||||
view.remove_prefix(pos);
|
||||
view = left_trim<wchar_t>(trim<wchar_t>(view));
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex_excluded_apps);
|
||||
m_settings.excludedApps = std::move(excludedApps);
|
||||
m_prevForegrndAppExcl = { NULL, false };
|
||||
}
|
||||
}
|
||||
|
||||
bool KeyboardListener::IsForegroundAppExcluded()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex_excluded_apps);
|
||||
|
||||
if (m_settings.excludedApps.empty())
|
||||
{
|
||||
m_prevForegrndAppExcl = { NULL, false };
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HWND foregroundApp{ GetForegroundWindow() })
|
||||
{
|
||||
if (m_prevForegrndAppExcl.first == foregroundApp)
|
||||
{
|
||||
return m_prevForegrndAppExcl.second;
|
||||
}
|
||||
auto processPath = get_process_path(foregroundApp);
|
||||
CharUpperBuffW(processPath.data(), (DWORD)processPath.length());
|
||||
m_prevForegrndAppExcl = { foregroundApp,
|
||||
find_app_name_in_path(processPath, m_settings.excludedApps) };
|
||||
|
||||
return m_prevForegrndAppExcl.second;
|
||||
}
|
||||
|
||||
m_prevForegrndAppExcl = { NULL, false };
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KeyboardListener::OnKeyDown(KBDLLHOOKSTRUCT info) noexcept
|
||||
{
|
||||
if (std::find(std::begin(letters), end(letters), static_cast<LetterKey>(info.vkCode)) != end(letters) && m_isLanguageLetterCb(static_cast<LetterKey>(info.vkCode)))
|
||||
auto letterKey = static_cast<LetterKey>(info.vkCode);
|
||||
if (std::find(letters.begin(), letters.end(), letterKey) != cend(letters) && m_isLanguageLetterCb(letterKey))
|
||||
{
|
||||
m_stopwatch.reset();
|
||||
letterPressed = static_cast<LetterKey>(info.vkCode);
|
||||
letterPressed = letterKey;
|
||||
}
|
||||
|
||||
UINT triggerPressed = 0;
|
||||
@@ -106,19 +161,18 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
||||
((triggerPressed == VK_LEFT || triggerPressed == VK_RIGHT) && m_settings.activationKey == PowerAccentActivationKey::Space))
|
||||
{
|
||||
triggerPressed = 0;
|
||||
Logger::info(L"Reset trigger key");
|
||||
Logger::debug(L"Reset trigger key");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_toolbarVisible && letterPressed != LetterKey::None && triggerPressed)
|
||||
if (!m_toolbarVisible && letterPressed != LetterKey::None && triggerPressed && !IsForegroundAppExcluded())
|
||||
{
|
||||
Logger::info(L"Show toolbar. Letter: %d, Trigger: %d", letterPressed, triggerPressed);
|
||||
Logger::debug(L"Show toolbar. Letter: {}, Trigger: {}", letterPressed, triggerPressed);
|
||||
|
||||
// Keep track if it was triggered with space so that it can be typed on false starts.
|
||||
m_triggeredWithSpace = triggerPressed == VK_SPACE;
|
||||
m_toolbarVisible = true;
|
||||
|
||||
m_showToolbarCb(letterPressed);
|
||||
}
|
||||
|
||||
@@ -126,17 +180,17 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
||||
{
|
||||
if (triggerPressed == VK_LEFT)
|
||||
{
|
||||
Logger::info(L"Next toolbar position - left");
|
||||
Logger::debug(L"Next toolbar position - left");
|
||||
m_nextCharCb(TriggerKey::Left);
|
||||
}
|
||||
else if (triggerPressed == VK_RIGHT)
|
||||
{
|
||||
Logger::info(L"Next toolbar position - right");
|
||||
Logger::debug(L"Next toolbar position - right");
|
||||
m_nextCharCb(TriggerKey::Right);
|
||||
}
|
||||
else if (triggerPressed == VK_SPACE)
|
||||
{
|
||||
Logger::info(L"Next toolbar position - space");
|
||||
Logger::debug(L"Next toolbar position - space");
|
||||
m_nextCharCb(TriggerKey::Space);
|
||||
}
|
||||
|
||||
@@ -156,7 +210,7 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
||||
{
|
||||
if (m_stopwatch.elapsed() < m_settings.inputTime)
|
||||
{
|
||||
Logger::info(L"Activation too fast. Do nothing.");
|
||||
Logger::debug(L"Activation too fast. Do nothing.");
|
||||
|
||||
// False start, we should output the space if it was the trigger.
|
||||
if (m_triggeredWithSpace)
|
||||
@@ -167,12 +221,10 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
||||
{
|
||||
m_hideToolbarCb(InputType::None);
|
||||
}
|
||||
|
||||
m_toolbarVisible = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Logger::info(L"Hide toolbar event and input char");
|
||||
Logger::debug(L"Hide toolbar event and input char");
|
||||
|
||||
m_hideToolbarCb(InputType::Char);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
||||
{
|
||||
PowerAccentActivationKey activationKey{ PowerAccentActivationKey::Both };
|
||||
std::chrono::milliseconds inputTime{ 200 };
|
||||
std::vector<std::wstring> excludedApps;
|
||||
};
|
||||
|
||||
struct KeyboardListener : KeyboardListenerT<KeyboardListener>
|
||||
@@ -36,12 +37,14 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
||||
|
||||
void UpdateActivationKey(int32_t activationKey);
|
||||
void UpdateInputTime(int32_t inputTime);
|
||||
void UpdateExcludedApps(std::wstring_view excludedApps);
|
||||
|
||||
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
private:
|
||||
bool OnKeyDown(KBDLLHOOKSTRUCT info) noexcept;
|
||||
bool OnKeyUp(KBDLLHOOKSTRUCT info) noexcept;
|
||||
bool IsForegroundAppExcluded();
|
||||
|
||||
static inline KeyboardListener* s_instance;
|
||||
HHOOK s_llKeyboardHook = nullptr;
|
||||
@@ -54,6 +57,9 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
||||
bool m_triggeredWithSpace;
|
||||
spdlog::stopwatch m_stopwatch;
|
||||
|
||||
std::mutex m_mutex_excluded_apps;
|
||||
std::pair<HWND, bool> m_prevForegrndAppExcl{ NULL, false };
|
||||
|
||||
static inline const std::vector<LetterKey> letters = { LetterKey::VK_0,
|
||||
LetterKey::VK_1,
|
||||
LetterKey::VK_2,
|
||||
|
||||
@@ -73,6 +73,7 @@ namespace PowerToys
|
||||
void SetIsLanguageLetterDelegate(IsLanguageLetter isLanguageLetterDelegate);
|
||||
void UpdateActivationKey(Int32 activationKey);
|
||||
void UpdateInputTime(Int32 inputTime);
|
||||
void UpdateExcludedApps(String excludedApps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,12 +21,16 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
[JsonPropertyName("selected_lang")]
|
||||
public StringProperty SelectedLang { get; set; }
|
||||
|
||||
[JsonPropertyName("excluded_apps")]
|
||||
public StringProperty ExcludedApps { get; set; }
|
||||
|
||||
public PowerAccentProperties()
|
||||
{
|
||||
ActivationKey = PowerAccentActivationKey.Both;
|
||||
ToolbarPosition = "Top center";
|
||||
InputTime = new IntProperty(200);
|
||||
SelectedLang = "ALL";
|
||||
ExcludedApps = new StringProperty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2420,6 +2420,15 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<value>Hold the key down for this much time to make the accent menu appear (ms)</value>
|
||||
<comment>ms = milliseconds</comment>
|
||||
</data>
|
||||
<data name="QuickAccent_ExcludedApps.Description" xml:space="preserve">
|
||||
<value>Prevents module activation if a foreground application is excluded. Add one application name per line.</value>
|
||||
</data>
|
||||
<data name="QuickAccent_ExcludedApps.Header" xml:space="preserve">
|
||||
<value>Excluded apps</value>
|
||||
</data>
|
||||
<data name="QuickAccent_ExcludedApps_TextBoxControl.PlaceholderText" xml:space="preserve">
|
||||
<value>Example: Teams.exe</value>
|
||||
</data>
|
||||
<data name="LearnMore_TextExtractor.Text" xml:space="preserve">
|
||||
<value>Learn more about Text Extractor</value>
|
||||
</data>
|
||||
|
||||
@@ -90,6 +90,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
|
||||
_inputTimeMs = _powerAccentSettings.Properties.InputTime.Value;
|
||||
|
||||
_excludedApps = _powerAccentSettings.Properties.ExcludedApps.Value;
|
||||
|
||||
_selectedLangIndex = Array.IndexOf(_languageOptions, _powerAccentSettings.Properties.SelectedLang.Value);
|
||||
|
||||
_toolbarPositionIndex = Array.IndexOf(_toolbarOptions, _powerAccentSettings.Properties.ToolbarPosition.Value);
|
||||
@@ -165,6 +167,27 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
private string _excludedApps;
|
||||
|
||||
public string ExcludedApps
|
||||
{
|
||||
get
|
||||
{
|
||||
return _excludedApps;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value != _excludedApps)
|
||||
{
|
||||
_excludedApps = value;
|
||||
_powerAccentSettings.Properties.ExcludedApps.Value = value;
|
||||
OnPropertyChanged(nameof(ExcludedApps));
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int _toolbarPositionIndex;
|
||||
|
||||
public int ToolbarPositionIndex
|
||||
|
||||
@@ -103,6 +103,24 @@
|
||||
LargeChange="100"/>
|
||||
</controls:Setting.ActionContent>
|
||||
</controls:Setting>
|
||||
<controls:SettingExpander IsExpanded="False">
|
||||
<controls:SettingExpander.Header>
|
||||
<controls:Setting x:Uid="QuickAccent_ExcludedApps" Icon="" IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}" Style="{StaticResource ExpanderHeaderSettingStyle}"/>
|
||||
</controls:SettingExpander.Header>
|
||||
<controls:SettingExpander.Content>
|
||||
<TextBox x:Uid="QuickAccent_ExcludedApps_TextBoxControl"
|
||||
Margin="{StaticResource ExpanderSettingMargin}"
|
||||
Text="{x:Bind Mode=TwoWay, Path=ViewModel.ExcludedApps, UpdateSourceTrigger=PropertyChanged}"
|
||||
ScrollViewer.VerticalScrollBarVisibility ="Visible"
|
||||
ScrollViewer.VerticalScrollMode="Enabled"
|
||||
ScrollViewer.IsVerticalRailEnabled="True"
|
||||
TextWrapping="Wrap"
|
||||
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"
|
||||
AcceptsReturn="True"
|
||||
MinWidth="240"
|
||||
MinHeight="160" />
|
||||
</controls:SettingExpander.Content>
|
||||
</controls:SettingExpander>
|
||||
</controls:SettingsGroup>
|
||||
</StackPanel>
|
||||
</controls:SettingsPageControl.ModuleContent>
|
||||
|
||||
Reference in New Issue
Block a user