mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 02:36:19 +02:00
[Keyboard Manager] Added in Shortcut to Key and Key to Shortcut remapping (#5070)
* Added union class * Added key to shortcut backend implementation * Added tests * Added tests for CapsLock/modifier workaround for key to shortcut * Added correct JSON loading step * Cleaned shortcut remap code to use helper function for modifier keys * Removed RemapKey class * Enable Key to Shortcut in UI along with Type Shortcut in Remap key window * Fixed orphaning and unsuccessful remap dialog * Fixed column width * Renamed second type key button * Fixed Type Shortcut issues * Fixed shortcut to key backend logic and manually tested most scenarios * Added s2k in UI, manually verified its working * Added one more k2s test * Added tests for s2k * Added tests for Caps Lock workaround in shortcut remaps * Fixed formatting * Fixed formatting * Removed safety code since it can cause issues with code generated key up events * Added test for key up scenario * Tweaked warning text * Tweaked text * Tweaked text to fit in two lines * telemetry additions
This commit is contained in:
@@ -138,13 +138,13 @@ namespace KeyboardManagerHelper
|
||||
case ErrorType::NoError:
|
||||
return L"Remapping successful";
|
||||
case ErrorType::SameKeyPreviouslyMapped:
|
||||
return L"Cannot remap a key more than once";
|
||||
return L"Cannot remap a key more than once for the same target app";
|
||||
case ErrorType::MapToSameKey:
|
||||
return L"Cannot remap a key to itself";
|
||||
case ErrorType::ConflictingModifierKey:
|
||||
return L"Cannot remap this key as it conflicts with another remapped key";
|
||||
case ErrorType::SameShortcutPreviouslyMapped:
|
||||
return L"Cannot remap a shortcut more than once";
|
||||
return L"Cannot remap a shortcut more than once for the same target app";
|
||||
case ErrorType::MapToSameShortcut:
|
||||
return L"Cannot remap a shortcut to itself";
|
||||
case ErrorType::ConflictingModifierShortcut:
|
||||
@@ -215,7 +215,7 @@ namespace KeyboardManagerHelper
|
||||
{
|
||||
std::wstring process_path = get_process_path(current_window_handle);
|
||||
process_name = process_path;
|
||||
|
||||
|
||||
// Get process name from path
|
||||
PathStripPath(&process_path[0]);
|
||||
|
||||
@@ -248,4 +248,81 @@ namespace KeyboardManagerHelper
|
||||
|
||||
return process_name;
|
||||
}
|
||||
|
||||
// Function to set key events for modifier keys: When shortcutToCompare is passed (non-empty shortcut), then the key event is sent only if both shortcut's don't have the same modifier key. When keyToBeReleased is passed (non-NULL), then the key event is sent if either the shortcuts don't have the same modfifier or if the shortcutToBeSent's modifier matches the keyToBeReleased
|
||||
void SetModifierKeyEvents(const Shortcut& shortcutToBeSent, const ModifierKey& winKeyInvoked, LPINPUT keyEventArray, int& index, bool isKeyDown, ULONG_PTR extraInfoFlag, const Shortcut& shortcutToCompare, const DWORD& keyToBeReleased)
|
||||
{
|
||||
// If key down is to be sent, send in the order Win, Ctrl, Alt, Shift
|
||||
if (isKeyDown)
|
||||
{
|
||||
// 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 modfifier 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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
// If key up is to be sent, send in the order Shift, Alt, Ctrl, Win
|
||||
else
|
||||
{
|
||||
// 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 modfifier 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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function to filter the key codes for artificial key codes
|
||||
DWORD FilterArtificialKeys(const DWORD& key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
// If a key is remapped to VK_WIN_BOTH, we send VK_LWIN instead
|
||||
case CommonSharedConstants::VK_WIN_BOTH:
|
||||
return VK_LWIN;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
// Function to sort a vector of shortcuts based on it's size
|
||||
void SortShortcutVectorBasedOnSize(std::vector<Shortcut>& shortcutVector)
|
||||
{
|
||||
std::sort(shortcutVector.begin(), shortcutVector.end(), [](Shortcut first, Shortcut second) {
|
||||
return first.Size() > second.Size();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#pragma once
|
||||
#include "Shortcut.h"
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
struct hstring;
|
||||
@@ -88,4 +90,13 @@ namespace KeyboardManagerHelper
|
||||
|
||||
// Function to return the executable name of the application in focus
|
||||
std::wstring GetCurrentApplication(bool keepPath);
|
||||
|
||||
// Function to set key events for modifier keys: When shortcutToCompare is passed (non-empty shortcut), then the key event is sent only if both shortcut's don't have the same modifier key. When keyToBeReleased is passed (non-NULL), then the key event is sent if either the shortcuts don't have the same modfifier or if the shortcutToBeSent's modifier matches the keyToBeReleased
|
||||
void SetModifierKeyEvents(const Shortcut& shortcutToBeSent, const ModifierKey& winKeyInvoked, LPINPUT keyEventArray, int& index, bool isKeyDown, ULONG_PTR extraInfoFlag, const Shortcut& shortcutToCompare = Shortcut(), const DWORD& keyToBeReleased = NULL);
|
||||
|
||||
// Function to filter the key codes for artificial key codes
|
||||
DWORD FilterArtificialKeys(const DWORD& key);
|
||||
|
||||
// Function to sort a vector of shortcuts based on it's size
|
||||
void SortShortcutVectorBasedOnSize(std::vector<Shortcut>& shortcutVector);
|
||||
}
|
||||
@@ -121,6 +121,7 @@
|
||||
<ClCompile Include="trace.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ModifierKey.h" />
|
||||
<ClInclude Include="InputInterface.h" />
|
||||
<ClInclude Include="Helpers.h" />
|
||||
<ClInclude Include="KeyboardManagerConstants.h" />
|
||||
|
||||
@@ -65,6 +65,9 @@
|
||||
<ClInclude Include="InputInterface.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ModifierKey.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace KeyboardManagerConstants
|
||||
|
||||
// String constant for the default app name in Remap shortcuts
|
||||
inline const std::wstring DefaultAppName = L"All Apps";
|
||||
|
||||
|
||||
// String constant to represent no activated application in app-specific shortcuts
|
||||
inline const std::wstring NoActivatedApp = L"";
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "pch.h"
|
||||
#include "KeyboardManagerState.h"
|
||||
#include "Shortcut.h"
|
||||
#include "RemapShortcut.h"
|
||||
#include <../common/settings_helpers.h>
|
||||
#include "KeyDelay.h"
|
||||
#include "Helpers.h"
|
||||
|
||||
// Constructor
|
||||
KeyboardManagerState::KeyboardManagerState() :
|
||||
@@ -103,6 +106,7 @@ void KeyboardManagerState::ClearOSLevelShortcuts()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(osLevelShortcutReMap_mutex);
|
||||
osLevelShortcutReMap.clear();
|
||||
osLevelShortcutReMapSortedKeys.clear();
|
||||
}
|
||||
|
||||
// Function to clear the Keys remapping table.
|
||||
@@ -117,10 +121,11 @@ void KeyboardManagerState::ClearAppSpecificShortcuts()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(appSpecificShortcutReMap_mutex);
|
||||
appSpecificShortcutReMap.clear();
|
||||
appSpecificShortcutReMapSortedKeys.clear();
|
||||
}
|
||||
|
||||
// Function to add a new OS level shortcut remapping
|
||||
bool KeyboardManagerState::AddOSLevelShortcut(const Shortcut& originalSC, const Shortcut& newSC)
|
||||
bool KeyboardManagerState::AddOSLevelShortcut(const Shortcut& originalSC, const std::variant<DWORD, Shortcut>& newSC)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(osLevelShortcutReMap_mutex);
|
||||
|
||||
@@ -132,11 +137,14 @@ bool KeyboardManagerState::AddOSLevelShortcut(const Shortcut& originalSC, const
|
||||
}
|
||||
|
||||
osLevelShortcutReMap[originalSC] = RemapShortcut(newSC);
|
||||
osLevelShortcutReMapSortedKeys.push_back(originalSC);
|
||||
KeyboardManagerHelper::SortShortcutVectorBasedOnSize(osLevelShortcutReMapSortedKeys);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Function to add a new OS level shortcut remapping
|
||||
bool KeyboardManagerState::AddSingleKeyRemap(const DWORD& originalKey, const DWORD& newRemapKey)
|
||||
// Function to add a new single key to key/shortcut remapping
|
||||
bool KeyboardManagerState::AddSingleKeyRemap(const DWORD& originalKey, const std::variant<DWORD, Shortcut>& newRemapKey)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(singleKeyReMap_mutex);
|
||||
|
||||
@@ -152,28 +160,34 @@ bool KeyboardManagerState::AddSingleKeyRemap(const DWORD& originalKey, const DWO
|
||||
}
|
||||
|
||||
// Function to add a new App specific shortcut remapping
|
||||
bool KeyboardManagerState::AddAppSpecificShortcut(const std::wstring& app, const Shortcut& originalSC, const Shortcut& newSC)
|
||||
bool KeyboardManagerState::AddAppSpecificShortcut(const std::wstring& app, const Shortcut& originalSC, const std::variant<DWORD, Shortcut>& newSC)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(appSpecificShortcutReMap_mutex);
|
||||
|
||||
// Check if there are any app specific shortcuts for this app
|
||||
auto appIt = appSpecificShortcutReMap.find(app);
|
||||
if (appIt != appSpecificShortcutReMap.end())
|
||||
{
|
||||
// Check if the shortcut is already remapped
|
||||
auto shortcutIt = appSpecificShortcutReMap[app].find(originalSC);
|
||||
if (shortcutIt != appSpecificShortcutReMap[app].end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -349,10 +363,10 @@ KeyboardManagerHelper::KeyboardHookDecision KeyboardManagerState::DetectSingleRe
|
||||
}
|
||||
|
||||
// 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)
|
||||
KeyboardManagerHelper::KeyboardHookDecision KeyboardManagerState::DetectShortcutUIBackend(LowlevelKeyboardEvent* data, bool isRemapKey)
|
||||
{
|
||||
// Check if the detect shortcut UI window has been activated
|
||||
if (CheckUIState(KeyboardManagerUIState::DetectShortcutWindowActivated))
|
||||
if ((!isRemapKey && CheckUIState(KeyboardManagerUIState::DetectShortcutWindowActivated)) || (isRemapKey && CheckUIState(KeyboardManagerUIState::DetectShortcutWindowInEditKeyboardWindowActivated)))
|
||||
{
|
||||
if (HandleKeyDelayEvent(data))
|
||||
{
|
||||
@@ -375,7 +389,7 @@ KeyboardManagerHelper::KeyboardHookDecision KeyboardManagerState::DetectShortcut
|
||||
}
|
||||
|
||||
// If the detect shortcut UI window is not activated, then clear the shortcut buffer if it isn't empty
|
||||
else
|
||||
else if (!CheckUIState(KeyboardManagerUIState::DetectShortcutWindowActivated) && !CheckUIState(KeyboardManagerUIState::DetectShortcutWindowInEditKeyboardWindowActivated))
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(detectedShortcut_mutex);
|
||||
if (!detectedShortcut.IsEmpty())
|
||||
@@ -385,7 +399,7 @@ KeyboardManagerHelper::KeyboardHookDecision KeyboardManagerState::DetectShortcut
|
||||
}
|
||||
|
||||
// If the settings window is up, shortcut remappings should not be applied, but we should not suppress events in the hook
|
||||
if (CheckUIState(KeyboardManagerUIState::EditShortcutsWindowActivated))
|
||||
if (!isRemapKey && (CheckUIState(KeyboardManagerUIState::EditShortcutsWindowActivated)) || (isRemapKey && uiState == KeyboardManagerUIState::DetectShortcutWindowInEditKeyboardWindowActivated))
|
||||
{
|
||||
return KeyboardManagerHelper::KeyboardHookDecision::SkipHook;
|
||||
}
|
||||
@@ -452,7 +466,18 @@ bool KeyboardManagerState::SaveConfigToFile()
|
||||
{
|
||||
json::JsonObject keys;
|
||||
keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(winrt::to_hstring((unsigned int)it.first)));
|
||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(winrt::to_hstring((unsigned int)it.second)));
|
||||
|
||||
// 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);
|
||||
}
|
||||
@@ -463,12 +488,23 @@ bool KeyboardManagerState::SaveConfigToFile()
|
||||
{
|
||||
json::JsonObject keys;
|
||||
keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(it.first.ToHstringVK()));
|
||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(it.second.targetShortcut.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);
|
||||
}
|
||||
lockOsLevelShortcutReMap.unlock();
|
||||
|
||||
|
||||
std::unique_lock<std::mutex> lockAppSpecificShortcutReMap(appSpecificShortcutReMap_mutex);
|
||||
for (const auto& itApp : appSpecificShortcutReMap)
|
||||
{
|
||||
@@ -477,12 +513,23 @@ bool KeyboardManagerState::SaveConfigToFile()
|
||||
{
|
||||
json::JsonObject keys;
|
||||
keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(itKeys.first.ToHstringVK()));
|
||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(itKeys.second.targetShortcut.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);
|
||||
appSpecificRemapShortcutsArray.Append(keys);
|
||||
}
|
||||
|
||||
}
|
||||
lockAppSpecificShortcutReMap.unlock();
|
||||
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
#pragma once
|
||||
#include "Helpers.h"
|
||||
#include "Shortcut.h"
|
||||
#include "RemapShortcut.h"
|
||||
#include <mutex>
|
||||
#include "KeyboardManagerConstants.h"
|
||||
#include "../common/keyboard_layout.h"
|
||||
#include <functional>
|
||||
#include <interface/lowlevel_keyboard_event_data.h>
|
||||
#include <variant>
|
||||
#include "Shortcut.h"
|
||||
#include "RemapShortcut.h"
|
||||
|
||||
class KeyDelay;
|
||||
|
||||
namespace KeyboardManagerHelper
|
||||
{
|
||||
enum class KeyboardHookDecision;
|
||||
}
|
||||
|
||||
namespace winrt::Windows::UI::Xaml::Controls
|
||||
{
|
||||
struct StackPanel;
|
||||
@@ -22,6 +27,8 @@ enum class KeyboardManagerUIState
|
||||
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
|
||||
@@ -84,7 +91,7 @@ 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, DWORD> singleKeyReMap;
|
||||
std::unordered_map<DWORD, std::variant<DWORD, Shortcut>> singleKeyReMap;
|
||||
std::mutex singleKeyReMap_mutex;
|
||||
|
||||
// Stores keys which need to be changed from toggle behavior to modifier behavior. Eg. Caps Lock
|
||||
@@ -93,10 +100,12 @@ public:
|
||||
|
||||
// Stores the os level shortcut remappings
|
||||
std::map<Shortcut, RemapShortcut> osLevelShortcutReMap;
|
||||
std::vector<Shortcut> osLevelShortcutReMapSortedKeys;
|
||||
std::mutex osLevelShortcutReMap_mutex;
|
||||
|
||||
// Stores the app-specific shortcut remappings. Maps application name to the shortcut map
|
||||
std::map<std::wstring, std::map<Shortcut, RemapShortcut>> appSpecificShortcutReMap;
|
||||
std::map<std::wstring, std::vector<Shortcut>> appSpecificShortcutReMapSortedKeys;
|
||||
std::mutex appSpecificShortcutReMap_mutex;
|
||||
|
||||
// Stores the keyboard layout
|
||||
@@ -129,14 +138,14 @@ public:
|
||||
// Function to clear the App specific shortcut remapping table
|
||||
void ClearAppSpecificShortcuts();
|
||||
|
||||
// Function to add a new single key remapping
|
||||
bool AddSingleKeyRemap(const DWORD& originalKey, const DWORD& newRemapKey);
|
||||
// Function to add a new single key to key remapping
|
||||
bool AddSingleKeyRemap(const DWORD& originalKey, const std::variant<DWORD, Shortcut>& newRemapKey);
|
||||
|
||||
// Function to add a new OS level shortcut remapping
|
||||
bool AddOSLevelShortcut(const Shortcut& originalSC, const Shortcut& newSC);
|
||||
bool AddOSLevelShortcut(const Shortcut& originalSC, const std::variant<DWORD, Shortcut>& newSC);
|
||||
|
||||
// Function to add a new App specific level shortcut remapping
|
||||
bool AddAppSpecificShortcut(const std::wstring& app, const Shortcut& originalSC, const Shortcut& newSC);
|
||||
bool AddAppSpecificShortcut(const std::wstring& app, const Shortcut& originalSC, const std::variant<DWORD, Shortcut>& newSC);
|
||||
|
||||
// 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);
|
||||
@@ -160,7 +169,7 @@ public:
|
||||
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);
|
||||
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.
|
||||
|
||||
10
src/modules/keyboardmanager/common/ModifierKey.h
Normal file
10
src/modules/keyboardmanager/common/ModifierKey.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
// Enum type to store different states of the win key
|
||||
enum class ModifierKey
|
||||
{
|
||||
Disabled,
|
||||
Left,
|
||||
Right,
|
||||
Both
|
||||
};
|
||||
@@ -1,21 +1,22 @@
|
||||
#pragma once
|
||||
#include "Shortcut.h"
|
||||
#include <variant>
|
||||
|
||||
// This class stores all the variables associated with each shortcut remapping
|
||||
class RemapShortcut
|
||||
{
|
||||
public:
|
||||
Shortcut targetShortcut;
|
||||
std::variant<DWORD, Shortcut> targetShortcut;
|
||||
bool isShortcutInvoked;
|
||||
ModifierKey winKeyInvoked;
|
||||
|
||||
RemapShortcut(const Shortcut& sc) :
|
||||
RemapShortcut(const std::variant<DWORD, Shortcut>& sc) :
|
||||
targetShortcut(sc), isShortcutInvoked(false), winKeyInvoked(ModifierKey::Disabled)
|
||||
{
|
||||
}
|
||||
|
||||
RemapShortcut() :
|
||||
isShortcutInvoked(false), winKeyInvoked(ModifierKey::Disabled)
|
||||
targetShortcut(Shortcut()), isShortcutInvoked(false), winKeyInvoked(ModifierKey::Disabled)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "ModifierKey.h"
|
||||
class InputInterface;
|
||||
class LayoutMap;
|
||||
namespace KeyboardManagerHelper
|
||||
@@ -7,15 +7,6 @@ namespace KeyboardManagerHelper
|
||||
enum class ErrorType;
|
||||
}
|
||||
|
||||
// Enum type to store different states of the win key
|
||||
enum class ModifierKey
|
||||
{
|
||||
Disabled,
|
||||
Left,
|
||||
Right,
|
||||
Both
|
||||
};
|
||||
|
||||
class Shortcut
|
||||
{
|
||||
private:
|
||||
|
||||
@@ -30,34 +30,40 @@ void Trace::EnableKeyboardManager(const bool enabled) noexcept
|
||||
}
|
||||
|
||||
// Log number of key remaps when the user uses Edit Keyboard and saves settings
|
||||
void Trace::KeyRemapCount(const DWORD count) noexcept
|
||||
void Trace::KeyRemapCount(const DWORD keyToKeyCount, const DWORD keyToShortcutCount) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"KeyboardManager_KeyRemapCount",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingValue(count, "KeyRemapCount"));
|
||||
TraceLoggingValue(keyToKeyCount + keyToShortcutCount, "KeyRemapCount"),
|
||||
TraceLoggingValue(keyToKeyCount, "KeyToKeyRemapCount"),
|
||||
TraceLoggingValue(keyToShortcutCount, "KeyToShortcutRemapCount"));
|
||||
}
|
||||
|
||||
// Log number of os level shortcut remaps when the user uses Edit Shortcuts and saves settings
|
||||
void Trace::OSLevelShortcutRemapCount(const DWORD count) noexcept
|
||||
void Trace::OSLevelShortcutRemapCount(const DWORD shortcutToShortcutCount, const DWORD shortcutToKeyCount) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"KeyboardManager_OSLevelShortcutRemapCount",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingValue(count, "OSLevelShortcutRemapCount"));
|
||||
TraceLoggingValue(shortcutToShortcutCount + shortcutToKeyCount, "OSLevelShortcutRemapCount"),
|
||||
TraceLoggingValue(shortcutToShortcutCount, "OSLevelShortcutToShortcutRemapCount"),
|
||||
TraceLoggingValue(shortcutToKeyCount, "OSLevelShortcutToKeyRemapCount"));
|
||||
}
|
||||
|
||||
// Log number of app specific shortcut remaps when the user uses Edit Shortcuts and saves settings
|
||||
void Trace::AppSpecificShortcutRemapCount(const DWORD count) noexcept
|
||||
void Trace::AppSpecificShortcutRemapCount(const DWORD shortcutToShortcutCount, const DWORD shortcutToKeyCount) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"KeyboardManager_AppSpecificShortcutRemapCount",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingValue(count, "AppSpecificShortcutRemapCount"));
|
||||
TraceLoggingValue(shortcutToShortcutCount + shortcutToKeyCount, "AppSpecificShortcutRemapCount"),
|
||||
TraceLoggingValue(shortcutToShortcutCount, "AppSpecificShortcutToShortcutRemapCount"),
|
||||
TraceLoggingValue(shortcutToKeyCount, "AppSpecificShortcutToKeyRemapCount"));
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ public:
|
||||
static void EnableKeyboardManager(const bool enabled) noexcept;
|
||||
|
||||
// Log number of key remaps when the user uses Edit Keyboard and saves settings
|
||||
static void KeyRemapCount(const DWORD count) noexcept;
|
||||
static void KeyRemapCount(const DWORD keyToKeyCount, const DWORD keyToShortcutCount) noexcept;
|
||||
|
||||
// Log number of os level shortcut remaps when the user uses Edit Shortcuts and saves settings
|
||||
static void OSLevelShortcutRemapCount(const DWORD count) noexcept;
|
||||
static void OSLevelShortcutRemapCount(const DWORD shortcutToShortcutCount, const DWORD shortcutToKeyCount) noexcept;
|
||||
|
||||
// Log number of app specific shortcut remaps when the user uses Edit Shortcuts and saves settings
|
||||
static void AppSpecificShortcutRemapCount(const DWORD count) noexcept;
|
||||
static void AppSpecificShortcutRemapCount(const DWORD shortcutToShortcutCount, const DWORD shortcutToKeyCount) noexcept;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user