[Keyboard Manager] Added in Shortcut to Key and Key to Shortcut remapping (#5070)

* Added union class

* Added key to shortcut backend implementation

* Added tests

* Added tests for CapsLock/modifier workaround for key to shortcut

* Added correct JSON loading step

* Cleaned shortcut remap code to use helper function for modifier keys

* Removed RemapKey class

* Enable Key to Shortcut in UI along with Type Shortcut in Remap key window

* Fixed orphaning and unsuccessful remap dialog

* Fixed column width

* Renamed second type key button

* Fixed Type Shortcut issues

* Fixed shortcut to key backend logic and manually tested most scenarios

* Added s2k in UI, manually verified its working

* Added one more k2s test

* Added tests for s2k

* Added tests for Caps Lock workaround in shortcut remaps

* Fixed formatting

* Fixed formatting

* Removed safety code since it can cause issues with code generated key up events

* Added test for key up scenario

* Tweaked warning text

* Tweaked text

* Tweaked text to fit in two lines

* telemetry additions
This commit is contained in:
Arjun Balgovind
2020-07-23 16:43:49 -07:00
committed by GitHub
parent 53c4c6cbb8
commit ff1e04b957
32 changed files with 2322 additions and 686 deletions

View File

@@ -40,7 +40,7 @@ namespace RemappingLogicTests
input[0].ki.wVk = 0x41;
// Send A keydown
mockedInputHandler.SendVirtualInput(1, input, sizeof(INPUT));
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
// A key state should be unchanged, and B key state should be true
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
@@ -48,7 +48,7 @@ namespace RemappingLogicTests
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
// Send A keyup
mockedInputHandler.SendVirtualInput(1, input, sizeof(INPUT));
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
// A key state should be unchanged, and B key state should be false
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
@@ -67,14 +67,14 @@ namespace RemappingLogicTests
input[0].ki.wVk = 0x41;
// Send A keydown
mockedInputHandler.SendVirtualInput(1, input, sizeof(INPUT));
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
// A key state should be unchanged
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
// Send A keyup
mockedInputHandler.SendVirtualInput(1, input, sizeof(INPUT));
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
// A key state should be unchanged
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
@@ -92,7 +92,7 @@ namespace RemappingLogicTests
input[0].ki.wVk = 0x41;
// Send A keydown
mockedInputHandler.SendVirtualInput(1, input, sizeof(INPUT));
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
// A key state should be unchanged, and common Win key state should be true
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
@@ -100,7 +100,7 @@ namespace RemappingLogicTests
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
// Send A keyup
mockedInputHandler.SendVirtualInput(1, input, sizeof(INPUT));
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
// A key state should be unchanged, and common Win key state should be false
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
@@ -108,7 +108,7 @@ namespace RemappingLogicTests
}
// Test if SendVirtualInput is sent exactly once with the suppress flag when Caps Lock is remapped to Ctrl
TEST_METHOD (HandleSingleKeyRemapEvent_ShouldSendVirutalInputWithSuppressFlagExactlyOnce_WhenCapsLockIsMappedToCtrlAltShift)
TEST_METHOD (HandleSingleKeyRemapEvent_ShouldSendVirtualInputWithSuppressFlagExactlyOnce_WhenCapsLockIsMappedToCtrlAltShift)
{
// Set sendvirtualinput call count condition to return true if the key event was sent with the suppress flag
mockedInputHandler.SetSendVirtualInputTestHandler([](LowlevelKeyboardEvent* data) {
@@ -127,14 +127,14 @@ namespace RemappingLogicTests
input[0].ki.wVk = VK_CAPITAL;
// Send Caps Lock keydown
mockedInputHandler.SendVirtualInput(1, input, sizeof(INPUT));
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
// SendVirtualInput should be called exactly once with the above condition
Assert::AreEqual(1, mockedInputHandler.GetSendVirtualInputCallCount());
}
// Test if SendVirtualInput is sent exactly once with the suppress flag when Ctrl is remapped to Caps Lock
TEST_METHOD (HandleSingleKeyRemapEvent_ShouldSendVirutalInputWithSuppressFlagExactlyOnce_WhenCtrlAltShiftIsMappedToCapsLock)
TEST_METHOD (HandleSingleKeyRemapEvent_ShouldSendVirtualInputWithSuppressFlagExactlyOnce_WhenCtrlAltShiftIsMappedToCapsLock)
{
// Set sendvirtualinput call count condition to return true if the key event was sent with the suppress flag
mockedInputHandler.SetSendVirtualInputTestHandler([](LowlevelKeyboardEvent* data) {
@@ -153,10 +153,166 @@ namespace RemappingLogicTests
input[0].ki.wVk = VK_CONTROL;
// Send Ctrl keydown
mockedInputHandler.SendVirtualInput(1, input, sizeof(INPUT));
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
// SendVirtualInput should be called exactly once with the above condition
Assert::AreEqual(1, mockedInputHandler.GetSendVirtualInputCallCount());
}
// Test if SendVirtualInput is sent exactly twice with the suppress flag when Caps Lock is remapped to shortcut with Ctrl and Shift
TEST_METHOD (HandleSingleKeyRemapEvent_ShouldSendVirtualInputWithSuppressFlagExactlyTwice_WhenCapsLockIsMappedToShortcutWithCtrlAltShift)
{
// Set sendvirtualinput call count condition to return true if the key event was sent with the suppress flag
mockedInputHandler.SetSendVirtualInputTestHandler([](LowlevelKeyboardEvent* data) {
if (data->lParam->dwExtraInfo == KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG)
return true;
else
return false;
});
// Remap Caps Lock to Ctrl+Shift+V
Shortcut dest;
dest.SetKey(VK_CONTROL);
dest.SetKey(VK_SHIFT);
dest.SetKey(0x56);
testState.AddSingleKeyRemap(VK_CAPITAL, dest);
const int nInputs = 1;
INPUT input[nInputs] = {};
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = VK_CAPITAL;
// Send Caps Lock keydown
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
// SendVirtualInput should be called exactly twice with the above condition
Assert::AreEqual(2, mockedInputHandler.GetSendVirtualInputCallCount());
}
// Test if SendVirtualInput is sent exactly once with the suppress flag when Ctrl is remapped to a shortcut with Caps Lock
TEST_METHOD (HandleSingleKeyRemapEvent_ShouldSendVirtualInputWithSuppressFlagExactlyOnce_WhenCtrlAltShiftIsMappedToShortcutWithCapsLock)
{
// Set sendvirtualinput call count condition to return true if the key event was sent with the suppress flag
mockedInputHandler.SetSendVirtualInputTestHandler([](LowlevelKeyboardEvent* data) {
if (data->lParam->dwExtraInfo == KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG)
return true;
else
return false;
});
// Remap Ctrl to Ctrl+Caps Lock
Shortcut dest;
dest.SetKey(VK_CONTROL);
dest.SetKey(VK_CAPITAL);
testState.AddSingleKeyRemap(VK_CONTROL, dest);
const int nInputs = 1;
INPUT input[nInputs] = {};
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = VK_CONTROL;
// Send Ctrl keydown
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
// SendVirtualInput should be called exactly once with the above condition
Assert::AreEqual(1, mockedInputHandler.GetSendVirtualInputCallCount());
}
// Test if correct keyboard states are set for a single key to two key shortcut remap
TEST_METHOD (RemappedKeyToTwoKeyShortcut_ShouldSetTargetKeyState_OnKeyEvent)
{
// Remap A to Ctrl+V
Shortcut dest;
dest.SetKey(VK_CONTROL);
dest.SetKey(0x56);
testState.AddSingleKeyRemap(0x41, dest);
const int nInputs = 1;
INPUT input[nInputs] = {};
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = 0x41;
// Send A keydown
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
// A key state should be unchanged, and Ctrl, V key state should be true
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true);
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true);
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
// Send A keyup
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
// A key state should be unchanged, and Ctrl, V key state should be false
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false);
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false);
}
// Test if correct keyboard states are set for a single key to three key shortcut remap
TEST_METHOD (RemappedKeyToThreeKeyShortcut_ShouldSetTargetKeyState_OnKeyEvent)
{
// Remap A to Ctrl+Shift+V
Shortcut dest;
dest.SetKey(VK_CONTROL);
dest.SetKey(VK_SHIFT);
dest.SetKey(0x56);
testState.AddSingleKeyRemap(0x41, dest);
const int nInputs = 1;
INPUT input[nInputs] = {};
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = 0x41;
// Send A keydown
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
// A key state should be unchanged, and Ctrl, Shift, V key state should be true
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true);
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), true);
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true);
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
// Send A keyup
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
// A key state should be unchanged, and Ctrl, Shift, V key state should be false
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false);
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false);
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false);
}
// Test if correct keyboard states are set for a remap from a single key to a shortcut containing the source key
TEST_METHOD (RemappedKeyToShortcutContainingSourceKey_ShouldSetTargetKeyState_OnKeyEvent)
{
// Remap LCtrl to LCtrl+V
Shortcut dest;
dest.SetKey(VK_LCONTROL);
dest.SetKey(0x56);
testState.AddSingleKeyRemap(VK_LCONTROL, dest);
const int nInputs = 1;
INPUT input[nInputs] = {};
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = VK_LCONTROL;
// Send LCtrl keydown
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
// LCtrl, V key state should be true
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LCONTROL), true);
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true);
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
// Send LCtrl keyup
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
// LCtrl, V key state should be false
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LCONTROL), false);
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false);
}
};
}