Skip to content
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

Add VS Code keys and improve keybinding documentation #4392

Merged
merged 13 commits into from
Feb 4, 2020
120 changes: 57 additions & 63 deletions doc/cascadia/SettingsSchema.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,69 +90,63 @@ Properties listed below are specific to each custom key binding.
| -------- | ---- | ----------- | ----------- |
| `command` | _Required_ | String | The command executed when the associated key bindings are pressed. |
| `keys` | _Required_ | Array[String] | Defines the key combinations used to call the command. |

### Implemented Commands

Commands listed below are per the implementation in [`src/cascadia/TerminalApp/AppKeyBindingsSerialization.cpp`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/AppKeyBindingsSerialization.cpp)

- copy
- copyTextWithoutNewlines
- paste
- newTab
- openNewTabDropdown
- duplicateTab
- newTabProfile0
- newTabProfile1
- newTabProfile2
- newTabProfile3
- newTabProfile4
- newTabProfile5
- newTabProfile6
- newTabProfile7
- newTabProfile8
- closeWindow
- closeTab
- closePane
- switchToTab
- nextTab
- prevTab
- increaseFontSize
- decreaseFontSize
- resetFontSize
- scrollUp
- scrollDown
- scrollUpPage
- scrollDownPage
- switchToTab0
- switchToTab1
- switchToTab2
- switchToTab3
- switchToTab4
- switchToTab5
- switchToTab6
- switchToTab7
- switchToTab8
- openSettings
- splitPane
- resizePaneLeft
- resizePaneRight
- resizePaneUp
- resizePaneDown
- moveFocusLeft
- moveFocusRight
- moveFocusUp
- moveFocusDown
- toggleFullscreen
- find

## Example Keys
- ctrl+1
- ctrl+plus
- alt+-
- shift+numpad_1
- ctrL+shift+numpad_plus
- ctrl+pgdn
- ctrl+alt+shift+pgup
| `action` | Optional | String | Adds additional functionality to certain commands. |

### Implemented Commands and Actions

Commands listed below are per the implementation in [`src/cascadia/TerminalApp/AppKeyBindingsSerialization.cpp`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/AppKeyBindingsSerialization.cpp).

Keybindings can be structured in the following manners:

For commands without actions:
<br>
`{ "command": "commandName", "keys": [ "modifiers+keys" ] }`

For commands with actions:
<br>
`{ "command": { "action": "commandName", "actionName": "actionArguments" }, "keys": ["modifiers+keys"] }`

| Command | Command Description | Action | Action Arguments | Action Desciption |
| ------- | ------------------- | ------ | ---------------- | ----------------- |
| closePane | Close the active pane. | | | |
| closeTab | Close the current tab. | | | |
| closeWindow | Close the current window and all tabs within it. | | | |
| copy | Make a duplicate of the selected content. | `trimWhitespace` | boolean | |
| decreaseFontSize | Make the text smaller by one delta. | `delta` | integer | Amount of size decrease per command invocation. |
| duplicateTab | Make a copy and open the current tab. | | | |
| find | Open the search dialog box. | | | |
| increaseFontSize | Make the text larger by one delta. | `delta` | integer | Amount of size increase per command invocation. |
| moveFocus | Focus on a different pane depending on direction. | `direction` | `left`, `right`, `up`, `down` | Direction which the focus will move. |
| newTab | Create a new tab. | - `commandLine`<br>- `startingDirectory`<br>- `tabTitle`<br>- `index`<br>- `profile` | - string<br>- string<br>- string<br>- integer<br>- string | - Executable run within the tab.<br>- Directory in which the tab will open.<br>- Title of the new tab.<br>- Profile that will open based on its position in the dropdown (starting at 0).<br>- Profile that will open based on its GUID or name. |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we mention that by default, we open a tab with the default profile. Also, same problem as above: which args are required and what do they default to. This one is probably the most complicated one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC, none of these args are required.

| nextTab | Open the tab to the right of the current one. | | | |
| openNewTabDropdown | Open the dropdown menu. | | | |
| openSettings | Open the settings file. | | | |
| paste | Insert the content saved on the clipboard into the selected space. | | | |
| prevTab | Open the tab to the left of the current one. | | | |
| resetFontSize | Reset the text size to the default value. | | | |
| resizePane | Change the size of the active pane. | `direction` | `left`, `right`, `up`, `down` | Direction which the pane will be resized. |
| scrollDown | Move the screen down. | | | |
| scrollUp | Move the screen up. | | | |
| scrollUpPage | Move the screen up a whole page. | | | |
| scrollDownPage | Move the screen down a whole page. | | | |
| splitPane | Separate the active pane into two. | - `split`<br>- `commandLine`<br>- `startingDirectory`<br>- `tabTitle`<br>- `index`<br>- `profile` | - `vertical`, `horizontal`, `auto`<br>- string<br>- string<br>- string<br>- integer<br>- string | - How the pane will split. `auto` will split in the direction that provides the most surface area.<br>- Executable run within the pane.<br>- Directory in which the pane will open.<br>- Title of the tab when the new pane is focused.<br>- Profile that will open based on its position in the dropdown (starting at 0).<br>- Profile that will open based on its GUID or name. |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separate the active pane into two.
False.

Also, this will have similar problems to newTab

| switchToTab | Open a specific tab dependending on index. | `index` | integer | Tab that will open based on its position in the tab bar (starting at 0). |
| toggleFullscreen | Switch between fullscreen and default window sizes. | | | |
| unbound | Unbind the associated keys from any command. | | | |

### Accepted Modifiers and Keys

#### Modifiers
`Ctrl+`, `Shift+`, `Alt+`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a note here...

  • You can bind a command to a key-combo without modifiers, but that's not a good idea...
  • We recommend not binding to ctrl + <key> because it may conflict with common keybindings from command line applications. (i.e.: CTRL+C should not be bound to stuff willy nilly, or else you won't be able to stop processes)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this is necessary?


#### Keys
| Type | Keys |
| ---- | ---- |
| Function and Alphanumeric Keys | `f1-f24`, `a-z`, `0-9` |
| Symbols | ``` ` ```, `-`, `=`, `[`, `]`, `\`, `;`, `'`, `,`, `.`, `/` |
| Arrow Keys | `down`, `left`, `right`, `up`, `pagedown`, `pageup`, `pgdn`, `pgup`, `end`, `home`, `plus` |
| Action Keys | `tab`, `enter`, `esc`, `escape`, `space`, `backspace`, `delete`, `insert` |
| Numpad Keys | `numpad_0-numpad_9`, `numpad0-numpad9`, `numpad_add`, `numpad_plus`, `numpad_decimal`, `numpad_period`, `numpad_divide`, `numpad_minus`, `numpad_subtract`, `numpad_multiply` |

## Background Images and Icons
Some Terminal settings allow you to specify custom background images and icons. It is recommended that custom images and icons are stored in system-provided folders and are referred to using the correct [URI Schemes](https://docs.microsoft.com/en-us/windows/uwp/app-resources/uri-schemes). URI Schemes provide a way to reference files independent of their physical paths (which may change in the future).
Expand Down
158 changes: 87 additions & 71 deletions src/cascadia/TerminalApp/KeyChordSerialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,62 +13,78 @@ static constexpr std::wstring_view ALT_KEY{ L"alt" };
static constexpr int MAX_CHORD_PARTS = 4;

// clang-format off
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" }
static const std::unordered_map<std::wstring_view, int32_t> vkeyNamePairs {
{ L"backspace" , VK_BACK },
{ L"tab" , VK_TAB },
{ L"enter" , VK_RETURN },
{ L"esc" , VK_ESCAPE },
{ L"escape" , VK_ESCAPE },
{ L"space" , VK_SPACE },
{ L"pgup" , VK_PRIOR },
{ L"pageup" , VK_PRIOR },
{ L"pgdn" , VK_NEXT },
{ L"pagedown" , VK_NEXT },
{ L"end" , VK_END },
{ L"home" , VK_HOME },
{ L"left" , VK_LEFT },
{ L"up" , VK_UP },
{ L"right" , VK_RIGHT },
{ L"down" , VK_DOWN },
{ L"insert" , VK_INSERT },
{ L"delete" , VK_DELETE },
{ L"numpad_0" , VK_NUMPAD0 },
{ L"numpad0" , VK_NUMPAD0 },
{ L"numpad_1" , VK_NUMPAD1 },
{ L"numpad1" , VK_NUMPAD1 },
{ L"numpad_2" , VK_NUMPAD2 },
{ L"numpad2" , VK_NUMPAD2 },
{ L"numpad_3" , VK_NUMPAD3 },
{ L"numpad3" , VK_NUMPAD3 },
{ L"numpad_4" , VK_NUMPAD4 },
{ L"numpad4" , VK_NUMPAD4 },
{ L"numpad_5" , VK_NUMPAD5 },
{ L"numpad5" , VK_NUMPAD5 },
{ L"numpad_6" , VK_NUMPAD6 },
{ L"numpad6" , VK_NUMPAD6 },
{ L"numpad_7" , VK_NUMPAD7 },
{ L"numpad7" , VK_NUMPAD7 },
{ L"numpad_8" , VK_NUMPAD8 },
{ L"numpad8" , VK_NUMPAD8 },
{ L"numpad_9" , VK_NUMPAD9 },
{ L"numpad9" , VK_NUMPAD9 },
{ L"numpad_multiply" , VK_MULTIPLY },
{ L"numpad_plus" , VK_ADD },
{ L"numpad_add" , VK_ADD },
{ L"numpad_minus" , VK_SUBTRACT },
{ L"numpad_subtract" , VK_SUBTRACT },
{ L"numpad_period" , VK_DECIMAL },
{ L"numpad_decimal" , VK_DECIMAL },
{ L"numpad_divide" , VK_DIVIDE },
{ L"f1" , VK_F1 },
{ L"f2" , VK_F2 },
{ L"f3" , VK_F3 },
{ L"f4" , VK_F4 },
{ L"f5" , VK_F5 },
{ L"f6" , VK_F6 },
{ L"f7" , VK_F7 },
{ L"f8" , VK_F8 },
{ L"f9" , VK_F9 },
{ L"f10" , VK_F10 },
{ L"f11" , VK_F11 },
{ L"f12" , VK_F12 },
{ L"f13" , VK_F13 },
{ L"f14" , VK_F14 },
{ L"f15" , VK_F15 },
{ L"f16" , VK_F16 },
{ L"f17" , VK_F17 },
{ L"f18" , VK_F18 },
{ L"f19" , VK_F19 },
{ L"f20" , VK_F20 },
{ L"f21" , VK_F21 },
{ L"f22" , VK_F22 },
{ L"f23" , VK_F23 },
{ L"f24" , VK_F24 },
{ L"plus" , VK_OEM_PLUS }
};
// clang-format on

Expand Down Expand Up @@ -151,19 +167,13 @@ winrt::Microsoft::Terminal::Settings::KeyChord KeyChordSerialization::FromString

// If we didn't find the key with a quick lookup, search the
// table to see if we have a matching name.
if (!foundKey)
if (!foundKey && vkeyNamePairs.find(part) != vkeyNamePairs.end())
{
for (const auto& pair : vkeyNamePairs)
{
if (pair.second == part)
{
vkey = pair.first;
foundKey = true;
break;
}
}
vkey = vkeyNamePairs.at(part);
foundKey = true;
break;
}

// If we haven't found a key, attempt a keyboard mapping
if (!foundKey && part.size() == 1)
{
Expand Down Expand Up @@ -240,12 +250,18 @@ winrt::hstring KeyChordSerialization::ToString(const KeyChord& chord)
}
else
{
if (vkeyNamePairs.find(vkey) != vkeyNamePairs.end())
bool foundKey = false;
for (const auto& pair : vkeyNamePairs)
{
buffer += vkeyNamePairs.at(vkey);
serializedSuccessfully = true;
if (pair.second == vkey)
{
buffer += pair.first;
serializedSuccessfully = true;
foundKey = true;
break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm glad you made the serialization more expensive honestly - we shouldn't be using it often. parsing happens all the dang time.

}
}
else
if (!foundKey)
{
auto mappedChar = MapVirtualKeyW(vkey, MAPVK_VK_TO_CHAR);
if (mappedChar != 0)
Expand Down