mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-12-05 04:39:08 +08:00
Change behavior on Edit Keyboard screen to be physical keys (#2666)
* Commented out ToggleToMod and AppSpecific function calls * Added logic to make sure key remaps don't occur on Edit Keyboard Window * Changed behavior such that remappings only apply after window is closed
This commit is contained in:
parent
855f3d74fe
commit
c4f884f104
@ -37,6 +37,14 @@ namespace KeyboardManagerHelper
|
||||
ShortcutNotMoreThanOneActionKey
|
||||
};
|
||||
|
||||
// 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);
|
||||
|
||||
|
@ -20,18 +20,18 @@ KeyboardManagerState::~KeyboardManagerState()
|
||||
}
|
||||
}
|
||||
|
||||
// Function to check the if the UI state matches the argument state. For states with activated windows it also checks if the window is in focus.
|
||||
// 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)
|
||||
if (uiState == KeyboardManagerUIState::Deactivated || uiState == KeyboardManagerUIState::EditKeyboardWindowActivated || uiState == KeyboardManagerUIState::EditShortcutsWindowActivated)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// If the UI state is activated then we also have to ensure that the UI window is in focus.
|
||||
// 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())
|
||||
{
|
||||
@ -254,14 +254,14 @@ void KeyboardManagerState::ResetDetectedShortcutKey(DWORD 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.
|
||||
bool KeyboardManagerState::DetectSingleRemapKeyUIBackend(LowlevelKeyboardEvent* data)
|
||||
KeyboardManagerHelper::KeyboardHookDecision KeyboardManagerState::DetectSingleRemapKeyUIBackend(LowlevelKeyboardEvent* data)
|
||||
{
|
||||
// Check if the detect key UI window has been activated
|
||||
if (CheckUIState(KeyboardManagerUIState::DetectSingleKeyRemapWindowActivated))
|
||||
{
|
||||
if (HandleKeyDelayEvent(data))
|
||||
{
|
||||
return true;
|
||||
return KeyboardManagerHelper::KeyboardHookDecision::Suppress;
|
||||
}
|
||||
// detect the key if it is pressed down
|
||||
if (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN)
|
||||
@ -270,21 +270,27 @@ bool KeyboardManagerState::DetectSingleRemapKeyUIBackend(LowlevelKeyboardEvent*
|
||||
}
|
||||
|
||||
// Suppress the keyboard event
|
||||
return true;
|
||||
return KeyboardManagerHelper::KeyboardHookDecision::Suppress;
|
||||
}
|
||||
|
||||
return false;
|
||||
// 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.
|
||||
bool KeyboardManagerState::DetectShortcutUIBackend(LowlevelKeyboardEvent* data)
|
||||
KeyboardManagerHelper::KeyboardHookDecision KeyboardManagerState::DetectShortcutUIBackend(LowlevelKeyboardEvent* data)
|
||||
{
|
||||
// Check if the detect shortcut UI window has been activated
|
||||
if (CheckUIState(KeyboardManagerUIState::DetectShortcutWindowActivated))
|
||||
{
|
||||
if (HandleKeyDelayEvent(data))
|
||||
{
|
||||
return true;
|
||||
return KeyboardManagerHelper::KeyboardHookDecision::Suppress;
|
||||
}
|
||||
|
||||
// Add the key if it is pressed down
|
||||
@ -299,7 +305,7 @@ bool KeyboardManagerState::DetectShortcutUIBackend(LowlevelKeyboardEvent* data)
|
||||
}
|
||||
|
||||
// Suppress the keyboard event
|
||||
return true;
|
||||
return KeyboardManagerHelper::KeyboardHookDecision::Suppress;
|
||||
}
|
||||
|
||||
// If the detect shortcut UI window is not activated, then clear the shortcut buffer if it isn't empty
|
||||
@ -312,7 +318,13 @@ bool KeyboardManagerState::DetectShortcutUIBackend(LowlevelKeyboardEvent* data)
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
// 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))
|
||||
{
|
||||
return KeyboardManagerHelper::KeyboardHookDecision::SkipHook;
|
||||
}
|
||||
|
||||
return KeyboardManagerHelper::KeyboardHookDecision::ContinueExec;
|
||||
}
|
||||
|
||||
void KeyboardManagerState::RegisterKeyDelay(
|
||||
|
@ -19,8 +19,12 @@ 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 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
|
||||
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
|
||||
@ -100,7 +104,7 @@ public:
|
||||
// Function to reset the UI state members
|
||||
void ResetUIState();
|
||||
|
||||
// Function to check the if the UI state matches the argument state. For states with activated windows it also checks if the window is in focus.
|
||||
// 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
|
||||
@ -140,10 +144,10 @@ public:
|
||||
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.
|
||||
bool DetectSingleRemapKeyUIBackend(LowlevelKeyboardEvent* data);
|
||||
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.
|
||||
bool DetectShortcutUIBackend(LowlevelKeyboardEvent* data);
|
||||
KeyboardManagerHelper::KeyboardHookDecision DetectShortcutUIBackend(LowlevelKeyboardEvent* data);
|
||||
|
||||
// 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.
|
||||
|
@ -345,10 +345,15 @@ public:
|
||||
intptr_t HandleKeyboardHookEvent(LowlevelKeyboardEvent* data) noexcept
|
||||
{
|
||||
// If the Detect Key Window is currently activated, then suppress the keyboard event
|
||||
if (keyboardManagerState.DetectSingleRemapKeyUIBackend(data))
|
||||
KeyboardManagerHelper::KeyboardHookDecision singleKeyRemapUIDetected = keyboardManagerState.DetectSingleRemapKeyUIBackend(data);
|
||||
if (singleKeyRemapUIDetected == KeyboardManagerHelper::KeyboardHookDecision::Suppress)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (singleKeyRemapUIDetected == KeyboardManagerHelper::KeyboardHookDecision::SkipHook)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Remap a key
|
||||
intptr_t SingleKeyRemapResult = HandleSingleKeyRemapEvent(data);
|
||||
@ -360,28 +365,33 @@ public:
|
||||
}
|
||||
|
||||
// If the Detect Shortcut Window is currently activated, then suppress the keyboard event
|
||||
if (keyboardManagerState.DetectShortcutUIBackend(data))
|
||||
KeyboardManagerHelper::KeyboardHookDecision shortcutUIDetected = keyboardManagerState.DetectShortcutUIBackend(data);
|
||||
if (shortcutUIDetected == KeyboardManagerHelper::KeyboardHookDecision::Suppress)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Remap a key to behave like a modifier instead of a toggle
|
||||
intptr_t SingleKeyToggleToModResult = HandleSingleKeyToggleToModEvent(data);
|
||||
|
||||
// Handle an app-specific shortcut remapping
|
||||
intptr_t AppSpecificShortcutRemapResult = HandleAppSpecificShortcutRemapEvent(data);
|
||||
|
||||
// If an app-specific shortcut is remapped then the os-level shortcut remapping should be suppressed.
|
||||
if (AppSpecificShortcutRemapResult == 1)
|
||||
else if (shortcutUIDetected == KeyboardManagerHelper::KeyboardHookDecision::SkipHook)
|
||||
{
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//// Remap a key to behave like a modifier instead of a toggle
|
||||
//intptr_t SingleKeyToggleToModResult = HandleSingleKeyToggleToModEvent(data);
|
||||
|
||||
//// Handle an app-specific shortcut remapping
|
||||
//intptr_t AppSpecificShortcutRemapResult = HandleAppSpecificShortcutRemapEvent(data);
|
||||
|
||||
//// If an app-specific shortcut is remapped then the os-level shortcut remapping should be suppressed.
|
||||
//if (AppSpecificShortcutRemapResult == 1)
|
||||
//{
|
||||
// return 1;
|
||||
//}
|
||||
|
||||
// Handle an os-level shortcut remapping
|
||||
intptr_t OSLevelShortcutRemapResult = HandleOSLevelShortcutRemapEvent(data);
|
||||
|
||||
// If any of the supported types of remappings took place, then suppress the key event
|
||||
if ((SingleKeyRemapResult + SingleKeyToggleToModResult + OSLevelShortcutRemapResult + AppSpecificShortcutRemapResult) > 0)
|
||||
if ((SingleKeyRemapResult + OSLevelShortcutRemapResult) > 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
@ -150,6 +150,9 @@ void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan
|
||||
// Vector to store dynamically allocated control objects to avoid early destruction
|
||||
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);
|
||||
|
||||
// Load existing remaps into UI
|
||||
std::unique_lock<std::mutex> lock(keyboardManagerState.singleKeyReMap_mutex);
|
||||
std::unordered_map<DWORD, DWORD> singleKeyRemapCopy = keyboardManagerState.singleKeyReMap;
|
||||
@ -328,6 +331,7 @@ void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan
|
||||
hWndXamlIslandEditKeyboardWindow = nullptr;
|
||||
hwndLock.lock();
|
||||
hwndEditKeyboardNativeWindow = nullptr;
|
||||
keyboardManagerState.ResetUIState();
|
||||
|
||||
// Cannot be done in WM_DESTROY because that causes crashes due to fatal app exit
|
||||
xamlBridge.ClearXamlIslands();
|
||||
|
@ -146,6 +146,9 @@ void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMa
|
||||
// Vector to store dynamically allocated control objects to avoid early destruction
|
||||
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);
|
||||
|
||||
// Load existing shortcuts into UI
|
||||
std::unique_lock<std::mutex> lock(keyboardManagerState.osLevelShortcutReMap_mutex);
|
||||
for (const auto& it : keyboardManagerState.osLevelShortcutReMap)
|
||||
@ -252,6 +255,7 @@ void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMa
|
||||
hWndXamlIslandEditShortcutsWindow = nullptr;
|
||||
hwndLock.lock();
|
||||
hwndEditShortcutsNativeWindow = nullptr;
|
||||
keyboardManagerState.ResetUIState();
|
||||
|
||||
// Cannot be done in WM_DESTROY because that causes crashes due to fatal app exit
|
||||
xamlBridge.ClearXamlIslands();
|
||||
|
@ -178,6 +178,8 @@ void ShortcutControl::createDetectShortcutWindow(winrt::Windows::Foundation::IIn
|
||||
|
||||
// Reset the keyboard manager UI state
|
||||
keyboardManagerState.ResetUIState();
|
||||
// Revert UI state back to Edit Shortcut window
|
||||
keyboardManagerState.SetUIState(KeyboardManagerUIState::EditShortcutsWindowActivated, EditShortcutsWindowHandle);
|
||||
unregisterKeys();
|
||||
detectShortcutBox.Hide();
|
||||
};
|
||||
@ -225,6 +227,8 @@ void ShortcutControl::createDetectShortcutWindow(winrt::Windows::Foundation::IIn
|
||||
cancelButton.Click([detectShortcutBox, unregisterKeys, &keyboardManagerState](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
// Reset the keyboard manager UI state
|
||||
keyboardManagerState.ResetUIState();
|
||||
// Revert UI state back to Edit Shortcut window
|
||||
keyboardManagerState.SetUIState(KeyboardManagerUIState::EditShortcutsWindowActivated, EditShortcutsWindowHandle);
|
||||
unregisterKeys();
|
||||
detectShortcutBox.Hide();
|
||||
});
|
||||
@ -240,6 +244,8 @@ void ShortcutControl::createDetectShortcutWindow(winrt::Windows::Foundation::IIn
|
||||
});
|
||||
|
||||
keyboardManagerState.ResetUIState();
|
||||
// Revert UI state back to Edit Shortcut window
|
||||
keyboardManagerState.SetUIState(KeyboardManagerUIState::EditShortcutsWindowActivated, EditShortcutsWindowHandle);
|
||||
unregisterKeys();
|
||||
},
|
||||
nullptr);
|
||||
|
@ -154,6 +154,8 @@ 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);
|
||||
unregisterKeys();
|
||||
detectRemapKeyBox.Hide();
|
||||
};
|
||||
@ -199,6 +201,8 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
|
||||
cancelButton.Click([detectRemapKeyBox, unregisterKeys, &keyboardManagerState](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
// Reset the keyboard manager UI state
|
||||
keyboardManagerState.ResetUIState();
|
||||
// Revert UI state back to Edit Keyboard window
|
||||
keyboardManagerState.SetUIState(KeyboardManagerUIState::EditKeyboardWindowActivated, EditKeyboardWindowHandle);
|
||||
unregisterKeys();
|
||||
detectRemapKeyBox.Hide();
|
||||
});
|
||||
@ -214,6 +218,8 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
|
||||
});
|
||||
|
||||
keyboardManagerState.ResetUIState();
|
||||
// Revert UI state back to Edit Keyboard window
|
||||
keyboardManagerState.SetUIState(KeyboardManagerUIState::EditKeyboardWindowActivated, EditKeyboardWindowHandle);
|
||||
unregisterKeys();
|
||||
},
|
||||
nullptr);
|
||||
|
Loading…
Reference in New Issue
Block a user