diff --git a/src/modules/keyboardmanager/common/KeyDelay.cpp b/src/modules/keyboardmanager/common/KeyDelay.cpp index 0c7f384bda..825b5e35b8 100644 --- a/src/modules/keyboardmanager/common/KeyDelay.cpp +++ b/src/modules/keyboardmanager/common/KeyDelay.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include "KeyDelay.h" +// NOTE: The destructor should never be called on the DelayThread, i.e. from any of shortPress, longPress or longPressReleased, as it will re-enter the mutex. Even if the mutex is removed it will deadlock because of the join statement KeyDelay::~KeyDelay() { std::unique_lock l(_queueMutex); diff --git a/src/modules/keyboardmanager/ui/ShortcutControl.cpp b/src/modules/keyboardmanager/ui/ShortcutControl.cpp index 1ed92ead8d..c1f1da5fab 100644 --- a/src/modules/keyboardmanager/ui/ShortcutControl.cpp +++ b/src/modules/keyboardmanager/ui/ShortcutControl.cpp @@ -355,6 +355,7 @@ void ShortcutControl::createDetectShortcutWindow(winrt::Windows::Foundation::IIn onAccept(); }); + // NOTE: UnregisterKeys should never be called on the DelayThread, as it will re-enter the mutex. To avoid this it is run on the dispatcher thread keyboardManagerState.RegisterKeyDelay( VK_RETURN, selectDetectedShortcutAndResetKeys, @@ -367,19 +368,24 @@ void ShortcutControl::createDetectShortcutWindow(winrt::Windows::Foundation::IIn onPressEnter(); }); }, - [onReleaseEnter](DWORD) { - onReleaseEnter(); + [onReleaseEnter, detectShortcutBox](DWORD) { + detectShortcutBox.Dispatcher().RunAsync( + Windows::UI::Core::CoreDispatcherPriority::Normal, + [onReleaseEnter]() { + onReleaseEnter(); + }); }); TextBlock cancelButtonText; cancelButtonText.Text(GET_RESOURCE_STRING(IDS_CANCEL_BUTTON)); - Button cancelButton; - cancelButton.HorizontalAlignment(HorizontalAlignment::Stretch); - cancelButton.Margin({ 2, 2, 2, 2 }); - cancelButton.Content(cancelButtonText); - // Cancel button - cancelButton.Click([detectShortcutBox, unregisterKeys, &keyboardManagerState, isSingleKeyWindow, parentWindow](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) { + auto onCancel = [&keyboardManagerState, + detectShortcutBox, + unregisterKeys, + isSingleKeyWindow, + parentWindow] { + detectShortcutBox.Hide(); + // Reset the keyboard manager UI state keyboardManagerState.ResetUIState(); if (isSingleKeyWindow) @@ -393,31 +399,27 @@ void ShortcutControl::createDetectShortcutWindow(winrt::Windows::Foundation::IIn keyboardManagerState.SetUIState(KeyboardManagerUIState::EditShortcutsWindowActivated, parentWindow); } unregisterKeys(); - detectShortcutBox.Hide(); + }; + + Button cancelButton; + cancelButton.HorizontalAlignment(HorizontalAlignment::Stretch); + cancelButton.Margin({ 2, 2, 2, 2 }); + cancelButton.Content(cancelButtonText); + // Cancel button + cancelButton.Click([onCancel](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) { + onCancel(); }); + // NOTE: UnregisterKeys should never be called on the DelayThread, as it will re-enter the mutex. To avoid this it is run on the dispatcher thread keyboardManagerState.RegisterKeyDelay( VK_ESCAPE, selectDetectedShortcutAndResetKeys, - [&keyboardManagerState, detectShortcutBox, unregisterKeys, isSingleKeyWindow, parentWindow](DWORD) { + [onCancel, detectShortcutBox](DWORD) { detectShortcutBox.Dispatcher().RunAsync( Windows::UI::Core::CoreDispatcherPriority::Normal, - [detectShortcutBox] { - detectShortcutBox.Hide(); + [onCancel] { + onCancel(); }); - - keyboardManagerState.ResetUIState(); - if (isSingleKeyWindow) - { - // Revert UI state back to Edit Keyboard window - keyboardManagerState.SetUIState(KeyboardManagerUIState::EditKeyboardWindowActivated, parentWindow); - } - else - { - // Revert UI state back to Edit Shortcut window - keyboardManagerState.SetUIState(KeyboardManagerUIState::EditShortcutsWindowActivated, parentWindow); - } - unregisterKeys(); }, nullptr); diff --git a/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp b/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp index d464deba8f..a9545bbf1e 100644 --- a/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp +++ b/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp @@ -269,6 +269,7 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II onAccept(); }); + // NOTE: UnregisterKeys should never be called on the DelayThread, as it will re-enter the mutex. To avoid this it is run on the dispatcher thread keyboardManagerState.RegisterKeyDelay( VK_RETURN, std::bind(&KeyboardManagerState::SelectDetectedRemapKey, &keyboardManagerState, std::placeholders::_1), @@ -281,41 +282,48 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II onPressEnter(); }); }, - [onReleaseEnter](DWORD) { - onReleaseEnter(); + [onReleaseEnter, detectRemapKeyBox](DWORD) { + detectRemapKeyBox.Dispatcher().RunAsync( + Windows::UI::Core::CoreDispatcherPriority::Normal, + [onReleaseEnter]() { + onReleaseEnter(); + }); }); TextBlock cancelButtonText; cancelButtonText.Text(GET_RESOURCE_STRING(IDS_CANCEL_BUTTON)); + auto onCancel = [&keyboardManagerState, + detectRemapKeyBox, + unregisterKeys] { + detectRemapKeyBox.Hide(); + + // Reset the keyboard manager UI state + keyboardManagerState.ResetUIState(); + // Revert UI state back to Edit Keyboard window + keyboardManagerState.SetUIState(KeyboardManagerUIState::EditKeyboardWindowActivated, EditKeyboardWindowHandle); + unregisterKeys(); + }; + Button cancelButton; cancelButton.HorizontalAlignment(HorizontalAlignment::Stretch); cancelButton.Margin({ 2, 2, 2, 2 }); cancelButton.Content(cancelButtonText); // Cancel button - cancelButton.Click([detectRemapKeyBox, unregisterKeys, &keyboardManagerState](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) { - // Reset the keyboard manager UI state - keyboardManagerState.ResetUIState(); - // Revert UI state back to Edit Keyboard window - keyboardManagerState.SetUIState(KeyboardManagerUIState::EditKeyboardWindowActivated, EditKeyboardWindowHandle); - unregisterKeys(); - detectRemapKeyBox.Hide(); + cancelButton.Click([onCancel](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) { + onCancel(); }); + // NOTE: UnregisterKeys should never be called on the DelayThread, as it will re-enter the mutex. To avoid this it is run on the dispatcher thread keyboardManagerState.RegisterKeyDelay( VK_ESCAPE, std::bind(&KeyboardManagerState::SelectDetectedRemapKey, &keyboardManagerState, std::placeholders::_1), - [&keyboardManagerState, detectRemapKeyBox, unregisterKeys](DWORD) { + [onCancel, detectRemapKeyBox](DWORD) { detectRemapKeyBox.Dispatcher().RunAsync( Windows::UI::Core::CoreDispatcherPriority::Normal, - [detectRemapKeyBox] { - detectRemapKeyBox.Hide(); + [onCancel] { + onCancel(); }); - - keyboardManagerState.ResetUIState(); - // Revert UI state back to Edit Keyboard window - keyboardManagerState.SetUIState(KeyboardManagerUIState::EditKeyboardWindowActivated, EditKeyboardWindowHandle); - unregisterKeys(); }, nullptr);