mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-11-27 14:59:16 +08:00
[KBM]Allow remapping keys and shortcuts to arbitrary unicode sequences (#29399)
* [KBM] Allow remapping keys and shortcuts to arbitrary unicode sequences * f: spelling * f: tests * f: split shortcut configuration * f: address ui layout comments * [BugReport]Don't report personal info * f: fix crash in KBME * f: add missed type button * f: fix shortcut line UI elements alignment * f: align elements size * f: add warning about non-mapped keys
This commit is contained in:
parent
2543dee1f1
commit
f742d3c1c3
@ -287,6 +287,16 @@
|
|||||||
<value>Key</value>
|
<value>Key</value>
|
||||||
<comment>Key on a keyboard</comment>
|
<comment>Key on a keyboard</comment>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Mapping_Type_DropDown_Text" xml:space="preserve">
|
||||||
|
<value>Text</value>
|
||||||
|
</data>
|
||||||
|
<data name="Mapping_Type_DropDown_Shortcut" xml:space="preserve">
|
||||||
|
<value>Shortcut</value>
|
||||||
|
</data>
|
||||||
|
<data name="Mapping_Type_DropDown_Key" xml:space="preserve">
|
||||||
|
<value>Key</value>
|
||||||
|
<comment>Key on a keyboard</comment>
|
||||||
|
</data>
|
||||||
<data name="Add_Key_Remap_Button" xml:space="preserve">
|
<data name="Add_Key_Remap_Button" xml:space="preserve">
|
||||||
<value>Add key remapping</value>
|
<value>Add key remapping</value>
|
||||||
<comment>Key on a keyboard</comment>
|
<comment>Key on a keyboard</comment>
|
||||||
|
@ -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
|
// 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)
|
if (errorType == ShortcutErrorType::NoError)
|
||||||
{
|
{
|
||||||
KeyShortcutUnion tempShortcut;
|
KeyShortcutTextUnion tempShortcut;
|
||||||
if (isHybridControl && KeyDropDownControl::GetNumberOfSelectedKeys(selectedCodes) == 1)
|
if (isHybridControl && KeyDropDownControl::GetNumberOfSelectedKeys(selectedCodes) == 1)
|
||||||
{
|
{
|
||||||
tempShortcut = (DWORD)*std::find_if(selectedCodes.begin(), selectedCodes.end(), [](int32_t a) { return a != -1 && a != 0; });
|
tempShortcut = (DWORD)*std::find_if(selectedCodes.begin(), selectedCodes.end(), [](int32_t a) { return a != -1 && a != 0; });
|
||||||
|
@ -285,14 +285,21 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMan
|
|||||||
|
|
||||||
// Load existing remaps into UI
|
// Load existing remaps into UI
|
||||||
SingleKeyRemapTable singleKeyRemapCopy = mappingConfiguration.singleKeyReMap;
|
SingleKeyRemapTable singleKeyRemapCopy = mappingConfiguration.singleKeyReMap;
|
||||||
|
SingleKeyToTextRemapTable singleKeyToTextRemapCopy = mappingConfiguration.singleKeyToTextReMap;
|
||||||
|
|
||||||
LoadingAndSavingRemappingHelper::PreProcessRemapTable(singleKeyRemapCopy);
|
LoadingAndSavingRemappingHelper::PreProcessRemapTable(singleKeyRemapCopy);
|
||||||
|
LoadingAndSavingRemappingHelper::PreProcessRemapTable(singleKeyToTextRemapCopy);
|
||||||
|
|
||||||
for (const auto& it : singleKeyRemapCopy)
|
for (const auto& it : singleKeyRemapCopy)
|
||||||
{
|
{
|
||||||
SingleKeyRemapControl::AddNewControlKeyRemapRow(keyRemapTable, keyboardRemapControlObjects, it.first, it.second);
|
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
|
// Main Header Apply button
|
||||||
Button applyButton;
|
Button applyButton;
|
||||||
applyButton.Content(winrt::box_value(GET_RESOURCE_STRING(IDS_OK_BUTTON)));
|
applyButton.Content(winrt::box_value(GET_RESOURCE_STRING(IDS_OK_BUTTON)));
|
||||||
|
@ -35,7 +35,7 @@ namespace EditorConstants
|
|||||||
inline const long ShortcutTableRemoveColIndex = 4;
|
inline const long ShortcutTableRemoveColIndex = 4;
|
||||||
inline const long ShortcutArrowColumnWidth = 90;
|
inline const long ShortcutArrowColumnWidth = 90;
|
||||||
inline const DWORD64 ShortcutTableDropDownWidth = 160;
|
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 ShortcutOriginColumnWidth = 3 * ShortcutTableDropDownWidth + 3 * ShortcutTableDropDownSpacing;
|
||||||
inline const long ShortcutTargetColumnWidth = 3 * ShortcutTableDropDownWidth + 3 * ShortcutTableDropDownSpacing + 15;
|
inline const long ShortcutTargetColumnWidth = 3 * ShortcutTableDropDownWidth + 3 * ShortcutTableDropDownSpacing + 15;
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ void KeyDropDownControl::SetDefaultProperties(bool isShortcut, bool renderDisabl
|
|||||||
}
|
}
|
||||||
|
|
||||||
dropDown.as<ComboBox>().MaxDropDownHeight(EditorConstants::TableDropDownHeight);
|
dropDown.as<ComboBox>().MaxDropDownHeight(EditorConstants::TableDropDownHeight);
|
||||||
|
|
||||||
// Initialise layout attribute
|
// Initialise layout attribute
|
||||||
previousLayout = GetKeyboardLayout(0);
|
previousLayout = GetKeyboardLayout(0);
|
||||||
dropDown.as<ComboBox>().SelectedValuePath(L"DataContext");
|
dropDown.as<ComboBox>().SelectedValuePath(L"DataContext");
|
||||||
@ -83,7 +83,20 @@ void KeyDropDownControl::SetDefaultProperties(bool isShortcut, bool renderDisabl
|
|||||||
// Attach the tip to the drop down
|
// Attach the tip to the drop down
|
||||||
warningTip.Target(dropDown.as<ComboBox>());
|
warningTip.Target(dropDown.as<ComboBox>());
|
||||||
dropDown.as<ComboBox>().Loaded([&](winrt::Windows::Foundation::IInspectable const& sender, auto args) {
|
dropDown.as<ComboBox>().Loaded([&](winrt::Windows::Foundation::IInspectable const& sender, auto args) {
|
||||||
Media::VisualTreeHelper::GetChild(dropDown.as<ComboBox>(), 0).as<Grid>().Children().Append(warningTip);
|
auto combo = dropDown.as<ComboBox>();
|
||||||
|
auto child0 = Media::VisualTreeHelper::GetChild(combo, 0);
|
||||||
|
if (!child0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto grid = child0.as<Grid>();
|
||||||
|
if (!grid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto& gridChildren = grid.Children();
|
||||||
|
if (!gridChildren)
|
||||||
|
return;
|
||||||
|
|
||||||
|
gridChildren.Append(warningTip);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Tip properties
|
// Tip properties
|
||||||
@ -102,7 +115,7 @@ void KeyDropDownControl::SetDefaultProperties(bool isShortcut, bool renderDisabl
|
|||||||
warningFlyout.as<Flyout>().FlyoutPresenterStyle(style);
|
warningFlyout.as<Flyout>().FlyoutPresenterStyle(style);
|
||||||
dropDown.as<ComboBox>().ContextFlyout().SetAttachedFlyout((FrameworkElement)dropDown.as<ComboBox>(), warningFlyout.as<Flyout>());
|
dropDown.as<ComboBox>().ContextFlyout().SetAttachedFlyout((FrameworkElement)dropDown.as<ComboBox>(), warningFlyout.as<Flyout>());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// To set the accessible name of the combo-box (by default index 1)
|
// To set the accessible name of the combo-box (by default index 1)
|
||||||
SetAccessibleNameForComboBox(dropDown.as<ComboBox>(), 1);
|
SetAccessibleNameForComboBox(dropDown.as<ComboBox>(), 1);
|
||||||
}
|
}
|
||||||
@ -141,7 +154,7 @@ void KeyDropDownControl::SetSelectionHandler(StackPanel& table, StackPanel row,
|
|||||||
|
|
||||||
ComboBox currentDropDown = sender.as<ComboBox>();
|
ComboBox currentDropDown = sender.as<ComboBox>();
|
||||||
int selectedKeyCode = GetSelectedValue(currentDropDown);
|
int selectedKeyCode = GetSelectedValue(currentDropDown);
|
||||||
|
|
||||||
// Validate current remap selection
|
// Validate current remap selection
|
||||||
ShortcutErrorType errorType = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(rowIndex, colIndex, selectedKeyCode, singleKeyRemapBuffer);
|
ShortcutErrorType errorType = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(rowIndex, colIndex, selectedKeyCode, singleKeyRemapBuffer);
|
||||||
|
|
||||||
@ -228,7 +241,7 @@ std::pair<ShortcutErrorType, int> KeyDropDownControl::ValidateShortcutSelection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
parent.Children().RemoveAt(dropDownIndex);
|
parent.Children().RemoveAt(dropDownIndex);
|
||||||
|
|
||||||
// delete drop down control object from the vector so that it can be destructed
|
// delete drop down control object from the vector so that it can be destructed
|
||||||
keyDropDownControlObjects.erase(keyDropDownControlObjects.begin() + dropDownIndex);
|
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
|
// Check for errors only if the current selection is a valid shortcut
|
||||||
std::vector<int32_t> selectedKeyCodes = GetSelectedCodesFromStackPanel(parent);
|
std::vector<int32_t> selectedKeyCodes = GetSelectedCodesFromStackPanel(parent);
|
||||||
KeyShortcutUnion currentShortcut;
|
KeyShortcutTextUnion currentShortcut;
|
||||||
if (GetNumberOfSelectedKeys(selectedKeyCodes) == 1 && isHybridControl)
|
if (GetNumberOfSelectedKeys(selectedKeyCodes) == 1 && isHybridControl)
|
||||||
{
|
{
|
||||||
currentShortcut = (DWORD)selectedKeyCodes[0];
|
currentShortcut = (DWORD)selectedKeyCodes[0];
|
||||||
@ -415,7 +428,7 @@ void KeyDropDownControl::AddShortcutToControl(Shortcut shortcut, StackPanel tabl
|
|||||||
{
|
{
|
||||||
// Delete the existing drop down menus
|
// Delete the existing drop down menus
|
||||||
parent.Children().Clear();
|
parent.Children().Clear();
|
||||||
|
|
||||||
// Remove references to the old drop down objects to destroy them
|
// Remove references to the old drop down objects to destroy them
|
||||||
keyDropDownControlObjects.clear();
|
keyDropDownControlObjects.clear();
|
||||||
std::vector<DWORD> shortcutKeyCodes = shortcut.GetKeyCodes();
|
std::vector<DWORD> shortcutKeyCodes = shortcut.GetKeyCodes();
|
||||||
|
@ -11,7 +11,22 @@ namespace KeyboardManagerEditorStrings
|
|||||||
{
|
{
|
||||||
return GET_RESOURCE_STRING(IDS_EDITSHORTCUTS_ALLAPPS);
|
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
|
// Function to return the error message
|
||||||
winrt::hstring GetErrorMessage(ShortcutErrorType errorType);
|
winrt::hstring GetErrorMessage(ShortcutErrorType errorType);
|
||||||
}
|
}
|
||||||
|
@ -17,20 +17,20 @@ namespace LoadingAndSavingRemappingHelper
|
|||||||
ShortcutErrorType CheckIfRemappingsAreValid(const RemapBuffer& remappings)
|
ShortcutErrorType CheckIfRemappingsAreValid(const RemapBuffer& remappings)
|
||||||
{
|
{
|
||||||
ShortcutErrorType isSuccess = ShortcutErrorType::NoError;
|
ShortcutErrorType isSuccess = ShortcutErrorType::NoError;
|
||||||
std::map<std::wstring, std::set<KeyShortcutUnion>> ogKeys;
|
std::map<std::wstring, std::set<KeyShortcutTextUnion>> ogKeys;
|
||||||
for (int i = 0; i < remappings.size(); i++)
|
for (int i = 0; i < remappings.size(); i++)
|
||||||
{
|
{
|
||||||
KeyShortcutUnion ogKey = remappings[i].first[0];
|
KeyShortcutTextUnion ogKey = remappings[i].first[0];
|
||||||
KeyShortcutUnion newKey = remappings[i].first[1];
|
KeyShortcutTextUnion newKey = remappings[i].first[1];
|
||||||
std::wstring appName = remappings[i].second;
|
std::wstring appName = remappings[i].second;
|
||||||
|
|
||||||
bool ogKeyValidity = (ogKey.index() == 0 && std::get<DWORD>(ogKey) != NULL) || (ogKey.index() == 1 && EditorHelpers::IsValidShortcut(std::get<Shortcut>(ogKey)));
|
const bool ogKeyValidity = (ogKey.index() == 0 && std::get<DWORD>(ogKey) != NULL) || (ogKey.index() == 1 && EditorHelpers::IsValidShortcut(std::get<Shortcut>(ogKey)));
|
||||||
bool newKeyValidity = (newKey.index() == 0 && std::get<DWORD>(newKey) != NULL) || (newKey.index() == 1 && EditorHelpers::IsValidShortcut(std::get<Shortcut>(newKey)));
|
const bool newKeyValidity = (newKey.index() == 0 && std::get<DWORD>(newKey) != NULL) || (newKey.index() == 1 && EditorHelpers::IsValidShortcut(std::get<Shortcut>(newKey))) || (newKey.index() == 2 && !std::get<std::wstring>(newKey).empty());
|
||||||
|
|
||||||
// Add new set for a new target app name
|
// Add new set for a new target app name
|
||||||
if (ogKeys.find(appName) == ogKeys.end())
|
if (ogKeys.find(appName) == ogKeys.end())
|
||||||
{
|
{
|
||||||
ogKeys[appName] = std::set<KeyShortcutUnion>();
|
ogKeys[appName] = std::set<KeyShortcutTextUnion>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ogKeyValidity && newKeyValidity && ogKeys[appName].find(ogKey) == ogKeys[appName].end())
|
if (ogKeyValidity && newKeyValidity && ogKeys[appName].find(ogKey) == ogKeys[appName].end())
|
||||||
@ -59,9 +59,12 @@ namespace LoadingAndSavingRemappingHelper
|
|||||||
for (int i = 0; i < remappings.size(); i++)
|
for (int i = 0; i < remappings.size(); i++)
|
||||||
{
|
{
|
||||||
DWORD ogKey = std::get<DWORD>(remappings[i].first[0]);
|
DWORD ogKey = std::get<DWORD>(remappings[i].first[0]);
|
||||||
KeyShortcutUnion newKey = remappings[i].first[1];
|
KeyShortcutTextUnion newKey = remappings[i].first[1];
|
||||||
|
|
||||||
if (ogKey != NULL && ((newKey.index() == 0 && std::get<DWORD>(newKey) != 0) || (newKey.index() == 1 && EditorHelpers::IsValidShortcut(std::get<Shortcut>(newKey)))))
|
const bool hasValidKeyRemapping = newKey.index() == 0 && std::get<DWORD>(newKey) != 0;
|
||||||
|
const bool hasValidShortcutRemapping = newKey.index() == 1 && EditorHelpers::IsValidShortcut(std::get<Shortcut>(newKey));
|
||||||
|
const bool hasValidTextRemapping = newKey.index() == 2 && !std::get<std::wstring>(newKey).empty();
|
||||||
|
if (ogKey != NULL && (hasValidKeyRemapping || hasValidShortcutRemapping || hasValidTextRemapping))
|
||||||
{
|
{
|
||||||
ogKeys.insert(ogKey);
|
ogKeys.insert(ogKey);
|
||||||
|
|
||||||
@ -116,53 +119,64 @@ namespace LoadingAndSavingRemappingHelper
|
|||||||
{
|
{
|
||||||
// Clear existing Key Remaps
|
// Clear existing Key Remaps
|
||||||
mappingConfiguration.ClearSingleKeyRemaps();
|
mappingConfiguration.ClearSingleKeyRemaps();
|
||||||
|
mappingConfiguration.ClearSingleKeyToTextRemaps();
|
||||||
DWORD successfulKeyToKeyRemapCount = 0;
|
DWORD successfulKeyToKeyRemapCount = 0;
|
||||||
DWORD successfulKeyToShortcutRemapCount = 0;
|
DWORD successfulKeyToShortcutRemapCount = 0;
|
||||||
|
DWORD successfulKeyToTextRemapCount = 0;
|
||||||
for (int i = 0; i < remappings.size(); i++)
|
for (int i = 0; i < remappings.size(); i++)
|
||||||
{
|
{
|
||||||
DWORD originalKey = std::get<DWORD>(remappings[i].first[0]);
|
const DWORD originalKey = std::get<DWORD>(remappings[i].first[0]);
|
||||||
KeyShortcutUnion newKey = remappings[i].first[1];
|
KeyShortcutTextUnion newKey = remappings[i].first[1];
|
||||||
|
|
||||||
if (originalKey != NULL && !(newKey.index() == 0 && std::get<DWORD>(newKey) == NULL) && !(newKey.index() == 1 && !EditorHelpers::IsValidShortcut(std::get<Shortcut>(newKey))))
|
if (originalKey != NULL && !(newKey.index() == 0 && std::get<DWORD>(newKey) == NULL) && !(newKey.index() == 1 && !EditorHelpers::IsValidShortcut(std::get<Shortcut>(newKey))) && !(newKey.index() == 2 && std::get<std::wstring>(newKey).empty()))
|
||||||
{
|
{
|
||||||
// If Ctrl/Alt/Shift are added, add their L and R versions instead to the same key
|
// If Ctrl/Alt/Shift are added, add their L and R versions instead to the same key
|
||||||
bool result = false;
|
bool result = false;
|
||||||
bool res1, res2;
|
std::vector<DWORD> originalKeysWithModifiers;
|
||||||
switch (originalKey)
|
if (originalKey == VK_CONTROL)
|
||||||
{
|
{
|
||||||
case VK_CONTROL:
|
originalKeysWithModifiers.push_back(VK_LCONTROL);
|
||||||
res1 = mappingConfiguration.AddSingleKeyRemap(VK_LCONTROL, newKey);
|
originalKeysWithModifiers.push_back(VK_RCONTROL);
|
||||||
res2 = mappingConfiguration.AddSingleKeyRemap(VK_RCONTROL, newKey);
|
}
|
||||||
result = res1 && res2;
|
else if (originalKey == VK_MENU)
|
||||||
break;
|
{
|
||||||
case VK_MENU:
|
originalKeysWithModifiers.push_back(VK_LMENU);
|
||||||
res1 = mappingConfiguration.AddSingleKeyRemap(VK_LMENU, newKey);
|
originalKeysWithModifiers.push_back(VK_RMENU);
|
||||||
res2 = mappingConfiguration.AddSingleKeyRemap(VK_RMENU, newKey);
|
}
|
||||||
result = res1 && res2;
|
else if (originalKey == VK_SHIFT)
|
||||||
break;
|
{
|
||||||
case VK_SHIFT:
|
originalKeysWithModifiers.push_back(VK_LSHIFT);
|
||||||
res1 = mappingConfiguration.AddSingleKeyRemap(VK_LSHIFT, newKey);
|
originalKeysWithModifiers.push_back(VK_RSHIFT);
|
||||||
res2 = mappingConfiguration.AddSingleKeyRemap(VK_RSHIFT, newKey);
|
}
|
||||||
result = res1 && res2;
|
else if (originalKey == CommonSharedConstants::VK_WIN_BOTH)
|
||||||
break;
|
{
|
||||||
case CommonSharedConstants::VK_WIN_BOTH:
|
originalKeysWithModifiers.push_back(VK_LWIN);
|
||||||
res1 = mappingConfiguration.AddSingleKeyRemap(VK_LWIN, newKey);
|
originalKeysWithModifiers.push_back(VK_RWIN);
|
||||||
res2 = mappingConfiguration.AddSingleKeyRemap(VK_RWIN, newKey);
|
}
|
||||||
result = res1 && res2;
|
else
|
||||||
break;
|
{
|
||||||
default:
|
originalKeysWithModifiers.push_back(originalKey);
|
||||||
result = mappingConfiguration.AddSingleKeyRemap(originalKey, newKey);
|
}
|
||||||
|
|
||||||
|
for (const DWORD key : originalKeysWithModifiers)
|
||||||
|
{
|
||||||
|
const bool mappedToText = newKey.index() == 2;
|
||||||
|
result = mappedToText ? mappingConfiguration.AddSingleKeyToTextRemap(key, std::get<std::wstring>(newKey)) : mappingConfiguration.AddSingleKeyRemap(key, newKey) && result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
if (newKey.index() == 0)
|
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 telemetry is to be logged, log the key remap counts
|
||||||
if (isTelemetryRequired)
|
if (isTelemetryRequired)
|
||||||
{
|
{
|
||||||
Trace::KeyRemapCount(successfulKeyToKeyRemapCount, successfulKeyToShortcutRemapCount);
|
Trace::KeyRemapCount(successfulKeyToKeyRemapCount, successfulKeyToShortcutRemapCount, successfulKeyToTextRemapCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,14 +199,14 @@ namespace LoadingAndSavingRemappingHelper
|
|||||||
DWORD successfulOSLevelShortcutToKeyRemapCount = 0;
|
DWORD successfulOSLevelShortcutToKeyRemapCount = 0;
|
||||||
DWORD successfulAppSpecificShortcutToShortcutRemapCount = 0;
|
DWORD successfulAppSpecificShortcutToShortcutRemapCount = 0;
|
||||||
DWORD successfulAppSpecificShortcutToKeyRemapCount = 0;
|
DWORD successfulAppSpecificShortcutToKeyRemapCount = 0;
|
||||||
|
|
||||||
// Save the shortcuts that are valid and report if any of them were invalid
|
// Save the shortcuts that are valid and report if any of them were invalid
|
||||||
for (int i = 0; i < remappings.size(); i++)
|
for (int i = 0; i < remappings.size(); i++)
|
||||||
{
|
{
|
||||||
Shortcut originalShortcut = std::get<Shortcut>(remappings[i].first[0]);
|
Shortcut originalShortcut = std::get<Shortcut>(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<DWORD>(newShortcut) != NULL) || (newShortcut.index() == 1 && EditorHelpers::IsValidShortcut(std::get<Shortcut>(newShortcut)))))
|
if (EditorHelpers::IsValidShortcut(originalShortcut) && ((newShortcut.index() == 0 && std::get<DWORD>(newShortcut) != NULL) || (newShortcut.index() == 1 && EditorHelpers::IsValidShortcut(std::get<Shortcut>(newShortcut))) || (newShortcut.index() == 2 && !std::get<std::wstring>(newShortcut).empty())))
|
||||||
{
|
{
|
||||||
if (remappings[i].second == L"")
|
if (remappings[i].second == L"")
|
||||||
{
|
{
|
||||||
|
@ -15,10 +15,10 @@ namespace LoadingAndSavingRemappingHelper
|
|||||||
std::vector<DWORD> GetOrphanedKeys(const RemapBuffer& remappings);
|
std::vector<DWORD> GetOrphanedKeys(const RemapBuffer& remappings);
|
||||||
|
|
||||||
// Function to combine remappings if the L and R version of the modifier is mapped to the same key
|
// Function to combine remappings if the L and R version of the modifier is mapped to the same key
|
||||||
void CombineRemappings(std::unordered_map<DWORD, KeyShortcutUnion>& table, DWORD leftKey, DWORD rightKey, DWORD combinedKey);
|
void CombineRemappings(std::unordered_map<DWORD, KeyShortcutTextUnion>& table, DWORD leftKey, DWORD rightKey, DWORD combinedKey);
|
||||||
|
|
||||||
// Function to pre process the remap table before loading it into the UI
|
// Function to pre process the remap table before loading it into the UI
|
||||||
void PreProcessRemapTable(std::unordered_map<DWORD, KeyShortcutUnion>& table);
|
void PreProcessRemapTable(std::unordered_map<DWORD, KeyShortcutTextUnion>& table);
|
||||||
|
|
||||||
// Function to apply the single key remappings from the buffer to the KeyboardManagerState variable
|
// Function to apply the single key remappings from the buffer to the KeyboardManagerState variable
|
||||||
void ApplySingleKeyRemappings(MappingConfiguration& mappingConfiguration, const RemapBuffer& remappings, bool isTelemetryRequired);
|
void ApplySingleKeyRemappings(MappingConfiguration& mappingConfiguration, const RemapBuffer& remappings, bool isTelemetryRequired);
|
||||||
|
@ -21,7 +21,7 @@ ShortcutControl::ShortcutControl(StackPanel table, StackPanel row, const int col
|
|||||||
shortcutDropDownVariableSizedWrapGrid = VariableSizedWrapGrid();
|
shortcutDropDownVariableSizedWrapGrid = VariableSizedWrapGrid();
|
||||||
typeShortcut = Button();
|
typeShortcut = Button();
|
||||||
shortcutControlLayout = StackPanel();
|
shortcutControlLayout = StackPanel();
|
||||||
bool isHybridControl = colIndex == 1 ? true : false;
|
const bool isHybridControl = colIndex == 1;
|
||||||
|
|
||||||
// TODO: Check if there is a VariableSizedWrapGrid equivalent.
|
// TODO: Check if there is a VariableSizedWrapGrid equivalent.
|
||||||
// shortcutDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>().Spacing(EditorConstants::ShortcutTableDropDownSpacing);
|
// shortcutDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>().Spacing(EditorConstants::ShortcutTableDropDownSpacing);
|
||||||
@ -41,7 +41,13 @@ ShortcutControl::ShortcutControl(StackPanel table, StackPanel row, const int col
|
|||||||
|
|
||||||
shortcutControlLayout.as<StackPanel>().Spacing(EditorConstants::ShortcutTableDropDownSpacing);
|
shortcutControlLayout.as<StackPanel>().Spacing(EditorConstants::ShortcutTableDropDownSpacing);
|
||||||
|
|
||||||
shortcutControlLayout.as<StackPanel>().Children().Append(typeShortcut.as<Button>());
|
keyComboAndSelectStackPanel = StackPanel();
|
||||||
|
keyComboAndSelectStackPanel.as<StackPanel>().Orientation(Windows::UI::Xaml::Controls::Orientation::Horizontal);
|
||||||
|
keyComboAndSelectStackPanel.as<StackPanel>().Spacing(EditorConstants::ShortcutTableDropDownSpacing);
|
||||||
|
|
||||||
|
keyComboAndSelectStackPanel.as<StackPanel>().Children().Append(typeShortcut.as<Button>());
|
||||||
|
shortcutControlLayout.as<StackPanel>().Children().InsertAt(0, keyComboAndSelectStackPanel.as<StackPanel>());
|
||||||
|
|
||||||
shortcutControlLayout.as<StackPanel>().Children().Append(shortcutDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>());
|
shortcutControlLayout.as<StackPanel>().Children().Append(shortcutDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>());
|
||||||
KeyDropDownControl::AddDropDown(table, row, shortcutDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>(), colIndex, shortcutRemapBuffer, keyDropDownControlObjects, targetApp, isHybridControl, false);
|
KeyDropDownControl::AddDropDown(table, row, shortcutDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>(), colIndex, shortcutRemapBuffer, keyDropDownControlObjects, targetApp, isHybridControl, false);
|
||||||
try
|
try
|
||||||
@ -63,7 +69,7 @@ void ShortcutControl::SetAccessibleNameForTextBox(TextBox targetAppTextBox, int
|
|||||||
{
|
{
|
||||||
targetAppTextBoxAccessibleName += GET_RESOURCE_STRING(IDS_EDITSHORTCUTS_ALLAPPS);
|
targetAppTextBoxAccessibleName += GET_RESOURCE_STRING(IDS_EDITSHORTCUTS_ALLAPPS);
|
||||||
}
|
}
|
||||||
|
|
||||||
targetAppTextBox.SetValue(Automation::AutomationProperties::NameProperty(), box_value(targetAppTextBoxAccessibleName));
|
targetAppTextBox.SetValue(Automation::AutomationProperties::NameProperty(), box_value(targetAppTextBoxAccessibleName));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +83,7 @@ void ShortcutControl::UpdateAccessibleNames(StackPanel sourceColumn, StackPanel
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Function to add a new row to the shortcut table. If the originalKeys and newKeys args are provided, then the displayed shortcuts are set to those values.
|
// Function to add a new row to the shortcut table. If the originalKeys and newKeys args are provided, then the displayed shortcuts are set to those values.
|
||||||
void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<std::vector<std::unique_ptr<ShortcutControl>>>& keyboardRemapControlObjects, const Shortcut& originalKeys, const KeyShortcutUnion& newKeys, const std::wstring& targetAppName)
|
void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<std::vector<std::unique_ptr<ShortcutControl>>>& keyboardRemapControlObjects, const Shortcut& originalKeys, const KeyShortcutTextUnion& newKeys, const std::wstring& targetAppName)
|
||||||
{
|
{
|
||||||
// Textbox for target application
|
// Textbox for target application
|
||||||
TextBox targetAppTextBox;
|
TextBox targetAppTextBox;
|
||||||
@ -115,6 +121,60 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
|
|||||||
// ShortcutControl for the new shortcut
|
// ShortcutControl for the new shortcut
|
||||||
auto target = keyboardRemapControlObjects.back()[1]->GetShortcutControl();
|
auto target = keyboardRemapControlObjects.back()[1]->GetShortcutControl();
|
||||||
target.Width(EditorConstants::ShortcutTargetColumnWidth);
|
target.Width(EditorConstants::ShortcutTargetColumnWidth);
|
||||||
|
|
||||||
|
auto typeCombo = ComboBox();
|
||||||
|
typeCombo.Width(EditorConstants::RemapTableDropDownWidth);
|
||||||
|
typeCombo.Items().Append(winrt::box_value(KeyboardManagerEditorStrings::MappingTypeShortcut()));
|
||||||
|
typeCombo.Items().Append(winrt::box_value(KeyboardManagerEditorStrings::MappingTypeText()));
|
||||||
|
auto controlStackPanel = keyboardRemapControlObjects.back()[1]->shortcutControlLayout.as<StackPanel>();
|
||||||
|
auto firstLineStackPanel = keyboardRemapControlObjects.back()[1]->keyComboAndSelectStackPanel.as<StackPanel>();
|
||||||
|
firstLineStackPanel.Children().InsertAt(0, typeCombo);
|
||||||
|
|
||||||
|
auto textInput = TextBox();
|
||||||
|
auto textInputMargin = Windows::UI::Xaml::Thickness();
|
||||||
|
textInputMargin.Top = -EditorConstants::ShortcutTableDropDownSpacing;
|
||||||
|
textInputMargin.Bottom = EditorConstants::ShortcutTableDropDownSpacing; // compensate for a collapsed UIElement
|
||||||
|
textInput.Margin(textInputMargin);
|
||||||
|
|
||||||
|
textInput.AcceptsReturn(false);
|
||||||
|
textInput.Visibility(Visibility::Collapsed);
|
||||||
|
textInput.Width(EditorConstants::TableDropDownHeight);
|
||||||
|
controlStackPanel.Children().Append(textInput);
|
||||||
|
textInput.HorizontalAlignment(HorizontalAlignment::Left);
|
||||||
|
textInput.TextChanged([parent, row](winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Controls::TextChangedEventArgs const& e) mutable {
|
||||||
|
auto textbox = sender.as<TextBox>();
|
||||||
|
auto text = textbox.Text();
|
||||||
|
uint32_t rowIndex = -1;
|
||||||
|
|
||||||
|
if (!parent.Children().IndexOf(row, rowIndex))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
shortcutRemapBuffer[rowIndex].first[1] = text.c_str();
|
||||||
|
});
|
||||||
|
|
||||||
|
auto grid = keyboardRemapControlObjects.back()[1]->shortcutDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>();
|
||||||
|
auto gridMargin = Windows::UI::Xaml::Thickness();
|
||||||
|
gridMargin.Bottom = -EditorConstants::ShortcutTableDropDownSpacing; // compensate for a collapsed textInput
|
||||||
|
grid.Margin(gridMargin);
|
||||||
|
auto button = keyboardRemapControlObjects.back()[1]->typeShortcut.as<Button>();
|
||||||
|
|
||||||
|
typeCombo.SelectionChanged([typeCombo, grid, button, textInput](winrt::Windows::Foundation::IInspectable const&, SelectionChangedEventArgs const&) {
|
||||||
|
const bool textSelected = typeCombo.SelectedIndex() == 1;
|
||||||
|
|
||||||
|
const auto shortcutInputVisibility = textSelected ? Visibility::Collapsed : Visibility::Visible;
|
||||||
|
|
||||||
|
grid.Visibility(shortcutInputVisibility);
|
||||||
|
button.Visibility(shortcutInputVisibility);
|
||||||
|
|
||||||
|
const auto textInputVisibility = textSelected ? Visibility::Visible : Visibility::Collapsed;
|
||||||
|
textInput.Visibility(textInputVisibility);
|
||||||
|
});
|
||||||
|
|
||||||
|
const bool textSelected = newKeys.index() == 2;
|
||||||
|
typeCombo.SelectedIndex(textSelected);
|
||||||
|
|
||||||
row.Children().Append(target);
|
row.Children().Append(target);
|
||||||
|
|
||||||
targetAppTextBox.Width(EditorConstants::ShortcutTableDropDownWidth);
|
targetAppTextBox.Width(EditorConstants::ShortcutTableDropDownWidth);
|
||||||
@ -129,7 +189,7 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
|
|||||||
});
|
});
|
||||||
|
|
||||||
// LostFocus handler will be called whenever text is updated by a user and then they click something else or tab to another control. Does not get called if Text is updated while the TextBox isn't in focus (i.e. from code)
|
// LostFocus handler will be called whenever text is updated by a user and then they click something else or tab to another control. Does not get called if Text is updated while the TextBox isn't in focus (i.e. from code)
|
||||||
targetAppTextBox.LostFocus([&keyboardRemapControlObjects, parent, row, targetAppTextBox](auto const& sender, auto const& e) {
|
targetAppTextBox.LostFocus([&keyboardRemapControlObjects, parent, row, targetAppTextBox, typeCombo, textInput](auto const& sender, auto const& e) {
|
||||||
// Get index of targetAppTextBox button
|
// Get index of targetAppTextBox button
|
||||||
uint32_t rowIndex;
|
uint32_t rowIndex;
|
||||||
if (!parent.Children().IndexOf(row, rowIndex))
|
if (!parent.Children().IndexOf(row, rowIndex))
|
||||||
@ -151,19 +211,27 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
|
|||||||
std::get<Shortcut>(shortcutRemapBuffer[rowIndex].first[0]).SetKeyCodes(KeyDropDownControl::GetSelectedCodesFromStackPanel(keyboardRemapControlObjects[rowIndex][0]->shortcutDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>()));
|
std::get<Shortcut>(shortcutRemapBuffer[rowIndex].first[0]).SetKeyCodes(KeyDropDownControl::GetSelectedCodesFromStackPanel(keyboardRemapControlObjects[rowIndex][0]->shortcutDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>()));
|
||||||
// second column is a hybrid column
|
// second column is a hybrid column
|
||||||
|
|
||||||
std::vector<int32_t> selectedKeyCodes = KeyDropDownControl::GetSelectedCodesFromStackPanel(keyboardRemapControlObjects[rowIndex][1]->shortcutDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>());
|
const bool textSelected = typeCombo.SelectedIndex() == 1;
|
||||||
|
if (textSelected)
|
||||||
// If exactly one key is selected consider it to be a key remap
|
|
||||||
if (selectedKeyCodes.size() == 1)
|
|
||||||
{
|
{
|
||||||
shortcutRemapBuffer[rowIndex].first[1] = (DWORD)selectedKeyCodes[0];
|
shortcutRemapBuffer[rowIndex].first[1] = textInput.Text().c_str();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Shortcut tempShortcut;
|
std::vector<int32_t> selectedKeyCodes = KeyDropDownControl::GetSelectedCodesFromStackPanel(keyboardRemapControlObjects[rowIndex][1]->shortcutDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>());
|
||||||
tempShortcut.SetKeyCodes(selectedKeyCodes);
|
|
||||||
// Assign instead of setting the value in the buffer since the previous value may not be a Shortcut
|
// If exactly one key is selected consider it to be a key remap
|
||||||
shortcutRemapBuffer[rowIndex].first[1] = tempShortcut;
|
if (selectedKeyCodes.size() == 1)
|
||||||
|
{
|
||||||
|
shortcutRemapBuffer[rowIndex].first[1] = (DWORD)selectedKeyCodes[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Shortcut tempShortcut;
|
||||||
|
tempShortcut.SetKeyCodes(selectedKeyCodes);
|
||||||
|
// Assign instead of setting the value in the buffer since the previous value may not be a Shortcut
|
||||||
|
shortcutRemapBuffer[rowIndex].first[1] = tempShortcut;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
std::wstring newText = targetAppTextBox.Text().c_str();
|
std::wstring newText = targetAppTextBox.Text().c_str();
|
||||||
std::wstring lowercaseDefAppName = KeyboardManagerEditorStrings::DefaultAppName();
|
std::wstring lowercaseDefAppName = KeyboardManagerEditorStrings::DefaultAppName();
|
||||||
@ -263,10 +331,19 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
|
|||||||
{
|
{
|
||||||
keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1]->keyDropDownControlObjects[0]->SetSelectedValue(std::to_wstring(std::get<DWORD>(newKeys)));
|
keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1]->keyDropDownControlObjects[0]->SetSelectedValue(std::to_wstring(std::get<DWORD>(newKeys)));
|
||||||
}
|
}
|
||||||
else
|
else if (newKeys.index() == 1)
|
||||||
{
|
{
|
||||||
KeyDropDownControl::AddShortcutToControl(std::get<Shortcut>(newKeys), parent, keyboardRemapControlObjects.back()[1]->shortcutDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>(), *keyboardManagerState, 1, keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1]->keyDropDownControlObjects, shortcutRemapBuffer, row, targetAppTextBox, true, false);
|
KeyDropDownControl::AddShortcutToControl(std::get<Shortcut>(newKeys), parent, keyboardRemapControlObjects.back()[1]->shortcutDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>(), *keyboardManagerState, 1, keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1]->keyDropDownControlObjects, shortcutRemapBuffer, row, targetAppTextBox, true, false);
|
||||||
}
|
}
|
||||||
|
else if (newKeys.index() == 2)
|
||||||
|
{
|
||||||
|
shortcutRemapBuffer.back().first[1] = std::get<std::wstring>(newKeys);
|
||||||
|
const auto& remapControl = keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1];
|
||||||
|
const auto& controlChildren = remapControl->GetShortcutControl().Children();
|
||||||
|
const auto& topLineChildren = controlChildren.GetAt(0).as<StackPanel>();
|
||||||
|
topLineChildren.Children().GetAt(0).as<ComboBox>().SelectedIndex(1);
|
||||||
|
controlChildren.GetAt(2).as<TextBox>().Text(std::get<std::wstring>(newKeys));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -291,8 +368,8 @@ void ShortcutControl::CreateDetectShortcutWindow(winrt::Windows::Foundation::IIn
|
|||||||
detectShortcutBox.XamlRoot(xamlRoot);
|
detectShortcutBox.XamlRoot(xamlRoot);
|
||||||
detectShortcutBox.Title(box_value(GET_RESOURCE_STRING(IDS_TYPESHORTCUT_TITLE)));
|
detectShortcutBox.Title(box_value(GET_RESOURCE_STRING(IDS_TYPESHORTCUT_TITLE)));
|
||||||
|
|
||||||
// Get the linked stack panel for the "Type shortcut" button that was clicked
|
// Get the parent linked stack panel for the "Type shortcut" button that was clicked
|
||||||
VariableSizedWrapGrid linkedShortcutVariableSizedWrapGrid = UIHelpers::GetSiblingElement(sender).as<VariableSizedWrapGrid>();
|
VariableSizedWrapGrid linkedShortcutVariableSizedWrapGrid = UIHelpers::GetSiblingElement(sender.as<FrameworkElement>().Parent()).as<VariableSizedWrapGrid>();
|
||||||
|
|
||||||
auto unregisterKeys = [&keyboardManagerState]() {
|
auto unregisterKeys = [&keyboardManagerState]() {
|
||||||
keyboardManagerState.ClearRegisteredKeyDelays();
|
keyboardManagerState.ClearRegisteredKeyDelays();
|
||||||
|
@ -31,6 +31,9 @@ private:
|
|||||||
// StackPanel to parent the above controls
|
// StackPanel to parent the above controls
|
||||||
winrt::Windows::Foundation::IInspectable shortcutControlLayout;
|
winrt::Windows::Foundation::IInspectable shortcutControlLayout;
|
||||||
|
|
||||||
|
// StackPanel to parent the first line of "To" Column
|
||||||
|
winrt::Windows::Foundation::IInspectable keyComboAndSelectStackPanel;
|
||||||
|
|
||||||
// Function to set the accessible name of the target app text box
|
// Function to set the accessible name of the target app text box
|
||||||
static void SetAccessibleNameForTextBox(TextBox targetAppTextBox, int rowIndex);
|
static void SetAccessibleNameForTextBox(TextBox targetAppTextBox, int rowIndex);
|
||||||
|
|
||||||
@ -54,7 +57,7 @@ public:
|
|||||||
ShortcutControl(StackPanel table, StackPanel row, const int colIndex, TextBox targetApp);
|
ShortcutControl(StackPanel table, StackPanel row, const int colIndex, TextBox targetApp);
|
||||||
|
|
||||||
// Function to add a new row to the shortcut table. If the originalKeys and newKeys args are provided, then the displayed shortcuts are set to those values.
|
// Function to add a new row to the shortcut table. If the originalKeys and newKeys args are provided, then the displayed shortcuts are set to those values.
|
||||||
static void AddNewShortcutControlRow(StackPanel& parent, std::vector<std::vector<std::unique_ptr<ShortcutControl>>>& keyboardRemapControlObjects, const Shortcut& originalKeys = Shortcut(), const KeyShortcutUnion& newKeys = Shortcut(), const std::wstring& targetAppName = L"");
|
static void AddNewShortcutControlRow(StackPanel& parent, std::vector<std::vector<std::unique_ptr<ShortcutControl>>>& keyboardRemapControlObjects, const Shortcut& originalKeys = Shortcut(), const KeyShortcutTextUnion& newKeys = Shortcut(), const std::wstring& targetAppName = L"");
|
||||||
|
|
||||||
// Function to return the stack panel element of the ShortcutControl. This is the externally visible UI element which can be used to add it to other layouts
|
// Function to return the stack panel element of the ShortcutControl. This is the externally visible UI element which can be used to add it to other layouts
|
||||||
StackPanel GetShortcutControl();
|
StackPanel GetShortcutControl();
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "SingleKeyRemapControl.h"
|
#include "SingleKeyRemapControl.h"
|
||||||
|
|
||||||
#include "KeyboardManagerState.h"
|
#include "KeyboardManagerState.h"
|
||||||
|
#include "KeyboardManagerEditorStrings.h"
|
||||||
#include "ShortcutControl.h"
|
#include "ShortcutControl.h"
|
||||||
#include "UIHelpers.h"
|
#include "UIHelpers.h"
|
||||||
#include "EditorHelpers.h"
|
#include "EditorHelpers.h"
|
||||||
@ -20,25 +21,80 @@ SingleKeyRemapControl::SingleKeyRemapControl(StackPanel table, StackPanel row, c
|
|||||||
typeKey.as<Button>().Content(winrt::box_value(GET_RESOURCE_STRING(IDS_TYPE_BUTTON)));
|
typeKey.as<Button>().Content(winrt::box_value(GET_RESOURCE_STRING(IDS_TYPE_BUTTON)));
|
||||||
|
|
||||||
singleKeyRemapControlLayout = StackPanel();
|
singleKeyRemapControlLayout = StackPanel();
|
||||||
singleKeyRemapControlLayout.as<StackPanel>().Spacing(10);
|
singleKeyRemapControlLayout.as<StackPanel>().Spacing(EditorConstants::ShortcutTableDropDownSpacing);
|
||||||
singleKeyRemapControlLayout.as<StackPanel>().Children().Append(typeKey.as<Button>());
|
|
||||||
|
|
||||||
// Key column
|
// Key column (From key)
|
||||||
if (colIndex == 0)
|
if (colIndex == 0)
|
||||||
{
|
{
|
||||||
|
singleKeyRemapControlLayout.as<StackPanel>().Children().Append(typeKey.as<Button>());
|
||||||
|
|
||||||
keyDropDownControlObjects.emplace_back(std::make_unique<KeyDropDownControl>(false));
|
keyDropDownControlObjects.emplace_back(std::make_unique<KeyDropDownControl>(false));
|
||||||
singleKeyRemapControlLayout.as<StackPanel>().Children().Append(keyDropDownControlObjects[0]->GetComboBox());
|
singleKeyRemapControlLayout.as<StackPanel>().Children().Append(keyDropDownControlObjects[0]->GetComboBox());
|
||||||
// Set selection handler for the drop down
|
// Set selection handler for the drop down
|
||||||
keyDropDownControlObjects[0]->SetSelectionHandler(table, row, colIndex, singleKeyRemapBuffer);
|
keyDropDownControlObjects[0]->SetSelectionHandler(table, row, colIndex, singleKeyRemapBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hybrid column
|
// Hybrid column (To Key/Shortcut/Text)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
StackPanel keyComboAndSelectStackPanel;
|
||||||
|
keyComboAndSelectStackPanel.Orientation(Windows::UI::Xaml::Controls::Orientation::Horizontal);
|
||||||
|
keyComboAndSelectStackPanel.Spacing(EditorConstants::ShortcutTableDropDownSpacing);
|
||||||
|
|
||||||
hybridDropDownVariableSizedWrapGrid = VariableSizedWrapGrid();
|
hybridDropDownVariableSizedWrapGrid = VariableSizedWrapGrid();
|
||||||
hybridDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>().Orientation(Windows::UI::Xaml::Controls::Orientation::Horizontal);
|
auto grid = hybridDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>();
|
||||||
KeyDropDownControl::AddDropDown(table, row, hybridDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>(), colIndex, singleKeyRemapBuffer, keyDropDownControlObjects, nullptr, true, true);
|
grid.Orientation(Windows::UI::Xaml::Controls::Orientation::Horizontal);
|
||||||
singleKeyRemapControlLayout.as<StackPanel>().Children().Append(hybridDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>());
|
auto gridMargin = Windows::UI::Xaml::Thickness();
|
||||||
|
gridMargin.Bottom = -EditorConstants::ShortcutTableDropDownSpacing; // compensate for a collapsed textInput
|
||||||
|
grid.Margin(gridMargin);
|
||||||
|
|
||||||
|
KeyDropDownControl::AddDropDown(table, row, grid, colIndex, singleKeyRemapBuffer, keyDropDownControlObjects, nullptr, true, true);
|
||||||
|
|
||||||
|
singleKeyRemapControlLayout.as<StackPanel>().Children().Append(grid);
|
||||||
|
|
||||||
|
auto textInput = TextBox();
|
||||||
|
|
||||||
|
auto textBoxMargin = Windows::UI::Xaml::Thickness();
|
||||||
|
textBoxMargin.Top = -EditorConstants::ShortcutTableDropDownSpacing; // compensate for a collapsed grid
|
||||||
|
textBoxMargin.Bottom = EditorConstants::ShortcutTableDropDownSpacing;
|
||||||
|
textInput.Margin(textBoxMargin);
|
||||||
|
textInput.AcceptsReturn(false);
|
||||||
|
textInput.Visibility(Visibility::Collapsed);
|
||||||
|
textInput.Width(EditorConstants::TableDropDownHeight);
|
||||||
|
singleKeyRemapControlLayout.as<StackPanel>().Children().Append(textInput);
|
||||||
|
textInput.HorizontalAlignment(HorizontalAlignment::Left);
|
||||||
|
textInput.TextChanged([this, row, table](winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Controls::TextChangedEventArgs const& e) mutable {
|
||||||
|
auto textbox = sender.as<TextBox>();
|
||||||
|
auto text = textbox.Text();
|
||||||
|
uint32_t rowIndex = -1;
|
||||||
|
if (!table.Children().IndexOf(row, rowIndex))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
singleKeyRemapBuffer[rowIndex].first[1] = text.c_str();
|
||||||
|
});
|
||||||
|
|
||||||
|
auto typeCombo = ComboBox();
|
||||||
|
typeCombo.Width(EditorConstants::RemapTableDropDownWidth);
|
||||||
|
typeCombo.Items().Append(winrt::box_value(KeyboardManagerEditorStrings::MappingTypeKey()));
|
||||||
|
typeCombo.Items().Append(winrt::box_value(KeyboardManagerEditorStrings::MappingTypeText()));
|
||||||
|
keyComboAndSelectStackPanel.Children().Append(typeCombo);
|
||||||
|
keyComboAndSelectStackPanel.Children().Append(typeKey.as<Button>());
|
||||||
|
singleKeyRemapControlLayout.as<StackPanel>().Children().InsertAt(0, keyComboAndSelectStackPanel);
|
||||||
|
|
||||||
|
typeCombo.SelectedIndex(0);
|
||||||
|
typeCombo.SelectionChanged([this, typeCombo, grid, textInput](winrt::Windows::Foundation::IInspectable const&, SelectionChangedEventArgs const&) {
|
||||||
|
const bool textSelected = typeCombo.SelectedIndex() == 1;
|
||||||
|
|
||||||
|
const auto keyInputVisibility = textSelected ? Visibility::Collapsed : Visibility::Visible;
|
||||||
|
|
||||||
|
grid.Visibility(keyInputVisibility);
|
||||||
|
typeKey.as<Button>().Visibility(keyInputVisibility);
|
||||||
|
|
||||||
|
const auto textInputVisibility = textSelected ? Visibility::Visible : Visibility::Collapsed;
|
||||||
|
textInput.Visibility(textInputVisibility);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
typeKey.as<Button>().Click([&, table, colIndex, row](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
typeKey.as<Button>().Click([&, table, colIndex, row](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||||
@ -73,8 +129,15 @@ void SingleKeyRemapControl::UpdateAccessibleNames(StackPanel sourceColumn, Stack
|
|||||||
deleteButton.SetValue(Automation::AutomationProperties::NameProperty(), box_value(GET_RESOURCE_STRING(IDS_AUTOMATIONPROPERTIES_ROW) + std::to_wstring(rowIndex) + L", " + GET_RESOURCE_STRING(IDS_DELETE_REMAPPING_BUTTON)));
|
deleteButton.SetValue(Automation::AutomationProperties::NameProperty(), box_value(GET_RESOURCE_STRING(IDS_AUTOMATIONPROPERTIES_ROW) + std::to_wstring(rowIndex) + L", " + GET_RESOURCE_STRING(IDS_DELETE_REMAPPING_BUTTON)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SingleKeyRemapControl::TextToMapChangedHandler(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Controls::TextChangedEventArgs const& e) // TODO: remove
|
||||||
|
{
|
||||||
|
auto textbox = sender.as<TextBox>();
|
||||||
|
auto text = textbox.Text();
|
||||||
|
(void)text;
|
||||||
|
}
|
||||||
|
|
||||||
// Function to add a new row to the remap keys table. If the originalKey and newKey args are provided, then the displayed remap keys are set to those values.
|
// Function to add a new row to the remap keys table. If the originalKey and newKey args are provided, then the displayed remap keys are set to those values.
|
||||||
void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, std::vector<std::vector<std::unique_ptr<SingleKeyRemapControl>>>& keyboardRemapControlObjects, const DWORD originalKey, const KeyShortcutUnion newKey)
|
void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, std::vector<std::vector<std::unique_ptr<SingleKeyRemapControl>>>& keyboardRemapControlObjects, const DWORD originalKey, const KeyShortcutTextUnion newKey)
|
||||||
{
|
{
|
||||||
// Create new SingleKeyRemapControl objects dynamically so that we does not get destructed
|
// Create new SingleKeyRemapControl objects dynamically so that we does not get destructed
|
||||||
std::vector<std::unique_ptr<SingleKeyRemapControl>> newrow;
|
std::vector<std::unique_ptr<SingleKeyRemapControl>> newrow;
|
||||||
@ -112,7 +175,7 @@ void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, std::ve
|
|||||||
row.Children().Append(targetElement);
|
row.Children().Append(targetElement);
|
||||||
|
|
||||||
// Set the key text if the two keys are not null (i.e. default args)
|
// Set the key text if the two keys are not null (i.e. default args)
|
||||||
if (originalKey != NULL && !(newKey.index() == 0 && std::get<DWORD>(newKey) == NULL) && !(newKey.index() == 1 && !EditorHelpers::IsValidShortcut(std::get<Shortcut>(newKey))))
|
if (originalKey != NULL && !(newKey.index() == 0 && std::get<DWORD>(newKey) == NULL) && !(newKey.index() == 1 && !EditorHelpers::IsValidShortcut(std::get<Shortcut>(newKey))) && !(newKey.index() == 2 && std::get<std::wstring>(newKey).empty()))
|
||||||
{
|
{
|
||||||
singleKeyRemapBuffer.push_back(std::make_pair<RemapBufferItem, std::wstring>(RemapBufferItem{ originalKey, newKey }, L""));
|
singleKeyRemapBuffer.push_back(std::make_pair<RemapBufferItem, std::wstring>(RemapBufferItem{ originalKey, newKey }, L""));
|
||||||
keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][0]->keyDropDownControlObjects[0]->SetSelectedValue(std::to_wstring(originalKey));
|
keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][0]->keyDropDownControlObjects[0]->SetSelectedValue(std::to_wstring(originalKey));
|
||||||
@ -120,10 +183,20 @@ void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, std::ve
|
|||||||
{
|
{
|
||||||
keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1]->keyDropDownControlObjects[0]->SetSelectedValue(std::to_wstring(std::get<DWORD>(newKey)));
|
keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1]->keyDropDownControlObjects[0]->SetSelectedValue(std::to_wstring(std::get<DWORD>(newKey)));
|
||||||
}
|
}
|
||||||
else
|
else if (newKey.index() == 1)
|
||||||
{
|
{
|
||||||
KeyDropDownControl::AddShortcutToControl(std::get<Shortcut>(newKey), parent, keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1]->hybridDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>(), *keyboardManagerState, 1, keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1]->keyDropDownControlObjects, singleKeyRemapBuffer, row, nullptr, true, true);
|
KeyDropDownControl::AddShortcutToControl(std::get<Shortcut>(newKey), parent, keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1]->hybridDropDownVariableSizedWrapGrid.as<VariableSizedWrapGrid>(), *keyboardManagerState, 1, keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1]->keyDropDownControlObjects, singleKeyRemapBuffer, row, nullptr, true, true);
|
||||||
}
|
}
|
||||||
|
else if (newKey.index() == 2)
|
||||||
|
{
|
||||||
|
auto& singleKeyRemapControl = keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1];
|
||||||
|
|
||||||
|
const auto& firstLineStackPanel = singleKeyRemapControl->singleKeyRemapControlLayout.as<StackPanel>().Children().GetAt(0).as<StackPanel>();
|
||||||
|
|
||||||
|
firstLineStackPanel.Children().GetAt(0).as<ComboBox>().SelectedIndex(1);
|
||||||
|
|
||||||
|
singleKeyRemapControl->singleKeyRemapControlLayout.as<StackPanel>().Children().GetAt(2).as<TextBox>().Text(std::get<std::wstring>(newKey));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -178,7 +251,7 @@ void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, std::ve
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
singleKeyRemapBuffer.erase(singleKeyRemapBuffer.begin() + rowIndex);
|
singleKeyRemapBuffer.erase(singleKeyRemapBuffer.begin() + rowIndex);
|
||||||
|
|
||||||
// delete the SingleKeyRemapControl objects so that they get destructed
|
// delete the SingleKeyRemapControl objects so that they get destructed
|
||||||
keyboardRemapControlObjects.erase(keyboardRemapControlObjects.begin() + rowIndex);
|
keyboardRemapControlObjects.erase(keyboardRemapControlObjects.begin() + rowIndex);
|
||||||
});
|
});
|
||||||
|
@ -35,6 +35,8 @@ private:
|
|||||||
// Function to set the accessible names for all the controls in a row
|
// Function to set the accessible names for all the controls in a row
|
||||||
static void UpdateAccessibleNames(StackPanel sourceColumn, StackPanel mappedToColumn, Button deleteButton, int rowIndex);
|
static void UpdateAccessibleNames(StackPanel sourceColumn, StackPanel mappedToColumn, Button deleteButton, int rowIndex);
|
||||||
|
|
||||||
|
void TextToMapChangedHandler(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Controls::TextChangedEventArgs const& e);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Vector to store dynamically allocated KeyDropDownControl objects to avoid early destruction
|
// Vector to store dynamically allocated KeyDropDownControl objects to avoid early destruction
|
||||||
std::vector<std::unique_ptr<KeyDropDownControl>> keyDropDownControlObjects;
|
std::vector<std::unique_ptr<KeyDropDownControl>> keyDropDownControlObjects;
|
||||||
@ -52,7 +54,7 @@ public:
|
|||||||
SingleKeyRemapControl(StackPanel table, StackPanel row, const int colIndex);
|
SingleKeyRemapControl(StackPanel table, StackPanel row, const int colIndex);
|
||||||
|
|
||||||
// Function to add a new row to the remap keys table. If the originalKey and newKey args are provided, then the displayed remap keys are set to those values.
|
// Function to add a new row to the remap keys table. If the originalKey and newKey args are provided, then the displayed remap keys are set to those values.
|
||||||
static void AddNewControlKeyRemapRow(StackPanel& parent, std::vector<std::vector<std::unique_ptr<SingleKeyRemapControl>>>& keyboardRemapControlObjects, const DWORD originalKey = 0, const KeyShortcutUnion newKey = (DWORD)0);
|
static void AddNewControlKeyRemapRow(StackPanel& parent, std::vector<std::vector<std::unique_ptr<SingleKeyRemapControl>>>& keyboardRemapControlObjects, const DWORD originalKey = 0, const KeyShortcutTextUnion newKey = (DWORD)0);
|
||||||
|
|
||||||
// Function to return the stack panel element of the SingleKeyRemapControl. This is the externally visible UI element which can be used to add it to other layouts
|
// Function to return the stack panel element of the SingleKeyRemapControl. This is the externally visible UI element which can be used to add it to other layouts
|
||||||
winrt::Windows::UI::Xaml::Controls::StackPanel getSingleKeyRemapControl();
|
winrt::Windows::UI::Xaml::Controls::StackPanel getSingleKeyRemapControl();
|
||||||
|
@ -9,13 +9,19 @@ namespace UIHelpers
|
|||||||
void SetFocusOnTypeButtonInLastRow(StackPanel& parent, long colCount)
|
void SetFocusOnTypeButtonInLastRow(StackPanel& parent, long colCount)
|
||||||
{
|
{
|
||||||
// First element in the last row (StackPanel)
|
// First element in the last row (StackPanel)
|
||||||
StackPanel firstElementInLastRow = parent.Children().GetAt(parent.Children().Size() - 1).as<StackPanel>().Children().GetAt(0).as<StackPanel>();
|
auto lastHotKeyLine = parent.Children().GetAt(parent.Children().Size() - 1).as<StackPanel>();
|
||||||
|
|
||||||
// Type button is the first child in the StackPanel
|
// Get "To" Column
|
||||||
Button firstTypeButtonInLastRow = firstElementInLastRow.Children().GetAt(0).as<Button>();
|
auto toColumn = lastHotKeyLine.Children().GetAt(2).as<StackPanel>();
|
||||||
|
|
||||||
|
// Get first line in "To" Column
|
||||||
|
auto firstLineIntoColumn = toColumn.Children().GetAt(0).as<StackPanel>();
|
||||||
|
|
||||||
|
// Get Type Button from the first line
|
||||||
|
Button typeButton = firstLineIntoColumn.Children().GetAt(1).as<Button>();
|
||||||
|
|
||||||
// Set programmatic focus on the button
|
// Set programmatic focus on the button
|
||||||
firstTypeButtonInLastRow.Focus(FocusState::Programmatic);
|
typeButton.Focus(FocusState::Programmatic);
|
||||||
}
|
}
|
||||||
|
|
||||||
RECT GetForegroundWindowDesktopRect()
|
RECT GetForegroundWindowDesktopRect()
|
||||||
@ -68,4 +74,22 @@ namespace UIHelpers
|
|||||||
|
|
||||||
return boxList;
|
return boxList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::vector<std::wstring> GetChildrenNames(StackPanel& s)
|
||||||
|
{
|
||||||
|
std::vector<std::wstring> result;
|
||||||
|
for (auto child : s.Children())
|
||||||
|
{
|
||||||
|
std::wstring nameAndClass =
|
||||||
|
child.as<IFrameworkElement>().Name().c_str();
|
||||||
|
|
||||||
|
nameAndClass += L" ";
|
||||||
|
nameAndClass += winrt::get_class_name(child.try_as<winrt::Windows::Foundation::IInspectable>()).c_str();
|
||||||
|
result.push_back(nameAndClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -29,4 +29,9 @@ namespace UIHelpers
|
|||||||
|
|
||||||
// Function to return the list of key name in the order for the drop down based on the key codes
|
// Function to return the list of key name in the order for the drop down based on the key codes
|
||||||
winrt::Windows::Foundation::Collections::IVector<winrt::Windows::Foundation::IInspectable> ToBoxValue(const std::vector<std::pair<DWORD, std::wstring>>& list);
|
winrt::Windows::Foundation::Collections::IVector<winrt::Windows::Foundation::IInspectable> ToBoxValue(const std::vector<std::pair<DWORD, std::wstring>>& list);
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
// Useful For debugging issues
|
||||||
|
std::vector<std::wstring> GetChildrenNames(StackPanel& s);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ void Trace::UnregisterProvider() noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Log number of key remaps when the user uses Edit Keyboard and saves settings
|
// Log number of key remaps when the user uses Edit Keyboard and saves settings
|
||||||
void Trace::KeyRemapCount(const DWORD keyToKeyCount, const DWORD keyToShortcutCount) noexcept
|
void Trace::KeyRemapCount(const DWORD keyToKeyCount, const DWORD keyToShortcutCount, const DWORD keyToTextCount) noexcept
|
||||||
{
|
{
|
||||||
TraceLoggingWrite(
|
TraceLoggingWrite(
|
||||||
g_hProvider,
|
g_hProvider,
|
||||||
@ -28,7 +28,8 @@ void Trace::KeyRemapCount(const DWORD keyToKeyCount, const DWORD keyToShortcutCo
|
|||||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||||
TraceLoggingValue(keyToKeyCount + keyToShortcutCount, "KeyRemapCount"),
|
TraceLoggingValue(keyToKeyCount + keyToShortcutCount, "KeyRemapCount"),
|
||||||
TraceLoggingValue(keyToKeyCount, "KeyToKeyRemapCount"),
|
TraceLoggingValue(keyToKeyCount, "KeyToKeyRemapCount"),
|
||||||
TraceLoggingValue(keyToShortcutCount, "KeyToShortcutRemapCount"));
|
TraceLoggingValue(keyToShortcutCount, "KeyToShortcutRemapCount"),
|
||||||
|
TraceLoggingValue(keyToTextCount, "KeyToTextRemapCount"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log number of os level shortcut remaps when the user uses Edit Shortcuts and saves settings
|
// Log number of os level shortcut remaps when the user uses Edit Shortcuts and saves settings
|
||||||
|
@ -7,14 +7,14 @@ public:
|
|||||||
static void UnregisterProvider() noexcept;
|
static void UnregisterProvider() noexcept;
|
||||||
|
|
||||||
// Log number of key remaps when the user uses Edit Keyboard and saves settings
|
// Log number of key remaps when the user uses Edit Keyboard and saves settings
|
||||||
static void KeyRemapCount(const DWORD keyToKeyCount, const DWORD keyToShortcutCount) noexcept;
|
static void KeyRemapCount(const DWORD keyToKeyCount, const DWORD keyToShortcutCount, const DWORD keyToTextCount) noexcept;
|
||||||
|
|
||||||
// Log number of os level shortcut remaps when the user uses Edit Shortcuts and saves settings
|
// Log number of os level shortcut remaps when the user uses Edit Shortcuts and saves settings
|
||||||
static void OSLevelShortcutRemapCount(const DWORD shortcutToShortcutCount, const DWORD shortcutToKeyCount) noexcept;
|
static void OSLevelShortcutRemapCount(const DWORD shortcutToShortcutCount, const DWORD shortcutToKeyCount) noexcept;
|
||||||
|
|
||||||
// Log number of app specific shortcut remaps when the user uses Edit Shortcuts and saves settings
|
// Log number of app specific shortcut remaps when the user uses Edit Shortcuts and saves settings
|
||||||
static void AppSpecificShortcutRemapCount(const DWORD shortcutToShortcutCount, const DWORD shortcutToKeyCount) noexcept;
|
static void AppSpecificShortcutRemapCount(const DWORD shortcutToShortcutCount, const DWORD shortcutToKeyCount) noexcept;
|
||||||
|
|
||||||
// Log if an error occurs in KBM
|
// Log if an error occurs in KBM
|
||||||
static void Error(const DWORD errorCode, std::wstring errorMessage, std::wstring methodName) noexcept;
|
static void Error(const DWORD errorCode, std::wstring errorMessage, std::wstring methodName) noexcept;
|
||||||
};
|
};
|
||||||
|
@ -7,13 +7,21 @@
|
|||||||
#include <keyboardmanager/common/Helpers.h>
|
#include <keyboardmanager/common/Helpers.h>
|
||||||
#include <keyboardmanager/KeyboardManagerEngineLibrary/trace.h>
|
#include <keyboardmanager/KeyboardManagerEngineLibrary/trace.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool GeneratedByKBM(const LowlevelKeyboardEvent* data)
|
||||||
|
{
|
||||||
|
return data->lParam->dwExtraInfo & CommonSharedConstants::KEYBOARDMANAGER_INJECTED_FLAG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace KeyboardEventHandlers
|
namespace KeyboardEventHandlers
|
||||||
{
|
{
|
||||||
// Function to a handle a single key remap
|
// Function to a handle a single key remap
|
||||||
intptr_t HandleSingleKeyRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, State& state) noexcept
|
intptr_t HandleSingleKeyRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, State& state) noexcept
|
||||||
{
|
{
|
||||||
// Check if the key event was generated by KeyboardManager to avoid remapping events generated by us.
|
// Check if the key event was generated by KeyboardManager to avoid remapping events generated by us.
|
||||||
if (!(data->lParam->dwExtraInfo & CommonSharedConstants::KEYBOARDMANAGER_INJECTED_FLAG))
|
if (!GeneratedByKBM(data))
|
||||||
{
|
{
|
||||||
const auto remapping = state.GetSingleKeyRemap(data->lParam->vkCode);
|
const auto remapping = state.GetSingleKeyRemap(data->lParam->vkCode);
|
||||||
if (remapping)
|
if (remapping)
|
||||||
@ -21,7 +29,7 @@ namespace KeyboardEventHandlers
|
|||||||
auto it = remapping.value();
|
auto it = remapping.value();
|
||||||
|
|
||||||
// Check if the remap is to a key or a shortcut
|
// Check if the remap is to a key or a shortcut
|
||||||
bool remapToKey = (it->second.index() == 0);
|
const bool remapToKey = it->second.index() == 0;
|
||||||
|
|
||||||
// If mapped to VK_DISABLED then the key is disabled
|
// If mapped to VK_DISABLED then the key is disabled
|
||||||
if (remapToKey)
|
if (remapToKey)
|
||||||
@ -191,7 +199,9 @@ namespace KeyboardEventHandlers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the remap is to a key or a shortcut
|
// Check if the remap is to a key or a shortcut
|
||||||
bool remapToShortcut = (it->second.targetShortcut.index() == 1);
|
const bool remapToKey = it->second.targetShortcut.index() == 0;
|
||||||
|
const bool remapToShortcut = it->second.targetShortcut.index() == 1;
|
||||||
|
const bool remapToText = it->second.targetShortcut.index() == 2;
|
||||||
|
|
||||||
const size_t src_size = it->first.Size();
|
const size_t src_size = it->first.Size();
|
||||||
const size_t dest_size = remapToShortcut ? std::get<Shortcut>(it->second.targetShortcut).Size() : 1;
|
const size_t dest_size = remapToShortcut ? std::get<Shortcut>(it->second.targetShortcut).Size() : 1;
|
||||||
@ -202,13 +212,13 @@ namespace KeyboardEventHandlers
|
|||||||
if (data->lParam->vkCode == it->first.GetActionKey() && (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN))
|
if (data->lParam->vkCode == it->first.GetActionKey() && (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN))
|
||||||
{
|
{
|
||||||
// Check if any other keys have been pressed apart from the shortcut. If true, then check for the next shortcut. This is to be done only for shortcut to shortcut remaps
|
// Check if any other keys have been pressed apart from the shortcut. If true, then check for the next shortcut. This is to be done only for shortcut to shortcut remaps
|
||||||
if (!it->first.IsKeyboardStateClearExceptShortcut(ii) && (remapToShortcut || std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED))
|
if (!it->first.IsKeyboardStateClearExceptShortcut(ii) && (remapToShortcut || (remapToKey && std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t key_count;
|
size_t key_count = 0;
|
||||||
LPINPUT keyEventList;
|
LPINPUT keyEventList = nullptr;
|
||||||
|
|
||||||
// Remember which win key was pressed initially
|
// Remember which win key was pressed initially
|
||||||
if (ii.GetVirtualKeyState(VK_RWIN))
|
if (ii.GetVirtualKeyState(VK_RWIN))
|
||||||
@ -265,7 +275,7 @@ namespace KeyboardEventHandlers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (remapToKey)
|
||||||
{
|
{
|
||||||
// Dummy key, key up for all the original shortcut modifier keys and key down for remapped key
|
// Dummy key, key up for all the original shortcut modifier keys and key down for remapped key
|
||||||
key_count = KeyboardManagerConstants::DUMMY_KEY_EVENT_SIZE + (src_size - 1) + dest_size;
|
key_count = KeyboardManagerConstants::DUMMY_KEY_EVENT_SIZE + (src_size - 1) + dest_size;
|
||||||
@ -300,6 +310,33 @@ namespace KeyboardEventHandlers
|
|||||||
ResetIfModifierKeyForLowerLevelKeyHandlers(ii, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), data->lParam->vkCode);
|
ResetIfModifierKeyForLowerLevelKeyHandlers(ii, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), data->lParam->vkCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Remapped to text
|
||||||
|
else
|
||||||
|
{
|
||||||
|
key_count = KeyboardManagerConstants::DUMMY_KEY_EVENT_SIZE + src_size;
|
||||||
|
|
||||||
|
auto remapping = std::get<std::wstring>(it->second.targetShortcut);
|
||||||
|
const UINT inputEventCount = static_cast<UINT>(remapping.length() * 2);
|
||||||
|
key_count += inputEventCount;
|
||||||
|
|
||||||
|
keyEventList = new INPUT[key_count]{};
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
Helpers::SetDummyKeyEvent(keyEventList, i, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
|
|
||||||
|
// Release original shortcut state (release in reverse order of shortcut to be accurate)
|
||||||
|
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
|
|
||||||
|
for (size_t idx = 0; idx < inputEventCount; ++idx)
|
||||||
|
{
|
||||||
|
auto& input = keyEventList[idx + i];
|
||||||
|
input.type = INPUT_KEYBOARD;
|
||||||
|
const bool upEvent = idx & 0x1;
|
||||||
|
input.ki.dwFlags = KEYEVENTF_UNICODE | (upEvent ? KEYEVENTF_KEYUP : 0);
|
||||||
|
input.ki.dwExtraInfo = KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG;
|
||||||
|
input.ki.wScan = remapping[idx >> 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
it->second.isShortcutInvoked = true;
|
it->second.isShortcutInvoked = true;
|
||||||
// If app specific shortcut is invoked, store the target application
|
// If app specific shortcut is invoked, store the target application
|
||||||
@ -332,8 +369,8 @@ namespace KeyboardEventHandlers
|
|||||||
if ((it->first.CheckWinKey(data->lParam->vkCode) || it->first.CheckCtrlKey(data->lParam->vkCode) || it->first.CheckAltKey(data->lParam->vkCode) || it->first.CheckShiftKey(data->lParam->vkCode)) && (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP))
|
if ((it->first.CheckWinKey(data->lParam->vkCode) || it->first.CheckCtrlKey(data->lParam->vkCode) || it->first.CheckAltKey(data->lParam->vkCode) || it->first.CheckShiftKey(data->lParam->vkCode)) && (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP))
|
||||||
{
|
{
|
||||||
// Release new shortcut, and set original shortcut keys except the one released
|
// Release new shortcut, and set original shortcut keys except the one released
|
||||||
size_t key_count;
|
size_t key_count = 0;
|
||||||
LPINPUT keyEventList;
|
LPINPUT keyEventList = nullptr;
|
||||||
if (remapToShortcut)
|
if (remapToShortcut)
|
||||||
{
|
{
|
||||||
// if the released key is present in both shortcuts' modifiers (i.e part of the common modifiers)
|
// if the released key is present in both shortcuts' modifiers (i.e part of the common modifiers)
|
||||||
@ -373,7 +410,7 @@ namespace KeyboardEventHandlers
|
|||||||
// Send a dummy key event to prevent modifier press+release from being triggered. Example: Win+Ctrl+A->Ctrl+V, press Win+Ctrl+A and release A then Ctrl, since Win will be pressed here we need to send a dummy event after it
|
// Send a dummy key event to prevent modifier press+release from being triggered. Example: Win+Ctrl+A->Ctrl+V, press Win+Ctrl+A and release A then Ctrl, since Win will be pressed here we need to send a dummy event after it
|
||||||
Helpers::SetDummyKeyEvent(keyEventList, i, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetDummyKeyEvent(keyEventList, i, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
}
|
}
|
||||||
else
|
else if (remapToKey)
|
||||||
{
|
{
|
||||||
// 1 for releasing new key and original shortcut modifiers except the one released and dummy key
|
// 1 for releasing new key and original shortcut modifiers except the one released and dummy key
|
||||||
key_count = dest_size + src_size - 2 + KeyboardManagerConstants::DUMMY_KEY_EVENT_SIZE;
|
key_count = dest_size + src_size - 2 + KeyboardManagerConstants::DUMMY_KEY_EVENT_SIZE;
|
||||||
@ -432,13 +469,13 @@ namespace KeyboardEventHandlers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The system will see the modifiers of the new shortcut as being held down because of the shortcut remap
|
// The system will see the modifiers of the new shortcut as being held down because of the shortcut remap
|
||||||
if (!remapToShortcut || std::get<Shortcut>(it->second.targetShortcut).CheckModifiersKeyboardState(ii))
|
if (!remapToShortcut || (remapToShortcut && std::get<Shortcut>(it->second.targetShortcut).CheckModifiersKeyboardState(ii)))
|
||||||
{
|
{
|
||||||
// Case 2: If the original shortcut is still held down the keyboard will get a key down message of the action key in the original shortcut and the new shortcut's modifiers will be held down (keys held down send repeated keydown messages)
|
// Case 2: If the original shortcut is still held down the keyboard will get a key down message of the action key in the original shortcut and the new shortcut's modifiers will be held down (keys held down send repeated keydown messages)
|
||||||
if (data->lParam->vkCode == it->first.GetActionKey() && (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN))
|
if (data->lParam->vkCode == it->first.GetActionKey() && (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN))
|
||||||
{
|
{
|
||||||
// In case of mapping to disable do not send anything
|
// In case of mapping to disable do not send anything
|
||||||
if (!remapToShortcut && std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)
|
if (remapToKey && std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)
|
||||||
{
|
{
|
||||||
// Since the original shortcut's action key is pressed, set it to true
|
// Since the original shortcut's action key is pressed, set it to true
|
||||||
it->second.isOriginalActionKeyPressed = true;
|
it->second.isOriginalActionKeyPressed = true;
|
||||||
@ -446,15 +483,34 @@ namespace KeyboardEventHandlers
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t key_count = 1;
|
size_t key_count = 1;
|
||||||
LPINPUT keyEventList = new INPUT[key_count]{};
|
LPINPUT keyEventList = nullptr;
|
||||||
if (remapToShortcut)
|
if (remapToShortcut)
|
||||||
{
|
{
|
||||||
|
keyEventList = new INPUT[key_count]{};
|
||||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
}
|
}
|
||||||
else
|
else if (remapToKey)
|
||||||
{
|
{
|
||||||
|
keyEventList = new INPUT[key_count]{};
|
||||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
}
|
}
|
||||||
|
else if (remapToText)
|
||||||
|
{
|
||||||
|
auto remapping = std::get<std::wstring>(it->second.targetShortcut);
|
||||||
|
const UINT inputEventCount = static_cast<UINT>(remapping.length() * 2);
|
||||||
|
key_count = inputEventCount;
|
||||||
|
keyEventList = new INPUT[key_count]{};
|
||||||
|
|
||||||
|
for (size_t idx = 0; idx < inputEventCount; ++idx)
|
||||||
|
{
|
||||||
|
auto& input = keyEventList[idx];
|
||||||
|
input.type = INPUT_KEYBOARD;
|
||||||
|
const bool upEvent = idx & 0x1;
|
||||||
|
input.ki.dwFlags = KEYEVENTF_UNICODE | (upEvent ? KEYEVENTF_KEYUP : 0);
|
||||||
|
input.ki.dwExtraInfo = KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG;
|
||||||
|
input.ki.wScan = remapping[idx >> 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UINT res = ii.SendVirtualInput(static_cast<UINT>(key_count), keyEventList, sizeof(INPUT));
|
UINT res = ii.SendVirtualInput(static_cast<UINT>(key_count), keyEventList, sizeof(INPUT));
|
||||||
delete[] keyEventList;
|
delete[] keyEventList;
|
||||||
@ -462,10 +518,10 @@ namespace KeyboardEventHandlers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Case 3: If the action key is released from the original shortcut, keep modifiers of the new shortcut until some other key event which doesn't apply to the original shortcut
|
// Case 3: If the action key is released from the original shortcut, keep modifiers of the new shortcut until some other key event which doesn't apply to the original shortcut
|
||||||
if (data->lParam->vkCode == it->first.GetActionKey() && (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP))
|
if (!remapToText && data->lParam->vkCode == it->first.GetActionKey() && (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP))
|
||||||
{
|
{
|
||||||
size_t key_count = 1;
|
size_t key_count = 1;
|
||||||
LPINPUT keyEventList;
|
LPINPUT keyEventList = nullptr;
|
||||||
if (remapToShortcut)
|
if (remapToShortcut)
|
||||||
{
|
{
|
||||||
keyEventList = new INPUT[key_count]{};
|
keyEventList = new INPUT[key_count]{};
|
||||||
@ -683,16 +739,22 @@ namespace KeyboardEventHandlers
|
|||||||
// For remap to key, if the original action key is not currently pressed, we should revert the keyboard state to the physical keys. If it is pressed we should not suppress the event so that shortcut to key remaps can be pressed with other keys. Example use-case: Alt+D->Win, allows Alt+D+A to perform Win+A
|
// For remap to key, if the original action key is not currently pressed, we should revert the keyboard state to the physical keys. If it is pressed we should not suppress the event so that shortcut to key remaps can be pressed with other keys. Example use-case: Alt+D->Win, allows Alt+D+A to perform Win+A
|
||||||
|
|
||||||
// Modifier state reset might be required for this key depending on the target key - ex: Ctrl+A -> Caps, Shift is pressed. System should not see Shift and Caps pressed together
|
// Modifier state reset might be required for this key depending on the target key - ex: Ctrl+A -> Caps, Shift is pressed. System should not see Shift and Caps pressed together
|
||||||
ResetIfModifierKeyForLowerLevelKeyHandlers(ii, data->lParam->vkCode, Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)));
|
|
||||||
|
auto maybeTargetKey = std::get_if<DWORD>(&it->second.targetShortcut);
|
||||||
|
|
||||||
|
if (maybeTargetKey)
|
||||||
|
{
|
||||||
|
ResetIfModifierKeyForLowerLevelKeyHandlers(ii, data->lParam->vkCode, Helpers::FilterArtificialKeys(*maybeTargetKey));
|
||||||
|
}
|
||||||
|
|
||||||
// If the shortcut is remapped to Disable then we have to revert the keyboard state to the physical keys
|
// If the shortcut is remapped to Disable then we have to revert the keyboard state to the physical keys
|
||||||
bool isRemapToDisable = (std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED);
|
bool isRemapToDisable = maybeTargetKey && (*maybeTargetKey == CommonSharedConstants::VK_DISABLED);
|
||||||
bool isOriginalActionKeyPressed = false;
|
bool isOriginalActionKeyPressed = false;
|
||||||
|
|
||||||
if (!isRemapToDisable)
|
if (maybeTargetKey && !isRemapToDisable)
|
||||||
{
|
{
|
||||||
// If the remap target key is currently pressed, then we do not have to revert the keyboard state to the physical keys
|
// If the remap target key is currently pressed, then we do not have to revert the keyboard state to the physical keys
|
||||||
if (ii.GetVirtualKeyState((Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)))))
|
if (ii.GetVirtualKeyState((Helpers::FilterArtificialKeys(*maybeTargetKey))))
|
||||||
{
|
{
|
||||||
isOriginalActionKeyPressed = true;
|
isOriginalActionKeyPressed = true;
|
||||||
}
|
}
|
||||||
@ -850,4 +912,43 @@ namespace KeyboardEventHandlers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to generate a unicode string in response to a single keypress
|
||||||
|
intptr_t HandleSingleKeyToTextRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, State& state)
|
||||||
|
{
|
||||||
|
if (GeneratedByKBM(data))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only send the text on keydown event
|
||||||
|
if (data->wParam != WM_KEYDOWN)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto remapping = state.GetSingleKeyToTextRemapEvent(data->lParam->vkCode);
|
||||||
|
if (!remapping)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t keyCount = remapping->length();
|
||||||
|
const UINT eventCount = static_cast<UINT>(keyCount * 2);
|
||||||
|
auto keyEventList = std::make_unique<INPUT[]>(keyCount * 2);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < eventCount; ++i)
|
||||||
|
{
|
||||||
|
auto& input = keyEventList[i];
|
||||||
|
input.type = INPUT_KEYBOARD;
|
||||||
|
const bool upEvent = i & 0x1;
|
||||||
|
input.ki.dwFlags = KEYEVENTF_UNICODE | (upEvent ? KEYEVENTF_KEYUP : 0);
|
||||||
|
input.ki.dwExtraInfo = KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG;
|
||||||
|
input.ki.wScan = (*remapping)[i >> 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT res = ii.SendVirtualInput(eventCount, keyEventList.get(), sizeof(INPUT));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,9 @@ namespace KeyboardEventHandlers
|
|||||||
// Function to a handle an app-specific shortcut remap
|
// Function to a handle an app-specific shortcut remap
|
||||||
intptr_t HandleAppSpecificShortcutRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, State& state) noexcept;
|
intptr_t HandleAppSpecificShortcutRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, State& state) noexcept;
|
||||||
|
|
||||||
|
// Function to generate a unicode string in response to a single keypress
|
||||||
|
intptr_t HandleSingleKeyToTextRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, State& state);
|
||||||
|
|
||||||
// Function to ensure Ctrl/Shift/Alt modifier key state is not detected as pressed down by applications which detect keys at a lower level than hooks when it is remapped for scenarios where its required
|
// Function to ensure Ctrl/Shift/Alt modifier key state is not detected as pressed down by applications which detect keys at a lower level than hooks when it is remapped for scenarios where its required
|
||||||
void ResetIfModifierKeyForLowerLevelKeyHandlers(KeyboardManagerInput::InputInterface& ii, DWORD key, DWORD target);
|
void ResetIfModifierKeyForLowerLevelKeyHandlers(KeyboardManagerInput::InputInterface& ii, DWORD key, DWORD target);
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "KeyboardManager.h"
|
#include "KeyboardManager.h"
|
||||||
#include <interface/powertoy_module_interface.h>
|
#include <interface/powertoy_module_interface.h>
|
||||||
#include <common/SettingsAPI/settings_objects.h>
|
#include <common/SettingsAPI/settings_objects.h>
|
||||||
@ -68,12 +68,13 @@ void KeyboardManager::LoadSettings()
|
|||||||
|
|
||||||
LRESULT CALLBACK KeyboardManager::HookProc(int nCode, const WPARAM wParam, const LPARAM lParam)
|
LRESULT CALLBACK KeyboardManager::HookProc(int nCode, const WPARAM wParam, const LPARAM lParam)
|
||||||
{
|
{
|
||||||
LowlevelKeyboardEvent event;
|
LowlevelKeyboardEvent event{};
|
||||||
if (nCode == HC_ACTION)
|
if (nCode == HC_ACTION)
|
||||||
{
|
{
|
||||||
event.lParam = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
|
event.lParam = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
|
||||||
event.wParam = wParam;
|
event.wParam = wParam;
|
||||||
event.lParam->vkCode = Helpers::EncodeKeyNumpadOrigin(event.lParam->vkCode, event.lParam->flags & LLKHF_EXTENDED);
|
event.lParam->vkCode = Helpers::EncodeKeyNumpadOrigin(event.lParam->vkCode, event.lParam->flags & LLKHF_EXTENDED);
|
||||||
|
|
||||||
if (keyboardManagerObjectPtr->HandleKeyboardHookEvent(&event) == 1)
|
if (keyboardManagerObjectPtr->HandleKeyboardHookEvent(&event) == 1)
|
||||||
{
|
{
|
||||||
// Reset Num Lock whenever a NumLock key down event is suppressed since Num Lock key state change occurs before it is intercepted by low level hooks
|
// Reset Num Lock whenever a NumLock key down event is suppressed since Num Lock key state change occurs before it is intercepted by low level hooks
|
||||||
@ -162,6 +163,13 @@ intptr_t KeyboardManager::HandleKeyboardHookEvent(LowlevelKeyboardEvent* data) n
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
intptr_t SingleKeyToTextRemapResult = KeyboardEventHandlers::HandleSingleKeyToTextRemapEvent(inputHandler, data, state);
|
||||||
|
|
||||||
|
if (SingleKeyToTextRemapResult == 1)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Handle an os-level shortcut remapping
|
// Handle an os-level shortcut remapping
|
||||||
return KeyboardEventHandlers::HandleOSLevelShortcutRemapEvent(inputHandler, data, state);
|
return KeyboardEventHandlers::HandleOSLevelShortcutRemapEvent(inputHandler, data, state);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,18 @@ std::optional<SingleKeyRemapTable::iterator> State::GetSingleKeyRemap(const DWOR
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::wstring> State::GetSingleKeyToTextRemapEvent(const DWORD originalKey) const
|
||||||
|
{
|
||||||
|
if (auto it = singleKeyToTextReMap.find(originalKey); it != end(singleKeyToTextReMap))
|
||||||
|
{
|
||||||
|
return std::get<std::wstring>(it->second);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool State::CheckShortcutRemapInvoked(const std::optional<std::wstring>& appName)
|
bool State::CheckShortcutRemapInvoked(const std::optional<std::wstring>& appName)
|
||||||
{
|
{
|
||||||
// Assumes appName exists in the app-specific remap table
|
// Assumes appName exists in the app-specific remap table
|
||||||
|
@ -11,6 +11,9 @@ public:
|
|||||||
// Function to get the iterator of a single key remap given the source key. Returns nullopt if it isn't remapped
|
// Function to get the iterator of a single key remap given the source key. Returns nullopt if it isn't remapped
|
||||||
std::optional<SingleKeyRemapTable::iterator> GetSingleKeyRemap(const DWORD& originalKey);
|
std::optional<SingleKeyRemapTable::iterator> GetSingleKeyRemap(const DWORD& originalKey);
|
||||||
|
|
||||||
|
// Function to get a unicode string remap given the source key. Returns nullopt if it isn't remapped
|
||||||
|
std::optional<std::wstring> GetSingleKeyToTextRemapEvent(const DWORD originalKey) const;
|
||||||
|
|
||||||
bool CheckShortcutRemapInvoked(const std::optional<std::wstring>& appName);
|
bool CheckShortcutRemapInvoked(const std::optional<std::wstring>& appName);
|
||||||
|
|
||||||
// Function to get the source and target of a shortcut remap given the source shortcut. Returns nullopt if it isn't remapped
|
// Function to get the source and target of a shortcut remap given the source shortcut. Returns nullopt if it isn't remapped
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
namespace KeyboardManagerConstants
|
namespace KeyboardManagerConstants
|
||||||
{
|
{
|
||||||
// Event name for signaling settings changes
|
// Event name for signaling settings changes
|
||||||
inline const std::wstring SettingsEventName = L"PowerToys_KeyboardManager_Event_Settings";
|
inline const std::wstring SettingsEventName = L"PowerToys_KeyboardManager_Event_Settings";
|
||||||
|
|
||||||
inline const std::wstring EditorWindowEventName = L"PowerToys_KeyboardManager_Event_EditorWindow";
|
inline const std::wstring EditorWindowEventName = L"PowerToys_KeyboardManager_Event_EditorWindow";
|
||||||
|
|
||||||
// Name of the powertoy module.
|
// Name of the powertoy module.
|
||||||
inline const std::wstring ModuleName = L"Keyboard Manager";
|
inline const std::wstring ModuleName = L"Keyboard Manager";
|
||||||
@ -16,12 +16,18 @@ namespace KeyboardManagerConstants
|
|||||||
// Name of the property use to store single keyremaps.
|
// Name of the property use to store single keyremaps.
|
||||||
inline const std::wstring RemapKeysSettingName = L"remapKeys";
|
inline const std::wstring RemapKeysSettingName = L"remapKeys";
|
||||||
|
|
||||||
|
// Name of the property use to store single to text keyremaps.
|
||||||
|
inline const std::wstring RemapKeysToTextSettingName = L"remapKeysToText";
|
||||||
|
|
||||||
// Name of the property use to store single keyremaps array in case of in process approach.
|
// Name of the property use to store single keyremaps array in case of in process approach.
|
||||||
inline const std::wstring InProcessRemapKeysSettingName = L"inProcess";
|
inline const std::wstring InProcessRemapKeysSettingName = L"inProcess";
|
||||||
|
|
||||||
// Name of the property use to store shortcut remaps.
|
// Name of the property use to store shortcut remaps.
|
||||||
inline const std::wstring RemapShortcutsSettingName = L"remapShortcuts";
|
inline const std::wstring RemapShortcutsSettingName = L"remapShortcuts";
|
||||||
|
|
||||||
|
// Name of the property use to store shortcut to text remaps.
|
||||||
|
inline const std::wstring RemapShortcutsToTextSettingName = L"remapShortcutsToText";
|
||||||
|
|
||||||
// Name of the property use to store global shortcut remaps array.
|
// Name of the property use to store global shortcut remaps array.
|
||||||
inline const std::wstring GlobalRemapShortcutsSettingName = L"global";
|
inline const std::wstring GlobalRemapShortcutsSettingName = L"global";
|
||||||
|
|
||||||
@ -34,6 +40,9 @@ namespace KeyboardManagerConstants
|
|||||||
// Name of the property use to store new remap keys.
|
// Name of the property use to store new remap keys.
|
||||||
inline const std::wstring NewRemapKeysSettingName = L"newRemapKeys";
|
inline const std::wstring NewRemapKeysSettingName = L"newRemapKeys";
|
||||||
|
|
||||||
|
// Name of the property use to store new remapped string.
|
||||||
|
inline const std::wstring NewTextSettingName = L"unicodeText";
|
||||||
|
|
||||||
// Name of the property use to store the target application.
|
// Name of the property use to store the target application.
|
||||||
inline const std::wstring TargetAppSettingName = L"targetApp";
|
inline const std::wstring TargetAppSettingName = L"targetApp";
|
||||||
|
|
||||||
@ -44,7 +53,6 @@ namespace KeyboardManagerConstants
|
|||||||
inline const int MinimumEditKeyboardWindowWidth = 200;
|
inline const int MinimumEditKeyboardWindowWidth = 200;
|
||||||
inline const int MinimumEditKeyboardWindowHeight = 200;
|
inline const int MinimumEditKeyboardWindowHeight = 200;
|
||||||
|
|
||||||
|
|
||||||
// Flags used for distinguishing key events sent by Keyboard Manager
|
// Flags used for distinguishing key events sent by Keyboard Manager
|
||||||
inline const ULONG_PTR KEYBOARDMANAGER_SINGLEKEY_FLAG = 0x11; // Single key remaps
|
inline const ULONG_PTR KEYBOARDMANAGER_SINGLEKEY_FLAG = 0x11; // Single key remaps
|
||||||
inline const ULONG_PTR KEYBOARDMANAGER_SHORTCUT_FLAG = 0x101; // Shortcut remaps
|
inline const ULONG_PTR KEYBOARDMANAGER_SHORTCUT_FLAG = 0x101; // Shortcut remaps
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "MappingConfiguration.h"
|
#include "MappingConfiguration.h"
|
||||||
|
|
||||||
#include <common/SettingsAPI/settings_objects.h>
|
#include <common/SettingsAPI/settings_objects.h>
|
||||||
@ -17,13 +17,18 @@ void MappingConfiguration::ClearOSLevelShortcuts()
|
|||||||
osLevelShortcutReMapSortedKeys.clear();
|
osLevelShortcutReMapSortedKeys.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Function to clear the Keys remapping table.
|
// Function to clear the Keys remapping table.
|
||||||
void MappingConfiguration::ClearSingleKeyRemaps()
|
void MappingConfiguration::ClearSingleKeyRemaps()
|
||||||
{
|
{
|
||||||
singleKeyReMap.clear();
|
singleKeyReMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to clear the Keys remapping table.
|
||||||
|
void MappingConfiguration::ClearSingleKeyToTextRemaps()
|
||||||
|
{
|
||||||
|
singleKeyToTextReMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
// Function to clear the App specific shortcut remapping table
|
// Function to clear the App specific shortcut remapping table
|
||||||
void MappingConfiguration::ClearAppSpecificShortcuts()
|
void MappingConfiguration::ClearAppSpecificShortcuts()
|
||||||
{
|
{
|
||||||
@ -32,7 +37,7 @@ void MappingConfiguration::ClearAppSpecificShortcuts()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Function to add a new OS level shortcut remapping
|
// Function to add a new OS level shortcut remapping
|
||||||
bool MappingConfiguration::AddOSLevelShortcut(const Shortcut& originalSC, const KeyShortcutUnion& newSC)
|
bool MappingConfiguration::AddOSLevelShortcut(const Shortcut& originalSC, const KeyShortcutTextUnion& newSC)
|
||||||
{
|
{
|
||||||
// Check if the shortcut is already remapped
|
// Check if the shortcut is already remapped
|
||||||
auto it = osLevelShortcutReMap.find(originalSC);
|
auto it = osLevelShortcutReMap.find(originalSC);
|
||||||
@ -49,7 +54,7 @@ bool MappingConfiguration::AddOSLevelShortcut(const Shortcut& originalSC, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Function to add a new single key to key/shortcut remapping
|
// Function to add a new single key to key/shortcut remapping
|
||||||
bool MappingConfiguration::AddSingleKeyRemap(const DWORD& originalKey, const KeyShortcutUnion& newRemapKey)
|
bool MappingConfiguration::AddSingleKeyRemap(const DWORD& originalKey, const KeyShortcutTextUnion& newRemapKey)
|
||||||
{
|
{
|
||||||
// Check if the key is already remapped
|
// Check if the key is already remapped
|
||||||
auto it = singleKeyReMap.find(originalKey);
|
auto it = singleKeyReMap.find(originalKey);
|
||||||
@ -62,8 +67,21 @@ bool MappingConfiguration::AddSingleKeyRemap(const DWORD& originalKey, const Key
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MappingConfiguration::AddSingleKeyToTextRemap(const DWORD originalKey, const std::wstring& text)
|
||||||
|
{
|
||||||
|
if (auto it = singleKeyToTextReMap.find(originalKey); it != end(singleKeyToTextReMap))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
singleKeyToTextReMap[originalKey] = text;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Function to add a new App specific shortcut remapping
|
// Function to add a new App specific shortcut remapping
|
||||||
bool MappingConfiguration::AddAppSpecificShortcut(const std::wstring& app, const Shortcut& originalSC, const KeyShortcutUnion& newSC)
|
bool MappingConfiguration::AddAppSpecificShortcut(const std::wstring& app, const Shortcut& originalSC, const KeyShortcutTextUnion& newSC)
|
||||||
{
|
{
|
||||||
// Convert app name to lower case
|
// Convert app name to lower case
|
||||||
std::wstring process_name;
|
std::wstring process_name;
|
||||||
@ -92,7 +110,6 @@ bool MappingConfiguration::AddAppSpecificShortcut(const std::wstring& app, const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool MappingConfiguration::LoadSingleKeyRemaps(const json::JsonObject& jsonData)
|
bool MappingConfiguration::LoadSingleKeyRemaps(const json::JsonObject& jsonData)
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
@ -141,6 +158,45 @@ bool MappingConfiguration::LoadSingleKeyRemaps(const json::JsonObject& jsonData)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MappingConfiguration::LoadSingleKeyToTextRemaps(const json::JsonObject& jsonData)
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto remapKeysData = jsonData.GetNamedObject(KeyboardManagerConstants::RemapKeysToTextSettingName);
|
||||||
|
ClearSingleKeyToTextRemaps();
|
||||||
|
|
||||||
|
if (!remapKeysData)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto inProcessRemapKeys = remapKeysData.GetNamedArray(KeyboardManagerConstants::InProcessRemapKeysSettingName);
|
||||||
|
for (const auto& it : inProcessRemapKeys)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto originalKey = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
|
||||||
|
auto newText = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewTextSettingName);
|
||||||
|
AddSingleKeyToTextRemap(std::stoul(originalKey.c_str()), newText.c_str());
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
Logger::error(L"Improper Key Data JSON. Try the next remap.");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
Logger::error(L"Improper JSON format for single key to text remaps. Skip to next remap type");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool MappingConfiguration::LoadAppSpecificShortcutRemaps(const json::JsonObject& remapShortcutsData)
|
bool MappingConfiguration::LoadAppSpecificShortcutRemaps(const json::JsonObject& remapShortcutsData)
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
@ -153,19 +209,27 @@ bool MappingConfiguration::LoadAppSpecificShortcutRemaps(const json::JsonObject&
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto originalKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
|
auto originalKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
|
||||||
auto newRemapKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName);
|
auto newRemapKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName, {});
|
||||||
|
auto newRemapText = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewTextSettingName, {});
|
||||||
auto targetApp = it.GetObjectW().GetNamedString(KeyboardManagerConstants::TargetAppSettingName);
|
auto targetApp = it.GetObjectW().GetNamedString(KeyboardManagerConstants::TargetAppSettingName);
|
||||||
|
|
||||||
// If remapped to a shortcut
|
if (!newRemapKeys.empty())
|
||||||
if (std::wstring(newRemapKeys).find(L";") != std::string::npos)
|
|
||||||
{
|
{
|
||||||
AddAppSpecificShortcut(targetApp.c_str(), Shortcut(originalKeys.c_str()), Shortcut(newRemapKeys.c_str()));
|
// If remapped to a shortcut
|
||||||
}
|
if (std::wstring(newRemapKeys).find(L";") != std::string::npos)
|
||||||
|
{
|
||||||
|
AddAppSpecificShortcut(targetApp.c_str(), Shortcut(originalKeys.c_str()), Shortcut(newRemapKeys.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
// If remapped to a key
|
// If remapped to a key
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddAppSpecificShortcut(targetApp.c_str(), Shortcut(originalKeys.c_str()), std::stoul(newRemapKeys.c_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddAppSpecificShortcut(targetApp.c_str(), Shortcut(originalKeys.c_str()), std::stoul(newRemapKeys.c_str()));
|
AddAppSpecificShortcut(targetApp.c_str(), Shortcut(originalKeys.c_str()), newRemapText.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
@ -184,15 +248,13 @@ bool MappingConfiguration::LoadAppSpecificShortcutRemaps(const json::JsonObject&
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MappingConfiguration::LoadShortcutRemaps(const json::JsonObject& jsonData)
|
bool MappingConfiguration::LoadShortcutRemaps(const json::JsonObject& jsonData, const std::wstring& objectName)
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto remapShortcutsData = jsonData.GetNamedObject(KeyboardManagerConstants::RemapShortcutsSettingName);
|
auto remapShortcutsData = jsonData.GetNamedObject(objectName);
|
||||||
ClearOSLevelShortcuts();
|
|
||||||
ClearAppSpecificShortcuts();
|
|
||||||
if (remapShortcutsData)
|
if (remapShortcutsData)
|
||||||
{
|
{
|
||||||
// Load os level shortcut remaps
|
// Load os level shortcut remaps
|
||||||
@ -204,18 +266,25 @@ bool MappingConfiguration::LoadShortcutRemaps(const json::JsonObject& jsonData)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto originalKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
|
auto originalKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
|
||||||
auto newRemapKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName);
|
auto newRemapKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName, {});
|
||||||
|
auto newRemapText = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewTextSettingName, {});
|
||||||
|
|
||||||
// If remapped to a shortcut
|
if (!newRemapKeys.empty())
|
||||||
if (std::wstring(newRemapKeys).find(L";") != std::string::npos)
|
|
||||||
{
|
{
|
||||||
AddOSLevelShortcut(Shortcut(originalKeys.c_str()), Shortcut(newRemapKeys.c_str()));
|
// If remapped to a shortcut
|
||||||
|
if (std::wstring(newRemapKeys).find(L";") != std::string::npos)
|
||||||
|
{
|
||||||
|
AddOSLevelShortcut(Shortcut(originalKeys.c_str()), Shortcut(newRemapKeys.c_str()));
|
||||||
|
}
|
||||||
|
// If remapped to a key
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddOSLevelShortcut(Shortcut(originalKeys.c_str()), std::stoul(newRemapKeys.c_str()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If remapped to a key
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddOSLevelShortcut(Shortcut(originalKeys.c_str()), std::stoul(newRemapKeys.c_str()));
|
AddOSLevelShortcut(Shortcut(originalKeys.c_str()), newRemapText.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
@ -244,10 +313,6 @@ bool MappingConfiguration::LoadShortcutRemaps(const json::JsonObject& jsonData)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
MappingConfiguration::MappingConfiguration()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MappingConfiguration::LoadSettings()
|
bool MappingConfiguration::LoadSettings()
|
||||||
{
|
{
|
||||||
Logger::trace(L"SettingsHelper::LoadSettings()");
|
Logger::trace(L"SettingsHelper::LoadSettings()");
|
||||||
@ -271,7 +336,11 @@ bool MappingConfiguration::LoadSettings()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool result = LoadSingleKeyRemaps(*configFile);
|
bool result = LoadSingleKeyRemaps(*configFile);
|
||||||
result = result && LoadShortcutRemaps(*configFile);
|
ClearOSLevelShortcuts();
|
||||||
|
ClearAppSpecificShortcuts();
|
||||||
|
result = LoadShortcutRemaps(*configFile, KeyboardManagerConstants::RemapShortcutsSettingName) && result;
|
||||||
|
result = LoadShortcutRemaps(*configFile, KeyboardManagerConstants::RemapShortcutsToTextSettingName) && result;
|
||||||
|
result = LoadSingleKeyToTextRemaps(*configFile) && result;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -289,10 +358,20 @@ bool MappingConfiguration::SaveSettingsToFile()
|
|||||||
bool result = true;
|
bool result = true;
|
||||||
json::JsonObject configJson;
|
json::JsonObject configJson;
|
||||||
json::JsonObject remapShortcuts;
|
json::JsonObject remapShortcuts;
|
||||||
|
json::JsonObject remapShortcutsToText;
|
||||||
|
|
||||||
json::JsonObject remapKeys;
|
json::JsonObject remapKeys;
|
||||||
|
json::JsonObject remapKeysToText;
|
||||||
|
|
||||||
json::JsonArray inProcessRemapKeysArray;
|
json::JsonArray inProcessRemapKeysArray;
|
||||||
|
json::JsonArray inProcessRemapKeysToTextArray;
|
||||||
|
|
||||||
json::JsonArray appSpecificRemapShortcutsArray;
|
json::JsonArray appSpecificRemapShortcutsArray;
|
||||||
|
json::JsonArray appSpecificRemapShortcutsToTextArray;
|
||||||
|
|
||||||
json::JsonArray globalRemapShortcutsArray;
|
json::JsonArray globalRemapShortcutsArray;
|
||||||
|
json::JsonArray globalRemapShortcutsToTextArray;
|
||||||
|
|
||||||
for (const auto& it : singleKeyReMap)
|
for (const auto& it : singleKeyReMap)
|
||||||
{
|
{
|
||||||
json::JsonObject keys;
|
json::JsonObject keys;
|
||||||
@ -313,24 +392,43 @@ bool MappingConfiguration::SaveSettingsToFile()
|
|||||||
inProcessRemapKeysArray.Append(keys);
|
inProcessRemapKeysArray.Append(keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto& [code, text] : singleKeyToTextReMap)
|
||||||
|
{
|
||||||
|
json::JsonObject keys;
|
||||||
|
keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(winrt::to_hstring(static_cast<unsigned int>(code))));
|
||||||
|
keys.SetNamedValue(KeyboardManagerConstants::NewTextSettingName, json::value(std::get<std::wstring>(text)));
|
||||||
|
inProcessRemapKeysToTextArray.Append(keys);
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto& it : osLevelShortcutReMap)
|
for (const auto& it : osLevelShortcutReMap)
|
||||||
{
|
{
|
||||||
json::JsonObject keys;
|
json::JsonObject keys;
|
||||||
|
|
||||||
keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(it.first.ToHstringVK()));
|
keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(it.first.ToHstringVK()));
|
||||||
|
|
||||||
|
bool remapToText = false;
|
||||||
|
|
||||||
// For shortcut to key remapping
|
// For shortcut to key remapping
|
||||||
if (it.second.targetShortcut.index() == 0)
|
if (it.second.targetShortcut.index() == 0)
|
||||||
{
|
{
|
||||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(winrt::to_hstring((unsigned int)std::get<DWORD>(it.second.targetShortcut))));
|
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(winrt::to_hstring((unsigned int)std::get<DWORD>(it.second.targetShortcut))));
|
||||||
}
|
}
|
||||||
|
|
||||||
// For shortcut to shortcut remapping
|
// For shortcut to shortcut remapping
|
||||||
else
|
else if (it.second.targetShortcut.index() == 1)
|
||||||
{
|
{
|
||||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(std::get<Shortcut>(it.second.targetShortcut).ToHstringVK()));
|
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(std::get<Shortcut>(it.second.targetShortcut).ToHstringVK()));
|
||||||
}
|
}
|
||||||
|
// For shortcut to text remapping
|
||||||
|
else if (it.second.targetShortcut.index() == 2)
|
||||||
|
{
|
||||||
|
remapToText = true;
|
||||||
|
keys.SetNamedValue(KeyboardManagerConstants::NewTextSettingName, json::value(std::get<std::wstring>(it.second.targetShortcut)));
|
||||||
|
}
|
||||||
|
|
||||||
globalRemapShortcutsArray.Append(keys);
|
if (!remapToText)
|
||||||
|
globalRemapShortcutsArray.Append(keys);
|
||||||
|
else
|
||||||
|
globalRemapShortcutsToTextArray.Append(keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& itApp : appSpecificShortcutReMap)
|
for (const auto& itApp : appSpecificShortcutReMap)
|
||||||
@ -341,6 +439,8 @@ bool MappingConfiguration::SaveSettingsToFile()
|
|||||||
json::JsonObject keys;
|
json::JsonObject keys;
|
||||||
keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(itKeys.first.ToHstringVK()));
|
keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(itKeys.first.ToHstringVK()));
|
||||||
|
|
||||||
|
bool remapToText = false;
|
||||||
|
|
||||||
// For shortcut to key remapping
|
// For shortcut to key remapping
|
||||||
if (itKeys.second.targetShortcut.index() == 0)
|
if (itKeys.second.targetShortcut.index() == 0)
|
||||||
{
|
{
|
||||||
@ -348,22 +448,37 @@ bool MappingConfiguration::SaveSettingsToFile()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For shortcut to shortcut remapping
|
// For shortcut to shortcut remapping
|
||||||
else
|
else if (itKeys.second.targetShortcut.index() == 1)
|
||||||
{
|
{
|
||||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(std::get<Shortcut>(itKeys.second.targetShortcut).ToHstringVK()));
|
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(std::get<Shortcut>(itKeys.second.targetShortcut).ToHstringVK()));
|
||||||
}
|
}
|
||||||
|
else if (itKeys.second.targetShortcut.index() == 2)
|
||||||
|
{
|
||||||
|
keys.SetNamedValue(KeyboardManagerConstants::NewTextSettingName, json::value(std::get<std::wstring>(itKeys.second.targetShortcut)));
|
||||||
|
remapToText = true;
|
||||||
|
}
|
||||||
|
|
||||||
keys.SetNamedValue(KeyboardManagerConstants::TargetAppSettingName, json::value(itApp.first));
|
keys.SetNamedValue(KeyboardManagerConstants::TargetAppSettingName, json::value(itApp.first));
|
||||||
|
|
||||||
appSpecificRemapShortcutsArray.Append(keys);
|
if (!remapToText)
|
||||||
|
appSpecificRemapShortcutsArray.Append(keys);
|
||||||
|
else
|
||||||
|
appSpecificRemapShortcutsToTextArray.Append(keys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remapShortcuts.SetNamedValue(KeyboardManagerConstants::GlobalRemapShortcutsSettingName, globalRemapShortcutsArray);
|
remapShortcuts.SetNamedValue(KeyboardManagerConstants::GlobalRemapShortcutsSettingName, globalRemapShortcutsArray);
|
||||||
remapShortcuts.SetNamedValue(KeyboardManagerConstants::AppSpecificRemapShortcutsSettingName, appSpecificRemapShortcutsArray);
|
remapShortcuts.SetNamedValue(KeyboardManagerConstants::AppSpecificRemapShortcutsSettingName, appSpecificRemapShortcutsArray);
|
||||||
|
|
||||||
|
remapShortcutsToText.SetNamedValue(KeyboardManagerConstants::GlobalRemapShortcutsSettingName, globalRemapShortcutsToTextArray);
|
||||||
|
remapShortcutsToText.SetNamedValue(KeyboardManagerConstants::AppSpecificRemapShortcutsSettingName, appSpecificRemapShortcutsToTextArray);
|
||||||
|
|
||||||
remapKeys.SetNamedValue(KeyboardManagerConstants::InProcessRemapKeysSettingName, inProcessRemapKeysArray);
|
remapKeys.SetNamedValue(KeyboardManagerConstants::InProcessRemapKeysSettingName, inProcessRemapKeysArray);
|
||||||
|
remapKeysToText.SetNamedValue(KeyboardManagerConstants::InProcessRemapKeysSettingName, inProcessRemapKeysToTextArray);
|
||||||
configJson.SetNamedValue(KeyboardManagerConstants::RemapKeysSettingName, remapKeys);
|
configJson.SetNamedValue(KeyboardManagerConstants::RemapKeysSettingName, remapKeys);
|
||||||
|
configJson.SetNamedValue(KeyboardManagerConstants::RemapKeysToTextSettingName, remapKeysToText);
|
||||||
configJson.SetNamedValue(KeyboardManagerConstants::RemapShortcutsSettingName, remapShortcuts);
|
configJson.SetNamedValue(KeyboardManagerConstants::RemapShortcutsSettingName, remapShortcuts);
|
||||||
|
configJson.SetNamedValue(KeyboardManagerConstants::RemapShortcutsToTextSettingName, remapShortcutsToText);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -6,15 +6,14 @@
|
|||||||
#include <keyboardmanager/common/Shortcut.h>
|
#include <keyboardmanager/common/Shortcut.h>
|
||||||
#include <keyboardmanager/common/RemapShortcut.h>
|
#include <keyboardmanager/common/RemapShortcut.h>
|
||||||
|
|
||||||
using SingleKeyRemapTable = std::unordered_map<DWORD, KeyShortcutUnion>;
|
using SingleKeyRemapTable = std::unordered_map<DWORD, KeyShortcutTextUnion>;
|
||||||
|
using SingleKeyToTextRemapTable = SingleKeyRemapTable;
|
||||||
using ShortcutRemapTable = std::map<Shortcut, RemapShortcut>;
|
using ShortcutRemapTable = std::map<Shortcut, RemapShortcut>;
|
||||||
using AppSpecificShortcutRemapTable = std::map<std::wstring, ShortcutRemapTable>;
|
using AppSpecificShortcutRemapTable = std::map<std::wstring, ShortcutRemapTable>;
|
||||||
|
|
||||||
class MappingConfiguration
|
class MappingConfiguration
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MappingConfiguration();
|
|
||||||
|
|
||||||
~MappingConfiguration() = default;
|
~MappingConfiguration() = default;
|
||||||
|
|
||||||
// Load the configuration.
|
// Load the configuration.
|
||||||
@ -29,22 +28,31 @@ public:
|
|||||||
// Function to clear the Keys remapping table
|
// Function to clear the Keys remapping table
|
||||||
void ClearSingleKeyRemaps();
|
void ClearSingleKeyRemaps();
|
||||||
|
|
||||||
|
// Function to clear the Keys to text remapping table
|
||||||
|
void ClearSingleKeyToTextRemaps();
|
||||||
|
|
||||||
// Function to clear the App specific shortcut remapping table
|
// Function to clear the App specific shortcut remapping table
|
||||||
void ClearAppSpecificShortcuts();
|
void ClearAppSpecificShortcuts();
|
||||||
|
|
||||||
// Function to add a new single key to key remapping
|
// Function to add a new single key to key remapping
|
||||||
bool AddSingleKeyRemap(const DWORD& originalKey, const KeyShortcutUnion& newRemapKey);
|
bool AddSingleKeyRemap(const DWORD& originalKey, const KeyShortcutTextUnion& newRemapKey);
|
||||||
|
|
||||||
|
// Function to add a new single key to unicode string remapping
|
||||||
|
bool AddSingleKeyToTextRemap(const DWORD originalKey, const std::wstring& text);
|
||||||
|
|
||||||
// Function to add a new OS level shortcut remapping
|
// Function to add a new OS level shortcut remapping
|
||||||
bool AddOSLevelShortcut(const Shortcut& originalSC, const KeyShortcutUnion& newSC);
|
bool AddOSLevelShortcut(const Shortcut& originalSC, const KeyShortcutTextUnion& newSC);
|
||||||
|
|
||||||
// Function to add a new App specific level shortcut remapping
|
// Function to add a new App specific level shortcut remapping
|
||||||
bool AddAppSpecificShortcut(const std::wstring& app, const Shortcut& originalSC, const KeyShortcutUnion& newSC);
|
bool AddAppSpecificShortcut(const std::wstring& app, const Shortcut& originalSC, const KeyShortcutTextUnion& newSC);
|
||||||
|
|
||||||
// The map members and their mutexes are left as public since the maps are used extensively in dllmain.cpp.
|
// The map members and their mutexes are left as public since the maps are used extensively in dllmain.cpp.
|
||||||
// Maps which store the remappings for each of the features. The bool fields should be initialized to false. They are used to check the current state of the shortcut (i.e is that particular shortcut currently pressed down or not).
|
// Maps which store the remappings for each of the features. The bool fields should be initialized to false. They are used to check the current state of the shortcut (i.e is that particular shortcut currently pressed down or not).
|
||||||
// Stores single key remappings
|
// Stores single key remappings
|
||||||
std::unordered_map<DWORD, KeyShortcutUnion> singleKeyReMap;
|
SingleKeyRemapTable singleKeyReMap;
|
||||||
|
|
||||||
|
// Stores single key to text remappings
|
||||||
|
SingleKeyToTextRemapTable singleKeyToTextReMap;
|
||||||
|
|
||||||
// Stores the os level shortcut remappings
|
// Stores the os level shortcut remappings
|
||||||
ShortcutRemapTable osLevelShortcutReMap;
|
ShortcutRemapTable osLevelShortcutReMap;
|
||||||
@ -57,9 +65,9 @@ public:
|
|||||||
// Stores the current configuration name.
|
// Stores the current configuration name.
|
||||||
std::wstring currentConfig = KeyboardManagerConstants::DefaultConfiguration;
|
std::wstring currentConfig = KeyboardManagerConstants::DefaultConfiguration;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool LoadSingleKeyRemaps(const json::JsonObject& jsonData);
|
bool LoadSingleKeyRemaps(const json::JsonObject& jsonData);
|
||||||
bool LoadShortcutRemaps(const json::JsonObject& jsonData);
|
bool LoadSingleKeyToTextRemaps(const json::JsonObject& jsonData);
|
||||||
|
bool LoadShortcutRemaps(const json::JsonObject& jsonData, const std::wstring& objectName);
|
||||||
bool LoadAppSpecificShortcutRemaps(const json::JsonObject& remapShortcutsData);
|
bool LoadAppSpecificShortcutRemaps(const json::JsonObject& remapShortcutsData);
|
||||||
};
|
};
|
@ -6,13 +6,13 @@
|
|||||||
class RemapShortcut
|
class RemapShortcut
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
KeyShortcutUnion targetShortcut;
|
KeyShortcutTextUnion targetShortcut;
|
||||||
bool isShortcutInvoked;
|
bool isShortcutInvoked;
|
||||||
ModifierKey winKeyInvoked;
|
ModifierKey winKeyInvoked;
|
||||||
// This bool value is only required for remapping shortcuts to Disable
|
// This bool value is only required for remapping shortcuts to Disable
|
||||||
bool isOriginalActionKeyPressed;
|
bool isOriginalActionKeyPressed;
|
||||||
|
|
||||||
RemapShortcut(const KeyShortcutUnion& sc) :
|
RemapShortcut(const KeyShortcutTextUnion& sc) :
|
||||||
targetShortcut(sc), isShortcutInvoked(false), winKeyInvoked(ModifierKey::Disabled), isOriginalActionKeyPressed(false)
|
targetShortcut(sc), isShortcutInvoked(false), winKeyInvoked(ModifierKey::Disabled), isOriginalActionKeyPressed(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ public:
|
|||||||
int GetCommonModifiersCount(const Shortcut& input) const;
|
int GetCommonModifiersCount(const Shortcut& input) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
using KeyShortcutUnion = std::variant<DWORD, Shortcut>;
|
using KeyShortcutTextUnion = std::variant<DWORD, Shortcut, std::wstring>;
|
||||||
using RemapBufferItem = std::vector<KeyShortcutUnion>;
|
using RemapBufferItem = std::vector<KeyShortcutTextUnion>;
|
||||||
using RemapBufferRow = std::pair<RemapBufferItem, std::wstring>;
|
using RemapBufferRow = std::pair<RemapBufferItem, std::wstring>;
|
||||||
using RemapBuffer = std::vector<RemapBufferRow>;
|
using RemapBuffer = std::vector<RemapBufferRow>;
|
||||||
|
@ -28,9 +28,10 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
ArgumentNullException.ThrowIfNull(arg);
|
ArgumentNullException.ThrowIfNull(arg);
|
||||||
|
|
||||||
// Using Ordinal comparison for internal text
|
// Using Ordinal comparison for internal text
|
||||||
return OriginalKeys.Equals(arg.OriginalKeys, StringComparison.Ordinal) &&
|
return string.Equals(OriginalKeys, arg.OriginalKeys, StringComparison.Ordinal) &&
|
||||||
NewRemapKeys.Equals(arg.NewRemapKeys, StringComparison.Ordinal) &&
|
string.Equals(NewRemapKeys, arg.NewRemapKeys, StringComparison.Ordinal) &&
|
||||||
TargetApp.Equals(arg.TargetApp, StringComparison.Ordinal);
|
string.Equals(NewRemapString, arg.NewRemapString, StringComparison.Ordinal) &&
|
||||||
|
string.Equals(TargetApp, arg.TargetApp, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,13 +13,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
[JsonPropertyName("remapKeys")]
|
[JsonPropertyName("remapKeys")]
|
||||||
public RemapKeysDataModel RemapKeys { get; set; }
|
public RemapKeysDataModel RemapKeys { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("remapKeysToText")]
|
||||||
|
public RemapKeysDataModel RemapKeysToText { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("remapShortcuts")]
|
[JsonPropertyName("remapShortcuts")]
|
||||||
public ShortcutsKeyDataModel RemapShortcuts { get; set; }
|
public ShortcutsKeyDataModel RemapShortcuts { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("remapShortcutsToText")]
|
||||||
|
public ShortcutsKeyDataModel RemapShortcutsToText { get; set; }
|
||||||
|
|
||||||
public KeyboardManagerProfile()
|
public KeyboardManagerProfile()
|
||||||
{
|
{
|
||||||
RemapKeys = new RemapKeysDataModel();
|
RemapKeys = new RemapKeysDataModel();
|
||||||
|
RemapKeysToText = new RemapKeysDataModel();
|
||||||
|
|
||||||
RemapShortcuts = new ShortcutsKeyDataModel();
|
RemapShortcuts = new ShortcutsKeyDataModel();
|
||||||
|
RemapShortcutsToText = new ShortcutsKeyDataModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ToJsonString()
|
public string ToJsonString()
|
||||||
|
@ -18,6 +18,9 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
[JsonPropertyName("newRemapKeys")]
|
[JsonPropertyName("newRemapKeys")]
|
||||||
public string NewRemapKeys { get; set; }
|
public string NewRemapKeys { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("unicodeText")]
|
||||||
|
public string NewRemapString { get; set; }
|
||||||
|
|
||||||
private static List<string> MapKeys(string stringOfKeys)
|
private static List<string> MapKeys(string stringOfKeys)
|
||||||
{
|
{
|
||||||
return stringOfKeys
|
return stringOfKeys
|
||||||
@ -34,7 +37,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
|
|
||||||
public List<string> GetMappedNewRemapKeys()
|
public List<string> GetMappedNewRemapKeys()
|
||||||
{
|
{
|
||||||
return MapKeys(NewRemapKeys);
|
return string.IsNullOrEmpty(NewRemapString) ? MapKeys(NewRemapKeys) : new List<string> { NewRemapString };
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ToJsonString()
|
public string ToJsonString()
|
||||||
|
@ -306,6 +306,13 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
{
|
{
|
||||||
KeyboardManagerProfile kbmProfile = GetKBMProfile();
|
KeyboardManagerProfile kbmProfile = GetKBMProfile();
|
||||||
_kbmItem = new DashboardModuleKBMItem() { RemapKeys = kbmProfile?.RemapKeys.InProcessRemapKeys, RemapShortcuts = KeyboardManagerViewModel.CombineShortcutLists(kbmProfile?.RemapShortcuts.GlobalRemapShortcuts, kbmProfile?.RemapShortcuts.AppSpecificRemapShortcuts) };
|
_kbmItem = new DashboardModuleKBMItem() { RemapKeys = kbmProfile?.RemapKeys.InProcessRemapKeys, RemapShortcuts = KeyboardManagerViewModel.CombineShortcutLists(kbmProfile?.RemapShortcuts.GlobalRemapShortcuts, kbmProfile?.RemapShortcuts.AppSpecificRemapShortcuts) };
|
||||||
|
|
||||||
|
_kbmItem.RemapKeys = _kbmItem.RemapKeys.Concat(kbmProfile?.RemapKeysToText.InProcessRemapKeys).ToList();
|
||||||
|
|
||||||
|
var shortcutsToTextRemappings = KeyboardManagerViewModel.CombineShortcutLists(kbmProfile?.RemapShortcutsToText.GlobalRemapShortcuts, kbmProfile?.RemapShortcutsToText.AppSpecificRemapShortcuts);
|
||||||
|
|
||||||
|
_kbmItem.RemapShortcuts = _kbmItem.RemapShortcuts.Concat(shortcutsToTextRemappings).ToList();
|
||||||
|
|
||||||
var list = new List<DashboardModuleItem>
|
var list = new List<DashboardModuleItem>
|
||||||
{
|
{
|
||||||
_kbmItem,
|
_kbmItem,
|
||||||
|
@ -158,7 +158,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
{
|
{
|
||||||
if (_profile != null)
|
if (_profile != null)
|
||||||
{
|
{
|
||||||
return _profile.RemapKeys.InProcessRemapKeys;
|
return _profile.RemapKeys.InProcessRemapKeys.Concat(_profile.RemapKeysToText.InProcessRemapKeys).ToList();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -190,11 +190,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
}
|
}
|
||||||
else if (appSpecificShortcutList == null)
|
else if (appSpecificShortcutList == null)
|
||||||
{
|
{
|
||||||
return globalShortcutList.ConvertAll(x => new AppSpecificKeysDataModel { OriginalKeys = x.OriginalKeys, NewRemapKeys = x.NewRemapKeys, TargetApp = allAppsDescription }).ToList();
|
return globalShortcutList.ConvertAll(x => new AppSpecificKeysDataModel { OriginalKeys = x.OriginalKeys, NewRemapKeys = x.NewRemapKeys, NewRemapString = x.NewRemapString, TargetApp = allAppsDescription }).ToList();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return globalShortcutList.ConvertAll(x => new AppSpecificKeysDataModel { OriginalKeys = x.OriginalKeys, NewRemapKeys = x.NewRemapKeys, TargetApp = allAppsDescription }).Concat(appSpecificShortcutList).ToList();
|
return globalShortcutList.ConvertAll(x => new AppSpecificKeysDataModel { OriginalKeys = x.OriginalKeys, NewRemapKeys = x.NewRemapKeys, NewRemapString = x.NewRemapString, TargetApp = allAppsDescription }).Concat(appSpecificShortcutList).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
{
|
{
|
||||||
if (_profile != null)
|
if (_profile != null)
|
||||||
{
|
{
|
||||||
return CombineShortcutLists(_profile.RemapShortcuts.GlobalRemapShortcuts, _profile.RemapShortcuts.AppSpecificRemapShortcuts);
|
return CombineShortcutLists(_profile.RemapShortcuts.GlobalRemapShortcuts, _profile.RemapShortcuts.AppSpecificRemapShortcuts).Concat(CombineShortcutLists(_profile.RemapShortcutsToText.GlobalRemapShortcuts, _profile.RemapShortcutsToText.AppSpecificRemapShortcuts)).ToList();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -333,6 +333,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
if (readSuccessfully)
|
if (readSuccessfully)
|
||||||
{
|
{
|
||||||
FilterRemapKeysList(_profile?.RemapKeys?.InProcessRemapKeys);
|
FilterRemapKeysList(_profile?.RemapKeys?.InProcessRemapKeys);
|
||||||
|
FilterRemapKeysList(_profile?.RemapKeysToText?.InProcessRemapKeys);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -27,7 +27,9 @@ using namespace winrt::Windows::Data::Json;
|
|||||||
|
|
||||||
map<wstring, vector<wstring>> escapeInfo = {
|
map<wstring, vector<wstring>> escapeInfo = {
|
||||||
{ L"FancyZones\\app-zone-history.json", { L"app-zone-history/app-path" } },
|
{ L"FancyZones\\app-zone-history.json", { L"app-zone-history/app-path" } },
|
||||||
{ L"FancyZones\\settings.json", { L"properties/fancyzones_excluded_apps" } }
|
{ L"FancyZones\\settings.json", { L"properties/fancyzones_excluded_apps" } },
|
||||||
|
{ L"MouseWithoutBorders\\settings.json", { L"properties/SecurityKey" } }, // avoid leaking connection key
|
||||||
|
{ L"Keyboard Manager\\default.json", { L"remapKeysToText", L"remapShortcutsToText" } }, // avoid leaking personal information from text mappings
|
||||||
};
|
};
|
||||||
|
|
||||||
vector<wstring> filesToDelete = {
|
vector<wstring> filesToDelete = {
|
||||||
|
Loading…
Reference in New Issue
Block a user