OSLevelShortcutRemappingTests.cpp
1 #include "pch.h" 2 3 // Suppressing 26466 - Don't use static_cast downcasts - in CppUnitTest.h 4 #pragma warning(push) 5 #pragma warning(disable : 26466) 6 #include "CppUnitTest.h" 7 #pragma warning(pop) 8 9 #include "MockedInput.h" 10 #include <keyboardmanager/KeyboardManagerEngineLibrary/State.h> 11 #include <keyboardmanager/KeyboardManagerEngineLibrary/KeyboardEventHandlers.h> 12 #include "TestHelpers.h" 13 #include <common/interop/shared_constants.h> 14 15 using namespace Microsoft::VisualStudio::CppUnitTestFramework; 16 17 namespace RemappingLogicTests 18 { 19 // Tests for shortcut remapping logic 20 TEST_CLASS (OSLevelShortcutRemappingTests) 21 { 22 private: 23 KeyboardManagerInput::MockedInput mockedInputHandler; 24 State testState; 25 26 public: 27 TEST_METHOD_INITIALIZE(InitializeTestEnv) 28 { 29 // Reset test environment 30 TestHelpers::ResetTestEnv(mockedInputHandler, testState); 31 32 // Set HandleOSLevelShortcutRemapEvent as the hook procedure 33 std::function<intptr_t(LowlevelKeyboardEvent*)> currentHookProc = std::bind(&KeyboardEventHandlers::HandleOSLevelShortcutRemapEvent, std::ref(mockedInputHandler), std::placeholders::_1, std::ref(testState)); 34 mockedInputHandler.SetHookProc([currentHookProc](LowlevelKeyboardEvent* data) { 35 if (data->lParam->dwExtraInfo != KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG) 36 { 37 return currentHookProc(data); 38 } 39 else 40 { 41 return 1LL; 42 } 43 }); 44 } 45 46 // Tests for shortcut to shortcut remappings 47 48 // Test if correct keyboard states are set for a 2 key shortcut remap with different modifiers key down 49 TEST_METHOD (RemappedTwoKeyShortcutWithDiffModifiers_ShouldSetTargetShortcutDown_OnKeyDown) 50 { 51 // Remap Ctrl+A to Alt+V 52 Shortcut src; 53 src.SetKey(VK_CONTROL); 54 src.SetKey(0x41); 55 Shortcut dest; 56 dest.SetKey(VK_MENU); 57 dest.SetKey(0x56); 58 testState.AddOSLevelShortcut(src, dest); 59 60 std::vector<INPUT> inputs{ 61 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 62 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 63 }; 64 65 // Send Ctrl+A keydown 66 mockedInputHandler.SendVirtualInput(inputs); 67 68 // Ctrl and A key states should be unchanged, Alt and V key states should be true 69 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 70 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 71 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), true); 72 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true); 73 } 74 75 // Test if correct keyboard states are set for a 2 key shortcut remap with same modifiers key down 76 TEST_METHOD (RemappedTwoKeyShortcutWithSameModifiers_ShouldSetTargetShortcutDown_OnKeyDown) 77 { 78 // Remap Ctrl+A to Ctrl+V 79 Shortcut src; 80 src.SetKey(VK_CONTROL); 81 src.SetKey(0x41); 82 Shortcut dest; 83 dest.SetKey(VK_CONTROL); 84 dest.SetKey(0x56); 85 testState.AddOSLevelShortcut(src, dest); 86 87 std::vector<INPUT> inputs{ 88 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 89 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 90 }; 91 92 // Send Ctrl+A keydown 93 mockedInputHandler.SendVirtualInput(inputs); 94 95 // A key state should be unchanged, Ctrl and V key states should be true 96 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 97 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 98 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true); 99 } 100 101 // Test if correct keyboard states are set for a 2 key shortcut remap with different modifiers key down followed by key up 102 TEST_METHOD (RemappedTwoKeyShortcutWithDiffModifiers_ShouldClearKeyboard_OnKeyUp) 103 { 104 // Remap Ctrl+A to Alt+V 105 Shortcut src; 106 src.SetKey(VK_CONTROL); 107 src.SetKey(0x41); 108 Shortcut dest; 109 dest.SetKey(VK_MENU); 110 dest.SetKey(0x56); 111 testState.AddOSLevelShortcut(src, dest); 112 113 std::vector<INPUT> inputs{ 114 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 115 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 116 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 117 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 118 }; 119 120 // Send Ctrl+A keydown, followed by A and Ctrl released 121 mockedInputHandler.SendVirtualInput(inputs); 122 123 // Ctrl, A, Alt, V key states should be false 124 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 125 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 126 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 127 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 128 } 129 130 // Test if correct keyboard states are set for a 2 key shortcut remap with same modifiers key down followed by key up 131 TEST_METHOD (RemappedTwoKeyShortcutWithSameModifiers_ShouldClearKeyboard_OnKeyUp) 132 { 133 // Remap Ctrl+A to Ctrl+V 134 Shortcut src; 135 src.SetKey(VK_CONTROL); 136 src.SetKey(0x41); 137 Shortcut dest; 138 dest.SetKey(VK_CONTROL); 139 dest.SetKey(0x56); 140 testState.AddOSLevelShortcut(src, dest); 141 142 std::vector<INPUT> inputs{ 143 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 144 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 145 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 146 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 147 }; 148 149 // Send Ctrl+A keydown, followed by A and Ctrl released 150 mockedInputHandler.SendVirtualInput(inputs); 151 152 // Ctrl, A, V key states should be false 153 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 154 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 155 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 156 } 157 158 // Test if correct keyboard states are set when a 2 key shortcut is remapped, and a 3 key shortcut containing those keys is invoked - Ex: Ctrl+A remapped, but user presses Ctrl+Shift+A 159 TEST_METHOD (RemappedTwoKeyShortcutInvokingAShortcutContainingThoseKeys_ShouldNotBeRemapped_OnKeyDown) 160 { 161 // Remap Ctrl+A to Alt+V 162 Shortcut src; 163 src.SetKey(VK_CONTROL); 164 src.SetKey(0x41); 165 Shortcut dest; 166 dest.SetKey(VK_MENU); 167 dest.SetKey(0x56); 168 testState.AddOSLevelShortcut(src, dest); 169 170 std::vector<INPUT> inputs{ 171 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 172 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 173 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 174 }; 175 176 // Send Ctrl+Shift+A keydown 177 mockedInputHandler.SendVirtualInput(inputs); 178 179 // Since Ctrl+Shift+A is not remapped, no remapping should be invoked 180 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 181 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), true); 182 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), true); 183 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 184 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 185 } 186 187 // Test if correct keyboard states are set for a 3 key shortcut remap with different modifiers key down 188 TEST_METHOD (RemappedThreeKeyShortcutWithDiffModifiers_ShouldSetTargetShortcutDown_OnKeyDown) 189 { 190 // Remap Ctrl+Shift+A to Alt+LWin+V 191 Shortcut src; 192 src.SetKey(VK_CONTROL); 193 src.SetKey(VK_SHIFT); 194 src.SetKey(0x41); 195 Shortcut dest; 196 dest.SetKey(VK_MENU); 197 dest.SetKey(VK_LWIN); 198 dest.SetKey(0x56); 199 testState.AddOSLevelShortcut(src, dest); 200 201 std::vector<INPUT> inputs{ 202 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 203 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 204 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 205 }; 206 207 // Send Ctrl+Shift+A keydown 208 mockedInputHandler.SendVirtualInput(inputs); 209 210 // Ctrl, Shift, A key states should be unchanged, Alt, LWin, V key states should be true 211 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 212 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 213 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 214 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), true); 215 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LWIN), true); 216 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true); 217 } 218 219 // Test if correct keyboard states are set for a 3 key shortcut remap with partially different modifiers key down 220 TEST_METHOD (RemappedThreeKeyShortcutWithPartiallyDiffModifiers_ShouldSetTargetShortcutDown_OnKeyDown) 221 { 222 // Remap Ctrl+Shift+A to Alt+Ctrl+V 223 Shortcut src; 224 src.SetKey(VK_CONTROL); 225 src.SetKey(VK_SHIFT); 226 src.SetKey(0x41); 227 Shortcut dest; 228 dest.SetKey(VK_MENU); 229 dest.SetKey(VK_CONTROL); 230 dest.SetKey(0x56); 231 testState.AddOSLevelShortcut(src, dest); 232 233 std::vector<INPUT> inputs{ 234 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 235 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 236 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 237 }; 238 239 // Send Ctrl+Shift+A keydown 240 mockedInputHandler.SendVirtualInput(inputs); 241 242 // Shift, A key states should be unchanged, Alt, Ctrl, V key states should be true 243 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 244 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 245 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), true); 246 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 247 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true); 248 } 249 250 // Test if correct keyboard states are set for a 3 key shortcut remap with same modifiers key down 251 TEST_METHOD (RemappedThreeKeyShortcutWithSameModifiers_ShouldSetTargetShortcutDown_OnKeyDown) 252 { 253 // Remap Ctrl+Shift+A to Ctrl+Shift+V 254 Shortcut src; 255 src.SetKey(VK_CONTROL); 256 src.SetKey(VK_SHIFT); 257 src.SetKey(0x41); 258 Shortcut dest; 259 dest.SetKey(VK_CONTROL); 260 dest.SetKey(VK_SHIFT); 261 dest.SetKey(0x56); 262 testState.AddOSLevelShortcut(src, dest); 263 264 std::vector<INPUT> inputs{ 265 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 266 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 267 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 268 }; 269 270 // Send Ctrl+Shift+A keydown 271 mockedInputHandler.SendVirtualInput(inputs); 272 273 // A key state should be unchanged, Ctrl, Shift, V key states should be true 274 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 275 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 276 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), true); 277 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true); 278 } 279 280 // Test if correct keyboard states are set for a 3 key shortcut remap with different modifiers key down followed by key up 281 TEST_METHOD (RemappedThreeKeyShortcutWithDiffModifiers_ShouldClearKeyboard_OnKeyUp) 282 { 283 // Remap Ctrl+Shift+A to Alt+LWin+V 284 Shortcut src; 285 src.SetKey(VK_CONTROL); 286 src.SetKey(VK_SHIFT); 287 src.SetKey(0x41); 288 Shortcut dest; 289 dest.SetKey(VK_MENU); 290 dest.SetKey(VK_LWIN); 291 dest.SetKey(0x56); 292 testState.AddOSLevelShortcut(src, dest); 293 294 std::vector<INPUT> inputs{ 295 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 296 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 297 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 298 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 299 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT, .dwFlags = KEYEVENTF_KEYUP } }, 300 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 301 }; 302 303 // Send Ctrl+Shift+A keydown, followed by A, Shift and Ctrl released 304 mockedInputHandler.SendVirtualInput(inputs); 305 306 // Ctrl, Shift, A, Alt, LWin, V key states should be false 307 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 308 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 309 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 310 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 311 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LWIN), false); 312 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 313 } 314 315 // Test if correct keyboard states are set for a 3 key shortcut remap with partially different modifiers key down followed by key up 316 TEST_METHOD (RemappedThreeKeyShortcutWithPartiallyDiffModifiers_ShouldClearKeyboard_OnKeyUp) 317 { 318 // Remap Ctrl+Shift+A to Alt+Ctrl+V 319 Shortcut src; 320 src.SetKey(VK_CONTROL); 321 src.SetKey(VK_SHIFT); 322 src.SetKey(0x41); 323 Shortcut dest; 324 dest.SetKey(VK_MENU); 325 dest.SetKey(VK_CONTROL); 326 dest.SetKey(0x56); 327 testState.AddOSLevelShortcut(src, dest); 328 329 std::vector<INPUT> inputs{ 330 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 331 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 332 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 333 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 334 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT, .dwFlags = KEYEVENTF_KEYUP } }, 335 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 336 }; 337 338 // Send Ctrl+Shift+A keydown, followed by A, Shift and Ctrl released 339 mockedInputHandler.SendVirtualInput(inputs); 340 341 // Ctrl, Shift, A, Alt, V key states should be false 342 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 343 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 344 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 345 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 346 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 347 } 348 349 // Test if correct keyboard states are set for a 3 key shortcut remap with same modifiers key down followed by key up 350 TEST_METHOD (RemappedThreeKeyShortcutWithSameModifiers_ShouldClearKeyboard_OnKeyUp) 351 { 352 // Remap Ctrl+Shift+A to Ctrl+Shift+V 353 Shortcut src; 354 src.SetKey(VK_CONTROL); 355 src.SetKey(VK_SHIFT); 356 src.SetKey(0x41); 357 Shortcut dest; 358 dest.SetKey(VK_CONTROL); 359 dest.SetKey(VK_SHIFT); 360 dest.SetKey(0x56); 361 testState.AddOSLevelShortcut(src, dest); 362 363 std::vector<INPUT> inputs{ 364 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 365 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 366 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 367 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 368 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT, .dwFlags = KEYEVENTF_KEYUP } }, 369 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 370 }; 371 372 // Send Ctrl+Shift+A keydown, followed by A, Shift and Ctrl released 373 mockedInputHandler.SendVirtualInput(inputs); 374 375 // Ctrl, Shift, A, V key states should be false 376 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 377 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 378 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 379 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 380 } 381 382 // Test if correct keyboard states are set when a 3 key shortcut is remapped, and a 2 key shortcut which is a subset of those keys is invoked - Ex: Ctrl+Shift+A remapped, but user presses Ctrl+A 383 TEST_METHOD (RemappedThreeKeyShortcutInvokingAShortcutSubsetOfThoseKeys_ShouldNotBeRemapped_OnKeyDown) 384 { 385 // Remap Ctrl+Shift+A to Alt+V 386 Shortcut src; 387 src.SetKey(VK_CONTROL); 388 src.SetKey(VK_SHIFT); 389 src.SetKey(0x41); 390 Shortcut dest; 391 dest.SetKey(VK_MENU); 392 dest.SetKey(0x56); 393 testState.AddOSLevelShortcut(src, dest); 394 395 std::vector<INPUT> inputs{ 396 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 397 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 398 }; 399 400 // Send Ctrl+A keydown 401 mockedInputHandler.SendVirtualInput(inputs); 402 403 // Since Ctrl+A is not remapped, no remapping should be invoked 404 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 405 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), true); 406 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 407 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 408 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 409 } 410 411 // Test if correct keyboard states are set for a 3 key to 2 key shortcut remap with different modifiers key down 412 TEST_METHOD (RemappedThreeKeyToTwoKeyShortcutWithDiffModifiers_ShouldSetTargetShortcutDown_OnKeyDown) 413 { 414 // Remap Ctrl+Shift+A to Alt+V 415 Shortcut src; 416 src.SetKey(VK_CONTROL); 417 src.SetKey(VK_SHIFT); 418 src.SetKey(0x41); 419 Shortcut dest; 420 dest.SetKey(VK_MENU); 421 dest.SetKey(0x56); 422 testState.AddOSLevelShortcut(src, dest); 423 424 std::vector<INPUT> inputs{ 425 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 426 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 427 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 428 }; 429 430 // Send Ctrl+Shift+A keydown 431 mockedInputHandler.SendVirtualInput(inputs); 432 433 // Ctrl, Shift, A key states should be unchanged, Alt, V key states should be true 434 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 435 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 436 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 437 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), true); 438 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true); 439 } 440 441 // Test if correct keyboard states are set for a 3 key to 2 key shortcut remap with partially different modifiers key down 442 TEST_METHOD (RemappedThreeKeyToTwoKeyShortcutWithPartiallyDiffModifiers_ShouldSetTargetShortcutDown_OnKeyDown) 443 { 444 // Remap Ctrl+Shift+A to Ctrl+V 445 Shortcut src; 446 src.SetKey(VK_CONTROL); 447 src.SetKey(VK_SHIFT); 448 src.SetKey(0x41); 449 Shortcut dest; 450 dest.SetKey(VK_CONTROL); 451 dest.SetKey(0x56); 452 testState.AddOSLevelShortcut(src, dest); 453 454 std::vector<INPUT> inputs{ 455 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 456 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 457 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 458 }; 459 460 // Send Ctrl+Shift+A keydown 461 mockedInputHandler.SendVirtualInput(inputs); 462 463 // Shift, A key states should be unchanged, Ctrl, V key states should be true 464 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 465 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 466 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 467 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true); 468 } 469 470 // Test if correct keyboard states are set for a 3 key to 2 key shortcut remap with different modifiers key down followed by key up 471 TEST_METHOD (RemappedThreeKeyToTwoKeyShortcutWithDiffModifiers_ShouldClearKeyboard_OnKeyUp) 472 { 473 // Remap Ctrl+Shift+A to Alt+V 474 Shortcut src; 475 src.SetKey(VK_CONTROL); 476 src.SetKey(VK_SHIFT); 477 src.SetKey(0x41); 478 Shortcut dest; 479 dest.SetKey(VK_MENU); 480 dest.SetKey(0x56); 481 testState.AddOSLevelShortcut(src, dest); 482 483 std::vector<INPUT> inputs{ 484 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 485 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 486 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 487 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 488 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT, .dwFlags = KEYEVENTF_KEYUP } }, 489 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 490 }; 491 492 // Send Ctrl+Shift+A keydown, followed by A, Shift and Ctrl released 493 mockedInputHandler.SendVirtualInput(inputs); 494 495 // Ctrl, Shift, A, Alt, V key states should be false 496 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 497 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 498 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 499 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 500 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 501 } 502 503 // Test if correct keyboard states are set for a 3 key to 2 key shortcut remap with partially different modifiers key down followed by key up 504 TEST_METHOD (RemappedThreeKeyToTwoKeyShortcutWithPartiallyDiffModifiers_ShouldClearKeyboard_OnKeyUp) 505 { 506 // Remap Ctrl+Shift+A to Ctrl+V 507 Shortcut src; 508 src.SetKey(VK_CONTROL); 509 src.SetKey(VK_SHIFT); 510 src.SetKey(0x41); 511 Shortcut dest; 512 dest.SetKey(VK_CONTROL); 513 dest.SetKey(0x56); 514 testState.AddOSLevelShortcut(src, dest); 515 516 std::vector<INPUT> inputs{ 517 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 518 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 519 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 520 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 521 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT, .dwFlags = KEYEVENTF_KEYUP } }, 522 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 523 }; 524 525 // Send Ctrl+Shift+A keydown, followed by A, Shift and Ctrl released 526 mockedInputHandler.SendVirtualInput(inputs); 527 528 // Ctrl, Shift, A, V key states should be false 529 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 530 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 531 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 532 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 533 } 534 535 // Test if correct keyboard states are set for a 2 key to 3 key shortcut remap with different modifiers key down 536 TEST_METHOD (RemappedTwoKeyToThreeKeyShortcutWithDiffModifiers_ShouldSetTargetShortcutDown_OnKeyDown) 537 { 538 // Remap Ctrl+A to Alt+Shift+V 539 Shortcut src; 540 src.SetKey(VK_CONTROL); 541 src.SetKey(0x41); 542 Shortcut dest; 543 dest.SetKey(VK_MENU); 544 dest.SetKey(VK_SHIFT); 545 dest.SetKey(0x56); 546 testState.AddOSLevelShortcut(src, dest); 547 548 std::vector<INPUT> inputs{ 549 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 550 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 551 }; 552 553 // Send Ctrl+A keydown 554 mockedInputHandler.SendVirtualInput(inputs); 555 556 // Ctrl, A key states should be unchanged, Alt, Shift, V key states should be true 557 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 558 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 559 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), true); 560 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), true); 561 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true); 562 } 563 564 // Test if correct keyboard states are set for a 2 key to 3 key shortcut remap with partially different modifiers key down 565 TEST_METHOD (RemappedTwoKeyToThreeKeyShortcutWithPartiallyDiffModifiers_ShouldSetTargetShortcutDown_OnKeyDown) 566 { 567 // Remap Ctrl+A to Ctrl+Shift+V 568 Shortcut src; 569 src.SetKey(VK_CONTROL); 570 src.SetKey(0x41); 571 Shortcut dest; 572 dest.SetKey(VK_CONTROL); 573 dest.SetKey(VK_SHIFT); 574 dest.SetKey(0x56); 575 testState.AddOSLevelShortcut(src, dest); 576 577 std::vector<INPUT> inputs{ 578 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 579 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 580 }; 581 582 // Send Ctrl+A keydown 583 mockedInputHandler.SendVirtualInput(inputs); 584 585 // A key state should be unchanged, Ctrl, Shift, V key states should be true 586 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 587 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 588 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), true); 589 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true); 590 } 591 592 // Test if correct keyboard states are set for a 2 key to 3 key shortcut remap with different modifiers key down followed by key up 593 TEST_METHOD (RemappedTwoKeyToThreeKeyShortcutWithDiffModifiers_ShouldClearKeyboard_OnKeyUp) 594 { 595 // Remap Ctrl+A to Alt+Shift+V 596 Shortcut src; 597 src.SetKey(VK_CONTROL); 598 src.SetKey(0x41); 599 Shortcut dest; 600 dest.SetKey(VK_MENU); 601 dest.SetKey(VK_SHIFT); 602 dest.SetKey(0x56); 603 testState.AddOSLevelShortcut(src, dest); 604 605 std::vector<INPUT> inputs{ 606 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 607 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 608 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 609 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 610 }; 611 612 // Send Ctrl+A keydown and A, Ctrl are then released 613 mockedInputHandler.SendVirtualInput(inputs); 614 615 // Ctrl, A, Alt, Shift, V key states should be unchanged 616 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 617 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 618 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 619 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 620 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 621 } 622 623 // Test if correct keyboard states are set for a 2 key to 3 key shortcut remap with partially different modifiers key down followed by key up 624 TEST_METHOD (RemappedTwoKeyToThreeKeyShortcutWithPartiallyDiffModifiers_ShouldClearKeyboard_OnKeyUp) 625 { 626 // Remap Ctrl+A to Ctrl+Shift+V 627 Shortcut src; 628 src.SetKey(VK_CONTROL); 629 src.SetKey(0x41); 630 Shortcut dest; 631 dest.SetKey(VK_CONTROL); 632 dest.SetKey(VK_SHIFT); 633 dest.SetKey(0x56); 634 testState.AddOSLevelShortcut(src, dest); 635 636 std::vector<INPUT> inputs{ 637 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 638 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 639 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 640 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 641 }; 642 643 // Send Ctrl+A keydown and A, Ctrl are then released 644 mockedInputHandler.SendVirtualInput(inputs); 645 646 // Ctrl, A, Shift, V key states should be unchanged 647 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 648 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 649 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 650 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 651 } 652 653 // Test if correct keyboard states are set if a shortcut remap is pressed and then an unremapped shortcut with the same modifier is pressed - Ex: Ctrl+A is remapped. User invokes Ctrl+A then releases A and presses C (while Ctrl is held), should invoke Ctrl+C 654 TEST_METHOD (InvokingUnremappedShortcutAfterRemappedShortcutWithSameModifier_ShouldSetUnremappedShortcut_OnKeyDown) 655 { 656 // Remap Ctrl+A to Alt+Shift+V 657 Shortcut src; 658 src.SetKey(VK_CONTROL); 659 src.SetKey(0x41); 660 Shortcut dest; 661 dest.SetKey(VK_MENU); 662 dest.SetKey(VK_SHIFT); 663 dest.SetKey(0x56); 664 testState.AddOSLevelShortcut(src, dest); 665 666 std::vector<INPUT> inputs{ 667 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 668 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 669 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 670 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'C' } }, 671 }; 672 673 // Send Ctrl+A keydown, A key up, then C key down 674 mockedInputHandler.SendVirtualInput(inputs); 675 676 // A, Alt, Shift, V key states should be unchanged, Ctrl, C should be true 677 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 678 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 679 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 680 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 681 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 682 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x43), true); 683 } 684 685 // Test if correct keyboard states are set for a shortcut remap with win both modifier 686 TEST_METHOD (RemappedShortcutWithWinBothModifier_ShouldSetRemappedShortcut_OnKeyEvent) 687 { 688 // Remap Win+A to Alt+V 689 Shortcut src; 690 src.SetKey(CommonSharedConstants::VK_WIN_BOTH); 691 src.SetKey(0x41); 692 Shortcut dest; 693 dest.SetKey(VK_MENU); 694 dest.SetKey(0x56); 695 testState.AddOSLevelShortcut(src, dest); 696 697 // Remap Alt+D to Win+B 698 Shortcut dest1; 699 dest1.SetKey(CommonSharedConstants::VK_WIN_BOTH); 700 dest1.SetKey(0x42); 701 Shortcut src1; 702 src1.SetKey(VK_MENU); 703 src1.SetKey(0x44); 704 testState.AddOSLevelShortcut(src1, dest1); 705 706 // Test 2 cases for first remap - LWin, A, A(Up), LWin(Up). RWin, A, A(Up), RWin(Up) 707 std::vector<INPUT> inputs1{ 708 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_LWIN } }, 709 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 710 }; 711 712 // Send LWin+A keydown 713 mockedInputHandler.SendVirtualInput(inputs1); 714 715 // LWin, RWin, A key states should be unchanged, Alt, V should be true 716 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LWIN), false); 717 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_RWIN), false); 718 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 719 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), true); 720 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true); 721 722 std::vector<INPUT> inputs2{ 723 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 724 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_LWIN, .dwFlags = KEYEVENTF_KEYUP } }, 725 }; 726 727 // Release LWin+A 728 mockedInputHandler.SendVirtualInput(inputs2); 729 730 // LWin, RWin, A, Alt, V key states should be unchanged 731 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LWIN), false); 732 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_RWIN), false); 733 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 734 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 735 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 736 737 // Case 1.2 738 std::vector<INPUT> inputs3{ 739 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_RWIN } }, 740 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 741 }; 742 743 // Send RWin+A keydown 744 mockedInputHandler.SendVirtualInput(inputs3); 745 746 // LWin, RWin, A key states should be unchanged, Alt, V should be true 747 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LWIN), false); 748 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_RWIN), false); 749 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 750 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), true); 751 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true); 752 753 std::vector<INPUT> inputs4{ 754 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 755 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_RWIN, .dwFlags = KEYEVENTF_KEYUP } }, 756 }; 757 758 // Release RWin+A 759 mockedInputHandler.SendVirtualInput(inputs4); 760 761 // LWin, RWin, A, Alt, V key states should be unchanged 762 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LWIN), false); 763 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_RWIN), false); 764 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 765 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 766 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 767 768 // Case 2 769 std::vector<INPUT> inputs5{ 770 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_MENU } }, 771 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'D' } }, 772 }; 773 774 // Send Alt+D keydown 775 mockedInputHandler.SendVirtualInput(inputs5); 776 777 // Alt, D, RWin key states should be unchanged, LWin, B should be true 778 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LWIN), true); 779 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_RWIN), false); 780 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x42), true); 781 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 782 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x44), false); 783 784 std::vector<INPUT> inputs6{ 785 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'D', .dwFlags = KEYEVENTF_KEYUP } }, 786 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_MENU, .dwFlags = KEYEVENTF_KEYUP } }, 787 }; 788 789 // Release Alt+D 790 mockedInputHandler.SendVirtualInput(inputs6); 791 792 // LWin, RWin, B, Alt, D key states should be unchanged 793 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LWIN), false); 794 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_RWIN), false); 795 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x42), false); 796 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 797 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x44), false); 798 } 799 800 // Test if correct keyboard states are set if a win both shortcut remap is pressed and then an unremapped shortcut with the LWin modifier is pressed 801 TEST_METHOD (InvokingUnremappedShortcutWithLWinAfterRemappedShortcutWithWinBothModifier_ShouldSetUnremappedShortcutWithLWinKey_OnKeyDown) 802 { 803 // Remap Win+A to Alt+V 804 Shortcut src; 805 src.SetKey(CommonSharedConstants::VK_WIN_BOTH); 806 src.SetKey(0x41); 807 Shortcut dest; 808 dest.SetKey(VK_MENU); 809 dest.SetKey(0x56); 810 testState.AddOSLevelShortcut(src, dest); 811 812 // LWin, A, A(Up), C(Down) 813 std::vector<INPUT> inputs{ 814 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_LWIN } }, 815 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 816 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 817 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'C' } }, 818 }; 819 820 // Send LWin+A, release A and press C 821 mockedInputHandler.SendVirtualInput(inputs); 822 823 // RWin, A, Alt, V key states should be unchanged, LWin, C should be true 824 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LWIN), true); 825 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x43), true); 826 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_RWIN), false); 827 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 828 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 829 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 830 } 831 832 // Test if correct keyboard states are set if a win both shortcut remap is pressed and then an unremapped shortcut with the RWin modifier is pressed 833 TEST_METHOD (InvokingUnremappedShortcutWithRWinAfterRemappedShortcutWithWinBothModifier_ShouldSetUnremappedShortcutWithRWinKey_OnKeyDown) 834 { 835 // Remap Win+A to Alt+V 836 Shortcut src; 837 src.SetKey(CommonSharedConstants::VK_WIN_BOTH); 838 src.SetKey(0x41); 839 Shortcut dest; 840 dest.SetKey(VK_MENU); 841 dest.SetKey(0x56); 842 testState.AddOSLevelShortcut(src, dest); 843 844 // RWin, A, A(Up), C(Down) 845 std::vector<INPUT> inputs{ 846 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_RWIN } }, 847 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 848 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 849 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'C' } }, 850 }; 851 852 // Send RWin+A, release A and press C 853 mockedInputHandler.SendVirtualInput(inputs); 854 855 // LWin, A, Alt, V key states should be unchanged, RWin, C should be true 856 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LWIN), false); 857 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_RWIN), true); 858 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x43), true); 859 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 860 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 861 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 862 } 863 864 // Test if target modifier is still held down even if the action key of the original shortcut is released - required for Alt+Tab/Win+Space cases 865 TEST_METHOD (RemappedShortcutModifiers_ShouldBeDetectedAsPressed_OnReleasingActionKeyButHoldingModifiers) 866 { 867 // Remap Ctrl+A to Alt+Tab 868 Shortcut src; 869 src.SetKey(VK_CONTROL); 870 src.SetKey(0x41); 871 Shortcut dest; 872 dest.SetKey(VK_MENU); 873 dest.SetKey(VK_TAB); 874 testState.AddOSLevelShortcut(src, dest); 875 876 std::vector<INPUT> inputs{ 877 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 878 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 879 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 880 }; 881 882 // Send Ctrl+A, release A 883 mockedInputHandler.SendVirtualInput(inputs); 884 885 // Ctrl, A, Tab key states should be unchanged, Alt should be true 886 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 887 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 888 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), true); 889 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_TAB), false); 890 } 891 892 // Test if invoking two remapped shortcuts (with different modifiers between original and new shortcut) that share modifiers in succession sets the correct keyboard states 893 TEST_METHOD (TwoRemappedShortcutsWithDifferentModifiersThatShareModifiers_ShouldSetRemappedKeyStates_OnPressingSecondShortcutActionKeyAfterInvokingFirstShortcutRemap) 894 { 895 // Remap Alt+A to Ctrl+C 896 Shortcut src; 897 src.SetKey(VK_MENU); 898 src.SetKey(0x41); 899 Shortcut dest; 900 dest.SetKey(VK_CONTROL); 901 dest.SetKey(0x43); 902 testState.AddOSLevelShortcut(src, dest); 903 904 // Remap Alt+V to Ctrl+X 905 Shortcut src1; 906 src1.SetKey(VK_MENU); 907 src1.SetKey(0x56); 908 Shortcut dest1; 909 dest1.SetKey(VK_CONTROL); 910 dest1.SetKey(0x58); 911 testState.AddOSLevelShortcut(src1, dest1); 912 913 std::vector<INPUT> inputs{ 914 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_MENU } }, 915 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 916 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 917 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'V' } }, 918 }; 919 920 // Send Alt+A, release A, press V 921 mockedInputHandler.SendVirtualInput(inputs); 922 923 // Alt, A, C, V key states should be unchanged, Ctrl, X should be true 924 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 925 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 926 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x43), false); 927 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 928 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 929 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x58), true); 930 } 931 932 // Test if invoking two remapped shortcuts (with same modifiers between original and new shortcut) that share modifiers in succession sets the correct keyboard states 933 TEST_METHOD (TwoRemappedShortcutsWithSameModifiersThatShareModifiers_ShouldSetRemappedKeyStates_OnPressingSecondShortcutActionKeyAfterInvokingFirstShortcutRemap) 934 { 935 // Remap Ctrl+A to Ctrl+C 936 Shortcut src; 937 src.SetKey(VK_CONTROL); 938 src.SetKey(0x41); 939 Shortcut dest; 940 dest.SetKey(VK_CONTROL); 941 dest.SetKey(0x43); 942 testState.AddOSLevelShortcut(src, dest); 943 944 // Remap Ctrl+V to Ctrl+X 945 Shortcut src1; 946 src1.SetKey(VK_CONTROL); 947 src1.SetKey(0x56); 948 Shortcut dest1; 949 dest1.SetKey(VK_CONTROL); 950 dest1.SetKey(0x58); 951 testState.AddOSLevelShortcut(src1, dest1); 952 953 std::vector<INPUT> inputs{ 954 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 955 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 956 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 957 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'V' } }, 958 }; 959 960 // Send Ctrl+A, release A, press V 961 mockedInputHandler.SendVirtualInput(inputs); 962 963 // A, C, V key states should be unchanged, Ctrl, X should be true 964 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 965 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x43), false); 966 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 967 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 968 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x58), true); 969 } 970 971 // Tests for shortcut to key remappings 972 973 // Test if correct keyboard states are set for a 2 key shortcut to a single key remap not containing that key on key down followed by key up 974 TEST_METHOD (RemappedTwoKeyShortcutToSingleKeyNotContainingThatKey_ShouldSetCorrectKeyStates_OnKeyEvents) 975 { 976 // Remap Ctrl+A to Alt 977 Shortcut src; 978 src.SetKey(VK_CONTROL); 979 src.SetKey(0x41); 980 testState.AddOSLevelShortcut(src, (DWORD)VK_MENU); 981 982 std::vector<INPUT> inputs1{ 983 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 984 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 985 }; 986 987 // Send Ctrl+A keydown 988 mockedInputHandler.SendVirtualInput(inputs1); 989 990 // Ctrl, A should be false, Alt should be true 991 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 992 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 993 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), true); 994 995 std::vector<INPUT> inputs2{ 996 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 997 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 998 }; 999 1000 // Release Ctrl+A 1001 mockedInputHandler.SendVirtualInput(inputs2); 1002 1003 // Ctrl, A, Alt should be false 1004 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1005 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1006 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 1007 } 1008 1009 // Test if correct keyboard states are set for a 3 key shortcut to a single key remap not containing that key on key down followed by key up 1010 TEST_METHOD (RemappedThreeKeyShortcutToSingleKeyNotContainingThatKey_ShouldSetCorrectKeyStates_OnKeyEvents) 1011 { 1012 // Remap Ctrl+Shift+A to Alt 1013 Shortcut src; 1014 src.SetKey(VK_CONTROL); 1015 src.SetKey(VK_SHIFT); 1016 src.SetKey(0x41); 1017 testState.AddOSLevelShortcut(src, (DWORD)VK_MENU); 1018 1019 std::vector<INPUT> inputs1{ 1020 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1021 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 1022 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1023 }; 1024 1025 // Send Ctrl+Shift+A keydown 1026 mockedInputHandler.SendVirtualInput(inputs1); 1027 1028 // Ctrl, Shift, A should be false, Alt should be true 1029 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1030 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 1031 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1032 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), true); 1033 1034 std::vector<INPUT> inputs2{ 1035 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 1036 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT, .dwFlags = KEYEVENTF_KEYUP } }, 1037 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 1038 }; 1039 1040 // Release Ctrl+Shift+A 1041 mockedInputHandler.SendVirtualInput(inputs2); 1042 1043 // Ctrl, Shift, A, Alt should be false 1044 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1045 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 1046 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1047 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 1048 } 1049 1050 // Test if correct keyboard states are set for a 2 key shortcut to a single key remap containing that key on key down followed by key up 1051 TEST_METHOD (RemappedTwoKeyShortcutToSingleKeyContainingThatKey_ShouldSetCorrectKeyStates_OnKeyEvents) 1052 { 1053 // Remap Ctrl+A to Ctrl 1054 Shortcut src; 1055 src.SetKey(VK_CONTROL); 1056 src.SetKey(0x41); 1057 testState.AddOSLevelShortcut(src, (DWORD)VK_CONTROL); 1058 1059 std::vector<INPUT> inputs1{ 1060 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1061 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1062 }; 1063 1064 // Send Ctrl+A keydown 1065 mockedInputHandler.SendVirtualInput(inputs1); 1066 1067 // A should be false, Ctrl should be true 1068 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 1069 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1070 1071 std::vector<INPUT> inputs2{ 1072 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 1073 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 1074 }; 1075 1076 // Release Ctrl+A 1077 mockedInputHandler.SendVirtualInput(inputs2); 1078 1079 // Ctrl, A should be false 1080 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1081 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1082 } 1083 1084 // Test if correct keyboard states are set for a 3 key shortcut to a single key remap containing that key on key down followed by key up 1085 TEST_METHOD (RemappedThreeKeyShortcutToSingleKeyContainingThatKey_ShouldSetCorrectKeyStates_OnKeyEvents) 1086 { 1087 // Remap Ctrl+Shift+A to Ctrl 1088 Shortcut src; 1089 src.SetKey(VK_CONTROL); 1090 src.SetKey(VK_SHIFT); 1091 src.SetKey(0x41); 1092 testState.AddOSLevelShortcut(src, (DWORD)VK_CONTROL); 1093 1094 std::vector<INPUT> inputs1{ 1095 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1096 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 1097 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1098 }; 1099 1100 // Send Ctrl+Shift+A keydown 1101 mockedInputHandler.SendVirtualInput(inputs1); 1102 1103 // Shift, A should be false, Ctrl should be true 1104 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 1105 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 1106 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1107 1108 std::vector<INPUT> inputs2{ 1109 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 1110 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT, .dwFlags = KEYEVENTF_KEYUP } }, 1111 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 1112 }; 1113 1114 // Release Ctrl+Shift+A 1115 mockedInputHandler.SendVirtualInput(inputs2); 1116 1117 // Ctrl, Shift, A should be false 1118 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1119 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 1120 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1121 } 1122 1123 // Test if keyboard state is not reverted for a shortcut to a single key remap (target key is not a part of the shortcut) on key down followed by releasing the action key 1124 TEST_METHOD (RemappedShortcutToSingleKeyWhereKeyIsNotInShortcut_ShouldNotSetOriginalModifier_OnReleasingActionKey) 1125 { 1126 // Remap Ctrl+A to Alt 1127 Shortcut src; 1128 src.SetKey(VK_CONTROL); 1129 src.SetKey(0x41); 1130 testState.AddOSLevelShortcut(src, (DWORD)VK_MENU); 1131 1132 std::vector<INPUT> inputs{ 1133 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1134 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1135 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 1136 }; 1137 1138 // Press Ctrl+A, release A 1139 mockedInputHandler.SendVirtualInput(inputs); 1140 1141 // Ctrl, A, Alt should be false 1142 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1143 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1144 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 1145 // Shortcut invoked state should be true 1146 Assert::AreEqual(true, testState.osLevelShortcutReMap[src].isShortcutInvoked); 1147 } 1148 1149 // Test if keyboard state is not reverted for a shortcut to a single key remap (target key is a modifier in the shortcut) on key down followed by releasing the action key 1150 TEST_METHOD (RemappedShortcutToSingleKeyWhereKeyIsAModifierInShortcut_ShouldNotSetOriginalModifier_OnReleasingActionKey) 1151 { 1152 // Remap Ctrl+A to Ctrl 1153 Shortcut src; 1154 src.SetKey(VK_CONTROL); 1155 src.SetKey(0x41); 1156 testState.AddOSLevelShortcut(src, (DWORD)VK_CONTROL); 1157 1158 std::vector<INPUT> inputs{ 1159 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1160 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1161 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 1162 }; 1163 1164 // Press Ctrl+A, release A 1165 mockedInputHandler.SendVirtualInput(inputs); 1166 1167 // Both A and Ctrl should be false 1168 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1169 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1170 // Shortcut invoked state should be true 1171 Assert::AreEqual(true, testState.osLevelShortcutReMap[src].isShortcutInvoked); 1172 } 1173 1174 // Test if keyboard state is not reverted for a shortcut to a single key remap (target key is the action key in the shortcut) on key down followed by releasing the action key 1175 TEST_METHOD (RemappedShortcutToSingleKeyWhereKeyIsActionKeyInShortcut_ShouldNotSetOriginalModifier_OnReleasingActionKey) 1176 { 1177 // Remap Ctrl+A to A 1178 Shortcut src; 1179 src.SetKey(VK_CONTROL); 1180 src.SetKey(0x41); 1181 testState.AddOSLevelShortcut(src, (DWORD)0x41); 1182 1183 std::vector<INPUT> inputs{ 1184 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1185 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1186 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 1187 }; 1188 1189 // Press Ctrl+A, release A 1190 mockedInputHandler.SendVirtualInput(inputs); 1191 1192 // Ctrl, A should be false 1193 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1194 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1195 // Shortcut invoked state should be true 1196 Assert::AreEqual(true, testState.osLevelShortcutReMap[src].isShortcutInvoked); 1197 } 1198 1199 // Test if keyboard state is reverted for a shortcut to a single key remap (target key is not a part of the shortcut) on key down followed by releasing the modifier key 1200 TEST_METHOD (RemappedShortcutToSingleKeyWhereKeyIsNotInShortcut_ShouldSetOriginalModifier_OnReleasingModifierKey) 1201 { 1202 // Remap Ctrl+A to Alt 1203 Shortcut src; 1204 src.SetKey(VK_CONTROL); 1205 src.SetKey(0x41); 1206 testState.AddOSLevelShortcut(src, (DWORD)VK_MENU); 1207 1208 std::vector<INPUT> inputs{ 1209 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1210 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1211 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 1212 }; 1213 1214 // Press Ctrl+A, release Ctrl 1215 mockedInputHandler.SendVirtualInput(inputs); 1216 1217 // A, Alt, Ctrl should be false 1218 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1219 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1220 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 1221 // Shortcut invoked state should be false 1222 Assert::AreEqual(false, testState.osLevelShortcutReMap[src].isShortcutInvoked); 1223 } 1224 1225 // Test if keyboard state is reverted for a shortcut to a single key remap (target key is a modifier in the shortcut) on key down followed by releasing the modifier key 1226 TEST_METHOD (RemappedShortcutToSingleKeyWhereKeyIsAModifierInShortcut_ShouldSetOriginalModifier_OnReleasingModifierKey) 1227 { 1228 // Remap Ctrl+A to Ctrl 1229 Shortcut src; 1230 src.SetKey(VK_CONTROL); 1231 src.SetKey(0x41); 1232 testState.AddOSLevelShortcut(src, (DWORD)VK_CONTROL); 1233 1234 std::vector<INPUT> inputs{ 1235 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1236 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1237 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 1238 }; 1239 1240 // Press Ctrl+A, release Ctrl 1241 mockedInputHandler.SendVirtualInput(inputs); 1242 1243 // A, Ctrl should be false 1244 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1245 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1246 // Shortcut invoked state should be false 1247 Assert::AreEqual(false, testState.osLevelShortcutReMap[src].isShortcutInvoked); 1248 } 1249 1250 // Test if keyboard state is reverted for a shortcut to a single key remap (target key is the action key in the shortcut) on key down followed by releasing the modifier key 1251 TEST_METHOD (RemappedShortcutToSingleKeyWhereKeyIsActionKeyInShortcut_ShouldSetOriginalModifier_ModifierKey) 1252 { 1253 // Remap Ctrl+A to A 1254 Shortcut src; 1255 src.SetKey(VK_CONTROL); 1256 src.SetKey(0x41); 1257 testState.AddOSLevelShortcut(src, (DWORD)0x41); 1258 1259 std::vector<INPUT> inputs{ 1260 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1261 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1262 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 1263 }; 1264 1265 // Press Ctrl+A, release Ctrl 1266 mockedInputHandler.SendVirtualInput(inputs); 1267 1268 // A, Ctrl should be false 1269 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1270 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1271 } 1272 1273 // Test if remap is invoked for a shortcut to a single key remap when the shortcut is invoked along with other keys pressed before it 1274 TEST_METHOD (RemappedShortcutToSingleKey_ShouldBeInvoked_IfOtherKeysArePressedAlongWithIt) 1275 { 1276 // Remap Ctrl+A to Alt 1277 Shortcut src; 1278 src.SetKey(VK_CONTROL); 1279 src.SetKey(0x41); 1280 testState.AddOSLevelShortcut(src, (DWORD)VK_MENU); 1281 1282 std::vector<INPUT> inputs{ 1283 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'B' } }, 1284 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1285 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1286 }; 1287 1288 // Press B+Ctrl+A 1289 mockedInputHandler.SendVirtualInput(inputs); 1290 1291 // A, Ctrl should be false, B, Alt should be true 1292 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1293 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1294 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), true); 1295 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x42), true); 1296 } 1297 1298 // Test if remap is invoked for a shortcut to a single key remap and the keyboard state is reverted back to the physical keys when the shortcut is invoked along with other keys pressed before it and the action key is released 1299 TEST_METHOD (RemappedShortcutToSingleKey_ShouldRevertBackToPhysicalKeys_IfOtherKeysArePressedAlongWithItAndThenActionKeyIsReleased) 1300 { 1301 // Remap Ctrl+A to Alt 1302 Shortcut src; 1303 src.SetKey(VK_CONTROL); 1304 src.SetKey(0x41); 1305 testState.AddOSLevelShortcut(src, (DWORD)VK_MENU); 1306 1307 std::vector<INPUT> inputs{ 1308 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'B' } }, 1309 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1310 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1311 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 1312 }; 1313 1314 // Press B+Ctrl+A, release A 1315 mockedInputHandler.SendVirtualInput(inputs); 1316 1317 // Alt, A should be false, Ctrl, B should be true 1318 Assert::AreEqual(true, mockedInputHandler.GetVirtualKeyState(VK_CONTROL)); 1319 Assert::AreEqual(false, mockedInputHandler.GetVirtualKeyState(0x41)); 1320 Assert::AreEqual(false, mockedInputHandler.GetVirtualKeyState(VK_MENU)); 1321 Assert::AreEqual(true, mockedInputHandler.GetVirtualKeyState(0x42)); 1322 // Shortcut invoked state should be false 1323 Assert::AreEqual(false, testState.osLevelShortcutReMap[src].isShortcutInvoked); 1324 } 1325 1326 // Test that remap is not invoked for a shortcut to a single key remap when a larger remapped shortcut to shortcut containing those shortcut keys is invoked 1327 TEST_METHOD (RemappedShortcutToSingleKey_ShouldNotBeInvoked_IfALargerRemappedShortcutToShortcutContainingThoseShortcutKeysIsInvoked) 1328 { 1329 // Remap Ctrl+A to Alt 1330 Shortcut src; 1331 src.SetKey(VK_CONTROL); 1332 src.SetKey(0x41); 1333 testState.AddOSLevelShortcut(src, (DWORD)VK_MENU); 1334 // Remap Shift+Ctrl+A to Ctrl+V 1335 src.SetKey(VK_SHIFT); 1336 Shortcut dest; 1337 dest.SetKey(VK_CONTROL); 1338 dest.SetKey(0x56); 1339 testState.AddOSLevelShortcut(src, dest); 1340 1341 std::vector<INPUT> inputs{ 1342 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 1343 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1344 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1345 }; 1346 1347 // Press Shift+Ctrl+A 1348 mockedInputHandler.SendVirtualInput(inputs); 1349 1350 // Alt, A, Shift should be false, Ctrl, V should be true 1351 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 1352 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 1353 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1354 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 1355 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true); 1356 } 1357 1358 // Test that remap is not invoked for a shortcut to a single key remap when a larger remapped shortcut to key containing those shortcut keys is invoked 1359 TEST_METHOD (RemappedShortcutToSingleKey_ShouldNotBeInvoked_IfALargerRemappedShortcutToKeyContainingThoseShortcutKeysIsInvoked) 1360 { 1361 // Remap Ctrl+A to Alt 1362 Shortcut src; 1363 src.SetKey(VK_CONTROL); 1364 src.SetKey(0x41); 1365 testState.AddOSLevelShortcut(src, (DWORD)VK_MENU); 1366 // Remap Shift+Ctrl+A to B 1367 src.SetKey(VK_SHIFT); 1368 testState.AddOSLevelShortcut(src, (DWORD)0x42); 1369 1370 std::vector<INPUT> inputs{ 1371 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 1372 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1373 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1374 }; 1375 1376 // Press Shift+Ctrl+A 1377 mockedInputHandler.SendVirtualInput(inputs); 1378 1379 // Alt, Ctrl, A, Shift should be false, B should be true 1380 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1381 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), false); 1382 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1383 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 1384 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x42), true); 1385 } 1386 1387 // Test if remap is invoked and then reverted to physical keys for a shortcut to a single key remap when the shortcut is invoked along with other keys pressed after it and then action key is released 1388 TEST_METHOD (RemappedShortcutToSingleKey_ShouldBeInvokedAndThenRevertToPhysicalKeys_IfOtherKeysArePressedAfterItAndActionKeyIsReleased) 1389 { 1390 // Remap Ctrl+A to Alt 1391 Shortcut src; 1392 src.SetKey(VK_CONTROL); 1393 src.SetKey(0x41); 1394 testState.AddOSLevelShortcut(src, (DWORD)VK_MENU); 1395 1396 std::vector<INPUT> inputs1{ 1397 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1398 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1399 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'B' } }, 1400 }; 1401 1402 // Press Ctrl+A+B 1403 mockedInputHandler.SendVirtualInput(inputs1); 1404 1405 // A, Ctrl should be false, B, Alt should be true 1406 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1407 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1408 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), true); 1409 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x42), true); 1410 // Shortcut invoked state should be true 1411 Assert::AreEqual(true, testState.osLevelShortcutReMap[src].isShortcutInvoked); 1412 1413 std::vector<INPUT> inputs2{ 1414 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 1415 }; 1416 1417 // Release A 1418 mockedInputHandler.SendVirtualInput(inputs2); 1419 1420 // A, Alt should be false, Ctrl, B should be true 1421 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 1422 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1423 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 1424 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x42), true); 1425 // Shortcut invoked state should be false 1426 Assert::AreEqual(false, testState.osLevelShortcutReMap[src].isShortcutInvoked); 1427 } 1428 1429 // Test if remap is invoked and then reverted to physical keys for a shortcut to a single key remap when the shortcut is invoked along with other keys pressed after it and modifier key is released 1430 TEST_METHOD (RemappedShortcutToSingleKey_ShouldBeInvokedAndThenRevertToPhysicalKeys_IfOtherKeysArePressedAfterItAndModifierKeyIsReleased) 1431 { 1432 // Remap Ctrl+A to Alt 1433 Shortcut src; 1434 src.SetKey(VK_CONTROL); 1435 src.SetKey(0x41); 1436 testState.AddOSLevelShortcut(src, (DWORD)VK_MENU); 1437 std::vector<INPUT> inputs1{ 1438 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1439 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1440 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'B' } }, 1441 }; 1442 1443 // Press Ctrl+A+B 1444 mockedInputHandler.SendVirtualInput(inputs1); 1445 1446 // A, Ctrl should be false, B, Alt should be true 1447 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1448 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1449 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), true); 1450 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x42), true); 1451 // Shortcut invoked state should be true 1452 Assert::AreEqual(true, testState.osLevelShortcutReMap[src].isShortcutInvoked); 1453 1454 std::vector<INPUT> inputs2{ 1455 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 1456 }; 1457 1458 // Release Ctrl 1459 mockedInputHandler.SendVirtualInput(inputs2); 1460 1461 // Ctrl, Alt, A should be false, B should be true 1462 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1463 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1464 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 1465 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x42), true); 1466 // Shortcut invoked state should be false 1467 Assert::AreEqual(false, testState.osLevelShortcutReMap[src].isShortcutInvoked); 1468 } 1469 1470 // Test if remap is invoked and then reverted to physical keys for a shortcut to a single key remap when the shortcut is invoked and action key is released and then other keys pressed after it 1471 TEST_METHOD (RemappedShortcutToSingleKey_ShouldBeInvokedAndThenRevertToPhysicalKeys_IfActionKeyIsReleasedAndThenOtherKeysArePressedAfterIt) 1472 { 1473 // Remap Ctrl+A to Alt 1474 Shortcut src; 1475 src.SetKey(VK_CONTROL); 1476 src.SetKey(0x41); 1477 testState.AddOSLevelShortcut(src, (DWORD)VK_MENU); 1478 1479 std::vector<INPUT> inputs1{ 1480 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1481 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1482 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 1483 }; 1484 1485 // Press Ctrl+A, release A 1486 mockedInputHandler.SendVirtualInput(inputs1); 1487 1488 // A, Ctrl, Alt should be false 1489 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1490 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1491 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 1492 // Shortcut invoked state should be true 1493 Assert::AreEqual(true, testState.osLevelShortcutReMap[src].isShortcutInvoked); 1494 1495 std::vector<INPUT> inputs2{ 1496 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'B' } }, 1497 }; 1498 1499 // Press B 1500 mockedInputHandler.SendVirtualInput(inputs2); 1501 1502 // A, Alt should be false, Ctrl, B should be true 1503 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 1504 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1505 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 1506 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x42), true); 1507 // Shortcut invoked state should be false 1508 Assert::AreEqual(false, testState.osLevelShortcutReMap[src].isShortcutInvoked); 1509 } 1510 1511 // Test if Windows left key state is set when a shortcut remap to Win both is invoked 1512 TEST_METHOD (RemappedShortcutToWinBoth_ShouldSetLWinKeyState_OnKeyEvent) 1513 { 1514 // Remap Ctrl+A to Win both 1515 Shortcut src; 1516 src.SetKey(VK_CONTROL); 1517 src.SetKey(0x41); 1518 testState.AddOSLevelShortcut(src, (DWORD)CommonSharedConstants::VK_WIN_BOTH); 1519 1520 std::vector<INPUT> inputs1{ 1521 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1522 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1523 }; 1524 1525 // Press Ctrl+A 1526 mockedInputHandler.SendVirtualInput(inputs1); 1527 1528 // A, Ctrl should be false, LWin should be true 1529 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1530 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1531 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LWIN), true); 1532 1533 std::vector<INPUT> inputs2{ 1534 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 1535 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 1536 }; 1537 1538 // Release A, Ctrl 1539 mockedInputHandler.SendVirtualInput(inputs2); 1540 1541 // Ctrl, A, LWin should be false 1542 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1543 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1544 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 1545 } 1546 1547 // Tests for interaction between shortcut to shortcut and shortcut to key remappings 1548 1549 // Test if invoking two remapped shortcuts that share modifiers, where the first one remaps to a key and the second one remaps to a shortcut, in succession sets the correct keyboard states 1550 TEST_METHOD (TwoRemappedShortcutsThatShareModifiersWhereFirstOneRemapsToAKeyAndSecondOneRemapsToAShortcut_ShouldSetRemappedKeyStates_OnPressingSecondShortcutActionKeyAfterInvokingFirstShortcutRemap) 1551 { 1552 // Remap Alt+A to D 1553 Shortcut src; 1554 src.SetKey(VK_MENU); 1555 src.SetKey(0x41); 1556 testState.AddOSLevelShortcut(src, (DWORD)0x44); 1557 1558 // Remap Alt+V to Ctrl+X 1559 Shortcut src1; 1560 src1.SetKey(VK_MENU); 1561 src1.SetKey(0x56); 1562 Shortcut dest1; 1563 dest1.SetKey(VK_CONTROL); 1564 dest1.SetKey(0x58); 1565 testState.AddOSLevelShortcut(src1, dest1); 1566 1567 std::vector<INPUT> inputs{ 1568 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_MENU } }, 1569 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1570 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 1571 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'V' } }, 1572 }; 1573 1574 // Send Alt+A, release A, press V 1575 mockedInputHandler.SendVirtualInput(inputs); 1576 1577 // Alt, A, D, V key states should be unchanged, Ctrl, X should be true 1578 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 1579 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1580 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x44), false); 1581 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 1582 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 1583 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x58), true); 1584 } 1585 1586 // Test if invoking two remapped shortcuts that share modifiers, where the first one remaps to a key and the second one remaps to a key, in succession sets the correct keyboard states 1587 TEST_METHOD (TwoRemappedShortcutsThatShareModifiersWhereFirstOneRemapsToAKeyAndSecondOneRemapsToAKey_ShouldSetRemappedKeyStates_OnPressingSecondShortcutActionKeyAfterInvokingFirstShortcutRemap) 1588 { 1589 // Remap Alt+A to D 1590 Shortcut src; 1591 src.SetKey(VK_MENU); 1592 src.SetKey(0x41); 1593 testState.AddOSLevelShortcut(src, (DWORD)0x44); 1594 1595 // Remap Alt+V to X 1596 Shortcut src1; 1597 src1.SetKey(VK_MENU); 1598 src1.SetKey(0x56); 1599 testState.AddOSLevelShortcut(src1, (DWORD)0x58); 1600 1601 std::vector<INPUT> inputs{ 1602 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_MENU } }, 1603 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1604 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 1605 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'V' } }, 1606 }; 1607 1608 // Send Alt+A, release A, press V 1609 mockedInputHandler.SendVirtualInput(inputs); 1610 1611 // Alt, A, D, V key states should be unchanged, X should be true 1612 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 1613 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1614 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x44), false); 1615 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 1616 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x58), true); 1617 } 1618 1619 // Test if invoking two remapped shortcuts that share modifiers, where the first one remaps to a shortcut and the second one remaps to a key, in succession sets the correct keyboard states 1620 TEST_METHOD (TwoRemappedShortcutsThatShareModifiersWhereFirstOneRemapsToAShortcutAndSecondOneRemapsToAKey_ShouldSetRemappedKeyStates_OnPressingSecondShortcutActionKeyAfterInvokingFirstShortcutRemap) 1621 { 1622 // Remap Alt+A to Ctrl+C 1623 Shortcut src; 1624 src.SetKey(VK_MENU); 1625 src.SetKey(0x41); 1626 Shortcut dest; 1627 dest.SetKey(VK_CONTROL); 1628 dest.SetKey(0x43); 1629 testState.AddOSLevelShortcut(src, dest); 1630 1631 // Remap Alt+V to X 1632 Shortcut src1; 1633 src1.SetKey(VK_MENU); 1634 src1.SetKey(0x56); 1635 testState.AddOSLevelShortcut(src1, (DWORD)0x58); 1636 1637 std::vector<INPUT> inputs{ 1638 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_MENU } }, 1639 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1640 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 1641 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'V' } }, 1642 }; 1643 1644 // Send Alt+A, release A, press V 1645 mockedInputHandler.SendVirtualInput(inputs); 1646 1647 // Alt, A, C, V, Ctrl key states should be unchanged, X should be true 1648 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_MENU), false); 1649 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1650 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x44), false); 1651 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 1652 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1653 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x58), true); 1654 } 1655 1656 // Test if correct keyboard states are set if a shortcut to single key remap is pressed and then an unremapped shortcut with the same modifier is pressed - Ex: Ctrl+A is remapped. User invokes Ctrl+A then releases A and presses C (while Ctrl is held), should invoke Ctrl+C 1657 TEST_METHOD (InvokingUnremappedShortcutAfterRemappedShortcutToSingleKeyWithSameModifier_ShouldSetUnremappedShortcut_OnKeyDown) 1658 { 1659 // Remap Ctrl+A to V 1660 Shortcut src; 1661 src.SetKey(VK_CONTROL); 1662 src.SetKey(0x41); 1663 testState.AddOSLevelShortcut(src, (DWORD)0x56); 1664 1665 std::vector<INPUT> inputs{ 1666 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1667 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1668 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 1669 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'C' } }, 1670 }; 1671 1672 // Send Ctrl+A keydown, A key up, then C key down 1673 mockedInputHandler.SendVirtualInput(inputs); 1674 1675 // A, V key states should be unchanged, Ctrl, C should be true 1676 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 1677 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1678 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false); 1679 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x43), true); 1680 } 1681 1682 // Tests for IME Caps Lock workaround on shortcut remappings 1683 1684 // Test if SendVirtualInput is sent exactly once with the suppress flag when Win+CapsLock is remapped to shortcut containing Ctrl 1685 TEST_METHOD (HandleShortcutRemapEvent_ShouldSendVirtualInputWithSuppressFlagExactlyOnce_WhenWinCapsLockIsMappedToShortcutContainingCtrl) 1686 { 1687 // Set sendvirtualinput call count condition to return true if the key event was sent with the suppress flag 1688 mockedInputHandler.SetSendVirtualInputTestHandler([](LowlevelKeyboardEvent* data) { 1689 if (data->lParam->dwExtraInfo == KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG) 1690 return true; 1691 else 1692 return false; 1693 }); 1694 1695 // Remap Win+CapsLock to Ctrl+A 1696 Shortcut src; 1697 src.SetKey(CommonSharedConstants::VK_WIN_BOTH); 1698 src.SetKey(VK_CAPITAL); 1699 Shortcut dest; 1700 dest.SetKey(VK_CONTROL); 1701 dest.SetKey(0x41); 1702 testState.AddOSLevelShortcut(src, dest); 1703 1704 std::vector<INPUT> inputs{ 1705 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_LWIN } }, 1706 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CAPITAL } }, 1707 }; 1708 1709 // Send LWin+CapsLock keydown 1710 mockedInputHandler.SendVirtualInput(inputs); 1711 1712 // SendVirtualInput should be called exactly once with the above condition 1713 Assert::AreEqual(1, mockedInputHandler.GetSendVirtualInputCallCount()); 1714 } 1715 1716 // Test if SendVirtualInput is sent exactly once with the suppress flag when Win+CapsLock is remapped to Ctrl 1717 TEST_METHOD (HandleShortcutRemapEvent_ShouldSendVirtualInputWithSuppressFlagExactlyOnce_WhenWinCapsLockIsMappedToCtrl) 1718 { 1719 // Set sendvirtualinput call count condition to return true if the key event was sent with the suppress flag 1720 mockedInputHandler.SetSendVirtualInputTestHandler([](LowlevelKeyboardEvent* data) { 1721 if (data->lParam->dwExtraInfo == KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG) 1722 return true; 1723 else 1724 return false; 1725 }); 1726 1727 // Remap Win+CapsLock to Ctrl+A 1728 Shortcut src; 1729 src.SetKey(CommonSharedConstants::VK_WIN_BOTH); 1730 src.SetKey(VK_CAPITAL); 1731 testState.AddOSLevelShortcut(src, (DWORD)VK_CONTROL); 1732 1733 std::vector<INPUT> inputs{ 1734 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_LWIN } }, 1735 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CAPITAL } }, 1736 }; 1737 1738 // Send LWin+CapsLock keydown 1739 mockedInputHandler.SendVirtualInput(inputs); 1740 1741 // SendVirtualInput should be called exactly once with the above condition 1742 Assert::AreEqual(1, mockedInputHandler.GetSendVirtualInputCallCount()); 1743 } 1744 1745 // Test if SendVirtualInput is sent exactly once with the suppress flag when shortcut containing Ctrl is remapped to shortcut Win+CapsLock and Ctrl is pressed again while shortcut remap is invoked 1746 TEST_METHOD (HandleShortcutRemapEvent_ShouldSendVirtualInputWithSuppressFlagExactlyOnce_WhenShortcutContainingCtrlIsMappedToWinCapsLockAndCtrlIsPressedWhileInvoked) 1747 { 1748 // Set sendvirtualinput call count condition to return true if the key event was sent with the suppress flag 1749 mockedInputHandler.SetSendVirtualInputTestHandler([](LowlevelKeyboardEvent* data) { 1750 if (data->lParam->dwExtraInfo == KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG) 1751 return true; 1752 else 1753 return false; 1754 }); 1755 1756 // Remap Ctrl+A to Win+CapsLock 1757 Shortcut src; 1758 src.SetKey(VK_CONTROL); 1759 src.SetKey(0x41); 1760 Shortcut dest; 1761 dest.SetKey(CommonSharedConstants::VK_WIN_BOTH); 1762 dest.SetKey(VK_CAPITAL); 1763 testState.AddOSLevelShortcut(src, dest); 1764 1765 std::vector<INPUT> inputs{ 1766 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1767 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1768 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1769 }; 1770 1771 // Send Ctrl+A keydown followed by Ctrl 1772 mockedInputHandler.SendVirtualInput(inputs); 1773 1774 // SendVirtualInput should be called exactly once with the above condition 1775 Assert::AreEqual(1, mockedInputHandler.GetSendVirtualInputCallCount()); 1776 } 1777 1778 // Test if SendVirtualInput is sent exactly once with the suppress flag when shortcut containing Ctrl is remapped to shortcut Win+CapsLock and Shift is pressed again while shortcut remap is invoked 1779 TEST_METHOD (HandleShortcutRemapEvent_ShouldSendVirtualInputWithSuppressFlagExactlyOnce_WhenShortcutContainingCtrlIsMappedToWinCapsLockAndShiftIsPressedWhileInvoked) 1780 { 1781 // Set sendvirtualinput call count condition to return true if the key event was sent with the suppress flag 1782 mockedInputHandler.SetSendVirtualInputTestHandler([](LowlevelKeyboardEvent* data) { 1783 if (data->lParam->dwExtraInfo == KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG) 1784 return true; 1785 else 1786 return false; 1787 }); 1788 1789 // Remap Ctrl+A to Win+CapsLock 1790 Shortcut src; 1791 src.SetKey(VK_CONTROL); 1792 src.SetKey(0x41); 1793 Shortcut dest; 1794 dest.SetKey(CommonSharedConstants::VK_WIN_BOTH); 1795 dest.SetKey(VK_CAPITAL); 1796 testState.AddOSLevelShortcut(src, dest); 1797 1798 std::vector<INPUT> inputs{ 1799 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1800 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1801 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 1802 }; 1803 1804 // Send Ctrl+A keydown followed by Shift 1805 mockedInputHandler.SendVirtualInput(inputs); 1806 1807 // SendVirtualInput should be called exactly once with the above condition 1808 Assert::AreEqual(1, mockedInputHandler.GetSendVirtualInputCallCount()); 1809 } 1810 1811 // Test if SendVirtualInput is sent exactly once with the suppress flag when shortcut containing Ctrl is remapped to CapsLock and Ctrl is pressed again while shortcut remap is invoked 1812 TEST_METHOD (HandleShortcutRemapEvent_ShouldSendVirtualInputWithSuppressFlagExactlyOnce_WhenShortcutContainingCtrlIsMappedToCapsLockAndCtrlIsPressedWhileInvoked) 1813 { 1814 // Set sendvirtualinput call count condition to return true if the key event was sent with the suppress flag 1815 mockedInputHandler.SetSendVirtualInputTestHandler([](LowlevelKeyboardEvent* data) { 1816 if (data->lParam->dwExtraInfo == KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG) 1817 return true; 1818 else 1819 return false; 1820 }); 1821 1822 // Remap Ctrl+A to CapsLock 1823 Shortcut src; 1824 src.SetKey(VK_CONTROL); 1825 src.SetKey(0x41); 1826 testState.AddOSLevelShortcut(src, (DWORD)VK_CAPITAL); 1827 1828 std::vector<INPUT> inputs{ 1829 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1830 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1831 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1832 }; 1833 1834 // Send Ctrl+A keydown followed by Ctrl 1835 mockedInputHandler.SendVirtualInput(inputs); 1836 1837 // SendVirtualInput should be called exactly once with the above condition 1838 Assert::AreEqual(1, mockedInputHandler.GetSendVirtualInputCallCount()); 1839 } 1840 1841 // Test if SendVirtualInput is sent exactly once with the suppress flag when shortcut containing Ctrl is remapped to CapsLock and Shift is pressed again while shortcut remap is invoked 1842 TEST_METHOD (HandleShortcutRemapEvent_ShouldSendVirtualInputWithSuppressFlagExactlyOnce_WhenShortcutContainingCtrlIsMappedToCapsLockAndShiftIsPressedWhileInvoked) 1843 { 1844 // Set sendvirtualinput call count condition to return true if the key event was sent with the suppress flag 1845 mockedInputHandler.SetSendVirtualInputTestHandler([](LowlevelKeyboardEvent* data) { 1846 if (data->lParam->dwExtraInfo == KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG) 1847 return true; 1848 else 1849 return false; 1850 }); 1851 1852 // Remap Ctrl+A to CapsLock 1853 Shortcut src; 1854 src.SetKey(VK_CONTROL); 1855 src.SetKey(0x41); 1856 testState.AddOSLevelShortcut(src, (DWORD)VK_CAPITAL); 1857 1858 std::vector<INPUT> inputs{ 1859 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1860 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1861 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 1862 }; 1863 1864 // Send Ctrl+A keydown followed by Shift 1865 mockedInputHandler.SendVirtualInput(inputs); 1866 1867 // SendVirtualInput should be called exactly once with the above condition 1868 Assert::AreEqual(1, mockedInputHandler.GetSendVirtualInputCallCount()); 1869 } 1870 1871 // Tests for all types of shortcut remappings 1872 1873 // Test that the shortcut remap state is not reset when an unrelated key up message is sent - required to handle programs sending dummy key up messages 1874 TEST_METHOD (ShortcutRemap_ShouldNotGetReset_OnSendingKeyUpForAKeyNotPresentInTheShortcutAfterInvokingTheShortcut) 1875 { 1876 // Remap Ctrl+A to Ctrl+V 1877 Shortcut src; 1878 src.SetKey(VK_CONTROL); 1879 src.SetKey(0x41); 1880 Shortcut dest; 1881 dest.SetKey(VK_CONTROL); 1882 dest.SetKey(0x56); 1883 testState.AddOSLevelShortcut(src, dest); 1884 1885 std::vector<INPUT> inputs{ 1886 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1887 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 1888 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'B', .dwFlags = KEYEVENTF_KEYUP } }, 1889 }; 1890 1891 // Send Ctrl+A keydown, then B key up 1892 mockedInputHandler.SendVirtualInput(inputs); 1893 1894 // A key state should be unchanged, Ctrl, V should be true 1895 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 1896 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false); 1897 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true); 1898 1899 // Shortcut invoked state should be true 1900 Assert::AreEqual(true, testState.osLevelShortcutReMap[src].isShortcutInvoked); 1901 } 1902 1903 // Tests for shortcut disable remappings 1904 1905 // Test that shortcut is disabled if the current shortcut pressed matches the exact shortcut which was remapped to Disable 1906 TEST_METHOD (ShortcutDisable_ShouldDisableShortcut_OnExactMatch) 1907 { 1908 Shortcut src; 1909 src.SetKey(VK_CONTROL); 1910 WORD actionKey = 0x41; 1911 src.SetKey(actionKey); 1912 WORD disableKey = CommonSharedConstants::VK_DISABLED; 1913 1914 testState.AddOSLevelShortcut(src, disableKey); 1915 1916 std::vector<INPUT> inputs{ 1917 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1918 { .type = INPUT_KEYBOARD, .ki = { .wVk = actionKey } }, 1919 }; 1920 1921 // send Ctrl+A 1922 mockedInputHandler.SendVirtualInput(inputs); 1923 1924 // Check that Ctrl+A was released and Disable key was not sent 1925 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 1926 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(actionKey), false); 1927 } 1928 1929 // Test that shortcut is not disabled if the shortcut which was remapped to Disable is a subset of the keys currently pressed 1930 TEST_METHOD (ShortcutDisable_ShouldNotDisableShortcut_OnSubsetMatch) 1931 { 1932 Shortcut src; 1933 src.SetKey(VK_CONTROL); 1934 WORD actionKey = 0x41; 1935 src.SetKey(actionKey); 1936 WORD disableKey = CommonSharedConstants::VK_DISABLED; 1937 1938 testState.AddOSLevelShortcut(src, disableKey); 1939 1940 std::vector<INPUT> inputs{ 1941 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1942 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 1943 { .type = INPUT_KEYBOARD, .ki = { .wVk = actionKey } }, 1944 }; 1945 1946 // send Ctrl+Shift+A 1947 mockedInputHandler.SendVirtualInput(inputs); 1948 1949 // Check that Ctrl+Shift+A was not released and Disable key was not sent 1950 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 1951 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), true); 1952 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(actionKey), true); 1953 } 1954 1955 // Test that shortcut is not disabled if the shortcut which was remapped to Disable is pressed followed by another key 1956 TEST_METHOD (ShortcutDisable_ShouldNotDisableShortcutSuperset_AfterShortcutWasDisabled) 1957 { 1958 Shortcut src; 1959 src.SetKey(VK_CONTROL); 1960 WORD actionKey = 0x41; 1961 src.SetKey(actionKey); 1962 WORD disableKey = CommonSharedConstants::VK_DISABLED; 1963 1964 testState.AddOSLevelShortcut(src, disableKey); 1965 1966 std::vector<INPUT> inputs1{ 1967 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 1968 { .type = INPUT_KEYBOARD, .ki = { .wVk = actionKey } }, 1969 }; 1970 1971 // send Ctrl+A 1972 mockedInputHandler.SendVirtualInput(inputs1); 1973 1974 std::vector<INPUT> inputs2{ 1975 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'B' } }, 1976 }; 1977 1978 mockedInputHandler.SendVirtualInput(inputs2); 1979 1980 // Check that Ctrl+A+B was pressed 1981 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 1982 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(actionKey), true); 1983 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x42), true); 1984 // Shortcut invoked state should be false 1985 Assert::AreEqual(false, testState.osLevelShortcutReMap[src].isShortcutInvoked); 1986 } 1987 1988 // Test that shortcut is not disabled if the shortcut which was remapped to Disable is pressed and the action key is released, followed by pressing another key 1989 TEST_METHOD (ShortcutDisable_ShouldNotDisableShortcutSuperset_AfterActionKeyWasReleasedAndAnotherKeyWasPressedAfterIt) 1990 { 1991 Shortcut src; 1992 src.SetKey(VK_CONTROL); 1993 WORD actionKey = 0x41; 1994 src.SetKey(actionKey); 1995 WORD disableKey = CommonSharedConstants::VK_DISABLED; 1996 1997 testState.AddOSLevelShortcut(src, disableKey); 1998 1999 std::vector<INPUT> inputs1{ 2000 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 2001 { .type = INPUT_KEYBOARD, .ki = { .wVk = actionKey } }, 2002 { .type = INPUT_KEYBOARD, .ki = { .wVk = actionKey, .dwFlags = KEYEVENTF_KEYUP } }, 2003 }; 2004 2005 // send Ctrl+A, release A 2006 mockedInputHandler.SendVirtualInput(inputs1); 2007 2008 // Check that no keys are pressed 2009 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false); 2010 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(actionKey), false); 2011 // Shortcut invoked state should be true 2012 Assert::AreEqual(true, testState.osLevelShortcutReMap[src].isShortcutInvoked); 2013 2014 std::vector<INPUT> inputs2{ 2015 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'B' } }, 2016 }; 2017 2018 // send B 2019 mockedInputHandler.SendVirtualInput(inputs2); 2020 2021 // Check that Ctrl+B was pressed 2022 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true); 2023 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(actionKey), false); 2024 Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x42), true); 2025 // Shortcut invoked state should be false 2026 Assert::AreEqual(false, testState.osLevelShortcutReMap[src].isShortcutInvoked); 2027 } 2028 2029 // Test that the isOriginalActionKeyPressed flag is set to true on exact match of the shortcut 2030 TEST_METHOD (ShortcutDisable_ShouldSetIsOriginalActionKeyPressed_OnExactMatch) 2031 { 2032 Shortcut src; 2033 src.SetKey(VK_CONTROL); 2034 WORD actionKey = 0x41; 2035 src.SetKey(actionKey); 2036 WORD disableKey = CommonSharedConstants::VK_DISABLED; 2037 2038 testState.AddOSLevelShortcut(src, disableKey); 2039 2040 std::vector<INPUT> inputs{ 2041 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 2042 { .type = INPUT_KEYBOARD, .ki = { .wVk = actionKey } }, 2043 }; 2044 2045 // send Ctrl+A 2046 mockedInputHandler.SendVirtualInput(inputs); 2047 2048 // IsOriginalActionKeyPressed state should be true 2049 Assert::AreEqual(true, testState.osLevelShortcutReMap[src].isOriginalActionKeyPressed); 2050 } 2051 2052 // Test that the isOriginalActionKeyPressed flag is set to false on releasing the action key 2053 TEST_METHOD (ShortcutDisable_ShouldResetIsOriginalActionKeyPressed_OnReleasingActionKey) 2054 { 2055 Shortcut src; 2056 src.SetKey(VK_CONTROL); 2057 WORD actionKey = 0x41; 2058 src.SetKey(actionKey); 2059 WORD disableKey = CommonSharedConstants::VK_DISABLED; 2060 2061 testState.AddOSLevelShortcut(src, disableKey); 2062 2063 std::vector<INPUT> inputs1{ 2064 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 2065 { .type = INPUT_KEYBOARD, .ki = { .wVk = actionKey } }, 2066 }; 2067 2068 // send Ctrl+A 2069 mockedInputHandler.SendVirtualInput(inputs1); 2070 2071 // IsOriginalActionKeyPressed state should be true 2072 Assert::AreEqual(true, testState.osLevelShortcutReMap[src].isOriginalActionKeyPressed); 2073 2074 std::vector<INPUT> inputs2{ 2075 { .type = INPUT_KEYBOARD, .ki = { .wVk = actionKey, .dwFlags = KEYEVENTF_KEYUP } }, 2076 }; 2077 2078 // release A 2079 mockedInputHandler.SendVirtualInput(inputs2); 2080 2081 // IsOriginalActionKeyPressed state should be false 2082 Assert::AreEqual(false, testState.osLevelShortcutReMap[src].isOriginalActionKeyPressed); 2083 } 2084 2085 // Test that the isOriginalActionKeyPressed flag is set to true on pressing the action key again after releasing the action key 2086 TEST_METHOD (ShortcutDisable_ShouldSetIsOriginalActionKeyPressed_OnPressingActionKeyAfterReleasingActionKey) 2087 { 2088 Shortcut src; 2089 src.SetKey(VK_CONTROL); 2090 WORD actionKey = 0x41; 2091 src.SetKey(actionKey); 2092 WORD disableKey = CommonSharedConstants::VK_DISABLED; 2093 2094 testState.AddOSLevelShortcut(src, disableKey); 2095 2096 std::vector<INPUT> inputs1{ 2097 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 2098 { .type = INPUT_KEYBOARD, .ki = { .wVk = actionKey } }, 2099 { .type = INPUT_KEYBOARD, .ki = { .wVk = actionKey, .dwFlags = KEYEVENTF_KEYUP } } 2100 }; 2101 2102 // send Ctrl+A, release A 2103 mockedInputHandler.SendVirtualInput(inputs1); 2104 2105 // IsOriginalActionKeyPressed state should be false 2106 Assert::AreEqual(false, testState.osLevelShortcutReMap[src].isOriginalActionKeyPressed); 2107 2108 std::vector<INPUT> inputs2{ 2109 { .type = INPUT_KEYBOARD, .ki = { .wVk = actionKey } }, 2110 }; 2111 2112 // press A 2113 mockedInputHandler.SendVirtualInput(inputs2); 2114 2115 // IsOriginalActionKeyPressed state should be true 2116 Assert::AreEqual(true, testState.osLevelShortcutReMap[src].isOriginalActionKeyPressed); 2117 } 2118 2119 // Test that the isOriginalActionKeyPressed flag is set to false on releasing the modifier key 2120 TEST_METHOD (ShortcutDisable_ShouldResetIsOriginalActionKeyPressed_OnReleasingModifierKey) 2121 { 2122 Shortcut src; 2123 src.SetKey(VK_CONTROL); 2124 WORD actionKey = 0x41; 2125 src.SetKey(actionKey); 2126 WORD disableKey = CommonSharedConstants::VK_DISABLED; 2127 2128 testState.AddOSLevelShortcut(src, disableKey); 2129 2130 std::vector<INPUT> inputs1{ 2131 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 2132 { .type = INPUT_KEYBOARD, .ki = { .wVk = actionKey } }, 2133 }; 2134 2135 // send Ctrl+A 2136 mockedInputHandler.SendVirtualInput(inputs1); 2137 2138 // IsOriginalActionKeyPressed state should be true 2139 Assert::AreEqual(true, testState.osLevelShortcutReMap[src].isOriginalActionKeyPressed); 2140 2141 std::vector<INPUT> inputs2{ 2142 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 2143 }; 2144 2145 // release Ctrl 2146 mockedInputHandler.SendVirtualInput(inputs2); 2147 2148 // IsOriginalActionKeyPressed state should be false 2149 Assert::AreEqual(false, testState.osLevelShortcutReMap[src].isOriginalActionKeyPressed); 2150 } 2151 2152 // Test that the isOriginalActionKeyPressed flag is set to false on pressing another key 2153 TEST_METHOD (ShortcutDisable_ShouldResetIsOriginalActionKeyPressed_OnPressingAnotherKey) 2154 { 2155 Shortcut src; 2156 src.SetKey(VK_CONTROL); 2157 WORD actionKey = 0x41; 2158 src.SetKey(actionKey); 2159 WORD disableKey = CommonSharedConstants::VK_DISABLED; 2160 2161 testState.AddOSLevelShortcut(src, disableKey); 2162 2163 std::vector<INPUT> inputs1{ 2164 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 2165 { .type = INPUT_KEYBOARD, .ki = { .wVk = actionKey } }, 2166 }; 2167 2168 // send Ctrl+A 2169 mockedInputHandler.SendVirtualInput(inputs1); 2170 2171 // IsOriginalActionKeyPressed state should be true 2172 Assert::AreEqual(true, testState.osLevelShortcutReMap[src].isOriginalActionKeyPressed); 2173 2174 std::vector<INPUT> inputs2{ 2175 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'B' } }, 2176 }; 2177 2178 // press B 2179 mockedInputHandler.SendVirtualInput(inputs2); 2180 2181 // IsOriginalActionKeyPressed state should be false 2182 Assert::AreEqual(false, testState.osLevelShortcutReMap[src].isOriginalActionKeyPressed); 2183 } 2184 2185 // Tests for dummy key events in shortcut remaps 2186 2187 // Test if one set of dummy key events is sent before releasing the modifier when shortcut is remapped to a shortcut not containing original shortcut modifiers on invoking the shortcut. Example: Win+A->Ctrl+V, press Win+A, since Win will be released here we need to send a dummy event before it 2188 TEST_METHOD (HandleShortcutRemapEvent_ShouldSendOneSetOfDummyKeyEventsBeforeReleasingTheModifier_WhenShortcutIsRemappedToAShortcutNotContainingOriginalShortcutModifiersOnInvoke) 2189 { 2190 // Set sendvirtualinput call count condition to return true if the key event was a dummy key and LWin is pressed 2191 mockedInputHandler.SetSendVirtualInputTestHandler([this](LowlevelKeyboardEvent* data) { 2192 if (data->lParam->vkCode == KeyboardManagerConstants::DUMMY_KEY && mockedInputHandler.GetVirtualKeyState(VK_LWIN)) 2193 return true; 2194 else 2195 return false; 2196 }); 2197 2198 // Remap Win+A to Ctrl+V 2199 Shortcut src; 2200 src.SetKey(CommonSharedConstants::VK_WIN_BOTH); 2201 src.SetKey(0x41); 2202 Shortcut dest; 2203 dest.SetKey(VK_CONTROL); 2204 dest.SetKey(0x56); 2205 testState.AddOSLevelShortcut(src, dest); 2206 2207 std::vector<INPUT> inputs{ 2208 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_LWIN } }, 2209 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 2210 }; 2211 2212 // Send LWin+A 2213 mockedInputHandler.SendVirtualInput(inputs); 2214 2215 // SendVirtualInput should be called exactly twice with the above condition (since two dummy key events are sent in one set) 2216 Assert::AreEqual(2, mockedInputHandler.GetSendVirtualInputCallCount()); 2217 // LWin should be released 2218 Assert::AreEqual(false, mockedInputHandler.GetVirtualKeyState(VK_LWIN)); 2219 } 2220 2221 // Test if one set of dummy key events is sent after setting the modifier when three key shortcut is remapped to a shortcut on releasing action key and a modifier. 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 2222 TEST_METHOD (HandleShortcutRemapEvent_ShouldSendOneSetOfDummyKeyEventsAfterSettingTheModifier_When3KeyShortcutIsRemappedToShortcutOnReleasingActionKeyAndAModifier) 2223 { 2224 // Remap Win+Ctrl+A to Ctrl+V 2225 Shortcut src; 2226 src.SetKey(CommonSharedConstants::VK_WIN_BOTH); 2227 src.SetKey(VK_CONTROL); 2228 src.SetKey(0x41); 2229 Shortcut dest; 2230 dest.SetKey(VK_CONTROL); 2231 dest.SetKey(0x56); 2232 testState.AddOSLevelShortcut(src, dest); 2233 2234 std::vector<INPUT> inputs1{ 2235 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_LWIN } }, 2236 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 2237 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 2238 }; 2239 2240 // Send LWin+Ctrl+A 2241 mockedInputHandler.SendVirtualInput(inputs1); 2242 2243 // Set sendvirtualinput call count condition to return true if the key event was a dummy key and LWin is pressed 2244 mockedInputHandler.SetSendVirtualInputTestHandler([this](LowlevelKeyboardEvent* data) { 2245 if (data->lParam->vkCode == KeyboardManagerConstants::DUMMY_KEY && mockedInputHandler.GetVirtualKeyState(VK_LWIN)) 2246 return true; 2247 else 2248 return false; 2249 }); 2250 2251 std::vector<INPUT> inputs2{ 2252 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 2253 }; 2254 2255 // Release Ctrl 2256 mockedInputHandler.SendVirtualInput(inputs2); 2257 2258 // SendVirtualInput should be called exactly twice with the above condition (since two dummy key events are sent in one set) 2259 Assert::AreEqual(2, mockedInputHandler.GetSendVirtualInputCallCount()); 2260 // LWin should be pressed 2261 Assert::AreEqual(true, mockedInputHandler.GetVirtualKeyState(VK_LWIN)); 2262 } 2263 2264 // Test if one set of dummy key events is sent before releasing the modifier when shortcut is remapped to a single key on invoking the shortcut. Example: Win+A->V, press Win+A, since Win will be released here we need to send a dummy event before it 2265 TEST_METHOD (HandleShortcutRemapEvent_ShouldSendOneSetOfDummyKeyEventsBeforeReleasingTheModifier_WhenShortcutIsRemappedToASingleKeyOnInvoke) 2266 { 2267 // Set sendvirtualinput call count condition to return true if the key event was a dummy key and LWin is pressed 2268 mockedInputHandler.SetSendVirtualInputTestHandler([this](LowlevelKeyboardEvent* data) { 2269 if (data->lParam->vkCode == KeyboardManagerConstants::DUMMY_KEY && mockedInputHandler.GetVirtualKeyState(VK_LWIN)) 2270 return true; 2271 else 2272 return false; 2273 }); 2274 2275 // Remap Win+A toV 2276 Shortcut src; 2277 src.SetKey(CommonSharedConstants::VK_WIN_BOTH); 2278 src.SetKey(0x41); 2279 testState.AddOSLevelShortcut(src, (DWORD)0x56); 2280 2281 std::vector<INPUT> inputs{ 2282 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_LWIN } }, 2283 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 2284 }; 2285 2286 // Send LWin+A 2287 mockedInputHandler.SendVirtualInput(inputs); 2288 2289 // SendVirtualInput should be called exactly twice with the above condition (since two dummy key events are sent in one set) 2290 Assert::AreEqual(2, mockedInputHandler.GetSendVirtualInputCallCount()); 2291 // LWin should be released 2292 Assert::AreEqual(false, mockedInputHandler.GetVirtualKeyState(VK_LWIN)); 2293 } 2294 2295 // Test if one set of dummy key events is sent after setting the modifier when shortcut is remapped to a single key on releasing action key and a modifier. Example: Win+A->V, press Shift+Win+A and release A, since Win will be pressed here we need to send a dummy event after it 2296 TEST_METHOD (HandleShortcutRemapEvent_ShouldSendOneSetOfDummyKeyEventsAfterSettingTheModifier_WhenShortcutIsRemappedToSingleKeyOnReleasingActionKeyAndAModifier) 2297 { 2298 // Remap Win+Ctrl+A to V 2299 Shortcut src; 2300 src.SetKey(CommonSharedConstants::VK_WIN_BOTH); 2301 src.SetKey(VK_CONTROL); 2302 src.SetKey(0x41); 2303 testState.AddOSLevelShortcut(src, (DWORD)0x56); 2304 2305 std::vector<INPUT> inputs1{ 2306 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_LWIN } }, 2307 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } }, 2308 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 2309 }; 2310 2311 // Send LWin+Ctrl+A 2312 mockedInputHandler.SendVirtualInput(inputs1); 2313 2314 // Set sendvirtualinput call count condition to return true if the key event was a dummy key and LWin is pressed 2315 mockedInputHandler.SetSendVirtualInputTestHandler([this](LowlevelKeyboardEvent* data) { 2316 if (data->lParam->vkCode == KeyboardManagerConstants::DUMMY_KEY && mockedInputHandler.GetVirtualKeyState(VK_LWIN)) 2317 return true; 2318 else 2319 return false; 2320 }); 2321 2322 std::vector<INPUT> inputs2{ 2323 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }, 2324 }; 2325 2326 // Release Ctrl 2327 mockedInputHandler.SendVirtualInput(inputs2); 2328 2329 // SendVirtualInput should be called exactly twice with the above condition (since two dummy key events are sent in one set) 2330 Assert::AreEqual(2, mockedInputHandler.GetSendVirtualInputCallCount()); 2331 // LWin should be pressed 2332 Assert::AreEqual(true, mockedInputHandler.GetVirtualKeyState(VK_LWIN)); 2333 } 2334 2335 // Test if one set of dummy key events is sent after setting the modifier when shortcut is remapped to a single key on invoking shortcut after pressing another key and then releasing the action key. Example: Win+A->V, press Shift+Win+A and release A, since Win will be pressed here we need to send a dummy event after it 2336 TEST_METHOD (HandleShortcutRemapEvent_ShouldSendOneSetOfDummyKeyEventsAfterSettingTheModifier_WhenShortcutIsRemappedToSingleKeyOnInvokingTheShortcutAfterPressingAnotherKeyAndThenReleasingTheActionKey) 2337 { 2338 // Remap Win+A to V 2339 Shortcut src; 2340 src.SetKey(CommonSharedConstants::VK_WIN_BOTH); 2341 src.SetKey(0x41); 2342 testState.AddOSLevelShortcut(src, (DWORD)0x56); 2343 2344 std::vector<INPUT> inputs1{ 2345 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_SHIFT } }, 2346 { .type = INPUT_KEYBOARD, .ki = { .wVk = VK_LWIN } }, 2347 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }, 2348 }; 2349 2350 // Send Shift+LWin+A 2351 mockedInputHandler.SendVirtualInput(inputs1); 2352 2353 // Set sendvirtualinput call count condition to return true if the key event was a dummy key and LWin is pressed 2354 mockedInputHandler.SetSendVirtualInputTestHandler([this](LowlevelKeyboardEvent* data) { 2355 if (data->lParam->vkCode == KeyboardManagerConstants::DUMMY_KEY && mockedInputHandler.GetVirtualKeyState(VK_LWIN)) 2356 return true; 2357 else 2358 return false; 2359 }); 2360 2361 std::vector<INPUT> inputs2{ 2362 { .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } }, 2363 }; 2364 2365 // Release A 2366 mockedInputHandler.SendVirtualInput(inputs2); 2367 2368 // SendVirtualInput should be called exactly twice with the above condition (since two dummy key events are sent in one set) 2369 Assert::AreEqual(2, mockedInputHandler.GetSendVirtualInputCallCount()); 2370 // LWin should be pressed 2371 Assert::AreEqual(true, mockedInputHandler.GetVirtualKeyState(VK_LWIN)); 2372 } 2373 }; 2374 }