Skip to content

Commit

Permalink
Improve warnings for KBM (dev/build-features) (#2386)
Browse files Browse the repository at this point in the history
* Handled invalid input for single key remaps

* Added some functions

* Added better error message functions and finished warnings for edit keyboard

* Updated dropdown order of keys

* Added new warning template for shortcuts

* Added show warning on Apply code

* Removed old flyout code

* Fixed issue where tooltips were replaced on Apply

* Simplified == operator
  • Loading branch information
arjunbalgovind committed Apr 26, 2020
1 parent 7ec8d02 commit 38ecc82
Show file tree
Hide file tree
Showing 15 changed files with 439 additions and 125 deletions.
48 changes: 31 additions & 17 deletions src/common/keyboard_layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,19 +215,6 @@ std::vector<DWORD> LayoutMap::LayoutMapImpl::GetKeyCodeList(const bool isShortcu
std::vector<DWORD> keyCodes;
if (!isKeyCodeListGenerated)
{
// Add modifier keys
keyCodes.push_back(CommonSharedConstants::VK_WIN_BOTH);
keyCodes.push_back(VK_LWIN);
keyCodes.push_back(VK_RWIN);
keyCodes.push_back(VK_CONTROL);
keyCodes.push_back(VK_LCONTROL);
keyCodes.push_back(VK_RCONTROL);
keyCodes.push_back(VK_MENU);
keyCodes.push_back(VK_LMENU);
keyCodes.push_back(VK_RMENU);
keyCodes.push_back(VK_SHIFT);
keyCodes.push_back(VK_LSHIFT);
keyCodes.push_back(VK_RSHIFT);
// Add character keys
for (auto& it : unicodeKeys)
{
Expand All @@ -237,7 +224,23 @@ std::vector<DWORD> LayoutMap::LayoutMapImpl::GetKeyCodeList(const bool isShortcu
keyCodes.push_back(it.first);
}
}

// Add modifier keys in alphabetical order
keyCodes.push_back(VK_MENU);
keyCodes.push_back(VK_LMENU);
keyCodes.push_back(VK_RMENU);
keyCodes.push_back(VK_CONTROL);
keyCodes.push_back(VK_LCONTROL);
keyCodes.push_back(VK_RCONTROL);
keyCodes.push_back(VK_SHIFT);
keyCodes.push_back(VK_LSHIFT);
keyCodes.push_back(VK_RSHIFT);
keyCodes.push_back(CommonSharedConstants::VK_WIN_BOTH);
keyCodes.push_back(VK_LWIN);
keyCodes.push_back(VK_RWIN);

// Add all other special keys
std::vector<DWORD> specialKeys;
for (int i = 1; i < 256; i++)
{
// If it is not already been added (i.e. it was either a modifier or had a unicode representation)
Expand All @@ -247,14 +250,24 @@ std::vector<DWORD> LayoutMap::LayoutMapImpl::GetKeyCodeList(const bool isShortcu
auto it = unknownKeys.find(i);
if (it == unknownKeys.end())
{
keyCodes.push_back(i);
specialKeys.push_back(i);
}
else if (unknownKeys[i] != keyboardLayoutMap[i])
{
keyCodes.push_back(i);
specialKeys.push_back(i);
}
}
}

// Sort the special keys in alphabetical order
std::sort(specialKeys.begin(), specialKeys.end(), [&](const DWORD& lhs, const DWORD& rhs) {
return keyboardLayoutMap[lhs] < keyboardLayoutMap[rhs];
});
for (int i = 0; i < specialKeys.size(); i++)
{
keyCodes.push_back(specialKeys[i]);
}

// Add unknown keys
for (auto& it : unknownKeys)
{
Expand Down Expand Up @@ -285,20 +298,21 @@ std::vector<std::wstring> LayoutMap::LayoutMapImpl::GetKeyNameList(const bool is
{
std::vector<std::wstring> keyNames;
std::vector<DWORD> keyCodes = GetKeyCodeList(isShortcut);
std::lock_guard<std::mutex> lock(keyboardLayoutMap_mutex);
// If it is a key list for the shortcut control then we add a "None" key at the start
if (isShortcut)
{
keyNames.push_back(L"None");
for (int i = 1; i < keyCodes.size(); i++)
{
keyNames.push_back(GetKeyName(keyCodes[i]));
keyNames.push_back(keyboardLayoutMap[keyCodes[i]]);
}
}
else
{
for (int i = 0; i < keyCodes.size(); i++)
{
keyNames.push_back(GetKeyName(keyCodes[i]));
keyNames.push_back(keyboardLayoutMap[keyCodes[i]]);
}
}

Expand Down
72 changes: 71 additions & 1 deletion src/modules/keyboardmanager/common/Helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ namespace KeyboardManagerHelper
}

// Function to return if the key is an extended key which requires the use of the extended key flag
bool isExtendedKey(DWORD key)
bool IsExtendedKey(DWORD key)
{
switch (key)
{
Expand All @@ -79,6 +79,7 @@ namespace KeyboardManagerHelper
return false;
}
}

Collections::IVector<IInspectable> ToBoxValue(const std::vector<std::wstring>& list)
{
Collections::IVector<IInspectable> boxList = single_threaded_vector<IInspectable>();
Expand All @@ -89,4 +90,73 @@ namespace KeyboardManagerHelper

return boxList;
}

// 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_LCONTROL && second == VK_RCONTROL) || (first == VK_LMENU && second == VK_RMENU) || (first == VK_LSHIFT && second == VK_RSHIFT))
{
return ErrorType::NoError;
}
else
{
return ErrorType::ConflictingModifierKey;
}
}
// If no overlap
else
{
return ErrorType::NoError;
}
}

// Function to return the error message
winrt::hstring GetErrorMessage(ErrorType errorType)
{
switch (errorType)
{
case ErrorType::NoError:
return L"Remapping successful";
case ErrorType::SameKeyPreviouslyMapped:
return L"Cannot remap a key more than once";
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";
case ErrorType::MapToSameShortcut:
return L"Cannot remap a shortcut to itself";
case ErrorType::ConflictingModifierShortcut:
return L"Cannot remap this shortcut as it conflicts with another remapped shortcut";
case ErrorType::WinL:
return L"Cannot remap from/to Win L";
case ErrorType::CtrlAltDel:
return L"Cannot remap from/to Ctrl Alt Del";
case ErrorType::RemapUnsuccessful:
return L"Some remappings were not applied";
case ErrorType::SaveFailed:
return L"Failed to save the remappings";
case ErrorType::MissingKey:
return L"Incomplete remapping";
case ErrorType::ShortcutStartWithModifier:
return L"Shortcut must start with a modifier key";
case ErrorType::ShortcutCannotHaveRepeatedModifier:
return L"Shortcut cannot contain a repeated modifier";
case ErrorType::ShortcutAtleast2Keys:
return L"Shortcut must have atleast 2 keys";
case ErrorType::ShortcutOneActionKey:
return L"Shortcut must contain an action key";
case ErrorType::ShortcutNotMoreThanOneActionKey:
return L"Shortcut cannot have more than one action key";
}
}
}
31 changes: 28 additions & 3 deletions src/modules/keyboardmanager/common/Helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,48 @@ namespace KeyboardManagerHelper
Action
};

// Type to store codes for different errors
enum class ErrorType
{
NoError,
SameKeyPreviouslyMapped,
MapToSameKey,
ConflictingModifierKey,
SameShortcutPreviouslyMapped,
MapToSameShortcut,
ConflictingModifierShortcut,
WinL,
CtrlAltDel,
RemapUnsuccessful,
SaveFailed,
MissingKey,
ShortcutStartWithModifier,
ShortcutCannotHaveRepeatedModifier,
ShortcutAtleast2Keys,
ShortcutOneActionKey,
ShortcutNotMoreThanOneActionKey
};

// 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 the next sibling element for an element under a stack panel
winrt::Windows::Foundation::IInspectable getSiblingElement(winrt::Windows::Foundation::IInspectable const& element);

// Function to return if the key is an extended key which requires the use of the extended key flag
bool isExtendedKey(DWORD key);
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 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 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 return the error message
winrt::hstring GetErrorMessage(ErrorType errorType);

// Function to return the list of key name in the order for the drop down based on the key codes
winrt::Windows::Foundation::Collections::IVector<winrt::Windows::Foundation::IInspectable> ToBoxValue(const std::vector<std::wstring>& list);
Expand Down
3 changes: 3 additions & 0 deletions src/modules/keyboardmanager/common/KeyboardManagerConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,7 @@ namespace KeyboardManagerConstants

// Name of the dummy update file.
inline const std::wstring DummyUpdateFileName = L"settings-updated.json";

// Initial value for tooltip
inline const winrt::hstring ToolTipInitialContent = L"Initialised";
}
53 changes: 53 additions & 0 deletions src/modules/keyboardmanager/common/Shortcut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -764,3 +764,56 @@ 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;
}
// If both have win key modifiers and one is the both version then there will be an overlap
else if (first.winKey != ModifierKey::Disabled && second.winKey != ModifierKey::Disabled && (first.winKey == ModifierKey::Both || second.winKey == ModifierKey::Both))
{
return KeyboardManagerHelper::ErrorType::ConflictingModifierShortcut;
}
// If both have ctrl key modifiers and one is the both version then there will be an overlap
else if (first.ctrlKey != ModifierKey::Disabled && second.ctrlKey != ModifierKey::Disabled && (first.ctrlKey == ModifierKey::Both || second.ctrlKey == ModifierKey::Both))
{
return KeyboardManagerHelper::ErrorType::ConflictingModifierShortcut;
}
// If both have alt key modifiers and one is the both version then there will be an overlap
else if (first.altKey != ModifierKey::Disabled && second.altKey != ModifierKey::Disabled && (first.altKey == ModifierKey::Both || second.altKey == ModifierKey::Both))
{
return KeyboardManagerHelper::ErrorType::ConflictingModifierShortcut;
}
// If both have shift key modifiers and one is the both version then there will be an overlap
else if (first.shiftKey != ModifierKey::Disabled && second.shiftKey != ModifierKey::Disabled && (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;
}
12 changes: 12 additions & 0 deletions src/modules/keyboardmanager/common/Shortcut.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ class Shortcut
}
}

// == operator
inline bool operator==(const Shortcut& sc) const
{
return (winKey == sc.winKey && ctrlKey == sc.ctrlKey && altKey == sc.altKey && shiftKey == sc.shiftKey && actionKey == sc.actionKey);
}

// Less than operator must be defined to use with std::map.
inline bool operator<(const Shortcut& sc) const
{
Expand Down Expand Up @@ -168,4 +174,10 @@ class Shortcut

// 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;
};
2 changes: 1 addition & 1 deletion src/modules/keyboardmanager/dll/dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ class KeyboardManager : public PowertoyModuleIface
keyEventArray[index].type = inputType;
keyEventArray[index].ki.wVk = keyCode;
keyEventArray[index].ki.dwFlags = flags;
if (KeyboardManagerHelper::isExtendedKey(keyCode))
if (KeyboardManagerHelper::IsExtendedKey(keyCode))
{
keyEventArray[index].ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
}
Expand Down

0 comments on commit 38ecc82

Please sign in to comment.