mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-04 02:06:36 +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:
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user