mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-12-04 20:21:18 +08:00
[KBM] decoupling editor and engine (#11133)
This commit is contained in:
parent
9461909321
commit
8785fca309
@ -1,11 +1,10 @@
|
||||
#include "pch.h"
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
|
||||
#include "keyboard_layout_impl.h"
|
||||
#include "shared_constants.h"
|
||||
|
||||
#include <winrt/Windows.UI.Core.h>
|
||||
|
||||
using namespace winrt;
|
||||
|
||||
LayoutMap::LayoutMap() :
|
||||
impl(new LayoutMap::LayoutMapImpl())
|
||||
{
|
||||
|
@ -6,17 +6,16 @@
|
||||
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include <common/utils/ProcessWaiter.h>
|
||||
#include <common/utils/UnhandledExceptionHandler_x64.h>
|
||||
|
||||
#include <trace.h>
|
||||
|
||||
#include <KeyboardEventHandlers.h>
|
||||
#include <KeyboardManagerState.h>
|
||||
#include <SettingsHelper.h>
|
||||
#include <keyboardmanager/common/KeyboardEventHandlers.h>
|
||||
|
||||
#include <EditKeyboardWindow.h>
|
||||
#include <EditShortcutsWindow.h>
|
||||
#include <common/utils/ProcessWaiter.h>
|
||||
#include <KeyboardManagerState.h>
|
||||
|
||||
std::unique_ptr<KeyboardManagerEditor> editor = nullptr;
|
||||
const std::wstring instanceMutexName = L"Local\\PowerToys_KBMEditor_InstanceMutex";
|
||||
@ -114,13 +113,13 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
|
||||
KeyboardManagerEditor::KeyboardManagerEditor(HINSTANCE hInst) :
|
||||
hInstance(hInst)
|
||||
{
|
||||
bool loadedSuccessful = SettingsHelper::LoadSettings(keyboardManagerState);
|
||||
bool loadedSuccessful = mappingConfiguration.LoadSettings();
|
||||
if (!loadedSuccessful)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
|
||||
// retry once
|
||||
SettingsHelper::LoadSettings(keyboardManagerState);
|
||||
mappingConfiguration.LoadSettings();
|
||||
}
|
||||
|
||||
StartLowLevelKeyboardHook();
|
||||
@ -149,44 +148,44 @@ void KeyboardManagerEditor::OpenEditorWindow(KeyboardManagerEditorType type)
|
||||
switch (type)
|
||||
{
|
||||
case KeyboardManagerEditorType::KeyEditor:
|
||||
CreateEditKeyboardWindow(hInstance, keyboardManagerState);
|
||||
CreateEditKeyboardWindow(hInstance, keyboardManagerState, mappingConfiguration);
|
||||
break;
|
||||
case KeyboardManagerEditorType::ShortcutEditor:
|
||||
CreateEditShortcutsWindow(hInstance, keyboardManagerState);
|
||||
CreateEditShortcutsWindow(hInstance, keyboardManagerState, mappingConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t KeyboardManagerEditor::HandleKeyboardHookEvent(LowlevelKeyboardEvent* data) noexcept
|
||||
{
|
||||
// If the Detect Key Window is currently activated, then suppress the keyboard event
|
||||
KeyboardManagerHelper::KeyboardHookDecision singleKeyRemapUIDetected = keyboardManagerState.DetectSingleRemapKeyUIBackend(data);
|
||||
if (singleKeyRemapUIDetected == KeyboardManagerHelper::KeyboardHookDecision::Suppress)
|
||||
Helpers::KeyboardHookDecision singleKeyRemapUIDetected = keyboardManagerState.DetectSingleRemapKeyUIBackend(data);
|
||||
if (singleKeyRemapUIDetected == Helpers::KeyboardHookDecision::Suppress)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (singleKeyRemapUIDetected == KeyboardManagerHelper::KeyboardHookDecision::SkipHook)
|
||||
else if (singleKeyRemapUIDetected == Helpers::KeyboardHookDecision::SkipHook)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If the Detect Shortcut Window from Remap Keys is currently activated, then suppress the keyboard event
|
||||
KeyboardManagerHelper::KeyboardHookDecision remapKeyShortcutUIDetected = keyboardManagerState.DetectShortcutUIBackend(data, true);
|
||||
if (remapKeyShortcutUIDetected == KeyboardManagerHelper::KeyboardHookDecision::Suppress)
|
||||
Helpers::KeyboardHookDecision remapKeyShortcutUIDetected = keyboardManagerState.DetectShortcutUIBackend(data, true);
|
||||
if (remapKeyShortcutUIDetected == Helpers::KeyboardHookDecision::Suppress)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (remapKeyShortcutUIDetected == KeyboardManagerHelper::KeyboardHookDecision::SkipHook)
|
||||
else if (remapKeyShortcutUIDetected == Helpers::KeyboardHookDecision::SkipHook)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If the Detect Shortcut Window is currently activated, then suppress the keyboard event
|
||||
KeyboardManagerHelper::KeyboardHookDecision shortcutUIDetected = keyboardManagerState.DetectShortcutUIBackend(data, false);
|
||||
if (shortcutUIDetected == KeyboardManagerHelper::KeyboardHookDecision::Suppress)
|
||||
Helpers::KeyboardHookDecision shortcutUIDetected = keyboardManagerState.DetectShortcutUIBackend(data, false);
|
||||
if (shortcutUIDetected == Helpers::KeyboardHookDecision::Suppress)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (shortcutUIDetected == KeyboardManagerHelper::KeyboardHookDecision::SkipHook)
|
||||
else if (shortcutUIDetected == Helpers::KeyboardHookDecision::SkipHook)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <keyboardmanager/common/Input.h>
|
||||
#include <keyboardmanager/common/MappingConfiguration.h>
|
||||
|
||||
#include <KeyboardManagerState.h>
|
||||
#include <Input.h>
|
||||
|
||||
enum class KeyboardManagerEditorType
|
||||
{
|
||||
@ -32,7 +34,8 @@ private:
|
||||
inline static HHOOK hook;
|
||||
HINSTANCE hInstance;
|
||||
|
||||
KeyboardManagerState keyboardManagerState;
|
||||
KBMEditor::KeyboardManagerState keyboardManagerState;
|
||||
MappingConfiguration mappingConfiguration;
|
||||
|
||||
// Object of class which implements InputInterface. Required for calling library functions while enabling testing
|
||||
KeyboardManagerInput::Input inputHandler;
|
||||
|
@ -109,7 +109,7 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>./;$(SolutionDir)src\modules\;$(SolutionDir)src\modules\KeyboardManager\KeyboardManagerEditorLibrary\;$(SolutionDir)src\common\Display;$(SolutionDir)src\common\inc;$(SolutionDir)src\common\Telemetry;$(SolutionDir)src;./../common;./../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>./;$(SolutionDir)src\modules\;$(SolutionDir)src\modules\KeyboardManager\KeyboardManagerEditorLibrary\;$(SolutionDir)src\common\Display;$(SolutionDir)src\common\inc;$(SolutionDir)src\common\Telemetry;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Display.lib;shcore.lib;Dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
@ -118,7 +118,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>./;$(SolutionDir)src\modules\;$(SolutionDir)src\modules\KeyboardManager\KeyboardManagerEditorLibrary\;$(SolutionDir)src\common\Display;$(SolutionDir)src\common\inc;$(SolutionDir)src\common\Telemetry;$(SolutionDir)src;./../common;./../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>./;$(SolutionDir)src\modules\;$(SolutionDir)src\modules\KeyboardManager\KeyboardManagerEditorLibrary\;$(SolutionDir)src\common\Display;$(SolutionDir)src\common\inc;$(SolutionDir)src\common\Telemetry;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
|
@ -3,34 +3,12 @@
|
||||
#include "targetver.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#include <unknwn.h>
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
|
||||
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.UI.Core.h>
|
||||
#include <winrt/Windows.UI.Text.h>
|
||||
|
||||
#pragma push_macro("GetCurrentTime")
|
||||
#undef GetCurrentTime
|
||||
#include <winrt/Windows.UI.Xaml.Automation.h>
|
||||
#include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
|
||||
#include <winrt/Windows.UI.Xaml.Hosting.h>
|
||||
#include <winrt/Windows.UI.Xaml.Interop.h>
|
||||
#include <winrt/Windows.ui.xaml.media.h>
|
||||
#pragma pop_macro("GetCurrentTime")
|
||||
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/utils/resources.h>
|
||||
|
||||
#include <Generated Files/resource.h>
|
||||
|
||||
using namespace winrt;
|
||||
using namespace Windows::UI;
|
||||
using namespace Windows::UI::Composition;
|
||||
using namespace Windows::UI::Xaml::Hosting;
|
||||
using namespace Windows::Foundation::Numerics;
|
||||
using namespace Windows::UI::Xaml;
|
||||
using namespace Windows::UI::Xaml::Controls;
|
@ -2,17 +2,20 @@
|
||||
#include "BufferValidationHelpers.h"
|
||||
|
||||
#include <common/interop/shared_constants.h>
|
||||
#include <keyboardmanager/common/KeyboardManagerConstants.h>
|
||||
|
||||
#include <KeyboardManagerEditorStrings.h>
|
||||
#include <KeyboardManagerConstants.h>
|
||||
#include <KeyDropDownControl.h>
|
||||
#include "KeyboardManagerEditorStrings.h"
|
||||
#include "KeyDropDownControl.h"
|
||||
#include "UIHelpers.h"
|
||||
#include "EditorHelpers.h"
|
||||
#include "EditorConstants.h"
|
||||
|
||||
namespace BufferValidationHelpers
|
||||
{
|
||||
// Function to validate and update an element of the key remap buffer when the selection has changed
|
||||
KeyboardManagerHelper::ErrorType ValidateAndUpdateKeyBufferElement(int rowIndex, int colIndex, int selectedKeyCode, RemapBuffer& remapBuffer)
|
||||
ShortcutErrorType ValidateAndUpdateKeyBufferElement(int rowIndex, int colIndex, int selectedKeyCode, RemapBuffer& remapBuffer)
|
||||
{
|
||||
KeyboardManagerHelper::ErrorType errorType = KeyboardManagerHelper::ErrorType::NoError;
|
||||
ShortcutErrorType errorType = ShortcutErrorType::NoError;
|
||||
|
||||
// Check if the element was not found or the index exceeds the known keys
|
||||
if (selectedKeyCode != -1)
|
||||
@ -22,13 +25,13 @@ namespace BufferValidationHelpers
|
||||
{
|
||||
if (std::get<DWORD>(remapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)]) == selectedKeyCode)
|
||||
{
|
||||
errorType = KeyboardManagerHelper::ErrorType::MapToSameKey;
|
||||
errorType = ShortcutErrorType::MapToSameKey;
|
||||
}
|
||||
}
|
||||
|
||||
// If one column is shortcut and other is key no warning required
|
||||
|
||||
if (errorType == KeyboardManagerHelper::ErrorType::NoError && colIndex == 0)
|
||||
if (errorType == ShortcutErrorType::NoError && colIndex == 0)
|
||||
{
|
||||
// Check if the key is already remapped to something else
|
||||
for (int i = 0; i < remapBuffer.size(); i++)
|
||||
@ -37,8 +40,8 @@ namespace BufferValidationHelpers
|
||||
{
|
||||
if (remapBuffer[i].first[colIndex].index() == 0)
|
||||
{
|
||||
KeyboardManagerHelper::ErrorType result = KeyboardManagerHelper::DoKeysOverlap(std::get<DWORD>(remapBuffer[i].first[colIndex]), selectedKeyCode);
|
||||
if (result != KeyboardManagerHelper::ErrorType::NoError)
|
||||
ShortcutErrorType result = EditorHelpers::DoKeysOverlap(std::get<DWORD>(remapBuffer[i].first[colIndex]), selectedKeyCode);
|
||||
if (result != ShortcutErrorType::NoError)
|
||||
{
|
||||
errorType = result;
|
||||
break;
|
||||
@ -51,7 +54,7 @@ namespace BufferValidationHelpers
|
||||
}
|
||||
|
||||
// If there is no error, set the buffer
|
||||
if (errorType == KeyboardManagerHelper::ErrorType::NoError)
|
||||
if (errorType == ShortcutErrorType::NoError)
|
||||
{
|
||||
remapBuffer[rowIndex].first[colIndex] = selectedKeyCode;
|
||||
}
|
||||
@ -70,32 +73,32 @@ namespace BufferValidationHelpers
|
||||
}
|
||||
|
||||
// Function to validate an element of the shortcut remap buffer when the selection has changed
|
||||
std::pair<KeyboardManagerHelper::ErrorType, DropDownAction> ValidateShortcutBufferElement(int rowIndex, int colIndex, uint32_t dropDownIndex, const std::vector<int32_t>& selectedCodes, std::wstring appName, bool isHybridControl, const RemapBuffer& remapBuffer, bool dropDownFound)
|
||||
std::pair<ShortcutErrorType, DropDownAction> ValidateShortcutBufferElement(int rowIndex, int colIndex, uint32_t dropDownIndex, const std::vector<int32_t>& selectedCodes, std::wstring appName, bool isHybridControl, const RemapBuffer& remapBuffer, bool dropDownFound)
|
||||
{
|
||||
BufferValidationHelpers::DropDownAction dropDownAction = BufferValidationHelpers::DropDownAction::NoAction;
|
||||
KeyboardManagerHelper::ErrorType errorType = KeyboardManagerHelper::ErrorType::NoError;
|
||||
ShortcutErrorType errorType = ShortcutErrorType::NoError;
|
||||
size_t dropDownCount = selectedCodes.size();
|
||||
DWORD selectedKeyCode = dropDownFound ? selectedCodes[dropDownIndex] : -1;
|
||||
|
||||
if (selectedKeyCode != -1 && dropDownFound)
|
||||
{
|
||||
// If only 1 drop down and action key is chosen: Warn that a modifier must be chosen (if the drop down is not for a hybrid scenario)
|
||||
if (dropDownCount == 1 && !KeyboardManagerHelper::IsModifierKey(selectedKeyCode) && !isHybridControl)
|
||||
if (dropDownCount == 1 && !Helpers::IsModifierKey(selectedKeyCode) && !isHybridControl)
|
||||
{
|
||||
// warn and reset the drop down
|
||||
errorType = KeyboardManagerHelper::ErrorType::ShortcutStartWithModifier;
|
||||
errorType = ShortcutErrorType::ShortcutStartWithModifier;
|
||||
}
|
||||
else if (dropDownIndex == dropDownCount - 1)
|
||||
{
|
||||
// If it is the last drop down
|
||||
// If last drop down and a modifier is selected: add a new drop down (max drop down count should be enforced)
|
||||
if (KeyboardManagerHelper::IsModifierKey(selectedKeyCode) && dropDownCount < KeyboardManagerConstants::MaxShortcutSize)
|
||||
if (Helpers::IsModifierKey(selectedKeyCode) && dropDownCount < EditorConstants::MaxShortcutSize)
|
||||
{
|
||||
// If it matched any of the previous modifiers then reset that drop down
|
||||
if (KeyboardManagerHelper::CheckRepeatedModifier(selectedCodes, selectedKeyCode))
|
||||
if (EditorHelpers::CheckRepeatedModifier(selectedCodes, selectedKeyCode))
|
||||
{
|
||||
// warn and reset the drop down
|
||||
errorType = KeyboardManagerHelper::ErrorType::ShortcutCannotHaveRepeatedModifier;
|
||||
errorType = ShortcutErrorType::ShortcutCannotHaveRepeatedModifier;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -103,17 +106,17 @@ namespace BufferValidationHelpers
|
||||
dropDownAction = BufferValidationHelpers::DropDownAction::AddDropDown;
|
||||
}
|
||||
}
|
||||
else if (KeyboardManagerHelper::IsModifierKey(selectedKeyCode) && dropDownCount >= KeyboardManagerConstants::MaxShortcutSize)
|
||||
else if (Helpers::IsModifierKey(selectedKeyCode) && dropDownCount >= EditorConstants::MaxShortcutSize)
|
||||
{
|
||||
// If last drop down and a modifier is selected but there are already max drop downs: warn the user
|
||||
// warn and reset the drop down
|
||||
errorType = KeyboardManagerHelper::ErrorType::ShortcutMaxShortcutSizeOneActionKey;
|
||||
errorType = ShortcutErrorType::ShortcutMaxShortcutSizeOneActionKey;
|
||||
}
|
||||
else if (selectedKeyCode == 0)
|
||||
{
|
||||
// If None is selected but it's the last index: warn
|
||||
// If it is a hybrid control and there are 2 drop downs then deletion is allowed
|
||||
if (isHybridControl && dropDownCount == KeyboardManagerConstants::MinShortcutSize)
|
||||
if (isHybridControl && dropDownCount == EditorConstants::MinShortcutSize)
|
||||
{
|
||||
// set delete drop down flag
|
||||
dropDownAction = BufferValidationHelpers::DropDownAction::DeleteDropDown;
|
||||
@ -122,40 +125,40 @@ namespace BufferValidationHelpers
|
||||
else
|
||||
{
|
||||
// warn and reset the drop down
|
||||
errorType = KeyboardManagerHelper::ErrorType::ShortcutOneActionKey;
|
||||
errorType = ShortcutErrorType::ShortcutOneActionKey;
|
||||
}
|
||||
}
|
||||
else if (selectedKeyCode == CommonSharedConstants::VK_DISABLED && dropDownIndex)
|
||||
{
|
||||
// Disable can not be selected if one modifier key has already been selected
|
||||
errorType = KeyboardManagerHelper::ErrorType::ShortcutDisableAsActionKey;
|
||||
errorType = ShortcutErrorType::ShortcutDisableAsActionKey;
|
||||
}
|
||||
// If none of the above, then the action key will be set
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it is not the last drop down
|
||||
if (KeyboardManagerHelper::IsModifierKey(selectedKeyCode))
|
||||
if (Helpers::IsModifierKey(selectedKeyCode))
|
||||
{
|
||||
// If it matched any of the previous modifiers then reset that drop down
|
||||
if (KeyboardManagerHelper::CheckRepeatedModifier(selectedCodes, selectedKeyCode))
|
||||
if (EditorHelpers::CheckRepeatedModifier(selectedCodes, selectedKeyCode))
|
||||
{
|
||||
// warn and reset the drop down
|
||||
errorType = KeyboardManagerHelper::ErrorType::ShortcutCannotHaveRepeatedModifier;
|
||||
errorType = ShortcutErrorType::ShortcutCannotHaveRepeatedModifier;
|
||||
}
|
||||
// If not, the modifier key will be set
|
||||
}
|
||||
else if (selectedKeyCode == 0 && dropDownCount > KeyboardManagerConstants::MinShortcutSize)
|
||||
else if (selectedKeyCode == 0 && dropDownCount > EditorConstants::MinShortcutSize)
|
||||
{
|
||||
// If None is selected and there are more than 2 drop downs
|
||||
// set delete drop down flag
|
||||
dropDownAction = BufferValidationHelpers::DropDownAction::DeleteDropDown;
|
||||
// do not delete the drop down now since there may be some other error which would cause the drop down to be invalid after removal
|
||||
}
|
||||
else if (selectedKeyCode == 0 && dropDownCount <= KeyboardManagerConstants::MinShortcutSize)
|
||||
else if (selectedKeyCode == 0 && dropDownCount <= EditorConstants::MinShortcutSize)
|
||||
{
|
||||
// If it is a hybrid control and there are 2 drop downs then deletion is allowed
|
||||
if (isHybridControl && dropDownCount == KeyboardManagerConstants::MinShortcutSize)
|
||||
if (isHybridControl && dropDownCount == EditorConstants::MinShortcutSize)
|
||||
{
|
||||
// set delete drop down flag
|
||||
dropDownAction = BufferValidationHelpers::DropDownAction::DeleteDropDown;
|
||||
@ -164,13 +167,13 @@ namespace BufferValidationHelpers
|
||||
else
|
||||
{
|
||||
// warn and reset the drop down
|
||||
errorType = KeyboardManagerHelper::ErrorType::ShortcutAtleast2Keys;
|
||||
errorType = ShortcutErrorType::ShortcutAtleast2Keys;
|
||||
}
|
||||
}
|
||||
else if (selectedKeyCode == CommonSharedConstants::VK_DISABLED && dropDownIndex)
|
||||
{
|
||||
// Allow selection of VK_DISABLE only in first dropdown
|
||||
errorType = KeyboardManagerHelper::ErrorType::ShortcutDisableAsActionKey;
|
||||
errorType = ShortcutErrorType::ShortcutDisableAsActionKey;
|
||||
}
|
||||
else if (dropDownIndex != 0 || isHybridControl)
|
||||
{
|
||||
@ -193,20 +196,20 @@ namespace BufferValidationHelpers
|
||||
else
|
||||
{
|
||||
// warn and reset the drop down
|
||||
errorType = KeyboardManagerHelper::ErrorType::ShortcutNotMoreThanOneActionKey;
|
||||
errorType = ShortcutErrorType::ShortcutNotMoreThanOneActionKey;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there an action key is chosen on the first drop down and there are more than one drop down menus
|
||||
// warn and reset the drop down
|
||||
errorType = KeyboardManagerHelper::ErrorType::ShortcutStartWithModifier;
|
||||
errorType = ShortcutErrorType::ShortcutStartWithModifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// After validating the shortcut, now for errors like remap to same shortcut, remap shortcut more than once, Win L and Ctrl Alt Del
|
||||
if (errorType == KeyboardManagerHelper::ErrorType::NoError)
|
||||
if (errorType == ShortcutErrorType::NoError)
|
||||
{
|
||||
KeyShortcutUnion tempShortcut;
|
||||
if (isHybridControl && KeyDropDownControl::GetNumberOfSelectedKeys(selectedCodes) == 1)
|
||||
@ -234,9 +237,10 @@ namespace BufferValidationHelpers
|
||||
// If shortcut to shortcut
|
||||
if (remapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)].index() == 1)
|
||||
{
|
||||
if (std::get<Shortcut>(remapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)]) == std::get<Shortcut>(tempShortcut) && std::get<Shortcut>(remapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)]).IsValidShortcut() && std::get<Shortcut>(tempShortcut).IsValidShortcut())
|
||||
auto& shortcut = std::get<Shortcut>(remapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)]);
|
||||
if (shortcut == std::get<Shortcut>(tempShortcut) && EditorHelpers::IsValidShortcut(shortcut) && EditorHelpers::IsValidShortcut(std::get<Shortcut>(tempShortcut)))
|
||||
{
|
||||
errorType = KeyboardManagerHelper::ErrorType::MapToSameShortcut;
|
||||
errorType = ShortcutErrorType::MapToSameShortcut;
|
||||
}
|
||||
}
|
||||
|
||||
@ -249,14 +253,14 @@ namespace BufferValidationHelpers
|
||||
{
|
||||
if (std::get<DWORD>(remapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)]) == std::get<DWORD>(tempShortcut) && std::get<DWORD>(remapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)]) != NULL && std::get<DWORD>(tempShortcut) != NULL)
|
||||
{
|
||||
errorType = KeyboardManagerHelper::ErrorType::MapToSameKey;
|
||||
errorType = ShortcutErrorType::MapToSameKey;
|
||||
}
|
||||
}
|
||||
|
||||
// If one column is shortcut and other is key no warning required
|
||||
}
|
||||
|
||||
if (errorType == KeyboardManagerHelper::ErrorType::NoError && colIndex == 0)
|
||||
if (errorType == ShortcutErrorType::NoError && colIndex == 0)
|
||||
{
|
||||
// Check if the key is already remapped to something else for the same target app
|
||||
for (int i = 0; i < remapBuffer.size(); i++)
|
||||
@ -266,10 +270,10 @@ namespace BufferValidationHelpers
|
||||
|
||||
if (i != rowIndex && currAppName == appName)
|
||||
{
|
||||
KeyboardManagerHelper::ErrorType result = KeyboardManagerHelper::ErrorType::NoError;
|
||||
ShortcutErrorType result = ShortcutErrorType::NoError;
|
||||
if (!isHybridControl)
|
||||
{
|
||||
result = Shortcut::DoKeysOverlap(std::get<Shortcut>(remapBuffer[i].first[colIndex]), std::get<Shortcut>(tempShortcut));
|
||||
result = EditorHelpers::DoShortcutsOverlap(std::get<Shortcut>(remapBuffer[i].first[colIndex]), std::get<Shortcut>(tempShortcut));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -277,19 +281,20 @@ namespace BufferValidationHelpers
|
||||
{
|
||||
if (std::get<DWORD>(tempShortcut) != NULL && std::get<DWORD>(remapBuffer[i].first[colIndex]) != NULL)
|
||||
{
|
||||
result = KeyboardManagerHelper::DoKeysOverlap(std::get<DWORD>(remapBuffer[i].first[colIndex]), std::get<DWORD>(tempShortcut));
|
||||
result = EditorHelpers::DoKeysOverlap(std::get<DWORD>(remapBuffer[i].first[colIndex]), std::get<DWORD>(tempShortcut));
|
||||
}
|
||||
}
|
||||
else if (tempShortcut.index() == 1 && remapBuffer[i].first[colIndex].index() == 1)
|
||||
{
|
||||
if (std::get<Shortcut>(tempShortcut).IsValidShortcut() && std::get<Shortcut>(remapBuffer[i].first[colIndex]).IsValidShortcut())
|
||||
auto& shortcut = std::get<Shortcut>(remapBuffer[i].first[colIndex]);
|
||||
if (EditorHelpers::IsValidShortcut(std::get<Shortcut>(tempShortcut)) && EditorHelpers::IsValidShortcut(shortcut))
|
||||
{
|
||||
result = Shortcut::DoKeysOverlap(std::get<Shortcut>(remapBuffer[i].first[colIndex]), std::get<Shortcut>(tempShortcut));
|
||||
result = EditorHelpers::DoShortcutsOverlap(std::get<Shortcut>(remapBuffer[i].first[colIndex]), std::get<Shortcut>(tempShortcut));
|
||||
}
|
||||
}
|
||||
// Other scenarios not possible since key to shortcut is with key to key, and shortcut to key is with shortcut to shortcut
|
||||
}
|
||||
if (result != KeyboardManagerHelper::ErrorType::NoError)
|
||||
if (result != ShortcutErrorType::NoError)
|
||||
{
|
||||
errorType = result;
|
||||
break;
|
||||
@ -298,9 +303,9 @@ namespace BufferValidationHelpers
|
||||
}
|
||||
}
|
||||
|
||||
if (errorType == KeyboardManagerHelper::ErrorType::NoError && tempShortcut.index() == 1)
|
||||
if (errorType == ShortcutErrorType::NoError && tempShortcut.index() == 1)
|
||||
{
|
||||
errorType = std::get<Shortcut>(tempShortcut).IsShortcutIllegal();
|
||||
errorType = EditorHelpers::IsShortcutIllegal(std::get<Shortcut>(tempShortcut));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include <keyboardmanager/common/Helpers.h>
|
||||
|
||||
#include "ShortcutErrorType.h"
|
||||
|
||||
namespace BufferValidationHelpers
|
||||
{
|
||||
enum class DropDownAction
|
||||
@ -13,8 +15,8 @@ namespace BufferValidationHelpers
|
||||
};
|
||||
|
||||
// Function to validate and update an element of the key remap buffer when the selection has changed
|
||||
KeyboardManagerHelper::ErrorType ValidateAndUpdateKeyBufferElement(int rowIndex, int colIndex, int selectedKeyCode, RemapBuffer& remapBuffer);
|
||||
ShortcutErrorType ValidateAndUpdateKeyBufferElement(int rowIndex, int colIndex, int selectedKeyCode, RemapBuffer& remapBuffer);
|
||||
|
||||
// Function to validate an element of the shortcut remap buffer when the selection has changed
|
||||
std::pair<KeyboardManagerHelper::ErrorType, DropDownAction> ValidateShortcutBufferElement(int rowIndex, int colIndex, uint32_t dropDownIndex, const std::vector<int32_t>& selectedCodes, std::wstring appName, bool isHybridControl, const RemapBuffer& remapBuffer, bool dropDownFound);
|
||||
std::pair<ShortcutErrorType, DropDownAction> ValidateShortcutBufferElement(int rowIndex, int colIndex, uint32_t dropDownIndex, const std::vector<int32_t>& selectedCodes, std::wstring appName, bool isHybridControl, const RemapBuffer& remapBuffer, bool dropDownFound);
|
||||
}
|
||||
|
@ -6,12 +6,13 @@
|
||||
#include <common/interop/shared_constants.h>
|
||||
#include <common/themes/windows_colors.h>
|
||||
#include <common/utils/EventLocker.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
|
||||
#include <keyboardmanager/common/KeyboardManagerConstants.h>
|
||||
#include <keyboardmanager/common/MappingConfiguration.h>
|
||||
|
||||
#include <KeyboardManagerConstants.h>
|
||||
#include <KeyboardManagerState.h>
|
||||
|
||||
#include "EditKeyboardWindow.h"
|
||||
#include "ErrorTypes.h"
|
||||
#include "SingleKeyRemapControl.h"
|
||||
#include "KeyDropDownControl.h"
|
||||
#include "XamlBridge.h"
|
||||
@ -19,7 +20,8 @@
|
||||
#include "Dialog.h"
|
||||
#include "LoadingAndSavingRemappingHelper.h"
|
||||
#include "UIHelpers.h"
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include "ShortcutErrorType.h"
|
||||
#include "EditorConstants.h"
|
||||
|
||||
using namespace winrt::Windows::Foundation;
|
||||
|
||||
@ -41,7 +43,7 @@ std::mutex editKeyboardWindowMutex;
|
||||
static XamlBridge* xamlBridgePtr = nullptr;
|
||||
|
||||
static IAsyncOperation<bool> OrphanKeysConfirmationDialog(
|
||||
KeyboardManagerState& state,
|
||||
KBMEditor::KeyboardManagerState& state,
|
||||
const std::vector<DWORD>& keys,
|
||||
XamlRoot root)
|
||||
{
|
||||
@ -73,11 +75,11 @@ static IAsyncOperation<bool> OrphanKeysConfirmationDialog(
|
||||
co_return res == ContentDialogResult::Primary;
|
||||
}
|
||||
|
||||
static IAsyncAction OnClickAccept(KeyboardManagerState& keyboardManagerState, XamlRoot root, std::function<void()> ApplyRemappings)
|
||||
static IAsyncAction OnClickAccept(KBMEditor::KeyboardManagerState& keyboardManagerState, XamlRoot root, std::function<void()> ApplyRemappings)
|
||||
{
|
||||
KeyboardManagerHelper::ErrorType isSuccess = LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(SingleKeyRemapControl::singleKeyRemapBuffer);
|
||||
ShortcutErrorType isSuccess = LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(SingleKeyRemapControl::singleKeyRemapBuffer);
|
||||
|
||||
if (isSuccess != KeyboardManagerHelper::ErrorType::NoError)
|
||||
if (isSuccess != ShortcutErrorType::NoError)
|
||||
{
|
||||
if (!co_await Dialog::PartialRemappingConfirmationDialog(root, GET_RESOURCE_STRING(IDS_EDITKEYBOARD_PARTIALCONFIRMATIONDIALOGTITLE)))
|
||||
{
|
||||
@ -100,7 +102,7 @@ static IAsyncAction OnClickAccept(KeyboardManagerState& keyboardManagerState, Xa
|
||||
}
|
||||
|
||||
// Function to create the Edit Keyboard Window
|
||||
inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KeyboardManagerState& keyboardManagerState)
|
||||
inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardManagerState& keyboardManagerState, MappingConfiguration& mappingConfiguration)
|
||||
{
|
||||
Logger::trace("CreateEditKeyboardWindowImpl()");
|
||||
auto locker = EventLocker::Get(KeyboardManagerConstants::EditorWindowEventName.c_str());
|
||||
@ -142,8 +144,8 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KeyboardManagerState&
|
||||
RECT desktopRect = UIHelpers::GetForegroundWindowDesktopRect();
|
||||
|
||||
// Calculate DPI dependent window size
|
||||
int windowWidth = KeyboardManagerConstants::DefaultEditKeyboardWindowWidth;
|
||||
int windowHeight = KeyboardManagerConstants::DefaultEditKeyboardWindowHeight;
|
||||
int windowWidth = EditorConstants::DefaultEditKeyboardWindowWidth;
|
||||
int windowHeight = EditorConstants::DefaultEditKeyboardWindowHeight;
|
||||
|
||||
DPIAware::ConvertByCursorPosition(windowWidth, windowHeight);
|
||||
DPIAware::GetScreenDPIForCursor(g_currentDPI);
|
||||
@ -231,7 +233,7 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KeyboardManagerState&
|
||||
TextBlock originalKeyRemapHeader;
|
||||
originalKeyRemapHeader.Text(GET_RESOURCE_STRING(IDS_EDITKEYBOARD_SOURCEHEADER));
|
||||
originalKeyRemapHeader.FontWeight(Text::FontWeights::Bold());
|
||||
StackPanel originalKeyHeaderContainer = UIHelpers::GetWrapped(originalKeyRemapHeader, KeyboardManagerConstants::RemapTableDropDownWidth + KeyboardManagerConstants::TableArrowColWidth).as<StackPanel>();
|
||||
StackPanel originalKeyHeaderContainer = UIHelpers::GetWrapped(originalKeyRemapHeader, EditorConstants::RemapTableDropDownWidth + EditorConstants::TableArrowColWidth).as<StackPanel>();
|
||||
|
||||
// Second header textblock in the header row of the keys remap table
|
||||
TextBlock newKeyRemapHeader;
|
||||
@ -250,6 +252,7 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KeyboardManagerState&
|
||||
// Store keyboard manager state
|
||||
SingleKeyRemapControl::keyboardManagerState = &keyboardManagerState;
|
||||
KeyDropDownControl::keyboardManagerState = &keyboardManagerState;
|
||||
KeyDropDownControl::mappingConfiguration = &mappingConfiguration;
|
||||
|
||||
// Clear the single key remap buffer
|
||||
SingleKeyRemapControl::singleKeyRemapBuffer.clear();
|
||||
@ -258,10 +261,10 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KeyboardManagerState&
|
||||
std::vector<std::vector<std::unique_ptr<SingleKeyRemapControl>>> keyboardRemapControlObjects;
|
||||
|
||||
// Set keyboard manager UI state so that remaps are not applied while on this window
|
||||
keyboardManagerState.SetUIState(KeyboardManagerUIState::EditKeyboardWindowActivated, _hWndEditKeyboardWindow);
|
||||
keyboardManagerState.SetUIState(KBMEditor::KeyboardManagerUIState::EditKeyboardWindowActivated, _hWndEditKeyboardWindow);
|
||||
|
||||
// Load existing remaps into UI
|
||||
SingleKeyRemapTable singleKeyRemapCopy = keyboardManagerState.singleKeyReMap;
|
||||
SingleKeyRemapTable singleKeyRemapCopy = mappingConfiguration.singleKeyReMap;
|
||||
|
||||
LoadingAndSavingRemappingHelper::PreProcessRemapTable(singleKeyRemapCopy);
|
||||
|
||||
@ -274,14 +277,14 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KeyboardManagerState&
|
||||
Button applyButton;
|
||||
applyButton.Content(winrt::box_value(GET_RESOURCE_STRING(IDS_OK_BUTTON)));
|
||||
applyButton.Style(AccentButtonStyle());
|
||||
applyButton.MinWidth(KeyboardManagerConstants::HeaderButtonWidth);
|
||||
cancelButton.MinWidth(KeyboardManagerConstants::HeaderButtonWidth);
|
||||
applyButton.MinWidth(EditorConstants::HeaderButtonWidth);
|
||||
cancelButton.MinWidth(EditorConstants::HeaderButtonWidth);
|
||||
header.SetAlignRightWithPanel(cancelButton, true);
|
||||
header.SetLeftOf(applyButton, cancelButton);
|
||||
|
||||
auto ApplyRemappings = [&keyboardManagerState, _hWndEditKeyboardWindow]() {
|
||||
LoadingAndSavingRemappingHelper::ApplySingleKeyRemappings(keyboardManagerState, SingleKeyRemapControl::singleKeyRemapBuffer, true);
|
||||
bool saveResult = keyboardManagerState.SaveConfigToFile();
|
||||
auto ApplyRemappings = [&mappingConfiguration, _hWndEditKeyboardWindow]() {
|
||||
LoadingAndSavingRemappingHelper::ApplySingleKeyRemappings(mappingConfiguration, SingleKeyRemapControl::singleKeyRemapBuffer, true);
|
||||
bool saveResult = mappingConfiguration.SaveSettingsToFile();
|
||||
PostMessage(_hWndEditKeyboardWindow, WM_CLOSE, 0, 0);
|
||||
};
|
||||
|
||||
@ -313,7 +316,7 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KeyboardManagerState&
|
||||
scrollViewer.ChangeView(nullptr, scrollViewer.ScrollableHeight(), nullptr);
|
||||
|
||||
// Set focus to the first Type Button in the newly added row
|
||||
UIHelpers::SetFocusOnTypeButtonInLastRow(keyRemapTable, KeyboardManagerConstants::RemapTableColCount);
|
||||
UIHelpers::SetFocusOnTypeButtonInLastRow(keyRemapTable, EditorConstants::RemapTableColCount);
|
||||
});
|
||||
|
||||
// Set accessible name for the addRemapKey button
|
||||
@ -376,10 +379,10 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KeyboardManagerState&
|
||||
xamlBridge.ClearXamlIslands();
|
||||
}
|
||||
|
||||
void CreateEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardManagerState)
|
||||
void CreateEditKeyboardWindow(HINSTANCE hInst, KBMEditor::KeyboardManagerState& keyboardManagerState, MappingConfiguration& mappingConfiguration)
|
||||
{
|
||||
// Move implementation into the separate method so resources get destroyed correctly
|
||||
CreateEditKeyboardWindowImpl(hInst, keyboardManagerState);
|
||||
CreateEditKeyboardWindowImpl(hInst, keyboardManagerState, mappingConfiguration);
|
||||
|
||||
// Calling ClearXamlIslands() outside of the message loop is not enough to prevent
|
||||
// Microsoft.UI.XAML.dll from crashing during deinitialization, see https://github.com/microsoft/PowerToys/issues/10906
|
||||
@ -405,8 +408,8 @@ LRESULT CALLBACK EditKeyboardWindowProc(HWND hWnd, UINT messageCode, WPARAM wPar
|
||||
case WM_GETMINMAXINFO:
|
||||
{
|
||||
LPMINMAXINFO mmi = (LPMINMAXINFO)lParam;
|
||||
int minWidth = KeyboardManagerConstants::MinimumEditKeyboardWindowWidth;
|
||||
int minHeight = KeyboardManagerConstants::MinimumEditKeyboardWindowHeight;
|
||||
int minWidth = EditorConstants::MinimumEditKeyboardWindowWidth;
|
||||
int minHeight = EditorConstants::MinimumEditKeyboardWindowHeight;
|
||||
DPIAware::Convert(MonitorFromWindow(hWnd, MONITOR_DEFAULTTONULL), minWidth, minHeight);
|
||||
mmi->ptMinTrackSize.x = minWidth;
|
||||
mmi->ptMinTrackSize.y = minHeight;
|
||||
|
@ -1,8 +1,14 @@
|
||||
#pragma once
|
||||
class KeyboardManagerState;
|
||||
|
||||
namespace KBMEditor
|
||||
{
|
||||
class KeyboardManagerState;
|
||||
}
|
||||
|
||||
class MappingConfiguration;
|
||||
|
||||
// Function to create the Edit Keyboard Window
|
||||
void CreateEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardManagerState);
|
||||
void CreateEditKeyboardWindow(HINSTANCE hInst, KBMEditor::KeyboardManagerState& keyboardManagerState, MappingConfiguration& mappingConfiguration);
|
||||
|
||||
// Function to check if there is already a window active if yes bring to foreground
|
||||
bool CheckEditKeyboardWindowActive();
|
||||
|
@ -3,18 +3,19 @@
|
||||
|
||||
#include <common/Display/dpi_aware.h>
|
||||
#include <common/utils/EventLocker.h>
|
||||
|
||||
#include <KeyboardManagerState.h>
|
||||
|
||||
#include <Dialog.h>
|
||||
#include <ErrorTypes.h>
|
||||
#include <KeyDropDownControl.h>
|
||||
#include <LoadingAndSavingRemappingHelper.h>
|
||||
#include <ShortcutControl.h>
|
||||
#include <Styles.h>
|
||||
#include <UIHelpers.h>
|
||||
#include <XamlBridge.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include <keyboardmanager/common/MappingConfiguration.h>
|
||||
|
||||
#include "KeyboardManagerState.h"
|
||||
#include "Dialog.h"
|
||||
#include "KeyDropDownControl.h"
|
||||
#include "LoadingAndSavingRemappingHelper.h"
|
||||
#include "ShortcutControl.h"
|
||||
#include "Styles.h"
|
||||
#include "UIHelpers.h"
|
||||
#include "XamlBridge.h"
|
||||
#include "ShortcutErrorType.h"
|
||||
#include "EditorConstants.h"
|
||||
|
||||
using namespace winrt::Windows::Foundation;
|
||||
|
||||
@ -36,13 +37,13 @@ std::mutex editShortcutsWindowMutex;
|
||||
static XamlBridge* xamlBridgePtr = nullptr;
|
||||
|
||||
static IAsyncAction OnClickAccept(
|
||||
KeyboardManagerState& keyboardManagerState,
|
||||
KBMEditor::KeyboardManagerState& keyboardManagerState,
|
||||
XamlRoot root,
|
||||
std::function<void()> ApplyRemappings)
|
||||
{
|
||||
KeyboardManagerHelper::ErrorType isSuccess = LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(ShortcutControl::shortcutRemapBuffer);
|
||||
ShortcutErrorType isSuccess = LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(ShortcutControl::shortcutRemapBuffer);
|
||||
|
||||
if (isSuccess != KeyboardManagerHelper::ErrorType::NoError)
|
||||
if (isSuccess != ShortcutErrorType::NoError)
|
||||
{
|
||||
if (!co_await Dialog::PartialRemappingConfirmationDialog(root, GET_RESOURCE_STRING(IDS_EDITSHORTCUTS_PARTIALCONFIRMATIONDIALOGTITLE)))
|
||||
{
|
||||
@ -53,7 +54,7 @@ static IAsyncAction OnClickAccept(
|
||||
}
|
||||
|
||||
// Function to create the Edit Shortcuts Window
|
||||
inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KeyboardManagerState& keyboardManagerState)
|
||||
inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardManagerState& keyboardManagerState, MappingConfiguration& mappingConfiguration)
|
||||
{
|
||||
Logger::trace("CreateEditShortcutsWindowImpl()");
|
||||
auto locker = EventLocker::Get(KeyboardManagerConstants::EditorWindowEventName.c_str());
|
||||
@ -95,8 +96,8 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KeyboardManagerState&
|
||||
RECT desktopRect = UIHelpers::GetForegroundWindowDesktopRect();
|
||||
|
||||
// Calculate DPI dependent window size
|
||||
int windowWidth = KeyboardManagerConstants::DefaultEditShortcutsWindowWidth;
|
||||
int windowHeight = KeyboardManagerConstants::DefaultEditShortcutsWindowHeight;
|
||||
int windowWidth = EditorConstants::DefaultEditShortcutsWindowWidth;
|
||||
int windowHeight = EditorConstants::DefaultEditShortcutsWindowHeight;
|
||||
DPIAware::ConvertByCursorPosition(windowWidth, windowHeight);
|
||||
DPIAware::GetScreenDPIForCursor(g_currentDPI);
|
||||
|
||||
@ -198,9 +199,9 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KeyboardManagerState&
|
||||
StackPanel tableHeader = StackPanel();
|
||||
tableHeader.Orientation(Orientation::Horizontal);
|
||||
tableHeader.Margin({ 10, 0, 0, 10 });
|
||||
auto originalShortcutContainer = UIHelpers::GetWrapped(originalShortcutHeader, KeyboardManagerConstants::ShortcutOriginColumnWidth + (double)KeyboardManagerConstants::ShortcutArrowColumnWidth);
|
||||
auto originalShortcutContainer = UIHelpers::GetWrapped(originalShortcutHeader, EditorConstants::ShortcutOriginColumnWidth + (double)EditorConstants::ShortcutArrowColumnWidth);
|
||||
tableHeader.Children().Append(originalShortcutContainer.as<FrameworkElement>());
|
||||
auto newShortcutHeaderContainer = UIHelpers::GetWrapped(newShortcutHeader, KeyboardManagerConstants::ShortcutTargetColumnWidth);
|
||||
auto newShortcutHeaderContainer = UIHelpers::GetWrapped(newShortcutHeader, EditorConstants::ShortcutTargetColumnWidth);
|
||||
tableHeader.Children().Append(newShortcutHeaderContainer.as<FrameworkElement>());
|
||||
tableHeader.Children().Append(targetAppHeader);
|
||||
|
||||
@ -210,6 +211,7 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KeyboardManagerState&
|
||||
// Store keyboard manager state
|
||||
ShortcutControl::keyboardManagerState = &keyboardManagerState;
|
||||
KeyDropDownControl::keyboardManagerState = &keyboardManagerState;
|
||||
KeyDropDownControl::mappingConfiguration = &mappingConfiguration;
|
||||
|
||||
// Clear the shortcut remap buffer
|
||||
ShortcutControl::shortcutRemapBuffer.clear();
|
||||
@ -218,11 +220,11 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KeyboardManagerState&
|
||||
std::vector<std::vector<std::unique_ptr<ShortcutControl>>> keyboardRemapControlObjects;
|
||||
|
||||
// Set keyboard manager UI state so that shortcut remaps are not applied while on this window
|
||||
keyboardManagerState.SetUIState(KeyboardManagerUIState::EditShortcutsWindowActivated, _hWndEditShortcutsWindow);
|
||||
keyboardManagerState.SetUIState(KBMEditor::KeyboardManagerUIState::EditShortcutsWindowActivated, _hWndEditShortcutsWindow);
|
||||
|
||||
// Load existing os level shortcuts into UI
|
||||
// Create copy of the remaps to avoid concurrent access
|
||||
ShortcutRemapTable osLevelShortcutReMapCopy = keyboardManagerState.osLevelShortcutReMap;
|
||||
ShortcutRemapTable osLevelShortcutReMapCopy = mappingConfiguration.osLevelShortcutReMap;
|
||||
|
||||
for (const auto& it : osLevelShortcutReMapCopy)
|
||||
{
|
||||
@ -231,7 +233,7 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KeyboardManagerState&
|
||||
|
||||
// Load existing app-specific shortcuts into UI
|
||||
// Create copy of the remaps to avoid concurrent access
|
||||
AppSpecificShortcutRemapTable appSpecificShortcutReMapCopy = keyboardManagerState.appSpecificShortcutReMap;
|
||||
AppSpecificShortcutRemapTable appSpecificShortcutReMapCopy = mappingConfiguration.appSpecificShortcutReMap;
|
||||
|
||||
// Iterate through all the apps
|
||||
for (const auto& itApp : appSpecificShortcutReMapCopy)
|
||||
@ -247,14 +249,14 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KeyboardManagerState&
|
||||
Button applyButton;
|
||||
applyButton.Content(winrt::box_value(GET_RESOURCE_STRING(IDS_OK_BUTTON)));
|
||||
applyButton.Style(AccentButtonStyle());
|
||||
applyButton.MinWidth(KeyboardManagerConstants::HeaderButtonWidth);
|
||||
cancelButton.MinWidth(KeyboardManagerConstants::HeaderButtonWidth);
|
||||
applyButton.MinWidth(EditorConstants::HeaderButtonWidth);
|
||||
cancelButton.MinWidth(EditorConstants::HeaderButtonWidth);
|
||||
header.SetAlignRightWithPanel(cancelButton, true);
|
||||
header.SetLeftOf(applyButton, cancelButton);
|
||||
|
||||
auto ApplyRemappings = [&keyboardManagerState, _hWndEditShortcutsWindow]() {
|
||||
LoadingAndSavingRemappingHelper::ApplyShortcutRemappings(keyboardManagerState, ShortcutControl::shortcutRemapBuffer, true);
|
||||
bool saveResult = keyboardManagerState.SaveConfigToFile();
|
||||
auto ApplyRemappings = [&mappingConfiguration, _hWndEditShortcutsWindow]() {
|
||||
LoadingAndSavingRemappingHelper::ApplyShortcutRemappings(mappingConfiguration, ShortcutControl::shortcutRemapBuffer, true);
|
||||
bool saveResult = mappingConfiguration.SaveSettingsToFile();
|
||||
PostMessage(_hWndEditShortcutsWindow, WM_CLOSE, 0, 0);
|
||||
};
|
||||
|
||||
@ -286,7 +288,7 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KeyboardManagerState&
|
||||
scrollViewer.ChangeView(nullptr, scrollViewer.ScrollableHeight(), nullptr);
|
||||
|
||||
// Set focus to the first Type Button in the newly added row
|
||||
UIHelpers::SetFocusOnTypeButtonInLastRow(shortcutTable, KeyboardManagerConstants::ShortcutTableColCount);
|
||||
UIHelpers::SetFocusOnTypeButtonInLastRow(shortcutTable, EditorConstants::ShortcutTableColCount);
|
||||
});
|
||||
|
||||
// Set accessible name for the add shortcut button
|
||||
@ -349,10 +351,10 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KeyboardManagerState&
|
||||
xamlBridge.ClearXamlIslands();
|
||||
}
|
||||
|
||||
void CreateEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardManagerState)
|
||||
void CreateEditShortcutsWindow(HINSTANCE hInst, KBMEditor::KeyboardManagerState& keyboardManagerState, MappingConfiguration& mappingConfiguration)
|
||||
{
|
||||
// Move implementation into the separate method so resources get destroyed correctly
|
||||
CreateEditShortcutsWindowImpl(hInst, keyboardManagerState);
|
||||
CreateEditShortcutsWindowImpl(hInst, keyboardManagerState, mappingConfiguration);
|
||||
|
||||
// Calling ClearXamlIslands() outside of the message loop is not enough to prevent
|
||||
// Microsoft.UI.XAML.dll from crashing during deinitialization, see https://github.com/microsoft/PowerToys/issues/10906
|
||||
@ -378,8 +380,8 @@ LRESULT CALLBACK EditShortcutsWindowProc(HWND hWnd, UINT messageCode, WPARAM wPa
|
||||
case WM_GETMINMAXINFO:
|
||||
{
|
||||
LPMINMAXINFO mmi = (LPMINMAXINFO)lParam;
|
||||
int minWidth = KeyboardManagerConstants::MinimumEditShortcutsWindowWidth;
|
||||
int minHeight = KeyboardManagerConstants::MinimumEditShortcutsWindowHeight;
|
||||
int minWidth = EditorConstants::MinimumEditShortcutsWindowWidth;
|
||||
int minHeight = EditorConstants::MinimumEditShortcutsWindowHeight;
|
||||
DPIAware::Convert(MonitorFromWindow(hWnd, MONITOR_DEFAULTTONULL), minWidth, minHeight);
|
||||
mmi->ptMinTrackSize.x = minWidth;
|
||||
mmi->ptMinTrackSize.y = minHeight;
|
||||
|
@ -1,8 +1,14 @@
|
||||
#pragma once
|
||||
class KeyboardManagerState;
|
||||
|
||||
namespace KBMEditor
|
||||
{
|
||||
class KeyboardManagerState;
|
||||
}
|
||||
|
||||
class MappingConfiguration;
|
||||
|
||||
// Function to create the Edit Shortcuts Window
|
||||
void CreateEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardManagerState);
|
||||
void CreateEditShortcutsWindow(HINSTANCE hInst, KBMEditor::KeyboardManagerState& keyboardManagerState, MappingConfiguration& mappingConfiguration);
|
||||
|
||||
// Function to check if there is already a window active if yes bring to foreground
|
||||
bool CheckEditShortcutsWindowActive();
|
||||
|
@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
namespace EditorConstants
|
||||
{
|
||||
// Default window sizes
|
||||
inline const int DefaultEditKeyboardWindowWidth = 800;
|
||||
inline const int DefaultEditKeyboardWindowHeight = 600;
|
||||
inline const int MinimumEditKeyboardWindowWidth = 500;
|
||||
inline const int MinimumEditKeyboardWindowHeight = 450;
|
||||
inline const int EditKeyboardTableMinWidth = 700;
|
||||
inline const int DefaultEditShortcutsWindowWidth = 1050;
|
||||
inline const int DefaultEditShortcutsWindowHeight = 600;
|
||||
inline const int MinimumEditShortcutsWindowWidth = 500;
|
||||
inline const int MinimumEditShortcutsWindowHeight = 500;
|
||||
inline const int EditShortcutsTableMinWidth = 1000;
|
||||
|
||||
// Key Remap table constants
|
||||
inline const long RemapTableColCount = 4;
|
||||
inline const long RemapTableHeaderCount = 2;
|
||||
inline const long RemapTableOriginalColIndex = 0;
|
||||
inline const long RemapTableArrowColIndex = 1;
|
||||
inline const long RemapTableNewColIndex = 2;
|
||||
inline const long RemapTableRemoveColIndex = 3;
|
||||
inline const DWORD64 RemapTableDropDownWidth = 110;
|
||||
|
||||
// Shortcut table constants
|
||||
inline const long ShortcutTableColCount = 5;
|
||||
inline const long ShortcutTableHeaderCount = 3;
|
||||
inline const long ShortcutTableOriginalColIndex = 0;
|
||||
inline const long ShortcutTableArrowColIndex = 1;
|
||||
inline const long ShortcutTableNewColIndex = 2;
|
||||
inline const long ShortcutTableTargetAppColIndex = 3;
|
||||
inline const long ShortcutTableRemoveColIndex = 4;
|
||||
inline const long ShortcutArrowColumnWidth = 90;
|
||||
inline const DWORD64 ShortcutTableDropDownWidth = 110;
|
||||
inline const DWORD64 ShortcutTableDropDownSpacing = 10;
|
||||
inline const long ShortcutOriginColumnWidth = 3 * ShortcutTableDropDownWidth + 2 * ShortcutTableDropDownSpacing;
|
||||
inline const long ShortcutTargetColumnWidth = 3 * ShortcutTableDropDownWidth + 2 * ShortcutTableDropDownSpacing + 25;
|
||||
|
||||
// Drop down height used for both Edit Keyboard and Edit Shortcuts
|
||||
inline const DWORD64 TableDropDownHeight = 200;
|
||||
inline const DWORD64 TableArrowColWidth = 230;
|
||||
inline const DWORD64 TableRemoveColWidth = 20;
|
||||
inline const DWORD64 TableWarningColWidth = 20;
|
||||
inline const DWORD64 TableTargetAppColWidth = ShortcutTableDropDownWidth + TableRemoveColWidth * 2;
|
||||
|
||||
// Shared style constants for both Remap Table and Shortcut Table
|
||||
inline const DWORD64 HeaderButtonWidth = 100;
|
||||
|
||||
// Minimum and maximum size of a shortcut
|
||||
inline const long MinShortcutSize = 2;
|
||||
inline const long MaxShortcutSize = 3;
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
#include "pch.h"
|
||||
#include <common/interop/keyboard_layout.h>
|
||||
#include <keyboardmanager/common/Helpers.h>
|
||||
|
||||
#include "ShortcutErrorType.h"
|
||||
|
||||
using Helpers::GetKeyType;
|
||||
|
||||
namespace EditorHelpers
|
||||
{
|
||||
// Function to check if two keys are equal or cover the same set of keys. Return value depends on type of overlap
|
||||
ShortcutErrorType DoKeysOverlap(DWORD first, DWORD second)
|
||||
{
|
||||
// If the keys are same
|
||||
if (first == second)
|
||||
{
|
||||
return ShortcutErrorType::SameKeyPreviouslyMapped;
|
||||
}
|
||||
else if ((GetKeyType(first) == GetKeyType(second)) && GetKeyType(first) != Helpers::KeyType::Action)
|
||||
{
|
||||
// If the keys are of the same modifier type and overlapping, i.e. one is L/R and other is common
|
||||
if (((first == VK_LWIN && second == VK_RWIN) || (first == VK_RWIN && second == VK_LWIN)) || ((first == VK_LCONTROL && second == VK_RCONTROL) || (first == VK_RCONTROL && second == VK_LCONTROL)) || ((first == VK_LMENU && second == VK_RMENU) || (first == VK_RMENU && second == VK_LMENU)) || ((first == VK_LSHIFT && second == VK_RSHIFT) || (first == VK_RSHIFT && second == VK_LSHIFT)))
|
||||
{
|
||||
return ShortcutErrorType::NoError;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ShortcutErrorType::ConflictingModifierKey;
|
||||
}
|
||||
}
|
||||
// If no overlap
|
||||
else
|
||||
{
|
||||
return ShortcutErrorType::NoError;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to check if a modifier has been repeated in the previous drop downs
|
||||
bool CheckRepeatedModifier(const std::vector<int32_t>& currentKeys, int selectedKeyCode)
|
||||
{
|
||||
// Count the number of keys that are equal to 'selectedKeyCode'
|
||||
int numberOfSameType = 0;
|
||||
for (int i = 0; i < currentKeys.size(); i++)
|
||||
{
|
||||
numberOfSameType += Helpers::GetKeyType(selectedKeyCode) == Helpers::GetKeyType(currentKeys[i]);
|
||||
}
|
||||
|
||||
// If we have at least two keys equal to 'selectedKeyCode' than modifier was repeated
|
||||
return numberOfSameType > 1;
|
||||
}
|
||||
|
||||
// Function to return true if the shortcut is valid. A valid shortcut has atleast one modifier, as well as an action key
|
||||
bool IsValidShortcut(Shortcut shortcut)
|
||||
{
|
||||
if (shortcut.actionKey != NULL)
|
||||
{
|
||||
if (shortcut.winKey != ModifierKey::Disabled || shortcut.ctrlKey != ModifierKey::Disabled || shortcut.altKey != ModifierKey::Disabled || shortcut.shiftKey != ModifierKey::Disabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Function to check if the two shortcuts are equal or cover the same set of keys. Return value depends on type of overlap
|
||||
ShortcutErrorType DoShortcutsOverlap(const Shortcut& first, const Shortcut& second)
|
||||
{
|
||||
if (IsValidShortcut(first) && IsValidShortcut(second))
|
||||
{
|
||||
// If the shortcuts are equal
|
||||
if (first == second)
|
||||
{
|
||||
return ShortcutErrorType::SameShortcutPreviouslyMapped;
|
||||
}
|
||||
// action keys match
|
||||
else if (first.actionKey == second.actionKey)
|
||||
{
|
||||
// corresponding modifiers are either both disabled or both not disabled - this ensures that both match in types of modifiers i.e. Ctrl(l/r/c) Shift (l/r/c) A matches Ctrl(l/r/c) Shift (l/r/c) A
|
||||
if (((first.winKey != ModifierKey::Disabled && second.winKey != ModifierKey::Disabled) || (first.winKey == ModifierKey::Disabled && second.winKey == ModifierKey::Disabled)) &&
|
||||
((first.ctrlKey != ModifierKey::Disabled && second.ctrlKey != ModifierKey::Disabled) || (first.ctrlKey == ModifierKey::Disabled && second.ctrlKey == ModifierKey::Disabled)) &&
|
||||
((first.altKey != ModifierKey::Disabled && second.altKey != ModifierKey::Disabled) || (first.altKey == ModifierKey::Disabled && second.altKey == ModifierKey::Disabled)) &&
|
||||
((first.shiftKey != ModifierKey::Disabled && second.shiftKey != ModifierKey::Disabled) || (first.shiftKey == ModifierKey::Disabled && second.shiftKey == ModifierKey::Disabled)))
|
||||
{
|
||||
// If one of the modifier is common
|
||||
if ((first.winKey == ModifierKey::Both || second.winKey == ModifierKey::Both) ||
|
||||
(first.ctrlKey == ModifierKey::Both || second.ctrlKey == ModifierKey::Both) ||
|
||||
(first.altKey == ModifierKey::Both || second.altKey == ModifierKey::Both) ||
|
||||
(first.shiftKey == ModifierKey::Both || second.shiftKey == ModifierKey::Both))
|
||||
{
|
||||
return ShortcutErrorType::ConflictingModifierShortcut;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ShortcutErrorType::NoError;
|
||||
}
|
||||
|
||||
// Function to return a vector of hstring for each key in the display order
|
||||
std::vector<winrt::hstring> GetKeyVector(Shortcut shortcut, LayoutMap& keyboardMap)
|
||||
{
|
||||
std::vector<winrt::hstring> keys;
|
||||
if (shortcut.winKey != ModifierKey::Disabled)
|
||||
{
|
||||
keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(shortcut.GetWinKey(ModifierKey::Both)).c_str()));
|
||||
}
|
||||
if (shortcut.ctrlKey != ModifierKey::Disabled)
|
||||
{
|
||||
keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(shortcut.GetCtrlKey()).c_str()));
|
||||
}
|
||||
if (shortcut.altKey != ModifierKey::Disabled)
|
||||
{
|
||||
keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(shortcut.GetAltKey()).c_str()));
|
||||
}
|
||||
if (shortcut.shiftKey != ModifierKey::Disabled)
|
||||
{
|
||||
keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(shortcut.GetShiftKey()).c_str()));
|
||||
}
|
||||
if (shortcut.actionKey != NULL)
|
||||
{
|
||||
keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(shortcut.actionKey).c_str()));
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
// Function to check if the shortcut is illegal (i.e. Win+L or Ctrl+Alt+Del)
|
||||
ShortcutErrorType IsShortcutIllegal(Shortcut shortcut)
|
||||
{
|
||||
// Win+L
|
||||
if (shortcut.winKey != ModifierKey::Disabled && shortcut.ctrlKey == ModifierKey::Disabled && shortcut.altKey == ModifierKey::Disabled && shortcut.shiftKey == ModifierKey::Disabled && shortcut.actionKey == 0x4C)
|
||||
{
|
||||
return ShortcutErrorType::WinL;
|
||||
}
|
||||
|
||||
// Ctrl+Alt+Del
|
||||
if (shortcut.winKey == ModifierKey::Disabled && shortcut.ctrlKey != ModifierKey::Disabled && shortcut.altKey != ModifierKey::Disabled && shortcut.shiftKey == ModifierKey::Disabled && shortcut.actionKey == VK_DELETE)
|
||||
{
|
||||
return ShortcutErrorType::CtrlAltDel;
|
||||
}
|
||||
|
||||
return ShortcutErrorType::NoError;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include <keyboardmanager/common/Shortcut.h>
|
||||
|
||||
#include "ShortcutErrorType.h"
|
||||
|
||||
namespace EditorHelpers
|
||||
{
|
||||
// Function to check if two keys are equal or cover the same set of keys. Return value depends on type of overlap
|
||||
ShortcutErrorType DoKeysOverlap(DWORD first, DWORD second);
|
||||
|
||||
// Function to check if a modifier has been repeated in the previous drop downs
|
||||
bool CheckRepeatedModifier(const std::vector<int32_t>& currentKeys, int selectedKeyCodes);
|
||||
|
||||
// Function to return true if the shortcut is valid. A valid shortcut has atleast one modifier, as well as an action key
|
||||
bool IsValidShortcut(Shortcut shortcut);
|
||||
|
||||
// Function to check if the two shortcuts are equal or cover the same set of keys. Return value depends on type of overlap
|
||||
ShortcutErrorType DoShortcutsOverlap(const Shortcut& first, const Shortcut& second);
|
||||
|
||||
// Function to return a vector of hstring for each key in the display order
|
||||
std::vector<winrt::hstring> GetKeyVector(Shortcut shortcut, LayoutMap& keyboardMap);
|
||||
|
||||
// Function to check if the shortcut is illegal (i.e. Win+L or Ctrl+Alt+Del)
|
||||
ShortcutErrorType IsShortcutIllegal(Shortcut shortcut);
|
||||
}
|
@ -1,166 +1,166 @@
|
||||
#include "pch.h"
|
||||
#include "KeyDelay.h"
|
||||
|
||||
// NOTE: The destructor should never be called on the DelayThread, i.e. from any of shortPress, longPress or longPressReleased, as it will re-enter the mutex. Even if the mutex is removed it will deadlock because of the join statement
|
||||
KeyDelay::~KeyDelay()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(_queueMutex);
|
||||
_quit = true;
|
||||
_cv.notify_all();
|
||||
l.unlock();
|
||||
_delayThread.join();
|
||||
}
|
||||
|
||||
void KeyDelay::KeyEvent(LowlevelKeyboardEvent* ev)
|
||||
{
|
||||
std::lock_guard guard(_queueMutex);
|
||||
_queue.push({ ev->lParam->time, ev->wParam });
|
||||
_cv.notify_all();
|
||||
}
|
||||
|
||||
KeyTimedEvent KeyDelay::NextEvent()
|
||||
{
|
||||
auto ev = _queue.front();
|
||||
_queue.pop();
|
||||
return ev;
|
||||
}
|
||||
|
||||
bool KeyDelay::CheckIfMillisHaveElapsed(DWORD64 first, DWORD64 last, DWORD64 duration)
|
||||
{
|
||||
if (first < last && first <= first + duration)
|
||||
{
|
||||
return first + duration < last;
|
||||
}
|
||||
else
|
||||
{
|
||||
first += ULLONG_MAX / 2;
|
||||
last += ULLONG_MAX / 2;
|
||||
return first + duration < last;
|
||||
}
|
||||
}
|
||||
|
||||
bool KeyDelay::HasNextEvent()
|
||||
{
|
||||
return !_queue.empty();
|
||||
}
|
||||
|
||||
bool KeyDelay::HandleRelease()
|
||||
{
|
||||
while (HasNextEvent())
|
||||
{
|
||||
auto ev = NextEvent();
|
||||
switch (ev.message)
|
||||
{
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
_state = KeyDelayState::ON_HOLD;
|
||||
_initialHoldKeyDown = ev.time;
|
||||
return false;
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeyDelay::HandleOnHold(std::unique_lock<std::mutex>& cvLock)
|
||||
{
|
||||
while (HasNextEvent())
|
||||
{
|
||||
auto ev = NextEvent();
|
||||
switch (ev.message)
|
||||
{
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
break;
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
if (CheckIfMillisHaveElapsed(_initialHoldKeyDown, ev.time, LONG_PRESS_DELAY_MILLIS))
|
||||
{
|
||||
if (_onLongPressDetected != nullptr)
|
||||
{
|
||||
_onLongPressDetected(_key);
|
||||
}
|
||||
if (_onLongPressReleased != nullptr)
|
||||
{
|
||||
_onLongPressReleased(_key);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_onShortPress != nullptr)
|
||||
{
|
||||
_onShortPress(_key);
|
||||
}
|
||||
}
|
||||
_state = KeyDelayState::RELEASED;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (CheckIfMillisHaveElapsed(_initialHoldKeyDown, GetTickCount64(), LONG_PRESS_DELAY_MILLIS))
|
||||
{
|
||||
if (_onLongPressDetected != nullptr)
|
||||
{
|
||||
_onLongPressDetected(_key);
|
||||
}
|
||||
_state = KeyDelayState::ON_HOLD_TIMEOUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cv.wait_for(cvLock, std::chrono::milliseconds(ON_HOLD_WAIT_TIMEOUT_MILLIS));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KeyDelay::HandleOnHoldTimeout()
|
||||
{
|
||||
while (HasNextEvent())
|
||||
{
|
||||
auto ev = NextEvent();
|
||||
switch (ev.message)
|
||||
{
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
break;
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
if (_onLongPressReleased != nullptr)
|
||||
{
|
||||
_onLongPressReleased(_key);
|
||||
}
|
||||
_state = KeyDelayState::RELEASED;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void KeyDelay::DelayThread()
|
||||
{
|
||||
std::unique_lock<std::mutex> qLock(_queueMutex);
|
||||
bool shouldWait = true;
|
||||
while (!_quit)
|
||||
{
|
||||
if (shouldWait)
|
||||
{
|
||||
_cv.wait(qLock);
|
||||
}
|
||||
|
||||
switch (_state)
|
||||
{
|
||||
case KeyDelayState::RELEASED:
|
||||
shouldWait = HandleRelease();
|
||||
break;
|
||||
case KeyDelayState::ON_HOLD:
|
||||
shouldWait = HandleOnHold(qLock);
|
||||
break;
|
||||
case KeyDelayState::ON_HOLD_TIMEOUT:
|
||||
shouldWait = HandleOnHoldTimeout();
|
||||
break;
|
||||
}
|
||||
}
|
||||
#include "pch.h"
|
||||
#include "KeyDelay.h"
|
||||
|
||||
// NOTE: The destructor should never be called on the DelayThread, i.e. from any of shortPress, longPress or longPressReleased, as it will re-enter the mutex. Even if the mutex is removed it will deadlock because of the join statement
|
||||
KeyDelay::~KeyDelay()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(_queueMutex);
|
||||
_quit = true;
|
||||
_cv.notify_all();
|
||||
l.unlock();
|
||||
_delayThread.join();
|
||||
}
|
||||
|
||||
void KeyDelay::KeyEvent(LowlevelKeyboardEvent* ev)
|
||||
{
|
||||
std::lock_guard guard(_queueMutex);
|
||||
_queue.push({ ev->lParam->time, ev->wParam });
|
||||
_cv.notify_all();
|
||||
}
|
||||
|
||||
KeyTimedEvent KeyDelay::NextEvent()
|
||||
{
|
||||
auto ev = _queue.front();
|
||||
_queue.pop();
|
||||
return ev;
|
||||
}
|
||||
|
||||
bool KeyDelay::CheckIfMillisHaveElapsed(DWORD64 first, DWORD64 last, DWORD64 duration)
|
||||
{
|
||||
if (first < last && first <= first + duration)
|
||||
{
|
||||
return first + duration < last;
|
||||
}
|
||||
else
|
||||
{
|
||||
first += ULLONG_MAX / 2;
|
||||
last += ULLONG_MAX / 2;
|
||||
return first + duration < last;
|
||||
}
|
||||
}
|
||||
|
||||
bool KeyDelay::HasNextEvent()
|
||||
{
|
||||
return !_queue.empty();
|
||||
}
|
||||
|
||||
bool KeyDelay::HandleRelease()
|
||||
{
|
||||
while (HasNextEvent())
|
||||
{
|
||||
auto ev = NextEvent();
|
||||
switch (ev.message)
|
||||
{
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
_state = KeyDelayState::ON_HOLD;
|
||||
_initialHoldKeyDown = ev.time;
|
||||
return false;
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeyDelay::HandleOnHold(std::unique_lock<std::mutex>& cvLock)
|
||||
{
|
||||
while (HasNextEvent())
|
||||
{
|
||||
auto ev = NextEvent();
|
||||
switch (ev.message)
|
||||
{
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
break;
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
if (CheckIfMillisHaveElapsed(_initialHoldKeyDown, ev.time, LONG_PRESS_DELAY_MILLIS))
|
||||
{
|
||||
if (_onLongPressDetected != nullptr)
|
||||
{
|
||||
_onLongPressDetected(_key);
|
||||
}
|
||||
if (_onLongPressReleased != nullptr)
|
||||
{
|
||||
_onLongPressReleased(_key);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_onShortPress != nullptr)
|
||||
{
|
||||
_onShortPress(_key);
|
||||
}
|
||||
}
|
||||
_state = KeyDelayState::RELEASED;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (CheckIfMillisHaveElapsed(_initialHoldKeyDown, GetTickCount64(), LONG_PRESS_DELAY_MILLIS))
|
||||
{
|
||||
if (_onLongPressDetected != nullptr)
|
||||
{
|
||||
_onLongPressDetected(_key);
|
||||
}
|
||||
_state = KeyDelayState::ON_HOLD_TIMEOUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cv.wait_for(cvLock, std::chrono::milliseconds(ON_HOLD_WAIT_TIMEOUT_MILLIS));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KeyDelay::HandleOnHoldTimeout()
|
||||
{
|
||||
while (HasNextEvent())
|
||||
{
|
||||
auto ev = NextEvent();
|
||||
switch (ev.message)
|
||||
{
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
break;
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
if (_onLongPressReleased != nullptr)
|
||||
{
|
||||
_onLongPressReleased(_key);
|
||||
}
|
||||
_state = KeyDelayState::RELEASED;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void KeyDelay::DelayThread()
|
||||
{
|
||||
std::unique_lock<std::mutex> qLock(_queueMutex);
|
||||
bool shouldWait = true;
|
||||
while (!_quit)
|
||||
{
|
||||
if (shouldWait)
|
||||
{
|
||||
_cv.wait(qLock);
|
||||
}
|
||||
|
||||
switch (_state)
|
||||
{
|
||||
case KeyDelayState::RELEASED:
|
||||
shouldWait = HandleRelease();
|
||||
break;
|
||||
case KeyDelayState::ON_HOLD:
|
||||
shouldWait = HandleOnHold(qLock);
|
||||
break;
|
||||
case KeyDelayState::ON_HOLD_TIMEOUT:
|
||||
shouldWait = HandleOnHoldTimeout();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,93 +1,93 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
|
||||
#include <common/hooks/LowlevelKeyboardEvent.h>
|
||||
// Available states for the KeyDelay state machine.
|
||||
enum class KeyDelayState
|
||||
{
|
||||
RELEASED,
|
||||
ON_HOLD,
|
||||
ON_HOLD_TIMEOUT,
|
||||
};
|
||||
|
||||
// Virtual key + timestamp (in millis since Windows startup)
|
||||
struct KeyTimedEvent
|
||||
{
|
||||
DWORD64 time;
|
||||
WPARAM message;
|
||||
};
|
||||
|
||||
// Handles delayed key inputs.
|
||||
// Implemented as a state machine running on its own thread.
|
||||
// Thread stops on destruction.
|
||||
class KeyDelay
|
||||
{
|
||||
public:
|
||||
KeyDelay(
|
||||
DWORD key,
|
||||
std::function<void(DWORD)> onShortPress,
|
||||
std::function<void(DWORD)> onLongPressDetected,
|
||||
std::function<void(DWORD)> onLongPressReleased) :
|
||||
_quit(false),
|
||||
_state(KeyDelayState::RELEASED),
|
||||
_initialHoldKeyDown(0),
|
||||
_key(key),
|
||||
_onShortPress(onShortPress),
|
||||
_onLongPressDetected(onLongPressDetected),
|
||||
_onLongPressReleased(onLongPressReleased),
|
||||
_delayThread(&KeyDelay::DelayThread, this){};
|
||||
|
||||
// Enque new KeyTimedEvent and notify the condition variable.
|
||||
void KeyEvent(LowlevelKeyboardEvent* ev);
|
||||
~KeyDelay();
|
||||
|
||||
private:
|
||||
// Runs the state machine, waits if there is no events to process.
|
||||
// Checks for _quit condition.
|
||||
void DelayThread();
|
||||
|
||||
// Manage state transitions and trigger callbacks on certain events.
|
||||
// Returns whether or not the thread should wait on new events.
|
||||
bool HandleRelease();
|
||||
bool HandleOnHold(std::unique_lock<std::mutex>& cvLock);
|
||||
bool HandleOnHoldTimeout();
|
||||
|
||||
// Get next key event in queue.
|
||||
KeyTimedEvent NextEvent();
|
||||
bool HasNextEvent();
|
||||
|
||||
// Check if <duration> milliseconds passed since <first> millisecond.
|
||||
// Also checks for overflow conditions.
|
||||
bool CheckIfMillisHaveElapsed(DWORD64 first, DWORD64 last, DWORD64 duration);
|
||||
|
||||
bool _quit;
|
||||
KeyDelayState _state;
|
||||
|
||||
// Callback functions, the key provided in the constructor is passed as an argument.
|
||||
std::function<void(DWORD)> _onLongPressDetected;
|
||||
std::function<void(DWORD)> _onLongPressReleased;
|
||||
std::function<void(DWORD)> _onShortPress;
|
||||
|
||||
// Queue holding key events that are not processed yet. Should be kept synchronized
|
||||
// using _queueMutex
|
||||
std::queue<KeyTimedEvent> _queue;
|
||||
std::mutex _queueMutex;
|
||||
|
||||
// DelayThread waits on this condition variable when there is no events to process.
|
||||
std::condition_variable _cv;
|
||||
|
||||
// Keeps track of the time at which the initial KEY_DOWN event happened.
|
||||
DWORD64 _initialHoldKeyDown;
|
||||
|
||||
// Virtual Key provided in the constructor. Passed to callback functions.
|
||||
DWORD _key;
|
||||
|
||||
// Declare _delayThread after all other members so that it is the last to be initialized by the constructor
|
||||
std::thread _delayThread;
|
||||
|
||||
static const DWORD64 LONG_PRESS_DELAY_MILLIS = 900;
|
||||
static const DWORD64 ON_HOLD_WAIT_TIMEOUT_MILLIS = 50;
|
||||
};
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
|
||||
#include <common/hooks/LowlevelKeyboardEvent.h>
|
||||
// Available states for the KeyDelay state machine.
|
||||
enum class KeyDelayState
|
||||
{
|
||||
RELEASED,
|
||||
ON_HOLD,
|
||||
ON_HOLD_TIMEOUT,
|
||||
};
|
||||
|
||||
// Virtual key + timestamp (in millis since Windows startup)
|
||||
struct KeyTimedEvent
|
||||
{
|
||||
DWORD64 time;
|
||||
WPARAM message;
|
||||
};
|
||||
|
||||
// Handles delayed key inputs.
|
||||
// Implemented as a state machine running on its own thread.
|
||||
// Thread stops on destruction.
|
||||
class KeyDelay
|
||||
{
|
||||
public:
|
||||
KeyDelay(
|
||||
DWORD key,
|
||||
std::function<void(DWORD)> onShortPress,
|
||||
std::function<void(DWORD)> onLongPressDetected,
|
||||
std::function<void(DWORD)> onLongPressReleased) :
|
||||
_quit(false),
|
||||
_state(KeyDelayState::RELEASED),
|
||||
_initialHoldKeyDown(0),
|
||||
_key(key),
|
||||
_onShortPress(onShortPress),
|
||||
_onLongPressDetected(onLongPressDetected),
|
||||
_onLongPressReleased(onLongPressReleased),
|
||||
_delayThread(&KeyDelay::DelayThread, this){};
|
||||
|
||||
// Enque new KeyTimedEvent and notify the condition variable.
|
||||
void KeyEvent(LowlevelKeyboardEvent* ev);
|
||||
~KeyDelay();
|
||||
|
||||
private:
|
||||
// Runs the state machine, waits if there is no events to process.
|
||||
// Checks for _quit condition.
|
||||
void DelayThread();
|
||||
|
||||
// Manage state transitions and trigger callbacks on certain events.
|
||||
// Returns whether or not the thread should wait on new events.
|
||||
bool HandleRelease();
|
||||
bool HandleOnHold(std::unique_lock<std::mutex>& cvLock);
|
||||
bool HandleOnHoldTimeout();
|
||||
|
||||
// Get next key event in queue.
|
||||
KeyTimedEvent NextEvent();
|
||||
bool HasNextEvent();
|
||||
|
||||
// Check if <duration> milliseconds passed since <first> millisecond.
|
||||
// Also checks for overflow conditions.
|
||||
bool CheckIfMillisHaveElapsed(DWORD64 first, DWORD64 last, DWORD64 duration);
|
||||
|
||||
bool _quit;
|
||||
KeyDelayState _state;
|
||||
|
||||
// Callback functions, the key provided in the constructor is passed as an argument.
|
||||
std::function<void(DWORD)> _onLongPressDetected;
|
||||
std::function<void(DWORD)> _onLongPressReleased;
|
||||
std::function<void(DWORD)> _onShortPress;
|
||||
|
||||
// Queue holding key events that are not processed yet. Should be kept synchronized
|
||||
// using _queueMutex
|
||||
std::queue<KeyTimedEvent> _queue;
|
||||
std::mutex _queueMutex;
|
||||
|
||||
// DelayThread waits on this condition variable when there is no events to process.
|
||||
std::condition_variable _cv;
|
||||
|
||||
// Keeps track of the time at which the initial KEY_DOWN event happened.
|
||||
DWORD64 _initialHoldKeyDown;
|
||||
|
||||
// Virtual Key provided in the constructor. Passed to callback functions.
|
||||
DWORD _key;
|
||||
|
||||
// Declare _delayThread after all other members so that it is the last to be initialized by the constructor
|
||||
std::thread _delayThread;
|
||||
|
||||
static const DWORD64 LONG_PRESS_DELAY_MILLIS = 900;
|
||||
static const DWORD64 ON_HOLD_WAIT_TIMEOUT_MILLIS = 50;
|
||||
};
|
@ -2,15 +2,20 @@
|
||||
#include "KeyDropDownControl.h"
|
||||
|
||||
#include <common/interop/shared_constants.h>
|
||||
#include <KeyboardManagerState.h>
|
||||
|
||||
#include <BufferValidationHelpers.h>
|
||||
#include <KeyboardManagerEditorStrings.h>
|
||||
#include <ErrorTypes.h>
|
||||
#include <UIHelpers.h>
|
||||
#include <keyboardmanager/common/MappingConfiguration.h>
|
||||
|
||||
#include "KeyboardManagerState.h"
|
||||
#include "BufferValidationHelpers.h"
|
||||
#include "KeyboardManagerEditorStrings.h"
|
||||
#include "UIHelpers.h"
|
||||
#include "EditorHelpers.h"
|
||||
#include "ShortcutErrorType.h"
|
||||
#include "EditorConstants.h"
|
||||
|
||||
// Initialized to null
|
||||
KeyboardManagerState* KeyDropDownControl::keyboardManagerState = nullptr;
|
||||
KBMEditor::KeyboardManagerState* KeyDropDownControl::keyboardManagerState = nullptr;
|
||||
MappingConfiguration* KeyDropDownControl::mappingConfiguration = nullptr;
|
||||
|
||||
// Get selected value of dropdown or -1 if nothing is selected
|
||||
DWORD KeyDropDownControl::GetSelectedValue(ComboBox comboBox)
|
||||
@ -51,14 +56,14 @@ void KeyDropDownControl::SetDefaultProperties(bool isShortcut, bool renderDisabl
|
||||
|
||||
if (!isShortcut)
|
||||
{
|
||||
dropDown.as<ComboBox>().Width(KeyboardManagerConstants::RemapTableDropDownWidth);
|
||||
dropDown.as<ComboBox>().Width(EditorConstants::RemapTableDropDownWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
dropDown.as<ComboBox>().Width(KeyboardManagerConstants::ShortcutTableDropDownWidth);
|
||||
dropDown.as<ComboBox>().Width(EditorConstants::ShortcutTableDropDownWidth);
|
||||
}
|
||||
|
||||
dropDown.as<ComboBox>().MaxDropDownHeight(KeyboardManagerConstants::TableDropDownHeight);
|
||||
dropDown.as<ComboBox>().MaxDropDownHeight(EditorConstants::TableDropDownHeight);
|
||||
|
||||
// Initialise layout attribute
|
||||
previousLayout = GetKeyboardLayout(0);
|
||||
@ -121,10 +126,10 @@ void KeyDropDownControl::SetSelectionHandler(StackPanel& table, StackPanel row,
|
||||
int selectedKeyCode = GetSelectedValue(currentDropDown);
|
||||
|
||||
// Validate current remap selection
|
||||
KeyboardManagerHelper::ErrorType errorType = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(rowIndex, colIndex, selectedKeyCode, singleKeyRemapBuffer);
|
||||
ShortcutErrorType errorType = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(rowIndex, colIndex, selectedKeyCode, singleKeyRemapBuffer);
|
||||
|
||||
// If there is an error set the warning flyout
|
||||
if (errorType != KeyboardManagerHelper::ErrorType::NoError)
|
||||
if (errorType != ShortcutErrorType::NoError)
|
||||
{
|
||||
SetDropDownError(currentDropDown, KeyboardManagerEditorStrings::GetErrorMessage(errorType));
|
||||
}
|
||||
@ -145,12 +150,12 @@ void KeyDropDownControl::SetSelectionHandler(StackPanel& table, StackPanel row,
|
||||
});
|
||||
}
|
||||
|
||||
std::pair<KeyboardManagerHelper::ErrorType, int> KeyDropDownControl::ValidateShortcutSelection(StackPanel table, StackPanel row, StackPanel parent, int colIndex, RemapBuffer& shortcutRemapBuffer, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects, TextBox targetApp, bool isHybridControl, bool isSingleKeyWindow)
|
||||
std::pair<ShortcutErrorType, int> KeyDropDownControl::ValidateShortcutSelection(StackPanel table, StackPanel row, StackPanel parent, int colIndex, RemapBuffer& shortcutRemapBuffer, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects, TextBox targetApp, bool isHybridControl, bool isSingleKeyWindow)
|
||||
{
|
||||
ComboBox currentDropDown = dropDown.as<ComboBox>();
|
||||
uint32_t dropDownIndex = -1;
|
||||
bool dropDownFound = parent.Children().IndexOf(currentDropDown, dropDownIndex);
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> validationResult = std::make_pair(KeyboardManagerHelper::ErrorType::NoError, BufferValidationHelpers::DropDownAction::NoAction);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> validationResult = std::make_pair(ShortcutErrorType::NoError, BufferValidationHelpers::DropDownAction::NoAction);
|
||||
|
||||
uint32_t rowIndex;
|
||||
bool controlIindexFound = table.Children().IndexOf(row, rowIndex);
|
||||
@ -185,13 +190,13 @@ std::pair<KeyboardManagerHelper::ErrorType, int> KeyDropDownControl::ValidateSho
|
||||
}
|
||||
|
||||
// If ignore key to shortcut warning flag is true and it is a hybrid control in SingleKeyRemapControl, then skip MapToSameKey error
|
||||
if (isHybridControl && isSingleKeyWindow && ignoreKeyToShortcutWarning && (validationResult.first == KeyboardManagerHelper::ErrorType::MapToSameKey))
|
||||
if (isHybridControl && isSingleKeyWindow && ignoreKeyToShortcutWarning && (validationResult.first == ShortcutErrorType::MapToSameKey))
|
||||
{
|
||||
validationResult.first = KeyboardManagerHelper::ErrorType::NoError;
|
||||
validationResult.first = ShortcutErrorType::NoError;
|
||||
}
|
||||
|
||||
// If the remapping is invalid display an error message
|
||||
if (validationResult.first != KeyboardManagerHelper::ErrorType::NoError)
|
||||
if (validationResult.first != ShortcutErrorType::NoError)
|
||||
{
|
||||
SetDropDownError(currentDropDown, KeyboardManagerEditorStrings::GetErrorMessage(validationResult.first));
|
||||
}
|
||||
@ -227,13 +232,13 @@ std::pair<KeyboardManagerHelper::ErrorType, int> KeyDropDownControl::ValidateSho
|
||||
void KeyDropDownControl::SetSelectionHandler(StackPanel& table, StackPanel row, StackPanel parent, int colIndex, RemapBuffer& shortcutRemapBuffer, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects, TextBox& targetApp, bool isHybridControl, bool isSingleKeyWindow)
|
||||
{
|
||||
auto onSelectionChange = [&, table, row, colIndex, parent, targetApp, isHybridControl, isSingleKeyWindow](winrt::Windows::Foundation::IInspectable const& sender) {
|
||||
std::pair<KeyboardManagerHelper::ErrorType, int> validationResult = ValidateShortcutSelection(table, row, parent, colIndex, shortcutRemapBuffer, keyDropDownControlObjects, targetApp, isHybridControl, isSingleKeyWindow);
|
||||
std::pair<ShortcutErrorType, int> validationResult = ValidateShortcutSelection(table, row, parent, colIndex, shortcutRemapBuffer, keyDropDownControlObjects, targetApp, isHybridControl, isSingleKeyWindow);
|
||||
|
||||
// Check if the drop down row index was identified from the return value of validateSelection
|
||||
if (validationResult.second != -1)
|
||||
{
|
||||
// If an error occurred
|
||||
if (validationResult.first != KeyboardManagerHelper::ErrorType::NoError)
|
||||
if (validationResult.first != ShortcutErrorType::NoError)
|
||||
{
|
||||
// Validate all the drop downs
|
||||
ValidateShortcutFromDropDownList(table, row, parent, colIndex, shortcutRemapBuffer, keyDropDownControlObjects, targetApp, isHybridControl, isSingleKeyWindow);
|
||||
@ -362,7 +367,7 @@ void KeyDropDownControl::ValidateShortcutFromDropDownList(StackPanel table, Stac
|
||||
}
|
||||
|
||||
// If the key/shortcut is valid and that drop down is not empty
|
||||
if (((currentShortcut.index() == 0 && std::get<DWORD>(currentShortcut) != NULL) || (currentShortcut.index() == 1 && std::get<Shortcut>(currentShortcut).IsValidShortcut())) && GetSelectedValue(keyDropDownControlObjects[i]->GetComboBox()) != -1)
|
||||
if (((currentShortcut.index() == 0 && std::get<DWORD>(currentShortcut) != NULL) || (currentShortcut.index() == 1 && EditorHelpers::IsValidShortcut(std::get<Shortcut>(currentShortcut)))) && GetSelectedValue(keyDropDownControlObjects[i]->GetComboBox()) != -1)
|
||||
{
|
||||
keyDropDownControlObjects[i]->ValidateShortcutSelection(table, row, parent, colIndex, shortcutRemapBuffer, keyDropDownControlObjects, targetApp, isHybridControl, isSingleKeyWindow);
|
||||
}
|
||||
@ -378,7 +383,7 @@ void KeyDropDownControl::SetDropDownError(ComboBox currentDropDown, hstring mess
|
||||
}
|
||||
|
||||
// Function to add a shortcut to the UI control as combo boxes
|
||||
void KeyDropDownControl::AddShortcutToControl(Shortcut shortcut, StackPanel table, StackPanel parent, KeyboardManagerState& keyboardManagerState, const int colIndex, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects, RemapBuffer& remapBuffer, StackPanel row, TextBox targetApp, bool isHybridControl, bool isSingleKeyWindow)
|
||||
void KeyDropDownControl::AddShortcutToControl(Shortcut shortcut, StackPanel table, StackPanel parent, KBMEditor::KeyboardManagerState& keyboardManagerState, const int colIndex, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects, RemapBuffer& remapBuffer, StackPanel row, TextBox targetApp, bool isHybridControl, bool isSingleKeyWindow)
|
||||
{
|
||||
// Delete the existing drop down menus
|
||||
parent.Children().Clear();
|
||||
|
@ -1,8 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <Shortcut.h>
|
||||
#include <keyboardmanager/common/Shortcut.h>
|
||||
|
||||
class KeyboardManagerState;
|
||||
namespace KBMEditor
|
||||
{
|
||||
class KeyboardManagerState;
|
||||
}
|
||||
|
||||
class MappingConfiguration;
|
||||
|
||||
namespace winrt::Windows
|
||||
{
|
||||
@ -20,10 +25,7 @@ namespace winrt::Windows
|
||||
}
|
||||
}
|
||||
|
||||
namespace KeyboardManagerHelper
|
||||
{
|
||||
enum class ErrorType;
|
||||
}
|
||||
enum class ShortcutErrorType;
|
||||
|
||||
// Wrapper class for the key drop down menu
|
||||
class KeyDropDownControl
|
||||
@ -58,7 +60,8 @@ private:
|
||||
|
||||
public:
|
||||
// Pointer to the keyboard manager state
|
||||
static KeyboardManagerState* keyboardManagerState;
|
||||
static KBMEditor::KeyboardManagerState* keyboardManagerState;
|
||||
static MappingConfiguration* mappingConfiguration;
|
||||
|
||||
// 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, bool renderDisable = false) :
|
||||
@ -71,7 +74,7 @@ public:
|
||||
void SetSelectionHandler(StackPanel& table, StackPanel row, int colIndex, RemapBuffer& singleKeyRemapBuffer);
|
||||
|
||||
// Function for validating the selection of shortcuts for the drop down
|
||||
std::pair<KeyboardManagerHelper::ErrorType, int> ValidateShortcutSelection(StackPanel table, StackPanel row, StackPanel parent, int colIndex, RemapBuffer& shortcutRemapBuffer, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects, winrt::Windows::UI::Xaml::Controls::TextBox targetApp, bool isHybridControl, bool isSingleKeyWindow);
|
||||
std::pair<ShortcutErrorType, int> ValidateShortcutSelection(StackPanel table, StackPanel row, StackPanel parent, int colIndex, RemapBuffer& shortcutRemapBuffer, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects, winrt::Windows::UI::Xaml::Controls::TextBox targetApp, bool isHybridControl, bool isSingleKeyWindow);
|
||||
|
||||
// Function to set selection handler for shortcut drop down.
|
||||
void SetSelectionHandler(StackPanel& table, StackPanel row, winrt::Windows::UI::Xaml::Controls::StackPanel parent, int colIndex, RemapBuffer& shortcutRemapBuffer, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects, winrt::Windows::UI::Xaml::Controls::TextBox& targetApp, bool isHybridControl, bool isSingleKeyWindow);
|
||||
@ -95,7 +98,7 @@ public:
|
||||
void SetSelectedValue(std::wstring value);
|
||||
|
||||
// Function to add a shortcut to the UI control as combo boxes
|
||||
static void AddShortcutToControl(Shortcut shortcut, StackPanel table, StackPanel parent, KeyboardManagerState& keyboardManagerState, const int colIndex, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects, RemapBuffer& remapBuffer, StackPanel row, TextBox targetApp, bool isHybridControl, bool isSingleKeyWindow);
|
||||
static void AddShortcutToControl(Shortcut shortcut, StackPanel table, StackPanel parent, KBMEditor::KeyboardManagerState& keyboardManagerState, const int colIndex, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects, RemapBuffer& remapBuffer, StackPanel row, TextBox targetApp, bool isHybridControl, bool isSingleKeyWindow);
|
||||
|
||||
// Get keys name list depending if Disable is in dropdown
|
||||
static std::vector<std::pair<DWORD,std::wstring>> GetKeyList(bool isShortcut, bool renderDisable);
|
||||
|
@ -27,7 +27,7 @@
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<AdditionalIncludeDirectories>./;$(SolutionDir)src\modules\;$(SolutionDir)src\common\Display;$(SolutionDir)src\common\inc;$(SolutionDir)src\common\Telemetry;$(SolutionDir)src;./../common;./../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>./;$(SolutionDir)src\modules\;$(SolutionDir)src\common\Display;$(SolutionDir)src\common\inc;$(SolutionDir)src\common\Telemetry;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
@ -36,12 +36,17 @@
|
||||
<ClInclude Include="BufferValidationHelpers.h" />
|
||||
<ClInclude Include="Dialog.h" />
|
||||
<ClInclude Include="EditKeyboardWindow.h" />
|
||||
<ClInclude Include="EditorConstants.h" />
|
||||
<ClInclude Include="EditorHelpers.h" />
|
||||
<ClInclude Include="EditShortcutsWindow.h" />
|
||||
<ClInclude Include="KeyboardManagerEditorStrings.h" />
|
||||
<ClInclude Include="KeyboardManagerState.h" />
|
||||
<ClInclude Include="KeyDelay.h" />
|
||||
<ClInclude Include="KeyDropDownControl.h" />
|
||||
<ClInclude Include="LoadingAndSavingRemappingHelper.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="ShortcutControl.h" />
|
||||
<ClInclude Include="ShortcutErrorType.h" />
|
||||
<ClInclude Include="SingleKeyRemapControl.h" />
|
||||
<ClInclude Include="Styles.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
@ -53,8 +58,11 @@
|
||||
<ClCompile Include="BufferValidationHelpers.cpp" />
|
||||
<ClCompile Include="Dialog.cpp" />
|
||||
<ClCompile Include="EditKeyboardWindow.cpp" />
|
||||
<ClCompile Include="EditorHelpers.cpp" />
|
||||
<ClCompile Include="EditShortcutsWindow.cpp" />
|
||||
<ClCompile Include="KeyboardManagerEditorStrings.cpp" />
|
||||
<ClCompile Include="KeyboardManagerState.cpp" />
|
||||
<ClCompile Include="KeyDelay.cpp" />
|
||||
<ClCompile Include="KeyDropDownControl.cpp" />
|
||||
<ClCompile Include="LoadingAndSavingRemappingHelper.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
|
@ -60,6 +60,21 @@
|
||||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="KeyboardManagerState.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="EditorHelpers.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ShortcutErrorType.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="KeyDelay.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="EditorConstants.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
@ -104,6 +119,15 @@
|
||||
<ClCompile Include="trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="KeyboardManagerState.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="EditorHelpers.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="KeyDelay.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
@ -2,47 +2,45 @@
|
||||
#include "KeyboardManagerEditorStrings.h"
|
||||
|
||||
// Function to return the error message
|
||||
winrt::hstring KeyboardManagerEditorStrings::GetErrorMessage(KeyboardManagerHelper::ErrorType errorType)
|
||||
winrt::hstring KeyboardManagerEditorStrings::GetErrorMessage(ShortcutErrorType errorType)
|
||||
{
|
||||
using namespace KeyboardManagerHelper;
|
||||
|
||||
switch (errorType)
|
||||
{
|
||||
case ErrorType::NoError:
|
||||
case ShortcutErrorType::NoError:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_REMAPSUCCESSFUL).c_str();
|
||||
case ErrorType::SameKeyPreviouslyMapped:
|
||||
case ShortcutErrorType::SameKeyPreviouslyMapped:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_SAMEKEYPREVIOUSLYMAPPED).c_str();
|
||||
case ErrorType::MapToSameKey:
|
||||
case ShortcutErrorType::MapToSameKey:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_MAPPEDTOSAMEKEY).c_str();
|
||||
case ErrorType::ConflictingModifierKey:
|
||||
case ShortcutErrorType::ConflictingModifierKey:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_CONFLICTINGMODIFIERKEY).c_str();
|
||||
case ErrorType::SameShortcutPreviouslyMapped:
|
||||
case ShortcutErrorType::SameShortcutPreviouslyMapped:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_SAMESHORTCUTPREVIOUSLYMAPPED).c_str();
|
||||
case ErrorType::MapToSameShortcut:
|
||||
case ShortcutErrorType::MapToSameShortcut:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_MAPTOSAMESHORTCUT).c_str();
|
||||
case ErrorType::ConflictingModifierShortcut:
|
||||
case ShortcutErrorType::ConflictingModifierShortcut:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_CONFLICTINGMODIFIERSHORTCUT).c_str();
|
||||
case ErrorType::WinL:
|
||||
case ShortcutErrorType::WinL:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_WINL).c_str();
|
||||
case ErrorType::CtrlAltDel:
|
||||
case ShortcutErrorType::CtrlAltDel:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_CTRLALTDEL).c_str();
|
||||
case ErrorType::RemapUnsuccessful:
|
||||
case ShortcutErrorType::RemapUnsuccessful:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_REMAPUNSUCCESSFUL).c_str();
|
||||
case ErrorType::SaveFailed:
|
||||
case ShortcutErrorType::SaveFailed:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_SAVEFAILED).c_str();
|
||||
case ErrorType::ShortcutStartWithModifier:
|
||||
case ShortcutErrorType::ShortcutStartWithModifier:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_SHORTCUTSTARTWITHMODIFIER).c_str();
|
||||
case ErrorType::ShortcutCannotHaveRepeatedModifier:
|
||||
case ShortcutErrorType::ShortcutCannotHaveRepeatedModifier:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_SHORTCUTNOREPEATEDMODIFIER).c_str();
|
||||
case ErrorType::ShortcutAtleast2Keys:
|
||||
case ShortcutErrorType::ShortcutAtleast2Keys:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_SHORTCUTATLEAST2KEYS).c_str();
|
||||
case ErrorType::ShortcutOneActionKey:
|
||||
case ShortcutErrorType::ShortcutOneActionKey:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_SHORTCUTONEACTIONKEY).c_str();
|
||||
case ErrorType::ShortcutNotMoreThanOneActionKey:
|
||||
case ShortcutErrorType::ShortcutNotMoreThanOneActionKey:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_SHORTCUTMAXONEACTIONKEY).c_str();
|
||||
case ErrorType::ShortcutMaxShortcutSizeOneActionKey:
|
||||
case ShortcutErrorType::ShortcutMaxShortcutSizeOneActionKey:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_MAXSHORTCUTSIZE).c_str();
|
||||
case ErrorType::ShortcutDisableAsActionKey:
|
||||
case ShortcutErrorType::ShortcutDisableAsActionKey:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_DISABLEASACTIONKEY).c_str();
|
||||
default:
|
||||
return GET_RESOURCE_STRING(IDS_ERRORMESSAGE_DEFAULT).c_str();
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include <ErrorTypes.h>
|
||||
#include "ShortcutErrorType.h"
|
||||
|
||||
namespace KeyboardManagerEditorStrings
|
||||
{
|
||||
@ -10,5 +10,5 @@ namespace KeyboardManagerEditorStrings
|
||||
inline const std::wstring DefaultAppName = GET_RESOURCE_STRING(IDS_EDITSHORTCUTS_ALLAPPS);
|
||||
|
||||
// Function to return the error message
|
||||
winrt::hstring GetErrorMessage(KeyboardManagerHelper::ErrorType errorType);
|
||||
}
|
||||
winrt::hstring GetErrorMessage(ShortcutErrorType errorType);
|
||||
}
|
||||
|
@ -1,624 +1,363 @@
|
||||
#include "pch.h"
|
||||
#include "KeyboardManagerState.h"
|
||||
#include "Shortcut.h"
|
||||
#include "RemapShortcut.h"
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include "KeyDelay.h"
|
||||
#include "Helpers.h"
|
||||
#include <common/logger/logger.h>
|
||||
|
||||
// Constructor
|
||||
KeyboardManagerState::KeyboardManagerState() :
|
||||
uiState(KeyboardManagerUIState::Deactivated), currentUIWindow(nullptr), currentShortcutUI1(nullptr), currentShortcutUI2(nullptr), currentSingleKeyUI(nullptr), detectedRemapKey(NULL), remappingsEnabled(true)
|
||||
{
|
||||
}
|
||||
|
||||
// Destructor
|
||||
KeyboardManagerState::~KeyboardManagerState()
|
||||
{
|
||||
}
|
||||
|
||||
// Function to check the if the UI state matches the argument state. For states with detect windows it also checks if the window is in focus.
|
||||
bool KeyboardManagerState::CheckUIState(KeyboardManagerUIState state)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(uiState_mutex);
|
||||
if (uiState == state)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(currentUIWindow_mutex);
|
||||
if (uiState == KeyboardManagerUIState::Deactivated || uiState == KeyboardManagerUIState::EditKeyboardWindowActivated || uiState == KeyboardManagerUIState::EditShortcutsWindowActivated)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// If the UI state is a detect window then we also have to ensure that the UI window is in focus.
|
||||
// GetForegroundWindow can be used here since we only need to check the main parent window and not the sub windows within the content dialog. Using GUIThreadInfo will give more specific sub-windows within the XAML window which is not needed.
|
||||
else if (currentUIWindow == GetForegroundWindow())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// If we are checking for EditKeyboardWindowActivated then it's possible the state could be DetectSingleKeyRemapWindowActivated but not in focus
|
||||
else if (state == KeyboardManagerUIState::EditKeyboardWindowActivated && uiState == KeyboardManagerUIState::DetectSingleKeyRemapWindowActivated)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// If we are checking for EditShortcutsWindowActivated then it's possible the state could be DetectShortcutWindowActivated but not in focus
|
||||
else if (state == KeyboardManagerUIState::EditShortcutsWindowActivated && uiState == KeyboardManagerUIState::DetectShortcutWindowActivated)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Function to set the window handle of the current UI window that is activated
|
||||
void KeyboardManagerState::SetCurrentUIWindow(HWND windowHandle)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(currentUIWindow_mutex);
|
||||
currentUIWindow = windowHandle;
|
||||
}
|
||||
|
||||
// Function to set the UI state. When a window is activated, the handle to the window can be passed in the windowHandle argument.
|
||||
void KeyboardManagerState::SetUIState(KeyboardManagerUIState state, HWND windowHandle)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(uiState_mutex);
|
||||
uiState = state;
|
||||
SetCurrentUIWindow(windowHandle);
|
||||
}
|
||||
|
||||
// Function to reset the UI state members
|
||||
void KeyboardManagerState::ResetUIState()
|
||||
{
|
||||
SetUIState(KeyboardManagerUIState::Deactivated);
|
||||
|
||||
// Reset the shortcut UI stored variables
|
||||
std::unique_lock<std::mutex> currentShortcutUI_lock(currentShortcutUI_mutex);
|
||||
currentShortcutUI1 = nullptr;
|
||||
currentShortcutUI2 = nullptr;
|
||||
currentShortcutUI_lock.unlock();
|
||||
|
||||
std::unique_lock<std::mutex> detectedShortcut_lock(detectedShortcut_mutex);
|
||||
detectedShortcut.Reset();
|
||||
detectedShortcut_lock.unlock();
|
||||
|
||||
std::unique_lock<std::mutex> currentShortcut_lock(currentShortcut_mutex);
|
||||
currentShortcut.Reset();
|
||||
currentShortcut_lock.unlock();
|
||||
|
||||
// Reset all the single key remap UI stored variables.
|
||||
std::unique_lock<std::mutex> currentSingleKeyUI_lock(currentSingleKeyUI_mutex);
|
||||
currentSingleKeyUI = nullptr;
|
||||
currentSingleKeyUI_lock.unlock();
|
||||
|
||||
std::unique_lock<std::mutex> detectedRemapKey_lock(detectedRemapKey_mutex);
|
||||
detectedRemapKey = NULL;
|
||||
detectedRemapKey_lock.unlock();
|
||||
}
|
||||
|
||||
// Function to clear the OS Level shortcut remapping table
|
||||
void KeyboardManagerState::ClearOSLevelShortcuts()
|
||||
{
|
||||
osLevelShortcutReMap.clear();
|
||||
osLevelShortcutReMapSortedKeys.clear();
|
||||
}
|
||||
|
||||
// Function to clear the Keys remapping table.
|
||||
void KeyboardManagerState::ClearSingleKeyRemaps()
|
||||
{
|
||||
singleKeyReMap.clear();
|
||||
}
|
||||
|
||||
// Function to clear the App specific shortcut remapping table
|
||||
void KeyboardManagerState::ClearAppSpecificShortcuts()
|
||||
{
|
||||
appSpecificShortcutReMap.clear();
|
||||
appSpecificShortcutReMapSortedKeys.clear();
|
||||
}
|
||||
|
||||
// Function to add a new OS level shortcut remapping
|
||||
bool KeyboardManagerState::AddOSLevelShortcut(const Shortcut& originalSC, const KeyShortcutUnion& newSC)
|
||||
{
|
||||
// Check if the shortcut is already remapped
|
||||
auto it = osLevelShortcutReMap.find(originalSC);
|
||||
if (it != osLevelShortcutReMap.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
osLevelShortcutReMap[originalSC] = RemapShortcut(newSC);
|
||||
osLevelShortcutReMapSortedKeys.push_back(originalSC);
|
||||
KeyboardManagerHelper::SortShortcutVectorBasedOnSize(osLevelShortcutReMapSortedKeys);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Function to add a new single key to key/shortcut remapping
|
||||
bool KeyboardManagerState::AddSingleKeyRemap(const DWORD& originalKey, const KeyShortcutUnion& newRemapKey)
|
||||
{
|
||||
// Check if the key is already remapped
|
||||
auto it = singleKeyReMap.find(originalKey);
|
||||
if (it != singleKeyReMap.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
singleKeyReMap[originalKey] = newRemapKey;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Function to add a new App specific shortcut remapping
|
||||
bool KeyboardManagerState::AddAppSpecificShortcut(const std::wstring& app, const Shortcut& originalSC, const KeyShortcutUnion& newSC)
|
||||
{
|
||||
// Convert app name to lower case
|
||||
std::wstring process_name;
|
||||
process_name.resize(app.length());
|
||||
std::transform(app.begin(), app.end(), process_name.begin(), towlower);
|
||||
|
||||
// Check if there are any app specific shortcuts for this app
|
||||
auto appIt = appSpecificShortcutReMap.find(process_name);
|
||||
if (appIt != appSpecificShortcutReMap.end())
|
||||
{
|
||||
// Check if the shortcut is already remapped
|
||||
auto shortcutIt = appSpecificShortcutReMap[process_name].find(originalSC);
|
||||
if (shortcutIt != appSpecificShortcutReMap[process_name].end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
appSpecificShortcutReMapSortedKeys[process_name] = std::vector<Shortcut>();
|
||||
}
|
||||
|
||||
appSpecificShortcutReMap[process_name][originalSC] = RemapShortcut(newSC);
|
||||
appSpecificShortcutReMapSortedKeys[process_name].push_back(originalSC);
|
||||
KeyboardManagerHelper::SortShortcutVectorBasedOnSize(appSpecificShortcutReMapSortedKeys[process_name]);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Function to get the iterator of a single key remap given the source key. Returns nullopt if it isn't remapped
|
||||
std::optional<SingleKeyRemapTable::iterator> KeyboardManagerState::GetSingleKeyRemap(const DWORD& originalKey)
|
||||
{
|
||||
auto it = singleKeyReMap.find(originalKey);
|
||||
if (it != singleKeyReMap.end())
|
||||
{
|
||||
return it;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool KeyboardManagerState::CheckShortcutRemapInvoked(const std::optional<std::wstring>& appName)
|
||||
{
|
||||
// Assumes appName exists in the app-specific remap table
|
||||
ShortcutRemapTable& currentRemapTable = appName ? appSpecificShortcutReMap[*appName] : osLevelShortcutReMap;
|
||||
for (auto& it : currentRemapTable)
|
||||
{
|
||||
if (it.second.isShortcutInvoked)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<Shortcut>& KeyboardManagerState::GetSortedShortcutRemapVector(const std::optional<std::wstring>& appName)
|
||||
{
|
||||
// Assumes appName exists in the app-specific remap table
|
||||
return appName ? appSpecificShortcutReMapSortedKeys[*appName] : osLevelShortcutReMapSortedKeys;
|
||||
}
|
||||
|
||||
// Function to get the source and target of a shortcut remap given the source shortcut. Returns nullopt if it isn't remapped
|
||||
ShortcutRemapTable& KeyboardManagerState::GetShortcutRemapTable(const std::optional<std::wstring>& appName)
|
||||
{
|
||||
if (appName)
|
||||
{
|
||||
auto itTable = appSpecificShortcutReMap.find(*appName);
|
||||
if (itTable != appSpecificShortcutReMap.end())
|
||||
{
|
||||
return itTable->second;
|
||||
}
|
||||
}
|
||||
|
||||
return osLevelShortcutReMap;
|
||||
}
|
||||
|
||||
// Function to set the textblock of the detect shortcut UI so that it can be accessed by the hook
|
||||
void KeyboardManagerState::ConfigureDetectShortcutUI(const StackPanel& textBlock1, const StackPanel& textBlock2)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(currentShortcutUI_mutex);
|
||||
currentShortcutUI1 = textBlock1.as<winrt::Windows::Foundation::IInspectable>();
|
||||
currentShortcutUI2 = textBlock2.as<winrt::Windows::Foundation::IInspectable>();
|
||||
}
|
||||
|
||||
// Function to set the textblock of the detect remap key UI so that it can be accessed by the hook
|
||||
void KeyboardManagerState::ConfigureDetectSingleKeyRemapUI(const StackPanel& textBlock)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(currentSingleKeyUI_mutex);
|
||||
currentSingleKeyUI = textBlock.as<winrt::Windows::Foundation::IInspectable>();
|
||||
}
|
||||
|
||||
void KeyboardManagerState::AddKeyToLayout(const StackPanel& panel, const hstring& key)
|
||||
{
|
||||
// Textblock to display the detected key
|
||||
TextBlock remapKey;
|
||||
Border border;
|
||||
|
||||
border.Padding({ 20, 10, 20, 10 });
|
||||
border.Margin({ 0, 0, 10, 0 });
|
||||
// Use the base low brush to be consistent with the theme
|
||||
border.Background(Windows::UI::Xaml::Application::Current().Resources().Lookup(box_value(L"SystemControlBackgroundBaseLowBrush")).as<Windows::UI::Xaml::Media::SolidColorBrush>());
|
||||
remapKey.FontSize(20);
|
||||
border.HorizontalAlignment(HorizontalAlignment::Left);
|
||||
border.Child(remapKey);
|
||||
|
||||
remapKey.Text(key);
|
||||
panel.Children().Append(border);
|
||||
}
|
||||
|
||||
// Function to update the detect shortcut UI based on the entered keys
|
||||
void KeyboardManagerState::UpdateDetectShortcutUI()
|
||||
{
|
||||
std::lock_guard<std::mutex> currentShortcutUI_lock(currentShortcutUI_mutex);
|
||||
if (currentShortcutUI1 == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> detectedShortcut_lock(detectedShortcut_mutex);
|
||||
std::unique_lock<std::mutex> currentShortcut_lock(currentShortcut_mutex);
|
||||
// Save the latest displayed shortcut
|
||||
currentShortcut = detectedShortcut;
|
||||
auto detectedShortcutCopy = detectedShortcut;
|
||||
currentShortcut_lock.unlock();
|
||||
detectedShortcut_lock.unlock();
|
||||
// Since this function is invoked from the back-end thread, in order to update the UI the dispatcher must be used.
|
||||
currentShortcutUI1.as<StackPanel>().Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [this, detectedShortcutCopy]() {
|
||||
std::vector<hstring> shortcut = detectedShortcutCopy.GetKeyVector(keyboardMap);
|
||||
currentShortcutUI1.as<StackPanel>().Children().Clear();
|
||||
currentShortcutUI2.as<StackPanel>().Children().Clear();
|
||||
|
||||
// The second row should be hidden if there are 3 keys or lesser to avoid an extra margin
|
||||
if (shortcut.size() > 3)
|
||||
{
|
||||
currentShortcutUI2.as<StackPanel>().Visibility(Visibility::Visible);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentShortcutUI2.as<StackPanel>().Visibility(Visibility::Collapsed);
|
||||
}
|
||||
|
||||
for (int i = 0; i < shortcut.size(); i++)
|
||||
{
|
||||
if (i < 3)
|
||||
{
|
||||
AddKeyToLayout(currentShortcutUI1.as<StackPanel>(), shortcut[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddKeyToLayout(currentShortcutUI2.as<StackPanel>(), shortcut[i]);
|
||||
}
|
||||
}
|
||||
currentShortcutUI1.as<StackPanel>().UpdateLayout();
|
||||
currentShortcutUI2.as<StackPanel>().UpdateLayout();
|
||||
});
|
||||
}
|
||||
|
||||
// Function to update the detect remap key UI based on the entered key.
|
||||
void KeyboardManagerState::UpdateDetectSingleKeyRemapUI()
|
||||
{
|
||||
std::lock_guard<std::mutex> currentSingleKeyUI_lock(currentSingleKeyUI_mutex);
|
||||
if (currentSingleKeyUI == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Since this function is invoked from the back-end thread, in order to update the UI the dispatcher must be used.
|
||||
currentSingleKeyUI.as<StackPanel>().Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [this]() {
|
||||
currentSingleKeyUI.as<StackPanel>().Children().Clear();
|
||||
hstring key = winrt::to_hstring(keyboardMap.GetKeyName(detectedRemapKey).c_str());
|
||||
AddKeyToLayout(currentSingleKeyUI.as<StackPanel>(), key);
|
||||
currentSingleKeyUI.as<StackPanel>().UpdateLayout();
|
||||
});
|
||||
}
|
||||
|
||||
// Function to return the currently detected shortcut which is displayed on the UI
|
||||
Shortcut KeyboardManagerState::GetDetectedShortcut()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(currentShortcut_mutex);
|
||||
return currentShortcut;
|
||||
}
|
||||
|
||||
// Function to return the currently detected remap key which is displayed on the UI
|
||||
DWORD KeyboardManagerState::GetDetectedSingleRemapKey()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(detectedRemapKey_mutex);
|
||||
return detectedRemapKey;
|
||||
}
|
||||
|
||||
void KeyboardManagerState::SelectDetectedRemapKey(DWORD key)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(detectedRemapKey_mutex);
|
||||
detectedRemapKey = key;
|
||||
UpdateDetectSingleKeyRemapUI();
|
||||
return;
|
||||
}
|
||||
|
||||
void KeyboardManagerState::SelectDetectedShortcut(DWORD key)
|
||||
{
|
||||
// Set the new key and store if a change occurred
|
||||
std::unique_lock<std::mutex> lock(detectedShortcut_mutex);
|
||||
bool updateUI = detectedShortcut.SetKey(key);
|
||||
lock.unlock();
|
||||
|
||||
if (updateUI)
|
||||
{
|
||||
// Update the UI. This function is called here because it should store the set of keys pressed till the last key which was pressed down.
|
||||
UpdateDetectShortcutUI();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void KeyboardManagerState::ResetDetectedShortcutKey(DWORD key)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(detectedShortcut_mutex);
|
||||
detectedShortcut.ResetKey(key);
|
||||
}
|
||||
|
||||
// Function which can be used in HandleKeyboardHookEvent before the single key remap event to use the UI and suppress events while the remap window is active.
|
||||
KeyboardManagerHelper::KeyboardHookDecision KeyboardManagerState::DetectSingleRemapKeyUIBackend(LowlevelKeyboardEvent* data)
|
||||
{
|
||||
// Check if the detect key UI window has been activated
|
||||
if (CheckUIState(KeyboardManagerUIState::DetectSingleKeyRemapWindowActivated))
|
||||
{
|
||||
if (HandleKeyDelayEvent(data))
|
||||
{
|
||||
return KeyboardManagerHelper::KeyboardHookDecision::Suppress;
|
||||
}
|
||||
// detect the key if it is pressed down
|
||||
if (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN)
|
||||
{
|
||||
SelectDetectedRemapKey(data->lParam->vkCode);
|
||||
}
|
||||
|
||||
// Suppress the keyboard event
|
||||
return KeyboardManagerHelper::KeyboardHookDecision::Suppress;
|
||||
}
|
||||
|
||||
// If the settings window is up, remappings should not be applied, but we should not suppress events in the hook
|
||||
else if (CheckUIState(KeyboardManagerUIState::EditKeyboardWindowActivated))
|
||||
{
|
||||
return KeyboardManagerHelper::KeyboardHookDecision::SkipHook;
|
||||
}
|
||||
|
||||
return KeyboardManagerHelper::KeyboardHookDecision::ContinueExec;
|
||||
}
|
||||
|
||||
// Function which can be used in HandleKeyboardHookEvent before the os level shortcut remap event to use the UI and suppress events while the remap window is active.
|
||||
KeyboardManagerHelper::KeyboardHookDecision KeyboardManagerState::DetectShortcutUIBackend(LowlevelKeyboardEvent* data, bool isRemapKey)
|
||||
{
|
||||
// Check if the detect shortcut UI window has been activated
|
||||
if ((!isRemapKey && CheckUIState(KeyboardManagerUIState::DetectShortcutWindowActivated)) || (isRemapKey && CheckUIState(KeyboardManagerUIState::DetectShortcutWindowInEditKeyboardWindowActivated)))
|
||||
{
|
||||
if (HandleKeyDelayEvent(data))
|
||||
{
|
||||
return KeyboardManagerHelper::KeyboardHookDecision::Suppress;
|
||||
}
|
||||
|
||||
// Add the key if it is pressed down
|
||||
if (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN)
|
||||
{
|
||||
SelectDetectedShortcut(data->lParam->vkCode);
|
||||
}
|
||||
// Remove the key if it has been released
|
||||
else if (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP)
|
||||
{
|
||||
ResetDetectedShortcutKey(data->lParam->vkCode);
|
||||
}
|
||||
|
||||
// Suppress the keyboard event
|
||||
return KeyboardManagerHelper::KeyboardHookDecision::Suppress;
|
||||
}
|
||||
|
||||
// If the detect shortcut UI window is not activated, then clear the shortcut buffer if it isn't empty
|
||||
else if (!CheckUIState(KeyboardManagerUIState::DetectShortcutWindowActivated) && !CheckUIState(KeyboardManagerUIState::DetectShortcutWindowInEditKeyboardWindowActivated))
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(detectedShortcut_mutex);
|
||||
if (!detectedShortcut.IsEmpty())
|
||||
{
|
||||
detectedShortcut.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
// If the settings window is up, shortcut remappings should not be applied, but we should not suppress events in the hook
|
||||
if (!isRemapKey && (CheckUIState(KeyboardManagerUIState::EditShortcutsWindowActivated)) || (isRemapKey && uiState == KeyboardManagerUIState::DetectShortcutWindowInEditKeyboardWindowActivated))
|
||||
{
|
||||
return KeyboardManagerHelper::KeyboardHookDecision::SkipHook;
|
||||
}
|
||||
|
||||
return KeyboardManagerHelper::KeyboardHookDecision::ContinueExec;
|
||||
}
|
||||
|
||||
void KeyboardManagerState::RegisterKeyDelay(
|
||||
DWORD key,
|
||||
std::function<void(DWORD)> onShortPress,
|
||||
std::function<void(DWORD)> onLongPressDetected,
|
||||
std::function<void(DWORD)> onLongPressReleased)
|
||||
{
|
||||
std::lock_guard l(keyDelays_mutex);
|
||||
|
||||
if (keyDelays.find(key) != keyDelays.end())
|
||||
{
|
||||
throw std::invalid_argument("This key was already registered.");
|
||||
}
|
||||
|
||||
keyDelays[key] = std::make_unique<KeyDelay>(key, onShortPress, onLongPressDetected, onLongPressReleased);
|
||||
}
|
||||
|
||||
void KeyboardManagerState::UnregisterKeyDelay(DWORD key)
|
||||
{
|
||||
std::lock_guard l(keyDelays_mutex);
|
||||
|
||||
auto deleted = keyDelays.erase(key);
|
||||
if (deleted == 0)
|
||||
{
|
||||
throw std::invalid_argument("The key was not previously registered.");
|
||||
}
|
||||
}
|
||||
|
||||
// Function to clear all the registered key delays
|
||||
void KeyboardManagerState::ClearRegisteredKeyDelays()
|
||||
{
|
||||
std::lock_guard l(keyDelays_mutex);
|
||||
keyDelays.clear();
|
||||
}
|
||||
|
||||
bool KeyboardManagerState::HandleKeyDelayEvent(LowlevelKeyboardEvent* ev)
|
||||
{
|
||||
if (currentUIWindow != GetForegroundWindow())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard l(keyDelays_mutex);
|
||||
|
||||
if (keyDelays.find(ev->lParam->vkCode) == keyDelays.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
keyDelays[ev->lParam->vkCode]->KeyEvent(ev);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Save the updated configuration.
|
||||
bool KeyboardManagerState::SaveConfigToFile()
|
||||
{
|
||||
bool result = true;
|
||||
json::JsonObject configJson;
|
||||
json::JsonObject remapShortcuts;
|
||||
json::JsonObject remapKeys;
|
||||
json::JsonArray inProcessRemapKeysArray;
|
||||
json::JsonArray appSpecificRemapShortcutsArray;
|
||||
json::JsonArray globalRemapShortcutsArray;
|
||||
for (const auto& it : singleKeyReMap)
|
||||
{
|
||||
json::JsonObject keys;
|
||||
keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(winrt::to_hstring((unsigned int)it.first)));
|
||||
|
||||
// For key to key remapping
|
||||
if (it.second.index() == 0)
|
||||
{
|
||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(winrt::to_hstring((unsigned int)std::get<DWORD>(it.second))));
|
||||
}
|
||||
|
||||
// For key to shortcut remapping
|
||||
else
|
||||
{
|
||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(std::get<Shortcut>(it.second).ToHstringVK()));
|
||||
}
|
||||
|
||||
inProcessRemapKeysArray.Append(keys);
|
||||
}
|
||||
|
||||
for (const auto& it : osLevelShortcutReMap)
|
||||
{
|
||||
json::JsonObject keys;
|
||||
keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(it.first.ToHstringVK()));
|
||||
|
||||
// For shortcut to key remapping
|
||||
if (it.second.targetShortcut.index() == 0)
|
||||
{
|
||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(winrt::to_hstring((unsigned int)std::get<DWORD>(it.second.targetShortcut))));
|
||||
}
|
||||
|
||||
// For shortcut to shortcut remapping
|
||||
else
|
||||
{
|
||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(std::get<Shortcut>(it.second.targetShortcut).ToHstringVK()));
|
||||
}
|
||||
|
||||
globalRemapShortcutsArray.Append(keys);
|
||||
}
|
||||
|
||||
for (const auto& itApp : appSpecificShortcutReMap)
|
||||
{
|
||||
// Iterate over apps
|
||||
for (const auto& itKeys : itApp.second)
|
||||
{
|
||||
json::JsonObject keys;
|
||||
keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(itKeys.first.ToHstringVK()));
|
||||
|
||||
// For shortcut to key remapping
|
||||
if (itKeys.second.targetShortcut.index() == 0)
|
||||
{
|
||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(winrt::to_hstring((unsigned int)std::get<DWORD>(itKeys.second.targetShortcut))));
|
||||
}
|
||||
|
||||
// For shortcut to shortcut remapping
|
||||
else
|
||||
{
|
||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(std::get<Shortcut>(itKeys.second.targetShortcut).ToHstringVK()));
|
||||
}
|
||||
|
||||
keys.SetNamedValue(KeyboardManagerConstants::TargetAppSettingName, json::value(itApp.first));
|
||||
|
||||
appSpecificRemapShortcutsArray.Append(keys);
|
||||
}
|
||||
}
|
||||
|
||||
remapShortcuts.SetNamedValue(KeyboardManagerConstants::GlobalRemapShortcutsSettingName, globalRemapShortcutsArray);
|
||||
remapShortcuts.SetNamedValue(KeyboardManagerConstants::AppSpecificRemapShortcutsSettingName, appSpecificRemapShortcutsArray);
|
||||
remapKeys.SetNamedValue(KeyboardManagerConstants::InProcessRemapKeysSettingName, inProcessRemapKeysArray);
|
||||
configJson.SetNamedValue(KeyboardManagerConstants::RemapKeysSettingName, remapKeys);
|
||||
configJson.SetNamedValue(KeyboardManagerConstants::RemapShortcutsSettingName, remapShortcuts);
|
||||
|
||||
try
|
||||
{
|
||||
json::to_file((PTSettingsHelper::get_module_save_folder_location(KeyboardManagerConstants::ModuleName) + L"\\" + GetCurrentConfigName() + L".json"), configJson);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
result = false;
|
||||
Logger::error(L"Failed to save the settings");
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
auto hEvent = CreateEvent(nullptr, false, false, KeyboardManagerConstants::SettingsEventName.c_str());
|
||||
if (hEvent)
|
||||
{
|
||||
SetEvent(hEvent);
|
||||
Logger::trace(L"Signaled {} event", KeyboardManagerConstants::SettingsEventName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error(L"Failed to signal {} event", KeyboardManagerConstants::SettingsEventName);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void KeyboardManagerState::SetCurrentConfigName(const std::wstring& configName)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(currentConfig_mutex);
|
||||
currentConfig = configName;
|
||||
}
|
||||
|
||||
std::wstring KeyboardManagerState::GetCurrentConfigName()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(currentConfig_mutex);
|
||||
return currentConfig;
|
||||
}
|
||||
|
||||
// Sets the activated target application in app-specific shortcut
|
||||
void KeyboardManagerState::SetActivatedApp(const std::wstring& appName)
|
||||
{
|
||||
activatedAppSpecificShortcutTarget = appName;
|
||||
}
|
||||
|
||||
// Gets the activated target application in app-specific shortcut
|
||||
std::wstring KeyboardManagerState::GetActivatedApp()
|
||||
{
|
||||
return activatedAppSpecificShortcutTarget;
|
||||
}
|
||||
#include "pch.h"
|
||||
#include "KeyboardManagerState.h"
|
||||
|
||||
#include <keyboardmanager/common/Helpers.h>
|
||||
|
||||
#include "EditorHelpers.h"
|
||||
#include "KeyDelay.h"
|
||||
|
||||
using namespace KBMEditor;
|
||||
|
||||
// Constructor
|
||||
KeyboardManagerState::KeyboardManagerState() :
|
||||
uiState(KeyboardManagerUIState::Deactivated), currentUIWindow(nullptr), currentShortcutUI1(nullptr), currentShortcutUI2(nullptr), currentSingleKeyUI(nullptr), detectedRemapKey(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// Destructor
|
||||
KeyboardManagerState::~KeyboardManagerState()
|
||||
{
|
||||
}
|
||||
|
||||
// Function to check the if the UI state matches the argument state. For states with detect windows it also checks if the window is in focus.
|
||||
bool KeyboardManagerState::CheckUIState(KeyboardManagerUIState state)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(uiState_mutex);
|
||||
if (uiState == state)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(currentUIWindow_mutex);
|
||||
if (uiState == KeyboardManagerUIState::Deactivated || uiState == KeyboardManagerUIState::EditKeyboardWindowActivated || uiState == KeyboardManagerUIState::EditShortcutsWindowActivated)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// If the UI state is a detect window then we also have to ensure that the UI window is in focus.
|
||||
// GetForegroundWindow can be used here since we only need to check the main parent window and not the sub windows within the content dialog. Using GUIThreadInfo will give more specific sub-windows within the XAML window which is not needed.
|
||||
else if (currentUIWindow == GetForegroundWindow())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// If we are checking for EditKeyboardWindowActivated then it's possible the state could be DetectSingleKeyRemapWindowActivated but not in focus
|
||||
else if (state == KeyboardManagerUIState::EditKeyboardWindowActivated && uiState == KeyboardManagerUIState::DetectSingleKeyRemapWindowActivated)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// If we are checking for EditShortcutsWindowActivated then it's possible the state could be DetectShortcutWindowActivated but not in focus
|
||||
else if (state == KeyboardManagerUIState::EditShortcutsWindowActivated && uiState == KeyboardManagerUIState::DetectShortcutWindowActivated)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Function to set the window handle of the current UI window that is activated
|
||||
void KeyboardManagerState::SetCurrentUIWindow(HWND windowHandle)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(currentUIWindow_mutex);
|
||||
currentUIWindow = windowHandle;
|
||||
}
|
||||
|
||||
// Function to set the UI state. When a window is activated, the handle to the window can be passed in the windowHandle argument.
|
||||
void KeyboardManagerState::SetUIState(KeyboardManagerUIState state, HWND windowHandle)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(uiState_mutex);
|
||||
uiState = state;
|
||||
SetCurrentUIWindow(windowHandle);
|
||||
}
|
||||
|
||||
// Function to reset the UI state members
|
||||
void KeyboardManagerState::ResetUIState()
|
||||
{
|
||||
SetUIState(KeyboardManagerUIState::Deactivated);
|
||||
|
||||
// Reset the shortcut UI stored variables
|
||||
std::unique_lock<std::mutex> currentShortcutUI_lock(currentShortcutUI_mutex);
|
||||
currentShortcutUI1 = nullptr;
|
||||
currentShortcutUI2 = nullptr;
|
||||
currentShortcutUI_lock.unlock();
|
||||
|
||||
std::unique_lock<std::mutex> detectedShortcut_lock(detectedShortcut_mutex);
|
||||
detectedShortcut.Reset();
|
||||
detectedShortcut_lock.unlock();
|
||||
|
||||
std::unique_lock<std::mutex> currentShortcut_lock(currentShortcut_mutex);
|
||||
currentShortcut.Reset();
|
||||
currentShortcut_lock.unlock();
|
||||
|
||||
// Reset all the single key remap UI stored variables.
|
||||
std::unique_lock<std::mutex> currentSingleKeyUI_lock(currentSingleKeyUI_mutex);
|
||||
currentSingleKeyUI = nullptr;
|
||||
currentSingleKeyUI_lock.unlock();
|
||||
|
||||
std::unique_lock<std::mutex> detectedRemapKey_lock(detectedRemapKey_mutex);
|
||||
detectedRemapKey = NULL;
|
||||
detectedRemapKey_lock.unlock();
|
||||
}
|
||||
|
||||
// Function to set the textblock of the detect shortcut UI so that it can be accessed by the hook
|
||||
void KeyboardManagerState::ConfigureDetectShortcutUI(const StackPanel& textBlock1, const StackPanel& textBlock2)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(currentShortcutUI_mutex);
|
||||
currentShortcutUI1 = textBlock1.as<winrt::Windows::Foundation::IInspectable>();
|
||||
currentShortcutUI2 = textBlock2.as<winrt::Windows::Foundation::IInspectable>();
|
||||
}
|
||||
|
||||
// Function to set the textblock of the detect remap key UI so that it can be accessed by the hook
|
||||
void KeyboardManagerState::ConfigureDetectSingleKeyRemapUI(const StackPanel& textBlock)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(currentSingleKeyUI_mutex);
|
||||
currentSingleKeyUI = textBlock.as<winrt::Windows::Foundation::IInspectable>();
|
||||
}
|
||||
|
||||
void KeyboardManagerState::AddKeyToLayout(const StackPanel& panel, const hstring& key)
|
||||
{
|
||||
// Textblock to display the detected key
|
||||
TextBlock remapKey;
|
||||
Border border;
|
||||
|
||||
border.Padding({ 20, 10, 20, 10 });
|
||||
border.Margin({ 0, 0, 10, 0 });
|
||||
// Use the base low brush to be consistent with the theme
|
||||
border.Background(Windows::UI::Xaml::Application::Current().Resources().Lookup(box_value(L"SystemControlBackgroundBaseLowBrush")).as<Windows::UI::Xaml::Media::SolidColorBrush>());
|
||||
remapKey.FontSize(20);
|
||||
border.HorizontalAlignment(HorizontalAlignment::Left);
|
||||
border.Child(remapKey);
|
||||
|
||||
remapKey.Text(key);
|
||||
panel.Children().Append(border);
|
||||
}
|
||||
|
||||
// Function to update the detect shortcut UI based on the entered keys
|
||||
void KeyboardManagerState::UpdateDetectShortcutUI()
|
||||
{
|
||||
std::lock_guard<std::mutex> currentShortcutUI_lock(currentShortcutUI_mutex);
|
||||
if (currentShortcutUI1 == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> detectedShortcut_lock(detectedShortcut_mutex);
|
||||
std::unique_lock<std::mutex> currentShortcut_lock(currentShortcut_mutex);
|
||||
// Save the latest displayed shortcut
|
||||
currentShortcut = detectedShortcut;
|
||||
auto detectedShortcutCopy = detectedShortcut;
|
||||
currentShortcut_lock.unlock();
|
||||
detectedShortcut_lock.unlock();
|
||||
// Since this function is invoked from the back-end thread, in order to update the UI the dispatcher must be used.
|
||||
currentShortcutUI1.as<StackPanel>().Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [this, detectedShortcutCopy]() {
|
||||
std::vector<hstring> shortcut = EditorHelpers::GetKeyVector(detectedShortcutCopy, keyboardMap);
|
||||
currentShortcutUI1.as<StackPanel>().Children().Clear();
|
||||
currentShortcutUI2.as<StackPanel>().Children().Clear();
|
||||
|
||||
// The second row should be hidden if there are 3 keys or lesser to avoid an extra margin
|
||||
if (shortcut.size() > 3)
|
||||
{
|
||||
currentShortcutUI2.as<StackPanel>().Visibility(Visibility::Visible);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentShortcutUI2.as<StackPanel>().Visibility(Visibility::Collapsed);
|
||||
}
|
||||
|
||||
for (int i = 0; i < shortcut.size(); i++)
|
||||
{
|
||||
if (i < 3)
|
||||
{
|
||||
AddKeyToLayout(currentShortcutUI1.as<StackPanel>(), shortcut[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddKeyToLayout(currentShortcutUI2.as<StackPanel>(), shortcut[i]);
|
||||
}
|
||||
}
|
||||
currentShortcutUI1.as<StackPanel>().UpdateLayout();
|
||||
currentShortcutUI2.as<StackPanel>().UpdateLayout();
|
||||
});
|
||||
}
|
||||
|
||||
// Function to update the detect remap key UI based on the entered key.
|
||||
void KeyboardManagerState::UpdateDetectSingleKeyRemapUI()
|
||||
{
|
||||
std::lock_guard<std::mutex> currentSingleKeyUI_lock(currentSingleKeyUI_mutex);
|
||||
if (currentSingleKeyUI == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Since this function is invoked from the back-end thread, in order to update the UI the dispatcher must be used.
|
||||
currentSingleKeyUI.as<StackPanel>().Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [this]() {
|
||||
currentSingleKeyUI.as<StackPanel>().Children().Clear();
|
||||
hstring key = winrt::to_hstring(keyboardMap.GetKeyName(detectedRemapKey).c_str());
|
||||
AddKeyToLayout(currentSingleKeyUI.as<StackPanel>(), key);
|
||||
currentSingleKeyUI.as<StackPanel>().UpdateLayout();
|
||||
});
|
||||
}
|
||||
|
||||
// Function to return the currently detected shortcut which is displayed on the UI
|
||||
Shortcut KeyboardManagerState::GetDetectedShortcut()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(currentShortcut_mutex);
|
||||
return currentShortcut;
|
||||
}
|
||||
|
||||
// Function to return the currently detected remap key which is displayed on the UI
|
||||
DWORD KeyboardManagerState::GetDetectedSingleRemapKey()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(detectedRemapKey_mutex);
|
||||
return detectedRemapKey;
|
||||
}
|
||||
|
||||
void KeyboardManagerState::SelectDetectedRemapKey(DWORD key)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(detectedRemapKey_mutex);
|
||||
detectedRemapKey = key;
|
||||
UpdateDetectSingleKeyRemapUI();
|
||||
return;
|
||||
}
|
||||
|
||||
void KeyboardManagerState::SelectDetectedShortcut(DWORD key)
|
||||
{
|
||||
// Set the new key and store if a change occurred
|
||||
std::unique_lock<std::mutex> lock(detectedShortcut_mutex);
|
||||
bool updateUI = detectedShortcut.SetKey(key);
|
||||
lock.unlock();
|
||||
|
||||
if (updateUI)
|
||||
{
|
||||
// Update the UI. This function is called here because it should store the set of keys pressed till the last key which was pressed down.
|
||||
UpdateDetectShortcutUI();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void KeyboardManagerState::ResetDetectedShortcutKey(DWORD key)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(detectedShortcut_mutex);
|
||||
detectedShortcut.ResetKey(key);
|
||||
}
|
||||
|
||||
// Function which can be used in HandleKeyboardHookEvent before the single key remap event to use the UI and suppress events while the remap window is active.
|
||||
Helpers::KeyboardHookDecision KeyboardManagerState::DetectSingleRemapKeyUIBackend(LowlevelKeyboardEvent* data)
|
||||
{
|
||||
// Check if the detect key UI window has been activated
|
||||
if (CheckUIState(KeyboardManagerUIState::DetectSingleKeyRemapWindowActivated))
|
||||
{
|
||||
if (HandleKeyDelayEvent(data))
|
||||
{
|
||||
return Helpers::KeyboardHookDecision::Suppress;
|
||||
}
|
||||
// detect the key if it is pressed down
|
||||
if (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN)
|
||||
{
|
||||
SelectDetectedRemapKey(data->lParam->vkCode);
|
||||
}
|
||||
|
||||
// Suppress the keyboard event
|
||||
return Helpers::KeyboardHookDecision::Suppress;
|
||||
}
|
||||
|
||||
// If the settings window is up, remappings should not be applied, but we should not suppress events in the hook
|
||||
else if (CheckUIState(KeyboardManagerUIState::EditKeyboardWindowActivated))
|
||||
{
|
||||
return Helpers::KeyboardHookDecision::SkipHook;
|
||||
}
|
||||
|
||||
return Helpers::KeyboardHookDecision::ContinueExec;
|
||||
}
|
||||
|
||||
// Function which can be used in HandleKeyboardHookEvent before the os level shortcut remap event to use the UI and suppress events while the remap window is active.
|
||||
Helpers::KeyboardHookDecision KeyboardManagerState::DetectShortcutUIBackend(LowlevelKeyboardEvent* data, bool isRemapKey)
|
||||
{
|
||||
// Check if the detect shortcut UI window has been activated
|
||||
if ((!isRemapKey && CheckUIState(KeyboardManagerUIState::DetectShortcutWindowActivated)) || (isRemapKey && CheckUIState(KeyboardManagerUIState::DetectShortcutWindowInEditKeyboardWindowActivated)))
|
||||
{
|
||||
if (HandleKeyDelayEvent(data))
|
||||
{
|
||||
return Helpers::KeyboardHookDecision::Suppress;
|
||||
}
|
||||
|
||||
// Add the key if it is pressed down
|
||||
if (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN)
|
||||
{
|
||||
SelectDetectedShortcut(data->lParam->vkCode);
|
||||
}
|
||||
// Remove the key if it has been released
|
||||
else if (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP)
|
||||
{
|
||||
ResetDetectedShortcutKey(data->lParam->vkCode);
|
||||
}
|
||||
|
||||
// Suppress the keyboard event
|
||||
return Helpers::KeyboardHookDecision::Suppress;
|
||||
}
|
||||
|
||||
// If the detect shortcut UI window is not activated, then clear the shortcut buffer if it isn't empty
|
||||
else if (!CheckUIState(KeyboardManagerUIState::DetectShortcutWindowActivated) && !CheckUIState(KeyboardManagerUIState::DetectShortcutWindowInEditKeyboardWindowActivated))
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(detectedShortcut_mutex);
|
||||
if (!detectedShortcut.IsEmpty())
|
||||
{
|
||||
detectedShortcut.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
// If the settings window is up, shortcut remappings should not be applied, but we should not suppress events in the hook
|
||||
if (!isRemapKey && (CheckUIState(KeyboardManagerUIState::EditShortcutsWindowActivated)) || (isRemapKey && uiState == KeyboardManagerUIState::DetectShortcutWindowInEditKeyboardWindowActivated))
|
||||
{
|
||||
return Helpers::KeyboardHookDecision::SkipHook;
|
||||
}
|
||||
|
||||
return Helpers::KeyboardHookDecision::ContinueExec;
|
||||
}
|
||||
|
||||
void KeyboardManagerState::RegisterKeyDelay(
|
||||
DWORD key,
|
||||
std::function<void(DWORD)> onShortPress,
|
||||
std::function<void(DWORD)> onLongPressDetected,
|
||||
std::function<void(DWORD)> onLongPressReleased)
|
||||
{
|
||||
std::lock_guard l(keyDelays_mutex);
|
||||
|
||||
if (keyDelays.find(key) != keyDelays.end())
|
||||
{
|
||||
throw std::invalid_argument("This key was already registered.");
|
||||
}
|
||||
|
||||
keyDelays[key] = std::make_unique<KeyDelay>(key, onShortPress, onLongPressDetected, onLongPressReleased);
|
||||
}
|
||||
|
||||
void KeyboardManagerState::UnregisterKeyDelay(DWORD key)
|
||||
{
|
||||
std::lock_guard l(keyDelays_mutex);
|
||||
|
||||
auto deleted = keyDelays.erase(key);
|
||||
if (deleted == 0)
|
||||
{
|
||||
throw std::invalid_argument("The key was not previously registered.");
|
||||
}
|
||||
}
|
||||
|
||||
// Function to clear all the registered key delays
|
||||
void KeyboardManagerState::ClearRegisteredKeyDelays()
|
||||
{
|
||||
std::lock_guard l(keyDelays_mutex);
|
||||
keyDelays.clear();
|
||||
}
|
||||
|
||||
bool KeyboardManagerState::HandleKeyDelayEvent(LowlevelKeyboardEvent* ev)
|
||||
{
|
||||
if (currentUIWindow != GetForegroundWindow())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard l(keyDelays_mutex);
|
||||
|
||||
if (keyDelays.find(ev->lParam->vkCode) == keyDelays.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
keyDelays[ev->lParam->vkCode]->KeyEvent(ev);
|
||||
return true;
|
||||
}
|
@ -0,0 +1,161 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/hooks/LowlevelKeyboardEvent.h>
|
||||
#include <common/interop/keyboard_layout.h>
|
||||
|
||||
#include <keyboardmanager/common/KeyboardManagerConstants.h>
|
||||
#include <keyboardmanager/common/Shortcut.h>
|
||||
|
||||
class KeyDelay;
|
||||
|
||||
namespace Helpers
|
||||
{
|
||||
// Enum type to store possible decision for input in the low level hook
|
||||
enum class KeyboardHookDecision
|
||||
{
|
||||
ContinueExec,
|
||||
Suppress,
|
||||
SkipHook
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Windows::UI::Xaml::Controls
|
||||
{
|
||||
struct StackPanel;
|
||||
}
|
||||
|
||||
namespace KBMEditor
|
||||
{
|
||||
// Enum type to store different states of the UI
|
||||
enum class KeyboardManagerUIState
|
||||
{
|
||||
// If set to this value then there is no keyboard manager window currently active that requires a hook
|
||||
Deactivated,
|
||||
// If set to this value then the detect key window is currently active and it requires a hook
|
||||
DetectSingleKeyRemapWindowActivated,
|
||||
// If set to this value then the detect shortcut window in edit keyboard window is currently active and it requires a hook
|
||||
DetectShortcutWindowInEditKeyboardWindowActivated,
|
||||
// If set to this value then the edit keyboard window is currently active and remaps should not be applied
|
||||
EditKeyboardWindowActivated,
|
||||
// If set to this value then the detect shortcut window is currently active and it requires a hook
|
||||
DetectShortcutWindowActivated,
|
||||
// If set to this value then the edit shortcuts window is currently active and remaps should not be applied
|
||||
EditShortcutsWindowActivated
|
||||
};
|
||||
|
||||
// Class to store the shared state of the keyboard manager between the UI and the hook
|
||||
class KeyboardManagerState
|
||||
{
|
||||
private:
|
||||
// State variable used to store which UI window is currently active that requires interaction with the hook
|
||||
KeyboardManagerUIState uiState;
|
||||
std::mutex uiState_mutex;
|
||||
|
||||
// Window handle for the current UI window which is active. Should be set to nullptr if UI is deactivated
|
||||
HWND currentUIWindow;
|
||||
std::mutex currentUIWindow_mutex;
|
||||
|
||||
// Object to store the shortcut detected in the detect shortcut UI window. Gets cleared on releasing keys. This is used in both the backend and the UI.
|
||||
Shortcut detectedShortcut;
|
||||
std::mutex detectedShortcut_mutex;
|
||||
|
||||
// Object to store the shortcut state displayed in the UI window. Always stores last displayed shortcut irrespective of releasing keys. This is used in both the backend and the UI.
|
||||
Shortcut currentShortcut;
|
||||
std::mutex currentShortcut_mutex;
|
||||
|
||||
// Store detected remap key in the remap UI window. This is used in both the backend and the UI.
|
||||
DWORD detectedRemapKey;
|
||||
std::mutex detectedRemapKey_mutex;
|
||||
|
||||
// Stores the UI element which is to be updated based on the remap key entered.
|
||||
winrt::Windows::Foundation::IInspectable currentSingleKeyUI;
|
||||
std::mutex currentSingleKeyUI_mutex;
|
||||
|
||||
// Stores the UI element which is to be updated based on the shortcut entered (each stackpanel represents a row of keys)
|
||||
winrt::Windows::Foundation::IInspectable currentShortcutUI1;
|
||||
winrt::Windows::Foundation::IInspectable currentShortcutUI2;
|
||||
std::mutex currentShortcutUI_mutex;
|
||||
|
||||
// Registered KeyDelay objects, used to notify delayed key events.
|
||||
std::map<DWORD, std::unique_ptr<KeyDelay>> keyDelays;
|
||||
std::mutex keyDelays_mutex;
|
||||
|
||||
// Display a key by appending a border Control as a child of the panel.
|
||||
void AddKeyToLayout(const winrt::Windows::UI::Xaml::Controls::StackPanel& panel, const winrt::hstring& key);
|
||||
|
||||
public:
|
||||
// Stores the keyboard layout
|
||||
LayoutMap keyboardMap;
|
||||
|
||||
// Constructor
|
||||
KeyboardManagerState();
|
||||
|
||||
// Destructor
|
||||
~KeyboardManagerState();
|
||||
|
||||
// Function to reset the UI state members
|
||||
void ResetUIState();
|
||||
|
||||
// Function to check the if the UI state matches the argument state. For states with detect windows it also checks if the window is in focus.
|
||||
bool CheckUIState(KeyboardManagerUIState state);
|
||||
|
||||
// Function to set the window handle of the current UI window that is activated
|
||||
void SetCurrentUIWindow(HWND windowHandle);
|
||||
|
||||
// Function to set the UI state. When a window is activated, the handle to the window can be passed in the windowHandle argument.
|
||||
void SetUIState(KeyboardManagerUIState state, HWND windowHandle = nullptr);
|
||||
|
||||
// Function to set the textblock of the detect shortcut UI so that it can be accessed by the hook
|
||||
void ConfigureDetectShortcutUI(const winrt::Windows::UI::Xaml::Controls::StackPanel& textBlock1, const winrt::Windows::UI::Xaml::Controls::StackPanel& textBlock2);
|
||||
|
||||
// Function to set the textblock of the detect remap key UI so that it can be accessed by the hook
|
||||
void ConfigureDetectSingleKeyRemapUI(const winrt::Windows::UI::Xaml::Controls::StackPanel& textBlock);
|
||||
|
||||
// Function to update the detect shortcut UI based on the entered keys
|
||||
void UpdateDetectShortcutUI();
|
||||
|
||||
// Function to update the detect remap key UI based on the entered key.
|
||||
void UpdateDetectSingleKeyRemapUI();
|
||||
|
||||
// Function to return the currently detected shortcut which is displayed on the UI
|
||||
Shortcut GetDetectedShortcut();
|
||||
|
||||
// Function to return the currently detected remap key which is displayed on the UI
|
||||
DWORD GetDetectedSingleRemapKey();
|
||||
|
||||
// Function which can be used in HandleKeyboardHookEvent before the single key remap event to use the UI and suppress events while the remap window is active.
|
||||
Helpers::KeyboardHookDecision DetectSingleRemapKeyUIBackend(LowlevelKeyboardEvent* data);
|
||||
|
||||
// Function which can be used in HandleKeyboardHookEvent before the os level shortcut remap event to use the UI and suppress events while the remap window is active.
|
||||
Helpers::KeyboardHookDecision DetectShortcutUIBackend(LowlevelKeyboardEvent* data, bool isRemapKey);
|
||||
|
||||
// Add a KeyDelay object to get delayed key presses events for a given virtual key
|
||||
// NOTE: this will throw an exception if a virtual key is registered twice.
|
||||
// NOTE*: the virtual key should represent the original, unmapped virtual key.
|
||||
void RegisterKeyDelay(
|
||||
DWORD key,
|
||||
std::function<void(DWORD)> onShortPress,
|
||||
std::function<void(DWORD)> onLongPressDetected,
|
||||
std::function<void(DWORD)> onLongPressReleased);
|
||||
|
||||
// Remove a KeyDelay.
|
||||
// NOTE: this method will throw if the virtual key is not registered beforehand.
|
||||
// NOTE*: the virtual key should represent the original, unmapped virtual key.
|
||||
void UnregisterKeyDelay(DWORD key);
|
||||
|
||||
// Function to clear all the registered key delays
|
||||
void ClearRegisteredKeyDelays();
|
||||
|
||||
// Handle a key event, for a delayed key.
|
||||
bool HandleKeyDelayEvent(LowlevelKeyboardEvent* ev);
|
||||
|
||||
// Update the currently selected single key remap
|
||||
void SelectDetectedRemapKey(DWORD key);
|
||||
|
||||
// Update the currently selected shortcut.
|
||||
void SelectDetectedShortcut(DWORD key);
|
||||
|
||||
// Reset the shortcut (backend) state after releasing a key.
|
||||
void ResetDetectedShortcutKey(DWORD key);
|
||||
};
|
||||
}
|
@ -2,19 +2,20 @@
|
||||
#include "LoadingAndSavingRemappingHelper.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <common/interop/shared_constants.h>
|
||||
#include <ErrorTypes.h>
|
||||
#include <KeyboardManagerState.h>
|
||||
#include <keyboardmanager/common/MappingConfiguration.h>
|
||||
|
||||
#include <keyboardmanager/KeyboardManagerEditorLibrary/trace.h>
|
||||
#include "KeyboardManagerState.h"
|
||||
#include "keyboardmanager/KeyboardManagerEditorLibrary/trace.h"
|
||||
#include "EditorHelpers.h"
|
||||
#include "ShortcutErrorType.h"
|
||||
|
||||
namespace LoadingAndSavingRemappingHelper
|
||||
{
|
||||
// Function to check if the set of remappings in the buffer are valid
|
||||
KeyboardManagerHelper::ErrorType CheckIfRemappingsAreValid(const RemapBuffer& remappings)
|
||||
ShortcutErrorType CheckIfRemappingsAreValid(const RemapBuffer& remappings)
|
||||
{
|
||||
KeyboardManagerHelper::ErrorType isSuccess = KeyboardManagerHelper::ErrorType::NoError;
|
||||
ShortcutErrorType isSuccess = ShortcutErrorType::NoError;
|
||||
std::map<std::wstring, std::set<KeyShortcutUnion>> ogKeys;
|
||||
for (int i = 0; i < remappings.size(); i++)
|
||||
{
|
||||
@ -22,8 +23,8 @@ namespace LoadingAndSavingRemappingHelper
|
||||
KeyShortcutUnion newKey = remappings[i].first[1];
|
||||
std::wstring appName = remappings[i].second;
|
||||
|
||||
bool ogKeyValidity = (ogKey.index() == 0 && std::get<DWORD>(ogKey) != NULL) || (ogKey.index() == 1 && std::get<Shortcut>(ogKey).IsValidShortcut());
|
||||
bool newKeyValidity = (newKey.index() == 0 && std::get<DWORD>(newKey) != NULL) || (newKey.index() == 1 && std::get<Shortcut>(newKey).IsValidShortcut());
|
||||
bool ogKeyValidity = (ogKey.index() == 0 && std::get<DWORD>(ogKey) != NULL) || (ogKey.index() == 1 && EditorHelpers::IsValidShortcut(std::get<Shortcut>(ogKey)));
|
||||
bool newKeyValidity = (newKey.index() == 0 && std::get<DWORD>(newKey) != NULL) || (newKey.index() == 1 && EditorHelpers::IsValidShortcut(std::get<Shortcut>(newKey)));
|
||||
|
||||
// Add new set for a new target app name
|
||||
if (ogKeys.find(appName) == ogKeys.end())
|
||||
@ -37,11 +38,11 @@ namespace LoadingAndSavingRemappingHelper
|
||||
}
|
||||
else if (ogKeyValidity && newKeyValidity && ogKeys[appName].find(ogKey) != ogKeys[appName].end())
|
||||
{
|
||||
isSuccess = KeyboardManagerHelper::ErrorType::RemapUnsuccessful;
|
||||
isSuccess = ShortcutErrorType::RemapUnsuccessful;
|
||||
}
|
||||
else
|
||||
{
|
||||
isSuccess = KeyboardManagerHelper::ErrorType::RemapUnsuccessful;
|
||||
isSuccess = ShortcutErrorType::RemapUnsuccessful;
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,7 +60,7 @@ namespace LoadingAndSavingRemappingHelper
|
||||
DWORD ogKey = std::get<DWORD>(remappings[i].first[0]);
|
||||
KeyShortcutUnion newKey = remappings[i].first[1];
|
||||
|
||||
if (ogKey != NULL && ((newKey.index() == 0 && std::get<DWORD>(newKey) != 0) || (newKey.index() == 1 && std::get<Shortcut>(newKey).IsValidShortcut())))
|
||||
if (ogKey != NULL && ((newKey.index() == 0 && std::get<DWORD>(newKey) != 0) || (newKey.index() == 1 && EditorHelpers::IsValidShortcut(std::get<Shortcut>(newKey)))))
|
||||
{
|
||||
ogKeys.insert(ogKey);
|
||||
|
||||
@ -105,10 +106,10 @@ namespace LoadingAndSavingRemappingHelper
|
||||
}
|
||||
|
||||
// Function to apply the single key remappings from the buffer to the KeyboardManagerState variable
|
||||
void ApplySingleKeyRemappings(KeyboardManagerState& keyboardManagerState, const RemapBuffer& remappings, bool isTelemetryRequired)
|
||||
void ApplySingleKeyRemappings(MappingConfiguration& mappingConfiguration, const RemapBuffer& remappings, bool isTelemetryRequired)
|
||||
{
|
||||
// Clear existing Key Remaps
|
||||
keyboardManagerState.ClearSingleKeyRemaps();
|
||||
mappingConfiguration.ClearSingleKeyRemaps();
|
||||
DWORD successfulKeyToKeyRemapCount = 0;
|
||||
DWORD successfulKeyToShortcutRemapCount = 0;
|
||||
for (int i = 0; i < remappings.size(); i++)
|
||||
@ -116,7 +117,7 @@ namespace LoadingAndSavingRemappingHelper
|
||||
DWORD originalKey = std::get<DWORD>(remappings[i].first[0]);
|
||||
KeyShortcutUnion newKey = remappings[i].first[1];
|
||||
|
||||
if (originalKey != NULL && !(newKey.index() == 0 && std::get<DWORD>(newKey) == NULL) && !(newKey.index() == 1 && !std::get<Shortcut>(newKey).IsValidShortcut()))
|
||||
if (originalKey != NULL && !(newKey.index() == 0 && std::get<DWORD>(newKey) == NULL) && !(newKey.index() == 1 && !EditorHelpers::IsValidShortcut(std::get<Shortcut>(newKey))))
|
||||
{
|
||||
// If Ctrl/Alt/Shift are added, add their L and R versions instead to the same key
|
||||
bool result = false;
|
||||
@ -124,27 +125,27 @@ namespace LoadingAndSavingRemappingHelper
|
||||
switch (originalKey)
|
||||
{
|
||||
case VK_CONTROL:
|
||||
res1 = keyboardManagerState.AddSingleKeyRemap(VK_LCONTROL, newKey);
|
||||
res2 = keyboardManagerState.AddSingleKeyRemap(VK_RCONTROL, newKey);
|
||||
res1 = mappingConfiguration.AddSingleKeyRemap(VK_LCONTROL, newKey);
|
||||
res2 = mappingConfiguration.AddSingleKeyRemap(VK_RCONTROL, newKey);
|
||||
result = res1 && res2;
|
||||
break;
|
||||
case VK_MENU:
|
||||
res1 = keyboardManagerState.AddSingleKeyRemap(VK_LMENU, newKey);
|
||||
res2 = keyboardManagerState.AddSingleKeyRemap(VK_RMENU, newKey);
|
||||
res1 = mappingConfiguration.AddSingleKeyRemap(VK_LMENU, newKey);
|
||||
res2 = mappingConfiguration.AddSingleKeyRemap(VK_RMENU, newKey);
|
||||
result = res1 && res2;
|
||||
break;
|
||||
case VK_SHIFT:
|
||||
res1 = keyboardManagerState.AddSingleKeyRemap(VK_LSHIFT, newKey);
|
||||
res2 = keyboardManagerState.AddSingleKeyRemap(VK_RSHIFT, newKey);
|
||||
res1 = mappingConfiguration.AddSingleKeyRemap(VK_LSHIFT, newKey);
|
||||
res2 = mappingConfiguration.AddSingleKeyRemap(VK_RSHIFT, newKey);
|
||||
result = res1 && res2;
|
||||
break;
|
||||
case CommonSharedConstants::VK_WIN_BOTH:
|
||||
res1 = keyboardManagerState.AddSingleKeyRemap(VK_LWIN, newKey);
|
||||
res2 = keyboardManagerState.AddSingleKeyRemap(VK_RWIN, newKey);
|
||||
res1 = mappingConfiguration.AddSingleKeyRemap(VK_LWIN, newKey);
|
||||
res2 = mappingConfiguration.AddSingleKeyRemap(VK_RWIN, newKey);
|
||||
result = res1 && res2;
|
||||
break;
|
||||
default:
|
||||
result = keyboardManagerState.AddSingleKeyRemap(originalKey, newKey);
|
||||
result = mappingConfiguration.AddSingleKeyRemap(originalKey, newKey);
|
||||
}
|
||||
|
||||
if (result)
|
||||
@ -169,11 +170,11 @@ namespace LoadingAndSavingRemappingHelper
|
||||
}
|
||||
|
||||
// Function to apply the shortcut remappings from the buffer to the KeyboardManagerState variable
|
||||
void ApplyShortcutRemappings(KeyboardManagerState& keyboardManagerState, const RemapBuffer& remappings, bool isTelemetryRequired)
|
||||
void ApplyShortcutRemappings(MappingConfiguration& mappingConfiguration, const RemapBuffer& remappings, bool isTelemetryRequired)
|
||||
{
|
||||
// Clear existing shortcuts
|
||||
keyboardManagerState.ClearOSLevelShortcuts();
|
||||
keyboardManagerState.ClearAppSpecificShortcuts();
|
||||
mappingConfiguration.ClearOSLevelShortcuts();
|
||||
mappingConfiguration.ClearAppSpecificShortcuts();
|
||||
DWORD successfulOSLevelShortcutToShortcutRemapCount = 0;
|
||||
DWORD successfulOSLevelShortcutToKeyRemapCount = 0;
|
||||
DWORD successfulAppSpecificShortcutToShortcutRemapCount = 0;
|
||||
@ -185,11 +186,11 @@ namespace LoadingAndSavingRemappingHelper
|
||||
Shortcut originalShortcut = std::get<Shortcut>(remappings[i].first[0]);
|
||||
KeyShortcutUnion newShortcut = remappings[i].first[1];
|
||||
|
||||
if (originalShortcut.IsValidShortcut() && ((newShortcut.index() == 0 && std::get<DWORD>(newShortcut) != NULL) || (newShortcut.index() == 1 && std::get<Shortcut>(newShortcut).IsValidShortcut())))
|
||||
if (EditorHelpers::IsValidShortcut(originalShortcut) && ((newShortcut.index() == 0 && std::get<DWORD>(newShortcut) != NULL) || (newShortcut.index() == 1 && EditorHelpers::IsValidShortcut(std::get<Shortcut>(newShortcut)))))
|
||||
{
|
||||
if (remappings[i].second == L"")
|
||||
{
|
||||
bool result = keyboardManagerState.AddOSLevelShortcut(originalShortcut, newShortcut);
|
||||
bool result = mappingConfiguration.AddOSLevelShortcut(originalShortcut, newShortcut);
|
||||
if (result)
|
||||
{
|
||||
if (newShortcut.index() == 0)
|
||||
@ -204,7 +205,7 @@ namespace LoadingAndSavingRemappingHelper
|
||||
}
|
||||
else
|
||||
{
|
||||
bool result = keyboardManagerState.AddAppSpecificShortcut(remappings[i].second, originalShortcut, newShortcut);
|
||||
bool result = mappingConfiguration.AddAppSpecificShortcut(remappings[i].second, originalShortcut, newShortcut);
|
||||
if (result)
|
||||
{
|
||||
if (newShortcut.index() == 0)
|
||||
|
@ -2,12 +2,14 @@
|
||||
|
||||
#include <keyboardmanager/common/Helpers.h>
|
||||
|
||||
class KeyboardManagerState;
|
||||
#include "ShortcutErrorType.h"
|
||||
|
||||
class MappingConfiguration;
|
||||
|
||||
namespace LoadingAndSavingRemappingHelper
|
||||
{
|
||||
// Function to check if the set of remappings in the buffer are valid
|
||||
KeyboardManagerHelper::ErrorType CheckIfRemappingsAreValid(const RemapBuffer& remappings);
|
||||
ShortcutErrorType CheckIfRemappingsAreValid(const RemapBuffer& remappings);
|
||||
|
||||
// Function to return the set of keys that have been orphaned from the remap buffer
|
||||
std::vector<DWORD> GetOrphanedKeys(const RemapBuffer& remappings);
|
||||
@ -19,8 +21,8 @@ namespace LoadingAndSavingRemappingHelper
|
||||
void PreProcessRemapTable(std::unordered_map<DWORD, KeyShortcutUnion>& table);
|
||||
|
||||
// Function to apply the single key remappings from the buffer to the KeyboardManagerState variable
|
||||
void ApplySingleKeyRemappings(KeyboardManagerState& keyboardManagerState, const RemapBuffer& remappings, bool isTelemetryRequired);
|
||||
void ApplySingleKeyRemappings(MappingConfiguration& mappingConfiguration, const RemapBuffer& remappings, bool isTelemetryRequired);
|
||||
|
||||
// Function to apply the shortcut remappings from the buffer to the KeyboardManagerState variable
|
||||
void ApplyShortcutRemappings(KeyboardManagerState& keyboardManagerState, const RemapBuffer& remappings, bool isTelemetryRequired);
|
||||
void ApplyShortcutRemappings(MappingConfiguration& mappingConfiguration, const RemapBuffer& remappings, bool isTelemetryRequired);
|
||||
}
|
||||
|
@ -3,15 +3,16 @@
|
||||
|
||||
#include <common/interop/shared_constants.h>
|
||||
|
||||
#include <KeyboardManagerState.h>
|
||||
|
||||
#include <KeyboardManagerEditorStrings.h>
|
||||
#include <KeyDropDownControl.h>
|
||||
#include <UIHelpers.h>
|
||||
#include "KeyboardManagerState.h"
|
||||
#include "KeyboardManagerEditorStrings.h"
|
||||
#include "KeyDropDownControl.h"
|
||||
#include "UIHelpers.h"
|
||||
#include "EditorHelpers.h"
|
||||
#include "EditorConstants.h"
|
||||
|
||||
//Both static members are initialized to null
|
||||
HWND ShortcutControl::editShortcutsWindowHandle = nullptr;
|
||||
KeyboardManagerState* ShortcutControl::keyboardManagerState = nullptr;
|
||||
KBMEditor::KeyboardManagerState* ShortcutControl::keyboardManagerState = nullptr;
|
||||
// Initialized as new vector
|
||||
RemapBuffer ShortcutControl::shortcutRemapBuffer;
|
||||
|
||||
@ -22,13 +23,13 @@ ShortcutControl::ShortcutControl(StackPanel table, StackPanel row, const int col
|
||||
shortcutControlLayout = StackPanel();
|
||||
bool isHybridControl = colIndex == 1 ? true : false;
|
||||
|
||||
shortcutDropDownStackPanel.as<StackPanel>().Spacing(KeyboardManagerConstants::ShortcutTableDropDownSpacing);
|
||||
shortcutDropDownStackPanel.as<StackPanel>().Spacing(EditorConstants::ShortcutTableDropDownSpacing);
|
||||
shortcutDropDownStackPanel.as<StackPanel>().Orientation(Windows::UI::Xaml::Controls::Orientation::Horizontal);
|
||||
|
||||
typeShortcut.as<Button>().Content(winrt::box_value(GET_RESOURCE_STRING(IDS_TYPE_BUTTON)));
|
||||
typeShortcut.as<Button>().Width(KeyboardManagerConstants::ShortcutTableDropDownWidth);
|
||||
typeShortcut.as<Button>().Width(EditorConstants::ShortcutTableDropDownWidth);
|
||||
typeShortcut.as<Button>().Click([&, table, row, colIndex, isHybridControl, targetApp](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
keyboardManagerState->SetUIState(KeyboardManagerUIState::DetectShortcutWindowActivated, editShortcutsWindowHandle);
|
||||
keyboardManagerState->SetUIState(KBMEditor::KeyboardManagerUIState::DetectShortcutWindowActivated, editShortcutsWindowHandle);
|
||||
// Using the XamlRoot of the typeShortcut to get the root of the XAML host
|
||||
CreateDetectShortcutWindow(sender, sender.as<Button>().XamlRoot(), *keyboardManagerState, colIndex, table, keyDropDownControlObjects, row, targetApp, isHybridControl, false, editShortcutsWindowHandle, shortcutRemapBuffer);
|
||||
});
|
||||
@ -36,7 +37,7 @@ ShortcutControl::ShortcutControl(StackPanel table, StackPanel row, const int col
|
||||
// Set an accessible name for the type shortcut button
|
||||
typeShortcut.as<Button>().SetValue(Automation::AutomationProperties::NameProperty(), box_value(GET_RESOURCE_STRING(IDS_TYPE_BUTTON)));
|
||||
|
||||
shortcutControlLayout.as<StackPanel>().Spacing(KeyboardManagerConstants::ShortcutTableDropDownSpacing);
|
||||
shortcutControlLayout.as<StackPanel>().Spacing(EditorConstants::ShortcutTableDropDownSpacing);
|
||||
|
||||
shortcutControlLayout.as<StackPanel>().Children().Append(typeShortcut.as<Button>());
|
||||
shortcutControlLayout.as<StackPanel>().Children().Append(shortcutDropDownStackPanel.as<StackPanel>());
|
||||
@ -90,7 +91,7 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
|
||||
|
||||
// ShortcutControl for the original shortcut
|
||||
auto origin = keyboardRemapControlObjects.back()[0]->GetShortcutControl();
|
||||
origin.Width(KeyboardManagerConstants::ShortcutOriginColumnWidth);
|
||||
origin.Width(EditorConstants::ShortcutOriginColumnWidth);
|
||||
row.Children().Append(origin);
|
||||
|
||||
// Arrow icon
|
||||
@ -99,17 +100,17 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
|
||||
arrowIcon.Glyph(L"\xE72A");
|
||||
arrowIcon.VerticalAlignment(VerticalAlignment::Center);
|
||||
arrowIcon.HorizontalAlignment(HorizontalAlignment::Center);
|
||||
auto arrowIconContainer = UIHelpers::GetWrapped(arrowIcon, KeyboardManagerConstants::ShortcutArrowColumnWidth).as<StackPanel>();
|
||||
auto arrowIconContainer = UIHelpers::GetWrapped(arrowIcon, EditorConstants::ShortcutArrowColumnWidth).as<StackPanel>();
|
||||
arrowIconContainer.Orientation(Orientation::Vertical);
|
||||
arrowIconContainer.VerticalAlignment(VerticalAlignment::Center);
|
||||
row.Children().Append(arrowIconContainer);
|
||||
|
||||
// ShortcutControl for the new shortcut
|
||||
auto target = keyboardRemapControlObjects.back()[1]->GetShortcutControl();
|
||||
target.Width(KeyboardManagerConstants::ShortcutTargetColumnWidth);
|
||||
target.Width(EditorConstants::ShortcutTargetColumnWidth);
|
||||
row.Children().Append(target);
|
||||
|
||||
targetAppTextBox.Width(KeyboardManagerConstants::ShortcutTableDropDownWidth);
|
||||
targetAppTextBox.Width(EditorConstants::ShortcutTableDropDownWidth);
|
||||
targetAppTextBox.PlaceholderText(KeyboardManagerEditorStrings::DefaultAppName);
|
||||
targetAppTextBox.Text(targetAppName);
|
||||
|
||||
@ -174,10 +175,10 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
|
||||
});
|
||||
|
||||
// We need two containers in order to align it horizontally and vertically
|
||||
StackPanel targetAppHorizontal = UIHelpers::GetWrapped(targetAppTextBox, KeyboardManagerConstants::TableTargetAppColWidth).as<StackPanel>();
|
||||
StackPanel targetAppHorizontal = UIHelpers::GetWrapped(targetAppTextBox, EditorConstants::TableTargetAppColWidth).as<StackPanel>();
|
||||
targetAppHorizontal.Orientation(Orientation::Horizontal);
|
||||
targetAppHorizontal.HorizontalAlignment(HorizontalAlignment::Left);
|
||||
StackPanel targetAppContainer = UIHelpers::GetWrapped(targetAppHorizontal, KeyboardManagerConstants::TableTargetAppColWidth).as<StackPanel>();
|
||||
StackPanel targetAppContainer = UIHelpers::GetWrapped(targetAppHorizontal, EditorConstants::TableTargetAppColWidth).as<StackPanel>();
|
||||
targetAppContainer.Orientation(Orientation::Vertical);
|
||||
targetAppContainer.VerticalAlignment(VerticalAlignment::Bottom);
|
||||
row.Children().Append(targetAppContainer);
|
||||
@ -240,7 +241,7 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
|
||||
UpdateAccessibleNames(keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][0]->GetShortcutControl(), keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1]->GetShortcutControl(), targetAppTextBox, deleteShortcut, (int)keyboardRemapControlObjects.size());
|
||||
|
||||
// Set the shortcut text if the two vectors are not empty (i.e. default args)
|
||||
if (originalKeys.IsValidShortcut() && !(newKeys.index() == 0 && std::get<DWORD>(newKeys) == NULL) && !(newKeys.index() == 1 && !std::get<Shortcut>(newKeys).IsValidShortcut()))
|
||||
if (EditorHelpers::IsValidShortcut(originalKeys) && !(newKeys.index() == 0 && std::get<DWORD>(newKeys) == NULL) && !(newKeys.index() == 1 && !EditorHelpers::IsValidShortcut(std::get<Shortcut>(newKeys))))
|
||||
{
|
||||
// change to load app name
|
||||
shortcutRemapBuffer.push_back(std::make_pair<RemapBufferItem, std::wstring>(RemapBufferItem{ Shortcut(), Shortcut() }, std::wstring(targetAppName)));
|
||||
@ -269,7 +270,7 @@ StackPanel ShortcutControl::GetShortcutControl()
|
||||
}
|
||||
|
||||
// Function to create the detect shortcut UI window
|
||||
void ShortcutControl::CreateDetectShortcutWindow(winrt::Windows::Foundation::IInspectable const& sender, XamlRoot xamlRoot, KeyboardManagerState& keyboardManagerState, const int colIndex, StackPanel table, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects, StackPanel row, TextBox targetApp, bool isHybridControl, bool isSingleKeyWindow, HWND parentWindow, RemapBuffer& remapBuffer)
|
||||
void ShortcutControl::CreateDetectShortcutWindow(winrt::Windows::Foundation::IInspectable const& sender, XamlRoot xamlRoot, KBMEditor::KeyboardManagerState& keyboardManagerState, const int colIndex, StackPanel table, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects, StackPanel row, TextBox targetApp, bool isHybridControl, bool isSingleKeyWindow, HWND parentWindow, RemapBuffer& remapBuffer)
|
||||
{
|
||||
// ContentDialog for detecting shortcuts. This is the parent UI element.
|
||||
ContentDialog detectShortcutBox;
|
||||
@ -325,12 +326,12 @@ void ShortcutControl::CreateDetectShortcutWindow(winrt::Windows::Foundation::IIn
|
||||
if (isSingleKeyWindow)
|
||||
{
|
||||
// Revert UI state back to Edit Keyboard window
|
||||
keyboardManagerState.SetUIState(KeyboardManagerUIState::EditKeyboardWindowActivated, parentWindow);
|
||||
keyboardManagerState.SetUIState(KBMEditor::KeyboardManagerUIState::EditKeyboardWindowActivated, parentWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Revert UI state back to Edit Shortcut window
|
||||
keyboardManagerState.SetUIState(KeyboardManagerUIState::EditShortcutsWindowActivated, parentWindow);
|
||||
keyboardManagerState.SetUIState(KBMEditor::KeyboardManagerUIState::EditShortcutsWindowActivated, parentWindow);
|
||||
}
|
||||
|
||||
unregisterKeys();
|
||||
@ -391,12 +392,12 @@ void ShortcutControl::CreateDetectShortcutWindow(winrt::Windows::Foundation::IIn
|
||||
if (isSingleKeyWindow)
|
||||
{
|
||||
// Revert UI state back to Edit Keyboard window
|
||||
keyboardManagerState.SetUIState(KeyboardManagerUIState::EditKeyboardWindowActivated, parentWindow);
|
||||
keyboardManagerState.SetUIState(KBMEditor::KeyboardManagerUIState::EditKeyboardWindowActivated, parentWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Revert UI state back to Edit Shortcut window
|
||||
keyboardManagerState.SetUIState(KeyboardManagerUIState::EditShortcutsWindowActivated, parentWindow);
|
||||
keyboardManagerState.SetUIState(KBMEditor::KeyboardManagerUIState::EditShortcutsWindowActivated, parentWindow);
|
||||
}
|
||||
unregisterKeys();
|
||||
};
|
||||
|
@ -1,8 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <Shortcut.h>
|
||||
#include <keyboardmanager/common/Shortcut.h>
|
||||
|
||||
namespace KBMEditor
|
||||
{
|
||||
class KeyboardManagerState;
|
||||
}
|
||||
|
||||
class KeyboardManagerState;
|
||||
class KeyDropDownControl;
|
||||
namespace winrt::Windows::UI::Xaml
|
||||
{
|
||||
@ -38,7 +42,7 @@ public:
|
||||
static HWND editShortcutsWindowHandle;
|
||||
|
||||
// Pointer to the keyboard manager state
|
||||
static KeyboardManagerState* keyboardManagerState;
|
||||
static KBMEditor::KeyboardManagerState* keyboardManagerState;
|
||||
|
||||
// Stores the current list of remappings
|
||||
static RemapBuffer shortcutRemapBuffer;
|
||||
@ -56,5 +60,5 @@ public:
|
||||
StackPanel GetShortcutControl();
|
||||
|
||||
// Function to create the detect shortcut UI window
|
||||
static void CreateDetectShortcutWindow(winrt::Windows::Foundation::IInspectable const& sender, XamlRoot xamlRoot, KeyboardManagerState& keyboardManagerState, const int colIndex, StackPanel table, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects, StackPanel controlLayout, TextBox targetApp, bool isHybridControl, bool isSingleKeyWindow, HWND parentWindow, RemapBuffer& remapBuffer);
|
||||
static void CreateDetectShortcutWindow(winrt::Windows::Foundation::IInspectable const& sender, XamlRoot xamlRoot, KBMEditor::KeyboardManagerState& keyboardManagerState, const int colIndex, StackPanel table, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects, StackPanel controlLayout, TextBox targetApp, bool isHybridControl, bool isSingleKeyWindow, HWND parentWindow, RemapBuffer& remapBuffer);
|
||||
};
|
||||
|
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
// Type to store codes for different errors
|
||||
enum class ShortcutErrorType
|
||||
{
|
||||
NoError,
|
||||
SameKeyPreviouslyMapped,
|
||||
MapToSameKey,
|
||||
ConflictingModifierKey,
|
||||
SameShortcutPreviouslyMapped,
|
||||
MapToSameShortcut,
|
||||
ConflictingModifierShortcut,
|
||||
WinL,
|
||||
CtrlAltDel,
|
||||
RemapUnsuccessful,
|
||||
SaveFailed,
|
||||
ShortcutStartWithModifier,
|
||||
ShortcutCannotHaveRepeatedModifier,
|
||||
ShortcutAtleast2Keys,
|
||||
ShortcutOneActionKey,
|
||||
ShortcutNotMoreThanOneActionKey,
|
||||
ShortcutMaxShortcutSizeOneActionKey,
|
||||
ShortcutDisableAsActionKey
|
||||
};
|
@ -1,21 +1,22 @@
|
||||
#include "pch.h"
|
||||
#include "SingleKeyRemapControl.h"
|
||||
|
||||
#include <KeyboardManagerState.h>
|
||||
|
||||
#include <ShortcutControl.h>
|
||||
#include <UIHelpers.h>
|
||||
#include "KeyboardManagerState.h"
|
||||
#include "ShortcutControl.h"
|
||||
#include "UIHelpers.h"
|
||||
#include "EditorHelpers.h"
|
||||
#include "EditorConstants.h"
|
||||
|
||||
//Both static members are initialized to null
|
||||
HWND SingleKeyRemapControl::EditKeyboardWindowHandle = nullptr;
|
||||
KeyboardManagerState* SingleKeyRemapControl::keyboardManagerState = nullptr;
|
||||
KBMEditor::KeyboardManagerState* SingleKeyRemapControl::keyboardManagerState = nullptr;
|
||||
// Initialized as new vector
|
||||
RemapBuffer SingleKeyRemapControl::singleKeyRemapBuffer;
|
||||
|
||||
SingleKeyRemapControl::SingleKeyRemapControl(StackPanel table, StackPanel row, const int colIndex)
|
||||
{
|
||||
typeKey = Button();
|
||||
typeKey.as<Button>().Width(KeyboardManagerConstants::RemapTableDropDownWidth);
|
||||
typeKey.as<Button>().Width(EditorConstants::RemapTableDropDownWidth);
|
||||
typeKey.as<Button>().Content(winrt::box_value(GET_RESOURCE_STRING(IDS_TYPE_BUTTON)));
|
||||
|
||||
singleKeyRemapControlLayout = StackPanel();
|
||||
@ -35,7 +36,7 @@ SingleKeyRemapControl::SingleKeyRemapControl(StackPanel table, StackPanel row, c
|
||||
else
|
||||
{
|
||||
hybridDropDownStackPanel = StackPanel();
|
||||
hybridDropDownStackPanel.as<StackPanel>().Spacing(KeyboardManagerConstants::ShortcutTableDropDownSpacing);
|
||||
hybridDropDownStackPanel.as<StackPanel>().Spacing(EditorConstants::ShortcutTableDropDownSpacing);
|
||||
hybridDropDownStackPanel.as<StackPanel>().Orientation(Windows::UI::Xaml::Controls::Orientation::Horizontal);
|
||||
KeyDropDownControl::AddDropDown(table, row, hybridDropDownStackPanel.as<StackPanel>(), colIndex, singleKeyRemapBuffer, keyDropDownControlObjects, nullptr, true, true);
|
||||
singleKeyRemapControlLayout.as<StackPanel>().Children().Append(hybridDropDownStackPanel.as<StackPanel>());
|
||||
@ -45,12 +46,12 @@ SingleKeyRemapControl::SingleKeyRemapControl(StackPanel table, StackPanel row, c
|
||||
// Using the XamlRoot of the typeKey to get the root of the XAML host
|
||||
if (colIndex == 0)
|
||||
{
|
||||
keyboardManagerState->SetUIState(KeyboardManagerUIState::DetectSingleKeyRemapWindowActivated, EditKeyboardWindowHandle);
|
||||
keyboardManagerState->SetUIState(KBMEditor::KeyboardManagerUIState::DetectSingleKeyRemapWindowActivated, EditKeyboardWindowHandle);
|
||||
createDetectKeyWindow(sender, sender.as<Button>().XamlRoot(), *keyboardManagerState);
|
||||
}
|
||||
else
|
||||
{
|
||||
keyboardManagerState->SetUIState(KeyboardManagerUIState::DetectShortcutWindowInEditKeyboardWindowActivated, EditKeyboardWindowHandle);
|
||||
keyboardManagerState->SetUIState(KBMEditor::KeyboardManagerUIState::DetectShortcutWindowInEditKeyboardWindowActivated, EditKeyboardWindowHandle);
|
||||
ShortcutControl::CreateDetectShortcutWindow(sender, sender.as<Button>().XamlRoot(), *keyboardManagerState, colIndex, table, keyDropDownControlObjects, row, nullptr, true, true, EditKeyboardWindowHandle, singleKeyRemapBuffer);
|
||||
}
|
||||
});
|
||||
@ -87,7 +88,7 @@ void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, std::ve
|
||||
|
||||
// SingleKeyRemapControl for the original key.
|
||||
auto originalElement = keyboardRemapControlObjects.back()[0]->getSingleKeyRemapControl();
|
||||
originalElement.Width(KeyboardManagerConstants::RemapTableDropDownWidth);
|
||||
originalElement.Width(EditorConstants::RemapTableDropDownWidth);
|
||||
row.Children().Append(originalElement);
|
||||
|
||||
// Arrow icon
|
||||
@ -96,18 +97,18 @@ void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, std::ve
|
||||
arrowIcon.Glyph(L"\xE72A");
|
||||
arrowIcon.VerticalAlignment(VerticalAlignment::Center);
|
||||
arrowIcon.HorizontalAlignment(HorizontalAlignment::Center);
|
||||
auto arrowIconContainer = UIHelpers::GetWrapped(arrowIcon, KeyboardManagerConstants::TableArrowColWidth).as<StackPanel>();
|
||||
auto arrowIconContainer = UIHelpers::GetWrapped(arrowIcon, EditorConstants::TableArrowColWidth).as<StackPanel>();
|
||||
arrowIconContainer.Orientation(Orientation::Vertical);
|
||||
arrowIconContainer.VerticalAlignment(VerticalAlignment::Center);
|
||||
row.Children().Append(arrowIconContainer);
|
||||
|
||||
// SingleKeyRemapControl for the new remap key
|
||||
auto targetElement = keyboardRemapControlObjects.back()[1]->getSingleKeyRemapControl();
|
||||
targetElement.Width(KeyboardManagerConstants::ShortcutTargetColumnWidth);
|
||||
targetElement.Width(EditorConstants::ShortcutTargetColumnWidth);
|
||||
row.Children().Append(targetElement);
|
||||
|
||||
// Set the key text if the two keys are not null (i.e. default args)
|
||||
if (originalKey != NULL && !(newKey.index() == 0 && std::get<DWORD>(newKey) == NULL) && !(newKey.index() == 1 && !std::get<Shortcut>(newKey).IsValidShortcut()))
|
||||
if (originalKey != NULL && !(newKey.index() == 0 && std::get<DWORD>(newKey) == NULL) && !(newKey.index() == 1 && !EditorHelpers::IsValidShortcut(std::get<Shortcut>(newKey))))
|
||||
{
|
||||
singleKeyRemapBuffer.push_back(std::make_pair<RemapBufferItem, std::wstring>(RemapBufferItem{ originalKey, newKey }, L""));
|
||||
keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][0]->keyDropDownControlObjects[0]->SetSelectedValue(std::to_wstring(originalKey));
|
||||
@ -186,7 +187,7 @@ StackPanel SingleKeyRemapControl::getSingleKeyRemapControl()
|
||||
}
|
||||
|
||||
// Function to create the detect remap key UI window
|
||||
void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::IInspectable const& sender, XamlRoot xamlRoot, KeyboardManagerState& keyboardManagerState)
|
||||
void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::IInspectable const& sender, XamlRoot xamlRoot, KBMEditor::KeyboardManagerState& keyboardManagerState)
|
||||
{
|
||||
// ContentDialog for detecting remap key. This is the parent UI element.
|
||||
ContentDialog detectRemapKeyBox;
|
||||
@ -229,7 +230,7 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
|
||||
// Reset the keyboard manager UI state
|
||||
keyboardManagerState.ResetUIState();
|
||||
// Revert UI state back to Edit Keyboard window
|
||||
keyboardManagerState.SetUIState(KeyboardManagerUIState::EditKeyboardWindowActivated, EditKeyboardWindowHandle);
|
||||
keyboardManagerState.SetUIState(KBMEditor::KeyboardManagerUIState::EditKeyboardWindowActivated, EditKeyboardWindowHandle);
|
||||
unregisterKeys();
|
||||
};
|
||||
|
||||
@ -253,7 +254,7 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
|
||||
// NOTE: UnregisterKeys should never be called on the DelayThread, as it will re-enter the mutex. To avoid this it is run on the dispatcher thread
|
||||
keyboardManagerState.RegisterKeyDelay(
|
||||
VK_RETURN,
|
||||
std::bind(&KeyboardManagerState::SelectDetectedRemapKey, &keyboardManagerState, std::placeholders::_1),
|
||||
std::bind(&KBMEditor::KeyboardManagerState::SelectDetectedRemapKey, &keyboardManagerState, std::placeholders::_1),
|
||||
[primaryButton, onPressEnter, detectRemapKeyBox](DWORD) {
|
||||
detectRemapKeyBox.Dispatcher().RunAsync(
|
||||
Windows::UI::Core::CoreDispatcherPriority::Normal,
|
||||
@ -283,7 +284,7 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
|
||||
keyboardManagerState.ResetUIState();
|
||||
|
||||
// Revert UI state back to Edit Keyboard window
|
||||
keyboardManagerState.SetUIState(KeyboardManagerUIState::EditKeyboardWindowActivated, EditKeyboardWindowHandle);
|
||||
keyboardManagerState.SetUIState(KBMEditor::KeyboardManagerUIState::EditKeyboardWindowActivated, EditKeyboardWindowHandle);
|
||||
unregisterKeys();
|
||||
};
|
||||
|
||||
@ -300,7 +301,7 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
|
||||
// NOTE: UnregisterKeys should never be called on the DelayThread, as it will re-enter the mutex. To avoid this it is run on the dispatcher thread
|
||||
keyboardManagerState.RegisterKeyDelay(
|
||||
VK_ESCAPE,
|
||||
std::bind(&KeyboardManagerState::SelectDetectedRemapKey, &keyboardManagerState, std::placeholders::_1),
|
||||
std::bind(&KBMEditor::KeyboardManagerState::SelectDetectedRemapKey, &keyboardManagerState, std::placeholders::_1),
|
||||
[onCancel, detectRemapKeyBox](DWORD) {
|
||||
detectRemapKeyBox.Dispatcher().RunAsync(
|
||||
Windows::UI::Core::CoreDispatcherPriority::Normal,
|
||||
|
@ -1,10 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <Shortcut.h>
|
||||
#include <keyboardmanager/common/Shortcut.h>
|
||||
|
||||
#include <KeyDropDownControl.h>
|
||||
|
||||
class KeyboardManagerState;
|
||||
namespace KBMEditor
|
||||
{
|
||||
class KeyboardManagerState;
|
||||
}
|
||||
|
||||
namespace winrt::Windows::UI::Xaml
|
||||
{
|
||||
struct XamlRoot;
|
||||
@ -39,7 +43,7 @@ public:
|
||||
static HWND EditKeyboardWindowHandle;
|
||||
|
||||
// Pointer to the keyboard manager state
|
||||
static KeyboardManagerState* keyboardManagerState;
|
||||
static KBMEditor::KeyboardManagerState* keyboardManagerState;
|
||||
|
||||
// Stores the current list of remappings
|
||||
static RemapBuffer singleKeyRemapBuffer;
|
||||
@ -54,5 +58,5 @@ public:
|
||||
winrt::Windows::UI::Xaml::Controls::StackPanel getSingleKeyRemapControl();
|
||||
|
||||
// Function to create the detect remap keys UI window
|
||||
void createDetectKeyWindow(winrt::Windows::Foundation::IInspectable const& sender, XamlRoot xamlRoot, KeyboardManagerState& keyboardManagerState);
|
||||
void createDetectKeyWindow(winrt::Windows::Foundation::IInspectable const& sender, XamlRoot xamlRoot, KBMEditor::KeyboardManagerState& keyboardManagerState);
|
||||
};
|
||||
|
@ -1,14 +1,12 @@
|
||||
#include "pch.h"
|
||||
#include "CppUnitTest.h"
|
||||
#include <keyboardmanager/KeyboardManagerEditorLibrary/BufferValidationHelpers.h>
|
||||
#include "TestHelpers.h"
|
||||
#include <common/interop/keyboard_layout.h>
|
||||
#include <common/interop/shared_constants.h>
|
||||
#include <functional>
|
||||
#include <keyboardmanager/common/ErrorTypes.h>
|
||||
#include <keyboardmanager/KeyboardManagerEditorLibrary/ShortcutErrorType.h>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace TestHelpers;
|
||||
|
||||
namespace RemappingUITests
|
||||
{
|
||||
@ -61,10 +59,10 @@ namespace RemappingUITests
|
||||
|
||||
// Validate and update the element when -1 i.e. null selection is made on an empty row.
|
||||
ValidateAndUpdateKeyBufferElementArgs args = { 0, 0, -1 };
|
||||
KeyboardManagerHelper::ErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
ShortcutErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
|
||||
// Assert that the element is validated and buffer is updated
|
||||
Assert::AreEqual(true, error == KeyboardManagerHelper::ErrorType::NoError);
|
||||
Assert::AreEqual(true, error == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual((DWORD)NULL, std::get<DWORD>(remapBuffer[0].first[0]));
|
||||
Assert::AreEqual((DWORD)NULL, std::get<DWORD>(remapBuffer[0].first[1]));
|
||||
Assert::AreEqual((DWORD)NULL, std::get<DWORD>(remapBuffer[1].first[0]));
|
||||
@ -81,10 +79,10 @@ namespace RemappingUITests
|
||||
|
||||
// Validate and update the element when selecting B on an empty row
|
||||
ValidateAndUpdateKeyBufferElementArgs args = { 0, 0, 0x42 };
|
||||
KeyboardManagerHelper::ErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
ShortcutErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
|
||||
// Assert that the element is validated and buffer is updated
|
||||
Assert::AreEqual(true, error == KeyboardManagerHelper::ErrorType::NoError);
|
||||
Assert::AreEqual(true, error == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual((DWORD)0x42, std::get<DWORD>(remapBuffer[0].first[0]));
|
||||
Assert::AreEqual((DWORD)NULL, std::get<DWORD>(remapBuffer[0].first[1]));
|
||||
}
|
||||
@ -99,10 +97,10 @@ namespace RemappingUITests
|
||||
|
||||
// Validate and update the element when selecting B on a row
|
||||
ValidateAndUpdateKeyBufferElementArgs args = { 0, 0, 0x42 };
|
||||
KeyboardManagerHelper::ErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
ShortcutErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
|
||||
// Assert that the element is validated and buffer is updated
|
||||
Assert::AreEqual(true, error == KeyboardManagerHelper::ErrorType::NoError);
|
||||
Assert::AreEqual(true, error == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual((DWORD)0x42, std::get<DWORD>(remapBuffer[0].first[0]));
|
||||
Assert::AreEqual((DWORD)0x41, std::get<DWORD>(remapBuffer[0].first[1]));
|
||||
}
|
||||
@ -117,10 +115,10 @@ namespace RemappingUITests
|
||||
|
||||
// Validate and update the element when selecting B on a row
|
||||
ValidateAndUpdateKeyBufferElementArgs args = { 0, 0, 0x42 };
|
||||
KeyboardManagerHelper::ErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
ShortcutErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
|
||||
// Assert that the element is validated and buffer is updated
|
||||
Assert::AreEqual(true, error == KeyboardManagerHelper::ErrorType::NoError);
|
||||
Assert::AreEqual(true, error == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual((DWORD)0x42, std::get<DWORD>(remapBuffer[0].first[0]));
|
||||
Assert::AreEqual(true, Shortcut(std::vector<int32_t>{ VK_CONTROL, 0x41 }) == std::get<Shortcut>(remapBuffer[0].first[1]));
|
||||
}
|
||||
@ -135,10 +133,10 @@ namespace RemappingUITests
|
||||
|
||||
// Validate and update the element when selecting A on a row
|
||||
ValidateAndUpdateKeyBufferElementArgs args = { 0, 0, 0x41 };
|
||||
KeyboardManagerHelper::ErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
ShortcutErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
|
||||
// Assert that the element is invalid and buffer is not updated
|
||||
Assert::AreEqual(true, error == KeyboardManagerHelper::ErrorType::MapToSameKey);
|
||||
Assert::AreEqual(true, error == ShortcutErrorType::MapToSameKey);
|
||||
Assert::AreEqual((DWORD)NULL, std::get<DWORD>(remapBuffer[0].first[0]));
|
||||
Assert::AreEqual((DWORD)0x41, std::get<DWORD>(remapBuffer[0].first[1]));
|
||||
}
|
||||
@ -154,10 +152,10 @@ namespace RemappingUITests
|
||||
|
||||
// Validate and update the element when selecting A on second row
|
||||
ValidateAndUpdateKeyBufferElementArgs args = { 1, 0, 0x41 };
|
||||
KeyboardManagerHelper::ErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
ShortcutErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
|
||||
// Assert that the element is invalid and buffer is not updated
|
||||
Assert::AreEqual(true, error == KeyboardManagerHelper::ErrorType::SameKeyPreviouslyMapped);
|
||||
Assert::AreEqual(true, error == ShortcutErrorType::SameKeyPreviouslyMapped);
|
||||
Assert::AreEqual((DWORD)NULL, std::get<DWORD>(remapBuffer[1].first[0]));
|
||||
Assert::AreEqual((DWORD)0x43, std::get<DWORD>(remapBuffer[1].first[1]));
|
||||
}
|
||||
@ -173,10 +171,10 @@ namespace RemappingUITests
|
||||
|
||||
// Validate and update the element when selecting A on second row
|
||||
ValidateAndUpdateKeyBufferElementArgs args = { 1, 0, 0x41 };
|
||||
KeyboardManagerHelper::ErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
ShortcutErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
|
||||
// Assert that the element is invalid and buffer is not updated
|
||||
Assert::AreEqual(true, error == KeyboardManagerHelper::ErrorType::SameKeyPreviouslyMapped);
|
||||
Assert::AreEqual(true, error == ShortcutErrorType::SameKeyPreviouslyMapped);
|
||||
Assert::AreEqual((DWORD)NULL, std::get<DWORD>(remapBuffer[1].first[0]));
|
||||
Assert::AreEqual(true, Shortcut(std::vector<int32_t>{ VK_CONTROL, 0x41 }) == std::get<Shortcut>(remapBuffer[1].first[1]));
|
||||
}
|
||||
@ -192,10 +190,10 @@ namespace RemappingUITests
|
||||
|
||||
// Validate and update the element when selecting LCtrl on second row
|
||||
ValidateAndUpdateKeyBufferElementArgs args = { 1, 0, VK_LCONTROL };
|
||||
KeyboardManagerHelper::ErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
ShortcutErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
|
||||
// Assert that the element is invalid and buffer is not updated
|
||||
Assert::AreEqual(true, error == KeyboardManagerHelper::ErrorType::ConflictingModifierKey);
|
||||
Assert::AreEqual(true, error == ShortcutErrorType::ConflictingModifierKey);
|
||||
Assert::AreEqual((DWORD)NULL, std::get<DWORD>(remapBuffer[1].first[0]));
|
||||
Assert::AreEqual((DWORD)0x43, std::get<DWORD>(remapBuffer[1].first[1]));
|
||||
}
|
||||
@ -211,10 +209,10 @@ namespace RemappingUITests
|
||||
|
||||
// Validate and update the element when selecting LCtrl on second row
|
||||
ValidateAndUpdateKeyBufferElementArgs args = { 1, 0, VK_LCONTROL };
|
||||
KeyboardManagerHelper::ErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
ShortcutErrorType error = BufferValidationHelpers::ValidateAndUpdateKeyBufferElement(args.elementRowIndex, args.elementColIndex, args.selectedCodeFromDropDown, remapBuffer);
|
||||
|
||||
// Assert that the element is invalid and buffer is not updated
|
||||
Assert::AreEqual(true, error == KeyboardManagerHelper::ErrorType::ConflictingModifierKey);
|
||||
Assert::AreEqual(true, error == ShortcutErrorType::ConflictingModifierKey);
|
||||
Assert::AreEqual((DWORD)NULL, std::get<DWORD>(remapBuffer[1].first[0]));
|
||||
Assert::AreEqual(true, Shortcut(std::vector<int32_t>{ VK_CONTROL, 0x41 }) == std::get<Shortcut>(remapBuffer[1].first[1]));
|
||||
}
|
||||
@ -268,10 +266,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is valid and no drop down action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::NoError);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
});
|
||||
}
|
||||
@ -295,10 +293,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid and no drop down action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::ShortcutStartWithModifier);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::ShortcutStartWithModifier);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
});
|
||||
}
|
||||
@ -318,10 +316,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is valid and no drop down action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::NoError);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
});
|
||||
}
|
||||
@ -341,10 +339,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid and no drop down action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::ShortcutNotMoreThanOneActionKey);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::ShortcutNotMoreThanOneActionKey);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
});
|
||||
}
|
||||
@ -364,10 +362,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid and no drop down action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::ShortcutNotMoreThanOneActionKey);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::ShortcutNotMoreThanOneActionKey);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
});
|
||||
}
|
||||
@ -395,10 +393,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is valid and no drop down action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::NoError);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
});
|
||||
}
|
||||
@ -426,10 +424,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is valid and ClearUnusedDropDowns action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::NoError);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::ClearUnusedDropDowns);
|
||||
});
|
||||
}
|
||||
@ -447,10 +445,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is valid and ClearUnusedDropDowns action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::NoError);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::ClearUnusedDropDowns);
|
||||
});
|
||||
}
|
||||
@ -482,10 +480,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is valid and AddDropDown action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::NoError);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::AddDropDown);
|
||||
});
|
||||
}
|
||||
@ -509,10 +507,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid and no action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::ShortcutCannotHaveRepeatedModifier);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::ShortcutCannotHaveRepeatedModifier);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
});
|
||||
}
|
||||
@ -546,10 +544,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid and no action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::ShortcutMaxShortcutSizeOneActionKey);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::ShortcutMaxShortcutSizeOneActionKey);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
});
|
||||
}
|
||||
@ -577,10 +575,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid and no action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::ShortcutMaxShortcutSizeOneActionKey);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::ShortcutMaxShortcutSizeOneActionKey);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
});
|
||||
}
|
||||
@ -614,10 +612,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is valid and no action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::NoError);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
});
|
||||
}
|
||||
@ -651,10 +649,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid and no action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::ShortcutCannotHaveRepeatedModifier);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::ShortcutCannotHaveRepeatedModifier);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
});
|
||||
}
|
||||
@ -674,10 +672,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid and no action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::ShortcutStartWithModifier);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::ShortcutStartWithModifier);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
});
|
||||
}
|
||||
@ -695,10 +693,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid and no action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::ShortcutOneActionKey);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::ShortcutOneActionKey);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
});
|
||||
}
|
||||
@ -722,10 +720,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid and no action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::ShortcutAtleast2Keys);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::ShortcutAtleast2Keys);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
});
|
||||
}
|
||||
@ -749,10 +747,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid and no action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::ShortcutOneActionKey);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::ShortcutOneActionKey);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
});
|
||||
}
|
||||
@ -776,10 +774,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is valid and DeleteDropDown action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::NoError);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::DeleteDropDown);
|
||||
});
|
||||
}
|
||||
@ -819,10 +817,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is valid and DeleteDropDown action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::NoError);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::DeleteDropDown);
|
||||
});
|
||||
}
|
||||
@ -850,10 +848,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid and no action is required
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::ShortcutOneActionKey);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::ShortcutOneActionKey);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
});
|
||||
}
|
||||
@ -889,10 +887,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::WinL);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::WinL);
|
||||
});
|
||||
}
|
||||
|
||||
@ -921,10 +919,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::WinL);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::WinL);
|
||||
});
|
||||
}
|
||||
|
||||
@ -953,10 +951,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::CtrlAltDel);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::CtrlAltDel);
|
||||
});
|
||||
}
|
||||
|
||||
@ -987,10 +985,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::MapToSameKey);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::MapToSameKey);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1025,10 +1023,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::MapToSameShortcut);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::MapToSameShortcut);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1103,10 +1101,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::MapToSameShortcut);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::MapToSameShortcut);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1129,10 +1127,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::SameShortcutPreviouslyMapped);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::SameShortcutPreviouslyMapped);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1157,10 +1155,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is valid
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::NoError);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::NoError);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1183,10 +1181,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::ConflictingModifierShortcut);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::ConflictingModifierShortcut);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1209,10 +1207,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is valid
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::NoError);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::NoError);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1249,10 +1247,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::SameShortcutPreviouslyMapped);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::SameShortcutPreviouslyMapped);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1289,10 +1287,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is valid
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::NoError);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::NoError);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1329,10 +1327,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is invalid
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::ConflictingModifierShortcut);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::ConflictingModifierShortcut);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1369,10 +1367,10 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(testCase.bufferRow);
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(testCase.elementRowIndex, testCase.elementColIndex, testCase.indexOfDropDownLastModified, testCase.selectedCodesOnDropDowns, testCase.targetAppNameInTextBox, testCase.isHybridColumn, remapBuffer, true);
|
||||
|
||||
// Assert that the element is valid
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::NoError);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::NoError);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1388,10 +1386,10 @@ namespace RemappingUITests
|
||||
};
|
||||
|
||||
// Act
|
||||
std::pair<KeyboardManagerHelper::ErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(0, 1, 1, selectedCodes, testApp1, true, remapBuffer, true);
|
||||
std::pair<ShortcutErrorType, BufferValidationHelpers::DropDownAction> result = BufferValidationHelpers::ValidateShortcutBufferElement(0, 1, 1, selectedCodes, testApp1, true, remapBuffer, true);
|
||||
|
||||
// Assert
|
||||
Assert::AreEqual(true, result.first == KeyboardManagerHelper::ErrorType::ShortcutDisableAsActionKey);
|
||||
Assert::AreEqual(true, result.first == ShortcutErrorType::ShortcutDisableAsActionKey);
|
||||
Assert::AreEqual(true, result.second == BufferValidationHelpers::DropDownAction::NoAction);
|
||||
}
|
||||
};
|
||||
|
@ -0,0 +1,295 @@
|
||||
#include "pch.h"
|
||||
#include "CppUnitTest.h"
|
||||
#include <keyboardmanager/KeyboardManagerEditorLibrary/ShortcutErrorType.h>
|
||||
#include <keyboardmanager/common/Helpers.h>
|
||||
#include <common/interop/keyboard_layout.h>
|
||||
#include <keyboardmanager/KeyboardManagerEditorLibrary/EditorHelpers.h>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
|
||||
namespace EditorHelpersTests
|
||||
{
|
||||
TEST_CLASS (EditorHelpersTests)
|
||||
{
|
||||
public:
|
||||
// Test if the DoKeysOverlap method returns SameKeyPreviouslyMapped on passing the same key for both arguments
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnSameKeyPreviouslyMapped_OnPassingSameKeyForBothArguments)
|
||||
{
|
||||
// Arrange
|
||||
DWORD key1 = 0x41;
|
||||
DWORD key2 = key1;
|
||||
|
||||
// Act
|
||||
auto result = EditorHelpers::DoKeysOverlap(key1, key2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == ShortcutErrorType::SameKeyPreviouslyMapped);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns ConflictingModifierKey on passing left modifier and common modifier
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnConflictingModifierKey_OnPassingLeftModifierAndCommonModifierOfSameType)
|
||||
{
|
||||
// Arrange
|
||||
DWORD key1 = VK_LCONTROL;
|
||||
DWORD key2 = VK_CONTROL;
|
||||
|
||||
// Act
|
||||
auto result = EditorHelpers::DoKeysOverlap(key1, key2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == ShortcutErrorType::ConflictingModifierKey);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns ConflictingModifierKey on passing right modifier and common modifier
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnConflictingModifierKey_OnPassingRightModifierAndCommonModifierOfSameType)
|
||||
{
|
||||
// Arrange
|
||||
DWORD key1 = VK_RCONTROL;
|
||||
DWORD key2 = VK_CONTROL;
|
||||
|
||||
// Act
|
||||
auto result = EditorHelpers::DoKeysOverlap(key1, key2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == ShortcutErrorType::ConflictingModifierKey);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns NoError on passing left modifier and right modifier
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnNoError_OnPassingLeftModifierAndRightModifierOfSameType)
|
||||
{
|
||||
// Arrange
|
||||
DWORD key1 = VK_LCONTROL;
|
||||
DWORD key2 = VK_RCONTROL;
|
||||
|
||||
// Act
|
||||
auto result = EditorHelpers::DoKeysOverlap(key1, key2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == ShortcutErrorType::NoError);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns NoError on passing keys of different types
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnNoError_OnPassingKeysOfDifferentTypes)
|
||||
{
|
||||
// Arrange
|
||||
DWORD key1 = VK_CONTROL;
|
||||
DWORD key2 = VK_SHIFT;
|
||||
|
||||
// Act
|
||||
auto result = EditorHelpers::DoKeysOverlap(key1, key2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == ShortcutErrorType::NoError);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns NoError on passing different action keys
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnNoError_OnPassingDifferentActionKeys)
|
||||
{
|
||||
// Arrange
|
||||
DWORD key1 = 0x41;
|
||||
DWORD key2 = 0x42;
|
||||
|
||||
// Act
|
||||
auto result = EditorHelpers::DoKeysOverlap(key1, key2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == ShortcutErrorType::NoError);
|
||||
}
|
||||
|
||||
// Test if the CheckRepeatedModifier method returns true on passing vector with same modifier repeated
|
||||
TEST_METHOD (CheckRepeatedModifier_ShouldReturnTrue_OnPassingSameModifierRepeated)
|
||||
{
|
||||
// Arrange
|
||||
std::vector<int32_t> keys = { VK_CONTROL, VK_CONTROL, 0x41 };
|
||||
|
||||
// Act
|
||||
bool result = EditorHelpers::CheckRepeatedModifier(keys, VK_CONTROL);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result);
|
||||
}
|
||||
|
||||
// Test if the CheckRepeatedModifier method returns true on passing vector with conflicting modifier repeated
|
||||
TEST_METHOD (CheckRepeatedModifier_ShouldReturnTrue_OnPassingConflictingModifierRepeated)
|
||||
{
|
||||
// Arrange
|
||||
std::vector<int32_t> keys = { VK_CONTROL, VK_LCONTROL, 0x41 };
|
||||
|
||||
// Act
|
||||
bool result = EditorHelpers::CheckRepeatedModifier(keys, VK_LCONTROL);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result);
|
||||
}
|
||||
|
||||
// Test if the CheckRepeatedModifier method returns false on passing vector with different modifiers
|
||||
TEST_METHOD (CheckRepeatedModifier_ShouldReturnFalse_OnPassingDifferentModifiers)
|
||||
{
|
||||
// Arrange
|
||||
std::vector<int32_t> keys = { VK_CONTROL, VK_SHIFT, 0x41 };
|
||||
|
||||
// Act
|
||||
bool result = EditorHelpers::CheckRepeatedModifier(keys, VK_SHIFT);
|
||||
|
||||
// Assert
|
||||
Assert::IsFalse(result);
|
||||
}
|
||||
|
||||
|
||||
// Test if the IsValidShortcut method returns false on passing shortcut with null action key
|
||||
TEST_METHOD (IsValidShortcut_ShouldReturnFalse_OnPassingShortcutWithNullActionKey)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s;
|
||||
s.SetKey(NULL);
|
||||
|
||||
// Act
|
||||
bool result = EditorHelpers::IsValidShortcut(s);
|
||||
|
||||
// Assert
|
||||
Assert::IsFalse(result);
|
||||
}
|
||||
|
||||
// Test if the IsValidShortcut method returns false on passing shortcut with only action key
|
||||
TEST_METHOD (IsValidShortcut_ShouldReturnFalse_OnPassingShortcutWithOnlyActionKey)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s;
|
||||
s.SetKey(0x41);
|
||||
|
||||
// Act
|
||||
bool result = EditorHelpers::IsValidShortcut(s);
|
||||
|
||||
// Assert
|
||||
Assert::IsFalse(result);
|
||||
}
|
||||
|
||||
// Test if the IsValidShortcut method returns false on passing shortcut with only modifier keys
|
||||
TEST_METHOD (IsValidShortcut_ShouldReturnFalse_OnPassingShortcutWithOnlyModifierKeys)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s;
|
||||
s.SetKey(VK_CONTROL);
|
||||
s.SetKey(VK_SHIFT);
|
||||
|
||||
// Act
|
||||
bool result = EditorHelpers::IsValidShortcut(s);
|
||||
|
||||
// Assert
|
||||
Assert::IsFalse(result);
|
||||
}
|
||||
|
||||
// Test if the IsValidShortcut method returns true on passing shortcut with modifier and action key
|
||||
TEST_METHOD (IsValidShortcut_ShouldReturnFalse_OnPassingShortcutWithModifierAndActionKey)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s;
|
||||
s.SetKey(VK_CONTROL);
|
||||
s.SetKey(0x41);
|
||||
|
||||
// Act
|
||||
bool result = EditorHelpers::IsValidShortcut(s);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns NoError on passing invalid shortcut for one of the arguments
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnNoError_OnPassingInvalidShortcutForOneOfTheArguments)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s1(std::vector<int32_t>{ NULL });
|
||||
Shortcut s2(std::vector<int32_t>{ VK_CONTROL, 0x41 });
|
||||
|
||||
// Act
|
||||
auto result = EditorHelpers::DoShortcutsOverlap(s1, s2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == ShortcutErrorType::NoError);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns SameShortcutPreviouslyMapped on passing same shortcut for both arguments
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnSameShortcutPreviouslyMapped_OnPassingSameShortcutForBothArguments)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s1(std::vector<int32_t>{ VK_CONTROL, 0x41 });
|
||||
Shortcut s2 = s1;
|
||||
|
||||
// Act
|
||||
auto result = EditorHelpers::DoShortcutsOverlap(s1, s2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == ShortcutErrorType::SameShortcutPreviouslyMapped);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns NoError on passing shortcuts with different action keys
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnNoError_OnPassingShortcutsWithDifferentActionKeys)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s1(std::vector<int32_t>{ VK_CONTROL, 0x42 });
|
||||
Shortcut s2(std::vector<int32_t>{ VK_CONTROL, 0x41 });
|
||||
|
||||
// Act
|
||||
auto result = EditorHelpers::DoShortcutsOverlap(s1, s2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == ShortcutErrorType::NoError);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns NoError on passing shortcuts with different modifiers
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnNoError_OnPassingShortcutsWithDifferentModifiers)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s1(std::vector<int32_t>{ VK_CONTROL, 0x42 });
|
||||
Shortcut s2(std::vector<int32_t>{ VK_SHIFT, 0x42 });
|
||||
|
||||
// Act
|
||||
auto result = EditorHelpers::DoShortcutsOverlap(s1, s2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == ShortcutErrorType::NoError);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns ConflictingModifierShortcut on passing shortcuts with left modifier and common modifier
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnConflictingModifierShortcut_OnPassingShortcutsWithLeftModifierAndCommonModifierOfSameType)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s1(std::vector<int32_t>{ VK_LCONTROL, 0x42 });
|
||||
Shortcut s2(std::vector<int32_t>{ VK_CONTROL, 0x42 });
|
||||
|
||||
// Act
|
||||
auto result = EditorHelpers::DoShortcutsOverlap(s1, s2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == ShortcutErrorType::ConflictingModifierShortcut);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns ConflictingModifierShortcut on passing shortcuts with right modifier and common modifier
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnConflictingModifierShortcut_OnPassingShortcutsWithRightModifierAndCommonModifierOfSameType)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s1(std::vector<int32_t>{ VK_RCONTROL, 0x42 });
|
||||
Shortcut s2(std::vector<int32_t>{ VK_CONTROL, 0x42 });
|
||||
|
||||
// Act
|
||||
auto result = EditorHelpers::DoShortcutsOverlap(s1, s2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == ShortcutErrorType::ConflictingModifierShortcut);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns ConflictingModifierShortcut on passing shortcuts with left modifier and right modifier
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnConflictingModifierShortcut_OnPassingShortcutsWithLeftModifierAndRightModifierOfSameType)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s1(std::vector<int32_t>{ VK_LCONTROL, 0x42 });
|
||||
Shortcut s2(std::vector<int32_t>{ VK_RCONTROL, 0x42 });
|
||||
|
||||
// Act
|
||||
auto result = EditorHelpers::DoShortcutsOverlap(s1, s2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == ShortcutErrorType::NoError);
|
||||
}
|
||||
};
|
||||
}
|
@ -40,17 +40,14 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="BufferValidationTests.cpp" />
|
||||
<ClCompile Include="LoadingAndSavingRemappingTests.cpp" />
|
||||
<ClCompile Include="MockedInput.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TestHelpers.cpp" />
|
||||
<ClCompile Include="EditorHelpersTests.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="MockedInput.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="TestHelpers.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SetttingsAPI.vcxproj">
|
||||
|
@ -24,10 +24,7 @@
|
||||
<ClCompile Include="BufferValidationTests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TestHelpers.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MockedInput.cpp">
|
||||
<ClCompile Include="EditorHelpersTests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
@ -35,15 +32,9 @@
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MockedInput.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TestHelpers.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="KeyboardManagerEditorTest.rc">
|
||||
|
@ -1,10 +1,9 @@
|
||||
#include "pch.h"
|
||||
#include "CppUnitTest.h"
|
||||
#include <keyboardmanager/common/KeyboardManagerState.h>
|
||||
#include <keyboardmanager/common/MappingConfiguration.h>
|
||||
#include <keyboardmanager/KeyboardManagerEditorLibrary/LoadingAndSavingRemappingHelper.h>
|
||||
#include "TestHelpers.h"
|
||||
#include <common/interop/shared_constants.h>
|
||||
#include <keyboardmanager/common/ErrorTypes.h>
|
||||
#include <keyboardmanager/KeyboardManagerEditorLibrary/ShortcutErrorType.h>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
|
||||
@ -27,7 +26,7 @@ namespace RemappingUITests
|
||||
RemapBuffer remapBuffer;
|
||||
|
||||
// Assert that remapping set is valid
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == KeyboardManagerHelper::ErrorType::NoError);
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual(true, isSuccess);
|
||||
}
|
||||
|
||||
@ -41,7 +40,7 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(std::make_pair(RemapBufferItem({ 0x42, 0x43 }), std::wstring()));
|
||||
|
||||
// Assert that remapping set is valid
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == KeyboardManagerHelper::ErrorType::NoError);
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual(true, isSuccess);
|
||||
}
|
||||
|
||||
@ -61,7 +60,7 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(std::make_pair(RemapBufferItem({ 0x42, s2 }), std::wstring()));
|
||||
|
||||
// Assert that remapping set is valid
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == KeyboardManagerHelper::ErrorType::NoError);
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual(true, isSuccess);
|
||||
}
|
||||
|
||||
@ -81,7 +80,7 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(std::make_pair(RemapBufferItem({ s2, 0x42 }), std::wstring()));
|
||||
|
||||
// Assert that remapping set is valid
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == KeyboardManagerHelper::ErrorType::NoError);
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual(true, isSuccess);
|
||||
}
|
||||
|
||||
@ -107,7 +106,7 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(std::make_pair(RemapBufferItem({ src2, dest2 }), std::wstring()));
|
||||
|
||||
// Assert that remapping set is valid
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == KeyboardManagerHelper::ErrorType::NoError);
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual(true, isSuccess);
|
||||
}
|
||||
|
||||
@ -135,7 +134,7 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(std::make_pair(RemapBufferItem({ 0x42, dest2 }), std::wstring()));
|
||||
|
||||
// Assert that remapping set is valid
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == KeyboardManagerHelper::ErrorType::NoError);
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual(true, isSuccess);
|
||||
}
|
||||
|
||||
@ -148,7 +147,7 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(std::make_pair(RemapBufferItem({ 0x41, NULL }), std::wstring()));
|
||||
|
||||
// Assert that remapping set is invalid
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == KeyboardManagerHelper::ErrorType::RemapUnsuccessful);
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == ShortcutErrorType::RemapUnsuccessful);
|
||||
Assert::AreEqual(true, isSuccess);
|
||||
}
|
||||
|
||||
@ -163,7 +162,7 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(std::make_pair(RemapBufferItem({ 0x41, src1 }), std::wstring()));
|
||||
|
||||
// Assert that remapping set is invalid
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == KeyboardManagerHelper::ErrorType::RemapUnsuccessful);
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == ShortcutErrorType::RemapUnsuccessful);
|
||||
Assert::AreEqual(true, isSuccess);
|
||||
}
|
||||
|
||||
@ -180,7 +179,7 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(std::make_pair(RemapBufferItem({ 0x41, src1 }), std::wstring()));
|
||||
|
||||
// Assert that remapping set is invalid
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == KeyboardManagerHelper::ErrorType::RemapUnsuccessful);
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == ShortcutErrorType::RemapUnsuccessful);
|
||||
Assert::AreEqual(true, isSuccess);
|
||||
}
|
||||
|
||||
@ -200,7 +199,7 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(std::make_pair(RemapBufferItem({ src1, dest1 }), std::wstring()));
|
||||
|
||||
// Assert that remapping set is invalid
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == KeyboardManagerHelper::ErrorType::RemapUnsuccessful);
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == ShortcutErrorType::RemapUnsuccessful);
|
||||
Assert::AreEqual(true, isSuccess);
|
||||
}
|
||||
|
||||
@ -220,7 +219,7 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(std::make_pair(RemapBufferItem({ src1, dest1 }), testApp1));
|
||||
|
||||
// Assert that remapping set is invalid
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == KeyboardManagerHelper::ErrorType::RemapUnsuccessful);
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == ShortcutErrorType::RemapUnsuccessful);
|
||||
Assert::AreEqual(true, isSuccess);
|
||||
}
|
||||
|
||||
@ -240,7 +239,7 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(std::make_pair(RemapBufferItem({ src1, dest1 }), testApp2));
|
||||
|
||||
// Assert that remapping set is valid
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == KeyboardManagerHelper::ErrorType::NoError);
|
||||
bool isSuccess = (LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer) == ShortcutErrorType::NoError);
|
||||
Assert::AreEqual(true, isSuccess);
|
||||
}
|
||||
|
||||
@ -361,23 +360,23 @@ namespace RemappingUITests
|
||||
// Test if the ApplySingleKeyRemappings method resets the keyboard manager state's single key remappings on passing an empty buffer
|
||||
TEST_METHOD (ApplySingleKeyRemappings_ShouldResetSingleKeyRemappings_OnPassingEmptyBuffer)
|
||||
{
|
||||
KeyboardManagerState testState;
|
||||
MappingConfiguration testShortcuts;
|
||||
RemapBuffer remapBuffer;
|
||||
|
||||
// Remap A to B
|
||||
testState.AddSingleKeyRemap(0x41, 0x42);
|
||||
testShortcuts.AddSingleKeyRemap(0x41, 0x42);
|
||||
|
||||
// Apply the single key remaps from the buffer to the keyboard manager state variable
|
||||
LoadingAndSavingRemappingHelper::ApplySingleKeyRemappings(testState, remapBuffer, false);
|
||||
LoadingAndSavingRemappingHelper::ApplySingleKeyRemappings(testShortcuts, remapBuffer, false);
|
||||
|
||||
// Assert that single key remapping in the kbm state variable is empty
|
||||
Assert::AreEqual((size_t)0, testState.singleKeyReMap.size());
|
||||
Assert::AreEqual((size_t)0, testShortcuts.singleKeyReMap.size());
|
||||
}
|
||||
|
||||
// Test if the ApplySingleKeyRemappings method copies only the valid remappings to the keyboard manager state variable when some of the remappings are invalid
|
||||
TEST_METHOD (ApplySingleKeyRemappings_ShouldCopyOnlyValidRemappings_OnPassingBufferWithSomeInvalidRemappings)
|
||||
{
|
||||
KeyboardManagerState testState;
|
||||
MappingConfiguration testShortcuts;
|
||||
RemapBuffer remapBuffer;
|
||||
|
||||
// Add A->B, B->Ctrl+V, C to incomplete shortcut and D to incomplete key remappings to the buffer
|
||||
@ -392,21 +391,21 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(std::make_pair(RemapBufferItem({ 0x44, s2 }), std::wstring()));
|
||||
|
||||
// Apply the single key remaps from the buffer to the keyboard manager state variable
|
||||
LoadingAndSavingRemappingHelper::ApplySingleKeyRemappings(testState, remapBuffer, false);
|
||||
LoadingAndSavingRemappingHelper::ApplySingleKeyRemappings(testShortcuts, remapBuffer, false);
|
||||
|
||||
// Expected A remapped to B, B remapped to Ctrl+V
|
||||
SingleKeyRemapTable expectedTable;
|
||||
expectedTable[0x41] = 0x42;
|
||||
expectedTable[0x42] = s1;
|
||||
|
||||
bool areTablesEqual = (expectedTable == testState.singleKeyReMap);
|
||||
bool areTablesEqual = (expectedTable == testShortcuts.singleKeyReMap);
|
||||
Assert::AreEqual(true, areTablesEqual);
|
||||
}
|
||||
|
||||
// Test if the ApplySingleKeyRemappings method splits common modifiers to their left and right version when copying to the keyboard manager state variable if remappings from common modifiers are passed
|
||||
TEST_METHOD (ApplySingleKeyRemappings_ShouldSplitRemappingsFromCommonModifiers_OnPassingBufferWithSomeMappingsFromCommonModifiers)
|
||||
{
|
||||
KeyboardManagerState testState;
|
||||
MappingConfiguration testShortcuts;
|
||||
RemapBuffer remapBuffer;
|
||||
|
||||
// Add Ctrl->A, Alt->B, Shift->C and Win->D remappings to the buffer
|
||||
@ -416,7 +415,7 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(std::make_pair(RemapBufferItem({ CommonSharedConstants::VK_WIN_BOTH, 0x44 }), std::wstring()));
|
||||
|
||||
// Apply the single key remaps from the buffer to the keyboard manager state variable
|
||||
LoadingAndSavingRemappingHelper::ApplySingleKeyRemappings(testState, remapBuffer, false);
|
||||
LoadingAndSavingRemappingHelper::ApplySingleKeyRemappings(testShortcuts, remapBuffer, false);
|
||||
|
||||
// Expected LCtrl/RCtrl remapped to A, LAlt/RAlt to B, LShift/RShift to C, LWin/RWin to D
|
||||
SingleKeyRemapTable expectedTable;
|
||||
@ -429,14 +428,14 @@ namespace RemappingUITests
|
||||
expectedTable[VK_LWIN] = 0x44;
|
||||
expectedTable[VK_RWIN] = 0x44;
|
||||
|
||||
bool areTablesEqual = (expectedTable == testState.singleKeyReMap);
|
||||
bool areTablesEqual = (expectedTable == testShortcuts.singleKeyReMap);
|
||||
Assert::AreEqual(true, areTablesEqual);
|
||||
}
|
||||
|
||||
// Test if the ApplyShortcutRemappings method resets the keyboard manager state's os level and app specific shortcut remappings on passing an empty buffer
|
||||
TEST_METHOD (ApplyShortcutRemappings_ShouldResetShortcutRemappings_OnPassingEmptyBuffer)
|
||||
{
|
||||
KeyboardManagerState testState;
|
||||
MappingConfiguration testShortcuts;
|
||||
RemapBuffer remapBuffer;
|
||||
|
||||
// Remap Ctrl+A to Ctrl+B for all apps and Ctrl+C to Alt+V for testApp1
|
||||
@ -452,21 +451,21 @@ namespace RemappingUITests
|
||||
Shortcut dest2;
|
||||
dest2.SetKey(VK_MENU);
|
||||
dest2.SetKey(0x56);
|
||||
testState.AddOSLevelShortcut(src1, dest1);
|
||||
testState.AddAppSpecificShortcut(testApp1, src1, dest1);
|
||||
testShortcuts.AddOSLevelShortcut(src1, dest1);
|
||||
testShortcuts.AddAppSpecificShortcut(testApp1, src1, dest1);
|
||||
|
||||
// Apply the shortcut remaps from the buffer to the keyboard manager state variable
|
||||
LoadingAndSavingRemappingHelper::ApplyShortcutRemappings(testState, remapBuffer, false);
|
||||
LoadingAndSavingRemappingHelper::ApplyShortcutRemappings(testShortcuts, remapBuffer, false);
|
||||
|
||||
// Assert that shortcut remappings in the kbm state variable is empty
|
||||
Assert::AreEqual((size_t)0, testState.osLevelShortcutReMap.size());
|
||||
Assert::AreEqual((size_t)0, testState.appSpecificShortcutReMap.size());
|
||||
Assert::AreEqual((size_t)0, testShortcuts.osLevelShortcutReMap.size());
|
||||
Assert::AreEqual((size_t)0, testShortcuts.appSpecificShortcutReMap.size());
|
||||
}
|
||||
|
||||
// Test if the ApplyShortcutRemappings method copies only the valid remappings to the keyboard manager state variable when some of the remappings are invalid
|
||||
TEST_METHOD (ApplyShortcutRemappings_ShouldCopyOnlyValidRemappings_OnPassingBufferWithSomeInvalidRemappings)
|
||||
{
|
||||
KeyboardManagerState testState;
|
||||
MappingConfiguration testShortcuts;
|
||||
RemapBuffer remapBuffer;
|
||||
|
||||
// Add Ctrl+A->Ctrl+B, Ctrl+C->Alt+V, Ctrl+F->incomplete shortcut and Ctrl+G->incomplete key os level remappings to buffer
|
||||
@ -501,7 +500,7 @@ namespace RemappingUITests
|
||||
remapBuffer.push_back(std::make_pair(RemapBufferItem({ src2, dest4 }), testApp1));
|
||||
|
||||
// Apply the shortcut remaps from the buffer to the keyboard manager state variable
|
||||
LoadingAndSavingRemappingHelper::ApplyShortcutRemappings(testState, remapBuffer, false);
|
||||
LoadingAndSavingRemappingHelper::ApplyShortcutRemappings(testShortcuts, remapBuffer, false);
|
||||
|
||||
// Ctrl+A->Ctrl+B and Ctrl+C->Alt+V
|
||||
ShortcutRemapTable expectedOSLevelTable;
|
||||
@ -513,8 +512,8 @@ namespace RemappingUITests
|
||||
expectedAppSpecificLevelTable[testApp1][src3] = RemapShortcut(dest2);
|
||||
expectedAppSpecificLevelTable[testApp1][src4] = RemapShortcut(dest1);
|
||||
|
||||
bool areOSLevelTablesEqual = (expectedOSLevelTable == testState.osLevelShortcutReMap);
|
||||
bool areAppSpecificTablesEqual = (expectedAppSpecificLevelTable == testState.appSpecificShortcutReMap);
|
||||
bool areOSLevelTablesEqual = (expectedOSLevelTable == testShortcuts.osLevelShortcutReMap);
|
||||
bool areAppSpecificTablesEqual = (expectedAppSpecificLevelTable == testShortcuts.appSpecificShortcutReMap);
|
||||
Assert::AreEqual(true, areOSLevelTablesEqual);
|
||||
Assert::AreEqual(true, areAppSpecificTablesEqual);
|
||||
}
|
||||
|
@ -1,161 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "MockedInput.h"
|
||||
|
||||
// Set the keyboard hook procedure to be tested
|
||||
void MockedInput::SetHookProc(std::function<intptr_t(LowlevelKeyboardEvent*)> hookProcedure)
|
||||
{
|
||||
hookProc = hookProcedure;
|
||||
}
|
||||
|
||||
// Function to simulate keyboard input - arguments and return value based on SendInput function (https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput)
|
||||
UINT MockedInput::SendVirtualInput(UINT cInputs, LPINPUT pInputs, int cbSize)
|
||||
{
|
||||
// Iterate over inputs
|
||||
for (UINT i = 0; i < cInputs; i++)
|
||||
{
|
||||
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://docs.microsoft.com/en-us/windows/win32/inputdev/wm-syskeydown
|
||||
if (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP)
|
||||
{
|
||||
if (keyboardState[VK_MENU] == true)
|
||||
{
|
||||
keyEvent.wParam = WM_SYSKEYUP;
|
||||
}
|
||||
else
|
||||
{
|
||||
keyEvent.wParam = WM_KEYUP;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pInputs[i].ki.wVk == VK_F10 || keyboardState[VK_MENU] == true)
|
||||
{
|
||||
keyEvent.wParam = WM_SYSKEYDOWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
keyEvent.wParam = WM_KEYDOWN;
|
||||
}
|
||||
}
|
||||
KBDLLHOOKSTRUCT lParam = {};
|
||||
|
||||
// Set only vkCode and dwExtraInfo since other values are unused
|
||||
lParam.vkCode = pInputs[i].ki.wVk;
|
||||
lParam.dwExtraInfo = pInputs[i].ki.dwExtraInfo;
|
||||
keyEvent.lParam = &lParam;
|
||||
|
||||
// If the SendVirtualInput call condition is true, increment the count. If no condition is set then always increment the count
|
||||
if (sendVirtualInputCallCondition == nullptr || sendVirtualInputCallCondition(&keyEvent))
|
||||
{
|
||||
sendVirtualInputCallCount++;
|
||||
}
|
||||
|
||||
// Call low level hook handler
|
||||
intptr_t result = MockedKeyboardHook(&keyEvent);
|
||||
|
||||
// Set keyboard state if the hook does not suppress the input
|
||||
if (result == 0)
|
||||
{
|
||||
// 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;
|
||||
|
||||
// Handling modifier key codes
|
||||
switch (pInputs[i].ki.wVk)
|
||||
{
|
||||
case VK_CONTROL:
|
||||
if (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP)
|
||||
{
|
||||
keyboardState[VK_LCONTROL] = false;
|
||||
keyboardState[VK_RCONTROL] = false;
|
||||
}
|
||||
break;
|
||||
case VK_LCONTROL:
|
||||
keyboardState[VK_CONTROL] = (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
||||
break;
|
||||
case VK_RCONTROL:
|
||||
keyboardState[VK_CONTROL] = (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
||||
break;
|
||||
case VK_MENU:
|
||||
if (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP)
|
||||
{
|
||||
keyboardState[VK_LMENU] = false;
|
||||
keyboardState[VK_RMENU] = false;
|
||||
}
|
||||
break;
|
||||
case VK_LMENU:
|
||||
keyboardState[VK_MENU] = (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
||||
break;
|
||||
case VK_RMENU:
|
||||
keyboardState[VK_MENU] = (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
||||
break;
|
||||
case VK_SHIFT:
|
||||
if (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP)
|
||||
{
|
||||
keyboardState[VK_LSHIFT] = false;
|
||||
keyboardState[VK_RSHIFT] = false;
|
||||
}
|
||||
break;
|
||||
case VK_LSHIFT:
|
||||
keyboardState[VK_SHIFT] = (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
||||
break;
|
||||
case VK_RSHIFT:
|
||||
keyboardState[VK_SHIFT] = (pInputs[i].ki.dwFlags & KEYEVENTF_KEYUP) ? false : true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cInputs;
|
||||
}
|
||||
|
||||
// Function to simulate keyboard hook behavior
|
||||
intptr_t MockedInput::MockedKeyboardHook(LowlevelKeyboardEvent* data)
|
||||
{
|
||||
// If the hookProc is set to null, then skip the hook
|
||||
if (hookProc != nullptr)
|
||||
{
|
||||
return hookProc(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to get the state of a particular key
|
||||
bool MockedInput::GetVirtualKeyState(int key)
|
||||
{
|
||||
return keyboardState[key];
|
||||
}
|
||||
|
||||
// Function to reset the mocked keyboard state
|
||||
void MockedInput::ResetKeyboardState()
|
||||
{
|
||||
std::fill(keyboardState.begin(), keyboardState.end(), false);
|
||||
}
|
||||
|
||||
// Function to set SendVirtualInput call count condition
|
||||
void MockedInput::SetSendVirtualInputTestHandler(std::function<bool(LowlevelKeyboardEvent*)> condition)
|
||||
{
|
||||
sendVirtualInputCallCount = 0;
|
||||
sendVirtualInputCallCondition = condition;
|
||||
}
|
||||
|
||||
// Function to get SendVirtualInput call count
|
||||
int MockedInput::GetSendVirtualInputCallCount()
|
||||
{
|
||||
return sendVirtualInputCallCount;
|
||||
}
|
||||
|
||||
// Function to get the foreground process name
|
||||
void MockedInput::SetForegroundProcess(std::wstring process)
|
||||
{
|
||||
currentProcess = process;
|
||||
}
|
||||
|
||||
// Function to get the foreground process name
|
||||
void MockedInput::GetForegroundProcess(_Out_ std::wstring& foregroundProcess)
|
||||
{
|
||||
foregroundProcess = currentProcess;
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
#pragma once
|
||||
#include <keyboardmanager/common/InputInterface.h>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
#include <common/hooks/LowlevelKeyboardEvent.h>
|
||||
|
||||
// Class for mocked keyboard input
|
||||
class MockedInput :
|
||||
public KeyboardManagerInput::InputInterface
|
||||
{
|
||||
private:
|
||||
// Stores the states for all the keys - false for key up, and true for key down
|
||||
std::vector<bool> keyboardState;
|
||||
|
||||
// Function to be executed as a low level hook. By default it is nullptr so the hook is skipped
|
||||
std::function<intptr_t(LowlevelKeyboardEvent*)> hookProc;
|
||||
|
||||
// Stores the count of sendVirtualInput calls given if the condition sendVirtualInputCallCondition is satisfied
|
||||
int sendVirtualInputCallCount = 0;
|
||||
std::function<bool(LowlevelKeyboardEvent*)> sendVirtualInputCallCondition;
|
||||
|
||||
std::wstring currentProcess;
|
||||
|
||||
public:
|
||||
MockedInput()
|
||||
{
|
||||
keyboardState.resize(256, false);
|
||||
}
|
||||
|
||||
// Set the keyboard hook procedure to be tested
|
||||
void SetHookProc(std::function<intptr_t(LowlevelKeyboardEvent*)> hookProcedure);
|
||||
|
||||
// Function to simulate keyboard input
|
||||
UINT SendVirtualInput(UINT cInputs, LPINPUT pInputs, int cbSize);
|
||||
|
||||
// Function to simulate keyboard hook behavior
|
||||
intptr_t MockedKeyboardHook(LowlevelKeyboardEvent* data);
|
||||
|
||||
// Function to get the state of a particular key
|
||||
bool GetVirtualKeyState(int key);
|
||||
|
||||
// Function to reset the mocked keyboard state
|
||||
void ResetKeyboardState();
|
||||
|
||||
// Function to set SendVirtualInput call count condition
|
||||
void SetSendVirtualInputTestHandler(std::function<bool(LowlevelKeyboardEvent*)> condition);
|
||||
|
||||
// Function to get SendVirtualInput call count
|
||||
int GetSendVirtualInputCallCount();
|
||||
|
||||
// Function to get the foreground process name
|
||||
void SetForegroundProcess(std::wstring process);
|
||||
|
||||
// Function to get the foreground process name
|
||||
void GetForegroundProcess(_Out_ std::wstring& foregroundProcess);
|
||||
};
|
@ -1,25 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "TestHelpers.h"
|
||||
#include "MockedInput.h"
|
||||
#include "keyboardmanager/common/KeyboardManagerState.h"
|
||||
|
||||
namespace TestHelpers
|
||||
{
|
||||
// Function to reset the environment variables for tests
|
||||
void ResetTestEnv(MockedInput& input, KeyboardManagerState& state)
|
||||
{
|
||||
input.ResetKeyboardState();
|
||||
input.SetHookProc(nullptr);
|
||||
input.SetSendVirtualInputTestHandler(nullptr);
|
||||
input.SetForegroundProcess(L"");
|
||||
state.ClearSingleKeyRemaps();
|
||||
state.ClearOSLevelShortcuts();
|
||||
state.ClearAppSpecificShortcuts();
|
||||
|
||||
// Allocate memory for the keyboardManagerState activatedApp member to avoid CRT assert errors
|
||||
std::wstring maxLengthString;
|
||||
maxLengthString.resize(MAX_PATH);
|
||||
state.SetActivatedApp(maxLengthString);
|
||||
state.SetActivatedApp(KeyboardManagerConstants::NoActivatedApp);
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
class MockedInput;
|
||||
class KeyboardManagerState;
|
||||
|
||||
namespace TestHelpers
|
||||
{
|
||||
// Function to reset the environment variables for tests
|
||||
void ResetTestEnv(MockedInput& input, KeyboardManagerState& state);
|
||||
|
||||
// Function to return the index of the given key code from the drop down key list
|
||||
int GetDropDownIndexFromDropDownList(DWORD key, const std::vector<DWORD>& keyList);
|
||||
}
|
@ -69,9 +69,6 @@
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SetttingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\common\KeyboardManagerCommon.vcxproj">
|
||||
<Project>{8affa899-0b73-49ec-8c50-0fadda57b2fc}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\KeyboardManagerEngineLibrary\KeyboardManagerEngineLibrary.vcxproj">
|
||||
<Project>{e496b7fc-1e99-4bab-849b-0e8367040b02}</Project>
|
||||
</ProjectReference>
|
||||
|
@ -3,10 +3,10 @@
|
||||
#include <common/utils/ProcessWaiter.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include <common/utils/UnhandledExceptionHandler_x64.h>
|
||||
#include <keyboardmanager/common/KeyboardManagerConstants.h>
|
||||
#include <keyboardmanager/KeyboardManagerEngineLibrary/KeyboardManager.h>
|
||||
#include <keyboardmanager/KeyboardManagerEngineLibrary/trace.h>
|
||||
#include <common/utils/UnhandledExceptionHandler_x64.h>
|
||||
|
||||
const std::wstring instanceMutexName = L"Local\\PowerToys_KBMEngine_InstanceMutex";
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include <common/interop/shared_constants.h>
|
||||
|
||||
#include <keyboardmanager/common/KeyboardManagerState.h>
|
||||
#include <keyboardmanager/common/InputInterface.h>
|
||||
#include <keyboardmanager/common/Helpers.h>
|
||||
#include <keyboardmanager/KeyboardManagerEngineLibrary/trace.h>
|
||||
@ -11,12 +10,12 @@
|
||||
namespace KeyboardEventHandlers
|
||||
{
|
||||
// Function to a handle a single key remap
|
||||
intptr_t HandleSingleKeyRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, KeyboardManagerState& keyboardManagerState) noexcept
|
||||
intptr_t HandleSingleKeyRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, State& state) noexcept
|
||||
{
|
||||
// Check if the key event was generated by KeyboardManager to avoid remapping events generated by us.
|
||||
if (!(data->lParam->dwExtraInfo & CommonSharedConstants::KEYBOARDMANAGER_INJECTED_FLAG))
|
||||
{
|
||||
const auto remapping = keyboardManagerState.GetSingleKeyRemap(data->lParam->vkCode);
|
||||
const auto remapping = state.GetSingleKeyRemap(data->lParam->vkCode);
|
||||
if (remapping)
|
||||
{
|
||||
auto it = remapping.value();
|
||||
@ -50,11 +49,11 @@ namespace KeyboardEventHandlers
|
||||
DWORD target;
|
||||
if (remapToKey)
|
||||
{
|
||||
target = KeyboardManagerHelper::FilterArtificialKeys(std::get<DWORD>(it->second));
|
||||
target = Helpers::FilterArtificialKeys(std::get<DWORD>(it->second));
|
||||
}
|
||||
else
|
||||
{
|
||||
target = KeyboardManagerHelper::FilterArtificialKeys(std::get<Shortcut>(it->second).GetActionKey());
|
||||
target = Helpers::FilterArtificialKeys(std::get<Shortcut>(it->second).GetActionKey());
|
||||
}
|
||||
|
||||
// If Ctrl/Alt/Shift is being remapped to Caps Lock, then reset the modifier key state to fix issues in certain IME keyboards where the IME shortcut gets invoked since it detects that the modifier and Caps Lock is pressed even though it is suppressed by the hook - More information at the GitHub issue https://github.com/microsoft/PowerToys/issues/3397
|
||||
@ -67,11 +66,11 @@ namespace KeyboardEventHandlers
|
||||
{
|
||||
if (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP)
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)target, KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)target, KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||
}
|
||||
else
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)target, 0, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)target, 0, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -80,16 +79,16 @@ namespace KeyboardEventHandlers
|
||||
Shortcut targetShortcut = std::get<Shortcut>(it->second);
|
||||
if (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP)
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)targetShortcut.GetActionKey(), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)targetShortcut.GetActionKey(), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||
i++;
|
||||
KeyboardManagerHelper::SetModifierKeyEvents(targetShortcut, ModifierKey::Disabled, keyEventList, i, 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
|
||||
}
|
||||
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
|
||||
KeyboardManagerHelper::SetModifierKeyEvents(targetShortcut, ModifierKey::Disabled, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)targetShortcut.GetActionKey(), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||
Helpers::SetModifierKeyEvents(targetShortcut, ModifierKey::Disabled, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)targetShortcut.GetActionKey(), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@ -127,22 +126,22 @@ namespace KeyboardEventHandlers
|
||||
/* This feature has not been enabled (code from proof of concept stage)
|
||||
*
|
||||
// Function to a change a key's behavior from toggle to modifier
|
||||
__declspec(dllexport) intptr_t HandleSingleKeyToggleToModEvent(InputInterface& ii, LowlevelKeyboardEvent* data, KeyboardManagerState& keyboardManagerState) noexcept
|
||||
__declspec(dllexport) intptr_t HandleSingleKeyToggleToModEvent(InputInterface& ii, LowlevelKeyboardEvent* data, State& State) noexcept
|
||||
{
|
||||
// Check if the key event was generated by KeyboardManager to avoid remapping events generated by us.
|
||||
if (!(data->lParam->dwExtraInfo & CommonSharedConstants::KEYBOARDMANAGER_INJECTED_FLAG))
|
||||
{
|
||||
// The mutex should be unlocked before SendInput is called to avoid re-entry into the same mutex. More details can be found at https://github.com/microsoft/PowerToys/pull/1789#issuecomment-607555837
|
||||
std::unique_lock<std::mutex> lock(keyboardManagerState.singleKeyToggleToMod_mutex);
|
||||
auto it = keyboardManagerState.singleKeyToggleToMod.find(data->lParam->vkCode);
|
||||
if (it != keyboardManagerState.singleKeyToggleToMod.end())
|
||||
std::unique_lock<std::mutex> lock(State.singleKeyToggleToMod_mutex);
|
||||
auto it = State.singleKeyToggleToMod.find(data->lParam->vkCode);
|
||||
if (it != State.singleKeyToggleToMod.end())
|
||||
{
|
||||
// To avoid long presses (which leads to continuous keydown messages) from toggling the key on and off
|
||||
if (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN)
|
||||
{
|
||||
if (it->second == false)
|
||||
{
|
||||
keyboardManagerState.singleKeyToggleToMod[data->lParam->vkCode] = true;
|
||||
State.singleKeyToggleToMod[data->lParam->vkCode] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -153,8 +152,8 @@ namespace KeyboardEventHandlers
|
||||
int key_count = 2;
|
||||
LPINPUT keyEventList = new INPUT[size_t(key_count)]();
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)data->lParam->vkCode, 0, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, 1, INPUT_KEYBOARD, (WORD)data->lParam->vkCode, KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)data->lParam->vkCode, 0, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, 1, INPUT_KEYBOARD, (WORD)data->lParam->vkCode, KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
|
||||
|
||||
lock.unlock();
|
||||
UINT res = ii.SendVirtualInput(key_count, keyEventList, sizeof(INPUT));
|
||||
@ -164,7 +163,7 @@ namespace KeyboardEventHandlers
|
||||
if (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP)
|
||||
{
|
||||
lock.lock();
|
||||
keyboardManagerState.singleKeyToggleToMod[data->lParam->vkCode] = false;
|
||||
State.singleKeyToggleToMod[data->lParam->vkCode] = false;
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
@ -177,16 +176,16 @@ namespace KeyboardEventHandlers
|
||||
*/
|
||||
|
||||
// Function to a handle a shortcut remap
|
||||
intptr_t HandleShortcutRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, KeyboardManagerState& keyboardManagerState, const std::optional<std::wstring>& activatedApp) noexcept
|
||||
intptr_t HandleShortcutRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, State& state, const std::optional<std::wstring>& activatedApp) noexcept
|
||||
{
|
||||
// Check if any shortcut is currently in the invoked state
|
||||
bool isShortcutInvoked = keyboardManagerState.CheckShortcutRemapInvoked(activatedApp);
|
||||
bool isShortcutInvoked = state.CheckShortcutRemapInvoked(activatedApp);
|
||||
|
||||
// Get shortcut table for given activatedApp
|
||||
ShortcutRemapTable& reMap = keyboardManagerState.GetShortcutRemapTable(activatedApp);
|
||||
ShortcutRemapTable& reMap = state.GetShortcutRemapTable(activatedApp);
|
||||
|
||||
// Iterate through the shortcut remaps and apply whichever has been pressed
|
||||
for (auto& itShortcut : keyboardManagerState.GetSortedShortcutRemapVector(activatedApp))
|
||||
for (auto& itShortcut : state.GetSortedShortcutRemapVector(activatedApp))
|
||||
{
|
||||
const auto it = reMap.find(itShortcut);
|
||||
|
||||
@ -239,8 +238,8 @@ namespace KeyboardEventHandlers
|
||||
keyEventList = new INPUT[key_count]();
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
int i = 0;
|
||||
KeyboardManagerHelper::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (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, (WORD)std::get<Shortcut>(it->second.targetShortcut).GetActionKey(), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
i++;
|
||||
}
|
||||
else
|
||||
@ -252,14 +251,14 @@ namespace KeyboardEventHandlers
|
||||
|
||||
// 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;
|
||||
KeyboardManagerHelper::SetDummyKeyEvent(keyEventList, i, 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)
|
||||
KeyboardManagerHelper::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, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut));
|
||||
|
||||
// Set new shortcut key down state
|
||||
KeyboardManagerHelper::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (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, (WORD)std::get<Shortcut>(it->second.targetShortcut).GetActionKey(), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
i++;
|
||||
}
|
||||
|
||||
@ -291,22 +290,22 @@ namespace KeyboardEventHandlers
|
||||
|
||||
// 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;
|
||||
KeyboardManagerHelper::SetDummyKeyEvent(keyEventList, i, 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)
|
||||
KeyboardManagerHelper::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
Helpers::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);
|
||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (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
|
||||
if (it->first.GetCtrlKey() == NULL && it->first.GetAltKey() == NULL && it->first.GetShiftKey() == NULL)
|
||||
{
|
||||
ResetIfModifierKeyForLowerLevelKeyHandlers(ii, (WORD)KeyboardManagerHelper::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)), data->lParam->vkCode);
|
||||
ResetIfModifierKeyForLowerLevelKeyHandlers(ii, (WORD)Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)), data->lParam->vkCode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -314,7 +313,7 @@ namespace KeyboardEventHandlers
|
||||
// If app specific shortcut is invoked, store the target application
|
||||
if (activatedApp)
|
||||
{
|
||||
keyboardManagerState.SetActivatedApp(*activatedApp);
|
||||
state.SetActivatedApp(*activatedApp);
|
||||
}
|
||||
|
||||
UINT res = ii.SendVirtualInput((UINT)key_count, keyEventList, sizeof(INPUT));
|
||||
@ -375,16 +374,16 @@ namespace KeyboardEventHandlers
|
||||
int i = 0;
|
||||
if (isActionKeyPressed)
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)std::get<Shortcut>(it->second.targetShortcut).GetActionKey(), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)std::get<Shortcut>(it->second.targetShortcut).GetActionKey(), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
i++;
|
||||
}
|
||||
KeyboardManagerHelper::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, i, 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
|
||||
KeyboardManagerHelper::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, i, 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
|
||||
KeyboardManagerHelper::SetDummyKeyEvent(keyEventList, i, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
Helpers::SetDummyKeyEvent(keyEventList, i, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -397,7 +396,7 @@ namespace KeyboardEventHandlers
|
||||
{
|
||||
key_count--;
|
||||
}
|
||||
else if (ii.GetVirtualKeyState(KeyboardManagerHelper::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))))
|
||||
else if (ii.GetVirtualKeyState(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))))
|
||||
{
|
||||
isTargetKeyPressed = true;
|
||||
}
|
||||
@ -414,15 +413,15 @@ namespace KeyboardEventHandlers
|
||||
int i = 0;
|
||||
if (std::get<DWORD>(it->second.targetShortcut) != CommonSharedConstants::VK_DISABLED && isTargetKeyPressed)
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)KeyboardManagerHelper::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (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
|
||||
KeyboardManagerHelper::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, i, 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
|
||||
KeyboardManagerHelper::SetDummyKeyEvent(keyEventList, i, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
Helpers::SetDummyKeyEvent(keyEventList, i, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
}
|
||||
|
||||
// Reset the remap state
|
||||
@ -433,7 +432,7 @@ namespace KeyboardEventHandlers
|
||||
// If app specific shortcut has finished invoking, reset the target application
|
||||
if (activatedApp)
|
||||
{
|
||||
keyboardManagerState.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
|
||||
@ -464,11 +463,11 @@ namespace KeyboardEventHandlers
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
if (remapToShortcut)
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)std::get<Shortcut>(it->second.targetShortcut).GetActionKey(), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)std::get<Shortcut>(it->second.targetShortcut).GetActionKey(), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
}
|
||||
else
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)KeyboardManagerHelper::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
}
|
||||
|
||||
UINT res = ii.SendVirtualInput((UINT)key_count, keyEventList, sizeof(INPUT));
|
||||
@ -485,7 +484,7 @@ namespace KeyboardEventHandlers
|
||||
{
|
||||
keyEventList = new INPUT[key_count]();
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)std::get<Shortcut>(it->second.targetShortcut).GetActionKey(), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)std::get<Shortcut>(it->second.targetShortcut).GetActionKey(), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
}
|
||||
else if (std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)
|
||||
{
|
||||
@ -497,14 +496,14 @@ namespace KeyboardEventHandlers
|
||||
else
|
||||
{
|
||||
// Check if the keyboard state is clear apart from the target remap key (by creating a temp Shortcut object with the target key)
|
||||
bool isKeyboardStateClear = Shortcut(std::vector<int32_t>({ KeyboardManagerHelper::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)) })).IsKeyboardStateClearExceptShortcut(ii);
|
||||
bool isKeyboardStateClear = Shortcut(std::vector<int32_t>({ Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)) })).IsKeyboardStateClearExceptShortcut(ii);
|
||||
|
||||
// If the keyboard state is clear, we release the target key but do not reset the remap state
|
||||
if (isKeyboardStateClear)
|
||||
{
|
||||
keyEventList = new INPUT[key_count]();
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)KeyboardManagerHelper::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -519,14 +518,14 @@ namespace KeyboardEventHandlers
|
||||
|
||||
// Release new key state
|
||||
int i = 0;
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)KeyboardManagerHelper::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (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
|
||||
KeyboardManagerHelper::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, 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
|
||||
KeyboardManagerHelper::SetDummyKeyEvent(keyEventList, i, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
Helpers::SetDummyKeyEvent(keyEventList, i, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
|
||||
// Reset the remap state
|
||||
it->second.isShortcutInvoked = false;
|
||||
@ -536,7 +535,7 @@ namespace KeyboardEventHandlers
|
||||
// If app specific shortcut has finished invoking, reset the target application
|
||||
if (activatedApp != KeyboardManagerConstants::NoActivatedApp)
|
||||
{
|
||||
keyboardManagerState.SetActivatedApp(KeyboardManagerConstants::NoActivatedApp);
|
||||
state.SetActivatedApp(KeyboardManagerConstants::NoActivatedApp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -561,7 +560,7 @@ namespace KeyboardEventHandlers
|
||||
{
|
||||
// If it is not remapped to Disable
|
||||
// Modifier state reset might be required for this key depending on the target key - ex: Ctrl+A -> Caps
|
||||
ResetIfModifierKeyForLowerLevelKeyHandlers(ii, data->lParam->vkCode, KeyboardManagerHelper::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)));
|
||||
ResetIfModifierKeyForLowerLevelKeyHandlers(ii, data->lParam->vkCode, Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)));
|
||||
}
|
||||
|
||||
// Suppress the modifier as it is already physically pressed
|
||||
@ -601,20 +600,20 @@ namespace KeyboardEventHandlers
|
||||
int i = 0;
|
||||
if (isActionKeyPressed)
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)std::get<Shortcut>(it->second.targetShortcut).GetActionKey(), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)std::get<Shortcut>(it->second.targetShortcut).GetActionKey(), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
i++;
|
||||
}
|
||||
KeyboardManagerHelper::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, 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)
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)it->first.GetActionKey(), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
Helpers::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);
|
||||
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
|
||||
@ -639,23 +638,23 @@ namespace KeyboardEventHandlers
|
||||
int i = 0;
|
||||
if (isActionKeyPressed)
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)std::get<Shortcut>(it->second.targetShortcut).GetActionKey(), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)std::get<Shortcut>(it->second.targetShortcut).GetActionKey(), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
i++;
|
||||
}
|
||||
KeyboardManagerHelper::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, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
|
||||
|
||||
// Set old shortcut key down state
|
||||
KeyboardManagerHelper::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, i, 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
|
||||
if (isActionKeyPressed)
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)it->first.GetActionKey(), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
Helpers::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);
|
||||
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
|
||||
@ -669,7 +668,7 @@ namespace KeyboardEventHandlers
|
||||
// If app specific shortcut has finished invoking, reset the target application
|
||||
if (activatedApp)
|
||||
{
|
||||
keyboardManagerState.SetActivatedApp(KeyboardManagerConstants::NoActivatedApp);
|
||||
state.SetActivatedApp(KeyboardManagerConstants::NoActivatedApp);
|
||||
}
|
||||
|
||||
UINT res = ii.SendVirtualInput((UINT)key_count, keyEventList, sizeof(INPUT));
|
||||
@ -681,7 +680,7 @@ namespace KeyboardEventHandlers
|
||||
// For remap to key, if the original action key is not currently pressed, we should revert the keyboard state to the physical keys. If it is pressed we should not suppress the event so that shortcut to key remaps can be pressed with other keys. Example use-case: Alt+D->Win, allows Alt+D+A to perform Win+A
|
||||
|
||||
// Modifier state reset might be required for this key depending on the target key - ex: Ctrl+A -> Caps, Shift is pressed. System should not see Shift and Caps pressed together
|
||||
ResetIfModifierKeyForLowerLevelKeyHandlers(ii, data->lParam->vkCode, KeyboardManagerHelper::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)));
|
||||
ResetIfModifierKeyForLowerLevelKeyHandlers(ii, data->lParam->vkCode, Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)));
|
||||
|
||||
// If the shortcut is remapped to Disable then we have to revert the keyboard state to the physical keys
|
||||
bool isRemapToDisable = (std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED);
|
||||
@ -690,7 +689,7 @@ namespace KeyboardEventHandlers
|
||||
if (!isRemapToDisable)
|
||||
{
|
||||
// If the remap target key is currently pressed, then we do not have to revert the keyboard state to the physical keys
|
||||
if (ii.GetVirtualKeyState((KeyboardManagerHelper::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)))))
|
||||
if (ii.GetVirtualKeyState((Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)))))
|
||||
{
|
||||
isOriginalActionKeyPressed = true;
|
||||
}
|
||||
@ -710,13 +709,13 @@ namespace KeyboardEventHandlers
|
||||
|
||||
// Set original shortcut key down state
|
||||
int i = 0;
|
||||
KeyboardManagerHelper::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, i, 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
|
||||
if (isRemapToDisable && isOriginalActionKeyPressed)
|
||||
{
|
||||
// Set original action key
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)it->first.GetActionKey(), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, (WORD)it->first.GetActionKey(), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
i++;
|
||||
}
|
||||
else
|
||||
@ -725,7 +724,7 @@ namespace KeyboardEventHandlers
|
||||
}
|
||||
|
||||
// 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);
|
||||
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 another shortcut to key remap is released to open start menu
|
||||
@ -738,7 +737,7 @@ namespace KeyboardEventHandlers
|
||||
// If app specific shortcut has finished invoking, reset the target application
|
||||
if (activatedApp != KeyboardManagerConstants::NoActivatedApp)
|
||||
{
|
||||
keyboardManagerState.SetActivatedApp(KeyboardManagerConstants::NoActivatedApp);
|
||||
state.SetActivatedApp(KeyboardManagerConstants::NoActivatedApp);
|
||||
}
|
||||
|
||||
UINT res = ii.SendVirtualInput((UINT)key_count, keyEventList, sizeof(INPUT));
|
||||
@ -760,12 +759,12 @@ namespace KeyboardEventHandlers
|
||||
}
|
||||
|
||||
// Function to a handle an os-level shortcut remap
|
||||
intptr_t HandleOSLevelShortcutRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, KeyboardManagerState& keyboardManagerState) noexcept
|
||||
intptr_t HandleOSLevelShortcutRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, State& state) noexcept
|
||||
{
|
||||
// Check if the key event was generated by KeyboardManager to avoid remapping events generated by us.
|
||||
if (data->lParam->dwExtraInfo != KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG)
|
||||
{
|
||||
bool result = HandleShortcutRemapEvent(ii, data, keyboardManagerState);
|
||||
bool result = HandleShortcutRemapEvent(ii, data, state);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -773,7 +772,7 @@ namespace KeyboardEventHandlers
|
||||
}
|
||||
|
||||
// Function to a handle an app-specific shortcut remap
|
||||
intptr_t HandleAppSpecificShortcutRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, KeyboardManagerState& keyboardManagerState) noexcept
|
||||
intptr_t HandleAppSpecificShortcutRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, State& state) noexcept
|
||||
{
|
||||
// Check if the key event was generated by KeyboardManager to avoid remapping events generated by us.
|
||||
if (data->lParam->dwExtraInfo != KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG)
|
||||
@ -800,29 +799,29 @@ namespace KeyboardEventHandlers
|
||||
AppSpecificShortcutRemapTable::iterator it;
|
||||
|
||||
// Check if an app-specific shortcut is already activated
|
||||
if (keyboardManagerState.GetActivatedApp() == KeyboardManagerConstants::NoActivatedApp)
|
||||
if (state.GetActivatedApp() == KeyboardManagerConstants::NoActivatedApp)
|
||||
{
|
||||
query_string = process_name;
|
||||
it = keyboardManagerState.appSpecificShortcutReMap.find(query_string);
|
||||
it = state.appSpecificShortcutReMap.find(query_string);
|
||||
|
||||
// If no entry is found, search for the process name without it's file extension
|
||||
if (it == keyboardManagerState.appSpecificShortcutReMap.end())
|
||||
if (it == state.appSpecificShortcutReMap.end())
|
||||
{
|
||||
// Find index of the file extension
|
||||
size_t extensionIndex = process_name.find_last_of(L".");
|
||||
query_string = process_name.substr(0, extensionIndex);
|
||||
it = keyboardManagerState.appSpecificShortcutReMap.find(query_string);
|
||||
it = state.appSpecificShortcutReMap.find(query_string);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
query_string = keyboardManagerState.GetActivatedApp();
|
||||
it = keyboardManagerState.appSpecificShortcutReMap.find(query_string);
|
||||
query_string = state.GetActivatedApp();
|
||||
it = state.appSpecificShortcutReMap.find(query_string);
|
||||
}
|
||||
|
||||
if (it != keyboardManagerState.appSpecificShortcutReMap.end())
|
||||
if (it != state.appSpecificShortcutReMap.end())
|
||||
{
|
||||
bool result = HandleShortcutRemapEvent(ii, data, keyboardManagerState, query_string);
|
||||
bool result = HandleShortcutRemapEvent(ii, data, state, query_string);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -837,14 +836,14 @@ namespace KeyboardEventHandlers
|
||||
if (target == VK_CAPITAL)
|
||||
{
|
||||
// If the argument is either of the Ctrl/Shift/Alt modifier key codes
|
||||
if (KeyboardManagerHelper::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;
|
||||
LPINPUT keyEventList = new INPUT[size_t(key_count)]();
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
|
||||
// Use the suppress flag to ensure these are not intercepted by any remapped keys or shortcuts
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)key, KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)key, KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG);
|
||||
UINT res = ii.SendVirtualInput((UINT)key_count, keyEventList, sizeof(INPUT));
|
||||
delete[] keyEventList;
|
||||
}
|
||||
|
@ -1,32 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/hooks/LowlevelKeyboardEvent.h>
|
||||
#include "State.h"
|
||||
|
||||
namespace KeyboardManagerInput
|
||||
{
|
||||
class InputInterface;
|
||||
}
|
||||
|
||||
class KeyboardManagerState;
|
||||
|
||||
namespace KeyboardEventHandlers
|
||||
{
|
||||
// Function to a handle a single key remap
|
||||
intptr_t HandleSingleKeyRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, KeyboardManagerState& keyboardManagerState) noexcept;
|
||||
intptr_t HandleSingleKeyRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, State& state) noexcept;
|
||||
|
||||
/* This feature has not been enabled (code from proof of concept stage)
|
||||
// Function to a change a key's behavior from toggle to modifier
|
||||
__declspec(dllexport) intptr_t HandleSingleKeyToggleToModEvent(InputInterface& ii, LowlevelKeyboardEvent* data, KeyboardManagerState& keyboardManagerState) noexcept;
|
||||
__declspec(dllexport) intptr_t HandleSingleKeyToggleToModEvent(InputInterface& ii, LowlevelKeyboardEvent* data, State& state) noexcept;
|
||||
*/
|
||||
|
||||
// Function to a handle a shortcut remap
|
||||
intptr_t HandleShortcutRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, KeyboardManagerState& keyboardManagerState, const std::optional<std::wstring>& activatedApp = std::nullopt) noexcept;
|
||||
intptr_t HandleShortcutRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, State& state, const std::optional<std::wstring>& activatedApp = std::nullopt) noexcept;
|
||||
|
||||
// Function to a handle an os-level shortcut remap
|
||||
intptr_t HandleOSLevelShortcutRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, KeyboardManagerState& keyboardManagerState) noexcept;
|
||||
intptr_t HandleOSLevelShortcutRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, State& state) noexcept;
|
||||
|
||||
// Function to a handle an app-specific shortcut remap
|
||||
intptr_t HandleAppSpecificShortcutRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, KeyboardManagerState& keyboardManagerState) noexcept;
|
||||
intptr_t HandleAppSpecificShortcutRemapEvent(KeyboardManagerInput::InputInterface& ii, LowlevelKeyboardEvent* data, State& state) noexcept;
|
||||
|
||||
// Function to ensure Ctrl/Shift/Alt modifier key state is not detected as pressed down by applications which detect keys at a lower level than hooks when it is remapped for scenarios where its required
|
||||
void ResetIfModifierKeyForLowerLevelKeyHandlers(KeyboardManagerInput::InputInterface& ii, DWORD key, DWORD target);
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include <keyboardmanager/common/KeyboardManagerConstants.h>
|
||||
#include <keyboardmanager/common/Helpers.h>
|
||||
#include <keyboardmanager/common/KeyboardEventHandlers.h>
|
||||
#include <keyboardmanager/common/SettingsHelper.h>
|
||||
#include <ctime>
|
||||
|
||||
#include "KeyboardEventHandlers.h"
|
||||
@ -56,13 +55,13 @@ KeyboardManager::KeyboardManager()
|
||||
|
||||
void KeyboardManager::LoadSettings()
|
||||
{
|
||||
bool loadedSuccessful = SettingsHelper::LoadSettings(keyboardManagerState);
|
||||
bool loadedSuccessful = state.LoadSettings();
|
||||
if (!loadedSuccessful)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
|
||||
// retry once
|
||||
SettingsHelper::LoadSettings(keyboardManagerState);
|
||||
state.LoadSettings();
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,7 +139,7 @@ intptr_t KeyboardManager::HandleKeyboardHookEvent(LowlevelKeyboardEvent* data) n
|
||||
}
|
||||
|
||||
// Remap a key
|
||||
intptr_t SingleKeyRemapResult = KeyboardEventHandlers::HandleSingleKeyRemapEvent(inputHandler, data, keyboardManagerState);
|
||||
intptr_t SingleKeyRemapResult = KeyboardEventHandlers::HandleSingleKeyRemapEvent(inputHandler, data, state);
|
||||
|
||||
// Single key remaps have priority. If a key is remapped, only the remapped version should be visible to the shortcuts and hence the event should be suppressed here.
|
||||
if (SingleKeyRemapResult == 1)
|
||||
@ -154,7 +153,7 @@ intptr_t KeyboardManager::HandleKeyboardHookEvent(LowlevelKeyboardEvent* data) n
|
||||
*/
|
||||
|
||||
// Handle an app-specific shortcut remapping
|
||||
intptr_t AppSpecificShortcutRemapResult = KeyboardEventHandlers::HandleAppSpecificShortcutRemapEvent(inputHandler, data, keyboardManagerState);
|
||||
intptr_t AppSpecificShortcutRemapResult = KeyboardEventHandlers::HandleAppSpecificShortcutRemapEvent(inputHandler, data, state);
|
||||
|
||||
// If an app-specific shortcut is remapped then the os-level shortcut remapping should be suppressed.
|
||||
if (AppSpecificShortcutRemapResult == 1)
|
||||
@ -163,5 +162,5 @@ intptr_t KeyboardManager::HandleKeyboardHookEvent(LowlevelKeyboardEvent* data) n
|
||||
}
|
||||
|
||||
// Handle an os-level shortcut remapping
|
||||
return KeyboardEventHandlers::HandleOSLevelShortcutRemapEvent(inputHandler, data, keyboardManagerState);
|
||||
return KeyboardEventHandlers::HandleOSLevelShortcutRemapEvent(inputHandler, data, state);
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
#include <common/hooks/LowlevelKeyboardEvent.h>
|
||||
#include <common/utils/EventWaiter.h>
|
||||
#include <keyboardmanager/common/KeyboardManagerState.h>
|
||||
#include <keyboardmanager/common/Input.h>
|
||||
#include "State.h"
|
||||
|
||||
class KeyboardManager
|
||||
{
|
||||
@ -27,7 +28,7 @@ private:
|
||||
static KeyboardManager* keyboardManagerObjectPtr;
|
||||
|
||||
// Variable which stores all the state information to be shared between the UI and back-end
|
||||
KeyboardManagerState keyboardManagerState;
|
||||
State state;
|
||||
|
||||
// Object of class which implements InputInterface. Required for calling library functions while enabling testing
|
||||
KeyboardManagerInput::Input inputHandler;
|
||||
|
@ -36,6 +36,7 @@
|
||||
<ClInclude Include="KeyboardEventHandlers.h" />
|
||||
<ClInclude Include="KeyboardManager.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="State.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -44,11 +45,17 @@
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="State.cpp" />
|
||||
<ClCompile Include="trace.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\common\KeyboardManagerCommon.vcxproj">
|
||||
<Project>{8affa899-0b73-49ec-8c50-0fadda57b2fc}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
@ -27,6 +27,9 @@
|
||||
<ClInclude Include="KeyboardEventHandlers.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="State.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
@ -41,6 +44,9 @@
|
||||
<ClCompile Include="KeyboardEventHandlers.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="State.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
@ -0,0 +1,63 @@
|
||||
#include "pch.h"
|
||||
#include "State.h"
|
||||
#include <optional>
|
||||
|
||||
// Function to get the iterator of a single key remap given the source key. Returns nullopt if it isn't remapped
|
||||
std::optional<SingleKeyRemapTable::iterator> State::GetSingleKeyRemap(const DWORD& originalKey)
|
||||
{
|
||||
auto it = singleKeyReMap.find(originalKey);
|
||||
if (it != singleKeyReMap.end())
|
||||
{
|
||||
return it;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool State::CheckShortcutRemapInvoked(const std::optional<std::wstring>& appName)
|
||||
{
|
||||
// Assumes appName exists in the app-specific remap table
|
||||
ShortcutRemapTable& currentRemapTable = appName ? appSpecificShortcutReMap[*appName] : osLevelShortcutReMap;
|
||||
for (auto& it : currentRemapTable)
|
||||
{
|
||||
if (it.second.isShortcutInvoked)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Function to get the source and target of a shortcut remap given the source shortcut. Returns nullopt if it isn't remapped
|
||||
ShortcutRemapTable& State::GetShortcutRemapTable(const std::optional<std::wstring>& appName)
|
||||
{
|
||||
if (appName)
|
||||
{
|
||||
auto itTable = appSpecificShortcutReMap.find(*appName);
|
||||
if (itTable != appSpecificShortcutReMap.end())
|
||||
{
|
||||
return itTable->second;
|
||||
}
|
||||
}
|
||||
|
||||
return osLevelShortcutReMap;
|
||||
}
|
||||
|
||||
std::vector<Shortcut>& State::GetSortedShortcutRemapVector(const std::optional<std::wstring>& appName)
|
||||
{
|
||||
// Assumes appName exists in the app-specific remap table
|
||||
return appName ? appSpecificShortcutReMapSortedKeys[*appName] : osLevelShortcutReMapSortedKeys;
|
||||
}
|
||||
|
||||
// Sets the activated target application in app-specific shortcut
|
||||
void State::SetActivatedApp(const std::wstring& appName)
|
||||
{
|
||||
activatedAppSpecificShortcutTarget = appName;
|
||||
}
|
||||
|
||||
// Gets the activated target application in app-specific shortcut
|
||||
std::wstring State::GetActivatedApp()
|
||||
{
|
||||
return activatedAppSpecificShortcutTarget;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include <keyboardmanager/common/MappingConfiguration.h>
|
||||
|
||||
class State : public MappingConfiguration
|
||||
{
|
||||
private:
|
||||
// Stores the activated target application in app-specific shortcut
|
||||
std::wstring activatedAppSpecificShortcutTarget;
|
||||
|
||||
public:
|
||||
// Function to get the iterator of a single key remap given the source key. Returns nullopt if it isn't remapped
|
||||
std::optional<SingleKeyRemapTable::iterator> GetSingleKeyRemap(const DWORD& originalKey);
|
||||
|
||||
bool CheckShortcutRemapInvoked(const std::optional<std::wstring>& appName);
|
||||
|
||||
// Function to get the source and target of a shortcut remap given the source shortcut. Returns nullopt if it isn't remapped
|
||||
ShortcutRemapTable& GetShortcutRemapTable(const std::optional<std::wstring>& appName);
|
||||
|
||||
std::vector<Shortcut>& GetSortedShortcutRemapVector(const std::optional<std::wstring>& appName);
|
||||
|
||||
// Sets the activated target application in app-specific shortcut
|
||||
void SetActivatedApp(const std::wstring& appName);
|
||||
|
||||
// Gets the activated target application in app-specific shortcut
|
||||
std::wstring GetActivatedApp();
|
||||
};
|
@ -1,7 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "CppUnitTest.h"
|
||||
#include "MockedInput.h"
|
||||
#include <keyboardmanager/common/KeyboardManagerState.h>
|
||||
#include <keyboardmanager/KeyboardManagerEngineLibrary/State.h>
|
||||
#include <keyboardmanager/KeyboardManagerEngineLibrary/KeyboardEventHandlers.h>
|
||||
#include "TestHelpers.h"
|
||||
#include <common/interop/shared_constants.h>
|
||||
@ -15,7 +15,7 @@ namespace RemappingLogicTests
|
||||
{
|
||||
private:
|
||||
KeyboardManagerInput::MockedInput mockedInputHandler;
|
||||
KeyboardManagerState testState;
|
||||
State testState;
|
||||
std::wstring testApp1 = L"testtrocess1.exe";
|
||||
std::wstring testApp2 = L"testprocess2.exe";
|
||||
|
||||
|
@ -1,143 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "CppUnitTest.h"
|
||||
#include <keyboardmanager/common/ErrorTypes.h>
|
||||
#include <keyboardmanager/common/Helpers.h>
|
||||
#include "TestHelpers.h"
|
||||
#include <common/interop/keyboard_layout.h>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
|
||||
namespace KeyboardManagerCommonTests
|
||||
{
|
||||
// Tests for methods in the KeyboardManagerHelper namespace
|
||||
TEST_CLASS (KeyboardManagerHelperTests)
|
||||
{
|
||||
public:
|
||||
TEST_METHOD_INITIALIZE(InitializeTestEnv)
|
||||
{
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns SameKeyPreviouslyMapped on passing the same key for both arguments
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnSameKeyPreviouslyMapped_OnPassingSameKeyForBothArguments)
|
||||
{
|
||||
// Arrange
|
||||
DWORD key1 = 0x41;
|
||||
DWORD key2 = key1;
|
||||
|
||||
// Act
|
||||
auto result = KeyboardManagerHelper::DoKeysOverlap(key1, key2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == KeyboardManagerHelper::ErrorType::SameKeyPreviouslyMapped);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns ConflictingModifierKey on passing left modifier and common modifier
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnConflictingModifierKey_OnPassingLeftModifierAndCommonModifierOfSameType)
|
||||
{
|
||||
// Arrange
|
||||
DWORD key1 = VK_LCONTROL;
|
||||
DWORD key2 = VK_CONTROL;
|
||||
|
||||
// Act
|
||||
auto result = KeyboardManagerHelper::DoKeysOverlap(key1, key2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == KeyboardManagerHelper::ErrorType::ConflictingModifierKey);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns ConflictingModifierKey on passing right modifier and common modifier
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnConflictingModifierKey_OnPassingRightModifierAndCommonModifierOfSameType)
|
||||
{
|
||||
// Arrange
|
||||
DWORD key1 = VK_RCONTROL;
|
||||
DWORD key2 = VK_CONTROL;
|
||||
|
||||
// Act
|
||||
auto result = KeyboardManagerHelper::DoKeysOverlap(key1, key2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == KeyboardManagerHelper::ErrorType::ConflictingModifierKey);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns NoError on passing left modifier and right modifier
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnNoError_OnPassingLeftModifierAndRightModifierOfSameType)
|
||||
{
|
||||
// Arrange
|
||||
DWORD key1 = VK_LCONTROL;
|
||||
DWORD key2 = VK_RCONTROL;
|
||||
|
||||
// Act
|
||||
auto result = KeyboardManagerHelper::DoKeysOverlap(key1, key2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == KeyboardManagerHelper::ErrorType::NoError);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns NoError on passing keys of different types
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnNoError_OnPassingKeysOfDifferentTypes)
|
||||
{
|
||||
// Arrange
|
||||
DWORD key1 = VK_CONTROL;
|
||||
DWORD key2 = VK_SHIFT;
|
||||
|
||||
// Act
|
||||
auto result = KeyboardManagerHelper::DoKeysOverlap(key1, key2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == KeyboardManagerHelper::ErrorType::NoError);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns NoError on passing different action keys
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnNoError_OnPassingDifferentActionKeys)
|
||||
{
|
||||
// Arrange
|
||||
DWORD key1 = 0x41;
|
||||
DWORD key2 = 0x42;
|
||||
|
||||
// Act
|
||||
auto result = KeyboardManagerHelper::DoKeysOverlap(key1, key2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == KeyboardManagerHelper::ErrorType::NoError);
|
||||
}
|
||||
|
||||
// Test if the CheckRepeatedModifier method returns true on passing vector with same modifier repeated
|
||||
TEST_METHOD (CheckRepeatedModifier_ShouldReturnTrue_OnPassingSameModifierRepeated)
|
||||
{
|
||||
// Arrange
|
||||
std::vector<int32_t> keys = { VK_CONTROL, VK_CONTROL, 0x41 };
|
||||
|
||||
// Act
|
||||
bool result = KeyboardManagerHelper::CheckRepeatedModifier(keys, VK_CONTROL);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result);
|
||||
}
|
||||
|
||||
// Test if the CheckRepeatedModifier method returns true on passing vector with conflicting modifier repeated
|
||||
TEST_METHOD (CheckRepeatedModifier_ShouldReturnTrue_OnPassingConflictingModifierRepeated)
|
||||
{
|
||||
// Arrange
|
||||
std::vector<int32_t> keys = { VK_CONTROL, VK_LCONTROL, 0x41 };
|
||||
|
||||
// Act
|
||||
bool result = KeyboardManagerHelper::CheckRepeatedModifier(keys, VK_LCONTROL);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result);
|
||||
}
|
||||
|
||||
// Test if the CheckRepeatedModifier method returns false on passing vector with different modifiers
|
||||
TEST_METHOD (CheckRepeatedModifier_ShouldReturnFalse_OnPassingDifferentModifiers)
|
||||
{
|
||||
// Arrange
|
||||
std::vector<int32_t> keys = { VK_CONTROL, VK_SHIFT, 0x41 };
|
||||
|
||||
// Act
|
||||
bool result = KeyboardManagerHelper::CheckRepeatedModifier(keys, VK_SHIFT);
|
||||
|
||||
// Assert
|
||||
Assert::IsFalse(result);
|
||||
}
|
||||
};
|
||||
}
|
@ -47,9 +47,7 @@
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ShortcutTests.cpp" />
|
||||
<ClCompile Include="SingleKeyRemappingTests.cpp" />
|
||||
<ClCompile Include="HelperTests.cpp" />
|
||||
<ClCompile Include="TestHelpers.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -39,12 +39,6 @@
|
||||
<ClCompile Include="AppSpecificShortcutRemappingTests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HelperTests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ShortcutTests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "CppUnitTest.h"
|
||||
#include "MockedInput.h"
|
||||
#include <keyboardmanager/common/KeyboardManagerState.h>
|
||||
#include <keyboardmanager/KeyboardManagerEngineLibrary/State.h>
|
||||
#include <keyboardmanager/common/KeyboardEventHandlers.h>
|
||||
#include "TestHelpers.h"
|
||||
|
||||
@ -14,7 +14,7 @@ namespace RemappingLogicTests
|
||||
{
|
||||
private:
|
||||
KeyboardManagerInput::MockedInput mockedInputHandler;
|
||||
KeyboardManagerState testState;
|
||||
State testState;
|
||||
|
||||
public:
|
||||
TEST_METHOD_INITIALIZE(InitializeTestEnv)
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "CppUnitTest.h"
|
||||
#include "MockedInput.h"
|
||||
#include <keyboardmanager/common/KeyboardManagerState.h>
|
||||
#include <keyboardmanager/KeyboardManagerEngineLibrary/State.h>
|
||||
#include <keyboardmanager/KeyboardManagerEngineLibrary/KeyboardEventHandlers.h>
|
||||
#include "TestHelpers.h"
|
||||
#include <common/interop/shared_constants.h>
|
||||
@ -15,7 +15,7 @@ namespace RemappingLogicTests
|
||||
{
|
||||
private:
|
||||
KeyboardManagerInput::MockedInput mockedInputHandler;
|
||||
KeyboardManagerState testState;
|
||||
State testState;
|
||||
|
||||
public:
|
||||
TEST_METHOD_INITIALIZE(InitializeTestEnv)
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "CppUnitTest.h"
|
||||
#include "MockedInput.h"
|
||||
#include <keyboardmanager/common/KeyboardManagerState.h>
|
||||
#include <keyboardmanager/KeyboardManagerEngineLibrary/State.h>
|
||||
#include <keyboardmanager/common/KeyboardEventHandlers.h>
|
||||
#include <keyboardmanager/common/Helpers.h>
|
||||
#include "TestHelpers.h"
|
||||
@ -15,7 +15,7 @@ namespace RemappingLogicTests
|
||||
{
|
||||
private:
|
||||
KeyboardManagerInput::MockedInput mockedInputHandler;
|
||||
KeyboardManagerState testState;
|
||||
State testState;
|
||||
|
||||
public:
|
||||
TEST_METHOD_INITIALIZE(InitializeTestEnv)
|
||||
@ -36,7 +36,7 @@ namespace RemappingLogicTests
|
||||
for (int i = 0; i < nInputs; i++)
|
||||
{
|
||||
// Set key events for all the extended keys
|
||||
KeyboardManagerHelper::SetKeyEvent(input, i, INPUT_KEYBOARD, keyCodes[i], 0, 0);
|
||||
Helpers::SetKeyEvent(input, i, INPUT_KEYBOARD, keyCodes[i], 0, 0);
|
||||
// Extended key flag should be set
|
||||
Assert::AreEqual(true, bool(input[i].ki.dwFlags & KEYEVENTF_EXTENDEDKEY));
|
||||
}
|
||||
@ -49,7 +49,7 @@ namespace RemappingLogicTests
|
||||
INPUT input[nInputs] = {};
|
||||
|
||||
int index = 0;
|
||||
KeyboardManagerHelper::SetDummyKeyEvent(input, index, 0);
|
||||
Helpers::SetDummyKeyEvent(input, index, 0);
|
||||
|
||||
// Assert that wScan for both inputs is 0
|
||||
Assert::AreEqual<unsigned int>(0, input[0].ki.wScan);
|
||||
|
@ -1,177 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "CppUnitTest.h"
|
||||
#include <keyboardmanager/common/ErrorTypes.h>
|
||||
#include <keyboardmanager/common/Shortcut.h>
|
||||
#include <keyboardmanager/common/Helpers.h>
|
||||
#include "TestHelpers.h"
|
||||
#include <common/interop/keyboard_layout.h>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
|
||||
namespace KeyboardManagerCommonTests
|
||||
{
|
||||
// Tests for methods in the Shortcut class
|
||||
TEST_CLASS (KeyboardManagerHelperTests)
|
||||
{
|
||||
public:
|
||||
TEST_METHOD_INITIALIZE(InitializeTestEnv)
|
||||
{
|
||||
}
|
||||
|
||||
// Test if the IsValidShortcut method returns false on passing shortcut with null action key
|
||||
TEST_METHOD (IsValidShortcut_ShouldReturnFalse_OnPassingShortcutWithNullActionKey)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s;
|
||||
s.SetKey(NULL);
|
||||
|
||||
// Act
|
||||
bool result = s.IsValidShortcut();
|
||||
|
||||
// Assert
|
||||
Assert::IsFalse(result);
|
||||
}
|
||||
|
||||
// Test if the IsValidShortcut method returns false on passing shortcut with only action key
|
||||
TEST_METHOD (IsValidShortcut_ShouldReturnFalse_OnPassingShortcutWithOnlyActionKey)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s;
|
||||
s.SetKey(0x41);
|
||||
|
||||
// Act
|
||||
bool result = s.IsValidShortcut();
|
||||
|
||||
// Assert
|
||||
Assert::IsFalse(result);
|
||||
}
|
||||
|
||||
// Test if the IsValidShortcut method returns false on passing shortcut with only modifier keys
|
||||
TEST_METHOD (IsValidShortcut_ShouldReturnFalse_OnPassingShortcutWithOnlyModifierKeys)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s;
|
||||
s.SetKey(VK_CONTROL);
|
||||
s.SetKey(VK_SHIFT);
|
||||
|
||||
// Act
|
||||
bool result = s.IsValidShortcut();
|
||||
|
||||
// Assert
|
||||
Assert::IsFalse(result);
|
||||
}
|
||||
|
||||
// Test if the IsValidShortcut method returns true on passing shortcut with modifier and action key
|
||||
TEST_METHOD (IsValidShortcut_ShouldReturnFalse_OnPassingShortcutWithModifierAndActionKey)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s;
|
||||
s.SetKey(VK_CONTROL);
|
||||
s.SetKey(0x41);
|
||||
|
||||
// Act
|
||||
bool result = s.IsValidShortcut();
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns NoError on passing invalid shortcut for one of the arguments
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnNoError_OnPassingInvalidShortcutForOneOfTheArguments)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s1(std::vector<int32_t>{ NULL });
|
||||
Shortcut s2(std::vector<int32_t>{ VK_CONTROL, 0x41 });
|
||||
|
||||
// Act
|
||||
auto result = Shortcut::DoKeysOverlap(s1, s2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == KeyboardManagerHelper::ErrorType::NoError);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns SameShortcutPreviouslyMapped on passing same shortcut for both arguments
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnSameShortcutPreviouslyMapped_OnPassingSameShortcutForBothArguments)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s1(std::vector<int32_t>{ VK_CONTROL, 0x41 });
|
||||
Shortcut s2 = s1;
|
||||
|
||||
// Act
|
||||
auto result = Shortcut::DoKeysOverlap(s1, s2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == KeyboardManagerHelper::ErrorType::SameShortcutPreviouslyMapped);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns NoError on passing shortcuts with different action keys
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnNoError_OnPassingShortcutsWithDifferentActionKeys)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s1(std::vector<int32_t>{ VK_CONTROL, 0x42 });
|
||||
Shortcut s2(std::vector<int32_t>{ VK_CONTROL, 0x41 });
|
||||
|
||||
// Act
|
||||
auto result = Shortcut::DoKeysOverlap(s1, s2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == KeyboardManagerHelper::ErrorType::NoError);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns NoError on passing shortcuts with different modifiers
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnNoError_OnPassingShortcutsWithDifferentModifiers)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s1(std::vector<int32_t>{ VK_CONTROL, 0x42 });
|
||||
Shortcut s2(std::vector<int32_t>{ VK_SHIFT, 0x42 });
|
||||
|
||||
// Act
|
||||
auto result = Shortcut::DoKeysOverlap(s1, s2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == KeyboardManagerHelper::ErrorType::NoError);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns ConflictingModifierShortcut on passing shortcuts with left modifier and common modifier
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnConflictingModifierShortcut_OnPassingShortcutsWithLeftModifierAndCommonModifierOfSameType)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s1(std::vector<int32_t>{ VK_LCONTROL, 0x42 });
|
||||
Shortcut s2(std::vector<int32_t>{ VK_CONTROL, 0x42 });
|
||||
|
||||
// Act
|
||||
auto result = Shortcut::DoKeysOverlap(s1, s2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == KeyboardManagerHelper::ErrorType::ConflictingModifierShortcut);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns ConflictingModifierShortcut on passing shortcuts with right modifier and common modifier
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnConflictingModifierShortcut_OnPassingShortcutsWithRightModifierAndCommonModifierOfSameType)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s1(std::vector<int32_t>{ VK_RCONTROL, 0x42 });
|
||||
Shortcut s2(std::vector<int32_t>{ VK_CONTROL, 0x42 });
|
||||
|
||||
// Act
|
||||
auto result = Shortcut::DoKeysOverlap(s1, s2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == KeyboardManagerHelper::ErrorType::ConflictingModifierShortcut);
|
||||
}
|
||||
|
||||
// Test if the DoKeysOverlap method returns ConflictingModifierShortcut on passing shortcuts with left modifier and right modifier
|
||||
TEST_METHOD (DoKeysOverlap_ShouldReturnConflictingModifierShortcut_OnPassingShortcutsWithLeftModifierAndRightModifierOfSameType)
|
||||
{
|
||||
// Arrange
|
||||
Shortcut s1(std::vector<int32_t>{ VK_LCONTROL, 0x42 });
|
||||
Shortcut s2(std::vector<int32_t>{ VK_RCONTROL, 0x42 });
|
||||
|
||||
// Act
|
||||
auto result = Shortcut::DoKeysOverlap(s1, s2);
|
||||
|
||||
// Assert
|
||||
Assert::IsTrue(result == KeyboardManagerHelper::ErrorType::NoError);
|
||||
}
|
||||
};
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "CppUnitTest.h"
|
||||
#include "MockedInput.h"
|
||||
#include <keyboardmanager/common/KeyboardManagerState.h>
|
||||
#include <keyboardmanager/KeyboardManagerEngineLibrary/State.h>
|
||||
#include <keyboardmanager/KeyboardManagerEngineLibrary/KeyboardEventHandlers.h>
|
||||
#include "TestHelpers.h"
|
||||
#include <common/interop/shared_constants.h>
|
||||
@ -15,7 +15,7 @@ namespace RemappingLogicTests
|
||||
{
|
||||
private:
|
||||
KeyboardManagerInput::MockedInput mockedInputHandler;
|
||||
KeyboardManagerState testState;
|
||||
State testState;
|
||||
|
||||
public:
|
||||
TEST_METHOD_INITIALIZE(InitializeTestEnv)
|
||||
|
@ -1,12 +1,12 @@
|
||||
#include "pch.h"
|
||||
#include "TestHelpers.h"
|
||||
#include "MockedInput.h"
|
||||
#include "keyboardmanager/common/KeyboardManagerState.h"
|
||||
#include <keyboardmanager/KeyboardManagerEngineLibrary/State.h>
|
||||
|
||||
namespace TestHelpers
|
||||
{
|
||||
// Function to reset the environment variables for tests
|
||||
void ResetTestEnv(KeyboardManagerInput::MockedInput& input, KeyboardManagerState& state)
|
||||
void ResetTestEnv(KeyboardManagerInput::MockedInput& input, State& state)
|
||||
{
|
||||
input.ResetKeyboardState();
|
||||
input.SetHookProc(nullptr);
|
||||
|
@ -4,12 +4,12 @@ namespace KeyboardManagerInput
|
||||
{
|
||||
class MockedInput;
|
||||
}
|
||||
class KeyboardManagerState;
|
||||
class State;
|
||||
|
||||
namespace TestHelpers
|
||||
{
|
||||
// Function to reset the environment variables for tests
|
||||
void ResetTestEnv(KeyboardManagerInput::MockedInput& input, KeyboardManagerState& state);
|
||||
void ResetTestEnv(KeyboardManagerInput::MockedInput& input, State& state);
|
||||
|
||||
// Function to return the index of the given key code from the drop down key list
|
||||
int GetDropDownIndexFromDropDownList(DWORD key, const std::vector<DWORD>& keyList);
|
||||
|
@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace KeyboardManagerHelper
|
||||
{
|
||||
// Type to store codes for different errors
|
||||
enum class ErrorType
|
||||
{
|
||||
NoError,
|
||||
SameKeyPreviouslyMapped,
|
||||
MapToSameKey,
|
||||
ConflictingModifierKey,
|
||||
SameShortcutPreviouslyMapped,
|
||||
MapToSameShortcut,
|
||||
ConflictingModifierShortcut,
|
||||
WinL,
|
||||
CtrlAltDel,
|
||||
RemapUnsuccessful,
|
||||
SaveFailed,
|
||||
ShortcutStartWithModifier,
|
||||
ShortcutCannotHaveRepeatedModifier,
|
||||
ShortcutAtleast2Keys,
|
||||
ShortcutOneActionKey,
|
||||
ShortcutNotMoreThanOneActionKey,
|
||||
ShortcutMaxShortcutSizeOneActionKey,
|
||||
ShortcutDisableAsActionKey
|
||||
};
|
||||
}
|
@ -5,27 +5,10 @@
|
||||
#include <common/interop/shared_constants.h>
|
||||
#include <common/utils/process_path.h>
|
||||
|
||||
#include "ErrorTypes.h"
|
||||
#include "KeyboardManagerConstants.h"
|
||||
|
||||
using namespace winrt::Windows::Foundation;
|
||||
|
||||
namespace KeyboardManagerHelper
|
||||
namespace Helpers
|
||||
{
|
||||
// Function to split a wstring based on a delimiter and return a vector of split strings
|
||||
std::vector<std::wstring> splitwstring(const std::wstring& input, wchar_t delimiter)
|
||||
{
|
||||
std::wstringstream ss(input);
|
||||
std::wstring item;
|
||||
std::vector<std::wstring> splittedStrings;
|
||||
while (std::getline(ss, item, delimiter))
|
||||
{
|
||||
splittedStrings.push_back(item);
|
||||
}
|
||||
|
||||
return splittedStrings;
|
||||
}
|
||||
|
||||
// Function to check if the key is a modifier key
|
||||
bool IsModifierKey(DWORD key)
|
||||
{
|
||||
@ -85,33 +68,6 @@ namespace KeyboardManagerHelper
|
||||
}
|
||||
}
|
||||
|
||||
// Function to check if two keys are equal or cover the same set of keys. Return value depends on type of overlap
|
||||
ErrorType DoKeysOverlap(DWORD first, DWORD second)
|
||||
{
|
||||
// If the keys are same
|
||||
if (first == second)
|
||||
{
|
||||
return ErrorType::SameKeyPreviouslyMapped;
|
||||
}
|
||||
else if ((GetKeyType(first) == GetKeyType(second)) && GetKeyType(first) != KeyType::Action)
|
||||
{
|
||||
// If the keys are of the same modifier type and overlapping, i.e. one is L/R and other is common
|
||||
if (((first == VK_LWIN && second == VK_RWIN) || (first == VK_RWIN && second == VK_LWIN)) || ((first == VK_LCONTROL && second == VK_RCONTROL) || (first == VK_RCONTROL && second == VK_LCONTROL)) || ((first == VK_LMENU && second == VK_RMENU) || (first == VK_RMENU && second == VK_LMENU)) || ((first == VK_LSHIFT && second == VK_RSHIFT) || (first == VK_RSHIFT && second == VK_LSHIFT)))
|
||||
{
|
||||
return ErrorType::NoError;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ErrorType::ConflictingModifierKey;
|
||||
}
|
||||
}
|
||||
// If no overlap
|
||||
else
|
||||
{
|
||||
return ErrorType::NoError;
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
@ -207,22 +163,22 @@ namespace KeyboardManagerHelper
|
||||
// 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)))
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, (WORD)shortcutToBeSent.GetWinKey(winKeyInvoked), 0, extraInfoFlag);
|
||||
Helpers::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, (WORD)shortcutToBeSent.GetWinKey(winKeyInvoked), 0, extraInfoFlag);
|
||||
index++;
|
||||
}
|
||||
if (shortcutToBeSent.GetCtrlKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetCtrlKey() != shortcutToCompare.GetCtrlKey()) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckCtrlKey(keyToBeReleased)))
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, (WORD)shortcutToBeSent.GetCtrlKey(), 0, extraInfoFlag);
|
||||
Helpers::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, (WORD)shortcutToBeSent.GetCtrlKey(), 0, extraInfoFlag);
|
||||
index++;
|
||||
}
|
||||
if (shortcutToBeSent.GetAltKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetAltKey() != shortcutToCompare.GetAltKey()) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckAltKey(keyToBeReleased)))
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, (WORD)shortcutToBeSent.GetAltKey(), 0, extraInfoFlag);
|
||||
Helpers::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, (WORD)shortcutToBeSent.GetAltKey(), 0, extraInfoFlag);
|
||||
index++;
|
||||
}
|
||||
if (shortcutToBeSent.GetShiftKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetShiftKey() != shortcutToCompare.GetShiftKey()) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckShiftKey(keyToBeReleased)))
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, (WORD)shortcutToBeSent.GetShiftKey(), 0, extraInfoFlag);
|
||||
Helpers::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, (WORD)shortcutToBeSent.GetShiftKey(), 0, extraInfoFlag);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
@ -233,22 +189,22 @@ namespace KeyboardManagerHelper
|
||||
// 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)))
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, (WORD)shortcutToBeSent.GetShiftKey(), KEYEVENTF_KEYUP, extraInfoFlag);
|
||||
Helpers::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, (WORD)shortcutToBeSent.GetShiftKey(), KEYEVENTF_KEYUP, extraInfoFlag);
|
||||
index++;
|
||||
}
|
||||
if (shortcutToBeSent.GetAltKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetAltKey() != shortcutToCompare.GetAltKey() || shortcutToBeSent.CheckAltKey(keyToBeReleased)))
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, (WORD)shortcutToBeSent.GetAltKey(), KEYEVENTF_KEYUP, extraInfoFlag);
|
||||
Helpers::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, (WORD)shortcutToBeSent.GetAltKey(), KEYEVENTF_KEYUP, extraInfoFlag);
|
||||
index++;
|
||||
}
|
||||
if (shortcutToBeSent.GetCtrlKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetCtrlKey() != shortcutToCompare.GetCtrlKey() || shortcutToBeSent.CheckCtrlKey(keyToBeReleased)))
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, (WORD)shortcutToBeSent.GetCtrlKey(), KEYEVENTF_KEYUP, extraInfoFlag);
|
||||
Helpers::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, (WORD)shortcutToBeSent.GetCtrlKey(), KEYEVENTF_KEYUP, extraInfoFlag);
|
||||
index++;
|
||||
}
|
||||
if (shortcutToBeSent.GetWinKey(winKeyInvoked) != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetWinKey(winKeyInvoked) != shortcutToCompare.GetWinKey(winKeyInvoked) || shortcutToBeSent.CheckWinKey(keyToBeReleased)))
|
||||
{
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, (WORD)shortcutToBeSent.GetWinKey(winKeyInvoked), KEYEVENTF_KEYUP, extraInfoFlag);
|
||||
Helpers::SetKeyEvent(keyEventArray, index, INPUT_KEYBOARD, (WORD)shortcutToBeSent.GetWinKey(winKeyInvoked), KEYEVENTF_KEYUP, extraInfoFlag);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
@ -274,18 +230,4 @@ namespace KeyboardManagerHelper
|
||||
return first.Size() > second.Size();
|
||||
});
|
||||
}
|
||||
|
||||
// Function to check if a modifier has been repeated in the previous drop downs
|
||||
bool CheckRepeatedModifier(const std::vector<int32_t>& currentKeys, int selectedKeyCode)
|
||||
{
|
||||
// Count the number of keys that are equal to 'selectedKeyCode'
|
||||
int numberOfSameType = 0;
|
||||
for (int i = 0; i < currentKeys.size(); i++)
|
||||
{
|
||||
numberOfSameType += KeyboardManagerHelper::GetKeyType(selectedKeyCode) == KeyboardManagerHelper::GetKeyType(currentKeys[i]);
|
||||
}
|
||||
|
||||
// If we have at least two keys equal to 'selectedKeyCode' than modifier was repeated
|
||||
return numberOfSameType > 1;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
class LayoutMap;
|
||||
|
||||
namespace KeyboardManagerHelper
|
||||
namespace Helpers
|
||||
{
|
||||
// Type to distinguish between keys
|
||||
enum class KeyType
|
||||
@ -15,29 +15,12 @@ namespace KeyboardManagerHelper
|
||||
Action
|
||||
};
|
||||
|
||||
// Enum type to store possible decision for input in the low level hook
|
||||
enum class KeyboardHookDecision
|
||||
{
|
||||
ContinueExec,
|
||||
Suppress,
|
||||
SkipHook
|
||||
};
|
||||
|
||||
// Function to split a wstring based on a delimiter and return a vector of split strings
|
||||
std::vector<std::wstring> splitwstring(const std::wstring& input, wchar_t delimiter);
|
||||
|
||||
// Function to return if the key is an extended key which requires the use of the extended key flag
|
||||
bool IsExtendedKey(DWORD key);
|
||||
|
||||
// Function to check if the key is a modifier key
|
||||
bool IsModifierKey(DWORD key);
|
||||
|
||||
// Function to get the type of the key
|
||||
KeyType GetKeyType(DWORD key);
|
||||
|
||||
// Function to check if two keys are equal or cover the same set of keys. Return value depends on type of overlap
|
||||
ErrorType DoKeysOverlap(DWORD first, DWORD second);
|
||||
|
||||
// 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);
|
||||
|
||||
@ -58,7 +41,4 @@ namespace KeyboardManagerHelper
|
||||
|
||||
// Function to sort a vector of shortcuts based on it's size
|
||||
void SortShortcutVectorBasedOnSize(std::vector<Shortcut>& shortcutVector);
|
||||
|
||||
// Function to check if a modifier has been repeated in the previous drop downs
|
||||
bool CheckRepeatedModifier(const std::vector<int32_t>& currentKeys, int selectedKeyCodes);
|
||||
}
|
@ -24,7 +24,7 @@ namespace KeyboardManagerInput
|
||||
// Function to get the foreground process name
|
||||
void GetForegroundProcess(_Out_ std::wstring& foregroundProcess)
|
||||
{
|
||||
foregroundProcess = KeyboardManagerHelper::GetCurrentApplication(false);
|
||||
foregroundProcess = Helpers::GetCurrentApplication(false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "pch.h"
|
||||
#include "KeyboardEventHandlers.h"
|
||||
#include <keyboardmanager/common/KeyboardManagerState.h>
|
||||
#include <keyboardmanager/common/InputInterface.h>
|
||||
#include <keyboardmanager/common/Helpers.h>
|
||||
#include <keyboardmanager/common/KeyboardManagerConstants.h>
|
||||
|
||||
namespace KeyboardEventHandlers
|
||||
{
|
||||
@ -16,8 +16,8 @@ namespace KeyboardEventHandlers
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
|
||||
// Use the suppress flag to ensure these are not intercepted by any remapped keys or shortcuts
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, VK_NUMLOCK, KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG);
|
||||
KeyboardManagerHelper::SetKeyEvent(keyEventList, 1, INPUT_KEYBOARD, VK_NUMLOCK, 0, KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, VK_NUMLOCK, KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG);
|
||||
Helpers::SetKeyEvent(keyEventList, 1, INPUT_KEYBOARD, VK_NUMLOCK, 0, KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG);
|
||||
UINT res = ii.SendVirtualInput((UINT)key_count, keyEventList, sizeof(INPUT));
|
||||
delete[] keyEventList;
|
||||
}
|
||||
|
@ -46,36 +46,28 @@
|
||||
<ClCompile Include="..\..\..\common\interop\keyboard_layout.cpp" />
|
||||
<ClCompile Include="Helpers.cpp" />
|
||||
<ClCompile Include="KeyboardEventHandlers.cpp" />
|
||||
<ClCompile Include="KeyboardManagerState.cpp" />
|
||||
<ClCompile Include="KeyDelay.cpp" />
|
||||
<ClCompile Include="MappingConfiguration.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SettingsHelper.cpp" />
|
||||
<ClCompile Include="Shortcut.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ErrorTypes.h" />
|
||||
<ClInclude Include="Input.h" />
|
||||
<ClInclude Include="KeyboardEventHandlers.h" />
|
||||
<ClInclude Include="MappingConfiguration.h" />
|
||||
<ClInclude Include="ModifierKey.h" />
|
||||
<ClInclude Include="InputInterface.h" />
|
||||
<ClInclude Include="Helpers.h" />
|
||||
<ClInclude Include="KeyboardManagerConstants.h" />
|
||||
<ClInclude Include="KeyboardManagerState.h" />
|
||||
<ClInclude Include="KeyDelay.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="RemapShortcut.h" />
|
||||
<ClInclude Include="SettingsHelper.h" />
|
||||
<ClInclude Include="Shortcut.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\COMUtils\COMUtils.vcxproj">
|
||||
<Project>{7319089e-46d6-4400-bc65-e39bdf1416ee}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\Display\Display.vcxproj">
|
||||
<Project>{caba8dfb-823b-4bf2-93ac-3f31984150d9}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
|
@ -15,9 +15,6 @@
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="KeyboardManagerState.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Helpers.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -27,23 +24,17 @@
|
||||
<ClCompile Include="Shortcut.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="KeyDelay.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\common\interop\keyboard_layout.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SettingsHelper.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="KeyboardEventHandlers.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MappingConfiguration.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="KeyboardManagerState.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Helpers.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -56,9 +47,6 @@
|
||||
<ClInclude Include="RemapShortcut.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="KeyDelay.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="KeyboardManagerConstants.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -68,16 +56,13 @@
|
||||
<ClInclude Include="ModifierKey.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SettingsHelper.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="KeyboardEventHandlers.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Input.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ErrorTypes.h">
|
||||
<ClInclude Include="MappingConfiguration.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
@ -40,67 +40,11 @@ namespace KeyboardManagerConstants
|
||||
// Name of the default configuration.
|
||||
inline const std::wstring DefaultConfiguration = L"default";
|
||||
|
||||
// Name of the dummy update file.
|
||||
inline const std::wstring DummyUpdateFileName = L"settings-updated.json";
|
||||
|
||||
// Minimum and maximum size of a shortcut
|
||||
inline const long MinShortcutSize = 2;
|
||||
inline const long MaxShortcutSize = 3;
|
||||
|
||||
// Default window sizes
|
||||
inline const int DefaultEditKeyboardWindowWidth = 800;
|
||||
inline const int DefaultEditKeyboardWindowHeight = 600;
|
||||
|
||||
// Increasing the min size can cause issues when moving the window between
|
||||
// monitors with different DPI scaling factor
|
||||
inline const int MinimumEditKeyboardWindowWidth = 200;
|
||||
inline const int MinimumEditKeyboardWindowHeight = 200;
|
||||
|
||||
inline const int EditKeyboardTableMinWidth = 700;
|
||||
|
||||
inline const int DefaultEditShortcutsWindowWidth = 1050;
|
||||
inline const int DefaultEditShortcutsWindowHeight = 600;
|
||||
|
||||
// Increasing the min size can cause issues when moving the window between
|
||||
// monitors with different DPI scaling factor
|
||||
inline const int MinimumEditShortcutsWindowWidth = 200;
|
||||
inline const int MinimumEditShortcutsWindowHeight = 200;
|
||||
|
||||
inline const int EditShortcutsTableMinWidth = 1000;
|
||||
|
||||
// Key Remap table constants
|
||||
inline const long RemapTableColCount = 4;
|
||||
inline const long RemapTableHeaderCount = 2;
|
||||
inline const long RemapTableOriginalColIndex = 0;
|
||||
inline const long RemapTableArrowColIndex = 1;
|
||||
inline const long RemapTableNewColIndex = 2;
|
||||
inline const long RemapTableRemoveColIndex = 3;
|
||||
inline const DWORD64 RemapTableDropDownWidth = 110;
|
||||
|
||||
// Shortcut table constants
|
||||
inline const long ShortcutTableColCount = 5;
|
||||
inline const long ShortcutTableHeaderCount = 3;
|
||||
inline const long ShortcutTableOriginalColIndex = 0;
|
||||
inline const long ShortcutTableArrowColIndex = 1;
|
||||
inline const long ShortcutTableNewColIndex = 2;
|
||||
inline const long ShortcutTableTargetAppColIndex = 3;
|
||||
inline const long ShortcutTableRemoveColIndex = 4;
|
||||
inline const long ShortcutArrowColumnWidth = 90;
|
||||
inline const DWORD64 ShortcutTableDropDownWidth = 110;
|
||||
inline const DWORD64 ShortcutTableDropDownSpacing = 10;
|
||||
inline const long ShortcutOriginColumnWidth = 3 * ShortcutTableDropDownWidth + 2 * ShortcutTableDropDownSpacing;
|
||||
inline const long ShortcutTargetColumnWidth = 3 * ShortcutTableDropDownWidth + 2 * ShortcutTableDropDownSpacing + 25;
|
||||
|
||||
// Drop down height used for both Edit Keyboard and Edit Shortcuts
|
||||
inline const DWORD64 TableDropDownHeight = 200;
|
||||
inline const DWORD64 TableArrowColWidth = 230;
|
||||
inline const DWORD64 TableRemoveColWidth = 20;
|
||||
inline const DWORD64 TableWarningColWidth = 20;
|
||||
inline const DWORD64 TableTargetAppColWidth = ShortcutTableDropDownWidth + TableRemoveColWidth * 2;
|
||||
|
||||
// Shared style constants for both Remap Table and Shortcut Table
|
||||
inline const DWORD64 HeaderButtonWidth = 100;
|
||||
|
||||
// Flags used for distinguishing key events sent by Keyboard Manager
|
||||
inline const ULONG_PTR KEYBOARDMANAGER_SINGLEKEY_FLAG = 0x11; // Single key remaps
|
||||
inline const ULONG_PTR KEYBOARDMANAGER_SHORTCUT_FLAG = 0x101; // Shortcut remaps
|
||||
|
@ -1,230 +0,0 @@
|
||||
#pragma once
|
||||
#include <mutex>
|
||||
#include "KeyboardManagerConstants.h"
|
||||
#include <common/interop/keyboard_layout.h>
|
||||
#include "../common/hooks/LowlevelKeyboardEvent.h"
|
||||
#include <functional>
|
||||
#include <variant>
|
||||
#include "Shortcut.h"
|
||||
#include "RemapShortcut.h"
|
||||
|
||||
class KeyDelay;
|
||||
|
||||
namespace KeyboardManagerHelper
|
||||
{
|
||||
enum class KeyboardHookDecision;
|
||||
}
|
||||
|
||||
namespace winrt::Windows::UI::Xaml::Controls
|
||||
{
|
||||
struct StackPanel;
|
||||
}
|
||||
|
||||
using SingleKeyRemapTable = std::unordered_map<DWORD, KeyShortcutUnion>;
|
||||
using ShortcutRemapTable = std::map<Shortcut, RemapShortcut>;
|
||||
using AppSpecificShortcutRemapTable = std::map<std::wstring, ShortcutRemapTable>;
|
||||
|
||||
// Enum type to store different states of the UI
|
||||
enum class KeyboardManagerUIState
|
||||
{
|
||||
// If set to this value then there is no keyboard manager window currently active that requires a hook
|
||||
Deactivated,
|
||||
// If set to this value then the detect key window is currently active and it requires a hook
|
||||
DetectSingleKeyRemapWindowActivated,
|
||||
// If set to this value then the detect shortcut window in edit keyboard window is currently active and it requires a hook
|
||||
DetectShortcutWindowInEditKeyboardWindowActivated,
|
||||
// If set to this value then the edit keyboard window is currently active and remaps should not be applied
|
||||
EditKeyboardWindowActivated,
|
||||
// If set to this value then the detect shortcut window is currently active and it requires a hook
|
||||
DetectShortcutWindowActivated,
|
||||
// If set to this value then the edit shortcuts window is currently active and remaps should not be applied
|
||||
EditShortcutsWindowActivated
|
||||
};
|
||||
|
||||
// Class to store the shared state of the keyboard manager between the UI and the hook
|
||||
class KeyboardManagerState
|
||||
{
|
||||
private:
|
||||
// State variable used to store which UI window is currently active that requires interaction with the hook
|
||||
KeyboardManagerUIState uiState;
|
||||
std::mutex uiState_mutex;
|
||||
|
||||
// Window handle for the current UI window which is active. Should be set to nullptr if UI is deactivated
|
||||
HWND currentUIWindow;
|
||||
std::mutex currentUIWindow_mutex;
|
||||
|
||||
// Object to store the shortcut detected in the detect shortcut UI window. Gets cleared on releasing keys. This is used in both the backend and the UI.
|
||||
Shortcut detectedShortcut;
|
||||
std::mutex detectedShortcut_mutex;
|
||||
|
||||
// Object to store the shortcut state displayed in the UI window. Always stores last displayed shortcut irrespective of releasing keys. This is used in both the backend and the UI.
|
||||
Shortcut currentShortcut;
|
||||
std::mutex currentShortcut_mutex;
|
||||
|
||||
// Store detected remap key in the remap UI window. This is used in both the backend and the UI.
|
||||
DWORD detectedRemapKey;
|
||||
std::mutex detectedRemapKey_mutex;
|
||||
|
||||
// Stores the UI element which is to be updated based on the remap key entered.
|
||||
winrt::Windows::Foundation::IInspectable currentSingleKeyUI;
|
||||
std::mutex currentSingleKeyUI_mutex;
|
||||
|
||||
// Stores the UI element which is to be updated based on the shortcut entered (each stackpanel represents a row of keys)
|
||||
winrt::Windows::Foundation::IInspectable currentShortcutUI1;
|
||||
winrt::Windows::Foundation::IInspectable currentShortcutUI2;
|
||||
std::mutex currentShortcutUI_mutex;
|
||||
|
||||
// Stores the current configuration name.
|
||||
std::wstring currentConfig = KeyboardManagerConstants::DefaultConfiguration;
|
||||
std::mutex currentConfig_mutex;
|
||||
|
||||
// Registered KeyDelay objects, used to notify delayed key events.
|
||||
std::map<DWORD, std::unique_ptr<KeyDelay>> keyDelays;
|
||||
std::mutex keyDelays_mutex;
|
||||
|
||||
// Stores the activated target application in app-specific shortcut
|
||||
std::wstring activatedAppSpecificShortcutTarget;
|
||||
|
||||
// Thread safe boolean value to check if remappings are currently enabled. This is used to disable remappings while the remap tables are being updated by the UI thread
|
||||
std::atomic_bool remappingsEnabled;
|
||||
|
||||
// Display a key by appending a border Control as a child of the panel.
|
||||
void AddKeyToLayout(const winrt::Windows::UI::Xaml::Controls::StackPanel& panel, const winrt::hstring& key);
|
||||
|
||||
public:
|
||||
// The map members and their mutexes are left as public since the maps are used extensively in dllmain.cpp.
|
||||
// Maps which store the remappings for each of the features. The bool fields should be initialized to false. They are used to check the current state of the shortcut (i.e is that particular shortcut currently pressed down or not).
|
||||
// Stores single key remappings
|
||||
std::unordered_map<DWORD, KeyShortcutUnion> singleKeyReMap;
|
||||
|
||||
/* This feature has not been enabled (code from proof of concept stage)
|
||||
*
|
||||
// Stores keys which need to be changed from toggle behavior to modifier behavior. Eg. Caps Lock
|
||||
std::unordered_map<DWORD, bool> singleKeyToggleToMod;
|
||||
*/
|
||||
|
||||
// Stores the os level shortcut remappings
|
||||
ShortcutRemapTable osLevelShortcutReMap;
|
||||
std::vector<Shortcut> osLevelShortcutReMapSortedKeys;
|
||||
|
||||
// Stores the app-specific shortcut remappings. Maps application name to the shortcut map
|
||||
AppSpecificShortcutRemapTable appSpecificShortcutReMap;
|
||||
std::map<std::wstring, std::vector<Shortcut>> appSpecificShortcutReMapSortedKeys;
|
||||
|
||||
// Stores the keyboard layout
|
||||
LayoutMap keyboardMap;
|
||||
|
||||
// Constructor
|
||||
KeyboardManagerState();
|
||||
|
||||
// Destructor
|
||||
~KeyboardManagerState();
|
||||
|
||||
// Function to reset the UI state members
|
||||
void ResetUIState();
|
||||
|
||||
// Function to check the if the UI state matches the argument state. For states with detect windows it also checks if the window is in focus.
|
||||
bool CheckUIState(KeyboardManagerUIState state);
|
||||
|
||||
// Function to set the window handle of the current UI window that is activated
|
||||
void SetCurrentUIWindow(HWND windowHandle);
|
||||
|
||||
// Function to set the UI state. When a window is activated, the handle to the window can be passed in the windowHandle argument.
|
||||
void SetUIState(KeyboardManagerUIState state, HWND windowHandle = nullptr);
|
||||
|
||||
// Function to clear the OS Level shortcut remapping table
|
||||
void ClearOSLevelShortcuts();
|
||||
|
||||
// Function to clear the Keys remapping table
|
||||
void ClearSingleKeyRemaps();
|
||||
|
||||
// Function to clear the App specific shortcut remapping table
|
||||
void ClearAppSpecificShortcuts();
|
||||
|
||||
// Function to add a new single key to key remapping
|
||||
bool AddSingleKeyRemap(const DWORD& originalKey, const KeyShortcutUnion& newRemapKey);
|
||||
|
||||
// Function to add a new OS level shortcut remapping
|
||||
bool AddOSLevelShortcut(const Shortcut& originalSC, const KeyShortcutUnion& newSC);
|
||||
|
||||
// Function to add a new App specific level shortcut remapping
|
||||
bool AddAppSpecificShortcut(const std::wstring& app, const Shortcut& originalSC, const KeyShortcutUnion& newSC);
|
||||
|
||||
// Function to get the iterator of a single key remap given the source key. Returns nullopt if it isn't remapped
|
||||
std::optional<SingleKeyRemapTable::iterator> GetSingleKeyRemap(const DWORD& originalKey);
|
||||
|
||||
bool CheckShortcutRemapInvoked(const std::optional<std::wstring>& appName);
|
||||
|
||||
std::vector<Shortcut>& GetSortedShortcutRemapVector(const std::optional<std::wstring>& appName);
|
||||
|
||||
// Function to get the source and target of a shortcut remap given the source shortcut. Returns nullopt if it isn't remapped
|
||||
ShortcutRemapTable& GetShortcutRemapTable(const std::optional<std::wstring>& appName);
|
||||
|
||||
// Function to set the textblock of the detect shortcut UI so that it can be accessed by the hook
|
||||
void ConfigureDetectShortcutUI(const winrt::Windows::UI::Xaml::Controls::StackPanel& textBlock1, const winrt::Windows::UI::Xaml::Controls::StackPanel& textBlock2);
|
||||
|
||||
// Function to set the textblock of the detect remap key UI so that it can be accessed by the hook
|
||||
void ConfigureDetectSingleKeyRemapUI(const winrt::Windows::UI::Xaml::Controls::StackPanel& textBlock);
|
||||
|
||||
// Function to update the detect shortcut UI based on the entered keys
|
||||
void UpdateDetectShortcutUI();
|
||||
|
||||
// Function to update the detect remap key UI based on the entered key.
|
||||
void UpdateDetectSingleKeyRemapUI();
|
||||
|
||||
// Function to return the currently detected shortcut which is displayed on the UI
|
||||
Shortcut GetDetectedShortcut();
|
||||
|
||||
// Function to return the currently detected remap key which is displayed on the UI
|
||||
DWORD GetDetectedSingleRemapKey();
|
||||
|
||||
// Function which can be used in HandleKeyboardHookEvent before the single key remap event to use the UI and suppress events while the remap window is active.
|
||||
KeyboardManagerHelper::KeyboardHookDecision DetectSingleRemapKeyUIBackend(LowlevelKeyboardEvent* data);
|
||||
|
||||
// Function which can be used in HandleKeyboardHookEvent before the os level shortcut remap event to use the UI and suppress events while the remap window is active.
|
||||
KeyboardManagerHelper::KeyboardHookDecision DetectShortcutUIBackend(LowlevelKeyboardEvent* data, bool isRemapKey);
|
||||
|
||||
// Add a KeyDelay object to get delayed key presses events for a given virtual key
|
||||
// NOTE: this will throw an exception if a virtual key is registered twice.
|
||||
// NOTE*: the virtual key should represent the original, unmapped virtual key.
|
||||
void RegisterKeyDelay(
|
||||
DWORD key,
|
||||
std::function<void(DWORD)> onShortPress,
|
||||
std::function<void(DWORD)> onLongPressDetected,
|
||||
std::function<void(DWORD)> onLongPressReleased);
|
||||
|
||||
// Remove a KeyDelay.
|
||||
// NOTE: this method will throw if the virtual key is not registered beforehand.
|
||||
// NOTE*: the virtual key should represent the original, unmapped virtual key.
|
||||
void UnregisterKeyDelay(DWORD key);
|
||||
|
||||
// Function to clear all the registered key delays
|
||||
void ClearRegisteredKeyDelays();
|
||||
|
||||
// Handle a key event, for a delayed key.
|
||||
bool HandleKeyDelayEvent(LowlevelKeyboardEvent* ev);
|
||||
|
||||
// Update the currently selected single key remap
|
||||
void SelectDetectedRemapKey(DWORD key);
|
||||
|
||||
// Update the currently selected shortcut.
|
||||
void SelectDetectedShortcut(DWORD key);
|
||||
|
||||
// Reset the shortcut (backend) state after releasing a key.
|
||||
void ResetDetectedShortcutKey(DWORD key);
|
||||
|
||||
// Save the updated configuration.
|
||||
bool SaveConfigToFile();
|
||||
|
||||
// Sets the Current Active Configuration Name.
|
||||
void SetCurrentConfigName(const std::wstring& configName);
|
||||
|
||||
// Gets the Current Active Configuration Name.
|
||||
std::wstring GetCurrentConfigName();
|
||||
|
||||
// Sets the activated target application in app-specific shortcut
|
||||
void SetActivatedApp(const std::wstring& appName);
|
||||
|
||||
// Gets the activated target application in app-specific shortcut
|
||||
std::wstring GetActivatedApp();
|
||||
};
|
393
src/modules/keyboardmanager/common/MappingConfiguration.cpp
Normal file
393
src/modules/keyboardmanager/common/MappingConfiguration.cpp
Normal file
@ -0,0 +1,393 @@
|
||||
#include "pch.h"
|
||||
#include "MappingConfiguration.h"
|
||||
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/logger/logger.h>
|
||||
|
||||
#include "KeyboardManagerConstants.h"
|
||||
#include "Shortcut.h"
|
||||
#include "RemapShortcut.h"
|
||||
#include "Helpers.h"
|
||||
|
||||
// Function to clear the OS Level shortcut remapping table
|
||||
void MappingConfiguration::ClearOSLevelShortcuts()
|
||||
{
|
||||
osLevelShortcutReMap.clear();
|
||||
osLevelShortcutReMapSortedKeys.clear();
|
||||
}
|
||||
|
||||
|
||||
// Function to clear the Keys remapping table.
|
||||
void MappingConfiguration::ClearSingleKeyRemaps()
|
||||
{
|
||||
singleKeyReMap.clear();
|
||||
}
|
||||
|
||||
// Function to clear the App specific shortcut remapping table
|
||||
void MappingConfiguration::ClearAppSpecificShortcuts()
|
||||
{
|
||||
appSpecificShortcutReMap.clear();
|
||||
appSpecificShortcutReMapSortedKeys.clear();
|
||||
}
|
||||
|
||||
// Function to add a new OS level shortcut remapping
|
||||
bool MappingConfiguration::AddOSLevelShortcut(const Shortcut& originalSC, const KeyShortcutUnion& newSC)
|
||||
{
|
||||
// Check if the shortcut is already remapped
|
||||
auto it = osLevelShortcutReMap.find(originalSC);
|
||||
if (it != osLevelShortcutReMap.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
osLevelShortcutReMap[originalSC] = RemapShortcut(newSC);
|
||||
osLevelShortcutReMapSortedKeys.push_back(originalSC);
|
||||
Helpers::SortShortcutVectorBasedOnSize(osLevelShortcutReMapSortedKeys);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Function to add a new single key to key/shortcut remapping
|
||||
bool MappingConfiguration::AddSingleKeyRemap(const DWORD& originalKey, const KeyShortcutUnion& newRemapKey)
|
||||
{
|
||||
// Check if the key is already remapped
|
||||
auto it = singleKeyReMap.find(originalKey);
|
||||
if (it != singleKeyReMap.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
singleKeyReMap[originalKey] = newRemapKey;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Function to add a new App specific shortcut remapping
|
||||
bool MappingConfiguration::AddAppSpecificShortcut(const std::wstring& app, const Shortcut& originalSC, const KeyShortcutUnion& newSC)
|
||||
{
|
||||
// Convert app name to lower case
|
||||
std::wstring process_name;
|
||||
process_name.resize(app.length());
|
||||
std::transform(app.begin(), app.end(), process_name.begin(), towlower);
|
||||
|
||||
// Check if there are any app specific shortcuts for this app
|
||||
auto appIt = appSpecificShortcutReMap.find(process_name);
|
||||
if (appIt != appSpecificShortcutReMap.end())
|
||||
{
|
||||
// Check if the shortcut is already remapped
|
||||
auto shortcutIt = appSpecificShortcutReMap[process_name].find(originalSC);
|
||||
if (shortcutIt != appSpecificShortcutReMap[process_name].end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
appSpecificShortcutReMapSortedKeys[process_name] = std::vector<Shortcut>();
|
||||
}
|
||||
|
||||
appSpecificShortcutReMap[process_name][originalSC] = RemapShortcut(newSC);
|
||||
appSpecificShortcutReMapSortedKeys[process_name].push_back(originalSC);
|
||||
Helpers::SortShortcutVectorBasedOnSize(appSpecificShortcutReMapSortedKeys[process_name]);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool MappingConfiguration::LoadSingleKeyRemaps(const json::JsonObject& jsonData)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
try
|
||||
{
|
||||
auto remapKeysData = jsonData.GetNamedObject(KeyboardManagerConstants::RemapKeysSettingName);
|
||||
ClearSingleKeyRemaps();
|
||||
|
||||
if (remapKeysData)
|
||||
{
|
||||
auto inProcessRemapKeys = remapKeysData.GetNamedArray(KeyboardManagerConstants::InProcessRemapKeysSettingName);
|
||||
for (const auto& it : inProcessRemapKeys)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto originalKey = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
|
||||
auto newRemapKey = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName);
|
||||
|
||||
// If remapped to a shortcut
|
||||
if (std::wstring(newRemapKey).find(L";") != std::string::npos)
|
||||
{
|
||||
AddSingleKeyRemap(std::stoul(originalKey.c_str()), Shortcut(newRemapKey.c_str()));
|
||||
}
|
||||
|
||||
// If remapped to a key
|
||||
else
|
||||
{
|
||||
AddSingleKeyRemap(std::stoul(originalKey.c_str()), std::stoul(newRemapKey.c_str()));
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"Improper Key Data JSON. Try the next remap.");
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"Improper JSON format for single key remaps. Skip to next remap type");
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool MappingConfiguration::LoadAppSpecificShortcutRemaps(const json::JsonObject& remapShortcutsData)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
try
|
||||
{
|
||||
auto appSpecificRemapShortcuts = remapShortcutsData.GetNamedArray(KeyboardManagerConstants::AppSpecificRemapShortcutsSettingName);
|
||||
for (const auto& it : appSpecificRemapShortcuts)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto originalKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
|
||||
auto newRemapKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName);
|
||||
auto targetApp = it.GetObjectW().GetNamedString(KeyboardManagerConstants::TargetAppSettingName);
|
||||
|
||||
// If remapped to a shortcut
|
||||
if (std::wstring(newRemapKeys).find(L";") != std::string::npos)
|
||||
{
|
||||
AddAppSpecificShortcut(targetApp.c_str(), Shortcut(originalKeys.c_str()), Shortcut(newRemapKeys.c_str()));
|
||||
}
|
||||
|
||||
// If remapped to a key
|
||||
else
|
||||
{
|
||||
AddAppSpecificShortcut(targetApp.c_str(), Shortcut(originalKeys.c_str()), std::stoul(newRemapKeys.c_str()));
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"Improper Key Data JSON. Try the next shortcut.");
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"Improper JSON format for os level shortcut remaps. Skip to next remap type");
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool MappingConfiguration::LoadShortcutRemaps(const json::JsonObject& jsonData)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
try
|
||||
{
|
||||
auto remapShortcutsData = jsonData.GetNamedObject(KeyboardManagerConstants::RemapShortcutsSettingName);
|
||||
ClearOSLevelShortcuts();
|
||||
ClearAppSpecificShortcuts();
|
||||
if (remapShortcutsData)
|
||||
{
|
||||
// Load os level shortcut remaps
|
||||
try
|
||||
{
|
||||
auto globalRemapShortcuts = remapShortcutsData.GetNamedArray(KeyboardManagerConstants::GlobalRemapShortcutsSettingName);
|
||||
for (const auto& it : globalRemapShortcuts)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto originalKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
|
||||
auto newRemapKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName);
|
||||
|
||||
// If remapped to a shortcut
|
||||
if (std::wstring(newRemapKeys).find(L";") != std::string::npos)
|
||||
{
|
||||
AddOSLevelShortcut(Shortcut(originalKeys.c_str()), Shortcut(newRemapKeys.c_str()));
|
||||
}
|
||||
|
||||
// If remapped to a key
|
||||
else
|
||||
{
|
||||
AddOSLevelShortcut(Shortcut(originalKeys.c_str()), std::stoul(newRemapKeys.c_str()));
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"Improper Key Data JSON. Try the next shortcut.");
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"Improper JSON format for os level shortcut remaps. Skip to next remap type");
|
||||
result = false;
|
||||
}
|
||||
|
||||
// Load app specific shortcut remaps
|
||||
result = result && LoadAppSpecificShortcutRemaps(remapShortcutsData);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"Improper JSON format for shortcut remaps. Skip to next remap type");
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MappingConfiguration::MappingConfiguration()
|
||||
{
|
||||
}
|
||||
|
||||
bool MappingConfiguration::LoadSettings()
|
||||
{
|
||||
Logger::trace(L"SettingsHelper::LoadSettings()");
|
||||
try
|
||||
{
|
||||
PowerToysSettings::PowerToyValues settings = PowerToysSettings::PowerToyValues::load_from_settings_file(KeyboardManagerConstants::ModuleName);
|
||||
auto current_config = settings.get_string_value(KeyboardManagerConstants::ActiveConfigurationSettingName);
|
||||
|
||||
if (!current_config)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
currentConfig = *current_config;
|
||||
|
||||
// Read the config file and load the remaps.
|
||||
auto configFile = json::from_file(PTSettingsHelper::get_module_save_folder_location(KeyboardManagerConstants::ModuleName) + L"\\" + *current_config + L".json");
|
||||
if (!configFile)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = LoadSingleKeyRemaps(*configFile);
|
||||
result = result && LoadShortcutRemaps(*configFile);
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"SettingsHelper::LoadSettings() failed");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save the updated configuration.
|
||||
bool MappingConfiguration::SaveSettingsToFile()
|
||||
{
|
||||
bool result = true;
|
||||
json::JsonObject configJson;
|
||||
json::JsonObject remapShortcuts;
|
||||
json::JsonObject remapKeys;
|
||||
json::JsonArray inProcessRemapKeysArray;
|
||||
json::JsonArray appSpecificRemapShortcutsArray;
|
||||
json::JsonArray globalRemapShortcutsArray;
|
||||
for (const auto& it : singleKeyReMap)
|
||||
{
|
||||
json::JsonObject keys;
|
||||
keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(winrt::to_hstring((unsigned int)it.first)));
|
||||
|
||||
// For key to key remapping
|
||||
if (it.second.index() == 0)
|
||||
{
|
||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(winrt::to_hstring((unsigned int)std::get<DWORD>(it.second))));
|
||||
}
|
||||
|
||||
// For key to shortcut remapping
|
||||
else
|
||||
{
|
||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(std::get<Shortcut>(it.second).ToHstringVK()));
|
||||
}
|
||||
|
||||
inProcessRemapKeysArray.Append(keys);
|
||||
}
|
||||
|
||||
for (const auto& it : osLevelShortcutReMap)
|
||||
{
|
||||
json::JsonObject keys;
|
||||
keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(it.first.ToHstringVK()));
|
||||
|
||||
// For shortcut to key remapping
|
||||
if (it.second.targetShortcut.index() == 0)
|
||||
{
|
||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(winrt::to_hstring((unsigned int)std::get<DWORD>(it.second.targetShortcut))));
|
||||
}
|
||||
|
||||
// For shortcut to shortcut remapping
|
||||
else
|
||||
{
|
||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(std::get<Shortcut>(it.second.targetShortcut).ToHstringVK()));
|
||||
}
|
||||
|
||||
globalRemapShortcutsArray.Append(keys);
|
||||
}
|
||||
|
||||
for (const auto& itApp : appSpecificShortcutReMap)
|
||||
{
|
||||
// Iterate over apps
|
||||
for (const auto& itKeys : itApp.second)
|
||||
{
|
||||
json::JsonObject keys;
|
||||
keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(itKeys.first.ToHstringVK()));
|
||||
|
||||
// For shortcut to key remapping
|
||||
if (itKeys.second.targetShortcut.index() == 0)
|
||||
{
|
||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(winrt::to_hstring((unsigned int)std::get<DWORD>(itKeys.second.targetShortcut))));
|
||||
}
|
||||
|
||||
// For shortcut to shortcut remapping
|
||||
else
|
||||
{
|
||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(std::get<Shortcut>(itKeys.second.targetShortcut).ToHstringVK()));
|
||||
}
|
||||
|
||||
keys.SetNamedValue(KeyboardManagerConstants::TargetAppSettingName, json::value(itApp.first));
|
||||
|
||||
appSpecificRemapShortcutsArray.Append(keys);
|
||||
}
|
||||
}
|
||||
|
||||
remapShortcuts.SetNamedValue(KeyboardManagerConstants::GlobalRemapShortcutsSettingName, globalRemapShortcutsArray);
|
||||
remapShortcuts.SetNamedValue(KeyboardManagerConstants::AppSpecificRemapShortcutsSettingName, appSpecificRemapShortcutsArray);
|
||||
remapKeys.SetNamedValue(KeyboardManagerConstants::InProcessRemapKeysSettingName, inProcessRemapKeysArray);
|
||||
configJson.SetNamedValue(KeyboardManagerConstants::RemapKeysSettingName, remapKeys);
|
||||
configJson.SetNamedValue(KeyboardManagerConstants::RemapShortcutsSettingName, remapShortcuts);
|
||||
|
||||
try
|
||||
{
|
||||
json::to_file((PTSettingsHelper::get_module_save_folder_location(KeyboardManagerConstants::ModuleName) + L"\\" + currentConfig + L".json"), configJson);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
result = false;
|
||||
Logger::error(L"Failed to save the settings");
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
auto hEvent = CreateEvent(nullptr, false, false, KeyboardManagerConstants::SettingsEventName.c_str());
|
||||
if (hEvent)
|
||||
{
|
||||
SetEvent(hEvent);
|
||||
Logger::trace(L"Signaled {} event", KeyboardManagerConstants::SettingsEventName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error(L"Failed to signal {} event", KeyboardManagerConstants::SettingsEventName);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
65
src/modules/keyboardmanager/common/MappingConfiguration.h
Normal file
65
src/modules/keyboardmanager/common/MappingConfiguration.h
Normal file
@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/utils/json.h>
|
||||
|
||||
#include <keyboardmanager/common/KeyboardManagerConstants.h>
|
||||
#include <keyboardmanager/common/Shortcut.h>
|
||||
#include <keyboardmanager/common/RemapShortcut.h>
|
||||
|
||||
using SingleKeyRemapTable = std::unordered_map<DWORD, KeyShortcutUnion>;
|
||||
using ShortcutRemapTable = std::map<Shortcut, RemapShortcut>;
|
||||
using AppSpecificShortcutRemapTable = std::map<std::wstring, ShortcutRemapTable>;
|
||||
|
||||
class MappingConfiguration
|
||||
{
|
||||
public:
|
||||
MappingConfiguration();
|
||||
|
||||
~MappingConfiguration() = default;
|
||||
|
||||
// Load the configuration.
|
||||
bool LoadSettings();
|
||||
|
||||
// Save the updated configuration.
|
||||
bool SaveSettingsToFile();
|
||||
|
||||
// Function to clear the OS Level shortcut remapping table
|
||||
void ClearOSLevelShortcuts();
|
||||
|
||||
// Function to clear the Keys remapping table
|
||||
void ClearSingleKeyRemaps();
|
||||
|
||||
// Function to clear the App specific shortcut remapping table
|
||||
void ClearAppSpecificShortcuts();
|
||||
|
||||
// Function to add a new single key to key remapping
|
||||
bool AddSingleKeyRemap(const DWORD& originalKey, const KeyShortcutUnion& newRemapKey);
|
||||
|
||||
// Function to add a new OS level shortcut remapping
|
||||
bool AddOSLevelShortcut(const Shortcut& originalSC, const KeyShortcutUnion& newSC);
|
||||
|
||||
// Function to add a new App specific level shortcut remapping
|
||||
bool AddAppSpecificShortcut(const std::wstring& app, const Shortcut& originalSC, const KeyShortcutUnion& newSC);
|
||||
|
||||
// The map members and their mutexes are left as public since the maps are used extensively in dllmain.cpp.
|
||||
// Maps which store the remappings for each of the features. The bool fields should be initialized to false. They are used to check the current state of the shortcut (i.e is that particular shortcut currently pressed down or not).
|
||||
// Stores single key remappings
|
||||
std::unordered_map<DWORD, KeyShortcutUnion> singleKeyReMap;
|
||||
|
||||
// Stores the os level shortcut remappings
|
||||
ShortcutRemapTable osLevelShortcutReMap;
|
||||
std::vector<Shortcut> osLevelShortcutReMapSortedKeys;
|
||||
|
||||
// Stores the app-specific shortcut remappings. Maps application name to the shortcut map
|
||||
AppSpecificShortcutRemapTable appSpecificShortcutReMap;
|
||||
std::map<std::wstring, std::vector<Shortcut>> appSpecificShortcutReMapSortedKeys;
|
||||
|
||||
// Stores the current configuration name.
|
||||
std::wstring currentConfig = KeyboardManagerConstants::DefaultConfiguration;
|
||||
|
||||
|
||||
private:
|
||||
bool LoadSingleKeyRemaps(const json::JsonObject& jsonData);
|
||||
bool LoadShortcutRemaps(const json::JsonObject& jsonData);
|
||||
bool LoadAppSpecificShortcutRemaps(const json::JsonObject& remapShortcutsData);
|
||||
};
|
@ -1,194 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "SettingsHelper.h"
|
||||
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/logger/logger.h>
|
||||
|
||||
#include <common/KeyboardManagerConstants.h>
|
||||
|
||||
bool LoadSingleKeyRemaps(KeyboardManagerState& keyboardManagerState, const json::JsonObject& jsonData)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
try
|
||||
{
|
||||
auto remapKeysData = jsonData.GetNamedObject(KeyboardManagerConstants::RemapKeysSettingName);
|
||||
keyboardManagerState.ClearSingleKeyRemaps();
|
||||
|
||||
if (remapKeysData)
|
||||
{
|
||||
auto inProcessRemapKeys = remapKeysData.GetNamedArray(KeyboardManagerConstants::InProcessRemapKeysSettingName);
|
||||
for (const auto& it : inProcessRemapKeys)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto originalKey = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
|
||||
auto newRemapKey = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName);
|
||||
|
||||
// If remapped to a shortcut
|
||||
if (std::wstring(newRemapKey).find(L";") != std::string::npos)
|
||||
{
|
||||
keyboardManagerState.AddSingleKeyRemap(std::stoul(originalKey.c_str()), Shortcut(newRemapKey.c_str()));
|
||||
}
|
||||
|
||||
// If remapped to a key
|
||||
else
|
||||
{
|
||||
keyboardManagerState.AddSingleKeyRemap(std::stoul(originalKey.c_str()), std::stoul(newRemapKey.c_str()));
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"Improper Key Data JSON. Try the next remap.");
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"Improper JSON format for single key remaps. Skip to next remap type");
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LoadAppSpecificShortcutRemaps(KeyboardManagerState& keyboardManagerState, const json::JsonObject& remapShortcutsData)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
try
|
||||
{
|
||||
auto appSpecificRemapShortcuts = remapShortcutsData.GetNamedArray(KeyboardManagerConstants::AppSpecificRemapShortcutsSettingName);
|
||||
for (const auto& it : appSpecificRemapShortcuts)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto originalKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
|
||||
auto newRemapKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName);
|
||||
auto targetApp = it.GetObjectW().GetNamedString(KeyboardManagerConstants::TargetAppSettingName);
|
||||
|
||||
// If remapped to a shortcut
|
||||
if (std::wstring(newRemapKeys).find(L";") != std::string::npos)
|
||||
{
|
||||
keyboardManagerState.AddAppSpecificShortcut(targetApp.c_str(), Shortcut(originalKeys.c_str()), Shortcut(newRemapKeys.c_str()));
|
||||
}
|
||||
|
||||
// If remapped to a key
|
||||
else
|
||||
{
|
||||
keyboardManagerState.AddAppSpecificShortcut(targetApp.c_str(), Shortcut(originalKeys.c_str()), std::stoul(newRemapKeys.c_str()));
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"Improper Key Data JSON. Try the next shortcut.");
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"Improper JSON format for os level shortcut remaps. Skip to next remap type");
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LoadShortcutRemaps(KeyboardManagerState& keyboardManagerState, const json::JsonObject& jsonData)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
try
|
||||
{
|
||||
auto remapShortcutsData = jsonData.GetNamedObject(KeyboardManagerConstants::RemapShortcutsSettingName);
|
||||
keyboardManagerState.ClearOSLevelShortcuts();
|
||||
keyboardManagerState.ClearAppSpecificShortcuts();
|
||||
if (remapShortcutsData)
|
||||
{
|
||||
// Load os level shortcut remaps
|
||||
try
|
||||
{
|
||||
auto globalRemapShortcuts = remapShortcutsData.GetNamedArray(KeyboardManagerConstants::GlobalRemapShortcutsSettingName);
|
||||
for (const auto& it : globalRemapShortcuts)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto originalKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
|
||||
auto newRemapKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName);
|
||||
|
||||
// If remapped to a shortcut
|
||||
if (std::wstring(newRemapKeys).find(L";") != std::string::npos)
|
||||
{
|
||||
keyboardManagerState.AddOSLevelShortcut(Shortcut(originalKeys.c_str()), Shortcut(newRemapKeys.c_str()));
|
||||
}
|
||||
|
||||
// If remapped to a key
|
||||
else
|
||||
{
|
||||
keyboardManagerState.AddOSLevelShortcut(Shortcut(originalKeys.c_str()), std::stoul(newRemapKeys.c_str()));
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"Improper Key Data JSON. Try the next shortcut.");
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"Improper JSON format for os level shortcut remaps. Skip to next remap type");
|
||||
result = false;
|
||||
}
|
||||
|
||||
// Load app specific shortcut remaps
|
||||
result = result && LoadAppSpecificShortcutRemaps(keyboardManagerState, remapShortcutsData);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"Improper JSON format for shortcut remaps. Skip to next remap type");
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SettingsHelper::LoadSettings(KeyboardManagerState& keyboardManagerState)
|
||||
{
|
||||
Logger::trace(L"SettingsHelper::LoadSettings()");
|
||||
try
|
||||
{
|
||||
PowerToysSettings::PowerToyValues settings = PowerToysSettings::PowerToyValues::load_from_settings_file(KeyboardManagerConstants::ModuleName);
|
||||
auto current_config = settings.get_string_value(KeyboardManagerConstants::ActiveConfigurationSettingName);
|
||||
|
||||
if (!current_config)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
keyboardManagerState.SetCurrentConfigName(*current_config);
|
||||
|
||||
// Read the config file and load the remaps.
|
||||
auto configFile = json::from_file(PTSettingsHelper::get_module_save_folder_location(KeyboardManagerConstants::ModuleName) + L"\\" + *current_config + L".json");
|
||||
if (!configFile)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = LoadSingleKeyRemaps(keyboardManagerState, *configFile);
|
||||
result = result && LoadShortcutRemaps(keyboardManagerState, *configFile);
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"SettingsHelper::LoadSettings() failed");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <keyboardmanager/common/KeyboardManagerState.h>
|
||||
|
||||
class SettingsHelper
|
||||
{
|
||||
public:
|
||||
static bool LoadSettings(KeyboardManagerState& state);
|
||||
};
|
@ -2,15 +2,29 @@
|
||||
#include "Shortcut.h"
|
||||
#include <common/interop/keyboard_layout.h>
|
||||
#include <common/interop/shared_constants.h>
|
||||
#include "ErrorTypes.h"
|
||||
#include "Helpers.h"
|
||||
#include "InputInterface.h"
|
||||
|
||||
|
||||
// Function to split a wstring based on a delimiter and return a vector of split strings
|
||||
std::vector<std::wstring> Shortcut::splitwstring(const std::wstring& input, wchar_t delimiter)
|
||||
{
|
||||
std::wstringstream ss(input);
|
||||
std::wstring item;
|
||||
std::vector<std::wstring> splittedStrings;
|
||||
while (std::getline(ss, item, delimiter))
|
||||
{
|
||||
splittedStrings.push_back(item);
|
||||
}
|
||||
|
||||
return splittedStrings;
|
||||
}
|
||||
|
||||
// Constructor to initialize Shortcut from it's virtual key code string representation.
|
||||
Shortcut::Shortcut(const std::wstring& shortcutVK) :
|
||||
winKey(ModifierKey::Disabled), ctrlKey(ModifierKey::Disabled), altKey(ModifierKey::Disabled), shiftKey(ModifierKey::Disabled), actionKey(NULL)
|
||||
{
|
||||
auto keys = KeyboardManagerHelper::splitwstring(shortcutVK, ';');
|
||||
auto keys = splitwstring(shortcutVK, ';');
|
||||
for (auto it : keys)
|
||||
{
|
||||
auto vkKeyCode = std::stoul(it);
|
||||
@ -75,20 +89,6 @@ void Shortcut::Reset()
|
||||
actionKey = NULL;
|
||||
}
|
||||
|
||||
// Function to return true if the shortcut is valid. A valid shortcut has atleast one modifier, as well as an action key
|
||||
bool Shortcut::IsValidShortcut() const
|
||||
{
|
||||
if (actionKey != NULL)
|
||||
{
|
||||
if (winKey != ModifierKey::Disabled || ctrlKey != ModifierKey::Disabled || altKey != ModifierKey::Disabled || shiftKey != ModifierKey::Disabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Function to return the action key
|
||||
DWORD Shortcut::GetActionKey() const
|
||||
{
|
||||
@ -418,33 +418,6 @@ void Shortcut::ResetKey(const DWORD& input)
|
||||
}
|
||||
}
|
||||
|
||||
// Function to return a vector of hstring for each key in the display order
|
||||
std::vector<winrt::hstring> Shortcut::GetKeyVector(LayoutMap& keyboardMap) const
|
||||
{
|
||||
std::vector<winrt::hstring> keys;
|
||||
if (winKey != ModifierKey::Disabled)
|
||||
{
|
||||
keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(GetWinKey(ModifierKey::Both)).c_str()));
|
||||
}
|
||||
if (ctrlKey != ModifierKey::Disabled)
|
||||
{
|
||||
keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(GetCtrlKey()).c_str()));
|
||||
}
|
||||
if (altKey != ModifierKey::Disabled)
|
||||
{
|
||||
keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(GetAltKey()).c_str()));
|
||||
}
|
||||
if (shiftKey != ModifierKey::Disabled)
|
||||
{
|
||||
keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(GetShiftKey()).c_str()));
|
||||
}
|
||||
if (actionKey != NULL)
|
||||
{
|
||||
keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(actionKey).c_str()));
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
// Function to return the string representation of the shortcut in virtual key codes appended in a string by ";" separator.
|
||||
winrt::hstring Shortcut::ToHstringVK() const
|
||||
{
|
||||
@ -842,55 +815,3 @@ int Shortcut::GetCommonModifiersCount(const Shortcut& input) const
|
||||
|
||||
return commonElements;
|
||||
}
|
||||
|
||||
// Function to check if the two shortcuts are equal or cover the same set of keys. Return value depends on type of overlap
|
||||
KeyboardManagerHelper::ErrorType Shortcut::DoKeysOverlap(const Shortcut& first, const Shortcut& second)
|
||||
{
|
||||
if (first.IsValidShortcut() && second.IsValidShortcut())
|
||||
{
|
||||
// If the shortcuts are equal
|
||||
if (first == second)
|
||||
{
|
||||
return KeyboardManagerHelper::ErrorType::SameShortcutPreviouslyMapped;
|
||||
}
|
||||
// action keys match
|
||||
else if (first.actionKey == second.actionKey)
|
||||
{
|
||||
// corresponding modifiers are either both disabled or both not disabled - this ensures that both match in types of modifiers i.e. Ctrl(l/r/c) Shift (l/r/c) A matches Ctrl(l/r/c) Shift (l/r/c) A
|
||||
if (((first.winKey != ModifierKey::Disabled && second.winKey != ModifierKey::Disabled) || (first.winKey == ModifierKey::Disabled && second.winKey == ModifierKey::Disabled)) &&
|
||||
((first.ctrlKey != ModifierKey::Disabled && second.ctrlKey != ModifierKey::Disabled) || (first.ctrlKey == ModifierKey::Disabled && second.ctrlKey == ModifierKey::Disabled)) &&
|
||||
((first.altKey != ModifierKey::Disabled && second.altKey != ModifierKey::Disabled) || (first.altKey == ModifierKey::Disabled && second.altKey == ModifierKey::Disabled)) &&
|
||||
((first.shiftKey != ModifierKey::Disabled && second.shiftKey != ModifierKey::Disabled) || (first.shiftKey == ModifierKey::Disabled && second.shiftKey == ModifierKey::Disabled)))
|
||||
{
|
||||
// If one of the modifier is common
|
||||
if ((first.winKey == ModifierKey::Both || second.winKey == ModifierKey::Both) ||
|
||||
(first.ctrlKey == ModifierKey::Both || second.ctrlKey == ModifierKey::Both) ||
|
||||
(first.altKey == ModifierKey::Both || second.altKey == ModifierKey::Both) ||
|
||||
(first.shiftKey == ModifierKey::Both || second.shiftKey == ModifierKey::Both))
|
||||
{
|
||||
return KeyboardManagerHelper::ErrorType::ConflictingModifierShortcut;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return KeyboardManagerHelper::ErrorType::NoError;
|
||||
}
|
||||
|
||||
// Function to check if the shortcut is illegal (i.e. Win+L or Ctrl+Alt+Del)
|
||||
KeyboardManagerHelper::ErrorType Shortcut::IsShortcutIllegal() const
|
||||
{
|
||||
// Win+L
|
||||
if (winKey != ModifierKey::Disabled && ctrlKey == ModifierKey::Disabled && altKey == ModifierKey::Disabled && shiftKey == ModifierKey::Disabled && actionKey == 0x4C)
|
||||
{
|
||||
return KeyboardManagerHelper::ErrorType::WinL;
|
||||
}
|
||||
|
||||
// Ctrl+Alt+Del
|
||||
if (winKey == ModifierKey::Disabled && ctrlKey != ModifierKey::Disabled && altKey != ModifierKey::Disabled && shiftKey == ModifierKey::Disabled && actionKey == VK_DELETE)
|
||||
{
|
||||
return KeyboardManagerHelper::ErrorType::CtrlAltDel;
|
||||
}
|
||||
|
||||
return KeyboardManagerHelper::ErrorType::NoError;
|
||||
}
|
||||
|
@ -7,21 +7,20 @@ namespace KeyboardManagerInput
|
||||
class InputInterface;
|
||||
}
|
||||
class LayoutMap;
|
||||
namespace KeyboardManagerHelper
|
||||
{
|
||||
enum class ErrorType;
|
||||
}
|
||||
|
||||
class Shortcut
|
||||
{
|
||||
private:
|
||||
// Function to split a wstring based on a delimiter and return a vector of split strings
|
||||
std::vector<std::wstring> splitwstring(const std::wstring& input, wchar_t delimiter);
|
||||
|
||||
public:
|
||||
ModifierKey winKey;
|
||||
ModifierKey ctrlKey;
|
||||
ModifierKey altKey;
|
||||
ModifierKey shiftKey;
|
||||
DWORD actionKey;
|
||||
|
||||
public:
|
||||
// By default create an empty shortcut
|
||||
Shortcut() :
|
||||
winKey(ModifierKey::Disabled), ctrlKey(ModifierKey::Disabled), altKey(ModifierKey::Disabled), shiftKey(ModifierKey::Disabled), actionKey(NULL)
|
||||
@ -111,9 +110,6 @@ public:
|
||||
// Function to reset all the keys in the shortcut
|
||||
void Reset();
|
||||
|
||||
// Function to return true if the shortcut is valid. A valid shortcut has atleast one modifier, as well as an action key
|
||||
bool IsValidShortcut() const;
|
||||
|
||||
// Function to return the action key
|
||||
DWORD GetActionKey() const;
|
||||
|
||||
@ -150,9 +146,6 @@ public:
|
||||
// Function to return the string representation of the shortcut in virtual key codes appended in a string by ";" separator.
|
||||
winrt::hstring ToHstringVK() const;
|
||||
|
||||
// Function to return a vector of hstring for each key in the display order
|
||||
std::vector<winrt::hstring> GetKeyVector(LayoutMap& keyboardMap) const;
|
||||
|
||||
// Function to return a vector of key codes in the display order
|
||||
std::vector<DWORD> GetKeyCodes();
|
||||
|
||||
@ -167,12 +160,6 @@ public:
|
||||
|
||||
// Function to get the number of modifiers that are common between the current shortcut and the shortcut in the argument
|
||||
int GetCommonModifiersCount(const Shortcut& input) const;
|
||||
|
||||
// Function to check if the two shortcuts are equal or cover the same set of keys. Return value depends on type of overlap
|
||||
static KeyboardManagerHelper::ErrorType DoKeysOverlap(const Shortcut& first, const Shortcut& second);
|
||||
|
||||
// Function to check if the shortcut is illegal (i.e. Win+L or Ctrl+Alt+Del)
|
||||
KeyboardManagerHelper::ErrorType IsShortcutIllegal() const;
|
||||
};
|
||||
|
||||
using KeyShortcutUnion = std::variant<DWORD, Shortcut>;
|
||||
|
@ -2,17 +2,8 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <winrt/base.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Graphics.h>
|
||||
#include <winrt/Windows.system.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include "winrt/Windows.Foundation.Numerics.h"
|
||||
#include <winrt/windows.ui.xaml.controls.h>
|
||||
#include "winrt/Windows.UI.Core.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stdlib.h>
|
||||
#include <ProjectTelemetry.h>
|
||||
|
||||
using namespace winrt;
|
||||
using namespace Windows::Foundation::Numerics;
|
||||
using namespace Windows::UI::Xaml;
|
||||
using namespace Windows::UI::Xaml::Controls;
|
||||
#include <ProjectTelemetry.h>
|
Loading…
Reference in New Issue
Block a user