diff --git a/src/modules/poweraccent/PowerAccent.Core/PowerAccent.cs b/src/modules/poweraccent/PowerAccent.Core/PowerAccent.cs index c2f0698f25..5d32f1d565 100644 --- a/src/modules/poweraccent/PowerAccent.Core/PowerAccent.cs +++ b/src/modules/poweraccent/PowerAccent.Core/PowerAccent.cs @@ -62,11 +62,11 @@ public partial class PowerAccent : IDisposable private void SetEvents() { - _keyboardListener.SetShowToolbarEvent(new PowerToys.PowerAccentKeyboardService.ShowToolbar((LetterKey letterKey) => + _keyboardListener.SetShowToolbarEvent(new PowerToys.PowerAccentKeyboardService.ShowToolbar((LetterKey letterKey, TriggerKey trigger ) => { System.Windows.Application.Current.Dispatcher.Invoke(() => { - ShowToolbar(letterKey); + ShowToolbar(letterKey, trigger); }); })); @@ -92,23 +92,15 @@ public partial class PowerAccent : IDisposable })); } - private void ShowToolbar(LetterKey letterKey) + private void ShowToolbar(LetterKey letterKey, TriggerKey trigger) { _visible = true; _characters = GetCharacters(letterKey); _characterDescriptions = GetCharacterDescriptions(_characters); _showUnicodeDescription = _settingService.ShowUnicodeDescription; - - Task.Delay(_settingService.InputTime).ContinueWith( - t => - { - if (_visible) - { - OnChangeDisplay?.Invoke(true, _characters); - } - }, - TaskScheduler.FromCurrentSynchronizationContext()); + OnChangeDisplay?.Invoke(true, _characters); + ProcessNextChar(trigger, false); } private string[] GetCharacters(LetterKey letterKey) diff --git a/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.cpp b/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.cpp index 93fb5c0230..3d38d20b91 100644 --- a/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.cpp +++ b/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.cpp @@ -13,7 +13,7 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation { KeyboardListener::KeyboardListener() : - m_toolbarVisible(false), m_triggeredWithSpace(false), m_leftShiftPressed(false), m_rightShiftPressed(false), m_triggeredWithLeftArrow(false), m_triggeredWithRightArrow(false) + m_toolbarVisible(false), m_activationKeyHold(false), m_triggeredWithSpace(false), m_leftShiftPressed(false), m_rightShiftPressed(false), m_triggeredWithLeftArrow(false), m_triggeredWithRightArrow(false) { s_instance = this; LoggerHelpers::init_logger(L"PowerAccent", L"PowerAccentKeyboardService", "PowerAccent"); @@ -53,8 +53,8 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation void KeyboardListener::SetShowToolbarEvent(ShowToolbar showToolbarEvent) { - m_showToolbarCb = [trigger = std::move(showToolbarEvent)](LetterKey key) { - trigger(key); + m_showToolbarCb = [trigger = std::move(showToolbarEvent)](LetterKey key, TriggerKey triggerKey) { + trigger(key, triggerKey); }; } @@ -152,6 +152,17 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation return false; } + void KeyboardListener::BeginShowToolbar(std::chrono::milliseconds delay, LetterKey key, TriggerKey trigger) + { + std::unique_lock lock(toolbarMutex); + auto result = toolbarCV.wait_for(lock, delay); + if (result == std::cv_status::timeout) + { + m_toolbarVisible = true; + m_showToolbarCb(key, trigger); + } + } + bool KeyboardListener::OnKeyDown(KBDLLHOOKSTRUCT info) noexcept { auto letterKey = static_cast(info.vkCode); @@ -199,7 +210,7 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation } } - if (!m_toolbarVisible && letterPressed != LetterKey::None && triggerPressed && !IsSuppressedByGameMode() && !IsForegroundAppExcluded()) + if (!m_toolbarVisible && !m_activationKeyHold && letterPressed != LetterKey::None && triggerPressed && !IsSuppressedByGameMode() && !IsForegroundAppExcluded()) { Logger::debug(L"Show toolbar. Letter: {}, Trigger: {}", letterPressed, triggerPressed); @@ -207,11 +218,21 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation m_triggeredWithSpace = triggerPressed == VK_SPACE; m_triggeredWithLeftArrow = triggerPressed == VK_LEFT; m_triggeredWithRightArrow = triggerPressed == VK_RIGHT; - m_toolbarVisible = true; - m_showToolbarCb(letterPressed); + m_activationKeyHold = true; + m_bothKeysPressed = true; + if (toolbarThread != nullptr) + { + toolbarCV.notify_all(); + toolbarThread->join(); + } + toolbarThread = std::make_unique(std::bind(&KeyboardListener::BeginShowToolbar, this, m_settings.inputTime, letterPressed,static_cast(triggerPressed))); } - if (m_toolbarVisible && triggerPressed) + if (m_activationKeyHold && triggerPressed && !m_toolbarVisible) + { + return true; + } + else if (m_toolbarVisible && triggerPressed) { if (triggerPressed == VK_LEFT) { @@ -251,8 +272,9 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation { letterPressed = LetterKey::None; - if (m_toolbarVisible) + if (m_toolbarVisible || m_bothKeysPressed) { + m_bothKeysPressed = false; if (m_stopwatch.elapsed() < m_settings.inputTime) { Logger::debug(L"Activation too fast. Do nothing."); @@ -280,11 +302,18 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation Logger::debug(L"Hide toolbar event and input char"); m_hideToolbarCb(InputType::Char); - m_toolbarVisible = false; } } + auto triggerPressed = info.vkCode; + + if (m_activationKeyHold && (letterPressed == LetterKey::None || (triggerPressed == VK_SPACE || triggerPressed == VK_LEFT || triggerPressed == VK_RIGHT))) + { + m_activationKeyHold = false; + toolbarCV.notify_all(); + } + return false; } diff --git a/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.h b/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.h index 61c28e1866..6ec1118775 100644 --- a/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.h +++ b/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.h @@ -2,6 +2,7 @@ #include "KeyboardListener.g.h" #include +#include #include namespace winrt::PowerToys::PowerAccentKeyboardService::implementation @@ -44,6 +45,7 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); private: + void BeginShowToolbar(std::chrono::milliseconds delay, LetterKey key, TriggerKey trigger); bool OnKeyDown(KBDLLHOOKSTRUCT info) noexcept; bool OnKeyUp(KBDLLHOOKSTRUCT info) noexcept; bool IsSuppressedByGameMode(); @@ -51,9 +53,14 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation static inline KeyboardListener* s_instance; HHOOK s_llKeyboardHook = nullptr; - bool m_toolbarVisible; + std::atomic m_toolbarVisible; + bool m_activationKeyHold; + bool m_bothKeysPressed = false; + std::unique_ptr toolbarThread; + std::mutex toolbarMutex; + std::condition_variable toolbarCV; PowerAccentSettings m_settings; - std::function m_showToolbarCb; + std::function m_showToolbarCb; std::function m_hideToolbarCb; std::function m_nextCharCb; std::function m_isLanguageLetterCb; diff --git a/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.idl b/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.idl index 9bc8448c22..9fc0f42e42 100644 --- a/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.idl +++ b/src/modules/poweraccent/PowerAccentKeyboardService/KeyboardListener.idl @@ -67,7 +67,7 @@ namespace PowerToys Char }; - [version(1.0), uuid(37197089-5438-4479-af57-30ab3f3c8be4)] delegate void ShowToolbar(LetterKey key); + [version(1.0), uuid(37197089-5438-4479-af57-30ab3f3c8be4)] delegate void ShowToolbar(LetterKey key, TriggerKey trigger); [version(1.0), uuid(8eb79d6b-1826-424f-9fbc-af21ae19725e)] delegate void HideToolbar(InputType inputType); [version(1.0), uuid(db72d45c-a5a2-446f-bdc1-506e9121764a)] delegate void NextChar(TriggerKey inputSpace, boolean shiftPressed); [version(1.0), uuid(20be2919-2b91-4313-b6e0-4c3484fe91ef)] delegate void IsLanguageLetter(LetterKey key, [out] boolean* result);