diff --git a/src/modules/poweraccent/PowerAccent.Core/Services/SettingsService.cs b/src/modules/poweraccent/PowerAccent.Core/Services/SettingsService.cs index c82215677c..8376352e08 100644 --- a/src/modules/poweraccent/PowerAccent.Core/Services/SettingsService.cs +++ b/src/modules/poweraccent/PowerAccent.Core/Services/SettingsService.cs @@ -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 diff --git a/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.cpp b/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.cpp index 63bde6769e..7de3ad9aaf 100644 --- a/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.cpp +++ b/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.cpp @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include 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 excludedApps; + auto excludedUppercase = std::wstring(excludedAppsView); + CharUpperBuffW(excludedUppercase.data(), (DWORD)excludedUppercase.length()); + std::wstring_view view(excludedUppercase); + view = left_trim(trim(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(trim(view)); + } + { + std::lock_guard lock(m_mutex_excluded_apps); + m_settings.excludedApps = std::move(excludedApps); + m_prevForegrndAppExcl = { NULL, false }; + } + } + + bool KeyboardListener::IsForegroundAppExcluded() + { + std::lock_guard 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(info.vkCode)) != end(letters) && m_isLanguageLetterCb(static_cast(info.vkCode))) + auto letterKey = static_cast(info.vkCode); + if (std::find(letters.begin(), letters.end(), letterKey) != cend(letters) && m_isLanguageLetterCb(letterKey)) { m_stopwatch.reset(); - letterPressed = static_cast(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); diff --git a/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.h b/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.h index 11140468dd..73e66611c7 100644 --- a/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.h +++ b/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.h @@ -17,6 +17,7 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation { PowerAccentActivationKey activationKey{ PowerAccentActivationKey::Both }; std::chrono::milliseconds inputTime{ 200 }; + std::vector excludedApps; }; struct KeyboardListener : KeyboardListenerT @@ -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 m_prevForegrndAppExcl{ NULL, false }; + static inline const std::vector letters = { LetterKey::VK_0, LetterKey::VK_1, LetterKey::VK_2, diff --git a/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.idl b/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.idl index 272d3ce3ed..4877dce395 100644 --- a/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.idl +++ b/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.idl @@ -73,6 +73,7 @@ namespace PowerToys void SetIsLanguageLetterDelegate(IsLanguageLetter isLanguageLetterDelegate); void UpdateActivationKey(Int32 activationKey); void UpdateInputTime(Int32 inputTime); + void UpdateExcludedApps(String excludedApps); } } -} \ No newline at end of file +} diff --git a/src/settings-ui/Settings.UI.Library/PowerAccentProperties.cs b/src/settings-ui/Settings.UI.Library/PowerAccentProperties.cs index e365da3366..0b1e76d4bc 100644 --- a/src/settings-ui/Settings.UI.Library/PowerAccentProperties.cs +++ b/src/settings-ui/Settings.UI.Library/PowerAccentProperties.cs @@ -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(); } } } diff --git a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw index e8333815b2..a4bb2bcbc2 100644 --- a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw +++ b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw @@ -2420,6 +2420,15 @@ Activate by holding the key for the character you want to add an accent to, then Hold the key down for this much time to make the accent menu appear (ms) ms = milliseconds + + Prevents module activation if a foreground application is excluded. Add one application name per line. + + + Excluded apps + + + Example: Teams.exe + Learn more about Text Extractor diff --git a/src/settings-ui/Settings.UI/ViewModels/PowerAccentViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/PowerAccentViewModel.cs index 8dfaeba9b1..c00c667e7e 100644 --- a/src/settings-ui/Settings.UI/ViewModels/PowerAccentViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/PowerAccentViewModel.cs @@ -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 diff --git a/src/settings-ui/Settings.UI/Views/PowerAccentPage.xaml b/src/settings-ui/Settings.UI/Views/PowerAccentPage.xaml index 8ed3f3f0ba..ceb6027b05 100644 --- a/src/settings-ui/Settings.UI/Views/PowerAccentPage.xaml +++ b/src/settings-ui/Settings.UI/Views/PowerAccentPage.xaml @@ -103,6 +103,24 @@ LargeChange="100"/> + + + + + + + +