mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-10 21:41:51 +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;
|
InputTime = settings.Properties.InputTime.Value;
|
||||||
_keyboardListener.UpdateInputTime(InputTime);
|
_keyboardListener.UpdateInputTime(InputTime);
|
||||||
|
|
||||||
|
ExcludedApps = settings.Properties.ExcludedApps.Value;
|
||||||
|
_keyboardListener.UpdateExcludedApps(ExcludedApps);
|
||||||
|
|
||||||
SelectedLang = Enum.TryParse(settings.Properties.SelectedLang.Value, out Language selectedLangValue) ? selectedLangValue : Language.ALL;
|
SelectedLang = Enum.TryParse(settings.Properties.SelectedLang.Value, out Language selectedLangValue) ? selectedLangValue : Language.ALL;
|
||||||
|
|
||||||
switch (settings.Properties.ToolbarPosition.Value)
|
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;
|
private Language _selectedLang;
|
||||||
|
|
||||||
public Language SelectedLang
|
public Language SelectedLang
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
#include <common/logger/logger.h>
|
#include <common/logger/logger.h>
|
||||||
#include <common/utils/logger_helper.h>
|
#include <common/utils/logger_helper.h>
|
||||||
#include <common/utils/winapi_error.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
|
namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
||||||
{
|
{
|
||||||
@@ -87,12 +90,64 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
|||||||
m_settings.inputTime = std::chrono::milliseconds(inputTime);
|
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
|
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();
|
m_stopwatch.reset();
|
||||||
letterPressed = static_cast<LetterKey>(info.vkCode);
|
letterPressed = letterKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT triggerPressed = 0;
|
UINT triggerPressed = 0;
|
||||||
@@ -106,19 +161,18 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
|||||||
((triggerPressed == VK_LEFT || triggerPressed == VK_RIGHT) && m_settings.activationKey == PowerAccentActivationKey::Space))
|
((triggerPressed == VK_LEFT || triggerPressed == VK_RIGHT) && m_settings.activationKey == PowerAccentActivationKey::Space))
|
||||||
{
|
{
|
||||||
triggerPressed = 0;
|
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.
|
// Keep track if it was triggered with space so that it can be typed on false starts.
|
||||||
m_triggeredWithSpace = triggerPressed == VK_SPACE;
|
m_triggeredWithSpace = triggerPressed == VK_SPACE;
|
||||||
m_toolbarVisible = true;
|
m_toolbarVisible = true;
|
||||||
|
|
||||||
m_showToolbarCb(letterPressed);
|
m_showToolbarCb(letterPressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,17 +180,17 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
|||||||
{
|
{
|
||||||
if (triggerPressed == VK_LEFT)
|
if (triggerPressed == VK_LEFT)
|
||||||
{
|
{
|
||||||
Logger::info(L"Next toolbar position - left");
|
Logger::debug(L"Next toolbar position - left");
|
||||||
m_nextCharCb(TriggerKey::Left);
|
m_nextCharCb(TriggerKey::Left);
|
||||||
}
|
}
|
||||||
else if (triggerPressed == VK_RIGHT)
|
else if (triggerPressed == VK_RIGHT)
|
||||||
{
|
{
|
||||||
Logger::info(L"Next toolbar position - right");
|
Logger::debug(L"Next toolbar position - right");
|
||||||
m_nextCharCb(TriggerKey::Right);
|
m_nextCharCb(TriggerKey::Right);
|
||||||
}
|
}
|
||||||
else if (triggerPressed == VK_SPACE)
|
else if (triggerPressed == VK_SPACE)
|
||||||
{
|
{
|
||||||
Logger::info(L"Next toolbar position - space");
|
Logger::debug(L"Next toolbar position - space");
|
||||||
m_nextCharCb(TriggerKey::Space);
|
m_nextCharCb(TriggerKey::Space);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +210,7 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
|||||||
{
|
{
|
||||||
if (m_stopwatch.elapsed() < m_settings.inputTime)
|
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.
|
// False start, we should output the space if it was the trigger.
|
||||||
if (m_triggeredWithSpace)
|
if (m_triggeredWithSpace)
|
||||||
@@ -167,12 +221,10 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
|||||||
{
|
{
|
||||||
m_hideToolbarCb(InputType::None);
|
m_hideToolbarCb(InputType::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_toolbarVisible = false;
|
m_toolbarVisible = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Logger::debug(L"Hide toolbar event and input char");
|
||||||
Logger::info(L"Hide toolbar event and input char");
|
|
||||||
|
|
||||||
m_hideToolbarCb(InputType::Char);
|
m_hideToolbarCb(InputType::Char);
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
|||||||
{
|
{
|
||||||
PowerAccentActivationKey activationKey{ PowerAccentActivationKey::Both };
|
PowerAccentActivationKey activationKey{ PowerAccentActivationKey::Both };
|
||||||
std::chrono::milliseconds inputTime{ 200 };
|
std::chrono::milliseconds inputTime{ 200 };
|
||||||
|
std::vector<std::wstring> excludedApps;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct KeyboardListener : KeyboardListenerT<KeyboardListener>
|
struct KeyboardListener : KeyboardListenerT<KeyboardListener>
|
||||||
@@ -36,12 +37,14 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
|||||||
|
|
||||||
void UpdateActivationKey(int32_t activationKey);
|
void UpdateActivationKey(int32_t activationKey);
|
||||||
void UpdateInputTime(int32_t inputTime);
|
void UpdateInputTime(int32_t inputTime);
|
||||||
|
void UpdateExcludedApps(std::wstring_view excludedApps);
|
||||||
|
|
||||||
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
|
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool OnKeyDown(KBDLLHOOKSTRUCT info) noexcept;
|
bool OnKeyDown(KBDLLHOOKSTRUCT info) noexcept;
|
||||||
bool OnKeyUp(KBDLLHOOKSTRUCT info) noexcept;
|
bool OnKeyUp(KBDLLHOOKSTRUCT info) noexcept;
|
||||||
|
bool IsForegroundAppExcluded();
|
||||||
|
|
||||||
static inline KeyboardListener* s_instance;
|
static inline KeyboardListener* s_instance;
|
||||||
HHOOK s_llKeyboardHook = nullptr;
|
HHOOK s_llKeyboardHook = nullptr;
|
||||||
@@ -54,6 +57,9 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
|||||||
bool m_triggeredWithSpace;
|
bool m_triggeredWithSpace;
|
||||||
spdlog::stopwatch m_stopwatch;
|
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,
|
static inline const std::vector<LetterKey> letters = { LetterKey::VK_0,
|
||||||
LetterKey::VK_1,
|
LetterKey::VK_1,
|
||||||
LetterKey::VK_2,
|
LetterKey::VK_2,
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ namespace PowerToys
|
|||||||
void SetIsLanguageLetterDelegate(IsLanguageLetter isLanguageLetterDelegate);
|
void SetIsLanguageLetterDelegate(IsLanguageLetter isLanguageLetterDelegate);
|
||||||
void UpdateActivationKey(Int32 activationKey);
|
void UpdateActivationKey(Int32 activationKey);
|
||||||
void UpdateInputTime(Int32 inputTime);
|
void UpdateInputTime(Int32 inputTime);
|
||||||
|
void UpdateExcludedApps(String excludedApps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,12 +21,16 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
[JsonPropertyName("selected_lang")]
|
[JsonPropertyName("selected_lang")]
|
||||||
public StringProperty SelectedLang { get; set; }
|
public StringProperty SelectedLang { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("excluded_apps")]
|
||||||
|
public StringProperty ExcludedApps { get; set; }
|
||||||
|
|
||||||
public PowerAccentProperties()
|
public PowerAccentProperties()
|
||||||
{
|
{
|
||||||
ActivationKey = PowerAccentActivationKey.Both;
|
ActivationKey = PowerAccentActivationKey.Both;
|
||||||
ToolbarPosition = "Top center";
|
ToolbarPosition = "Top center";
|
||||||
InputTime = new IntProperty(200);
|
InputTime = new IntProperty(200);
|
||||||
SelectedLang = "ALL";
|
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>
|
<value>Hold the key down for this much time to make the accent menu appear (ms)</value>
|
||||||
<comment>ms = milliseconds</comment>
|
<comment>ms = milliseconds</comment>
|
||||||
</data>
|
</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">
|
<data name="LearnMore_TextExtractor.Text" xml:space="preserve">
|
||||||
<value>Learn more about Text Extractor</value>
|
<value>Learn more about Text Extractor</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -90,6 +90,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
|
|
||||||
_inputTimeMs = _powerAccentSettings.Properties.InputTime.Value;
|
_inputTimeMs = _powerAccentSettings.Properties.InputTime.Value;
|
||||||
|
|
||||||
|
_excludedApps = _powerAccentSettings.Properties.ExcludedApps.Value;
|
||||||
|
|
||||||
_selectedLangIndex = Array.IndexOf(_languageOptions, _powerAccentSettings.Properties.SelectedLang.Value);
|
_selectedLangIndex = Array.IndexOf(_languageOptions, _powerAccentSettings.Properties.SelectedLang.Value);
|
||||||
|
|
||||||
_toolbarPositionIndex = Array.IndexOf(_toolbarOptions, _powerAccentSettings.Properties.ToolbarPosition.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;
|
private int _toolbarPositionIndex;
|
||||||
|
|
||||||
public int ToolbarPositionIndex
|
public int ToolbarPositionIndex
|
||||||
|
|||||||
@@ -103,6 +103,24 @@
|
|||||||
LargeChange="100"/>
|
LargeChange="100"/>
|
||||||
</controls:Setting.ActionContent>
|
</controls:Setting.ActionContent>
|
||||||
</controls:Setting>
|
</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>
|
</controls:SettingsGroup>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</controls:SettingsPageControl.ModuleContent>
|
</controls:SettingsPageControl.ModuleContent>
|
||||||
|
|||||||
Reference in New Issue
Block a user