[KBM Editor] fix crash when mapping left and right modifier to the combined key. (#12999)

* [KBM Editor] Don't combine keys to same key

* Avoid crashes when flyouts can't be shown yet

* Disallow mapping of left or right key to combined

* Refactor remap to combined key check

* Add log message when flyout fails to load
This commit is contained in:
Jaime Bernardo
2021-09-03 16:19:16 +01:00
committed by GitHub
parent 4a1e21ac83
commit b8236d55e2
6 changed files with 55 additions and 3 deletions

View File

@@ -3,6 +3,7 @@
#include <common/interop/shared_constants.h> #include <common/interop/shared_constants.h>
#include <keyboardmanager/common/KeyboardManagerConstants.h> #include <keyboardmanager/common/KeyboardManagerConstants.h>
#include <keyboardmanager/common/Helpers.h>
#include "KeyboardManagerEditorStrings.h" #include "KeyboardManagerEditorStrings.h"
#include "KeyDropDownControl.h" #include "KeyDropDownControl.h"
@@ -12,6 +13,13 @@
namespace BufferValidationHelpers namespace BufferValidationHelpers
{ {
// Helper function to verify if a key is being remapped to/from its combined key
bool IsKeyRemappingToItsCombinedKey(DWORD keyCode1, DWORD keyCode2)
{
return (keyCode1 == Helpers::GetCombinedKey(keyCode1) || keyCode2 == Helpers::GetCombinedKey(keyCode2)) &&
Helpers::GetCombinedKey(keyCode1) == Helpers::GetCombinedKey(keyCode2);
}
// Function to validate and update an element of the key remap buffer when the selection has changed // Function to validate and update an element of the key remap buffer when the selection has changed
ShortcutErrorType ValidateAndUpdateKeyBufferElement(int rowIndex, int colIndex, int selectedKeyCode, RemapBuffer& remapBuffer) ShortcutErrorType ValidateAndUpdateKeyBufferElement(int rowIndex, int colIndex, int selectedKeyCode, RemapBuffer& remapBuffer)
{ {
@@ -23,7 +31,8 @@ namespace BufferValidationHelpers
// Check if the value being set is the same as the other column // Check if the value being set is the same as the other column
if (remapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)].index() == 0) if (remapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)].index() == 0)
{ {
if (std::get<DWORD>(remapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)]) == selectedKeyCode) DWORD otherColumnKeyCode = std::get<DWORD>(remapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)]);
if (otherColumnKeyCode == selectedKeyCode || IsKeyRemappingToItsCombinedKey(selectedKeyCode, otherColumnKeyCode))
{ {
errorType = ShortcutErrorType::MapToSameKey; errorType = ShortcutErrorType::MapToSameKey;
} }
@@ -251,7 +260,9 @@ namespace BufferValidationHelpers
// If key to key // If key to key
if (remapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)].index() == 0) if (remapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)].index() == 0)
{ {
if (std::get<DWORD>(remapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)]) == std::get<DWORD>(tempShortcut) && std::get<DWORD>(remapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)]) != NULL && std::get<DWORD>(tempShortcut) != NULL) DWORD otherColumnKeyCode = std::get<DWORD>(remapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)]);
DWORD shortcutKeyCode = std::get<DWORD>(tempShortcut);
if ((otherColumnKeyCode == shortcutKeyCode || IsKeyRemappingToItsCombinedKey(otherColumnKeyCode, shortcutKeyCode)) && otherColumnKeyCode != NULL && shortcutKeyCode != NULL)
{ {
errorType = ShortcutErrorType::MapToSameKey; errorType = ShortcutErrorType::MapToSameKey;
} }

View File

@@ -14,6 +14,9 @@ namespace BufferValidationHelpers
ClearUnusedDropDowns ClearUnusedDropDowns
}; };
// Helper function to verify if a key is being remapped to/from its combined key
bool IsKeyRemappingToItsCombinedKey(DWORD keyCode1, DWORD keyCode2);
// Function to validate and update an element of the key remap buffer when the selection has changed // Function to validate and update an element of the key remap buffer when the selection has changed
ShortcutErrorType ValidateAndUpdateKeyBufferElement(int rowIndex, int colIndex, int selectedKeyCode, RemapBuffer& remapBuffer); ShortcutErrorType ValidateAndUpdateKeyBufferElement(int rowIndex, int colIndex, int selectedKeyCode, RemapBuffer& remapBuffer);

View File

@@ -376,7 +376,15 @@ void KeyDropDownControl::SetDropDownError(ComboBox currentDropDown, hstring mess
{ {
currentDropDown.SelectedIndex(-1); currentDropDown.SelectedIndex(-1);
warningMessage.as<TextBlock>().Text(message); warningMessage.as<TextBlock>().Text(message);
currentDropDown.ContextFlyout().ShowAttachedFlyout((FrameworkElement)dropDown.as<ComboBox>()); try
{
currentDropDown.ContextFlyout().ShowAttachedFlyout((FrameworkElement)dropDown.as<ComboBox>());
}
catch (winrt::hresult_error const&)
{
// If it's loading and some remaps are invalid from previous configs, avoid crashing when flyouts can't be showed yet.
Logger::error(L"Failed to show dropdown error flyout: {}", message);
}
} }
// Function to add a shortcut to the UI control as combo boxes // Function to add a shortcut to the UI control as combo boxes

View File

@@ -2,6 +2,7 @@
#include "LoadingAndSavingRemappingHelper.h" #include "LoadingAndSavingRemappingHelper.h"
#include <set> #include <set>
#include <variant>
#include <common/interop/shared_constants.h> #include <common/interop/shared_constants.h>
#include <keyboardmanager/common/MappingConfiguration.h> #include <keyboardmanager/common/MappingConfiguration.h>
@@ -88,6 +89,11 @@ namespace LoadingAndSavingRemappingHelper
// If they are mapped to the same key, delete those entries and set the common version // If they are mapped to the same key, delete those entries and set the common version
if (table[leftKey] == table[rightKey]) if (table[leftKey] == table[rightKey])
{ {
if (std::holds_alternative<DWORD>(table[leftKey]) && std::get<DWORD>(table[leftKey]) == combinedKey)
{
// Avoid mapping a key to itself when the combined key is equal to the resulting mapping.
return;
}
table[combinedKey] = table[leftKey]; table[combinedKey] = table[leftKey];
table.erase(leftKey); table.erase(leftKey);
table.erase(rightKey); table.erase(rightKey);

View File

@@ -15,6 +15,27 @@ namespace Helpers
return (GetKeyType(key) != KeyType::Action); return (GetKeyType(key) != KeyType::Action);
} }
// Function to get the combined key for modifier keys
DWORD GetCombinedKey(DWORD key)
{
switch (key) {
case VK_LWIN:
case VK_RWIN:
return CommonSharedConstants::VK_WIN_BOTH;
case VK_LCONTROL:
case VK_RCONTROL:
return VK_CONTROL;
case VK_LMENU:
case VK_RMENU:
return VK_MENU;
case VK_LSHIFT:
case VK_RSHIFT:
return VK_SHIFT;
default:
return key;
}
}
// Function to get the type of the key // Function to get the type of the key
KeyType GetKeyType(DWORD key) KeyType GetKeyType(DWORD key)
{ {

View File

@@ -18,6 +18,9 @@ namespace Helpers
// Function to check if the key is a modifier key // Function to check if the key is a modifier key
bool IsModifierKey(DWORD key); bool IsModifierKey(DWORD key);
// Function to get the combined key for modifier keys
DWORD GetCombinedKey(DWORD key);
// Function to get the type of the key // Function to get the type of the key
KeyType GetKeyType(DWORD key); KeyType GetKeyType(DWORD key);