Add support for arbitrary args in keybindings (#3391)
## Summary of the Pull Request Enables the user to provide arbitrary argument values to shortcut actions through a new `args` member of keybindings. For some keybindings, like `NewTabWithProfile<N>`, we previously needed 9 different `ShortcutAction`s, one for each value of `Index`. If a user wanted to have a `NewTabWithProfile11` keybinding, that was simply impossible. Now that the args are in their own separate json object, each binding can accept any number of arbitrary argument values. So instead of: ```json { "command": "newTab", "keys": ["ctrl+shift+t"] }, { "command": "newTabProfile0", "keys": ["ctrl+shift+1"] }, { "command": "newTabProfile1", "keys": ["ctrl+shift+2"] }, { "command": "newTabProfile2", "keys": ["ctrl+shift+3"] }, { "command": "newTabProfile3", "keys": ["ctrl+shift+4"] }, ``` We can now use: ```json { "command": "newTab", "keys": ["ctrl+shift+t"] }, { "command": { "action": "newTab", "index": 0 }, "keys": ["ctrl+shift+1"] }, { "command": { "action": "newTab", "index": 1 }, "keys": ["ctrl+shift+2"] }, { "command": { "action": "newTab", "index": 2 }, "keys": ["ctrl+shift+3"] }, ``` Initially, this does seem more verbose. However, for cases where there are multiple args, or there's a large range of values for the args, this will quickly become a more powerful system of expressing keybindings. The "legacy" keybindings are _left in_ in this PR. They have helper methods to generate appropriate `IActionArgs` values. Prior to releasing 1.0, I think we should remove them, if only to remove some code bloat. ## References See [the spec](https://github.com/microsoft/terminal/blob/master/doc/specs/%231142%20-%20Keybinding%20Arguments.md) for more details. This is part two of the implementation, part one was #2446 ## PR Checklist * [x] Closes #1142 * [x] I work here * [x] Tests added/passed * [x] Schema updated ## Validation Steps Performed * Ran Tests * Removed the legacy keybindings from the `defaults.json`, everything still works * Tried leaving the legacy keybingings in my `profiles.json`, everything still works. ------------------------------------------------- * this is a start, but there's a weird linker bug if I take the SetKeybinding(ShortcutAction, KeyChord) implementation out, which I don't totally understand * a good old-fashioned clean will fix that right up * all these things work * hey this actually _functionally_ works * Mostly cleanup and completion of implementation * Hey I bet we could just make NewTab the handler for NewTabWithProfile * Start writing tests for Keybinding args * Add tests * Revert a bad sln change, and clean out dead code * Change to include "command" as a single object This is a change to make @dhowett-msft happy. Changes the args to be a part of the "command" object, as opposed to an object on their own. EX: ```jsonc // Old style { "command": "switchToTab0", "keys": ["ctrl+1"] }, { "command": { "action": "switchToTab", "index": 0 }, "keys": ["ctrl+alt+1"] }, // new style { "command": "switchToTab0", "keys": ["ctrl+1"] }, { "command": "switchToTab", "args": { "index": 0 } "keys": ["ctrl+alt+1"] }, ``` * schemas are hard yo * Fix the build? * wonder why my -Wall settings are different than CI... * this makes me hate things * Comments from PR * Add a `Direction::None` * LOAD BEARING * add some GH ids to TODOs * add a comment * PR nits from carlos
This commit is contained in:
parent
d552959378
commit
6a4c737686
|
@ -13,62 +13,177 @@
|
|||
"pattern": "^\\{[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}\\}$",
|
||||
"type": "string"
|
||||
},
|
||||
"ShortcutActionName": {
|
||||
"enum": [
|
||||
"closePane",
|
||||
"closeTab",
|
||||
"closeWindow",
|
||||
"copy",
|
||||
"copyTextWithoutNewlines",
|
||||
"decreaseFontSize",
|
||||
"duplicateTab",
|
||||
"increaseFontSize",
|
||||
"moveFocus",
|
||||
"moveFocusDown",
|
||||
"moveFocusLeft",
|
||||
"moveFocusRight",
|
||||
"moveFocusUp",
|
||||
"newTab",
|
||||
"newTabProfile0",
|
||||
"newTabProfile1",
|
||||
"newTabProfile2",
|
||||
"newTabProfile3",
|
||||
"newTabProfile4",
|
||||
"newTabProfile5",
|
||||
"newTabProfile6",
|
||||
"newTabProfile7",
|
||||
"newTabProfile8",
|
||||
"nextTab",
|
||||
"openNewTabDropdown",
|
||||
"openSettings",
|
||||
"paste",
|
||||
"prevTab",
|
||||
"resizePane",
|
||||
"resizePaneDown",
|
||||
"resizePaneLeft",
|
||||
"resizePaneRight",
|
||||
"resizePaneUp",
|
||||
"scrollDown",
|
||||
"scrollDownPage",
|
||||
"scrollUp",
|
||||
"scrollUpPage",
|
||||
"splitHorizontal",
|
||||
"splitVertical",
|
||||
"switchToTab",
|
||||
"switchToTab0",
|
||||
"switchToTab1",
|
||||
"switchToTab2",
|
||||
"switchToTab3",
|
||||
"switchToTab4",
|
||||
"switchToTab5",
|
||||
"switchToTab6",
|
||||
"switchToTab7",
|
||||
"switchToTab8",
|
||||
"toggleFullscreen"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"Direction": {
|
||||
"enum": [
|
||||
"left",
|
||||
"right",
|
||||
"up",
|
||||
"down"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ShortcutAction": {
|
||||
"properties": {
|
||||
"action": {
|
||||
"description": "The action to execute",
|
||||
"$ref": "#/definitions/ShortcutActionName"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"action"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"CopyAction": {
|
||||
"description": "Arguments corresponding to a Copy Text Action",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ShortcutAction" },
|
||||
{
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "copy" },
|
||||
"trimWhitespace": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "If true, will trim whitespace from the end of the line on copy."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"NewTabAction": {
|
||||
"description": "Arguments corresponding to a New Tab Action",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ShortcutAction" },
|
||||
{
|
||||
"properties": {
|
||||
"action": { "type":"string", "pattern": "newTab" },
|
||||
"index": {
|
||||
"type": "integer",
|
||||
"description": "The index in the new tab dropdown to open in a new tab"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"SwitchToTabAction": {
|
||||
"description": "Arguments corresponding to a Switch To Tab Action",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ShortcutAction" },
|
||||
{
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "switchToTab" },
|
||||
"index": {
|
||||
"type": "integer",
|
||||
"default": 0,
|
||||
"description": "Which tab to switch to, with the first being 0"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"required": [ "index" ]
|
||||
},
|
||||
"MoveFocusAction": {
|
||||
"description": "Arguments corresponding to a Move Focus Action",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ShortcutAction" },
|
||||
{
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "moveFocus" },
|
||||
"direction": {
|
||||
"$ref": "#/definitions/Direction",
|
||||
"default": "left",
|
||||
"description": "The direction to move focus in, between panes"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"required": [ "direction" ]
|
||||
},
|
||||
"ResizePaneAction": {
|
||||
"description": "Arguments corresponding to a Resize Pane Action",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ShortcutAction" },
|
||||
{
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "resizePane" },
|
||||
"direction": {
|
||||
"$ref": "#/definitions/Direction",
|
||||
"default": "left",
|
||||
"description": "The direction to move the pane separator in"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"required": [ "direction" ]
|
||||
},
|
||||
"Keybinding": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"command": {
|
||||
"description": "The command executed when the associated key bindings are pressed.",
|
||||
"enum": [
|
||||
"closePane",
|
||||
"closeTab",
|
||||
"closeWindow",
|
||||
"copy",
|
||||
"copyTextWithoutNewlines",
|
||||
"decreaseFontSize",
|
||||
"duplicateTab",
|
||||
"increaseFontSize",
|
||||
"moveFocusDown",
|
||||
"moveFocusLeft",
|
||||
"moveFocusRight",
|
||||
"moveFocusUp",
|
||||
"newTab",
|
||||
"newTabProfile0",
|
||||
"newTabProfile1",
|
||||
"newTabProfile2",
|
||||
"newTabProfile3",
|
||||
"newTabProfile4",
|
||||
"newTabProfile5",
|
||||
"newTabProfile6",
|
||||
"newTabProfile7",
|
||||
"newTabProfile8",
|
||||
"nextTab",
|
||||
"openNewTabDropdown",
|
||||
"openSettings",
|
||||
"paste",
|
||||
"prevTab",
|
||||
"resizePaneDown",
|
||||
"resizePaneLeft",
|
||||
"resizePaneRight",
|
||||
"resizePaneUp",
|
||||
"scrollDown",
|
||||
"scrollDownPage",
|
||||
"scrollUp",
|
||||
"scrollUpPage",
|
||||
"splitHorizontal",
|
||||
"splitVertical",
|
||||
"switchToTab",
|
||||
"switchToTab0",
|
||||
"switchToTab1",
|
||||
"switchToTab2",
|
||||
"switchToTab3",
|
||||
"switchToTab4",
|
||||
"switchToTab5",
|
||||
"switchToTab6",
|
||||
"switchToTab7",
|
||||
"switchToTab8",
|
||||
"toggleFullscreen"
|
||||
],
|
||||
"type": "string"
|
||||
"description": "The action executed when the associated key bindings are pressed.",
|
||||
"oneOf": [
|
||||
{ "$ref": "#/definitions/CopyAction" },
|
||||
{ "$ref": "#/definitions/ShortcutActionName" },
|
||||
{ "$ref": "#/definitions/NewTabAction" },
|
||||
{ "$ref": "#/definitions/SwitchToTabAction" },
|
||||
{ "$ref": "#/definitions/MoveFocusAction" },
|
||||
{ "$ref": "#/definitions/ResizePaneAction" }
|
||||
]
|
||||
},
|
||||
"keys": {
|
||||
"description": "Defines the key combinations used to call the command.",
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
using namespace Microsoft::Console;
|
||||
using namespace TerminalApp;
|
||||
using namespace winrt::TerminalApp;
|
||||
using namespace winrt::Microsoft::Terminal::Settings;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::TestExecution;
|
||||
using namespace WEX::Common;
|
||||
|
@ -35,11 +37,33 @@ namespace TerminalAppLocalTests
|
|||
TEST_METHOD(LayerKeybindings);
|
||||
TEST_METHOD(UnbindKeybindings);
|
||||
|
||||
TEST_METHOD(TestArbitraryArgs);
|
||||
|
||||
TEST_CLASS_SETUP(ClassSetup)
|
||||
{
|
||||
InitializeJsonReader();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - This is a helper to retrieve the ActionAndArgs from the keybindings
|
||||
// for a given chord.
|
||||
// Arguments:
|
||||
// - bindings: The AppKeyBindings to lookup the ActionAndArgs from.
|
||||
// - kc: The key chord to look up the bound ActionAndArgs for.
|
||||
// Return Value:
|
||||
// - The ActionAndArgs bound to the given key, or nullptr if nothing is bound to it.
|
||||
static const ActionAndArgs KeyBindingsTests::GetActionAndArgs(const implementation::AppKeyBindings& bindings,
|
||||
const KeyChord& kc)
|
||||
{
|
||||
const auto keyIter = bindings._keyShortcuts.find(kc);
|
||||
VERIFY_IS_TRUE(keyIter != bindings._keyShortcuts.end(), L"Expected to find an action bound to the given KeyChord");
|
||||
if (keyIter != bindings._keyShortcuts.end())
|
||||
{
|
||||
return keyIter->second;
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
};
|
||||
|
||||
void KeyBindingsTests::ManyKeysSameAction()
|
||||
|
@ -156,4 +180,162 @@ namespace TerminalAppLocalTests
|
|||
appKeyBindings->LayerJson(bindings2Json);
|
||||
VERIFY_ARE_EQUAL(0u, appKeyBindings->_keyShortcuts.size());
|
||||
}
|
||||
|
||||
void KeyBindingsTests::TestArbitraryArgs()
|
||||
{
|
||||
const std::string bindings0String{ R"([
|
||||
{ "command": "copy", "keys": ["ctrl+c"] },
|
||||
{ "command": "copyTextWithoutNewlines", "keys": ["alt+c"] },
|
||||
{ "command": { "action": "copy", "trimWhitespace": false }, "keys": ["ctrl+shift+c"] },
|
||||
{ "command": { "action": "copy", "trimWhitespace": true }, "keys": ["alt+shift+c"] },
|
||||
|
||||
{ "command": "newTab", "keys": ["ctrl+t"] },
|
||||
{ "command": { "action": "newTab", "index": 0 }, "keys": ["ctrl+shift+t"] },
|
||||
{ "command": "newTabProfile0", "keys": ["alt+shift+t"] },
|
||||
{ "command": { "action": "newTab", "index": 11 }, "keys": ["ctrl+shift+y"] },
|
||||
{ "command": "newTabProfile8", "keys": ["alt+shift+y"] },
|
||||
|
||||
{ "command": { "action": "copy", "madeUpBool": true }, "keys": ["ctrl+b"] },
|
||||
{ "command": { "action": "copy" }, "keys": ["ctrl+shift+b"] }
|
||||
|
||||
])" };
|
||||
|
||||
const auto bindings0Json = VerifyParseSucceeded(bindings0String);
|
||||
|
||||
auto appKeyBindings = winrt::make_self<implementation::AppKeyBindings>();
|
||||
VERIFY_IS_NOT_NULL(appKeyBindings);
|
||||
VERIFY_ARE_EQUAL(0u, appKeyBindings->_keyShortcuts.size());
|
||||
appKeyBindings->LayerJson(bindings0Json);
|
||||
VERIFY_ARE_EQUAL(11u, appKeyBindings->_keyShortcuts.size());
|
||||
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Verify that `copy` without args parses as Copy(TrimWhitespace=false)"));
|
||||
KeyChord kc{ true, false, false, static_cast<int32_t>('C') };
|
||||
auto actionAndArgs = GetActionAndArgs(*appKeyBindings, kc);
|
||||
const auto& realArgs = actionAndArgs.Args().try_as<CopyTextArgs>();
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
// Verify the args have the expected value
|
||||
VERIFY_IS_FALSE(realArgs.TrimWhitespace());
|
||||
}
|
||||
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Verify that `copyTextWithoutNewlines` parses as Copy(TrimWhitespace=true)"));
|
||||
KeyChord kc{ false, true, false, static_cast<int32_t>('C') };
|
||||
auto actionAndArgs = GetActionAndArgs(*appKeyBindings, kc);
|
||||
const auto& realArgs = actionAndArgs.Args().try_as<CopyTextArgs>();
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
// Verify the args have the expected value
|
||||
VERIFY_IS_TRUE(realArgs.TrimWhitespace());
|
||||
}
|
||||
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Verify that `copy` with args parses them correctly"));
|
||||
KeyChord kc{ true, false, true, static_cast<int32_t>('C') };
|
||||
auto actionAndArgs = GetActionAndArgs(*appKeyBindings, kc);
|
||||
const auto& realArgs = actionAndArgs.Args().try_as<CopyTextArgs>();
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
// Verify the args have the expected value
|
||||
VERIFY_IS_FALSE(realArgs.TrimWhitespace());
|
||||
}
|
||||
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Verify that `copy` with args parses them correctly"));
|
||||
KeyChord kc{ false, true, true, static_cast<int32_t>('C') };
|
||||
auto actionAndArgs = GetActionAndArgs(*appKeyBindings, kc);
|
||||
const auto& realArgs = actionAndArgs.Args().try_as<CopyTextArgs>();
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
// Verify the args have the expected value
|
||||
VERIFY_IS_TRUE(realArgs.TrimWhitespace());
|
||||
}
|
||||
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Verify that `newTab` without args parses as NewTab(Index=null)"));
|
||||
KeyChord kc{ true, false, false, static_cast<int32_t>('T') };
|
||||
auto actionAndArgs = GetActionAndArgs(*appKeyBindings, kc);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action());
|
||||
const auto& realArgs = actionAndArgs.Args().try_as<NewTabArgs>();
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
// Verify the args have the expected value
|
||||
VERIFY_IS_NULL(realArgs.ProfileIndex());
|
||||
}
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Verify that `newTab` parses args correctly"));
|
||||
KeyChord kc{ true, false, true, static_cast<int32_t>('T') };
|
||||
auto actionAndArgs = GetActionAndArgs(*appKeyBindings, kc);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action());
|
||||
const auto& realArgs = actionAndArgs.Args().try_as<NewTabArgs>();
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
// Verify the args have the expected value
|
||||
VERIFY_IS_NOT_NULL(realArgs.ProfileIndex());
|
||||
VERIFY_ARE_EQUAL(0, realArgs.ProfileIndex().Value());
|
||||
}
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Verify that `newTabProfile0` parses as NewTab(Index=0)"));
|
||||
KeyChord kc{ false, true, true, static_cast<int32_t>('T') };
|
||||
auto actionAndArgs = GetActionAndArgs(*appKeyBindings, kc);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::NewTabProfile0, actionAndArgs.Action());
|
||||
const auto& realArgs = actionAndArgs.Args().try_as<NewTabArgs>();
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
// Verify the args have the expected value
|
||||
VERIFY_IS_NOT_NULL(realArgs.ProfileIndex());
|
||||
VERIFY_ARE_EQUAL(0, realArgs.ProfileIndex().Value());
|
||||
}
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Verify that `newTab` with an index greater than the legacy "
|
||||
L"args afforded parses correctly"));
|
||||
KeyChord kc{ true, false, true, static_cast<int32_t>('Y') };
|
||||
auto actionAndArgs = GetActionAndArgs(*appKeyBindings, kc);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action());
|
||||
const auto& realArgs = actionAndArgs.Args().try_as<NewTabArgs>();
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
// Verify the args have the expected value
|
||||
VERIFY_IS_NOT_NULL(realArgs.ProfileIndex());
|
||||
VERIFY_ARE_EQUAL(11, realArgs.ProfileIndex().Value());
|
||||
}
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Verify that `newTabProfile8` parses as NewTab(Index=8)"));
|
||||
KeyChord kc{ false, true, true, static_cast<int32_t>('Y') };
|
||||
auto actionAndArgs = GetActionAndArgs(*appKeyBindings, kc);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::NewTabProfile8, actionAndArgs.Action());
|
||||
const auto& realArgs = actionAndArgs.Args().try_as<NewTabArgs>();
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
// Verify the args have the expected value
|
||||
VERIFY_IS_NOT_NULL(realArgs.ProfileIndex());
|
||||
VERIFY_ARE_EQUAL(8, realArgs.ProfileIndex().Value());
|
||||
}
|
||||
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Verify that `copy` ignores args it doesn't understand"));
|
||||
KeyChord kc{ true, false, true, static_cast<int32_t>('B') };
|
||||
auto actionAndArgs = GetActionAndArgs(*appKeyBindings, kc);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::CopyText, actionAndArgs.Action());
|
||||
const auto& realArgs = actionAndArgs.Args().try_as<CopyTextArgs>();
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
// Verify the args have the expected value
|
||||
VERIFY_IS_FALSE(realArgs.TrimWhitespace());
|
||||
}
|
||||
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Verify that `copy` null as it's `args` parses as the default option"));
|
||||
KeyChord kc{ true, false, true, static_cast<int32_t>('B') };
|
||||
auto actionAndArgs = GetActionAndArgs(*appKeyBindings, kc);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::CopyText, actionAndArgs.Action());
|
||||
const auto& realArgs = actionAndArgs.Args().try_as<CopyTextArgs>();
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
// Verify the args have the expected value
|
||||
VERIFY_IS_FALSE(realArgs.TrimWhitespace());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
11
src/cascadia/TerminalApp/ActionAndArgs.cpp
Normal file
11
src/cascadia/TerminalApp/ActionAndArgs.cpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include "pch.h"
|
||||
#include "ActionAndArgs.h"
|
||||
#include "ActionAndArgs.g.cpp"
|
||||
|
||||
// We define everything necessary for the ActionAndArgs class in the header, but
|
||||
// we still need this file to compile the ActionAndArgs.g.cpp file, and we can't
|
||||
// just include that file in the header.
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
}
|
18
src/cascadia/TerminalApp/ActionAndArgs.h
Normal file
18
src/cascadia/TerminalApp/ActionAndArgs.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
#include "ActionAndArgs.g.h"
|
||||
#include "..\inc\cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct ActionAndArgs : public ActionAndArgsT<ActionAndArgs>
|
||||
{
|
||||
ActionAndArgs() = default;
|
||||
GETSET_PROPERTY(TerminalApp::ShortcutAction, Action, TerminalApp::ShortcutAction::Invalid);
|
||||
GETSET_PROPERTY(IActionArgs, Args, nullptr);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(ActionAndArgs);
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include "ActionEventArgs.g.cpp"
|
||||
#include "CopyTextArgs.g.cpp"
|
||||
#include "NewTabWithProfileArgs.g.cpp"
|
||||
#include "NewTabArgs.g.cpp"
|
||||
#include "SwitchToTabArgs.g.cpp"
|
||||
#include "ResizePaneArgs.g.cpp"
|
||||
#include "MoveFocusArgs.g.cpp"
|
||||
|
|
|
@ -7,13 +7,14 @@
|
|||
// *.g.cpp to ActionArgs.cpp!
|
||||
#include "ActionEventArgs.g.h"
|
||||
#include "CopyTextArgs.g.h"
|
||||
#include "NewTabWithProfileArgs.g.h"
|
||||
#include "NewTabArgs.g.h"
|
||||
#include "SwitchToTabArgs.g.h"
|
||||
#include "ResizePaneArgs.g.h"
|
||||
#include "MoveFocusArgs.g.h"
|
||||
#include "AdjustFontSizeArgs.g.h"
|
||||
|
||||
#include "../../cascadia/inc/cppwinrt_utils.h"
|
||||
#include "Utils.h"
|
||||
|
||||
// Notes on defining ActionArgs and ActionEventArgs:
|
||||
// * All properties specific to an action should be defined as an ActionArgs
|
||||
|
@ -36,30 +37,135 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
CopyTextArgs() = default;
|
||||
GETSET_PROPERTY(bool, TrimWhitespace, false);
|
||||
|
||||
static constexpr std::string_view TrimWhitespaceKey{ "trimWhitespace" };
|
||||
|
||||
public:
|
||||
static winrt::TerminalApp::IActionArgs FromJson(const Json::Value& json)
|
||||
{
|
||||
// LOAD BEARING: Not using make_self here _will_ break you in the future!
|
||||
auto args = winrt::make_self<CopyTextArgs>();
|
||||
if (auto trimWhitespace{ json[JsonKey(TrimWhitespaceKey)] })
|
||||
{
|
||||
args->_TrimWhitespace = trimWhitespace.asBool();
|
||||
}
|
||||
return *args;
|
||||
}
|
||||
};
|
||||
|
||||
struct NewTabWithProfileArgs : public NewTabWithProfileArgsT<NewTabWithProfileArgs>
|
||||
struct NewTabArgs : public NewTabArgsT<NewTabArgs>
|
||||
{
|
||||
NewTabWithProfileArgs() = default;
|
||||
GETSET_PROPERTY(int32_t, ProfileIndex, 0);
|
||||
NewTabArgs() = default;
|
||||
GETSET_PROPERTY(Windows::Foundation::IReference<int32_t>, ProfileIndex, nullptr);
|
||||
|
||||
static constexpr std::string_view ProfileIndexKey{ "index" };
|
||||
|
||||
public:
|
||||
static winrt::TerminalApp::IActionArgs FromJson(const Json::Value& json)
|
||||
{
|
||||
// LOAD BEARING: Not using make_self here _will_ break you in the future!
|
||||
auto args = winrt::make_self<NewTabArgs>();
|
||||
if (auto profileIndex{ json[JsonKey(ProfileIndexKey)] })
|
||||
{
|
||||
args->_ProfileIndex = profileIndex.asInt();
|
||||
}
|
||||
return *args;
|
||||
}
|
||||
};
|
||||
|
||||
struct SwitchToTabArgs : public SwitchToTabArgsT<SwitchToTabArgs>
|
||||
{
|
||||
SwitchToTabArgs() = default;
|
||||
GETSET_PROPERTY(int32_t, TabIndex, 0);
|
||||
|
||||
static constexpr std::string_view TabIndexKey{ "index" };
|
||||
|
||||
public:
|
||||
static winrt::TerminalApp::IActionArgs FromJson(const Json::Value& json)
|
||||
{
|
||||
// LOAD BEARING: Not using make_self here _will_ break you in the future!
|
||||
auto args = winrt::make_self<SwitchToTabArgs>();
|
||||
if (auto tabIndex{ json[JsonKey(TabIndexKey)] })
|
||||
{
|
||||
args->_TabIndex = tabIndex.asInt();
|
||||
}
|
||||
return *args;
|
||||
}
|
||||
};
|
||||
|
||||
// Possible Direction values
|
||||
// TODO:GH#2550/#3475 - move these to a centralized deserializing place
|
||||
static constexpr std::string_view LeftString{ "left" };
|
||||
static constexpr std::string_view RightString{ "right" };
|
||||
static constexpr std::string_view UpString{ "up" };
|
||||
static constexpr std::string_view DownString{ "down" };
|
||||
|
||||
// Function Description:
|
||||
// - Helper function for parsing a Direction from a string
|
||||
// Arguments:
|
||||
// - directionString: the string to attempt to parse
|
||||
// Return Value:
|
||||
// - The encoded Direction value, or Direction::None if it was an invalid string
|
||||
static TerminalApp::Direction ParseDirection(const std::string& directionString)
|
||||
{
|
||||
if (directionString == LeftString)
|
||||
{
|
||||
return TerminalApp::Direction::Left;
|
||||
}
|
||||
else if (directionString == RightString)
|
||||
{
|
||||
return TerminalApp::Direction::Right;
|
||||
}
|
||||
else if (directionString == UpString)
|
||||
{
|
||||
return TerminalApp::Direction::Up;
|
||||
}
|
||||
else if (directionString == DownString)
|
||||
{
|
||||
return TerminalApp::Direction::Down;
|
||||
}
|
||||
// default behavior for invalid data
|
||||
return TerminalApp::Direction::None;
|
||||
};
|
||||
|
||||
struct ResizePaneArgs : public ResizePaneArgsT<ResizePaneArgs>
|
||||
{
|
||||
ResizePaneArgs() = default;
|
||||
GETSET_PROPERTY(TerminalApp::Direction, Direction, TerminalApp::Direction::Left);
|
||||
GETSET_PROPERTY(TerminalApp::Direction, Direction, TerminalApp::Direction::None);
|
||||
|
||||
static constexpr std::string_view DirectionKey{ "direction" };
|
||||
|
||||
public:
|
||||
static winrt::TerminalApp::IActionArgs FromJson(const Json::Value& json)
|
||||
{
|
||||
// LOAD BEARING: Not using make_self here _will_ break you in the future!
|
||||
auto args = winrt::make_self<ResizePaneArgs>();
|
||||
if (auto directionString{ json[JsonKey(DirectionKey)] })
|
||||
{
|
||||
args->_Direction = ParseDirection(directionString.asString());
|
||||
}
|
||||
return *args;
|
||||
}
|
||||
};
|
||||
|
||||
struct MoveFocusArgs : public MoveFocusArgsT<MoveFocusArgs>
|
||||
{
|
||||
MoveFocusArgs() = default;
|
||||
GETSET_PROPERTY(TerminalApp::Direction, Direction, TerminalApp::Direction::Left);
|
||||
GETSET_PROPERTY(TerminalApp::Direction, Direction, TerminalApp::Direction::None);
|
||||
|
||||
static constexpr std::string_view DirectionKey{ "direction" };
|
||||
|
||||
public:
|
||||
static winrt::TerminalApp::IActionArgs FromJson(const Json::Value& json)
|
||||
{
|
||||
// LOAD BEARING: Not using make_self here _will_ break you in the future!
|
||||
auto args = winrt::make_self<MoveFocusArgs>();
|
||||
if (auto directionString{ json[JsonKey(DirectionKey)] })
|
||||
{
|
||||
args->_Direction = ParseDirection(directionString.asString());
|
||||
}
|
||||
return *args;
|
||||
}
|
||||
};
|
||||
|
||||
struct AdjustFontSizeArgs : public AdjustFontSizeArgsT<AdjustFontSizeArgs>
|
||||
|
|
|
@ -15,7 +15,8 @@ namespace TerminalApp
|
|||
|
||||
enum Direction
|
||||
{
|
||||
Left = 0,
|
||||
None = 0,
|
||||
Left,
|
||||
Right,
|
||||
Up,
|
||||
Down
|
||||
|
@ -31,9 +32,11 @@ namespace TerminalApp
|
|||
Boolean TrimWhitespace { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass NewTabWithProfileArgs : IActionArgs
|
||||
[default_interface] runtimeclass NewTabArgs : IActionArgs
|
||||
{
|
||||
Int32 ProfileIndex { get; };
|
||||
// ProfileIndex can be null (for "use the default"), so this needs to be
|
||||
// a IReference, so it's nullable
|
||||
Windows.Foundation.IReference<Int32> ProfileIndex { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass SwitchToTabArgs : IActionArgs
|
||||
|
@ -55,4 +58,5 @@ namespace TerminalApp
|
|||
{
|
||||
Int32 Delta { get; };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -26,12 +26,6 @@ namespace winrt
|
|||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
void TerminalPage::_HandleNewTab(const IInspectable& /*sender*/,
|
||||
const TerminalApp::ActionEventArgs& args)
|
||||
{
|
||||
_OpenNewTab(std::nullopt);
|
||||
args.Handled(true);
|
||||
}
|
||||
void TerminalPage::_HandleOpenNewTabDropdown(const IInspectable& /*sender*/,
|
||||
const TerminalApp::ActionEventArgs& args)
|
||||
{
|
||||
|
@ -138,12 +132,24 @@ namespace winrt::TerminalApp::implementation
|
|||
args.Handled(true);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleNewTabWithProfile(const IInspectable& /*sender*/,
|
||||
const TerminalApp::ActionEventArgs& args)
|
||||
void TerminalPage::_HandleNewTab(const IInspectable& /*sender*/,
|
||||
const TerminalApp::ActionEventArgs& args)
|
||||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<TerminalApp::NewTabWithProfileArgs>())
|
||||
if (args == nullptr)
|
||||
{
|
||||
_OpenNewTab({ realArgs.ProfileIndex() });
|
||||
_OpenNewTab(std::nullopt);
|
||||
args.Handled(true);
|
||||
}
|
||||
else if (const auto& realArgs = args.ActionArgs().try_as<TerminalApp::NewTabArgs>())
|
||||
{
|
||||
if (realArgs.ProfileIndex() == nullptr)
|
||||
{
|
||||
_OpenNewTab(std::nullopt);
|
||||
}
|
||||
else
|
||||
{
|
||||
_OpenNewTab(realArgs.ProfileIndex().Value());
|
||||
}
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
|
@ -163,8 +169,16 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<TerminalApp::ResizePaneArgs>())
|
||||
{
|
||||
_ResizePane(realArgs.Direction());
|
||||
args.Handled(true);
|
||||
if (realArgs.Direction() == TerminalApp::Direction::None)
|
||||
{
|
||||
// Do nothing
|
||||
args.Handled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ResizePane(realArgs.Direction());
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,8 +187,16 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<TerminalApp::MoveFocusArgs>())
|
||||
{
|
||||
_MoveFocus(realArgs.Direction());
|
||||
args.Handled(true);
|
||||
if (realArgs.Direction() == TerminalApp::Direction::None)
|
||||
{
|
||||
// Do nothing
|
||||
args.Handled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_MoveFocus(realArgs.Direction());
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,10 +12,10 @@ using namespace winrt::TerminalApp;
|
|||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
void AppKeyBindings::SetKeyBinding(const TerminalApp::ShortcutAction& action,
|
||||
void AppKeyBindings::SetKeyBinding(const TerminalApp::ActionAndArgs& actionAndArgs,
|
||||
const Settings::KeyChord& chord)
|
||||
{
|
||||
_keyShortcuts[chord] = action;
|
||||
_keyShortcuts[chord] = actionAndArgs;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -33,7 +33,7 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
for (auto& kv : _keyShortcuts)
|
||||
{
|
||||
if (kv.second == action)
|
||||
if (kv.second.Action() == action)
|
||||
{
|
||||
return kv.first;
|
||||
}
|
||||
|
@ -46,374 +46,185 @@ namespace winrt::TerminalApp::implementation
|
|||
const auto keyIter = _keyShortcuts.find(kc);
|
||||
if (keyIter != _keyShortcuts.end())
|
||||
{
|
||||
const auto action = keyIter->second;
|
||||
return _DoAction(action);
|
||||
const auto actionAndArgs = keyIter->second;
|
||||
return _DoAction(actionAndArgs);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AppKeyBindings::_DoAction(ShortcutAction action)
|
||||
bool AppKeyBindings::_DoAction(ActionAndArgs actionAndArgs)
|
||||
{
|
||||
const auto& action = actionAndArgs.Action();
|
||||
const auto& args = actionAndArgs.Args();
|
||||
auto eventArgs = args ? winrt::make_self<ActionEventArgs>(args) :
|
||||
winrt::make_self<ActionEventArgs>();
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case ShortcutAction::CopyText:
|
||||
{
|
||||
auto args = winrt::make_self<CopyTextArgs>();
|
||||
args->TrimWhitespace(true);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_CopyTextHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::CopyTextWithoutNewlines:
|
||||
{
|
||||
auto args = winrt::make_self<CopyTextArgs>();
|
||||
args->TrimWhitespace(false);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_CopyTextHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::PasteText:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_PasteTextHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::NewTab:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_NewTabHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::OpenNewTabDropdown:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_OpenNewTabDropdownHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::DuplicateTab:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_DuplicateTabHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::OpenSettings:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_OpenSettingsHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
|
||||
case ShortcutAction::NewTab:
|
||||
case ShortcutAction::NewTabProfile0:
|
||||
{
|
||||
auto args = winrt::make_self<NewTabWithProfileArgs>();
|
||||
args->ProfileIndex(0);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_NewTabWithProfileHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::NewTabProfile1:
|
||||
{
|
||||
auto args = winrt::make_self<NewTabWithProfileArgs>();
|
||||
args->ProfileIndex(1);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_NewTabWithProfileHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::NewTabProfile2:
|
||||
{
|
||||
auto args = winrt::make_self<NewTabWithProfileArgs>();
|
||||
args->ProfileIndex(2);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_NewTabWithProfileHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::NewTabProfile3:
|
||||
{
|
||||
auto args = winrt::make_self<NewTabWithProfileArgs>();
|
||||
args->ProfileIndex(3);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_NewTabWithProfileHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::NewTabProfile4:
|
||||
{
|
||||
auto args = winrt::make_self<NewTabWithProfileArgs>();
|
||||
args->ProfileIndex(4);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_NewTabWithProfileHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::NewTabProfile5:
|
||||
{
|
||||
auto args = winrt::make_self<NewTabWithProfileArgs>();
|
||||
args->ProfileIndex(5);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_NewTabWithProfileHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::NewTabProfile6:
|
||||
{
|
||||
auto args = winrt::make_self<NewTabWithProfileArgs>();
|
||||
args->ProfileIndex(6);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_NewTabWithProfileHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::NewTabProfile7:
|
||||
{
|
||||
auto args = winrt::make_self<NewTabWithProfileArgs>();
|
||||
args->ProfileIndex(7);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_NewTabWithProfileHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::NewTabProfile8:
|
||||
{
|
||||
auto args = winrt::make_self<NewTabWithProfileArgs>();
|
||||
args->ProfileIndex(8);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_NewTabWithProfileHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
_NewTabHandlers(*this, *eventArgs);
|
||||
break;
|
||||
}
|
||||
|
||||
case ShortcutAction::NewWindow:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_NewWindowHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::CloseWindow:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_CloseWindowHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::CloseTab:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_CloseTabHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::ClosePane:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_ClosePaneHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
|
||||
case ShortcutAction::ScrollUp:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_ScrollUpHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::ScrollDown:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_ScrollDownHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::ScrollUpPage:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_ScrollUpPageHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::ScrollDownPage:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_ScrollDownPageHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
|
||||
case ShortcutAction::NextTab:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_NextTabHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::PrevTab:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_PrevTabHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
|
||||
case ShortcutAction::SplitVertical:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_SplitVerticalHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::SplitHorizontal:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_SplitHorizontalHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
|
||||
case ShortcutAction::SwitchToTab:
|
||||
case ShortcutAction::SwitchToTab0:
|
||||
{
|
||||
auto args = winrt::make_self<SwitchToTabArgs>();
|
||||
args->TabIndex(0);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_SwitchToTabHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::SwitchToTab1:
|
||||
{
|
||||
auto args = winrt::make_self<SwitchToTabArgs>();
|
||||
args->TabIndex(1);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_SwitchToTabHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::SwitchToTab2:
|
||||
{
|
||||
auto args = winrt::make_self<SwitchToTabArgs>();
|
||||
args->TabIndex(2);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_SwitchToTabHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::SwitchToTab3:
|
||||
{
|
||||
auto args = winrt::make_self<SwitchToTabArgs>();
|
||||
args->TabIndex(3);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_SwitchToTabHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::SwitchToTab4:
|
||||
{
|
||||
auto args = winrt::make_self<SwitchToTabArgs>();
|
||||
args->TabIndex(4);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_SwitchToTabHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::SwitchToTab5:
|
||||
{
|
||||
auto args = winrt::make_self<SwitchToTabArgs>();
|
||||
args->TabIndex(5);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_SwitchToTabHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::SwitchToTab6:
|
||||
{
|
||||
auto args = winrt::make_self<SwitchToTabArgs>();
|
||||
args->TabIndex(6);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_SwitchToTabHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::SwitchToTab7:
|
||||
{
|
||||
auto args = winrt::make_self<SwitchToTabArgs>();
|
||||
args->TabIndex(7);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_SwitchToTabHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::SwitchToTab8:
|
||||
{
|
||||
auto args = winrt::make_self<SwitchToTabArgs>();
|
||||
args->TabIndex(8);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_SwitchToTabHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
|
||||
case ShortcutAction::ResizePane:
|
||||
case ShortcutAction::ResizePaneLeft:
|
||||
{
|
||||
auto args = winrt::make_self<ResizePaneArgs>();
|
||||
args->Direction(Direction::Left);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_ResizePaneHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::ResizePaneRight:
|
||||
{
|
||||
auto args = winrt::make_self<ResizePaneArgs>();
|
||||
args->Direction(Direction::Right);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_ResizePaneHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::ResizePaneUp:
|
||||
{
|
||||
auto args = winrt::make_self<ResizePaneArgs>();
|
||||
args->Direction(Direction::Up);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_ResizePaneHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::ResizePaneDown:
|
||||
{
|
||||
auto args = winrt::make_self<ResizePaneArgs>();
|
||||
args->Direction(Direction::Down);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_ResizePaneHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
|
||||
case ShortcutAction::MoveFocus:
|
||||
case ShortcutAction::MoveFocusLeft:
|
||||
{
|
||||
auto args = winrt::make_self<MoveFocusArgs>();
|
||||
args->Direction(Direction::Left);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_MoveFocusHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::MoveFocusRight:
|
||||
{
|
||||
auto args = winrt::make_self<MoveFocusArgs>();
|
||||
args->Direction(Direction::Right);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_MoveFocusHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::MoveFocusUp:
|
||||
{
|
||||
auto args = winrt::make_self<MoveFocusArgs>();
|
||||
args->Direction(Direction::Up);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_MoveFocusHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
case ShortcutAction::MoveFocusDown:
|
||||
{
|
||||
auto args = winrt::make_self<MoveFocusArgs>();
|
||||
args->Direction(Direction::Down);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_MoveFocusHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
|
||||
case ShortcutAction::IncreaseFontSize:
|
||||
{
|
||||
auto args = winrt::make_self<AdjustFontSizeArgs>();
|
||||
args->Delta(1);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_AdjustFontSizeHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::DecreaseFontSize:
|
||||
{
|
||||
auto args = winrt::make_self<AdjustFontSizeArgs>();
|
||||
args->Delta(-1);
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>(*args);
|
||||
_AdjustFontSizeHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::ToggleFullscreen:
|
||||
{
|
||||
auto eventArgs = winrt::make_self<ActionEventArgs>();
|
||||
_ToggleFullscreenHandlers(*this, *eventArgs);
|
||||
return eventArgs->Handled();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return eventArgs->Handled();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
|
|
@ -41,7 +41,9 @@ namespace winrt::TerminalApp::implementation
|
|||
AppKeyBindings() = default;
|
||||
|
||||
bool TryKeyChord(winrt::Microsoft::Terminal::Settings::KeyChord const& kc);
|
||||
void SetKeyBinding(TerminalApp::ShortcutAction const& action, winrt::Microsoft::Terminal::Settings::KeyChord const& chord);
|
||||
|
||||
void SetKeyBinding(TerminalApp::ActionAndArgs const& actionAndArgs,
|
||||
winrt::Microsoft::Terminal::Settings::KeyChord const& chord);
|
||||
void ClearKeyBinding(winrt::Microsoft::Terminal::Settings::KeyChord const& chord);
|
||||
Microsoft::Terminal::Settings::KeyChord GetKeyBinding(TerminalApp::ShortcutAction const& action);
|
||||
|
||||
|
@ -54,10 +56,9 @@ namespace winrt::TerminalApp::implementation
|
|||
// clang-format off
|
||||
TYPED_EVENT(CopyText, TerminalApp::AppKeyBindings, TerminalApp::ActionEventArgs);
|
||||
TYPED_EVENT(PasteText, TerminalApp::AppKeyBindings, TerminalApp::ActionEventArgs);
|
||||
TYPED_EVENT(NewTab, TerminalApp::AppKeyBindings, TerminalApp::ActionEventArgs);
|
||||
TYPED_EVENT(OpenNewTabDropdown,TerminalApp::AppKeyBindings, TerminalApp::ActionEventArgs);
|
||||
TYPED_EVENT(DuplicateTab, TerminalApp::AppKeyBindings, TerminalApp::ActionEventArgs);
|
||||
TYPED_EVENT(NewTabWithProfile, TerminalApp::AppKeyBindings, TerminalApp::ActionEventArgs);
|
||||
TYPED_EVENT(NewTab, TerminalApp::AppKeyBindings, TerminalApp::ActionEventArgs);
|
||||
TYPED_EVENT(NewWindow, TerminalApp::AppKeyBindings, TerminalApp::ActionEventArgs);
|
||||
TYPED_EVENT(CloseWindow, TerminalApp::AppKeyBindings, TerminalApp::ActionEventArgs);
|
||||
TYPED_EVENT(CloseTab, TerminalApp::AppKeyBindings, TerminalApp::ActionEventArgs);
|
||||
|
@ -79,8 +80,8 @@ namespace winrt::TerminalApp::implementation
|
|||
// clang-format on
|
||||
|
||||
private:
|
||||
std::unordered_map<winrt::Microsoft::Terminal::Settings::KeyChord, TerminalApp::ShortcutAction, KeyChordHash, KeyChordEquality> _keyShortcuts;
|
||||
bool _DoAction(ShortcutAction action);
|
||||
std::unordered_map<winrt::Microsoft::Terminal::Settings::KeyChord, TerminalApp::ActionAndArgs, KeyChordHash, KeyChordEquality> _keyShortcuts;
|
||||
bool _DoAction(ActionAndArgs actionAndArgs);
|
||||
|
||||
friend class TerminalAppLocalTests::SettingsTests;
|
||||
friend class TerminalAppLocalTests::KeyBindingsTests;
|
||||
|
|
|
@ -4,24 +4,27 @@ import "../ActionArgs.idl";
|
|||
|
||||
namespace TerminalApp
|
||||
{
|
||||
// TODO: GH#1069 - Many of these shortcut actions are "legacy" now that we
|
||||
// have support for arbitrary args (#1142). We should remove them, and our
|
||||
// legacy deserializers.
|
||||
enum ShortcutAction
|
||||
{
|
||||
Invalid = 0,
|
||||
CopyText,
|
||||
CopyTextWithoutNewlines,
|
||||
PasteText,
|
||||
NewTab,
|
||||
OpenNewTabDropdown,
|
||||
DuplicateTab,
|
||||
NewTabProfile0,
|
||||
NewTabProfile1,
|
||||
NewTabProfile2,
|
||||
NewTabProfile3,
|
||||
NewTabProfile4,
|
||||
NewTabProfile5,
|
||||
NewTabProfile6,
|
||||
NewTabProfile7,
|
||||
NewTabProfile8,
|
||||
NewTab,
|
||||
NewTabProfile0, // Legacy
|
||||
NewTabProfile1, // Legacy
|
||||
NewTabProfile2, // Legacy
|
||||
NewTabProfile3, // Legacy
|
||||
NewTabProfile4, // Legacy
|
||||
NewTabProfile5, // Legacy
|
||||
NewTabProfile6, // Legacy
|
||||
NewTabProfile7, // Legacy
|
||||
NewTabProfile8, // Legacy
|
||||
NewWindow,
|
||||
CloseWindow,
|
||||
CloseTab,
|
||||
|
@ -30,39 +33,49 @@ namespace TerminalApp
|
|||
PrevTab,
|
||||
SplitVertical,
|
||||
SplitHorizontal,
|
||||
SwitchToTab0,
|
||||
SwitchToTab1,
|
||||
SwitchToTab2,
|
||||
SwitchToTab3,
|
||||
SwitchToTab4,
|
||||
SwitchToTab5,
|
||||
SwitchToTab6,
|
||||
SwitchToTab7,
|
||||
SwitchToTab8,
|
||||
SwitchToTab,
|
||||
SwitchToTab0, // Legacy
|
||||
SwitchToTab1, // Legacy
|
||||
SwitchToTab2, // Legacy
|
||||
SwitchToTab3, // Legacy
|
||||
SwitchToTab4, // Legacy
|
||||
SwitchToTab5, // Legacy
|
||||
SwitchToTab6, // Legacy
|
||||
SwitchToTab7, // Legacy
|
||||
SwitchToTab8, // Legacy
|
||||
IncreaseFontSize,
|
||||
DecreaseFontSize,
|
||||
ScrollUp,
|
||||
ScrollDown,
|
||||
ScrollUpPage,
|
||||
ScrollDownPage,
|
||||
ResizePaneLeft,
|
||||
ResizePaneRight,
|
||||
ResizePaneUp,
|
||||
ResizePaneDown,
|
||||
MoveFocusLeft,
|
||||
MoveFocusRight,
|
||||
MoveFocusUp,
|
||||
MoveFocusDown,
|
||||
ResizePane,
|
||||
ResizePaneLeft, // Legacy
|
||||
ResizePaneRight, // Legacy
|
||||
ResizePaneUp, // Legacy
|
||||
ResizePaneDown, // Legacy
|
||||
MoveFocus,
|
||||
MoveFocusLeft, // Legacy
|
||||
MoveFocusRight, // Legacy
|
||||
MoveFocusUp, // Legacy
|
||||
MoveFocusDown, // Legacy
|
||||
ToggleFullscreen,
|
||||
OpenSettings
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass ActionAndArgs {
|
||||
ActionAndArgs();
|
||||
IActionArgs Args;
|
||||
ShortcutAction Action;
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass AppKeyBindings : Microsoft.Terminal.Settings.IKeyBindings
|
||||
{
|
||||
AppKeyBindings();
|
||||
|
||||
void SetKeyBinding(ShortcutAction action, Microsoft.Terminal.Settings.KeyChord chord);
|
||||
void SetKeyBinding(ActionAndArgs actionAndArgs, Microsoft.Terminal.Settings.KeyChord chord);
|
||||
void ClearKeyBinding(Microsoft.Terminal.Settings.KeyChord chord);
|
||||
|
||||
Microsoft.Terminal.Settings.KeyChord GetKeyBinding(ShortcutAction action);
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<AppKeyBindings, ActionEventArgs> CopyText;
|
||||
|
@ -70,7 +83,6 @@ namespace TerminalApp
|
|||
event Windows.Foundation.TypedEventHandler<AppKeyBindings, ActionEventArgs> NewTab;
|
||||
event Windows.Foundation.TypedEventHandler<AppKeyBindings, ActionEventArgs> OpenNewTabDropdown;
|
||||
event Windows.Foundation.TypedEventHandler<AppKeyBindings, ActionEventArgs> DuplicateTab;
|
||||
event Windows.Foundation.TypedEventHandler<AppKeyBindings, ActionEventArgs> NewTabWithProfile;
|
||||
event Windows.Foundation.TypedEventHandler<AppKeyBindings, ActionEventArgs> NewWindow;
|
||||
event Windows.Foundation.TypedEventHandler<AppKeyBindings, ActionEventArgs> CloseWindow;
|
||||
event Windows.Foundation.TypedEventHandler<AppKeyBindings, ActionEventArgs> CloseTab;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "pch.h"
|
||||
#include "AppKeyBindings.h"
|
||||
#include "ActionAndArgs.h"
|
||||
#include "KeyChordSerialization.h"
|
||||
#include "Utils.h"
|
||||
#include "JsonUtils.h"
|
||||
|
@ -18,25 +19,26 @@ using namespace winrt::TerminalApp;
|
|||
|
||||
static constexpr std::string_view KeysKey{ "keys" };
|
||||
static constexpr std::string_view CommandKey{ "command" };
|
||||
static constexpr std::string_view ActionKey{ "action" };
|
||||
|
||||
// This key is reserved to remove a keybinding, instead of mapping it to an action.
|
||||
static constexpr std::string_view UnboundKey{ "unbound" };
|
||||
|
||||
static constexpr std::string_view CopyTextKey{ "copy" };
|
||||
static constexpr std::string_view CopyTextWithoutNewlinesKey{ "copyTextWithoutNewlines" };
|
||||
static constexpr std::string_view CopyTextWithoutNewlinesKey{ "copyTextWithoutNewlines" }; // Legacy
|
||||
static constexpr std::string_view PasteTextKey{ "paste" };
|
||||
static constexpr std::string_view NewTabKey{ "newTab" };
|
||||
static constexpr std::string_view OpenNewTabDropdownKey{ "openNewTabDropdown" };
|
||||
static constexpr std::string_view DuplicateTabKey{ "duplicateTab" };
|
||||
static constexpr std::string_view NewTabWithProfile0Key{ "newTabProfile0" };
|
||||
static constexpr std::string_view NewTabWithProfile1Key{ "newTabProfile1" };
|
||||
static constexpr std::string_view NewTabWithProfile2Key{ "newTabProfile2" };
|
||||
static constexpr std::string_view NewTabWithProfile3Key{ "newTabProfile3" };
|
||||
static constexpr std::string_view NewTabWithProfile4Key{ "newTabProfile4" };
|
||||
static constexpr std::string_view NewTabWithProfile5Key{ "newTabProfile5" };
|
||||
static constexpr std::string_view NewTabWithProfile6Key{ "newTabProfile6" };
|
||||
static constexpr std::string_view NewTabWithProfile7Key{ "newTabProfile7" };
|
||||
static constexpr std::string_view NewTabWithProfile8Key{ "newTabProfile8" };
|
||||
static constexpr std::string_view NewTabKey{ "newTab" };
|
||||
static constexpr std::string_view NewTabWithProfile0Key{ "newTabProfile0" }; // Legacy
|
||||
static constexpr std::string_view NewTabWithProfile1Key{ "newTabProfile1" }; // Legacy
|
||||
static constexpr std::string_view NewTabWithProfile2Key{ "newTabProfile2" }; // Legacy
|
||||
static constexpr std::string_view NewTabWithProfile3Key{ "newTabProfile3" }; // Legacy
|
||||
static constexpr std::string_view NewTabWithProfile4Key{ "newTabProfile4" }; // Legacy
|
||||
static constexpr std::string_view NewTabWithProfile5Key{ "newTabProfile5" }; // Legacy
|
||||
static constexpr std::string_view NewTabWithProfile6Key{ "newTabProfile6" }; // Legacy
|
||||
static constexpr std::string_view NewTabWithProfile7Key{ "newTabProfile7" }; // Legacy
|
||||
static constexpr std::string_view NewTabWithProfile8Key{ "newTabProfile8" }; // Legacy
|
||||
static constexpr std::string_view NewWindowKey{ "newWindow" };
|
||||
static constexpr std::string_view CloseWindowKey{ "closeWindow" };
|
||||
static constexpr std::string_view CloseTabKey{ "closeTab" };
|
||||
|
@ -50,26 +52,29 @@ static constexpr std::string_view ScrollupKey{ "scrollUp" };
|
|||
static constexpr std::string_view ScrolldownKey{ "scrollDown" };
|
||||
static constexpr std::string_view ScrolluppageKey{ "scrollUpPage" };
|
||||
static constexpr std::string_view ScrolldownpageKey{ "scrollDownPage" };
|
||||
static constexpr std::string_view SwitchToTab0Key{ "switchToTab0" };
|
||||
static constexpr std::string_view SwitchToTab1Key{ "switchToTab1" };
|
||||
static constexpr std::string_view SwitchToTab2Key{ "switchToTab2" };
|
||||
static constexpr std::string_view SwitchToTab3Key{ "switchToTab3" };
|
||||
static constexpr std::string_view SwitchToTab4Key{ "switchToTab4" };
|
||||
static constexpr std::string_view SwitchToTab5Key{ "switchToTab5" };
|
||||
static constexpr std::string_view SwitchToTab6Key{ "switchToTab6" };
|
||||
static constexpr std::string_view SwitchToTab7Key{ "switchToTab7" };
|
||||
static constexpr std::string_view SwitchToTab8Key{ "switchToTab8" };
|
||||
static constexpr std::string_view OpenSettingsKey{ "openSettings" };
|
||||
static constexpr std::string_view SwitchToTabKey{ "switchToTab" };
|
||||
static constexpr std::string_view SwitchToTab0Key{ "switchToTab0" }; // Legacy
|
||||
static constexpr std::string_view SwitchToTab1Key{ "switchToTab1" }; // Legacy
|
||||
static constexpr std::string_view SwitchToTab2Key{ "switchToTab2" }; // Legacy
|
||||
static constexpr std::string_view SwitchToTab3Key{ "switchToTab3" }; // Legacy
|
||||
static constexpr std::string_view SwitchToTab4Key{ "switchToTab4" }; // Legacy
|
||||
static constexpr std::string_view SwitchToTab5Key{ "switchToTab5" }; // Legacy
|
||||
static constexpr std::string_view SwitchToTab6Key{ "switchToTab6" }; // Legacy
|
||||
static constexpr std::string_view SwitchToTab7Key{ "switchToTab7" }; // Legacy
|
||||
static constexpr std::string_view SwitchToTab8Key{ "switchToTab8" }; // Legacy
|
||||
static constexpr std::string_view OpenSettingsKey{ "openSettings" }; // Legacy
|
||||
static constexpr std::string_view SplitHorizontalKey{ "splitHorizontal" };
|
||||
static constexpr std::string_view SplitVerticalKey{ "splitVertical" };
|
||||
static constexpr std::string_view ResizePaneLeftKey{ "resizePaneLeft" };
|
||||
static constexpr std::string_view ResizePaneRightKey{ "resizePaneRight" };
|
||||
static constexpr std::string_view ResizePaneUpKey{ "resizePaneUp" };
|
||||
static constexpr std::string_view ResizePaneDownKey{ "resizePaneDown" };
|
||||
static constexpr std::string_view MoveFocusLeftKey{ "moveFocusLeft" };
|
||||
static constexpr std::string_view MoveFocusRightKey{ "moveFocusRight" };
|
||||
static constexpr std::string_view MoveFocusUpKey{ "moveFocusUp" };
|
||||
static constexpr std::string_view MoveFocusDownKey{ "moveFocusDown" };
|
||||
static constexpr std::string_view ResizePaneKey{ "resizePane" };
|
||||
static constexpr std::string_view ResizePaneLeftKey{ "resizePaneLeft" }; // Legacy
|
||||
static constexpr std::string_view ResizePaneRightKey{ "resizePaneRight" }; // Legacy
|
||||
static constexpr std::string_view ResizePaneUpKey{ "resizePaneUp" }; // Legacy
|
||||
static constexpr std::string_view ResizePaneDownKey{ "resizePaneDown" }; // Legacy
|
||||
static constexpr std::string_view MoveFocusKey{ "moveFocus" };
|
||||
static constexpr std::string_view MoveFocusLeftKey{ "moveFocusLeft" }; // Legacy
|
||||
static constexpr std::string_view MoveFocusRightKey{ "moveFocusRight" }; // Legacy
|
||||
static constexpr std::string_view MoveFocusUpKey{ "moveFocusUp" }; // Legacy
|
||||
static constexpr std::string_view MoveFocusDownKey{ "moveFocusDown" }; // Legacy
|
||||
static constexpr std::string_view ToggleFullscreenKey{ "toggleFullscreen" };
|
||||
|
||||
// Specifically use a map here over an unordered_map. We want to be able to
|
||||
|
@ -84,9 +89,9 @@ static const std::map<std::string_view, ShortcutAction, std::less<>> commandName
|
|||
{ CopyTextKey, ShortcutAction::CopyText },
|
||||
{ CopyTextWithoutNewlinesKey, ShortcutAction::CopyTextWithoutNewlines },
|
||||
{ PasteTextKey, ShortcutAction::PasteText },
|
||||
{ NewTabKey, ShortcutAction::NewTab },
|
||||
{ OpenNewTabDropdownKey, ShortcutAction::OpenNewTabDropdown },
|
||||
{ DuplicateTabKey, ShortcutAction::DuplicateTab },
|
||||
{ NewTabKey, ShortcutAction::NewTab },
|
||||
{ NewTabWithProfile0Key, ShortcutAction::NewTabProfile0 },
|
||||
{ NewTabWithProfile1Key, ShortcutAction::NewTabProfile1 },
|
||||
{ NewTabWithProfile2Key, ShortcutAction::NewTabProfile2 },
|
||||
|
@ -108,6 +113,7 @@ static const std::map<std::string_view, ShortcutAction, std::less<>> commandName
|
|||
{ ScrolldownKey, ShortcutAction::ScrollDown },
|
||||
{ ScrolluppageKey, ShortcutAction::ScrollUpPage },
|
||||
{ ScrolldownpageKey, ShortcutAction::ScrollDownPage },
|
||||
{ SwitchToTabKey, ShortcutAction::SwitchToTab },
|
||||
{ SwitchToTab0Key, ShortcutAction::SwitchToTab0 },
|
||||
{ SwitchToTab1Key, ShortcutAction::SwitchToTab1 },
|
||||
{ SwitchToTab2Key, ShortcutAction::SwitchToTab2 },
|
||||
|
@ -119,10 +125,12 @@ static const std::map<std::string_view, ShortcutAction, std::less<>> commandName
|
|||
{ SwitchToTab8Key, ShortcutAction::SwitchToTab8 },
|
||||
{ SplitHorizontalKey, ShortcutAction::SplitHorizontal },
|
||||
{ SplitVerticalKey, ShortcutAction::SplitVertical },
|
||||
{ ResizePaneKey, ShortcutAction::ResizePane },
|
||||
{ ResizePaneLeftKey, ShortcutAction::ResizePaneLeft },
|
||||
{ ResizePaneRightKey, ShortcutAction::ResizePaneRight },
|
||||
{ ResizePaneUpKey, ShortcutAction::ResizePaneUp },
|
||||
{ ResizePaneDownKey, ShortcutAction::ResizePaneDown },
|
||||
{ MoveFocusKey, ShortcutAction::MoveFocus },
|
||||
{ MoveFocusLeftKey, ShortcutAction::MoveFocusLeft },
|
||||
{ MoveFocusRightKey, ShortcutAction::MoveFocusRight },
|
||||
{ MoveFocusUpKey, ShortcutAction::MoveFocusUp },
|
||||
|
@ -132,6 +140,151 @@ static const std::map<std::string_view, ShortcutAction, std::less<>> commandName
|
|||
{ UnboundKey, ShortcutAction::Invalid },
|
||||
};
|
||||
|
||||
// Function Description:
|
||||
// - Creates a function that can be used to generate a MoveFocusArgs for the
|
||||
// legacy MoveFocus[Direction] actions. These actions don't accept args from
|
||||
// json, instead, they just return a MoveFocusArgs with the Direction already
|
||||
// per-defined, based on the input param.
|
||||
// - TODO: GH#1069 Remove this before 1.0, and force an upgrade to the new args.
|
||||
// Arguments:
|
||||
// - direction: the direction to create the parse function for.
|
||||
// Return Value:
|
||||
// - A function that can be used to "parse" json into one of the legacy
|
||||
// MoveFocus[Direction] args.
|
||||
std::function<IActionArgs(const Json::Value&)> LegacyParseMoveFocusArgs(Direction direction)
|
||||
{
|
||||
auto pfn = [direction](const Json::Value & /*value*/) -> IActionArgs {
|
||||
auto args = winrt::make_self<winrt::TerminalApp::implementation::MoveFocusArgs>();
|
||||
args->Direction(direction);
|
||||
return *args;
|
||||
};
|
||||
return pfn;
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Creates a function that can be used to generate a ResizePaneArgs for the
|
||||
// legacy ResizePane[Direction] actions. These actions don't accept args from
|
||||
// json, instead, they just return a ResizePaneArgs with the Direction already
|
||||
// per-defined, based on the input param.
|
||||
// - TODO: GH#1069 Remove this before 1.0, and force an upgrade to the new args.
|
||||
// Arguments:
|
||||
// - direction: the direction to create the parse function for.
|
||||
// Return Value:
|
||||
// - A function that can be used to "parse" json into one of the legacy
|
||||
// ResizePane[Direction] args.
|
||||
std::function<IActionArgs(const Json::Value&)> LegacyParseResizePaneArgs(Direction direction)
|
||||
{
|
||||
auto pfn = [direction](const Json::Value & /*value*/) -> IActionArgs {
|
||||
auto args = winrt::make_self<winrt::TerminalApp::implementation::ResizePaneArgs>();
|
||||
args->Direction(direction);
|
||||
return *args;
|
||||
};
|
||||
return pfn;
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Creates a function that can be used to generate a NewTabWithProfileArgs for
|
||||
// the legacy NewTabWithProfile[Index] actions. These actions don't accept
|
||||
// args from json, instead, they just return a NewTabWithProfileArgs with the
|
||||
// index already per-defined, based on the input param.
|
||||
// - TODO: GH#1069 Remove this before 1.0, and force an upgrade to the new args.
|
||||
// Arguments:
|
||||
// - index: the profile index to create the parse function for.
|
||||
// Return Value:
|
||||
// - A function that can be used to "parse" json into one of the legacy
|
||||
// NewTabWithProfile[Index] args.
|
||||
std::function<IActionArgs(const Json::Value&)> LegacyParseNewTabWithProfileArgs(int index)
|
||||
{
|
||||
auto pfn = [index](const Json::Value & /*value*/) -> IActionArgs {
|
||||
auto args = winrt::make_self<winrt::TerminalApp::implementation::NewTabArgs>();
|
||||
args->ProfileIndex(index);
|
||||
return *args;
|
||||
};
|
||||
return pfn;
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Creates a function that can be used to generate a SwitchToTabArgs for the
|
||||
// legacy SwitchToTab[Index] actions. These actions don't accept args from
|
||||
// json, instead, they just return a SwitchToTabArgs with the index already
|
||||
// per-defined, based on the input param.
|
||||
// - TODO: GH#1069 Remove this before 1.0, and force an upgrade to the new args.
|
||||
// Arguments:
|
||||
// - index: the tab index to create the parse function for.
|
||||
// Return Value:
|
||||
// - A function that can be used to "parse" json into one of the legacy
|
||||
// SwitchToTab[Index] args.
|
||||
std::function<IActionArgs(const Json::Value&)> LegacyParseSwitchToTabArgs(int index)
|
||||
{
|
||||
auto pfn = [index](const Json::Value & /*value*/) -> IActionArgs {
|
||||
auto args = winrt::make_self<winrt::TerminalApp::implementation::SwitchToTabArgs>();
|
||||
args->TabIndex(index);
|
||||
return *args;
|
||||
};
|
||||
return pfn;
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Used to generate a CopyTextArgs for the legacy CopyTextWithoutNewlines
|
||||
// action.
|
||||
// - TODO: GH#1069 Remove this before 1.0, and force an upgrade to the new args.
|
||||
// Arguments:
|
||||
// - direction: the direction to create the parse function for.
|
||||
// Return Value:
|
||||
// - A CopyTextArgs with TrimWhitespace set to true, to emulate "CopyTextWithoutNewlines".
|
||||
IActionArgs LegacyParseCopyTextWithoutNewlinesArgs(const Json::Value& /*json*/)
|
||||
{
|
||||
auto args = winrt::make_self<winrt::TerminalApp::implementation::CopyTextArgs>();
|
||||
args->TrimWhitespace(true);
|
||||
return *args;
|
||||
};
|
||||
|
||||
// This is a map of ShortcutAction->function<IActionArgs(Json::Value)>. It holds
|
||||
// a set of deserializer functions that can be used to deserialize a IActionArgs
|
||||
// from json. Each type of IActionArgs that can accept arbitrary args should be
|
||||
// placed into this map, with the corresponding deserializer function as the
|
||||
// value.
|
||||
static const std::map<ShortcutAction, std::function<IActionArgs(const Json::Value&)>, std::less<>> argParsers{
|
||||
{ ShortcutAction::CopyText, winrt::TerminalApp::implementation::CopyTextArgs::FromJson },
|
||||
{ ShortcutAction::CopyTextWithoutNewlines, LegacyParseCopyTextWithoutNewlinesArgs },
|
||||
|
||||
{ ShortcutAction::NewTab, winrt::TerminalApp::implementation::NewTabArgs::FromJson },
|
||||
{ ShortcutAction::NewTabProfile0, LegacyParseNewTabWithProfileArgs(0) },
|
||||
{ ShortcutAction::NewTabProfile1, LegacyParseNewTabWithProfileArgs(1) },
|
||||
{ ShortcutAction::NewTabProfile2, LegacyParseNewTabWithProfileArgs(2) },
|
||||
{ ShortcutAction::NewTabProfile3, LegacyParseNewTabWithProfileArgs(3) },
|
||||
{ ShortcutAction::NewTabProfile4, LegacyParseNewTabWithProfileArgs(4) },
|
||||
{ ShortcutAction::NewTabProfile5, LegacyParseNewTabWithProfileArgs(5) },
|
||||
{ ShortcutAction::NewTabProfile6, LegacyParseNewTabWithProfileArgs(6) },
|
||||
{ ShortcutAction::NewTabProfile7, LegacyParseNewTabWithProfileArgs(7) },
|
||||
{ ShortcutAction::NewTabProfile8, LegacyParseNewTabWithProfileArgs(8) },
|
||||
|
||||
{ ShortcutAction::SwitchToTab, winrt::TerminalApp::implementation::SwitchToTabArgs::FromJson },
|
||||
{ ShortcutAction::SwitchToTab0, LegacyParseSwitchToTabArgs(0) },
|
||||
{ ShortcutAction::SwitchToTab1, LegacyParseSwitchToTabArgs(1) },
|
||||
{ ShortcutAction::SwitchToTab2, LegacyParseSwitchToTabArgs(2) },
|
||||
{ ShortcutAction::SwitchToTab3, LegacyParseSwitchToTabArgs(3) },
|
||||
{ ShortcutAction::SwitchToTab4, LegacyParseSwitchToTabArgs(4) },
|
||||
{ ShortcutAction::SwitchToTab5, LegacyParseSwitchToTabArgs(5) },
|
||||
{ ShortcutAction::SwitchToTab6, LegacyParseSwitchToTabArgs(6) },
|
||||
{ ShortcutAction::SwitchToTab7, LegacyParseSwitchToTabArgs(7) },
|
||||
{ ShortcutAction::SwitchToTab8, LegacyParseSwitchToTabArgs(8) },
|
||||
|
||||
{ ShortcutAction::ResizePane, winrt::TerminalApp::implementation::ResizePaneArgs::FromJson },
|
||||
{ ShortcutAction::ResizePaneLeft, LegacyParseResizePaneArgs(Direction::Left) },
|
||||
{ ShortcutAction::ResizePaneRight, LegacyParseResizePaneArgs(Direction::Right) },
|
||||
{ ShortcutAction::ResizePaneUp, LegacyParseResizePaneArgs(Direction::Up) },
|
||||
{ ShortcutAction::ResizePaneDown, LegacyParseResizePaneArgs(Direction::Down) },
|
||||
|
||||
{ ShortcutAction::MoveFocus, winrt::TerminalApp::implementation::MoveFocusArgs::FromJson },
|
||||
{ ShortcutAction::MoveFocusLeft, LegacyParseMoveFocusArgs(Direction::Left) },
|
||||
{ ShortcutAction::MoveFocusRight, LegacyParseMoveFocusArgs(Direction::Right) },
|
||||
{ ShortcutAction::MoveFocusUp, LegacyParseMoveFocusArgs(Direction::Up) },
|
||||
{ ShortcutAction::MoveFocusDown, LegacyParseMoveFocusArgs(Direction::Down) },
|
||||
|
||||
{ ShortcutAction::Invalid, nullptr },
|
||||
};
|
||||
|
||||
// Function Description:
|
||||
// - Small helper to create a json value serialization of a single
|
||||
// KeyBinding->Action maping. The created object is of schema:
|
||||
|
@ -192,6 +345,21 @@ Json::Value winrt::TerminalApp::implementation::AppKeyBindings::ToJson()
|
|||
return bindingsArray;
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Attempts to match a string to a ShortcutAction. If there's no match, then
|
||||
// returns ShortcutAction::Invalid
|
||||
// Arguments:
|
||||
// - actionString: the string to match to a ShortcutAction
|
||||
// Return Value:
|
||||
// - The ShortcutAction corresponding to the given string, if a match exists.
|
||||
static ShortcutAction GetActionFromString(const std::string_view actionString)
|
||||
{
|
||||
// Try matching the command to one we have. If we can't find the
|
||||
// action name in our list of names, let's just unbind that key.
|
||||
const auto found = commandNames.find(actionString);
|
||||
return found != commandNames.end() ? found->second : ShortcutAction::Invalid;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Deserialize an AppKeyBindings from the key mappings that are in the array
|
||||
// `json`. The json array should contain an array of objects with both a
|
||||
|
@ -227,18 +395,48 @@ void winrt::TerminalApp::implementation::AppKeyBindings::LayerJson(const Json::V
|
|||
// Invalid is our placeholder that the action was not parsed.
|
||||
ShortcutAction action = ShortcutAction::Invalid;
|
||||
|
||||
// Keybindings can be serialized in two styles:
|
||||
// { "command": "switchToTab0", "keys": ["ctrl+1"] },
|
||||
// { "command": { "action": "switchToTab", "index": 0 }, "keys": ["ctrl+alt+1"] },
|
||||
|
||||
// 1. In the first case, the "command" is a string, that's the
|
||||
// action name. There are no provided args, so we'll pass
|
||||
// Json::Value::null to the parse function.
|
||||
// 2. In the second case, the "command" is an object. We'll use the
|
||||
// "action" in that object as the action name. We'll then pass
|
||||
// the "command" object to the arg parser, for furhter parsing.
|
||||
|
||||
auto argsVal = Json::Value::null;
|
||||
|
||||
// Only try to parse the action if it's actually a string value.
|
||||
// `null` will not pass this check.
|
||||
if (commandVal.isString())
|
||||
{
|
||||
auto commandString = commandVal.asString();
|
||||
|
||||
// Try matching the command to one we have. If we can't find the
|
||||
// action name in our list of names, let's just unbind that key.
|
||||
const auto found = commandNames.find(commandString);
|
||||
if (found != commandNames.end())
|
||||
action = GetActionFromString(commandString);
|
||||
}
|
||||
else if (commandVal.isObject())
|
||||
{
|
||||
const auto actionVal = commandVal[JsonKey(ActionKey)];
|
||||
if (actionVal.isString())
|
||||
{
|
||||
action = found->second;
|
||||
auto actionString = actionVal.asString();
|
||||
action = GetActionFromString(actionString);
|
||||
argsVal = commandVal;
|
||||
}
|
||||
}
|
||||
|
||||
// Some keybindings can accept other arbitrary arguments. If it
|
||||
// does, we'll try to deserialize any "args" that were provided with
|
||||
// the binding.
|
||||
IActionArgs args{ nullptr };
|
||||
const auto deserializersIter = argParsers.find(action);
|
||||
if (deserializersIter != argParsers.end())
|
||||
{
|
||||
auto pfn = deserializersIter->second;
|
||||
if (pfn)
|
||||
{
|
||||
args = pfn(argsVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,7 +451,10 @@ void winrt::TerminalApp::implementation::AppKeyBindings::LayerJson(const Json::V
|
|||
// found.
|
||||
if (action != ShortcutAction::Invalid)
|
||||
{
|
||||
SetKeyBinding(action, chord);
|
||||
auto actionAndArgs = winrt::make_self<ActionAndArgs>();
|
||||
actionAndArgs->Action(action);
|
||||
actionAndArgs->Args(args);
|
||||
SetKeyBinding(*actionAndArgs, chord);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -182,6 +182,10 @@ void CascadiaSettings::_ValidateSettings()
|
|||
// TODO:GH#2548 ensure there's at least one key bound. Display a warning if
|
||||
// there's _NO_ keys bound to any actions. That's highly irregular, and
|
||||
// likely an indication of an error somehow.
|
||||
|
||||
// TODO:GH#3522 With variable args to keybindings, it's possible that a user
|
||||
// set a keybinding without all the required args for an action. Display a
|
||||
// warning if an action didn't have a required arg.
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
|
|
@ -557,7 +557,6 @@ namespace winrt::TerminalApp::implementation
|
|||
// They should all be hooked up here, regardless of whether or not
|
||||
// there's an actual keychord for them.
|
||||
|
||||
bindings.NewTab({ this, &TerminalPage::_HandleNewTab });
|
||||
bindings.OpenNewTabDropdown({ this, &TerminalPage::_HandleOpenNewTabDropdown });
|
||||
bindings.DuplicateTab({ this, &TerminalPage::_HandleDuplicateTab });
|
||||
bindings.CloseTab({ this, &TerminalPage::_HandleCloseTab });
|
||||
|
@ -573,7 +572,7 @@ namespace winrt::TerminalApp::implementation
|
|||
bindings.ScrollDownPage({ this, &TerminalPage::_HandleScrollDownPage });
|
||||
bindings.OpenSettings({ this, &TerminalPage::_HandleOpenSettings });
|
||||
bindings.PasteText({ this, &TerminalPage::_HandlePasteText });
|
||||
bindings.NewTabWithProfile({ this, &TerminalPage::_HandleNewTabWithProfile });
|
||||
bindings.NewTab({ this, &TerminalPage::_HandleNewTab });
|
||||
bindings.SwitchToTab({ this, &TerminalPage::_HandleSwitchToTab });
|
||||
bindings.ResizePane({ this, &TerminalPage::_HandleResizePane });
|
||||
bindings.MoveFocus({ this, &TerminalPage::_HandleMoveFocus });
|
||||
|
|
|
@ -132,7 +132,6 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
#pragma region ActionHandlers
|
||||
// These are all defined in AppActionHandlers.cpp
|
||||
void _HandleNewTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||
void _HandleOpenNewTabDropdown(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||
void _HandleDuplicateTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||
void _HandleCloseTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||
|
@ -147,7 +146,7 @@ namespace winrt::TerminalApp::implementation
|
|||
void _HandleScrollDownPage(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||
void _HandleOpenSettings(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||
void _HandlePasteText(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||
void _HandleNewTabWithProfile(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||
void _HandleNewTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||
void _HandleSwitchToTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||
void _HandleResizePane(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||
void _HandleMoveFocus(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||
|
|
|
@ -205,15 +205,15 @@
|
|||
{ "command": "copy", "keys": ["ctrl+shift+c"] },
|
||||
{ "command": "duplicateTab", "keys": ["ctrl+shift+d"] },
|
||||
{ "command": "newTab", "keys": ["ctrl+shift+t"] },
|
||||
{ "command": "newTabProfile0", "keys": ["ctrl+shift+1"] },
|
||||
{ "command": "newTabProfile1", "keys": ["ctrl+shift+2"] },
|
||||
{ "command": "newTabProfile2", "keys": ["ctrl+shift+3"] },
|
||||
{ "command": "newTabProfile3", "keys": ["ctrl+shift+4"] },
|
||||
{ "command": "newTabProfile4", "keys": ["ctrl+shift+5"] },
|
||||
{ "command": "newTabProfile5", "keys": ["ctrl+shift+6"] },
|
||||
{ "command": "newTabProfile6", "keys": ["ctrl+shift+7"] },
|
||||
{ "command": "newTabProfile7", "keys": ["ctrl+shift+8"] },
|
||||
{ "command": "newTabProfile8", "keys": ["ctrl+shift+9"] },
|
||||
{ "command": { "action": "newTab", "index": 0 }, "keys": ["ctrl+shift+1"] },
|
||||
{ "command": { "action": "newTab", "index": 1 }, "keys": ["ctrl+shift+2"] },
|
||||
{ "command": { "action": "newTab", "index": 2 }, "keys": ["ctrl+shift+3"] },
|
||||
{ "command": { "action": "newTab", "index": 3 }, "keys": ["ctrl+shift+4"] },
|
||||
{ "command": { "action": "newTab", "index": 4 }, "keys": ["ctrl+shift+5"] },
|
||||
{ "command": { "action": "newTab", "index": 5 }, "keys": ["ctrl+shift+6"] },
|
||||
{ "command": { "action": "newTab", "index": 6 }, "keys": ["ctrl+shift+7"] },
|
||||
{ "command": { "action": "newTab", "index": 7 }, "keys": ["ctrl+shift+8"] },
|
||||
{ "command": { "action": "newTab", "index": 8 }, "keys": ["ctrl+shift+9"] },
|
||||
{ "command": "nextTab", "keys": ["ctrl+tab"] },
|
||||
{ "command": "openNewTabDropdown", "keys": ["ctrl+shift+space"] },
|
||||
{ "command": "openSettings", "keys": ["ctrl+,"] },
|
||||
|
@ -223,15 +223,15 @@
|
|||
{ "command": "scrollDownPage", "keys": ["ctrl+shift+pgdn"] },
|
||||
{ "command": "scrollUp", "keys": ["ctrl+shift+up"] },
|
||||
{ "command": "scrollUpPage", "keys": ["ctrl+shift+pgup"] },
|
||||
{ "command": "switchToTab0", "keys": ["ctrl+alt+1"] },
|
||||
{ "command": "switchToTab1", "keys": ["ctrl+alt+2"] },
|
||||
{ "command": "switchToTab2", "keys": ["ctrl+alt+3"] },
|
||||
{ "command": "switchToTab3", "keys": ["ctrl+alt+4"] },
|
||||
{ "command": "switchToTab4", "keys": ["ctrl+alt+5"] },
|
||||
{ "command": "switchToTab5", "keys": ["ctrl+alt+6"] },
|
||||
{ "command": "switchToTab6", "keys": ["ctrl+alt+7"] },
|
||||
{ "command": "switchToTab7", "keys": ["ctrl+alt+8"] },
|
||||
{ "command": "switchToTab8", "keys": ["ctrl+alt+9"] },
|
||||
{ "command": { "action": "switchToTab", "index": 0 }, "keys": ["ctrl+alt+1"] },
|
||||
{ "command": { "action": "switchToTab", "index": 1 }, "keys": ["ctrl+alt+2"] },
|
||||
{ "command": { "action": "switchToTab", "index": 2 }, "keys": ["ctrl+alt+3"] },
|
||||
{ "command": { "action": "switchToTab", "index": 3 }, "keys": ["ctrl+alt+4"] },
|
||||
{ "command": { "action": "switchToTab", "index": 4 }, "keys": ["ctrl+alt+5"] },
|
||||
{ "command": { "action": "switchToTab", "index": 5 }, "keys": ["ctrl+alt+6"] },
|
||||
{ "command": { "action": "switchToTab", "index": 6 }, "keys": ["ctrl+alt+7"] },
|
||||
{ "command": { "action": "switchToTab", "index": 7 }, "keys": ["ctrl+alt+8"] },
|
||||
{ "command": { "action": "switchToTab", "index": 8 }, "keys": ["ctrl+alt+9"] },
|
||||
{ "command": "decreaseFontSize", "keys": ["ctrl+-"] },
|
||||
{ "command": "increaseFontSize", "keys": ["ctrl+="] },
|
||||
{ "command": "toggleFullscreen", "keys": ["alt+enter"] },
|
||||
|
|
|
@ -90,6 +90,9 @@
|
|||
<ClInclude Include="../ActionArgs.h" >
|
||||
<DependentUpon>../ActionArgs.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="../ActionAndArgs.h" >
|
||||
<DependentUpon>../ActionArgs.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="../AppKeyBindings.h" >
|
||||
<DependentUpon>../AppKeyBindings.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
|
@ -138,6 +141,9 @@
|
|||
<ClCompile Include="../AppKeyBindings.cpp" >
|
||||
<DependentUpon>../AppKeyBindings.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="../ActionAndArgs.cpp" >
|
||||
<DependentUpon>../ActionArgs.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="../ActionArgs.cpp" >
|
||||
<DependentUpon>../ActionArgs.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
|
|
|
@ -40,3 +40,9 @@ Author(s):
|
|||
// UnitTests run in CI, while the LocalTests do not. However, since the CI can't
|
||||
// run XAML islands or unpackaged WinRT, any tests using those features will
|
||||
// need to be added to the LocalTests.
|
||||
|
||||
// These however are okay, for some _basic_ winrt things:
|
||||
#include <unknwn.h>
|
||||
#include <hstring.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
|
|
Loading…
Reference in a new issue