parent
b2e72e1ca4
commit
3f25d7ccc8
|
@ -215,6 +215,7 @@ void LayoutMap::LayoutMapImpl::UpdateLayout()
|
|||
keyboardLayoutMap[VK_NONCONVERT] = L"IME Non-Convert";
|
||||
keyboardLayoutMap[VK_ACCEPT] = L"IME Kana";
|
||||
keyboardLayoutMap[VK_MODECHANGE] = L"IME Mode Change";
|
||||
keyboardLayoutMap[CommonSharedConstants::VK_DISABLED] = L"Disable";
|
||||
}
|
||||
|
||||
// Function to return the list of key codes in the order for the drop down. It creates it if it doesn't exist
|
||||
|
|
|
@ -11,4 +11,7 @@ namespace CommonSharedConstants
|
|||
|
||||
// Path to the event used by PowerLauncher
|
||||
const wchar_t POWER_LAUNCHER_SHARED_EVENT[] = L"Local\\PowerToysRunInvokeEvent-30f26ad7-d36d-4c0e-ab02-68bb5ff3c4ab";
|
||||
|
||||
// Max DWORD for key code to disable keys.
|
||||
const DWORD VK_DISABLED = 0x100;
|
||||
}
|
|
@ -173,6 +173,8 @@ namespace KeyboardManagerHelper
|
|||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_SHORTCUTMAXONEACTIONKEY).c_str();
|
||||
case ErrorType::ShortcutMaxShortcutSizeOneActionKey:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_MAXSHORTCUTSIZE).c_str();
|
||||
case ErrorType::ShortcutDisableAsActionKey:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_DISABLEASACTIONKEY).c_str();
|
||||
default:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_DEFAULT).c_str();
|
||||
}
|
||||
|
|
|
@ -48,7 +48,8 @@ namespace KeyboardManagerHelper
|
|||
ShortcutAtleast2Keys,
|
||||
ShortcutOneActionKey,
|
||||
ShortcutNotMoreThanOneActionKey,
|
||||
ShortcutMaxShortcutSizeOneActionKey
|
||||
ShortcutMaxShortcutSizeOneActionKey,
|
||||
ShortcutDisableAsActionKey
|
||||
};
|
||||
|
||||
// Enum type to store possible decision for input in the low level hook
|
||||
|
|
|
@ -24,10 +24,10 @@ namespace KeyboardEventHandlers
|
|||
// Check if the remap is to a key or a shortcut
|
||||
bool remapToKey = (it->second.index() == 0);
|
||||
|
||||
// If mapped to 0x0 then the key is disabled
|
||||
// If mapped to VK_DISABLED then the key is disabled
|
||||
if (remapToKey)
|
||||
{
|
||||
if (std::get<DWORD>(it->second) == 0x0)
|
||||
if (std::get<DWORD>(it->second) == CommonSharedConstants::VK_DISABLED)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ namespace KeyboardEventHandlers
|
|||
if (data->lParam->vkCode == it->first.GetActionKey() && (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN))
|
||||
{
|
||||
// Check if any other keys have been pressed apart from the shortcut. If true, then check for the next shortcut. This is to be done only for shortcut to shortcut remaps
|
||||
if (!it->first.IsKeyboardStateClearExceptShortcut(ii) && remapToShortcut)
|
||||
if (!it->first.IsKeyboardStateClearExceptShortcut(ii) && (remapToShortcut || std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -284,6 +284,12 @@ namespace KeyboardEventHandlers
|
|||
{
|
||||
// Dummy key, key up for all the original shortcut modifier keys and key down for remapped key
|
||||
key_count = 1 + (src_size - 1) + dest_size;
|
||||
// Do not send Disable key
|
||||
if (std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)
|
||||
{
|
||||
key_count--;
|
||||
}
|
||||
|
||||
keyEventList = new INPUT[key_count]();
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
|
||||
|
@ -296,8 +302,11 @@ namespace KeyboardEventHandlers
|
|||
KeyboardManagerHelper::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
|
||||
// Set target key down state
|
||||
if (std::get<DWORD>(it->second.targetShortcut) != CommonSharedConstants::VK_DISABLED)
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)KeyboardManagerHelper::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
|
||||
if (it->first.GetCtrlKey() == NULL && it->first.GetAltKey() == NULL && it->first.GetShiftKey() == NULL)
|
||||
|
@ -382,13 +391,22 @@ namespace KeyboardEventHandlers
|
|||
{
|
||||
// 1 for releasing new key and original shortcut modifiers except the one released
|
||||
key_count = dest_size + src_size - 2;
|
||||
// Do not send Disable key up
|
||||
if (std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)
|
||||
{
|
||||
key_count--;
|
||||
}
|
||||
|
||||
keyEventList = new INPUT[key_count]();
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
|
||||
// Release new key state
|
||||
int i = 0;
|
||||
if (std::get<DWORD>(it->second.targetShortcut) != CommonSharedConstants::VK_DISABLED)
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)KeyboardManagerHelper::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
|
||||
KeyboardManagerHelper::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, Shortcut(), data->lParam->vkCode);
|
||||
|
@ -418,6 +436,12 @@ namespace KeyboardEventHandlers
|
|||
// 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() && (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN))
|
||||
{
|
||||
// In case of mapping to disable do not send anything
|
||||
if (!remapToShortcut && std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t key_count = 1;
|
||||
LPINPUT keyEventList = new INPUT[key_count]();
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
|
@ -455,13 +479,23 @@ namespace KeyboardEventHandlers
|
|||
{
|
||||
// 1 for releasing new key and original shortcut modifiers, and dummy key
|
||||
key_count = dest_size + src_size;
|
||||
// Do not send Disable key
|
||||
if (std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)
|
||||
{
|
||||
key_count--;
|
||||
}
|
||||
|
||||
keyEventList = new INPUT[key_count]();
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
|
||||
// Release new key state
|
||||
int i = 0;
|
||||
// Do not send Disable key
|
||||
if (std::get<DWORD>(it->second.targetShortcut) != CommonSharedConstants::VK_DISABLED)
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)KeyboardManagerHelper::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
|
||||
KeyboardManagerHelper::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
|
@ -499,6 +533,10 @@ namespace KeyboardEventHandlers
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
else if (std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Case 5: If any key apart from the action key or a modifier key in the original shortcut is pressed then revert the keyboard state to just the original modifiers being held down along with the current key press
|
||||
|
@ -598,6 +636,43 @@ namespace KeyboardEventHandlers
|
|||
i++;
|
||||
}
|
||||
|
||||
it->second.isShortcutInvoked = false;
|
||||
it->second.winKeyInvoked = ModifierKey::Disabled;
|
||||
// If app specific shortcut has finished invoking, reset the target application
|
||||
if (activatedApp != KeyboardManagerConstants::NoActivatedApp)
|
||||
{
|
||||
keyboardManagerState.SetActivatedApp(KeyboardManagerConstants::NoActivatedApp);
|
||||
}
|
||||
lock.unlock();
|
||||
UINT res = ii.SendVirtualInput((UINT)key_count, keyEventList, sizeof(INPUT));
|
||||
delete[] keyEventList;
|
||||
return 1;
|
||||
}
|
||||
// All modifier keys and action key will be pressed down because if they are not pressed that means that handler has already been invoked on key release
|
||||
else if (std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)
|
||||
{
|
||||
// Key down for original shortcut modifiers and action key, dummy key, and current key press
|
||||
size_t key_count = src_size + 1 + 1;
|
||||
|
||||
LPINPUT keyEventList = new INPUT[key_count]();
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
|
||||
// Set old shortcut key down state
|
||||
int i = 0;
|
||||
KeyboardManagerHelper::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
|
||||
// Set old action key
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (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
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)data->lParam->vkCode, 0, 0);
|
||||
i++;
|
||||
|
||||
// Send dummy key
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)KeyboardManagerConstants::DUMMY_KEY, KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
i++;
|
||||
|
||||
it->second.isShortcutInvoked = false;
|
||||
it->second.winKeyInvoked = ModifierKey::Disabled;
|
||||
// If app specific shortcut has finished invoking, reset the target application
|
||||
|
|
|
@ -279,4 +279,7 @@
|
|||
<data name="AutomationProperties_Row" xml:space="preserve">
|
||||
<value>Row </value>
|
||||
</data>
|
||||
<data name="ERRORMESSAGE_DISABLEASACTIONKEY" xml:space="preserve">
|
||||
<value>Disable can not be an action or a modifier key</value>
|
||||
</data>
|
||||
</root>
|
|
@ -4,12 +4,14 @@
|
|||
#include <keyboardmanager/common/KeyboardManagerState.h>
|
||||
#include <keyboardmanager/dll/KeyboardEventHandlers.h>
|
||||
#include "TestHelpers.h"
|
||||
#include <common\shared_constants.h>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
|
||||
namespace RemappingLogicTests
|
||||
{
|
||||
TEST_CLASS (AppSpecificShortcutRemappingTests)
|
||||
|
||||
{
|
||||
private:
|
||||
MockedInput mockedInputHandler;
|
||||
|
@ -312,5 +314,33 @@ namespace RemappingLogicTests
|
|||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x41), false);
|
||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x56), false);
|
||||
}
|
||||
|
||||
// Disable app specific shortcut
|
||||
TEST_METHOD (AppSpecificShortcutToDisable_ShouldDisable_WhenAppIsOnForeground)
|
||||
{
|
||||
Shortcut src;
|
||||
src.SetKey(VK_CONTROL);
|
||||
WORD actionKey = 0x41;
|
||||
src.SetKey(actionKey);
|
||||
WORD disableKey = CommonSharedConstants::VK_DISABLED;
|
||||
testState.AddAppSpecificShortcut(testApp1, src, disableKey);
|
||||
|
||||
// Set the testApp as the foreground process
|
||||
mockedInputHandler.SetForegroundProcess(testApp1);
|
||||
|
||||
const int nInputs = 2;
|
||||
INPUT input[nInputs] = {};
|
||||
input[0].type = INPUT_KEYBOARD;
|
||||
input[0].ki.wVk = VK_CONTROL;
|
||||
input[1].type = INPUT_KEYBOARD;
|
||||
input[1].ki.wVk = actionKey;
|
||||
|
||||
// Send Ctrl+A keydown
|
||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
||||
|
||||
// Check if Ctrl+A is released and disable key was not send
|
||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false);
|
||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(actionKey), false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1438,5 +1438,26 @@ namespace RemappingUITests
|
|||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::NoError);
|
||||
});
|
||||
}
|
||||
|
||||
// Return error on Disable as second modifier key or action key
|
||||
TEST_METHOD (ValidateShortcutBufferElement_ShouldReturnDisableAsActionKeyError_OnSettingSecondDropdownAsDisable)
|
||||
{
|
||||
std::vector<DWORD> keyList = keyboardLayout.GetKeyCodeList(true);
|
||||
keyList.insert(keyList.begin(), CommonSharedConstants::VK_DISABLED);
|
||||
// Arrange
|
||||
RemapBuffer remapBuffer;
|
||||
remapBuffer.push_back(std::make_pair(RemapBufferItem{ std::vector<DWORD>{ VK_SHIFT, CommonSharedConstants::VK_DISABLED }, Shortcut() }, testApp1));
|
||||
std::vector<int32_t> selectedIndices = {
|
||||
GetDropDownIndexFromDropDownList(VK_SHIFT, keyList),
|
||||
GetDropDownIndexFromDropDownList(CommonSharedConstants::VK_DISABLED, keyList)
|
||||
};
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(0, 1, 1, selectedIndices, testApp1, true, keyList, remapBuffer, true);
|
||||
|
||||
// Assert
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::ShortcutDisableAsActionKey);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2004,5 +2004,88 @@ namespace RemappingLogicTests
|
|||
// Shortcut invoked state should be true
|
||||
Assert::AreEqual(true, testState.osLevelShortcutReMap[src].isShortcutInvoked);
|
||||
}
|
||||
|
||||
TEST_METHOD (ShortcutDisable_ShouldDisableShortcut_OnExactMatch)
|
||||
{
|
||||
Shortcut src;
|
||||
src.SetKey(VK_CONTROL);
|
||||
WORD actionKey = 0x41;
|
||||
src.SetKey(actionKey);
|
||||
WORD disableKey = CommonSharedConstants::VK_DISABLED;
|
||||
|
||||
testState.AddOSLevelShortcut(src, disableKey);
|
||||
|
||||
const int nInputs = 2;
|
||||
INPUT input[nInputs] = {};
|
||||
input[0].type = INPUT_KEYBOARD;
|
||||
input[0].ki.wVk = VK_CONTROL;
|
||||
input[1].type = INPUT_KEYBOARD;
|
||||
input[1].ki.wVk = actionKey;
|
||||
|
||||
// send Ctrl+A
|
||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
||||
|
||||
// Check that Ctrl+A was released and Disable key was not sent
|
||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), false);
|
||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(actionKey), false);
|
||||
}
|
||||
|
||||
TEST_METHOD (ShortcutDisable_ShouldNotDisableShortcut_OnSubsetMatch)
|
||||
{
|
||||
Shortcut src;
|
||||
src.SetKey(VK_CONTROL);
|
||||
WORD actionKey = 0x41;
|
||||
src.SetKey(actionKey);
|
||||
WORD disableKey = CommonSharedConstants::VK_DISABLED;
|
||||
|
||||
testState.AddOSLevelShortcut(src, disableKey);
|
||||
|
||||
const int nInputs = 3;
|
||||
INPUT input[nInputs] = {};
|
||||
input[0].type = INPUT_KEYBOARD;
|
||||
input[0].ki.wVk = VK_CONTROL;
|
||||
input[1].type = INPUT_KEYBOARD;
|
||||
input[1].ki.wVk = VK_SHIFT;
|
||||
input[2].type = INPUT_KEYBOARD;
|
||||
input[2].ki.wVk = actionKey;
|
||||
|
||||
// send Ctrl+Shift+A
|
||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
||||
|
||||
// Check that Ctrl+A was not released and Disable key was not sent
|
||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true);
|
||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(actionKey), true);
|
||||
}
|
||||
|
||||
TEST_METHOD (ShortcutDisable_ShouldNotDisableShortcutSuperset_AfterShorcutWasDisabled)
|
||||
{
|
||||
Shortcut src;
|
||||
src.SetKey(VK_CONTROL);
|
||||
WORD actionKey = 0x41;
|
||||
src.SetKey(actionKey);
|
||||
WORD disableKey = CommonSharedConstants::VK_DISABLED;
|
||||
|
||||
testState.AddOSLevelShortcut(src, disableKey);
|
||||
|
||||
const int nInputs = 2;
|
||||
INPUT input[nInputs] = {};
|
||||
input[0].type = INPUT_KEYBOARD;
|
||||
input[0].ki.wVk = VK_CONTROL;
|
||||
input[1].type = INPUT_KEYBOARD;
|
||||
input[1].ki.wVk = actionKey;
|
||||
|
||||
// send Ctrl+A
|
||||
mockedInputHandler.SendVirtualInput(nInputs, input, sizeof(INPUT));
|
||||
|
||||
input[0].type = INPUT_KEYBOARD;
|
||||
input[0].ki.wVk = 0x42;
|
||||
// send B
|
||||
mockedInputHandler.SendVirtualInput(1, input, sizeof(INPUT));
|
||||
|
||||
// Check that Ctrl+A+B was pressed
|
||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(VK_CONTROL), true);
|
||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(actionKey), true);
|
||||
Assert::AreEqual(mockedInputHandler.GetVirtualKeyState(0x42), true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -58,8 +58,8 @@ namespace RemappingLogicTests
|
|||
// Test if key is suppressed if a key is disabled by single key remap
|
||||
TEST_METHOD (RemappedKeyDisabled_ShouldNotChangeKeyState_OnKeyEvent)
|
||||
{
|
||||
// Remap A to 0x0 (disabled)
|
||||
testState.AddSingleKeyRemap(0x41, 0x0);
|
||||
// Remap A to VK_DISABLE (disabled)
|
||||
testState.AddSingleKeyRemap(0x41, CommonSharedConstants::VK_DISABLED);
|
||||
const int nInputs = 1;
|
||||
|
||||
INPUT input[nInputs] = {};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "pch.h"
|
||||
#include "BufferValidationHelpers.h"
|
||||
#include <keyboardmanager/common/KeyboardManagerConstants.h>
|
||||
#include <common\shared_constants.h>
|
||||
|
||||
namespace BufferValidationHelpers
|
||||
{
|
||||
|
@ -121,9 +122,14 @@ namespace BufferValidationHelpers
|
|||
errorType = KeyboardManagerHelper::ErrorType::ShortcutOneActionKey;
|
||||
}
|
||||
}
|
||||
// Disable can not be selected if one modifier key has already been selected
|
||||
else if (keyCodeList[selectedKeyIndex] == CommonSharedConstants::VK_DISABLED && dropDownIndex)
|
||||
{
|
||||
errorType = KeyboardManagerHelper::ErrorType::ShortcutDisableAsActionKey;
|
||||
}
|
||||
// If none of the above, then the action key will be set
|
||||
}
|
||||
// If it is the not the last drop down
|
||||
// If it is not the last drop down
|
||||
else
|
||||
{
|
||||
if (KeyboardManagerHelper::IsModifierKey(keyCodeList[selectedKeyIndex]))
|
||||
|
@ -158,6 +164,11 @@ namespace BufferValidationHelpers
|
|||
errorType = KeyboardManagerHelper::ErrorType::ShortcutAtleast2Keys;
|
||||
}
|
||||
}
|
||||
// Allow selection of VK_DISABLE only in first dropdown
|
||||
else if (keyCodeList[selectedKeyIndex] == CommonSharedConstants::VK_DISABLED && dropDownIndex)
|
||||
{
|
||||
errorType = KeyboardManagerHelper::ErrorType::ShortcutDisableAsActionKey;
|
||||
}
|
||||
// If the user tries to set an action key check if all drop down menus after this are empty if it is not the first key. If it is a hybrid control, this can be done even on the first key
|
||||
else if (dropDownIndex != 0 || isHybridControl)
|
||||
{
|
||||
|
|
|
@ -3,12 +3,38 @@
|
|||
#include "keyboardmanager/common/Helpers.h"
|
||||
#include <keyboardmanager/common/KeyboardManagerState.h>
|
||||
#include "BufferValidationHelpers.h"
|
||||
#include <common\shared_constants.h>
|
||||
#include <common\keyboard_layout_impl.h>
|
||||
|
||||
// Initialized to null
|
||||
KeyboardManagerState* KeyDropDownControl::keyboardManagerState = nullptr;
|
||||
|
||||
// Get keys code list depending if Disable is in dropdown
|
||||
std::vector<DWORD> KeyDropDownControl::GetKeyCodeList(bool isShortcut, bool renderDisable)
|
||||
{
|
||||
auto list = keyboardManagerState->keyboardMap.GetKeyCodeList(isShortcut);
|
||||
if (renderDisable)
|
||||
{
|
||||
list.insert(list.begin(), CommonSharedConstants::VK_DISABLED);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
// Get keys name list depending if Disable is in dropdown
|
||||
std::vector<std::wstring> KeyDropDownControl::GetKeyNameList(bool isShortcut, bool renderDisable)
|
||||
{
|
||||
auto list = keyboardManagerState->keyboardMap.GetKeyNameList(isShortcut);
|
||||
if (renderDisable)
|
||||
{
|
||||
list.insert(list.begin(), keyboardManagerState->keyboardMap.GetKeyName(CommonSharedConstants::VK_DISABLED));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
// Function to set properties apart from the SelectionChanged event handler
|
||||
void KeyDropDownControl::SetDefaultProperties(bool isShortcut)
|
||||
void KeyDropDownControl::SetDefaultProperties(bool isShortcut, bool renderDisable)
|
||||
{
|
||||
dropDown = ComboBox();
|
||||
warningFlyout = Flyout();
|
||||
|
@ -25,12 +51,12 @@ void KeyDropDownControl::SetDefaultProperties(bool isShortcut)
|
|||
dropDown.as<ComboBox>().MaxDropDownHeight(KeyboardManagerConstants::TableDropDownHeight);
|
||||
// Initialise layout attribute
|
||||
previousLayout = GetKeyboardLayout(0);
|
||||
keyCodeList = keyboardManagerState->keyboardMap.GetKeyCodeList(isShortcut);
|
||||
dropDown.as<ComboBox>().ItemsSource(KeyboardManagerHelper::ToBoxValue(keyboardManagerState->keyboardMap.GetKeyNameList(isShortcut)));
|
||||
keyCodeList = GetKeyCodeList(isShortcut, renderDisable);
|
||||
dropDown.as<ComboBox>().ItemsSource(KeyboardManagerHelper::ToBoxValue(GetKeyNameList(isShortcut, renderDisable)));
|
||||
// drop down open handler - to reload the items with the latest layout
|
||||
dropDown.as<ComboBox>().DropDownOpened([&, isShortcut](winrt::Windows::Foundation::IInspectable const& sender, auto args) {
|
||||
ComboBox currentDropDown = sender.as<ComboBox>();
|
||||
CheckAndUpdateKeyboardLayout(currentDropDown, isShortcut);
|
||||
CheckAndUpdateKeyboardLayout(currentDropDown, isShortcut, renderDisable);
|
||||
});
|
||||
|
||||
// Attach flyout to the drop down
|
||||
|
@ -48,7 +74,7 @@ void KeyDropDownControl::SetAccessibleNameForComboBox(ComboBox dropDown, int ind
|
|||
}
|
||||
|
||||
// Function to check if the layout has changed and accordingly update the drop down list
|
||||
void KeyDropDownControl::CheckAndUpdateKeyboardLayout(ComboBox currentDropDown, bool isShortcut)
|
||||
void KeyDropDownControl::CheckAndUpdateKeyboardLayout(ComboBox currentDropDown, bool isShortcut, bool renderDisable)
|
||||
{
|
||||
// Get keyboard layout for current thread
|
||||
HKL layout = GetKeyboardLayout(0);
|
||||
|
@ -56,8 +82,8 @@ void KeyDropDownControl::CheckAndUpdateKeyboardLayout(ComboBox currentDropDown,
|
|||
// Check if the layout has changed
|
||||
if (previousLayout != layout)
|
||||
{
|
||||
keyCodeList = keyboardManagerState->keyboardMap.GetKeyCodeList(isShortcut);
|
||||
currentDropDown.ItemsSource(KeyboardManagerHelper::ToBoxValue(keyboardManagerState->keyboardMap.GetKeyNameList(isShortcut)));
|
||||
keyCodeList = GetKeyCodeList(isShortcut, renderDisable);
|
||||
currentDropDown.ItemsSource(KeyboardManagerHelper::ToBoxValue(GetKeyNameList(isShortcut, renderDisable)));
|
||||
previousLayout = layout;
|
||||
}
|
||||
}
|
||||
|
@ -203,7 +229,7 @@ void KeyDropDownControl::SetSelectionHandler(Grid& table, StackPanel shortcutCon
|
|||
}
|
||||
|
||||
// Reset the buffer based on the new selected drop down items. Use static key code list since the KeyDropDownControl object might be deleted
|
||||
std::vector selectedKeyCodes = KeyboardManagerHelper::GetKeyCodesFromSelectedIndices(GetSelectedIndicesFromStackPanel(parent), KeyDropDownControl::keyboardManagerState->keyboardMap.GetKeyCodeList(true));
|
||||
std::vector selectedKeyCodes = KeyboardManagerHelper::GetKeyCodesFromSelectedIndices(GetSelectedIndicesFromStackPanel(parent), GetKeyCodeList(true, colIndex == 1));
|
||||
if (!isHybridControl)
|
||||
{
|
||||
std::get<Shortcut>(shortcutRemapBuffer[validationResult.second].first[colIndex]).SetKeyCodes(selectedKeyCodes);
|
||||
|
@ -283,7 +309,7 @@ ComboBox KeyDropDownControl::GetComboBox()
|
|||
// Function to add a drop down to the shortcut stack panel
|
||||
void KeyDropDownControl::AddDropDown(Grid table, StackPanel shortcutControl, StackPanel parent, const int colIndex, RemapBuffer& shortcutRemapBuffer, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects, TextBox targetApp, bool isHybridControl, bool isSingleKeyWindow, bool ignoreWarning)
|
||||
{
|
||||
keyDropDownControlObjects.push_back(std::move(std::unique_ptr<KeyDropDownControl>(new KeyDropDownControl(true, ignoreWarning))));
|
||||
keyDropDownControlObjects.push_back(std::move(std::unique_ptr<KeyDropDownControl>(new KeyDropDownControl(true, ignoreWarning, colIndex == 1))));
|
||||
parent.Children().Append(keyDropDownControlObjects[keyDropDownControlObjects.size() - 1]->GetComboBox());
|
||||
keyDropDownControlObjects[keyDropDownControlObjects.size() - 1]->SetSelectionHandler(table, shortcutControl, parent, colIndex, shortcutRemapBuffer, keyDropDownControlObjects, targetApp, isHybridControl, isSingleKeyWindow);
|
||||
parent.UpdateLayout();
|
||||
|
@ -314,7 +340,7 @@ void KeyDropDownControl::ValidateShortcutFromDropDownList(Grid table, StackPanel
|
|||
for (int i = 0; i < keyDropDownControlObjects.size(); i++)
|
||||
{
|
||||
// Check for errors only if the current selection is a valid shortcut
|
||||
std::vector<DWORD> selectedKeyCodes = KeyboardManagerHelper::GetKeyCodesFromSelectedIndices(keyDropDownControlObjects[i]->GetSelectedIndicesFromStackPanel(parent), KeyDropDownControl::keyboardManagerState->keyboardMap.GetKeyCodeList(true));
|
||||
std::vector<DWORD> selectedKeyCodes = KeyboardManagerHelper::GetKeyCodesFromSelectedIndices(keyDropDownControlObjects[i]->GetSelectedIndicesFromStackPanel(parent), GetKeyCodeList(true, colIndex == 1));
|
||||
std::variant<DWORD, Shortcut> currentShortcut;
|
||||
if (selectedKeyCodes.size() == 1 && isHybridControl)
|
||||
{
|
||||
|
@ -352,7 +378,7 @@ void KeyDropDownControl::AddShortcutToControl(Shortcut shortcut, Grid table, Sta
|
|||
keyDropDownControlObjects.clear();
|
||||
|
||||
std::vector<DWORD> shortcutKeyCodes = shortcut.GetKeyCodes();
|
||||
std::vector<DWORD> keyCodeList = keyboardManagerState.keyboardMap.GetKeyCodeList(true);
|
||||
std::vector<DWORD> keyCodeList = GetKeyCodeList(true, colIndex == 1);
|
||||
if (shortcutKeyCodes.size() != 0)
|
||||
{
|
||||
bool ignoreWarning = false;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include <keyboardmanager/common/Shortcut.h>
|
||||
#include <vector>
|
||||
class KeyboardManagerState;
|
||||
|
||||
namespace winrt::Windows
|
||||
|
@ -42,23 +43,22 @@ private:
|
|||
bool ignoreKeyToShortcutWarning;
|
||||
|
||||
// Function to set properties apart from the SelectionChanged event handler
|
||||
void SetDefaultProperties(bool isShortcut);
|
||||
void SetDefaultProperties(bool isShortcut, bool renderDisable);
|
||||
|
||||
// Function to check if the layout has changed and accordingly update the drop down list
|
||||
void CheckAndUpdateKeyboardLayout(ComboBox currentDropDown, bool isShortcut);
|
||||
void CheckAndUpdateKeyboardLayout(ComboBox currentDropDown, bool isShortcut, bool renderDisable);
|
||||
|
||||
// Function to set accessible name for combobox
|
||||
static void SetAccessibleNameForComboBox(ComboBox dropDown, int index);
|
||||
|
||||
public:
|
||||
// Pointer to the keyboard manager state
|
||||
static KeyboardManagerState* keyboardManagerState;
|
||||
|
||||
// Constructor - the last default parameter should be passed as false only if it originates from Type shortcut or when an old shortcut is reloaded
|
||||
KeyDropDownControl(bool isShortcut, bool fromAddShortcutToControl = false) :
|
||||
KeyDropDownControl(bool isShortcut, bool fromAddShortcutToControl = false, bool renderDisable = false) :
|
||||
ignoreKeyToShortcutWarning(fromAddShortcutToControl)
|
||||
{
|
||||
SetDefaultProperties(isShortcut);
|
||||
SetDefaultProperties(isShortcut, renderDisable);
|
||||
}
|
||||
|
||||
// Function to set selection handler for single key remap drop down. Needs to be called after the constructor since the singleKeyControl StackPanel is null if called in the constructor
|
||||
|
@ -90,4 +90,10 @@ public:
|
|||
|
||||
// Function to add a shortcut to the UI control as combo boxes
|
||||
static void AddShortcutToControl(Shortcut shortcut, Grid table, StackPanel parent, KeyboardManagerState& keyboardManagerState, const int colIndex, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects, RemapBuffer& remapBuffer, StackPanel controlLayout, TextBox targetApp, bool isHybridControl, bool isSingleKeyWindow);
|
||||
|
||||
// Get keys code list depending if Disable is in dropdown
|
||||
static std::vector<DWORD> GetKeyCodeList(bool isShortcut, bool renderDisable);
|
||||
|
||||
// Get keys name list depending if Disable is in dropdown
|
||||
static std::vector<std::wstring> GetKeyNameList(bool isShortcut, bool renderDisable);
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "keyboardmanager/common/Helpers.h"
|
||||
#include "common/common.h"
|
||||
#include "keyboardmanager/dll/Generated Files/resource.h"
|
||||
#include <common\shared_constants.h>
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
//Both static members are initialized to null
|
||||
|
@ -132,9 +133,9 @@ void ShortcutControl::AddNewShortcutControlRow(Grid& parent, std::vector<std::ve
|
|||
KeyDropDownControl::ValidateShortcutFromDropDownList(parent, keyboardRemapControlObjects[rowIndex][1]->getShortcutControl(), keyboardRemapControlObjects[rowIndex][1]->shortcutDropDownStackPanel.as<StackPanel>(), 1, ShortcutControl::shortcutRemapBuffer, keyboardRemapControlObjects[rowIndex][1]->keyDropDownControlObjects, targetAppTextBox, true, false);
|
||||
|
||||
// Reset the buffer based on the selected drop down items
|
||||
std::get<Shortcut>(shortcutRemapBuffer[rowIndex].first[0]).SetKeyCodes(KeyboardManagerHelper::GetKeyCodesFromSelectedIndices(KeyDropDownControl::GetSelectedIndicesFromStackPanel(keyboardRemapControlObjects[rowIndex][0]->shortcutDropDownStackPanel.as<StackPanel>()), KeyDropDownControl::keyboardManagerState->keyboardMap.GetKeyCodeList(true)));
|
||||
std::get<Shortcut>(shortcutRemapBuffer[rowIndex].first[0]).SetKeyCodes(KeyboardManagerHelper::GetKeyCodesFromSelectedIndices(KeyDropDownControl::GetSelectedIndicesFromStackPanel(keyboardRemapControlObjects[rowIndex][0]->shortcutDropDownStackPanel.as<StackPanel>()), KeyDropDownControl::GetKeyCodeList(true, false)));
|
||||
// second column is a hybrid column
|
||||
std::vector<DWORD> selectedKeyCodes = KeyboardManagerHelper::GetKeyCodesFromSelectedIndices(KeyDropDownControl::GetSelectedIndicesFromStackPanel(keyboardRemapControlObjects[rowIndex][1]->shortcutDropDownStackPanel.as<StackPanel>()), KeyDropDownControl::keyboardManagerState->keyboardMap.GetKeyCodeList(true));
|
||||
std::vector<DWORD> selectedKeyCodes = KeyboardManagerHelper::GetKeyCodesFromSelectedIndices(KeyDropDownControl::GetSelectedIndicesFromStackPanel(keyboardRemapControlObjects[rowIndex][1]->shortcutDropDownStackPanel.as<StackPanel>()), KeyDropDownControl::GetKeyCodeList(true, true));
|
||||
|
||||
// If exactly one key is selected consider it to be a key remap
|
||||
if (selectedKeyCodes.size() == 1)
|
||||
|
@ -243,7 +244,7 @@ void ShortcutControl::AddNewShortcutControlRow(Grid& parent, std::vector<std::ve
|
|||
|
||||
if (newKeys.index() == 0)
|
||||
{
|
||||
std::vector<DWORD> shortcutListKeyCodes = keyboardManagerState->keyboardMap.GetKeyCodeList(true);
|
||||
std::vector<DWORD> shortcutListKeyCodes = KeyDropDownControl::GetKeyCodeList(true, true);
|
||||
auto it = std::find(shortcutListKeyCodes.begin(), shortcutListKeyCodes.end(), std::get<DWORD>(newKeys));
|
||||
if (it != shortcutListKeyCodes.end())
|
||||
{
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "ShortcutControl.h"
|
||||
#include "common/common.h"
|
||||
#include "keyboardmanager/dll/Generated Files/resource.h"
|
||||
#include <common\shared_constants.h>
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
//Both static members are initialized to null
|
||||
|
@ -106,7 +107,7 @@ void SingleKeyRemapControl::AddNewControlKeyRemapRow(Grid& parent, std::vector<s
|
|||
{
|
||||
singleKeyRemapBuffer.push_back(std::make_pair<RemapBufferItem, std::wstring>(RemapBufferItem{ originalKey, newKey }, L""));
|
||||
std::vector<DWORD> keyCodes = keyboardManagerState->keyboardMap.GetKeyCodeList();
|
||||
std::vector<DWORD> shortcutListKeyCodes = keyboardManagerState->keyboardMap.GetKeyCodeList(true);
|
||||
std::vector<DWORD> shortcutListKeyCodes = KeyDropDownControl::GetKeyCodeList(true, true);
|
||||
auto it = std::find(keyCodes.begin(), keyCodes.end(), originalKey);
|
||||
if (it != keyCodes.end())
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue