-
Notifications
You must be signed in to change notification settings - Fork 9.1k
Support remapping keybindings #748
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
ed657a0
Add support for serializing keybindings
zadjii-msft d3b9fa1
This is close, but at some point we lose the keybindings when they ge…
zadjii-msft 82f4fff
Fix actually loading the keys
zadjii-msft 0e3a197
Don't serialize over the unordered_map
zadjii-msft 66592b5
Clean up for PR
zadjii-msft 23e7859
Merge remote-tracking branch 'origin/master' into dev/migrie/f/keybin…
zadjii-msft 8727085
Some PR nits
zadjii-msft 4b75c85
well that was easier than expected
zadjii-msft 3eaabfa
* use a constexpr wstring_view
zadjii-msft 7aee31a
Move the serialization of keychords into a seperate file.
zadjii-msft f13d343
Some minor PR nits
zadjii-msft 6b7c16b
Merge remote-tracking branch 'origin/master' into dev/migrie/f/keybin…
zadjii-msft File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,249 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT license. | ||
|
|
||
| #include "pch.h" | ||
| #include "KeyChordSerialization.h" | ||
|
|
||
| using namespace winrt::Microsoft::Terminal::Settings; | ||
|
|
||
| static constexpr std::wstring_view CTRL_KEY{ L"ctrl" }; | ||
| static constexpr std::wstring_view SHIFT_KEY{ L"shift" }; | ||
| static constexpr std::wstring_view ALT_KEY{ L"alt" }; | ||
|
|
||
| static constexpr int MAX_CHORD_PARTS = 4; | ||
|
|
||
| static const std::unordered_map<int32_t, std::wstring_view> vkeyNamePairs { | ||
| { VK_BACK , L"backspace"}, | ||
| { VK_TAB , L"tab"}, | ||
| { VK_RETURN , L"enter" }, | ||
| { VK_ESCAPE , L"esc" }, | ||
| { VK_SPACE , L"space" }, | ||
| { VK_PRIOR , L"pgup" }, | ||
| { VK_NEXT , L"pgdn" }, | ||
| { VK_END , L"end" }, | ||
| { VK_HOME , L"home" }, | ||
| { VK_LEFT , L"left" }, | ||
| { VK_UP , L"up" }, | ||
| { VK_RIGHT , L"right" }, | ||
| { VK_DOWN , L"down" }, | ||
| { VK_INSERT , L"insert" }, | ||
| { VK_DELETE , L"delete" }, | ||
| { VK_NUMPAD0 , L"numpad_0" }, | ||
| { VK_NUMPAD1 , L"numpad_1" }, | ||
| { VK_NUMPAD2 , L"numpad_2" }, | ||
| { VK_NUMPAD3 , L"numpad_3" }, | ||
| { VK_NUMPAD4 , L"numpad_4" }, | ||
| { VK_NUMPAD5 , L"numpad_5" }, | ||
| { VK_NUMPAD6 , L"numpad_6" }, | ||
| { VK_NUMPAD7 , L"numpad_7" }, | ||
| { VK_NUMPAD8 , L"numpad_8" }, | ||
| { VK_NUMPAD9 , L"numpad_9" }, | ||
| { VK_MULTIPLY , L"numpad_multiply" }, | ||
| { VK_ADD , L"numpad_plus" }, | ||
| { VK_SUBTRACT , L"numpad_minus" }, | ||
| { VK_DECIMAL , L"numpad_period" }, | ||
| { VK_DIVIDE , L"numpad_divide" }, | ||
| { VK_F1 , L"f1" }, | ||
| { VK_F2 , L"f2" }, | ||
| { VK_F3 , L"f3" }, | ||
| { VK_F4 , L"f4" }, | ||
| { VK_F5 , L"f5" }, | ||
| { VK_F6 , L"f6" }, | ||
| { VK_F7 , L"f7" }, | ||
| { VK_F8 , L"f8" }, | ||
| { VK_F9 , L"f9" }, | ||
| { VK_F10 , L"f10" }, | ||
| { VK_F11 , L"f11" }, | ||
| { VK_F12 , L"f12" }, | ||
| { VK_F13 , L"f13" }, | ||
| { VK_F14 , L"f14" }, | ||
| { VK_F15 , L"f15" }, | ||
| { VK_F16 , L"f16" }, | ||
| { VK_F17 , L"f17" }, | ||
| { VK_F18 , L"f18" }, | ||
| { VK_F19 , L"f19" }, | ||
| { VK_F20 , L"f20" }, | ||
| { VK_F21 , L"f21" }, | ||
| { VK_F22 , L"f22" }, | ||
| { VK_F23 , L"f23" }, | ||
| { VK_F24 , L"f24" }, | ||
| { VK_OEM_PLUS , L"plus" }, | ||
| { VK_OEM_COMMA , L"," }, | ||
| { VK_OEM_MINUS , L"-" }, | ||
| { VK_OEM_PERIOD , L"." } | ||
| // TODO: | ||
| // These all look like they'd be good keybindings, but change based on keyboard | ||
| // layout. How do we deal with that? | ||
| // #define VK_OEM_NEC_EQUAL 0x92 // '=' key on numpad | ||
| // #define VK_OEM_1 0xBA // ';:' for US | ||
| // #define VK_OEM_2 0xBF // '/?' for US | ||
| // #define VK_OEM_3 0xC0 // '`~' for US | ||
| // #define VK_OEM_4 0xDB // '[{' for US | ||
| // #define VK_OEM_5 0xDC // '\|' for US | ||
| // #define VK_OEM_6 0xDD // ']}' for US | ||
| // #define VK_OEM_7 0xDE // ''"' for US | ||
| }; | ||
|
|
||
| // Function Description: | ||
| // - Deserializes the given string into a new KeyChord instance. If this | ||
| // fails to translate the string into a keychord, it will throw a | ||
| // hresult_invalid_argument exception. | ||
| // - The string should fit the format "[ctrl+][alt+][shift+]<keyName>", | ||
| // where each modifier is optional, and keyName is either one of the | ||
| // names listed in the vkeyNamePairs vector above, or is one of 0-9a-zA-Z. | ||
| // Arguments: | ||
| // - hstr: the string to parse into a keychord. | ||
| // Return Value: | ||
| // - a newly constructed KeyChord | ||
| winrt::Microsoft::Terminal::Settings::KeyChord KeyChordSerialization::FromString(const winrt::hstring& hstr) | ||
| { | ||
| std::wstring wstr{ hstr }; | ||
|
|
||
| // Split the string on '+' | ||
| std::wstring temp; | ||
| std::vector<std::wstring> parts; | ||
| std::wstringstream wss(wstr); | ||
|
|
||
| while(std::getline(wss, temp, L'+')) | ||
| { | ||
| parts.push_back(temp); | ||
|
|
||
| // If we have > 4, something's wrong. | ||
| if (parts.size() > MAX_CHORD_PARTS) | ||
| { | ||
| throw winrt::hresult_invalid_argument(); | ||
| } | ||
| } | ||
|
|
||
| KeyModifiers modifiers = KeyModifiers::None; | ||
| int32_t vkey = 0; | ||
|
|
||
| // Look for ctrl, shift, alt. Anything else might be a key | ||
| for (const auto& part : parts) | ||
| { | ||
| std::wstring lowercase = part; | ||
| std::transform(lowercase.begin(), lowercase.end(), lowercase.begin(), std::towlower); | ||
| if (lowercase == CTRL_KEY) | ||
| { | ||
| modifiers |= KeyModifiers::Ctrl; | ||
| } | ||
| else if (lowercase == ALT_KEY) | ||
| { | ||
| modifiers |= KeyModifiers::Alt; | ||
| } | ||
| else if (lowercase == SHIFT_KEY) | ||
| { | ||
| modifiers |= KeyModifiers::Shift; | ||
| } | ||
| else | ||
| { | ||
| bool foundKey = false; | ||
| // For potential keys, look through the pairs of strings and vkeys | ||
| if (part.size() == 1) | ||
| { | ||
| const wchar_t wch = part.at(0); | ||
| // Quick lookup: ranges of vkeys that correlate directly to a key. | ||
| if (wch >= L'0' && wch <= L'9') | ||
| { | ||
| vkey = static_cast<int32_t>(wch); | ||
| foundKey = true; | ||
| } | ||
| else if (wch >= L'a' && wch <= L'z') | ||
| { | ||
| // subtract 0x20 to shift to uppercase | ||
| vkey = static_cast<int32_t>(wch - 0x20); | ||
| foundKey = true; | ||
| } | ||
| else if (wch >= L'A' && wch <= L'Z') | ||
| { | ||
| vkey = static_cast<int32_t>(wch); | ||
| foundKey = true; | ||
| } | ||
| } | ||
|
|
||
| // If we didn't find the key with a quick lookup, search the | ||
| // table to see if we have a matching name. | ||
| if (!foundKey) | ||
| { | ||
| for (const auto& pair : vkeyNamePairs) | ||
| { | ||
| if (pair.second == part) | ||
| { | ||
| vkey = pair.first; | ||
| foundKey = true; | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // If we weren't able to find a match, throw an exception. | ||
| if (!foundKey) | ||
| { | ||
| throw winrt::hresult_invalid_argument(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return winrt::Microsoft::Terminal::Settings::KeyChord{ modifiers, vkey }; | ||
| } | ||
|
|
||
| // Function Description: | ||
| // - Serialize this keychord into a string represenation. | ||
| // - The string will fit the format "[ctrl+][alt+][shift+]<keyName>", | ||
| // where each modifier is optional, and keyName is either one of the | ||
| // names listed in the vkeyNamePairs vector above, or is one of 0-9a-z. | ||
| // Return Value: | ||
| // - a string which is an equivalent serialization of this object. | ||
| winrt::hstring KeyChordSerialization::ToString(const KeyChord& chord) | ||
| { | ||
| bool serializedSuccessfully = false; | ||
| const auto modifiers = chord.Modifiers(); | ||
| const auto vkey = chord.Vkey(); | ||
|
|
||
| std::wstring buffer{ L"" }; | ||
|
|
||
| // Add modifiers | ||
| if (WI_IsFlagSet(modifiers, KeyModifiers::Ctrl)) | ||
| { | ||
| buffer += CTRL_KEY; | ||
| buffer += L"+"; | ||
| } | ||
| if (WI_IsFlagSet(modifiers, KeyModifiers::Alt)) | ||
| { | ||
| buffer += ALT_KEY; | ||
| buffer += L"+"; | ||
| } | ||
| if (WI_IsFlagSet(modifiers, KeyModifiers::Shift)) | ||
| { | ||
| buffer += SHIFT_KEY; | ||
| buffer += L"+"; | ||
| } | ||
|
|
||
| // Quick lookup: ranges of vkeys that correlate directly to a key. | ||
| if (vkey >= L'0' && vkey <= L'9') | ||
| { | ||
| buffer += std::wstring(1, static_cast<wchar_t>(vkey)); | ||
| serializedSuccessfully = true; | ||
| } | ||
| else if (vkey >= L'A' && vkey <= L'Z') | ||
| { | ||
| // add 0x20 to shift to lowercase | ||
| buffer += std::wstring(1, static_cast<wchar_t>(vkey + 0x20)); | ||
| serializedSuccessfully = true; | ||
| } | ||
| else | ||
| { | ||
| if (vkeyNamePairs.find(vkey) != vkeyNamePairs.end()) | ||
| { | ||
| buffer += vkeyNamePairs.at(vkey); | ||
| serializedSuccessfully = true; | ||
| } | ||
| } | ||
|
|
||
| if (!serializedSuccessfully) | ||
| { | ||
| buffer = L""; | ||
| } | ||
|
|
||
| return winrt::hstring{ buffer }; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT license. | ||
|
|
||
| #pragma once | ||
| #include <winrt/Microsoft.Terminal.Settings.h> | ||
|
|
||
| class KeyChordSerialization final | ||
| { | ||
| public: | ||
| static winrt::Microsoft::Terminal::Settings::KeyChord FromString(const winrt::hstring& str); | ||
| static winrt::hstring ToString(const winrt::Microsoft::Terminal::Settings::KeyChord& chord); | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.