mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-23 19:49:43 +01:00
## Summary of the Pull Request - #39572 updated check-spelling but ignored: > 🐣 Breaking Changes [Code Scanning action requires a Code Scanning Ruleset](https://github.com/check-spelling/check-spelling/wiki/Breaking-Change:-Code-Scanning-action-requires-a-Code-Scanning-Ruleset) If you use SARIF reporting, then instead of the workflow yielding an ❌ when it fails, it will rely on [github-advanced-security 🤖](https://github.com/apps/github-advanced-security) to report the failure. You will need to adjust your checks for PRs. This means that check-spelling hasn't been properly doing its job 😦. I'm sorry, I should have pushed a thing to this repo earlier,... Anyway, as with most refreshes, this comes with a number of fixes, some are fixes for typos that snuck in before the 0.0.25 upgrade, some are for things that snuck in after, some are based on new rules in spell-check-this, and some are hand written patterns based on running through this repository a few times. About the 🐣 **breaking change**: someone needs to create a ruleset for this repository (see [Code Scanning action requires a Code Scanning Ruleset: Sample ruleset ](https://github.com/check-spelling/check-spelling/wiki/Breaking-Change:-Code-Scanning-action-requires-a-Code-Scanning-Ruleset#sample-ruleset)). The alternative to adding a ruleset is to change the condition to not use sarif for this repository. In general, I think the github integration from sarif is prettier/more helpful, so I think that it's the better choice. You can see an example of it working in: - https://github.com/check-spelling-sandbox/PowerToys/pull/23 --------- Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> Co-authored-by: Mike Griese <migrie@microsoft.com> Co-authored-by: Dustin L. Howett <dustin@howett.net>
375 lines
13 KiB
C++
375 lines
13 KiB
C++
#include "pch.h"
|
|
#include <array>
|
|
#include <algorithm>
|
|
|
|
#include "keyboard_layout_impl.h"
|
|
#include "shared_constants.h"
|
|
|
|
constexpr DWORD numpadOriginBit = 1ull << 31;
|
|
|
|
LayoutMap::LayoutMap() :
|
|
impl(new LayoutMap::LayoutMapImpl())
|
|
{
|
|
}
|
|
|
|
LayoutMap::~LayoutMap()
|
|
{
|
|
delete impl;
|
|
}
|
|
|
|
void LayoutMap::UpdateLayout()
|
|
{
|
|
impl->UpdateLayout();
|
|
}
|
|
|
|
std::wstring LayoutMap::GetKeyName(DWORD key)
|
|
{
|
|
return impl->GetKeyName(key);
|
|
}
|
|
|
|
DWORD LayoutMap::GetKeyFromName(const std::wstring& name)
|
|
{
|
|
auto list = impl->GetKeyNameList(false);
|
|
for (const auto& [value, key] : list)
|
|
{
|
|
if (key == name)
|
|
return value;
|
|
}
|
|
return {};
|
|
}
|
|
|
|
std::vector<DWORD> LayoutMap::GetKeyCodeList(const bool isShortcut)
|
|
{
|
|
return impl->GetKeyCodeList(isShortcut);
|
|
}
|
|
|
|
std::vector<std::pair<DWORD, std::wstring>> LayoutMap::GetKeyNameList(const bool isShortcut)
|
|
{
|
|
return impl->GetKeyNameList(isShortcut);
|
|
}
|
|
|
|
// Function to return the unicode string name of the key
|
|
std::wstring LayoutMap::LayoutMapImpl::GetKeyName(DWORD key)
|
|
{
|
|
std::wstring result = L"Undefined";
|
|
std::lock_guard<std::mutex> lock(keyboardLayoutMap_mutex);
|
|
UpdateLayout();
|
|
|
|
auto it = keyboardLayoutMap.find(key);
|
|
if (it != keyboardLayoutMap.end())
|
|
{
|
|
result = it->second;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool mapKeycodeToUnicode(const int vCode, HKL layout, const BYTE* keyState, std::array<wchar_t, 3>& outBuffer)
|
|
{
|
|
// Get the scan code from the virtual key code
|
|
const UINT scanCode = MapVirtualKeyExW(vCode, MAPVK_VK_TO_VSC, layout);
|
|
// Get the unicode representation from the virtual key code and scan code pair
|
|
const UINT wFlags = 1 << 2; // If bit 2 is set, keyboard state is not changed (Windows 10, version 1607 and newer)
|
|
const int result = ToUnicodeEx(vCode, scanCode, keyState, outBuffer.data(), static_cast<int>(outBuffer.size()), wFlags, layout);
|
|
return result != 0;
|
|
}
|
|
|
|
// Update Keyboard layout according to input locale identifier
|
|
void LayoutMap::LayoutMapImpl::UpdateLayout()
|
|
{
|
|
// Get keyboard layout for current thread
|
|
const HKL layout = GetKeyboardLayout(0);
|
|
if (layout == previousLayout)
|
|
{
|
|
return;
|
|
}
|
|
previousLayout = layout;
|
|
if (!isKeyCodeListGenerated)
|
|
{
|
|
unicodeKeys.clear();
|
|
unknownKeys.clear();
|
|
}
|
|
|
|
std::array<BYTE, 256> btKeys = { 0 };
|
|
// Only set the Caps Lock key to on for the key names in uppercase
|
|
btKeys[VK_CAPITAL] = 1;
|
|
|
|
// Iterate over all the virtual key codes. virtual key 0 is not used
|
|
for (int i = 1; i < 256; i++)
|
|
{
|
|
std::array<wchar_t, 3> szBuffer = { 0 };
|
|
if (mapKeycodeToUnicode(i, layout, btKeys.data(), szBuffer))
|
|
{
|
|
keyboardLayoutMap[i] = szBuffer.data();
|
|
if (!isKeyCodeListGenerated)
|
|
{
|
|
unicodeKeys[i] = szBuffer.data();
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Store the virtual key code as string
|
|
std::wstring vk = L"VK ";
|
|
vk += std::to_wstring(i);
|
|
keyboardLayoutMap[i] = vk;
|
|
if (!isKeyCodeListGenerated)
|
|
{
|
|
unknownKeys[i] = vk;
|
|
}
|
|
}
|
|
|
|
// Override special key names like Shift, Ctrl, etc. because they don't have unicode mappings and key names like Enter, Space as they appear as "\r", " "
|
|
// To do: localization
|
|
keyboardLayoutMap[VK_CANCEL] = L"Break";
|
|
keyboardLayoutMap[VK_BACK] = L"Backspace";
|
|
keyboardLayoutMap[VK_TAB] = L"Tab";
|
|
keyboardLayoutMap[VK_CLEAR] = L"Clear";
|
|
keyboardLayoutMap[VK_SHIFT] = L"Shift";
|
|
keyboardLayoutMap[VK_CONTROL] = L"Ctrl";
|
|
keyboardLayoutMap[VK_MENU] = L"Alt";
|
|
keyboardLayoutMap[VK_PAUSE] = L"Pause";
|
|
keyboardLayoutMap[VK_CAPITAL] = L"Caps Lock";
|
|
keyboardLayoutMap[VK_ESCAPE] = L"Esc";
|
|
keyboardLayoutMap[VK_SPACE] = L"Space";
|
|
|
|
keyboardLayoutMap[VK_LEFT] = L"Left";
|
|
keyboardLayoutMap[VK_RIGHT] = L"Right";
|
|
keyboardLayoutMap[VK_UP] = L"Up";
|
|
keyboardLayoutMap[VK_DOWN] = L"Down";
|
|
keyboardLayoutMap[VK_INSERT] = L"Insert";
|
|
keyboardLayoutMap[VK_DELETE] = L"Delete";
|
|
keyboardLayoutMap[VK_PRIOR] = L"PgUp";
|
|
keyboardLayoutMap[VK_NEXT] = L"PgDn";
|
|
keyboardLayoutMap[VK_HOME] = L"Home";
|
|
keyboardLayoutMap[VK_END] = L"End";
|
|
keyboardLayoutMap[VK_RETURN] = L"Enter";
|
|
|
|
keyboardLayoutMap[VK_LEFT | numpadOriginBit] = L"Left (Numpad)";
|
|
keyboardLayoutMap[VK_RIGHT | numpadOriginBit] = L"Right (Numpad)";
|
|
keyboardLayoutMap[VK_UP | numpadOriginBit] = L"Up (Numpad)";
|
|
keyboardLayoutMap[VK_DOWN | numpadOriginBit] = L"Down (Numpad)";
|
|
keyboardLayoutMap[VK_INSERT | numpadOriginBit] = L"Insert (Numpad)";
|
|
keyboardLayoutMap[VK_DELETE | numpadOriginBit] = L"Delete (Numpad)";
|
|
keyboardLayoutMap[VK_PRIOR | numpadOriginBit] = L"PgUp (Numpad)";
|
|
keyboardLayoutMap[VK_NEXT | numpadOriginBit] = L"PgDn (Numpad)";
|
|
keyboardLayoutMap[VK_HOME | numpadOriginBit] = L"Home (Numpad)";
|
|
keyboardLayoutMap[VK_END | numpadOriginBit] = L"End (Numpad)";
|
|
keyboardLayoutMap[VK_RETURN | numpadOriginBit] = L"Enter (Numpad)";
|
|
keyboardLayoutMap[VK_DIVIDE | numpadOriginBit] = L"/ (Numpad)";
|
|
|
|
keyboardLayoutMap[VK_SUBTRACT] = L"- (Subtract)";
|
|
keyboardLayoutMap[VK_SELECT] = L"Select";
|
|
keyboardLayoutMap[VK_PRINT] = L"Print";
|
|
keyboardLayoutMap[VK_EXECUTE] = L"Execute";
|
|
keyboardLayoutMap[VK_SNAPSHOT] = L"Print Screen";
|
|
keyboardLayoutMap[VK_HELP] = L"Help";
|
|
keyboardLayoutMap[VK_LWIN] = L"Win (Left)";
|
|
keyboardLayoutMap[VK_RWIN] = L"Win (Right)";
|
|
keyboardLayoutMap[VK_APPS] = L"Apps/Menu";
|
|
keyboardLayoutMap[VK_SLEEP] = L"Sleep";
|
|
keyboardLayoutMap[VK_NUMPAD0] = L"NumPad 0";
|
|
keyboardLayoutMap[VK_NUMPAD1] = L"NumPad 1";
|
|
keyboardLayoutMap[VK_NUMPAD2] = L"NumPad 2";
|
|
keyboardLayoutMap[VK_NUMPAD3] = L"NumPad 3";
|
|
keyboardLayoutMap[VK_NUMPAD4] = L"NumPad 4";
|
|
keyboardLayoutMap[VK_NUMPAD5] = L"NumPad 5";
|
|
keyboardLayoutMap[VK_NUMPAD6] = L"NumPad 6";
|
|
keyboardLayoutMap[VK_NUMPAD7] = L"NumPad 7";
|
|
keyboardLayoutMap[VK_NUMPAD8] = L"NumPad 8";
|
|
keyboardLayoutMap[VK_NUMPAD9] = L"NumPad 9";
|
|
keyboardLayoutMap[VK_SEPARATOR] = L"Separator";
|
|
keyboardLayoutMap[VK_F1] = L"F1";
|
|
keyboardLayoutMap[VK_F2] = L"F2";
|
|
keyboardLayoutMap[VK_F3] = L"F3";
|
|
keyboardLayoutMap[VK_F4] = L"F4";
|
|
keyboardLayoutMap[VK_F5] = L"F5";
|
|
keyboardLayoutMap[VK_F6] = L"F6";
|
|
keyboardLayoutMap[VK_F7] = L"F7";
|
|
keyboardLayoutMap[VK_F8] = L"F8";
|
|
keyboardLayoutMap[VK_F9] = L"F9";
|
|
keyboardLayoutMap[VK_F10] = L"F10";
|
|
keyboardLayoutMap[VK_F11] = L"F11";
|
|
keyboardLayoutMap[VK_F12] = L"F12";
|
|
keyboardLayoutMap[VK_F13] = L"F13";
|
|
keyboardLayoutMap[VK_F14] = L"F14";
|
|
keyboardLayoutMap[VK_F15] = L"F15";
|
|
keyboardLayoutMap[VK_F16] = L"F16";
|
|
keyboardLayoutMap[VK_F17] = L"F17";
|
|
keyboardLayoutMap[VK_F18] = L"F18";
|
|
keyboardLayoutMap[VK_F19] = L"F19";
|
|
keyboardLayoutMap[VK_F20] = L"F20";
|
|
keyboardLayoutMap[VK_F21] = L"F21";
|
|
keyboardLayoutMap[VK_F22] = L"F22";
|
|
keyboardLayoutMap[VK_F23] = L"F23";
|
|
keyboardLayoutMap[VK_F24] = L"F24";
|
|
keyboardLayoutMap[VK_NUMLOCK] = L"Num Lock";
|
|
keyboardLayoutMap[VK_SCROLL] = L"Scroll Lock";
|
|
keyboardLayoutMap[VK_LSHIFT] = L"Shift (Left)";
|
|
keyboardLayoutMap[VK_RSHIFT] = L"Shift (Right)";
|
|
keyboardLayoutMap[VK_LCONTROL] = L"Ctrl (Left)";
|
|
keyboardLayoutMap[VK_RCONTROL] = L"Ctrl (Right)";
|
|
keyboardLayoutMap[VK_LMENU] = L"Alt (Left)";
|
|
keyboardLayoutMap[VK_RMENU] = L"Alt (Right)";
|
|
keyboardLayoutMap[VK_BROWSER_BACK] = L"Browser Back";
|
|
keyboardLayoutMap[VK_BROWSER_FORWARD] = L"Browser Forward";
|
|
keyboardLayoutMap[VK_BROWSER_REFRESH] = L"Browser Refresh";
|
|
keyboardLayoutMap[VK_BROWSER_STOP] = L"Browser Stop";
|
|
keyboardLayoutMap[VK_BROWSER_SEARCH] = L"Browser Search";
|
|
keyboardLayoutMap[VK_BROWSER_FAVORITES] = L"Browser Favorites";
|
|
keyboardLayoutMap[VK_BROWSER_HOME] = L"Browser Home";
|
|
keyboardLayoutMap[VK_VOLUME_MUTE] = L"Volume Mute";
|
|
keyboardLayoutMap[VK_VOLUME_DOWN] = L"Volume Down";
|
|
keyboardLayoutMap[VK_VOLUME_UP] = L"Volume Up";
|
|
keyboardLayoutMap[VK_MEDIA_NEXT_TRACK] = L"Next Track";
|
|
keyboardLayoutMap[VK_MEDIA_PREV_TRACK] = L"Previous Track";
|
|
keyboardLayoutMap[VK_MEDIA_STOP] = L"Stop Media";
|
|
keyboardLayoutMap[VK_MEDIA_PLAY_PAUSE] = L"Play/Pause Media";
|
|
keyboardLayoutMap[VK_LAUNCH_MAIL] = L"Start Mail";
|
|
keyboardLayoutMap[VK_LAUNCH_MEDIA_SELECT] = L"Select Media";
|
|
keyboardLayoutMap[VK_LAUNCH_APP1] = L"Start App 1";
|
|
keyboardLayoutMap[VK_LAUNCH_APP2] = L"Start App 2";
|
|
keyboardLayoutMap[VK_PACKET] = L"Packet";
|
|
keyboardLayoutMap[VK_ATTN] = L"Attn";
|
|
keyboardLayoutMap[VK_CRSEL] = L"CrSel";
|
|
keyboardLayoutMap[VK_EXSEL] = L"ExSel";
|
|
keyboardLayoutMap[VK_EREOF] = L"Erase EOF";
|
|
keyboardLayoutMap[VK_PLAY] = L"Play";
|
|
keyboardLayoutMap[VK_ZOOM] = L"Zoom";
|
|
keyboardLayoutMap[VK_PA1] = L"PA1";
|
|
keyboardLayoutMap[VK_OEM_CLEAR] = L"Clear";
|
|
keyboardLayoutMap[0xFF] = L"Undefined";
|
|
keyboardLayoutMap[CommonSharedConstants::VK_WIN_BOTH] = L"Win";
|
|
keyboardLayoutMap[VK_KANA] = L"IME Kana";
|
|
keyboardLayoutMap[VK_HANGEUL] = L"IME Hangeul";
|
|
keyboardLayoutMap[VK_HANGUL] = L"IME Hangul";
|
|
keyboardLayoutMap[VK_IME_ON] = L"IME On";
|
|
keyboardLayoutMap[VK_JUNJA] = L"IME Junja";
|
|
keyboardLayoutMap[VK_FINAL] = L"IME Final";
|
|
keyboardLayoutMap[VK_HANJA] = L"IME Hanja";
|
|
keyboardLayoutMap[VK_KANJI] = L"IME Kanji";
|
|
keyboardLayoutMap[VK_IME_OFF] = L"IME Off";
|
|
keyboardLayoutMap[VK_CONVERT] = L"IME Convert";
|
|
keyboardLayoutMap[VK_NONCONVERT] = L"IME Non-Convert";
|
|
keyboardLayoutMap[VK_ACCEPT] = L"IME Kana";
|
|
keyboardLayoutMap[VK_MODECHANGE] = L"IME Mode Change";
|
|
keyboardLayoutMap[VK_DECIMAL] = L". (Numpad)";
|
|
keyboardLayoutMap[CommonSharedConstants::VK_DISABLED] = L"Disable";
|
|
}
|
|
|
|
// Function to return the list of key codes in the order for the drop down. It creates it if it doesn't exist
|
|
std::vector<DWORD> LayoutMap::LayoutMapImpl::GetKeyCodeList(const bool isShortcut)
|
|
{
|
|
std::lock_guard<std::mutex> lock(keyboardLayoutMap_mutex);
|
|
UpdateLayout();
|
|
std::vector<DWORD> keyCodes;
|
|
if (!isKeyCodeListGenerated)
|
|
{
|
|
// Add character keys
|
|
for (auto& it : unicodeKeys)
|
|
{
|
|
// If it was not renamed with a special name
|
|
if (it.second == keyboardLayoutMap[it.first])
|
|
{
|
|
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)
|
|
if (std::find(keyCodes.begin(), keyCodes.end(), i) == keyCodes.end())
|
|
{
|
|
// If it is any other key but it is not named as VK #
|
|
auto it = unknownKeys.find(i);
|
|
if (it == unknownKeys.end())
|
|
{
|
|
specialKeys.push_back(i);
|
|
}
|
|
else if (unknownKeys[i] != keyboardLayoutMap[i])
|
|
{
|
|
specialKeys.push_back(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add numpad keys
|
|
for (auto it = keyboardLayoutMap.rbegin(); it->first & numpadOriginBit; ++it)
|
|
{
|
|
keyCodes.push_back(it->first);
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
// If it was not renamed with a special name
|
|
if (it.second == keyboardLayoutMap[it.first])
|
|
{
|
|
keyCodes.push_back(it.first);
|
|
}
|
|
}
|
|
keyCodeList = keyCodes;
|
|
isKeyCodeListGenerated = true;
|
|
}
|
|
else
|
|
{
|
|
keyCodes = keyCodeList;
|
|
}
|
|
|
|
// If it is a key list for the shortcut control then we add a "None" key at the start
|
|
if (isShortcut)
|
|
{
|
|
keyCodes.insert(keyCodes.begin(), 0);
|
|
}
|
|
|
|
return keyCodes;
|
|
}
|
|
|
|
std::vector<std::pair<DWORD, std::wstring>> LayoutMap::LayoutMapImpl::GetKeyNameList(const bool isShortcut)
|
|
{
|
|
std::vector<std::pair<DWORD, 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({ 0, L"None" });
|
|
for (int i = 1; i < keyCodes.size(); i++)
|
|
{
|
|
keyNames.push_back({ keyCodes[i], keyboardLayoutMap[keyCodes[i]] });
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < keyCodes.size(); i++)
|
|
{
|
|
keyNames.push_back({ keyCodes[i], keyboardLayoutMap[keyCodes[i]] });
|
|
}
|
|
}
|
|
|
|
return keyNames;
|
|
}
|