#include "pch.h" #include "CppUnitTest.h" #include "MockedInput.h" #include #include #include "TestHelpers.h" #include "../common/shared_constants.h" using namespace Microsoft::VisualStudio::CppUnitTestFramework; namespace RemappingLogicTests { // Tests for single key remapping logic TEST_CLASS (SingleKeyRemappingTests) { private: MockedInput mockedInputHandler; KeyboardManagerState testState; public: TEST_METHOD_INITIALIZE(InitializeTestEnv) { // Reset test environment TestHelpers::ResetTestEnv(mockedInputHandler, testState); // Set HandleSingleKeyRemapEvent as the hook procedure std::function currentHookProc = std::bind(&KeyboardEventHandlers::HandleSingleKeyRemapEvent, std::ref(mockedInputHandler), std::placeholders::_1, std::ref(testState)); mockedInputHandler.SetHookProc(currentHookProc); } // Test if correct keyboard states are set for a single key remap TEST_METHOD (RemappedKey_ShouldSetTargetKeyState_OnKeyEvent) { // Remap A to B testState.AddSingleKeyRemap(0x41, 0x42); 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 B key state should be true Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x42), true); input[0].ki.dwFlags = KEYEVENTF_KEYUP; // Send A keyup 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); Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x42), false); } // Test if key is suppressed if a key is disabled by single key remap TEST_METHOD (RemappedKeyDisabled_ShouldNotChangeKeyState_OnKeyEvent) { // Remap A to 0x0 (disabled) testState.AddSingleKeyRemap(0x41, 0x0); 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 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); input[0].ki.dwFlags = KEYEVENTF_KEYUP; // Send A keyup mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT)); // A key state should be unchanged Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); } // Test if correct keyboard states are set for a remap to Win (Both) key TEST_METHOD (RemappedKeyToWinBoth_ShouldSetWinLeftKeyState_OnKeyEvent) { // Remap A to Common Win key testState.AddSingleKeyRemap(0x41, CommonSharedConstants::VK_WIN_BOTH); 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 common Win key state should be true Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LWIN), true); input[0].ki.dwFlags = KEYEVENTF_KEYUP; // Send A keyup 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); Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LWIN), false); } // Test if SendVirtualInput is sent exactly once with the suppress flag when Caps Lock is remapped to Ctrl 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) { if (data->lParam->dwExtraInfo == KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG) return true; else return false; }); // Remap Caps Lock to Ctrl testState.AddSingleKeyRemap(VK_CAPITAL, VK_CONTROL); 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 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_ShouldSendVirtualInputWithSuppressFlagExactlyOnce_WhenCtrlAltShiftIsMappedToCapsLock) { // 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 Caps Lock testState.AddSingleKeyRemap(VK_CONTROL, VK_CAPITAL); 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 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); } }; }