diff --git a/src/modules/keyboardmanager/KeyboardManagerEditor/Resources.resx b/src/modules/keyboardmanager/KeyboardManagerEditor/Resources.resx
index 1239cc7786..2ddc68f7a6 100644
--- a/src/modules/keyboardmanager/KeyboardManagerEditor/Resources.resx
+++ b/src/modules/keyboardmanager/KeyboardManagerEditor/Resources.resx
@@ -287,6 +287,16 @@
Key
Key on a keyboard
+
+ Text
+
+
+ Shortcut
+
+
+ Key
+ Key on a keyboard
+
Add key remapping
Key on a keyboard
diff --git a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/BufferValidationHelpers.cpp b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/BufferValidationHelpers.cpp
index 79ffcf0152..228e680f26 100644
--- a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/BufferValidationHelpers.cpp
+++ b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/BufferValidationHelpers.cpp
@@ -220,7 +220,7 @@ namespace BufferValidationHelpers
// After validating the shortcut, now for errors like remap to same shortcut, remap shortcut more than once, Win L and Ctrl Alt Del
if (errorType == ShortcutErrorType::NoError)
{
- KeyShortcutUnion tempShortcut;
+ KeyShortcutTextUnion tempShortcut;
if (isHybridControl && KeyDropDownControl::GetNumberOfSelectedKeys(selectedCodes) == 1)
{
tempShortcut = (DWORD)*std::find_if(selectedCodes.begin(), selectedCodes.end(), [](int32_t a) { return a != -1 && a != 0; });
diff --git a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditKeyboardWindow.cpp b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditKeyboardWindow.cpp
index 24126abebd..c3ec42a7ee 100644
--- a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditKeyboardWindow.cpp
+++ b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditKeyboardWindow.cpp
@@ -285,14 +285,21 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMan
// Load existing remaps into UI
SingleKeyRemapTable singleKeyRemapCopy = mappingConfiguration.singleKeyReMap;
+ SingleKeyToTextRemapTable singleKeyToTextRemapCopy = mappingConfiguration.singleKeyToTextReMap;
LoadingAndSavingRemappingHelper::PreProcessRemapTable(singleKeyRemapCopy);
+ LoadingAndSavingRemappingHelper::PreProcessRemapTable(singleKeyToTextRemapCopy);
for (const auto& it : singleKeyRemapCopy)
{
SingleKeyRemapControl::AddNewControlKeyRemapRow(keyRemapTable, keyboardRemapControlObjects, it.first, it.second);
}
+ for (const auto& it : singleKeyToTextRemapCopy)
+ {
+ SingleKeyRemapControl::AddNewControlKeyRemapRow(keyRemapTable, keyboardRemapControlObjects, it.first, it.second);
+ }
+
// Main Header Apply button
Button applyButton;
applyButton.Content(winrt::box_value(GET_RESOURCE_STRING(IDS_OK_BUTTON)));
diff --git a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditorConstants.h b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditorConstants.h
index 9943c146f4..cd38ad8d83 100644
--- a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditorConstants.h
+++ b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditorConstants.h
@@ -35,7 +35,7 @@ namespace EditorConstants
inline const long ShortcutTableRemoveColIndex = 4;
inline const long ShortcutArrowColumnWidth = 90;
inline const DWORD64 ShortcutTableDropDownWidth = 160;
- inline const DWORD64 ShortcutTableDropDownSpacing = 10;
+ inline const long ShortcutTableDropDownSpacing = 10;
inline const long ShortcutOriginColumnWidth = 3 * ShortcutTableDropDownWidth + 3 * ShortcutTableDropDownSpacing;
inline const long ShortcutTargetColumnWidth = 3 * ShortcutTableDropDownWidth + 3 * ShortcutTableDropDownSpacing + 15;
diff --git a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/KeyDropDownControl.cpp b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/KeyDropDownControl.cpp
index a3ff546ac8..39a7bb2aa3 100644
--- a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/KeyDropDownControl.cpp
+++ b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/KeyDropDownControl.cpp
@@ -66,7 +66,7 @@ void KeyDropDownControl::SetDefaultProperties(bool isShortcut, bool renderDisabl
}
dropDown.as().MaxDropDownHeight(EditorConstants::TableDropDownHeight);
-
+
// Initialise layout attribute
previousLayout = GetKeyboardLayout(0);
dropDown.as().SelectedValuePath(L"DataContext");
@@ -83,7 +83,20 @@ void KeyDropDownControl::SetDefaultProperties(bool isShortcut, bool renderDisabl
// Attach the tip to the drop down
warningTip.Target(dropDown.as());
dropDown.as().Loaded([&](winrt::Windows::Foundation::IInspectable const& sender, auto args) {
- Media::VisualTreeHelper::GetChild(dropDown.as(), 0).as().Children().Append(warningTip);
+ auto combo = dropDown.as();
+ auto child0 = Media::VisualTreeHelper::GetChild(combo, 0);
+ if (!child0)
+ return;
+
+ auto grid = child0.as();
+ if (!grid)
+ return;
+
+ auto& gridChildren = grid.Children();
+ if (!gridChildren)
+ return;
+
+ gridChildren.Append(warningTip);
});
// Tip properties
@@ -102,7 +115,7 @@ void KeyDropDownControl::SetDefaultProperties(bool isShortcut, bool renderDisabl
warningFlyout.as().FlyoutPresenterStyle(style);
dropDown.as().ContextFlyout().SetAttachedFlyout((FrameworkElement)dropDown.as(), warningFlyout.as());
#endif
-
+
// To set the accessible name of the combo-box (by default index 1)
SetAccessibleNameForComboBox(dropDown.as(), 1);
}
@@ -141,7 +154,7 @@ void KeyDropDownControl::SetSelectionHandler(StackPanel& table, StackPanel row,
ComboBox currentDropDown = sender.as();
int selectedKeyCode = GetSelectedValue(currentDropDown);
-
+
// Validate current remap selection
ShortcutErrorType errorType = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(rowIndex, colIndex, selectedKeyCode, singleKeyRemapBuffer);
@@ -228,7 +241,7 @@ std::pair KeyDropDownControl::ValidateShortcutSelection(
}
parent.Children().RemoveAt(dropDownIndex);
-
+
// delete drop down control object from the vector so that it can be destructed
keyDropDownControlObjects.erase(keyDropDownControlObjects.begin() + dropDownIndex);
}
@@ -368,7 +381,7 @@ void KeyDropDownControl::ValidateShortcutFromDropDownList(StackPanel table, Stac
{
// Check for errors only if the current selection is a valid shortcut
std::vector selectedKeyCodes = GetSelectedCodesFromStackPanel(parent);
- KeyShortcutUnion currentShortcut;
+ KeyShortcutTextUnion currentShortcut;
if (GetNumberOfSelectedKeys(selectedKeyCodes) == 1 && isHybridControl)
{
currentShortcut = (DWORD)selectedKeyCodes[0];
@@ -415,7 +428,7 @@ void KeyDropDownControl::AddShortcutToControl(Shortcut shortcut, StackPanel tabl
{
// Delete the existing drop down menus
parent.Children().Clear();
-
+
// Remove references to the old drop down objects to destroy them
keyDropDownControlObjects.clear();
std::vector shortcutKeyCodes = shortcut.GetKeyCodes();
diff --git a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/KeyboardManagerEditorStrings.h b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/KeyboardManagerEditorStrings.h
index 3538b32e30..f41002b4be 100644
--- a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/KeyboardManagerEditorStrings.h
+++ b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/KeyboardManagerEditorStrings.h
@@ -11,7 +11,22 @@ namespace KeyboardManagerEditorStrings
{
return GET_RESOURCE_STRING(IDS_EDITSHORTCUTS_ALLAPPS);
}
-
+
+ inline std::wstring MappingTypeText()
+ {
+ return GET_RESOURCE_STRING(IDS_MAPPING_TYPE_DROPDOWN_TEXT);
+ }
+
+ inline std::wstring MappingTypeShortcut()
+ {
+ return GET_RESOURCE_STRING(IDS_MAPPING_TYPE_DROPDOWN_SHORTCUT);
+ }
+
+ inline std::wstring MappingTypeKey()
+ {
+ return GET_RESOURCE_STRING(IDS_MAPPING_TYPE_DROPDOWN_KEY);
+ }
+
// Function to return the error message
winrt::hstring GetErrorMessage(ShortcutErrorType errorType);
}
diff --git a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/LoadingAndSavingRemappingHelper.cpp b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/LoadingAndSavingRemappingHelper.cpp
index c817d328d6..d1777e574b 100644
--- a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/LoadingAndSavingRemappingHelper.cpp
+++ b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/LoadingAndSavingRemappingHelper.cpp
@@ -17,20 +17,20 @@ namespace LoadingAndSavingRemappingHelper
ShortcutErrorType CheckIfRemappingsAreValid(const RemapBuffer& remappings)
{
ShortcutErrorType isSuccess = ShortcutErrorType::NoError;
- std::map> ogKeys;
+ std::map> ogKeys;
for (int i = 0; i < remappings.size(); i++)
{
- KeyShortcutUnion ogKey = remappings[i].first[0];
- KeyShortcutUnion newKey = remappings[i].first[1];
+ KeyShortcutTextUnion ogKey = remappings[i].first[0];
+ KeyShortcutTextUnion newKey = remappings[i].first[1];
std::wstring appName = remappings[i].second;
- bool ogKeyValidity = (ogKey.index() == 0 && std::get(ogKey) != NULL) || (ogKey.index() == 1 && EditorHelpers::IsValidShortcut(std::get(ogKey)));
- bool newKeyValidity = (newKey.index() == 0 && std::get(newKey) != NULL) || (newKey.index() == 1 && EditorHelpers::IsValidShortcut(std::get(newKey)));
+ const bool ogKeyValidity = (ogKey.index() == 0 && std::get(ogKey) != NULL) || (ogKey.index() == 1 && EditorHelpers::IsValidShortcut(std::get(ogKey)));
+ const bool newKeyValidity = (newKey.index() == 0 && std::get(newKey) != NULL) || (newKey.index() == 1 && EditorHelpers::IsValidShortcut(std::get(newKey))) || (newKey.index() == 2 && !std::get(newKey).empty());
// Add new set for a new target app name
if (ogKeys.find(appName) == ogKeys.end())
{
- ogKeys[appName] = std::set();
+ ogKeys[appName] = std::set();
}
if (ogKeyValidity && newKeyValidity && ogKeys[appName].find(ogKey) == ogKeys[appName].end())
@@ -59,9 +59,12 @@ namespace LoadingAndSavingRemappingHelper
for (int i = 0; i < remappings.size(); i++)
{
DWORD ogKey = std::get(remappings[i].first[0]);
- KeyShortcutUnion newKey = remappings[i].first[1];
+ KeyShortcutTextUnion newKey = remappings[i].first[1];
- if (ogKey != NULL && ((newKey.index() == 0 && std::get(newKey) != 0) || (newKey.index() == 1 && EditorHelpers::IsValidShortcut(std::get(newKey)))))
+ const bool hasValidKeyRemapping = newKey.index() == 0 && std::get(newKey) != 0;
+ const bool hasValidShortcutRemapping = newKey.index() == 1 && EditorHelpers::IsValidShortcut(std::get(newKey));
+ const bool hasValidTextRemapping = newKey.index() == 2 && !std::get(newKey).empty();
+ if (ogKey != NULL && (hasValidKeyRemapping || hasValidShortcutRemapping || hasValidTextRemapping))
{
ogKeys.insert(ogKey);
@@ -116,53 +119,64 @@ namespace LoadingAndSavingRemappingHelper
{
// Clear existing Key Remaps
mappingConfiguration.ClearSingleKeyRemaps();
+ mappingConfiguration.ClearSingleKeyToTextRemaps();
DWORD successfulKeyToKeyRemapCount = 0;
DWORD successfulKeyToShortcutRemapCount = 0;
+ DWORD successfulKeyToTextRemapCount = 0;
for (int i = 0; i < remappings.size(); i++)
{
- DWORD originalKey = std::get(remappings[i].first[0]);
- KeyShortcutUnion newKey = remappings[i].first[1];
+ const DWORD originalKey = std::get(remappings[i].first[0]);
+ KeyShortcutTextUnion newKey = remappings[i].first[1];
- if (originalKey != NULL && !(newKey.index() == 0 && std::get(newKey) == NULL) && !(newKey.index() == 1 && !EditorHelpers::IsValidShortcut(std::get(newKey))))
+ if (originalKey != NULL && !(newKey.index() == 0 && std::get(newKey) == NULL) && !(newKey.index() == 1 && !EditorHelpers::IsValidShortcut(std::get(newKey))) && !(newKey.index() == 2 && std::get(newKey).empty()))
{
// If Ctrl/Alt/Shift are added, add their L and R versions instead to the same key
bool result = false;
- bool res1, res2;
- switch (originalKey)
+ std::vector originalKeysWithModifiers;
+ if (originalKey == VK_CONTROL)
{
- case VK_CONTROL:
- res1 = mappingConfiguration.AddSingleKeyRemap(VK_LCONTROL, newKey);
- res2 = mappingConfiguration.AddSingleKeyRemap(VK_RCONTROL, newKey);
- result = res1 && res2;
- break;
- case VK_MENU:
- res1 = mappingConfiguration.AddSingleKeyRemap(VK_LMENU, newKey);
- res2 = mappingConfiguration.AddSingleKeyRemap(VK_RMENU, newKey);
- result = res1 && res2;
- break;
- case VK_SHIFT:
- res1 = mappingConfiguration.AddSingleKeyRemap(VK_LSHIFT, newKey);
- res2 = mappingConfiguration.AddSingleKeyRemap(VK_RSHIFT, newKey);
- result = res1 && res2;
- break;
- case CommonSharedConstants::VK_WIN_BOTH:
- res1 = mappingConfiguration.AddSingleKeyRemap(VK_LWIN, newKey);
- res2 = mappingConfiguration.AddSingleKeyRemap(VK_RWIN, newKey);
- result = res1 && res2;
- break;
- default:
- result = mappingConfiguration.AddSingleKeyRemap(originalKey, newKey);
+ originalKeysWithModifiers.push_back(VK_LCONTROL);
+ originalKeysWithModifiers.push_back(VK_RCONTROL);
+ }
+ else if (originalKey == VK_MENU)
+ {
+ originalKeysWithModifiers.push_back(VK_LMENU);
+ originalKeysWithModifiers.push_back(VK_RMENU);
+ }
+ else if (originalKey == VK_SHIFT)
+ {
+ originalKeysWithModifiers.push_back(VK_LSHIFT);
+ originalKeysWithModifiers.push_back(VK_RSHIFT);
+ }
+ else if (originalKey == CommonSharedConstants::VK_WIN_BOTH)
+ {
+ originalKeysWithModifiers.push_back(VK_LWIN);
+ originalKeysWithModifiers.push_back(VK_RWIN);
+ }
+ else
+ {
+ originalKeysWithModifiers.push_back(originalKey);
+ }
+
+ for (const DWORD key : originalKeysWithModifiers)
+ {
+ const bool mappedToText = newKey.index() == 2;
+ result = mappedToText ? mappingConfiguration.AddSingleKeyToTextRemap(key, std::get(newKey)) : mappingConfiguration.AddSingleKeyRemap(key, newKey) && result;
}
if (result)
{
if (newKey.index() == 0)
{
- successfulKeyToKeyRemapCount += 1;
+ ++successfulKeyToKeyRemapCount;
}
- else
+ else if (newKey.index() == 1)
{
- successfulKeyToShortcutRemapCount += 1;
+ ++successfulKeyToShortcutRemapCount;
+ }
+ else if (newKey.index() == 2)
+ {
+ ++successfulKeyToTextRemapCount;
}
}
}
@@ -171,7 +185,7 @@ namespace LoadingAndSavingRemappingHelper
// If telemetry is to be logged, log the key remap counts
if (isTelemetryRequired)
{
- Trace::KeyRemapCount(successfulKeyToKeyRemapCount, successfulKeyToShortcutRemapCount);
+ Trace::KeyRemapCount(successfulKeyToKeyRemapCount, successfulKeyToShortcutRemapCount, successfulKeyToTextRemapCount);
}
}
@@ -185,14 +199,14 @@ namespace LoadingAndSavingRemappingHelper
DWORD successfulOSLevelShortcutToKeyRemapCount = 0;
DWORD successfulAppSpecificShortcutToShortcutRemapCount = 0;
DWORD successfulAppSpecificShortcutToKeyRemapCount = 0;
-
+
// Save the shortcuts that are valid and report if any of them were invalid
for (int i = 0; i < remappings.size(); i++)
{
Shortcut originalShortcut = std::get(remappings[i].first[0]);
- KeyShortcutUnion newShortcut = remappings[i].first[1];
+ KeyShortcutTextUnion newShortcut = remappings[i].first[1];
- if (EditorHelpers::IsValidShortcut(originalShortcut) && ((newShortcut.index() == 0 && std::get(newShortcut) != NULL) || (newShortcut.index() == 1 && EditorHelpers::IsValidShortcut(std::get(newShortcut)))))
+ if (EditorHelpers::IsValidShortcut(originalShortcut) && ((newShortcut.index() == 0 && std::get(newShortcut) != NULL) || (newShortcut.index() == 1 && EditorHelpers::IsValidShortcut(std::get(newShortcut))) || (newShortcut.index() == 2 && !std::get(newShortcut).empty())))
{
if (remappings[i].second == L"")
{
diff --git a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/LoadingAndSavingRemappingHelper.h b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/LoadingAndSavingRemappingHelper.h
index db7b47b744..7197959024 100644
--- a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/LoadingAndSavingRemappingHelper.h
+++ b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/LoadingAndSavingRemappingHelper.h
@@ -15,10 +15,10 @@ namespace LoadingAndSavingRemappingHelper
std::vector GetOrphanedKeys(const RemapBuffer& remappings);
// Function to combine remappings if the L and R version of the modifier is mapped to the same key
- void CombineRemappings(std::unordered_map& table, DWORD leftKey, DWORD rightKey, DWORD combinedKey);
+ void CombineRemappings(std::unordered_map& table, DWORD leftKey, DWORD rightKey, DWORD combinedKey);
// Function to pre process the remap table before loading it into the UI
- void PreProcessRemapTable(std::unordered_map& table);
+ void PreProcessRemapTable(std::unordered_map& table);
// Function to apply the single key remappings from the buffer to the KeyboardManagerState variable
void ApplySingleKeyRemappings(MappingConfiguration& mappingConfiguration, const RemapBuffer& remappings, bool isTelemetryRequired);
diff --git a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/ShortcutControl.cpp b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/ShortcutControl.cpp
index b73ddef074..8de7350979 100644
--- a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/ShortcutControl.cpp
+++ b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/ShortcutControl.cpp
@@ -21,7 +21,7 @@ ShortcutControl::ShortcutControl(StackPanel table, StackPanel row, const int col
shortcutDropDownVariableSizedWrapGrid = VariableSizedWrapGrid();
typeShortcut = Button();
shortcutControlLayout = StackPanel();
- bool isHybridControl = colIndex == 1 ? true : false;
+ const bool isHybridControl = colIndex == 1;
// TODO: Check if there is a VariableSizedWrapGrid equivalent.
// shortcutDropDownVariableSizedWrapGrid.as().Spacing(EditorConstants::ShortcutTableDropDownSpacing);
@@ -41,7 +41,13 @@ ShortcutControl::ShortcutControl(StackPanel table, StackPanel row, const int col
shortcutControlLayout.as().Spacing(EditorConstants::ShortcutTableDropDownSpacing);
- shortcutControlLayout.as().Children().Append(typeShortcut.as