mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-11-24 04:12:32 +08:00
[KBM][CQ]Replace LPINPUT with std::vector<INPUT> (#32052)
This commit is contained in:
parent
9509d7c1cc
commit
62c7b0a66d
@ -72,7 +72,7 @@ In order to test the remapping logic, a mocked keyboard input handler had to be
|
|||||||
The [`MockedInput`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/MockedInput.h) class uses a 256 size `bool` vector to store the key state for each key code. Identifying the foreground process is mocked by simply setting and getting a string value for the name of the current process.
|
The [`MockedInput`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/MockedInput.h) class uses a 256 size `bool` vector to store the key state for each key code. Identifying the foreground process is mocked by simply setting and getting a string value for the name of the current process.
|
||||||
|
|
||||||
[To mock the `SendInput` method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/test/MockedInput.cpp#L10-L110), the steps for processing the input are as follows. This implementation is based on public documentation for SendInput and the behavior of key messages and keyboard hooks:
|
[To mock the `SendInput` method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/test/MockedInput.cpp#L10-L110), the steps for processing the input are as follows. This implementation is based on public documentation for SendInput and the behavior of key messages and keyboard hooks:
|
||||||
- Iterate over all the inputs in the INPUT array argument
|
- Iterate over all the inputs in the `INPUT` vector argument.
|
||||||
- If the event is a key up event, then it is considered [`WM_SYSKEYUP`](https://learn.microsoft.com/windows/win32/inputdev/wm-syskeyup) if Alt is held down, otherwise it is `WM_KEYUP`.
|
- If the event is a key up event, then it is considered [`WM_SYSKEYUP`](https://learn.microsoft.com/windows/win32/inputdev/wm-syskeyup) if Alt is held down, otherwise it is `WM_KEYUP`.
|
||||||
- If the event is a key down event, then it is considered [`WM_SYSKEYDOWN`](https://learn.microsoft.com/windows/win32/inputdev/wm-syskeydown) if either Alt is held down or if it is F10, otherwise it is `WM_KEYDOWN`.
|
- If the event is a key down event, then it is considered [`WM_SYSKEYDOWN`](https://learn.microsoft.com/windows/win32/inputdev/wm-syskeydown) if either Alt is held down or if it is F10, otherwise it is `WM_KEYDOWN`.
|
||||||
- An optional function which can be set on the `MockedInput` handler can be used to test for the number of times a key event is received by the system with a particular condition using [`sendVirtualInputCallCondition`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/test/MockedInput.cpp#L48-L52).
|
- An optional function which can be set on the `MockedInput` handler can be used to test for the number of times a key event is received by the system with a particular condition using [`sendVirtualInputCallCondition`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/test/MockedInput.cpp#L48-L52).
|
||||||
|
@ -69,7 +69,7 @@ namespace KeyboardEventHandlers
|
|||||||
key_count = std::get<Shortcut>(it->second).Size();
|
key_count = std::get<Shortcut>(it->second).Size();
|
||||||
}
|
}
|
||||||
|
|
||||||
LPINPUT keyEventList = new INPUT[size_t(key_count)]{};
|
std::vector<INPUT> keyEventList;
|
||||||
|
|
||||||
// Handle remaps to VK_WIN_BOTH
|
// Handle remaps to VK_WIN_BOTH
|
||||||
DWORD target;
|
DWORD target;
|
||||||
@ -92,35 +92,31 @@ namespace KeyboardEventHandlers
|
|||||||
{
|
{
|
||||||
if (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP)
|
if (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP)
|
||||||
{
|
{
|
||||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(target), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(target), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(target), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(target), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int i = 0;
|
|
||||||
Shortcut targetShortcut = std::get<Shortcut>(it->second);
|
Shortcut targetShortcut = std::get<Shortcut>(it->second);
|
||||||
if (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP)
|
if (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP)
|
||||||
{
|
{
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(targetShortcut.GetActionKey()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(targetShortcut.GetActionKey()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||||
i++;
|
Helpers::SetModifierKeyEvents(targetShortcut, ModifierKey::Disabled, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||||
Helpers::SetModifierKeyEvents(targetShortcut, ModifierKey::Disabled, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
|
||||||
// Dummy key is not required here since SetModifierKeyEvents will only add key-up events for the modifiers here, and the action key key-up is already sent before it
|
// Dummy key is not required here since SetModifierKeyEvents will only add key-up events for the modifiers here, and the action key key-up is already sent before it
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Dummy key is not required here since SetModifierKeyEvents will only add key-down events for the modifiers here, and the action key key-down is already sent after it
|
// Dummy key is not required here since SetModifierKeyEvents will only add key-down events for the modifiers here, and the action key key-down is already sent after it
|
||||||
Helpers::SetModifierKeyEvents(targetShortcut, ModifierKey::Disabled, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
Helpers::SetModifierKeyEvents(targetShortcut, ModifierKey::Disabled, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(targetShortcut.GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(targetShortcut.GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT res = ii.SendVirtualInput(key_count, keyEventList, sizeof(INPUT));
|
ii.SendVirtualInput(keyEventList);
|
||||||
delete[] keyEventList;
|
|
||||||
|
|
||||||
if (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN)
|
if (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN)
|
||||||
{
|
{
|
||||||
@ -194,14 +190,12 @@ namespace KeyboardEventHandlers
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int key_count = 2;
|
std::vector<INPUT> keyEventList;
|
||||||
LPINPUT keyEventList = new INPUT[size_t(key_count)]();
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, (WORD)data->lParam->vkCode, 0, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)data->lParam->vkCode, 0, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, (WORD)data->lParam->vkCode, KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||||
Helpers::SetKeyEvent(keyEventList, 1, INPUT_KEYBOARD, (WORD)data->lParam->vkCode, KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
|
||||||
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
UINT res = ii.SendVirtualInput(key_count, keyEventList, sizeof(INPUT));
|
ii.SendVirtualInput(keyEventList);
|
||||||
delete[] keyEventList;
|
|
||||||
|
|
||||||
// Reset the long press flag when the key has been lifted.
|
// Reset the long press flag when the key has been lifted.
|
||||||
if (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP)
|
if (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP)
|
||||||
@ -306,8 +300,7 @@ namespace KeyboardEventHandlers
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t key_count = 0;
|
std::vector<INPUT> keyEventList;
|
||||||
LPINPUT keyEventList = nullptr;
|
|
||||||
|
|
||||||
// Remember which win key was pressed initially
|
// Remember which win key was pressed initially
|
||||||
if (ii.GetVirtualKeyState(VK_RWIN))
|
if (ii.GetVirtualKeyState(VK_RWIN))
|
||||||
@ -331,8 +324,6 @@ namespace KeyboardEventHandlers
|
|||||||
myThread.detach();
|
myThread.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Logger::trace(L"ChordKeyboardHandler:returning..");
|
Logger::trace(L"ChordKeyboardHandler:returning..");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -362,7 +353,6 @@ namespace KeyboardEventHandlers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto threadFunction = [newUri]() {
|
auto threadFunction = [newUri]() {
|
||||||
HINSTANCE result = ShellExecute(NULL, L"open", newUri.c_str(), NULL, NULL, SW_SHOWNORMAL);
|
HINSTANCE result = ShellExecute(NULL, L"open", newUri.c_str(), NULL, NULL, SW_SHOWNORMAL);
|
||||||
|
|
||||||
@ -380,7 +370,6 @@ namespace KeyboardEventHandlers
|
|||||||
myThread.detach();
|
myThread.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Logger::trace(L"ChordKeyboardHandler:returning..");
|
Logger::trace(L"ChordKeyboardHandler:returning..");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -394,30 +383,22 @@ namespace KeyboardEventHandlers
|
|||||||
if (commonKeys == src_size - 1)
|
if (commonKeys == src_size - 1)
|
||||||
{
|
{
|
||||||
// key down for all new shortcut keys except the common modifiers
|
// key down for all new shortcut keys except the common modifiers
|
||||||
key_count = dest_size - commonKeys;
|
keyEventList = std::vector<INPUT>{};
|
||||||
keyEventList = new INPUT[key_count]{};
|
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
|
||||||
int i = 0;
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
|
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Dummy key, key up for all the original shortcut modifier keys and key down for all the new shortcut keys but common keys in each are not repeated
|
// Dummy key, key up for all the original shortcut modifier keys and key down for all the new shortcut keys but common keys in each are not repeated
|
||||||
key_count = KeyboardManagerConstants::DUMMY_KEY_EVENT_SIZE + (src_size - 1) + (dest_size) - (2 * static_cast<size_t>(commonKeys));
|
|
||||||
keyEventList = new INPUT[key_count]{};
|
|
||||||
|
|
||||||
// Send a dummy key event to prevent modifier press+release from being triggered. Example: Win+A->Ctrl+V, press Win+A, since Win will be released here we need to send a dummy event before it
|
// Send a dummy key event to prevent modifier press+release from being triggered. Example: Win+A->Ctrl+V, press Win+A, since Win will be released here we need to send a dummy event before it
|
||||||
int i = 0;
|
Helpers::SetDummyKeyEvent(keyEventList, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
Helpers::SetDummyKeyEvent(keyEventList, i, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
|
||||||
|
|
||||||
// Release original shortcut state (release in reverse order of shortcut to be accurate)
|
// Release original shortcut state (release in reverse order of shortcut to be accurate)
|
||||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut));
|
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut));
|
||||||
|
|
||||||
// Set new shortcut key down state
|
// Set new shortcut key down state
|
||||||
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
|
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modifier state reset might be required for this key depending on the shortcut's action and target modifiers - ex: Win+Caps -> Ctrl+A
|
// Modifier state reset might be required for this key depending on the shortcut's action and target modifiers - ex: Win+Caps -> Ctrl+A
|
||||||
@ -432,31 +413,23 @@ namespace KeyboardEventHandlers
|
|||||||
}
|
}
|
||||||
else if (remapToKey)
|
else if (remapToKey)
|
||||||
{
|
{
|
||||||
// Dummy key, key up for all the original shortcut modifier keys and key down for remapped key
|
|
||||||
key_count = KeyboardManagerConstants::DUMMY_KEY_EVENT_SIZE + (src_size - 1) + dest_size;
|
|
||||||
|
|
||||||
// Do not send Disable key
|
// Do not send Disable key
|
||||||
if (std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)
|
if (std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)
|
||||||
{
|
{
|
||||||
key_count--;
|
|
||||||
// Since the original shortcut's action key is pressed, set it to true
|
// Since the original shortcut's action key is pressed, set it to true
|
||||||
it->second.isOriginalActionKeyPressed = true;
|
it->second.isOriginalActionKeyPressed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
keyEventList = new INPUT[key_count]{};
|
|
||||||
|
|
||||||
// Send a dummy key event to prevent modifier press+release from being triggered. Example: Win+A->V, press Win+A, since Win will be released here we need to send a dummy event before it
|
// Send a dummy key event to prevent modifier press+release from being triggered. Example: Win+A->V, press Win+A, since Win will be released here we need to send a dummy event before it
|
||||||
int i = 0;
|
Helpers::SetDummyKeyEvent(keyEventList, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
Helpers::SetDummyKeyEvent(keyEventList, i, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
|
||||||
|
|
||||||
// Release original shortcut state (release in reverse order of shortcut to be accurate)
|
// Release original shortcut state (release in reverse order of shortcut to be accurate)
|
||||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
|
|
||||||
// Set target key down state
|
// Set target key down state
|
||||||
if (std::get<DWORD>(it->second.targetShortcut) != CommonSharedConstants::VK_DISABLED)
|
if (std::get<DWORD>(it->second.targetShortcut) != CommonSharedConstants::VK_DISABLED)
|
||||||
{
|
{
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modifier state reset might be required for this key depending on the shortcut's action and target modifier - ex: Win+Caps -> Ctrl
|
// Modifier state reset might be required for this key depending on the shortcut's action and target modifier - ex: Win+Caps -> Ctrl
|
||||||
@ -468,29 +441,14 @@ namespace KeyboardEventHandlers
|
|||||||
// Remapped to text
|
// Remapped to text
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
key_count = KeyboardManagerConstants::DUMMY_KEY_EVENT_SIZE + src_size;
|
auto& remapping = std::get<std::wstring>(it->second.targetShortcut);
|
||||||
|
|
||||||
auto remapping = std::get<std::wstring>(it->second.targetShortcut);
|
Helpers::SetDummyKeyEvent(keyEventList, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
const UINT inputEventCount = static_cast<UINT>(remapping.length() * 2);
|
|
||||||
key_count += inputEventCount;
|
|
||||||
|
|
||||||
keyEventList = new INPUT[key_count]{};
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
Helpers::SetDummyKeyEvent(keyEventList, i, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
|
||||||
|
|
||||||
// Release original shortcut state (release in reverse order of shortcut to be accurate)
|
// Release original shortcut state (release in reverse order of shortcut to be accurate)
|
||||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
|
|
||||||
for (size_t idx = 0; idx < inputEventCount; ++idx)
|
Helpers::SetTextKeyEvents(keyEventList, remapping);
|
||||||
{
|
|
||||||
auto& input = keyEventList[idx + i];
|
|
||||||
input.type = INPUT_KEYBOARD;
|
|
||||||
const bool upEvent = idx & 0x1;
|
|
||||||
input.ki.dwFlags = KEYEVENTF_UNICODE | (upEvent ? KEYEVENTF_KEYUP : 0);
|
|
||||||
input.ki.dwExtraInfo = KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG;
|
|
||||||
input.ki.wScan = remapping[idx >> 1];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
it->second.isShortcutInvoked = true;
|
it->second.isShortcutInvoked = true;
|
||||||
@ -500,12 +458,9 @@ namespace KeyboardEventHandlers
|
|||||||
state.SetActivatedApp(*activatedApp);
|
state.SetActivatedApp(*activatedApp);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::trace(L"ChordKeyboardHandler:key_count:{}", key_count);
|
Logger::trace(L"ChordKeyboardHandler:keyEventList.size:{}", keyEventList.size());
|
||||||
|
|
||||||
UINT res = ii.SendVirtualInput(static_cast<UINT>(key_count), keyEventList, sizeof(INPUT));
|
ii.SendVirtualInput(keyEventList);
|
||||||
delete[] keyEventList;
|
|
||||||
|
|
||||||
// Send daily telemetry event for Keyboard Manager key activation.
|
|
||||||
if (activatedApp.has_value())
|
if (activatedApp.has_value())
|
||||||
{
|
{
|
||||||
if (remapToKey)
|
if (remapToKey)
|
||||||
@ -574,84 +529,41 @@ namespace KeyboardEventHandlers
|
|||||||
if ((it->first.CheckWinKey(data->lParam->vkCode) || it->first.CheckCtrlKey(data->lParam->vkCode) || it->first.CheckAltKey(data->lParam->vkCode) || it->first.CheckShiftKey(data->lParam->vkCode)) && (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP))
|
if ((it->first.CheckWinKey(data->lParam->vkCode) || it->first.CheckCtrlKey(data->lParam->vkCode) || it->first.CheckAltKey(data->lParam->vkCode) || it->first.CheckShiftKey(data->lParam->vkCode)) && (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP))
|
||||||
{
|
{
|
||||||
// Release new shortcut, and set original shortcut keys except the one released
|
// Release new shortcut, and set original shortcut keys except the one released
|
||||||
size_t key_count = 0;
|
std::vector<INPUT> keyEventList;
|
||||||
LPINPUT keyEventList = nullptr;
|
|
||||||
if (remapToShortcut && !isRunProgram)
|
if (remapToShortcut && !isRunProgram)
|
||||||
{
|
{
|
||||||
// if the released key is present in both shortcuts' modifiers (i.e part of the common modifiers)
|
|
||||||
if (std::get<Shortcut>(it->second.targetShortcut).CheckWinKey(data->lParam->vkCode) || std::get<Shortcut>(it->second.targetShortcut).CheckCtrlKey(data->lParam->vkCode) || std::get<Shortcut>(it->second.targetShortcut).CheckAltKey(data->lParam->vkCode) || std::get<Shortcut>(it->second.targetShortcut).CheckShiftKey(data->lParam->vkCode))
|
|
||||||
{
|
|
||||||
// release all new shortcut keys and the common released modifier except the other common modifiers, and add all original shortcut modifiers except the common ones, and dummy key
|
|
||||||
key_count = (dest_size - commonKeys) + (src_size - 1 - commonKeys) + KeyboardManagerConstants::DUMMY_KEY_EVENT_SIZE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// release all new shortcut keys except the common modifiers and add all original shortcut modifiers except the common ones, and dummy key
|
|
||||||
key_count = (dest_size - 1) + (src_size - 2) - (2 * static_cast<size_t>(commonKeys)) + KeyboardManagerConstants::DUMMY_KEY_EVENT_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the target shortcut's action key is pressed, then it should be released
|
// If the target shortcut's action key is pressed, then it should be released
|
||||||
bool isActionKeyPressed = false;
|
bool isActionKeyPressed = ii.GetVirtualKeyState(std::get<Shortcut>(it->second.targetShortcut).GetActionKey());
|
||||||
if (ii.GetVirtualKeyState((std::get<Shortcut>(it->second.targetShortcut).GetActionKey())))
|
|
||||||
{
|
|
||||||
isActionKeyPressed = true;
|
|
||||||
key_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
keyEventList = new INPUT[key_count]{};
|
|
||||||
|
|
||||||
// Release new shortcut state (release in reverse order of shortcut to be accurate)
|
// Release new shortcut state (release in reverse order of shortcut to be accurate)
|
||||||
int i = 0;
|
|
||||||
if (isActionKeyPressed)
|
if (isActionKeyPressed)
|
||||||
{
|
{
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first, data->lParam->vkCode);
|
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first, data->lParam->vkCode);
|
||||||
|
|
||||||
// Set original shortcut key down state except the action key and the released modifier since the original action key may or may not be held down. If it is held down it will generate it's own key message
|
// Set original shortcut key down state except the action key and the released modifier since the original action key may or may not be held down. If it is held down it will generate it's own key message
|
||||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut), data->lParam->vkCode);
|
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut), data->lParam->vkCode);
|
||||||
|
|
||||||
// Send a dummy key event to prevent modifier press+release from being triggered. 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
|
// Send a dummy key event to prevent modifier press+release from being triggered. 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
|
||||||
Helpers::SetDummyKeyEvent(keyEventList, i, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetDummyKeyEvent(keyEventList, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
}
|
}
|
||||||
else if (remapToKey)
|
else if (remapToKey)
|
||||||
{
|
{
|
||||||
// 1 for releasing new key and original shortcut modifiers except the one released and dummy key
|
bool isTargetKeyPressed = (std::get<DWORD>(it->second.targetShortcut) != CommonSharedConstants::VK_DISABLED) && ii.GetVirtualKeyState(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)));
|
||||||
key_count = dest_size + src_size - 2 + KeyboardManagerConstants::DUMMY_KEY_EVENT_SIZE;
|
|
||||||
bool isTargetKeyPressed = false;
|
|
||||||
|
|
||||||
// Do not send Disable key up
|
|
||||||
if (std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)
|
|
||||||
{
|
|
||||||
key_count--;
|
|
||||||
}
|
|
||||||
else if (ii.GetVirtualKeyState(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))))
|
|
||||||
{
|
|
||||||
isTargetKeyPressed = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
isTargetKeyPressed = false;
|
|
||||||
key_count--;
|
|
||||||
}
|
|
||||||
|
|
||||||
keyEventList = new INPUT[key_count]{};
|
|
||||||
|
|
||||||
// Release new key state
|
// Release new key state
|
||||||
int i = 0;
|
|
||||||
if (std::get<DWORD>(it->second.targetShortcut) != CommonSharedConstants::VK_DISABLED && isTargetKeyPressed)
|
if (std::get<DWORD>(it->second.targetShortcut) != CommonSharedConstants::VK_DISABLED && isTargetKeyPressed)
|
||||||
{
|
{
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set original shortcut key down state except the action key and the released modifier since the original action key may or may not be held down. If it is held down it will generate it's own key message
|
// Set original shortcut key down state except the action key and the released modifier since the original action key may or may not be held down. If it is held down it will generate it's own key message
|
||||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, Shortcut(), data->lParam->vkCode);
|
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, Shortcut(), data->lParam->vkCode);
|
||||||
|
|
||||||
// Send a dummy key event to prevent modifier press+release from being triggered. Example: Win+Ctrl+A->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
|
// Send a dummy key event to prevent modifier press+release from being triggered. Example: Win+Ctrl+A->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
|
||||||
Helpers::SetDummyKeyEvent(keyEventList, i, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetDummyKeyEvent(keyEventList, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the remap state
|
// Reset the remap state
|
||||||
@ -665,12 +577,7 @@ namespace KeyboardEventHandlers
|
|||||||
state.SetActivatedApp(KeyboardManagerConstants::NoActivatedApp);
|
state.SetActivatedApp(KeyboardManagerConstants::NoActivatedApp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// key count can be 0 if both shortcuts have same modifiers and the action key is not held down. delete will throw an error if keyEventList is empty
|
ii.SendVirtualInput(keyEventList);
|
||||||
if (key_count > 0)
|
|
||||||
{
|
|
||||||
UINT res = ii.SendVirtualInput(static_cast<UINT>(key_count), keyEventList, sizeof(INPUT));
|
|
||||||
delete[] keyEventList;
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,7 +585,7 @@ namespace KeyboardEventHandlers
|
|||||||
if (!remapToShortcut || (remapToShortcut && std::get<Shortcut>(it->second.targetShortcut).CheckModifiersKeyboardState(ii)))
|
if (!remapToShortcut || (remapToShortcut && std::get<Shortcut>(it->second.targetShortcut).CheckModifiersKeyboardState(ii)))
|
||||||
{
|
{
|
||||||
// Case 2: If the original shortcut is still held down the keyboard will get a key down message of the action key in the original shortcut and the new shortcut's modifiers will be held down (keys held down send repeated keydown messages)
|
// Case 2: If the original shortcut is still held down the keyboard will get a key down message of the action key in the original shortcut and the new shortcut's modifiers will be held down (keys held down send repeated keydown messages)
|
||||||
if (((data->lParam->vkCode == it->first.GetActionKey() && !it->first.HasChord())||(data->lParam->vkCode == it->first.GetSecondKey() && it->first.HasChord())) && (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN))
|
if (((data->lParam->vkCode == it->first.GetActionKey() && !it->first.HasChord()) || (data->lParam->vkCode == it->first.GetSecondKey() && it->first.HasChord())) && (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN))
|
||||||
{
|
{
|
||||||
// In case of mapping to disable do not send anything
|
// In case of mapping to disable do not send anything
|
||||||
if (remapToKey && std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)
|
if (remapToKey && std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)
|
||||||
@ -688,69 +595,46 @@ namespace KeyboardEventHandlers
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t key_count = 1;
|
std::vector<INPUT> keyEventList;
|
||||||
LPINPUT keyEventList = nullptr;
|
|
||||||
if (remapToShortcut)
|
if (remapToShortcut)
|
||||||
{
|
{
|
||||||
keyEventList = new INPUT[key_count]{};
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
|
||||||
}
|
}
|
||||||
else if (remapToKey)
|
else if (remapToKey)
|
||||||
{
|
{
|
||||||
keyEventList = new INPUT[key_count]{};
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
|
||||||
}
|
}
|
||||||
else if (remapToText)
|
else if (remapToText)
|
||||||
{
|
{
|
||||||
auto remapping = std::get<std::wstring>(it->second.targetShortcut);
|
auto& remapping = std::get<std::wstring>(it->second.targetShortcut);
|
||||||
const UINT inputEventCount = static_cast<UINT>(remapping.length() * 2);
|
Helpers::SetTextKeyEvents(keyEventList, remapping);
|
||||||
key_count = inputEventCount;
|
|
||||||
keyEventList = new INPUT[key_count]{};
|
|
||||||
|
|
||||||
for (size_t idx = 0; idx < inputEventCount; ++idx)
|
|
||||||
{
|
|
||||||
auto& input = keyEventList[idx];
|
|
||||||
input.type = INPUT_KEYBOARD;
|
|
||||||
const bool upEvent = idx & 0x1;
|
|
||||||
input.ki.dwFlags = KEYEVENTF_UNICODE | (upEvent ? KEYEVENTF_KEYUP : 0);
|
|
||||||
input.ki.dwExtraInfo = KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG;
|
|
||||||
input.ki.wScan = remapping[idx >> 1];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT res = ii.SendVirtualInput(static_cast<UINT>(key_count), keyEventList, sizeof(INPUT));
|
ii.SendVirtualInput(keyEventList);
|
||||||
delete[] keyEventList;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case 3: If the action key is released from the original shortcut, keep modifiers of the new shortcut until some other key event which doesn't apply to the original shortcut
|
// Case 3: If the action key is released from the original shortcut, keep modifiers of the new shortcut until some other key event which doesn't apply to the original shortcut
|
||||||
if (!remapToText && ((!it->first.HasChord() && data->lParam->vkCode == it->first.GetActionKey()) || (it->first.HasChord() && data->lParam->vkCode==it->first.GetSecondKey())) && (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP))
|
if (!remapToText && ((!it->first.HasChord() && data->lParam->vkCode == it->first.GetActionKey()) || (it->first.HasChord() && data->lParam->vkCode == it->first.GetSecondKey())) && (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP))
|
||||||
{
|
{
|
||||||
size_t key_count = 1;
|
std::vector<INPUT> keyEventList;
|
||||||
LPINPUT keyEventList = nullptr;
|
|
||||||
if (remapToShortcut && !it->first.HasChord())
|
if (remapToShortcut && !it->first.HasChord())
|
||||||
{
|
{
|
||||||
// Just lift the action key for no chords.
|
// Just lift the action key for no chords.
|
||||||
keyEventList = new INPUT[key_count]{};
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
|
||||||
}
|
}
|
||||||
else if (remapToShortcut && it->first.HasChord())
|
else if (remapToShortcut && it->first.HasChord())
|
||||||
{
|
{
|
||||||
// If it has a chord, we'll want a full clean contemplated in the else, since you can't really repeat chords by pressing the end key again.
|
// If it has a chord, we'll want a full clean contemplated in the else, since you can't really repeat chords by pressing the end key again.
|
||||||
|
|
||||||
// Key up for all new shortcut keys, key down for original shortcut modifiers and current key press but common keys aren't repeated
|
// Key up for all new shortcut keys, key down for original shortcut modifiers and current key press but common keys aren't repeated
|
||||||
key_count = (dest_size) + (src_size +1) - (2 * static_cast<size_t>(commonKeys));
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
keyEventList = new INPUT[key_count]{};
|
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
|
||||||
i++;
|
|
||||||
|
|
||||||
// Release new shortcut state (release in reverse order of shortcut to be accurate)
|
// Release new shortcut state (release in reverse order of shortcut to be accurate)
|
||||||
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
|
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
|
||||||
|
|
||||||
// Set old shortcut key down state
|
// Set old shortcut key down state
|
||||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut));
|
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut));
|
||||||
|
|
||||||
// Reset the remap state
|
// Reset the remap state
|
||||||
it->second.isShortcutInvoked = false;
|
it->second.isShortcutInvoked = false;
|
||||||
@ -762,7 +646,6 @@ namespace KeyboardEventHandlers
|
|||||||
{
|
{
|
||||||
state.SetActivatedApp(KeyboardManagerConstants::NoActivatedApp);
|
state.SetActivatedApp(KeyboardManagerConstants::NoActivatedApp);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)
|
else if (std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)
|
||||||
{
|
{
|
||||||
@ -779,29 +662,21 @@ namespace KeyboardEventHandlers
|
|||||||
// If the keyboard state is clear, we release the target key but do not reset the remap state
|
// If the keyboard state is clear, we release the target key but do not reset the remap state
|
||||||
if (isKeyboardStateClear)
|
if (isKeyboardStateClear)
|
||||||
{
|
{
|
||||||
keyEventList = new INPUT[key_count]{};
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If any other key is pressed, then the keyboard state must be reverted back to the physical keys.
|
// If any other key is pressed, then the keyboard state must be reverted back to the physical keys.
|
||||||
// This is to take cases like Ctrl+A->D remap and user presses B+Ctrl+A and releases A, or Ctrl+A+B and releases A
|
// This is to take cases like Ctrl+A->D remap and user presses B+Ctrl+A and releases A, or Ctrl+A+B and releases A
|
||||||
|
|
||||||
// 1 for releasing new key and original shortcut modifiers, and dummy key
|
|
||||||
key_count = dest_size + (src_size - 1) + KeyboardManagerConstants::DUMMY_KEY_EVENT_SIZE;
|
|
||||||
|
|
||||||
keyEventList = new INPUT[key_count]{};
|
|
||||||
|
|
||||||
// Release new key state
|
// Release new key state
|
||||||
int i = 0;
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
|
||||||
i++;
|
|
||||||
|
|
||||||
// Set original shortcut key down state except the action key
|
// Set original shortcut key down state except the action key
|
||||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
|
|
||||||
// Send a dummy key event to prevent modifier press+release from being triggered. 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
|
// Send a dummy key event to prevent modifier press+release from being triggered. 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
|
||||||
Helpers::SetDummyKeyEvent(keyEventList, i, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetDummyKeyEvent(keyEventList, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
|
|
||||||
// Reset the remap state
|
// Reset the remap state
|
||||||
it->second.isShortcutInvoked = false;
|
it->second.isShortcutInvoked = false;
|
||||||
@ -816,8 +691,7 @@ namespace KeyboardEventHandlers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT res = ii.SendVirtualInput(static_cast<UINT>(key_count), keyEventList, sizeof(INPUT));
|
ii.SendVirtualInput(keyEventList);
|
||||||
delete[] keyEventList;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -854,8 +728,7 @@ namespace KeyboardEventHandlers
|
|||||||
ResetIfModifierKeyForLowerLevelKeyHandlers(ii, data->lParam->vkCode, std::get<Shortcut>(it->second.targetShortcut).GetActionKey());
|
ResetIfModifierKeyForLowerLevelKeyHandlers(ii, data->lParam->vkCode, std::get<Shortcut>(it->second.targetShortcut).GetActionKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t key_count;
|
std::vector<INPUT> keyEventList;
|
||||||
LPINPUT keyEventList = nullptr;
|
|
||||||
|
|
||||||
// Check if a new remapping should be applied
|
// Check if a new remapping should be applied
|
||||||
Shortcut currentlyPressed = it->first;
|
Shortcut currentlyPressed = it->first;
|
||||||
@ -868,40 +741,25 @@ namespace KeyboardEventHandlers
|
|||||||
if (newRemapping.RemapToKey())
|
if (newRemapping.RemapToKey())
|
||||||
{
|
{
|
||||||
DWORD to = std::get<0>(newRemapping.targetShortcut);
|
DWORD to = std::get<0>(newRemapping.targetShortcut);
|
||||||
bool isLastKeyStillPressed = ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey));
|
Helpers::SetModifierKeyEvents(from, it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
key_count = static_cast<size_t>(from.Size()) - 1 + 1 + (isLastKeyStillPressed ? 1 : 0);
|
|
||||||
keyEventList = new INPUT[key_count]{};
|
|
||||||
int i = 0;
|
|
||||||
Helpers::SetModifierKeyEvents(from, it->second.winKeyInvoked, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
|
||||||
if (ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey)))
|
if (ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey)))
|
||||||
{
|
{
|
||||||
// If the action key from the last shortcut is still being pressed, release it.
|
// If the action key from the last shortcut is still being pressed, release it.
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(from.actionKey), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(from.actionKey), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(to), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(to), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Shortcut to = std::get<Shortcut>(newRemapping.targetShortcut);
|
Shortcut to = std::get<Shortcut>(newRemapping.targetShortcut);
|
||||||
bool isLastKeyStillPressed = ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey));
|
Helpers::SetModifierKeyEvents(from, it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, to);
|
||||||
|
|
||||||
size_t temp_key_count_calculation = static_cast<size_t>(from.Size()) - 1;
|
|
||||||
temp_key_count_calculation += static_cast<size_t>(to.Size()) - 1;
|
|
||||||
temp_key_count_calculation -= static_cast<size_t>(2) * from.GetCommonModifiersCount(to);
|
|
||||||
key_count = temp_key_count_calculation + 1 + (isLastKeyStillPressed ? 1 : 0);
|
|
||||||
keyEventList = new INPUT[key_count]{};
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
Helpers::SetModifierKeyEvents(from, it->second.winKeyInvoked, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, to);
|
|
||||||
if (ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey)))
|
if (ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey)))
|
||||||
{
|
{
|
||||||
// If the action key from the last shortcut is still being pressed, release it.
|
// If the action key from the last shortcut is still being pressed, release it.
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(from.actionKey), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(from.actionKey), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
Helpers::SetModifierKeyEvents(to, it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, from);
|
Helpers::SetModifierKeyEvents(to, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, from);
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(to.actionKey), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(to.actionKey), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
newRemapping.isShortcutInvoked = true;
|
newRemapping.isShortcutInvoked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -917,41 +775,27 @@ namespace KeyboardEventHandlers
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Key up for all new shortcut keys, key down for original shortcut modifiers and current key press but common keys aren't repeated
|
|
||||||
key_count = (dest_size) + (src_size - 1) - (2 * static_cast<size_t>(commonKeys));
|
|
||||||
|
|
||||||
// If the target shortcut's action key is pressed, then it should be released and original shortcut's action key should be set
|
// If the target shortcut's action key is pressed, then it should be released and original shortcut's action key should be set
|
||||||
bool isActionKeyPressed = false;
|
bool isActionKeyPressed = ii.GetVirtualKeyState(std::get<Shortcut>(it->second.targetShortcut).GetActionKey());
|
||||||
if (ii.GetVirtualKeyState((std::get<Shortcut>(it->second.targetShortcut).GetActionKey())))
|
|
||||||
{
|
|
||||||
isActionKeyPressed = true;
|
|
||||||
key_count += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
keyEventList = new INPUT[key_count]{};
|
|
||||||
|
|
||||||
// Release new shortcut state (release in reverse order of shortcut to be accurate)
|
// Release new shortcut state (release in reverse order of shortcut to be accurate)
|
||||||
int i = 0;
|
|
||||||
if (isActionKeyPressed)
|
if (isActionKeyPressed)
|
||||||
{
|
{
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
|
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
|
||||||
|
|
||||||
// Set old shortcut key down state
|
// Set old shortcut key down state
|
||||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut));
|
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut));
|
||||||
|
|
||||||
// key down for original shortcut action key with shortcut flag so that we don't invoke the same shortcut remap again
|
// key down for original shortcut action key with shortcut flag so that we don't invoke the same shortcut remap again
|
||||||
if (isActionKeyPressed)
|
if (isActionKeyPressed)
|
||||||
{
|
{
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(it->first.GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(it->first.GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send current key pressed without shortcut flag so that it can be reprocessed in case the physical keys pressed are a different remapped shortcut
|
// Send current key pressed without shortcut flag so that it can be reprocessed in case the physical keys pressed are a different remapped shortcut
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(data->lParam->vkCode), 0, 0);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(data->lParam->vkCode), 0, 0);
|
||||||
i++;
|
|
||||||
|
|
||||||
// Do not send a dummy key as we want the current key press to behave as normal i.e. it can do press+release functionality if required. Required to allow a shortcut to Win key remap invoked directly after shortcut to shortcut is released to open start menu
|
// Do not send a dummy key as we want the current key press to behave as normal i.e. it can do press+release functionality if required. Required to allow a shortcut to Win key remap invoked directly after shortcut to shortcut is released to open start menu
|
||||||
}
|
}
|
||||||
@ -967,8 +811,7 @@ namespace KeyboardEventHandlers
|
|||||||
state.SetActivatedApp(KeyboardManagerConstants::NoActivatedApp);
|
state.SetActivatedApp(KeyboardManagerConstants::NoActivatedApp);
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT res = ii.SendVirtualInput(static_cast<UINT>(key_count), keyEventList, sizeof(INPUT));
|
ii.SendVirtualInput(keyEventList);
|
||||||
delete[] keyEventList;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1003,30 +846,20 @@ namespace KeyboardEventHandlers
|
|||||||
|
|
||||||
if (isRemapToDisable || !isOriginalActionKeyPressed)
|
if (isRemapToDisable || !isOriginalActionKeyPressed)
|
||||||
{
|
{
|
||||||
// Key down for original shortcut modifiers and action key, and current key press
|
std::vector<INPUT> keyEventList;
|
||||||
size_t key_count = src_size + 1;
|
|
||||||
|
|
||||||
LPINPUT keyEventList = new INPUT[key_count]{};
|
|
||||||
|
|
||||||
// Set original shortcut key down state
|
// Set original shortcut key down state
|
||||||
int i = 0;
|
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
|
||||||
|
|
||||||
// Send the original action key only if it is physically pressed. For remappings to keys other than disabled we already check earlier that it is not pressed in this scenario. For remap to disable
|
// Send the original action key only if it is physically pressed. For remappings to keys other than disabled we already check earlier that it is not pressed in this scenario. For remap to disable
|
||||||
if (isRemapToDisable && isOriginalActionKeyPressed)
|
if (isRemapToDisable && isOriginalActionKeyPressed)
|
||||||
{
|
{
|
||||||
// Set original action key
|
// Set original action key
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(it->first.GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(it->first.GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||||
i++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
key_count--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send current key pressed without shortcut flag so that it can be reprocessed in case the physical keys pressed are a different remapped shortcut
|
// Send current key pressed without shortcut flag so that it can be reprocessed in case the physical keys pressed are a different remapped shortcut
|
||||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(data->lParam->vkCode), 0, 0);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(data->lParam->vkCode), 0, 0);
|
||||||
i++;
|
|
||||||
|
|
||||||
// Do not send a dummy key as we want the current key press to behave as normal i.e. it can do press+release functionality if required. Required to allow a shortcut to Win key remap invoked directly after another shortcut to key remap is released to open start menu
|
// Do not send a dummy key as we want the current key press to behave as normal i.e. it can do press+release functionality if required. Required to allow a shortcut to Win key remap invoked directly after another shortcut to key remap is released to open start menu
|
||||||
|
|
||||||
@ -1041,8 +874,7 @@ namespace KeyboardEventHandlers
|
|||||||
state.SetActivatedApp(KeyboardManagerConstants::NoActivatedApp);
|
state.SetActivatedApp(KeyboardManagerConstants::NoActivatedApp);
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT res = ii.SendVirtualInput(static_cast<UINT>(key_count), keyEventList, sizeof(INPUT));
|
ii.SendVirtualInput(keyEventList);
|
||||||
delete[] keyEventList;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1344,7 +1176,7 @@ namespace KeyboardEventHandlers
|
|||||||
|
|
||||||
if (targetPid != 0 && shortcut.alreadyRunningAction != Shortcut::ProgramAlreadyRunningAction::StartAnother)
|
if (targetPid != 0 && shortcut.alreadyRunningAction != Shortcut::ProgramAlreadyRunningAction::StartAnother)
|
||||||
{
|
{
|
||||||
if (shortcut.alreadyRunningAction == Shortcut::ProgramAlreadyRunningAction::EndTask)
|
if (shortcut.alreadyRunningAction == Shortcut::ProgramAlreadyRunningAction::EndTask)
|
||||||
{
|
{
|
||||||
TerminateProcessesByName(fileNamePart);
|
TerminateProcessesByName(fileNamePart);
|
||||||
return;
|
return;
|
||||||
@ -1803,13 +1635,11 @@ namespace KeyboardEventHandlers
|
|||||||
// If the argument is either of the Ctrl/Shift/Alt modifier key codes
|
// If the argument is either of the Ctrl/Shift/Alt modifier key codes
|
||||||
if (Helpers::IsModifierKey(key) && !(key == VK_LWIN || key == VK_RWIN || key == CommonSharedConstants::VK_WIN_BOTH))
|
if (Helpers::IsModifierKey(key) && !(key == VK_LWIN || key == VK_RWIN || key == CommonSharedConstants::VK_WIN_BOTH))
|
||||||
{
|
{
|
||||||
int key_count = 1;
|
std::vector<INPUT> keyEventList;
|
||||||
LPINPUT keyEventList = new INPUT[size_t(key_count)]{};
|
|
||||||
|
|
||||||
// Use the suppress flag to ensure these are not intercepted by any remapped keys or shortcuts
|
// Use the suppress flag to ensure these are not intercepted by any remapped keys or shortcuts
|
||||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(key), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(key), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG);
|
||||||
UINT res = ii.SendVirtualInput(static_cast<UINT>(key_count), keyEventList, sizeof(INPUT));
|
ii.SendVirtualInput(keyEventList);
|
||||||
delete[] keyEventList;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1834,21 +1664,9 @@ namespace KeyboardEventHandlers
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t keyCount = remapping->length();
|
std::vector<INPUT> keyEventList;
|
||||||
const UINT eventCount = static_cast<UINT>(keyCount * 2);
|
Helpers::SetTextKeyEvents(keyEventList, *remapping);
|
||||||
auto keyEventList = std::make_unique<INPUT[]>(keyCount * 2);
|
ii.SendVirtualInput(keyEventList);
|
||||||
|
|
||||||
for (size_t i = 0; i < eventCount; ++i)
|
|
||||||
{
|
|
||||||
auto& input = keyEventList[i];
|
|
||||||
input.type = INPUT_KEYBOARD;
|
|
||||||
const bool upEvent = i & 0x1;
|
|
||||||
input.ki.dwFlags = KEYEVENTF_UNICODE | (upEvent ? KEYEVENTF_KEYUP : 0);
|
|
||||||
input.ki.dwExtraInfo = KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG;
|
|
||||||
input.ki.wScan = (*remapping)[i >> 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT res = ii.SendVirtualInput(eventCount, keyEventList.get(), sizeof(INPUT));
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -51,15 +51,13 @@ namespace RemappingLogicTests
|
|||||||
// Set the testApp as the foreground process
|
// Set the testApp as the foreground process
|
||||||
mockedInputHandler.SetForegroundProcess(testApp1);
|
mockedInputHandler.SetForegroundProcess(testApp1);
|
||||||
|
|
||||||
const int nInputs = 2;
|
std::vector<INPUT> inputs{
|
||||||
INPUT input[nInputs] = {};
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } },
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }
|
||||||
input[0].ki.wVk = VK_CONTROL;
|
};
|
||||||
input[1].type = INPUT_KEYBOARD;
|
|
||||||
input[1].ki.wVk = 0x41;
|
|
||||||
|
|
||||||
// Send Ctrl+A keydown
|
// Send Ctrl+A keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs);
|
||||||
|
|
||||||
// Ctrl and A key states should be unchanged, Alt and V key states should be true
|
// Ctrl and A key states should be unchanged, Alt and V key states should be true
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false);
|
||||||
@ -83,15 +81,13 @@ namespace RemappingLogicTests
|
|||||||
// Set the testApp as the foreground process
|
// Set the testApp as the foreground process
|
||||||
mockedInputHandler.SetForegroundProcess(testApp2);
|
mockedInputHandler.SetForegroundProcess(testApp2);
|
||||||
|
|
||||||
const int nInputs = 2;
|
std::vector<INPUT> inputs{
|
||||||
INPUT input[nInputs] = {};
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } },
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }
|
||||||
input[0].ki.wVk = VK_CONTROL;
|
};
|
||||||
input[1].type = INPUT_KEYBOARD;
|
|
||||||
input[1].ki.wVk = 0x41;
|
|
||||||
|
|
||||||
// Send Ctrl+A keydown
|
// Send Ctrl+A keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs);
|
||||||
|
|
||||||
// Ctrl and A key states should be true, Alt and V key states should be false
|
// Ctrl and A key states should be true, Alt and V key states should be false
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true);
|
||||||
@ -115,28 +111,24 @@ namespace RemappingLogicTests
|
|||||||
// Set the testApp as the foreground process
|
// Set the testApp as the foreground process
|
||||||
mockedInputHandler.SetForegroundProcess(testApp1);
|
mockedInputHandler.SetForegroundProcess(testApp1);
|
||||||
|
|
||||||
const int nInputs = 2;
|
std::vector<INPUT> inputs1{
|
||||||
INPUT input[nInputs] = {};
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } },
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }
|
||||||
input[0].ki.wVk = VK_CONTROL;
|
};
|
||||||
input[1].type = INPUT_KEYBOARD;
|
|
||||||
input[1].ki.wVk = 0x41;
|
|
||||||
|
|
||||||
// Send Ctrl+A keydown
|
// Send Ctrl+A keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs1);
|
||||||
|
|
||||||
// Activated app should be testApp1
|
// Activated app should be testApp1
|
||||||
Assert::AreEqual(testApp1, testState.GetActivatedApp());
|
Assert::AreEqual(testApp1, testState.GetActivatedApp());
|
||||||
|
|
||||||
input[0].type = INPUT_KEYBOARD;
|
std::vector<INPUT> inputs2{
|
||||||
input[0].ki.wVk = 0x41;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } },
|
||||||
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }
|
||||||
input[1].type = INPUT_KEYBOARD;
|
};
|
||||||
input[1].ki.wVk = VK_CONTROL;
|
|
||||||
input[1].ki.dwFlags = KEYEVENTF_KEYUP;
|
|
||||||
|
|
||||||
// Release A then Ctrl
|
// Release A then Ctrl
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs2);
|
||||||
|
|
||||||
// Activated app should be empty string
|
// Activated app should be empty string
|
||||||
Assert::AreEqual(std::wstring(KeyboardManagerConstants::NoActivatedApp), testState.GetActivatedApp());
|
Assert::AreEqual(std::wstring(KeyboardManagerConstants::NoActivatedApp), testState.GetActivatedApp());
|
||||||
@ -156,28 +148,24 @@ namespace RemappingLogicTests
|
|||||||
// Set the testApp as the foreground process
|
// Set the testApp as the foreground process
|
||||||
mockedInputHandler.SetForegroundProcess(testApp1);
|
mockedInputHandler.SetForegroundProcess(testApp1);
|
||||||
|
|
||||||
const int nInputs = 2;
|
std::vector<INPUT> inputs1{
|
||||||
INPUT input[nInputs] = {};
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } },
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }
|
||||||
input[0].ki.wVk = VK_CONTROL;
|
};
|
||||||
input[1].type = INPUT_KEYBOARD;
|
|
||||||
input[1].ki.wVk = 0x41;
|
|
||||||
|
|
||||||
// Send Ctrl+A keydown
|
// Send Ctrl+A keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs1);
|
||||||
|
|
||||||
// Set the testApp as the foreground process
|
// Set the testApp as the foreground process
|
||||||
mockedInputHandler.SetForegroundProcess(testApp2);
|
mockedInputHandler.SetForegroundProcess(testApp2);
|
||||||
|
|
||||||
input[0].type = INPUT_KEYBOARD;
|
std::vector<INPUT> inputs2{
|
||||||
input[0].ki.wVk = 0x41;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } },
|
||||||
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }
|
||||||
input[1].type = INPUT_KEYBOARD;
|
};
|
||||||
input[1].ki.wVk = VK_CONTROL;
|
|
||||||
input[1].ki.dwFlags = KEYEVENTF_KEYUP;
|
|
||||||
|
|
||||||
// Release A then Ctrl
|
// Release A then Ctrl
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs2);
|
||||||
|
|
||||||
// Ctrl, A, Alt and Tab should all be false
|
// Ctrl, A, Alt and Tab should all be false
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false);
|
||||||
@ -198,15 +186,13 @@ namespace RemappingLogicTests
|
|||||||
// Set the testApp as the foreground process
|
// Set the testApp as the foreground process
|
||||||
mockedInputHandler.SetForegroundProcess(testApp1);
|
mockedInputHandler.SetForegroundProcess(testApp1);
|
||||||
|
|
||||||
const int nInputs = 2;
|
std::vector<INPUT> inputs{
|
||||||
INPUT input[nInputs] = {};
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } },
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }
|
||||||
input[0].ki.wVk = VK_CONTROL;
|
};
|
||||||
input[1].type = INPUT_KEYBOARD;
|
|
||||||
input[1].ki.wVk = 0x41;
|
|
||||||
|
|
||||||
// Send Ctrl+A keydown
|
// Send Ctrl+A keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs);
|
||||||
|
|
||||||
// Ctrl and A key states should be unchanged, V key states should be true
|
// Ctrl and A key states should be unchanged, V key states should be true
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false);
|
||||||
@ -226,15 +212,13 @@ namespace RemappingLogicTests
|
|||||||
// Set the testApp as the foreground process
|
// Set the testApp as the foreground process
|
||||||
mockedInputHandler.SetForegroundProcess(testApp2);
|
mockedInputHandler.SetForegroundProcess(testApp2);
|
||||||
|
|
||||||
const int nInputs = 2;
|
std::vector<INPUT> inputs{
|
||||||
INPUT input[nInputs] = {};
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } },
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }
|
||||||
input[0].ki.wVk = VK_CONTROL;
|
};
|
||||||
input[1].type = INPUT_KEYBOARD;
|
|
||||||
input[1].ki.wVk = 0x41;
|
|
||||||
|
|
||||||
// Send Ctrl+A keydown
|
// Send Ctrl+A keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs);
|
||||||
|
|
||||||
// Ctrl and A key states should be true, V key state should be false
|
// Ctrl and A key states should be true, V key state should be false
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true);
|
||||||
@ -254,28 +238,24 @@ namespace RemappingLogicTests
|
|||||||
// Set the testApp as the foreground process
|
// Set the testApp as the foreground process
|
||||||
mockedInputHandler.SetForegroundProcess(testApp1);
|
mockedInputHandler.SetForegroundProcess(testApp1);
|
||||||
|
|
||||||
const int nInputs = 2;
|
std::vector<INPUT> inputs1{
|
||||||
INPUT input[nInputs] = {};
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } },
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }
|
||||||
input[0].ki.wVk = VK_CONTROL;
|
};
|
||||||
input[1].type = INPUT_KEYBOARD;
|
|
||||||
input[1].ki.wVk = 0x41;
|
|
||||||
|
|
||||||
// Send Ctrl+A keydown
|
// Send Ctrl+A keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs1);
|
||||||
|
|
||||||
// Activated app should be testApp1
|
// Activated app should be testApp1
|
||||||
Assert::AreEqual(testApp1, testState.GetActivatedApp());
|
Assert::AreEqual(testApp1, testState.GetActivatedApp());
|
||||||
|
|
||||||
input[0].type = INPUT_KEYBOARD;
|
std::vector<INPUT> inputs2{
|
||||||
input[0].ki.wVk = 0x41;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } },
|
||||||
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }
|
||||||
input[1].type = INPUT_KEYBOARD;
|
};
|
||||||
input[1].ki.wVk = VK_CONTROL;
|
|
||||||
input[1].ki.dwFlags = KEYEVENTF_KEYUP;
|
|
||||||
|
|
||||||
// Release A then Ctrl
|
// Release A then Ctrl
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs2);
|
||||||
|
|
||||||
// Activated app should be empty string
|
// Activated app should be empty string
|
||||||
Assert::AreEqual(std::wstring(KeyboardManagerConstants::NoActivatedApp), testState.GetActivatedApp());
|
Assert::AreEqual(std::wstring(KeyboardManagerConstants::NoActivatedApp), testState.GetActivatedApp());
|
||||||
@ -292,28 +272,24 @@ namespace RemappingLogicTests
|
|||||||
// Set the testApp as the foreground process
|
// Set the testApp as the foreground process
|
||||||
mockedInputHandler.SetForegroundProcess(testApp1);
|
mockedInputHandler.SetForegroundProcess(testApp1);
|
||||||
|
|
||||||
const int nInputs = 2;
|
std::vector<INPUT> inputs1{
|
||||||
INPUT input[nInputs] = {};
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } },
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } }
|
||||||
input[0].ki.wVk = VK_CONTROL;
|
};
|
||||||
input[1].type = INPUT_KEYBOARD;
|
|
||||||
input[1].ki.wVk = 0x41;
|
|
||||||
|
|
||||||
// Send Ctrl+A keydown
|
// Send Ctrl+A keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs1);
|
||||||
|
|
||||||
// Set the testApp as the foreground process
|
// Set the testApp as the foreground process
|
||||||
mockedInputHandler.SetForegroundProcess(testApp2);
|
mockedInputHandler.SetForegroundProcess(testApp2);
|
||||||
|
|
||||||
input[0].type = INPUT_KEYBOARD;
|
std::vector<INPUT> inputs2{
|
||||||
input[0].ki.wVk = 0x41;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } },
|
||||||
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL, .dwFlags = KEYEVENTF_KEYUP } }
|
||||||
input[1].type = INPUT_KEYBOARD;
|
};
|
||||||
input[1].ki.wVk = VK_CONTROL;
|
|
||||||
input[1].ki.dwFlags = KEYEVENTF_KEYUP;
|
|
||||||
|
|
||||||
// Release A then Ctrl
|
// Release A then Ctrl
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs2);
|
||||||
|
|
||||||
// Ctrl, A, V should all be false
|
// Ctrl, A, V should all be false
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false);
|
||||||
@ -334,15 +310,13 @@ namespace RemappingLogicTests
|
|||||||
// Set the testApp as the foreground process
|
// Set the testApp as the foreground process
|
||||||
mockedInputHandler.SetForegroundProcess(testApp1);
|
mockedInputHandler.SetForegroundProcess(testApp1);
|
||||||
|
|
||||||
const int nInputs = 2;
|
std::vector<INPUT> inputs{
|
||||||
INPUT input[nInputs] = {};
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } },
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = actionKey } }
|
||||||
input[0].ki.wVk = VK_CONTROL;
|
};
|
||||||
input[1].type = INPUT_KEYBOARD;
|
|
||||||
input[1].ki.wVk = actionKey;
|
|
||||||
|
|
||||||
// Send Ctrl+A keydown
|
// Send Ctrl+A keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs);
|
||||||
|
|
||||||
// Check if Ctrl+A is released and disable key was not send
|
// Check if Ctrl+A is released and disable key was not send
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false);
|
||||||
|
@ -10,15 +10,15 @@ void MockedInput::SetHookProc(std::function<intptr_t(LowlevelKeyboardEvent*)> ho
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Function to simulate keyboard input - arguments and return value based on SendInput function (https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-sendinput)
|
// Function to simulate keyboard input - arguments and return value based on SendInput function (https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-sendinput)
|
||||||
UINT MockedInput::SendVirtualInput(UINT cInputs, LPINPUT pInputs, int /*cbSize*/)
|
void MockedInput::SendVirtualInput(const std::vector<INPUT>& inputs)
|
||||||
{
|
{
|
||||||
// Iterate over inputs
|
// Iterate over inputs
|
||||||
for (UINT i = 0; i < cInputs; i++)
|
for (const INPUT& input : inputs)
|
||||||
{
|
{
|
||||||
LowlevelKeyboardEvent keyEvent;
|
LowlevelKeyboardEvent keyEvent{};
|
||||||
|
|
||||||
// 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
|
// 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
|
||||||
if (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP)
|
if (input.ki.dwFlags & KEYEVENTF_KEYUP)
|
||||||
{
|
{
|
||||||
if (keyboardState[VK_MENU] == true)
|
if (keyboardState[VK_MENU] == true)
|
||||||
{
|
{
|
||||||
@ -31,7 +31,7 @@ UINT MockedInput::SendVirtualInput(UINT cInputs, LPINPUT pInputs, int /*cbSize*/
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (pInputs[i].ki.wVk == VK_F10 || keyboardState[VK_MENU] == true)
|
if (input.ki.wVk == VK_F10 || keyboardState[VK_MENU] == true)
|
||||||
{
|
{
|
||||||
keyEvent.wParam = WM_SYSKEYDOWN;
|
keyEvent.wParam = WM_SYSKEYDOWN;
|
||||||
}
|
}
|
||||||
@ -43,8 +43,8 @@ UINT MockedInput::SendVirtualInput(UINT cInputs, LPINPUT pInputs, int /*cbSize*/
|
|||||||
KBDLLHOOKSTRUCT lParam = {};
|
KBDLLHOOKSTRUCT lParam = {};
|
||||||
|
|
||||||
// Set only vkCode and dwExtraInfo since other values are unused
|
// Set only vkCode and dwExtraInfo since other values are unused
|
||||||
lParam.vkCode = pInputs[i].ki.wVk;
|
lParam.vkCode = input.ki.wVk;
|
||||||
lParam.dwExtraInfo = pInputs[i].ki.dwExtraInfo;
|
lParam.dwExtraInfo = input.ki.dwExtraInfo;
|
||||||
keyEvent.lParam = &lParam;
|
keyEvent.lParam = &lParam;
|
||||||
|
|
||||||
// If the SendVirtualInput call condition is true, increment the count. If no condition is set then always increment the count
|
// If the SendVirtualInput call condition is true, increment the count. If no condition is set then always increment the count
|
||||||
@ -60,55 +60,53 @@ UINT MockedInput::SendVirtualInput(UINT cInputs, LPINPUT pInputs, int /*cbSize*/
|
|||||||
if (result == 0)
|
if (result == 0)
|
||||||
{
|
{
|
||||||
// If key up flag is set, then set keyboard state to false
|
// If key up flag is set, then set keyboard state to false
|
||||||
keyboardState[pInputs[i].ki.wVk] = (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
keyboardState[input.ki.wVk] = (input.ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
||||||
|
|
||||||
// Handling modifier key codes
|
// Handling modifier key codes
|
||||||
switch (pInputs[i].ki.wVk)
|
switch (input.ki.wVk)
|
||||||
{
|
{
|
||||||
case VK_CONTROL:
|
case VK_CONTROL:
|
||||||
if (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP)
|
if (input.ki.dwFlags & KEYEVENTF_KEYUP)
|
||||||
{
|
{
|
||||||
keyboardState[VK_LCONTROL] = false;
|
keyboardState[VK_LCONTROL] = false;
|
||||||
keyboardState[VK_RCONTROL] = false;
|
keyboardState[VK_RCONTROL] = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VK_LCONTROL:
|
case VK_LCONTROL:
|
||||||
keyboardState[VK_CONTROL] = (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
keyboardState[VK_CONTROL] = (input.ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
||||||
break;
|
break;
|
||||||
case VK_RCONTROL:
|
case VK_RCONTROL:
|
||||||
keyboardState[VK_CONTROL] = (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
keyboardState[VK_CONTROL] = (input.ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
||||||
break;
|
break;
|
||||||
case VK_MENU:
|
case VK_MENU:
|
||||||
if (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP)
|
if (input.ki.dwFlags & KEYEVENTF_KEYUP)
|
||||||
{
|
{
|
||||||
keyboardState[VK_LMENU] = false;
|
keyboardState[VK_LMENU] = false;
|
||||||
keyboardState[VK_RMENU] = false;
|
keyboardState[VK_RMENU] = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VK_LMENU:
|
case VK_LMENU:
|
||||||
keyboardState[VK_MENU] = (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
keyboardState[VK_MENU] = (input.ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
||||||
break;
|
break;
|
||||||
case VK_RMENU:
|
case VK_RMENU:
|
||||||
keyboardState[VK_MENU] = (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
keyboardState[VK_MENU] = (input.ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
||||||
break;
|
break;
|
||||||
case VK_SHIFT:
|
case VK_SHIFT:
|
||||||
if (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP)
|
if (input.ki.dwFlags & KEYEVENTF_KEYUP)
|
||||||
{
|
{
|
||||||
keyboardState[VK_LSHIFT] = false;
|
keyboardState[VK_LSHIFT] = false;
|
||||||
keyboardState[VK_RSHIFT] = false;
|
keyboardState[VK_RSHIFT] = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VK_LSHIFT:
|
case VK_LSHIFT:
|
||||||
keyboardState[VK_SHIFT] = (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
keyboardState[VK_SHIFT] = (input.ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
||||||
break;
|
break;
|
||||||
case VK_RSHIFT:
|
case VK_RSHIFT:
|
||||||
keyboardState[VK_SHIFT] = (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
keyboardState[VK_SHIFT] = (input.ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cInputs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to simulate keyboard hook behavior
|
// Function to simulate keyboard hook behavior
|
||||||
|
@ -34,7 +34,7 @@ namespace KeyboardManagerInput
|
|||||||
void SetHookProc(std::function<intptr_t(LowlevelKeyboardEvent*)> hookProcedure);
|
void SetHookProc(std::function<intptr_t(LowlevelKeyboardEvent*)> hookProcedure);
|
||||||
|
|
||||||
// Function to simulate keyboard input
|
// Function to simulate keyboard input
|
||||||
UINT SendVirtualInput(UINT cInputs, LPINPUT pInputs, int cbSize);
|
void SendVirtualInput(const std::vector<INPUT>& inputs);
|
||||||
|
|
||||||
// Function to simulate keyboard hook behavior
|
// Function to simulate keyboard hook behavior
|
||||||
intptr_t MockedKeyboardHook(LowlevelKeyboardEvent* data);
|
intptr_t MockedKeyboardHook(LowlevelKeyboardEvent* data);
|
||||||
|
@ -33,20 +33,22 @@ namespace RemappingLogicTests
|
|||||||
TEST_METHOD (MockedInput_ShouldSetKeyboardState_OnKeyEvent)
|
TEST_METHOD (MockedInput_ShouldSetKeyboardState_OnKeyEvent)
|
||||||
{
|
{
|
||||||
// Send key down and key up for A key (0x41) and check keyboard state both times
|
// Send key down and key up for A key (0x41) and check keyboard state both times
|
||||||
const int nInputs = 1;
|
std::vector<INPUT> inputs1{
|
||||||
INPUT input[nInputs] = {};
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } },
|
||||||
input[0].type = INPUT_KEYBOARD;
|
};
|
||||||
input[0].ki.wVk = 0x41;
|
|
||||||
|
|
||||||
// Send A keydown
|
// Send A keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs1);
|
||||||
|
|
||||||
// A key state should be true
|
// A key state should be true
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), true);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), true);
|
||||||
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
|
||||||
|
std::vector<INPUT> inputs2{
|
||||||
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } },
|
||||||
|
};
|
||||||
|
|
||||||
// Send A keyup
|
// Send A keyup
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs2);
|
||||||
|
|
||||||
// A key state should be false
|
// A key state should be false
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -34,7 +34,7 @@ namespace RemappingLogicTests
|
|||||||
TEST_METHOD (SetKeyEvent_ShouldUseExtendedKeyFlag_WhenArgumentIsExtendedKey)
|
TEST_METHOD (SetKeyEvent_ShouldUseExtendedKeyFlag_WhenArgumentIsExtendedKey)
|
||||||
{
|
{
|
||||||
const int nInputs = 15;
|
const int nInputs = 15;
|
||||||
INPUT input[nInputs] = {};
|
std::vector<INPUT> inputs;
|
||||||
|
|
||||||
// List of extended keys
|
// List of extended keys
|
||||||
WORD keyCodes[nInputs] = { VK_RCONTROL, VK_RMENU, VK_NUMLOCK, VK_SNAPSHOT, VK_CANCEL, VK_INSERT, VK_HOME, VK_PRIOR, VK_DELETE, VK_END, VK_NEXT, VK_LEFT, VK_DOWN, VK_RIGHT, VK_UP };
|
WORD keyCodes[nInputs] = { VK_RCONTROL, VK_RMENU, VK_NUMLOCK, VK_SNAPSHOT, VK_CANCEL, VK_INSERT, VK_HOME, VK_PRIOR, VK_DELETE, VK_END, VK_NEXT, VK_LEFT, VK_DOWN, VK_RIGHT, VK_UP };
|
||||||
@ -42,24 +42,22 @@ namespace RemappingLogicTests
|
|||||||
for (int i = 0; i < nInputs; i++)
|
for (int i = 0; i < nInputs; i++)
|
||||||
{
|
{
|
||||||
// Set key events for all the extended keys
|
// Set key events for all the extended keys
|
||||||
Helpers::SetKeyEvent(input, i, INPUT_KEYBOARD, keyCodes[i], 0, 0);
|
Helpers::SetKeyEvent(inputs, INPUT_KEYBOARD, keyCodes[i], 0, 0);
|
||||||
// Extended key flag should be set
|
// Extended key flag should be set
|
||||||
Assert::AreEqual(true, bool(input[i].ki.dwFlags & KEYEVENTF_EXTENDEDKEY));
|
Assert::AreEqual(true, bool(inputs[i].ki.dwFlags & KEYEVENTF_EXTENDEDKEY));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test if SetKeyEvent sets the scan code field to 0 for dummy key
|
// Test if SetKeyEvent sets the scan code field to 0 for dummy key
|
||||||
TEST_METHOD (SetKeyEvent_ShouldSetScanCodeFieldTo0_WhenArgumentIsDummyKey)
|
TEST_METHOD (SetKeyEvent_ShouldSetScanCodeFieldTo0_WhenArgumentIsDummyKey)
|
||||||
{
|
{
|
||||||
const int nInputs = KeyboardManagerConstants::DUMMY_KEY_EVENT_SIZE;
|
std::vector<INPUT> inputs{};
|
||||||
INPUT input[nInputs] = {};
|
|
||||||
|
|
||||||
int index = 0;
|
Helpers::SetDummyKeyEvent(inputs, 0);
|
||||||
Helpers::SetDummyKeyEvent(input, index, 0);
|
|
||||||
|
|
||||||
// Assert that wScan for both inputs is 0
|
// Assert that wScan for both inputs is 0
|
||||||
Assert::AreEqual<unsigned int>(0, input[0].ki.wScan);
|
Assert::AreEqual<unsigned int>(0, inputs[0].ki.wScan);
|
||||||
Assert::AreEqual<unsigned int>(0, input[1].ki.wScan);
|
Assert::AreEqual<unsigned int>(0, inputs[1].ki.wScan);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -39,22 +39,24 @@ namespace RemappingLogicTests
|
|||||||
{
|
{
|
||||||
// Remap A to B
|
// Remap A to B
|
||||||
testState.AddSingleKeyRemap(0x41, (DWORD)0x42);
|
testState.AddSingleKeyRemap(0x41, (DWORD)0x42);
|
||||||
const int nInputs = 1;
|
|
||||||
|
|
||||||
INPUT input[nInputs] = {};
|
std::vector<INPUT> inputs1{
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } },
|
||||||
input[0].ki.wVk = 0x41;
|
};
|
||||||
|
|
||||||
// Send A keydown
|
// Send A keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs1);
|
||||||
|
|
||||||
// A key state should be unchanged, and B key state should be true
|
// A key state should be unchanged, and B key state should be true
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x42), true);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x42), true);
|
||||||
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
|
||||||
|
std::vector<INPUT> inputs2{
|
||||||
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } },
|
||||||
|
};
|
||||||
|
|
||||||
// Send A keyup
|
// Send A keyup
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs2);
|
||||||
|
|
||||||
// A key state should be unchanged, and B key state should be false
|
// A key state should be unchanged, and B key state should be false
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
||||||
@ -66,21 +68,23 @@ namespace RemappingLogicTests
|
|||||||
{
|
{
|
||||||
// Remap A to VK_DISABLE (disabled)
|
// Remap A to VK_DISABLE (disabled)
|
||||||
testState.AddSingleKeyRemap(0x41, CommonSharedConstants::VK_DISABLED);
|
testState.AddSingleKeyRemap(0x41, CommonSharedConstants::VK_DISABLED);
|
||||||
const int nInputs = 1;
|
|
||||||
|
|
||||||
INPUT input[nInputs] = {};
|
std::vector<INPUT> inputs1{
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } },
|
||||||
input[0].ki.wVk = 0x41;
|
};
|
||||||
|
|
||||||
// Send A keydown
|
// Send A keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs1);
|
||||||
|
|
||||||
// A key state should be unchanged
|
// A key state should be unchanged
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
||||||
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
|
||||||
|
std::vector<INPUT> inputs2{
|
||||||
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } },
|
||||||
|
};
|
||||||
|
|
||||||
// Send A keyup
|
// Send A keyup
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs2);
|
||||||
|
|
||||||
// A key state should be unchanged
|
// A key state should be unchanged
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
||||||
@ -91,22 +95,24 @@ namespace RemappingLogicTests
|
|||||||
{
|
{
|
||||||
// Remap A to Common Win key
|
// Remap A to Common Win key
|
||||||
testState.AddSingleKeyRemap(0x41, CommonSharedConstants::VK_WIN_BOTH);
|
testState.AddSingleKeyRemap(0x41, CommonSharedConstants::VK_WIN_BOTH);
|
||||||
const int nInputs = 1;
|
|
||||||
|
|
||||||
INPUT input[nInputs] = {};
|
std::vector<INPUT> inputs1{
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } },
|
||||||
input[0].ki.wVk = 0x41;
|
};
|
||||||
|
|
||||||
// Send A keydown
|
// Send A keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs1);
|
||||||
|
|
||||||
// A key state should be unchanged, and common Win key state should be true
|
// A key state should be unchanged, and common Win key state should be true
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LWIN), true);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LWIN), true);
|
||||||
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
|
||||||
|
std::vector<INPUT> inputs2{
|
||||||
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } },
|
||||||
|
};
|
||||||
|
|
||||||
// Send A keyup
|
// Send A keyup
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs2);
|
||||||
|
|
||||||
// A key state should be unchanged, and common Win key state should be false
|
// A key state should be unchanged, and common Win key state should be false
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
||||||
@ -126,14 +132,13 @@ namespace RemappingLogicTests
|
|||||||
|
|
||||||
// Remap Caps Lock to Ctrl
|
// Remap Caps Lock to Ctrl
|
||||||
testState.AddSingleKeyRemap(VK_CAPITAL, (DWORD)VK_CONTROL);
|
testState.AddSingleKeyRemap(VK_CAPITAL, (DWORD)VK_CONTROL);
|
||||||
const int nInputs = 1;
|
|
||||||
|
|
||||||
INPUT input[nInputs] = {};
|
std::vector<INPUT> inputs{
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CAPITAL } },
|
||||||
input[0].ki.wVk = VK_CAPITAL;
|
};
|
||||||
|
|
||||||
// Send Caps Lock keydown
|
// Send Caps Lock keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs);
|
||||||
|
|
||||||
// SendVirtualInput should be called exactly once with the above condition
|
// SendVirtualInput should be called exactly once with the above condition
|
||||||
Assert::AreEqual(1, mockedInputHandler.GetSendVirtualInputCallCount());
|
Assert::AreEqual(1, mockedInputHandler.GetSendVirtualInputCallCount());
|
||||||
@ -152,14 +157,13 @@ namespace RemappingLogicTests
|
|||||||
|
|
||||||
// Remap Ctrl to Caps Lock
|
// Remap Ctrl to Caps Lock
|
||||||
testState.AddSingleKeyRemap(VK_CONTROL, (DWORD)VK_CAPITAL);
|
testState.AddSingleKeyRemap(VK_CONTROL, (DWORD)VK_CAPITAL);
|
||||||
const int nInputs = 1;
|
|
||||||
|
|
||||||
INPUT input[nInputs] = {};
|
std::vector<INPUT> inputs{
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } },
|
||||||
input[0].ki.wVk = VK_CONTROL;
|
};
|
||||||
|
|
||||||
// Send Ctrl keydown
|
// Send Ctrl keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs);
|
||||||
|
|
||||||
// SendVirtualInput should be called exactly once with the above condition
|
// SendVirtualInput should be called exactly once with the above condition
|
||||||
Assert::AreEqual(1, mockedInputHandler.GetSendVirtualInputCallCount());
|
Assert::AreEqual(1, mockedInputHandler.GetSendVirtualInputCallCount());
|
||||||
@ -182,14 +186,13 @@ namespace RemappingLogicTests
|
|||||||
dest.SetKey(VK_SHIFT);
|
dest.SetKey(VK_SHIFT);
|
||||||
dest.SetKey(0x56);
|
dest.SetKey(0x56);
|
||||||
testState.AddSingleKeyRemap(VK_CAPITAL, dest);
|
testState.AddSingleKeyRemap(VK_CAPITAL, dest);
|
||||||
const int nInputs = 1;
|
|
||||||
|
|
||||||
INPUT input[nInputs] = {};
|
std::vector<INPUT> inputs{
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CAPITAL } },
|
||||||
input[0].ki.wVk = VK_CAPITAL;
|
};
|
||||||
|
|
||||||
// Send Caps Lock keydown
|
// Send Caps Lock keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs);
|
||||||
|
|
||||||
// SendVirtualInput should be called exactly twice with the above condition
|
// SendVirtualInput should be called exactly twice with the above condition
|
||||||
Assert::AreEqual(2, mockedInputHandler.GetSendVirtualInputCallCount());
|
Assert::AreEqual(2, mockedInputHandler.GetSendVirtualInputCallCount());
|
||||||
@ -211,14 +214,13 @@ namespace RemappingLogicTests
|
|||||||
dest.SetKey(VK_CONTROL);
|
dest.SetKey(VK_CONTROL);
|
||||||
dest.SetKey(VK_CAPITAL);
|
dest.SetKey(VK_CAPITAL);
|
||||||
testState.AddSingleKeyRemap(VK_CONTROL, dest);
|
testState.AddSingleKeyRemap(VK_CONTROL, dest);
|
||||||
const int nInputs = 1;
|
|
||||||
|
|
||||||
INPUT input[nInputs] = {};
|
std::vector<INPUT> inputs{
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_CONTROL } },
|
||||||
input[0].ki.wVk = VK_CONTROL;
|
};
|
||||||
|
|
||||||
// Send Ctrl keydown
|
// Send Ctrl keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs);
|
||||||
|
|
||||||
// SendVirtualInput should be called exactly once with the above condition
|
// SendVirtualInput should be called exactly once with the above condition
|
||||||
Assert::AreEqual(1, mockedInputHandler.GetSendVirtualInputCallCount());
|
Assert::AreEqual(1, mockedInputHandler.GetSendVirtualInputCallCount());
|
||||||
@ -232,23 +234,25 @@ namespace RemappingLogicTests
|
|||||||
dest.SetKey(VK_CONTROL);
|
dest.SetKey(VK_CONTROL);
|
||||||
dest.SetKey(0x56);
|
dest.SetKey(0x56);
|
||||||
testState.AddSingleKeyRemap(0x41, dest);
|
testState.AddSingleKeyRemap(0x41, dest);
|
||||||
const int nInputs = 1;
|
|
||||||
|
|
||||||
INPUT input[nInputs] = {};
|
std::vector<INPUT> inputs1{
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } },
|
||||||
input[0].ki.wVk = 0x41;
|
};
|
||||||
|
|
||||||
// Send A keydown
|
// Send A keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs1);
|
||||||
|
|
||||||
// A key state should be unchanged, and Ctrl, V key state should be true
|
// A key state should be unchanged, and Ctrl, V key state should be true
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true);
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true);
|
||||||
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
|
||||||
|
std::vector<INPUT> inputs2{
|
||||||
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } },
|
||||||
|
};
|
||||||
|
|
||||||
// Send A keyup
|
// Send A keyup
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs2);
|
||||||
|
|
||||||
// A key state should be unchanged, and Ctrl, V key state should be false
|
// A key state should be unchanged, and Ctrl, V key state should be false
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
||||||
@ -265,24 +269,26 @@ namespace RemappingLogicTests
|
|||||||
dest.SetKey(VK_SHIFT);
|
dest.SetKey(VK_SHIFT);
|
||||||
dest.SetKey(0x56);
|
dest.SetKey(0x56);
|
||||||
testState.AddSingleKeyRemap(0x41, dest);
|
testState.AddSingleKeyRemap(0x41, dest);
|
||||||
const int nInputs = 1;
|
|
||||||
|
|
||||||
INPUT input[nInputs] = {};
|
std::vector<INPUT> inputs1{
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A' } },
|
||||||
input[0].ki.wVk = 0x41;
|
};
|
||||||
|
|
||||||
// Send A keydown
|
// Send A keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs1);
|
||||||
|
|
||||||
// A key state should be unchanged, and Ctrl, Shift, V key state should be true
|
// A key state should be unchanged, and Ctrl, Shift, V key state should be true
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true);
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), true);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_SHIFT), true);
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true);
|
||||||
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
|
||||||
|
std::vector<INPUT> inputs2{
|
||||||
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = 'A', .dwFlags = KEYEVENTF_KEYUP } },
|
||||||
|
};
|
||||||
|
|
||||||
// Send A keyup
|
// Send A keyup
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs2);
|
||||||
|
|
||||||
// A key state should be unchanged, and Ctrl, Shift, V key state should be false
|
// A key state should be unchanged, and Ctrl, Shift, V key state should be false
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
||||||
@ -299,22 +305,24 @@ namespace RemappingLogicTests
|
|||||||
dest.SetKey(VK_LCONTROL);
|
dest.SetKey(VK_LCONTROL);
|
||||||
dest.SetKey(0x56);
|
dest.SetKey(0x56);
|
||||||
testState.AddSingleKeyRemap(VK_LCONTROL, dest);
|
testState.AddSingleKeyRemap(VK_LCONTROL, dest);
|
||||||
const int nInputs = 1;
|
|
||||||
|
|
||||||
INPUT input[nInputs] = {};
|
std::vector<INPUT> inputs1{
|
||||||
input[0].type = INPUT_KEYBOARD;
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_LCONTROL } },
|
||||||
input[0].ki.wVk = VK_LCONTROL;
|
};
|
||||||
|
|
||||||
// Send LCtrl keydown
|
// Send LCtrl keydown
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs1);
|
||||||
|
|
||||||
// LCtrl, V key state should be true
|
// LCtrl, V key state should be true
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LCONTROL), true);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LCONTROL), true);
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), true);
|
||||||
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
|
||||||
|
std::vector<INPUT> inputs2{
|
||||||
|
{ .type = INPUT_KEYBOARD, .ki = { .wVk = VK_LCONTROL, .dwFlags = KEYEVENTF_KEYUP } },
|
||||||
|
};
|
||||||
|
|
||||||
// Send LCtrl keyup
|
// Send LCtrl keyup
|
||||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
mockedInputHandler.SendVirtualInput(inputs2);
|
||||||
|
|
||||||
// LCtrl, V key state should be false
|
// LCtrl, V key state should be false
|
||||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LCONTROL), false);
|
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_LCONTROL), false);
|
||||||
|
@ -154,29 +154,29 @@ namespace Helpers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Function to set the value of a key event based on the arguments
|
// Function to set the value of a key event based on the arguments
|
||||||
void SetKeyEvent(LPINPUT keyEventArray, int index, DWORD inputType, WORD keyCode, DWORD flags, ULONG_PTR extraInfo)
|
void SetKeyEvent(std::vector<INPUT>& keyEventArray, DWORD inputType, WORD keyCode, DWORD flags, ULONG_PTR extraInfo)
|
||||||
{
|
{
|
||||||
keyEventArray[index].type = inputType;
|
INPUT keyEvent{};
|
||||||
keyEventArray[index].ki.wVk = keyCode;
|
keyEvent.type = inputType;
|
||||||
keyEventArray[index].ki.dwFlags = flags;
|
keyEvent.ki.wVk = keyCode;
|
||||||
|
keyEvent.ki.dwFlags = flags;
|
||||||
if (IsExtendedKey(keyCode))
|
if (IsExtendedKey(keyCode))
|
||||||
{
|
{
|
||||||
keyEventArray[index].ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
|
keyEvent.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
|
||||||
}
|
}
|
||||||
keyEventArray[index].ki.dwExtraInfo = extraInfo;
|
keyEvent.ki.dwExtraInfo = extraInfo;
|
||||||
|
|
||||||
// Set wScan to the value from MapVirtualKey as some applications may use the scan code for handling input, for instance, Windows Terminal ignores non-character input which has scancode set to 0.
|
// Set wScan to the value from MapVirtualKey as some applications may use the scan code for handling input, for instance, Windows Terminal ignores non-character input which has scancode set to 0.
|
||||||
// MapVirtualKey returns 0 if the key code does not correspond to a physical key (such as unassigned/reserved keys). More details at https://github.com/microsoft/PowerToys/pull/7143#issue-498877747
|
// MapVirtualKey returns 0 if the key code does not correspond to a physical key (such as unassigned/reserved keys). More details at https://github.com/microsoft/PowerToys/pull/7143#issue-498877747
|
||||||
keyEventArray[index].ki.wScan = static_cast<WORD>(MapVirtualKey(keyCode, MAPVK_VK_TO_VSC));
|
keyEvent.ki.wScan = static_cast<WORD>(MapVirtualKey(keyCode, MAPVK_VK_TO_VSC));
|
||||||
|
keyEventArray.push_back(keyEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to set the dummy key events used for remapping shortcuts, required to ensure releasing a modifier doesn't trigger another action (For example, Win->Start Menu or Alt->Menu bar)
|
// Function to set the dummy key events used for remapping shortcuts, required to ensure releasing a modifier doesn't trigger another action (For example, Win->Start Menu or Alt->Menu bar)
|
||||||
void SetDummyKeyEvent(LPINPUT keyEventArray, int& index, ULONG_PTR extraInfo)
|
void SetDummyKeyEvent(std::vector<INPUT>& keyEventArray, ULONG_PTR extraInfo)
|
||||||
{
|
{
|
||||||
SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, static_cast<WORD>(KeyboardManagerConstants::DUMMY_KEY), 0, extraInfo);
|
SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(KeyboardManagerConstants::DUMMY_KEY), 0, extraInfo);
|
||||||
index++;
|
SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(KeyboardManagerConstants::DUMMY_KEY), KEYEVENTF_KEYUP, extraInfo);
|
||||||
SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, static_cast<WORD>(KeyboardManagerConstants::DUMMY_KEY), KEYEVENTF_KEYUP, extraInfo);
|
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to return window handle for a full screen UWP app
|
// Function to return window handle for a full screen UWP app
|
||||||
@ -240,7 +240,7 @@ namespace Helpers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Function to set key events for modifier keys: When shortcutToCompare is passed (non-empty shortcut), then the key event is sent only if both shortcut's don't have the same modifier key. When keyToBeReleased is passed (non-NULL), then the key event is sent if either the shortcuts don't have the same modifier or if the shortcutToBeSent's modifier matches the keyToBeReleased
|
// Function to set key events for modifier keys: When shortcutToCompare is passed (non-empty shortcut), then the key event is sent only if both shortcut's don't have the same modifier key. When keyToBeReleased is passed (non-NULL), then the key event is sent if either the shortcuts don't have the same modifier or if the shortcutToBeSent's modifier matches the keyToBeReleased
|
||||||
void SetModifierKeyEvents(const Shortcut& shortcutToBeSent, const ModifierKey& winKeyInvoked, LPINPUT keyEventArray, int& index, bool isKeyDown, ULONG_PTR extraInfoFlag, const Shortcut& shortcutToCompare, const DWORD& keyToBeReleased)
|
void SetModifierKeyEvents(const Shortcut& shortcutToBeSent, const ModifierKey& winKeyInvoked, std::vector<INPUT>& keyEventArray, bool isKeyDown, ULONG_PTR extraInfoFlag, const Shortcut& shortcutToCompare, const DWORD& keyToBeReleased)
|
||||||
{
|
{
|
||||||
// If key down is to be sent, send in the order Win, Ctrl, Alt, Shift
|
// If key down is to be sent, send in the order Win, Ctrl, Alt, Shift
|
||||||
if (isKeyDown)
|
if (isKeyDown)
|
||||||
@ -248,23 +248,19 @@ namespace Helpers
|
|||||||
// If shortcutToCompare is non-empty, then the key event is sent only if both shortcut's don't have the same modifier key. If keyToBeReleased is non-NULL, then the key event is sent if either the shortcuts don't have the same modifier or if the shortcutToBeSent's modifier matches the keyToBeReleased
|
// If shortcutToCompare is non-empty, then the key event is sent only if both shortcut's don't have the same modifier key. If keyToBeReleased is non-NULL, then the key event is sent if either the shortcuts don't have the same modifier or if the shortcutToBeSent's modifier matches the keyToBeReleased
|
||||||
if (shortcutToBeSent.GetWinKey(winKeyInvoked) != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetWinKey(winKeyInvoked) != shortcutToCompare.GetWinKey(winKeyInvoked)) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckWinKey(keyToBeReleased)))
|
if (shortcutToBeSent.GetWinKey(winKeyInvoked) != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetWinKey(winKeyInvoked) != shortcutToCompare.GetWinKey(winKeyInvoked)) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckWinKey(keyToBeReleased)))
|
||||||
{
|
{
|
||||||
Helpers::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetWinKey(winKeyInvoked)), 0, extraInfoFlag);
|
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetWinKey(winKeyInvoked)), 0, extraInfoFlag);
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
if (shortcutToBeSent.GetCtrlKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetCtrlKey() != shortcutToCompare.GetCtrlKey()) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckCtrlKey(keyToBeReleased)))
|
if (shortcutToBeSent.GetCtrlKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetCtrlKey() != shortcutToCompare.GetCtrlKey()) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckCtrlKey(keyToBeReleased)))
|
||||||
{
|
{
|
||||||
Helpers::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetCtrlKey()), 0, extraInfoFlag);
|
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetCtrlKey()), 0, extraInfoFlag);
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
if (shortcutToBeSent.GetAltKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetAltKey() != shortcutToCompare.GetAltKey()) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckAltKey(keyToBeReleased)))
|
if (shortcutToBeSent.GetAltKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetAltKey() != shortcutToCompare.GetAltKey()) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckAltKey(keyToBeReleased)))
|
||||||
{
|
{
|
||||||
Helpers::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetAltKey()), 0, extraInfoFlag);
|
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetAltKey()), 0, extraInfoFlag);
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
if (shortcutToBeSent.GetShiftKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetShiftKey() != shortcutToCompare.GetShiftKey()) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckShiftKey(keyToBeReleased)))
|
if (shortcutToBeSent.GetShiftKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetShiftKey() != shortcutToCompare.GetShiftKey()) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckShiftKey(keyToBeReleased)))
|
||||||
{
|
{
|
||||||
Helpers::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetShiftKey()), 0, extraInfoFlag);
|
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetShiftKey()), 0, extraInfoFlag);
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,23 +270,35 @@ namespace Helpers
|
|||||||
// If shortcutToCompare is non-empty, then the key event is sent only if both shortcut's don't have the same modifier key. If keyToBeReleased is non-NULL, then the key event is sent if either the shortcuts don't have the same modifier or if the shortcutToBeSent's modifier matches the keyToBeReleased
|
// If shortcutToCompare is non-empty, then the key event is sent only if both shortcut's don't have the same modifier key. If keyToBeReleased is non-NULL, then the key event is sent if either the shortcuts don't have the same modifier or if the shortcutToBeSent's modifier matches the keyToBeReleased
|
||||||
if (shortcutToBeSent.GetShiftKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetShiftKey() != shortcutToCompare.GetShiftKey() || shortcutToBeSent.CheckShiftKey(keyToBeReleased)))
|
if (shortcutToBeSent.GetShiftKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetShiftKey() != shortcutToCompare.GetShiftKey() || shortcutToBeSent.CheckShiftKey(keyToBeReleased)))
|
||||||
{
|
{
|
||||||
Helpers::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetShiftKey()), KEYEVENTF_KEYUP, extraInfoFlag);
|
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetShiftKey()), KEYEVENTF_KEYUP, extraInfoFlag);
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
if (shortcutToBeSent.GetAltKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetAltKey() != shortcutToCompare.GetAltKey() || shortcutToBeSent.CheckAltKey(keyToBeReleased)))
|
if (shortcutToBeSent.GetAltKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetAltKey() != shortcutToCompare.GetAltKey() || shortcutToBeSent.CheckAltKey(keyToBeReleased)))
|
||||||
{
|
{
|
||||||
Helpers::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetAltKey()), KEYEVENTF_KEYUP, extraInfoFlag);
|
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetAltKey()), KEYEVENTF_KEYUP, extraInfoFlag);
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
if (shortcutToBeSent.GetCtrlKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetCtrlKey() != shortcutToCompare.GetCtrlKey() || shortcutToBeSent.CheckCtrlKey(keyToBeReleased)))
|
if (shortcutToBeSent.GetCtrlKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetCtrlKey() != shortcutToCompare.GetCtrlKey() || shortcutToBeSent.CheckCtrlKey(keyToBeReleased)))
|
||||||
{
|
{
|
||||||
Helpers::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetCtrlKey()), KEYEVENTF_KEYUP, extraInfoFlag);
|
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetCtrlKey()), KEYEVENTF_KEYUP, extraInfoFlag);
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
if (shortcutToBeSent.GetWinKey(winKeyInvoked) != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetWinKey(winKeyInvoked) != shortcutToCompare.GetWinKey(winKeyInvoked) || shortcutToBeSent.CheckWinKey(keyToBeReleased)))
|
if (shortcutToBeSent.GetWinKey(winKeyInvoked) != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetWinKey(winKeyInvoked) != shortcutToCompare.GetWinKey(winKeyInvoked) || shortcutToBeSent.CheckWinKey(keyToBeReleased)))
|
||||||
{
|
{
|
||||||
Helpers::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetWinKey(winKeyInvoked)), KEYEVENTF_KEYUP, extraInfoFlag);
|
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetWinKey(winKeyInvoked)), KEYEVENTF_KEYUP, extraInfoFlag);
|
||||||
index++;
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTextKeyEvents(std::vector<INPUT>& keyEventArray, const std::wstring& remapping)
|
||||||
|
{
|
||||||
|
for (wchar_t c : remapping)
|
||||||
|
{
|
||||||
|
for (DWORD flag : { 0, KEYEVENTF_KEYUP })
|
||||||
|
{
|
||||||
|
INPUT input{};
|
||||||
|
input.type = INPUT_KEYBOARD;
|
||||||
|
input.ki.dwFlags = KEYEVENTF_UNICODE | flag;
|
||||||
|
input.ki.dwExtraInfo = KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG;
|
||||||
|
input.ki.wScan = c;
|
||||||
|
keyEventArray.push_back(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ namespace Helpers
|
|||||||
Shift,
|
Shift,
|
||||||
Action
|
Action
|
||||||
};
|
};
|
||||||
|
|
||||||
// Functions to encode that a key is originated from numpad
|
// Functions to encode that a key is originated from numpad
|
||||||
DWORD EncodeKeyNumpadOrigin(const DWORD key, const bool extended);
|
DWORD EncodeKeyNumpadOrigin(const DWORD key, const bool extended);
|
||||||
DWORD ClearKeyNumpadOrigin(const DWORD key);
|
DWORD ClearKeyNumpadOrigin(const DWORD key);
|
||||||
@ -31,10 +31,13 @@ namespace Helpers
|
|||||||
KeyType GetKeyType(DWORD key);
|
KeyType GetKeyType(DWORD key);
|
||||||
|
|
||||||
// Function to set the value of a key event based on the arguments
|
// Function to set the value of a key event based on the arguments
|
||||||
void SetKeyEvent(LPINPUT keyEventArray, int index, DWORD inputType, WORD keyCode, DWORD flags, ULONG_PTR extraInfo);
|
void SetKeyEvent(std::vector<INPUT>& keyEventArray, DWORD inputType, WORD keyCode, DWORD flags, ULONG_PTR extraInfo);
|
||||||
|
|
||||||
// Function to set the dummy key events used for remapping shortcuts, required to ensure releasing a modifier doesn't trigger another action (For example, Win->Start Menu or Alt->Menu bar)
|
// Function to set the dummy key events used for remapping shortcuts, required to ensure releasing a modifier doesn't trigger another action (For example, Win->Start Menu or Alt->Menu bar)
|
||||||
void SetDummyKeyEvent(LPINPUT keyEventArray, int& index, ULONG_PTR extraInfo);
|
void SetDummyKeyEvent(std::vector<INPUT>& keyEventArray, ULONG_PTR extraInfo);
|
||||||
|
|
||||||
|
// Function to set key events for remapping text.
|
||||||
|
void SetTextKeyEvents(std::vector<INPUT>& keyEventArray, const std::wstring& remapping);
|
||||||
|
|
||||||
// Function to return window handle for a full screen UWP app
|
// Function to return window handle for a full screen UWP app
|
||||||
HWND GetFullscreenUWPWindowHandle();
|
HWND GetFullscreenUWPWindowHandle();
|
||||||
@ -43,7 +46,7 @@ namespace Helpers
|
|||||||
std::wstring GetCurrentApplication(bool keepPath);
|
std::wstring GetCurrentApplication(bool keepPath);
|
||||||
|
|
||||||
// Function to set key events for modifier keys: When shortcutToCompare is passed (non-empty shortcut), then the key event is sent only if both shortcut's don't have the same modifier key. When keyToBeReleased is passed (non-NULL), then the key event is sent if either the shortcuts don't have the same modifier or if the shortcutToBeSent's modifier matches the keyToBeReleased
|
// Function to set key events for modifier keys: When shortcutToCompare is passed (non-empty shortcut), then the key event is sent only if both shortcut's don't have the same modifier key. When keyToBeReleased is passed (non-NULL), then the key event is sent if either the shortcuts don't have the same modifier or if the shortcutToBeSent's modifier matches the keyToBeReleased
|
||||||
void SetModifierKeyEvents(const Shortcut& shortcutToBeSent, const ModifierKey& winKeyInvoked, LPINPUT keyEventArray, int& index, bool isKeyDown, ULONG_PTR extraInfoFlag, const Shortcut& shortcutToCompare = Shortcut(), const DWORD& keyToBeReleased = NULL);
|
void SetModifierKeyEvents(const Shortcut& shortcutToBeSent, const ModifierKey& winKeyInvoked, std::vector<INPUT>& keyEventArray, bool isKeyDown, ULONG_PTR extraInfoFlag, const Shortcut& shortcutToCompare = Shortcut(), const DWORD& keyToBeReleased = NULL);
|
||||||
|
|
||||||
// Function to filter the key codes for artificial key codes
|
// Function to filter the key codes for artificial key codes
|
||||||
int32_t FilterArtificialKeys(const int32_t& key);
|
int32_t FilterArtificialKeys(const int32_t& key);
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <keyboardmanager/common/InputInterface.h>
|
#include <common/logger/logger.h>
|
||||||
|
#include <common/utils/winapi_error.h>
|
||||||
#include <keyboardmanager/common/Helpers.h>
|
#include <keyboardmanager/common/Helpers.h>
|
||||||
|
#include <keyboardmanager/common/InputInterface.h>
|
||||||
|
|
||||||
namespace KeyboardManagerInput
|
namespace KeyboardManagerInput
|
||||||
{
|
{
|
||||||
@ -10,9 +12,16 @@ namespace KeyboardManagerInput
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Function to simulate input
|
// Function to simulate input
|
||||||
UINT SendVirtualInput(UINT cInputs, LPINPUT pInputs, int cbSize)
|
void SendVirtualInput(const std::vector<INPUT>& inputs)
|
||||||
{
|
{
|
||||||
return SendInput(cInputs, pInputs, cbSize);
|
std::vector<INPUT> copy = inputs;
|
||||||
|
UINT eventCount = SendInput(static_cast<UINT>(copy.size()), copy.data(), sizeof(INPUT));
|
||||||
|
if (eventCount != copy.size())
|
||||||
|
{
|
||||||
|
Logger::error(
|
||||||
|
L"Failed to send input events. {}",
|
||||||
|
get_last_error_or_default(GetLastError()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to get the state of a particular key
|
// Function to get the state of a particular key
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
namespace KeyboardManagerInput
|
namespace KeyboardManagerInput
|
||||||
{
|
{
|
||||||
// Interface used to wrap keyboard input library methods
|
// Interface used to wrap keyboard input library methods
|
||||||
@ -7,7 +11,7 @@ namespace KeyboardManagerInput
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Function to simulate input
|
// Function to simulate input
|
||||||
virtual UINT SendVirtualInput(UINT cInputs, LPINPUT pInputs, int cbSize) = 0;
|
virtual void SendVirtualInput(const std::vector<INPUT>& inputs) = 0;
|
||||||
|
|
||||||
// Function to get the state of a particular key
|
// Function to get the state of a particular key
|
||||||
virtual bool GetVirtualKeyState(int key) = 0;
|
virtual bool GetVirtualKeyState(int key) = 0;
|
||||||
|
@ -10,14 +10,11 @@ namespace KeyboardEventHandlers
|
|||||||
void SetNumLockToPreviousState(KeyboardManagerInput::InputInterface& ii)
|
void SetNumLockToPreviousState(KeyboardManagerInput::InputInterface& ii)
|
||||||
{
|
{
|
||||||
// Num Lock's key state is applied before it is intercepted by low level keyboard hooks, so we have to manually set back the state when we suppress the key. This is done by sending an additional key up, key down set of messages.
|
// Num Lock's key state is applied before it is intercepted by low level keyboard hooks, so we have to manually set back the state when we suppress the key. This is done by sending an additional key up, key down set of messages.
|
||||||
// We need 2 key events because after Num Lock is suppressed, key up to release num lock key and key down to revert the num lock state
|
std::vector<INPUT> keyEventList;
|
||||||
int key_count = 2;
|
|
||||||
LPINPUT keyEventList = new INPUT[size_t(key_count)]{};
|
|
||||||
|
|
||||||
// Use the suppress flag to ensure these are not intercepted by any remapped keys or shortcuts
|
// Use the suppress flag to ensure these are not intercepted by any remapped keys or shortcuts
|
||||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, VK_NUMLOCK, KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, VK_NUMLOCK, KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG);
|
||||||
Helpers::SetKeyEvent(keyEventList, 1, INPUT_KEYBOARD, VK_NUMLOCK, 0, KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG);
|
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, VK_NUMLOCK, 0, KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG);
|
||||||
ii.SendVirtualInput(static_cast<UINT>(key_count), keyEventList, sizeof(INPUT));
|
ii.SendVirtualInput(keyEventList);
|
||||||
delete[] keyEventList;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user