Skip to content

Commit

Permalink
[Keyboard Manager] Alt+Tab navigation with arrow keys i (#12986)
Browse files Browse the repository at this point in the history
* Draft

# Conflicts:
#	src/modules/keyboardmanager/KeyboardManagerEngineLibrary/KeyboardEventHandlers.cpp

* Handle key case

* Fix key count

* Remember if win key was pressed

* Don't search twice, remove redundant assignment

* spelling
  • Loading branch information
mykhailopylyp committed Sep 4, 2021
1 parent 941221c commit a4f8484
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -579,46 +579,90 @@ namespace KeyboardEventHandlers
}

size_t key_count;
LPINPUT keyEventList;
LPINPUT keyEventList = nullptr;

// Check if a new remapping should be applied
Shortcut currentlyPressed = it->first;
currentlyPressed.actionKey = data->lParam->vkCode;
auto newRemappingIter = reMap.find(currentlyPressed);
if (newRemappingIter != reMap.end())
{
auto& newRemapping = newRemappingIter->second;
Shortcut from = std::get<Shortcut>(it->second.targetShortcut);
if (newRemapping.RemapToKey())
{
DWORD to = std::get<0>(newRemapping.targetShortcut);
key_count = from.Size() - 1 + 1;
keyEventList = new INPUT[key_count]();
memset(keyEventList, 0, sizeof(keyEventList));
int i = 0;
Helpers::SetModifierKeyEvents(from, it->second.winKeyInvoked, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)to, 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
}else
{
Shortcut to = std::get<Shortcut>(newRemapping.targetShortcut);
key_count = from.Size() - 1 + to.Size() - 1 - 2* from.GetCommonModifiersCount(to) + 1;
keyEventList = new INPUT[key_count]();

// 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 * (size_t)commonKeys);
int i = 0;
Helpers::SetModifierKeyEvents(from, it->second.winKeyInvoked, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, to);
Helpers::SetModifierKeyEvents(to, it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, from);

// 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;
if (ii.GetVirtualKeyState((std::get<Shortcut>(it->second.targetShortcut).GetActionKey())))
{
isActionKeyPressed = true;
key_count += 2;
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)to.actionKey, 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
newRemapping.isShortcutInvoked = true;
}

// Remember which win key was pressed initially
if (ii.GetVirtualKeyState(VK_RWIN))
{
newRemapping.winKeyInvoked = ModifierKey::Right;
}
else if (ii.GetVirtualKeyState(VK_LWIN))
{
newRemapping.winKeyInvoked = ModifierKey::Left;
}
}
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 * (size_t)commonKeys);

keyEventList = new INPUT[key_count]();
memset(keyEventList, 0, sizeof(keyEventList));
// 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;
if (ii.GetVirtualKeyState((std::get<Shortcut>(it->second.targetShortcut).GetActionKey())))
{
isActionKeyPressed = true;
key_count += 2;
}

// Release new shortcut state (release in reverse order of shortcut to be accurate)
int i = 0;
if (isActionKeyPressed)
{
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (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);
keyEventList = new INPUT[key_count]();
memset(keyEventList, 0, sizeof(keyEventList));

// 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));
// Release new shortcut state (release in reverse order of shortcut to be accurate)
int i = 0;
if (isActionKeyPressed)
{
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (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);

// key down for original shortcut action key with shortcut flag so that we don't invoke the same shortcut remap again
if (isActionKeyPressed)
{
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)it->first.GetActionKey(), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
i++;
}
// 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));

// 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, (WORD)data->lParam->vkCode, 0, 0);
i++;
// key down for original shortcut action key with shortcut flag so that we don't invoke the same shortcut remap again
if (isActionKeyPressed)
{
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)it->first.GetActionKey(), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
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
// 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, (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
}

// Reset the remap state
it->second.isShortcutInvoked = false;
Expand Down
5 changes: 5 additions & 0 deletions src/modules/keyboardmanager/common/RemapShortcut.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,9 @@ class RemapShortcut
{
return targetShortcut == sc.targetShortcut && isShortcutInvoked == sc.isShortcutInvoked && winKeyInvoked == sc.winKeyInvoked;
}

bool RemapToKey()
{
return targetShortcut.index() == 0;
}
};

0 comments on commit a4f8484

Please sign in to comment.