PowerAccent-21531: support excluded apps (#22004)

This commit is contained in:
Taras
2022-11-15 14:47:52 +02:00
committed by GitHub
parent b482188782
commit a357d62ff5
8 changed files with 145 additions and 14 deletions

View File

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

View File

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

View File

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

View File

@@ -73,6 +73,7 @@ namespace PowerToys
void SetIsLanguageLetterDelegate(IsLanguageLetter isLanguageLetterDelegate);
void UpdateActivationKey(Int32 activationKey);
void UpdateInputTime(Int32 inputTime);
void UpdateExcludedApps(String excludedApps);
}
}
}
}

View File

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

View File

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

View File

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

View File

@@ -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="&#xECE4;" 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>