MockedInput.cpp
1 #include "pch.h" 2 #include "MockedInput.h" 3 4 using namespace KeyboardManagerInput; 5 6 // Set the keyboard hook procedure to be tested 7 void MockedInput::SetHookProc(std::function<intptr_t(LowlevelKeyboardEvent*)> hookProcedure) 8 { 9 hookProc = hookProcedure; 10 } 11 12 // Function to simulate keyboard input - arguments and return value based on SendInput function (https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-sendinput) 13 void MockedInput::SendVirtualInput(const std::vector<INPUT>& inputs) 14 { 15 // Iterate over inputs 16 for (const INPUT& input : inputs) 17 { 18 LowlevelKeyboardEvent keyEvent{}; 19 20 // Distinguish between key and sys key by checking if the key is either F10 (for syskeydown) or if the key message is sent while Alt is held down. SYSKEY messages are also sent if there is no window in focus, but that has not been mocked since it would require many changes. More details on key messages at https://learn.microsoft.com/windows/win32/inputdev/wm-syskeydown 21 if (input.ki.dwFlags & KEYEVENTF_KEYUP) 22 { 23 if (keyboardState[VK_MENU] == true) 24 { 25 keyEvent.wParam = WM_SYSKEYUP; 26 } 27 else 28 { 29 keyEvent.wParam = WM_KEYUP; 30 } 31 } 32 else 33 { 34 if (input.ki.wVk == VK_F10 || keyboardState[VK_MENU] == true) 35 { 36 keyEvent.wParam = WM_SYSKEYDOWN; 37 } 38 else 39 { 40 keyEvent.wParam = WM_KEYDOWN; 41 } 42 } 43 KBDLLHOOKSTRUCT lParam = {}; 44 45 // Set only vkCode and dwExtraInfo since other values are unused 46 lParam.vkCode = input.ki.wVk; 47 lParam.dwExtraInfo = input.ki.dwExtraInfo; 48 keyEvent.lParam = &lParam; 49 50 // If the SendVirtualInput call condition is true, increment the count. If no condition is set then always increment the count 51 if (sendVirtualInputCallCondition == nullptr || sendVirtualInputCallCondition(&keyEvent)) 52 { 53 sendVirtualInputCallCount++; 54 } 55 56 // Call low level hook handler 57 intptr_t result = MockedKeyboardHook(&keyEvent); 58 59 // Set keyboard state if the hook does not suppress the input 60 if (result == 0) 61 { 62 // If key up flag is set, then set keyboard state to false 63 keyboardState[input.ki.wVk] = (input.ki.dwFlags & KEYEVENTF_KEYUP) ? false : true; 64 65 // Handling modifier key codes 66 switch (input.ki.wVk) 67 { 68 case VK_CONTROL: 69 if (input.ki.dwFlags & KEYEVENTF_KEYUP) 70 { 71 keyboardState[VK_LCONTROL] = false; 72 keyboardState[VK_RCONTROL] = false; 73 } 74 break; 75 case VK_LCONTROL: 76 keyboardState[VK_CONTROL] = (input.ki.dwFlags & KEYEVENTF_KEYUP) ? false : true; 77 break; 78 case VK_RCONTROL: 79 keyboardState[VK_CONTROL] = (input.ki.dwFlags & KEYEVENTF_KEYUP) ? false : true; 80 break; 81 case VK_MENU: 82 if (input.ki.dwFlags & KEYEVENTF_KEYUP) 83 { 84 keyboardState[VK_LMENU] = false; 85 keyboardState[VK_RMENU] = false; 86 } 87 break; 88 case VK_LMENU: 89 keyboardState[VK_MENU] = (input.ki.dwFlags & KEYEVENTF_KEYUP) ? false : true; 90 break; 91 case VK_RMENU: 92 keyboardState[VK_MENU] = (input.ki.dwFlags & KEYEVENTF_KEYUP) ? false : true; 93 break; 94 case VK_SHIFT: 95 if (input.ki.dwFlags & KEYEVENTF_KEYUP) 96 { 97 keyboardState[VK_LSHIFT] = false; 98 keyboardState[VK_RSHIFT] = false; 99 } 100 break; 101 case VK_LSHIFT: 102 keyboardState[VK_SHIFT] = (input.ki.dwFlags & KEYEVENTF_KEYUP) ? false : true; 103 break; 104 case VK_RSHIFT: 105 keyboardState[VK_SHIFT] = (input.ki.dwFlags & KEYEVENTF_KEYUP) ? false : true; 106 break; 107 } 108 } 109 } 110 } 111 112 // Function to simulate keyboard hook behavior 113 intptr_t MockedInput::MockedKeyboardHook(LowlevelKeyboardEvent* data) 114 { 115 // If the hookProc is set to null, then skip the hook 116 if (hookProc != nullptr) 117 { 118 return hookProc(data); 119 } 120 else 121 { 122 return 0; 123 } 124 } 125 126 // Function to get the state of a particular key 127 bool MockedInput::GetVirtualKeyState(int key) 128 { 129 return keyboardState[key]; 130 } 131 132 // Function to reset the mocked keyboard state 133 void MockedInput::ResetKeyboardState() 134 { 135 std::fill(keyboardState.begin(), keyboardState.end(), false); 136 } 137 138 // Function to set SendVirtualInput call count condition 139 void MockedInput::SetSendVirtualInputTestHandler(std::function<bool(LowlevelKeyboardEvent*)> condition) 140 { 141 sendVirtualInputCallCount = 0; 142 sendVirtualInputCallCondition = condition; 143 } 144 145 // Function to get SendVirtualInput call count 146 int MockedInput::GetSendVirtualInputCallCount() 147 { 148 return sendVirtualInputCallCount; 149 } 150 151 // Function to get the foreground process name 152 void MockedInput::SetForegroundProcess(std::wstring process) 153 { 154 currentProcess = process; 155 } 156 157 // Function to get the foreground process name 158 void MockedInput::GetForegroundProcess(_Out_ std::wstring& foregroundProcess) 159 { 160 foregroundProcess = currentProcess; 161 }