mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 17:56:44 +02:00
- remove common lib - split settings, remove common-md - move ipc interop/kb_layout to interop - rename core -> settings, settings -> old_settings - os-detect header-only; interop -> PowerToysInterop - split notifications, move single-use headers where they're used - winstore lib - rename com utils - rename Updating and Telemetry projects - rename core -> settings-ui and remove examples folder - rename settings-ui folder + consisent common/version include
319 lines
14 KiB
C++
319 lines
14 KiB
C++
#include "pch.h"
|
|
#include "CppUnitTest.h"
|
|
#include "MockedInput.h"
|
|
#include <keyboardmanager/common/KeyboardManagerState.h>
|
|
#include <keyboardmanager/dll/KeyboardEventHandlers.h>
|
|
#include "TestHelpers.h"
|
|
#include <common/interop/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<intptr_t(LowlevelKeyboardEvent*)> 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 VK_DISABLE (disabled)
|
|
testState.AddSingleKeyRemap(0x41, CommonSharedConstants::VK_DISABLED);
|
|
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);
|
|
}
|
|
};
|
|
}
|