1c6aa4d109
## Summary of the Pull Request Move `ICoreSettings` and `IControlSettings` from the TerminalSettings project to the TerminalCore and TerminalControl projects respectively. Also entirely removes the TerminalSettings project. The purpose of these interfaces is unchanged. `ICoreSettings` is used to instantiate a terminal. `IControlSettings` (which requires an `ICoreSettings`) is used to instantiate a UWP terminal control. ## References Closes #7140 Related Epic: #885 Related Spec: #6904 ## PR Checklist * [X] Closes #7140 * [X] CLA signed * [X] Tests ~added~/passed (no additional tests necessary) * [X] ~Documentation updated~ * [X] ~Schema updated~ ## Detailed Description of the Pull Request / Additional comments A lot of the work here was having to deal with winmd files across all of these projects. The TerminalCore project now outputs a Microsoft.Terminal.TerminalControl.winmd. Some magic happens in TerminalControl.vcxproj to get this to work properly. ## Validation Steps Performed Deployed Windows Terminal and opened a few new tabs.
164 lines
5.8 KiB
C++
164 lines
5.8 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
// - A couple helper functions for serializing/deserializing an AppKeyBindings
|
|
// to/from json.
|
|
//
|
|
// Author(s):
|
|
// - Mike Griese - May 2019
|
|
|
|
#include "pch.h"
|
|
#include "AppKeyBindings.h"
|
|
#include "ActionAndArgs.h"
|
|
#include "KeyChordSerialization.h"
|
|
#include "Utils.h"
|
|
#include "JsonUtils.h"
|
|
|
|
using namespace winrt::Microsoft::Terminal::TerminalControl;
|
|
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" };
|
|
|
|
// Function Description:
|
|
// - Small helper to create a json value serialization of a single
|
|
// KeyBinding->Action mapping.
|
|
// {
|
|
// keys:[String],
|
|
// command:String
|
|
// }
|
|
// Arguments:
|
|
// - chord: The KeyChord to serialize
|
|
// - actionName: the name of the ShortcutAction to use with this KeyChord
|
|
// Return Value:
|
|
// - a Json::Value which is an equivalent serialization of this object.
|
|
static Json::Value _ShortcutAsJsonObject(const KeyChord& chord,
|
|
const std::string_view actionName)
|
|
{
|
|
const auto keyString = KeyChordSerialization::ToString(chord);
|
|
if (keyString == L"")
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
Json::Value jsonObject;
|
|
Json::Value keysArray;
|
|
keysArray.append(winrt::to_string(keyString));
|
|
|
|
jsonObject[JsonKey(KeysKey)] = keysArray;
|
|
jsonObject[JsonKey(CommandKey)] = actionName.data();
|
|
|
|
return jsonObject;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Serialize this AppKeyBindings to a json array of objects. Each object in
|
|
// the array represents a single keybinding, mapping a KeyChord to a
|
|
// ShortcutAction.
|
|
// Return Value:
|
|
// - a Json::Value which is an equivalent serialization of this object.
|
|
Json::Value winrt::TerminalApp::implementation::AppKeyBindings::ToJson()
|
|
{
|
|
Json::Value bindingsArray;
|
|
|
|
// Iterate over all the possible actions in the names list, and see if
|
|
// it has a binding.
|
|
for (auto& actionName : ActionAndArgs::ActionKeyNamesMap)
|
|
{
|
|
const auto searchedForName = actionName.first;
|
|
const auto searchedForAction = actionName.second;
|
|
|
|
if (const auto chord{ GetKeyBindingForAction(searchedForAction) })
|
|
{
|
|
if (const auto serialization{ _ShortcutAsJsonObject(chord, searchedForName) })
|
|
{
|
|
bindingsArray.append(serialization);
|
|
}
|
|
}
|
|
}
|
|
|
|
return bindingsArray;
|
|
}
|
|
|
|
// 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
|
|
// `command` string and a `keys` array, where `command` is one of the names
|
|
// listed in `ActionAndArgs::ActionKeyNamesMap`, and `keys` is an array of
|
|
// keypresses. Currently, the array should contain a single string, which can
|
|
// be deserialized into a KeyChord.
|
|
// - Applies the deserialized keybindings to the provided `bindings` object. If
|
|
// a key chord in `json` is already bound to an action, that chord will be
|
|
// overwritten with the new action. If a chord is bound to `null` or
|
|
// `"unbound"`, then we'll clear the keybinding from the existing keybindings.
|
|
// Arguments:
|
|
// - json: an array of Json::Value's to deserialize into our _keyShortcuts mapping.
|
|
std::vector<::TerminalApp::SettingsLoadWarnings> winrt::TerminalApp::implementation::AppKeyBindings::LayerJson(const Json::Value& json)
|
|
{
|
|
// It's possible that the user provided keybindings have some warnings in
|
|
// them - problems that we should alert the user to, but we can recover
|
|
// from. Most of these warnings cannot be detected later in the Validate
|
|
// settings phase, so we'll collect them now.
|
|
std::vector<::TerminalApp::SettingsLoadWarnings> warnings;
|
|
|
|
for (const auto& value : json)
|
|
{
|
|
if (!value.isObject())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const auto commandVal = value[JsonKey(CommandKey)];
|
|
const auto keys = value[JsonKey(KeysKey)];
|
|
|
|
if (keys)
|
|
{
|
|
const auto validString = keys.isString();
|
|
const auto validArray = keys.isArray() && keys.size() == 1;
|
|
|
|
// GH#4239 - If the user provided more than one key
|
|
// chord to a "keys" array, warn the user here.
|
|
// TODO: GH#1334 - remove this check.
|
|
if (keys.isArray() && keys.size() > 1)
|
|
{
|
|
warnings.push_back(::TerminalApp::SettingsLoadWarnings::TooManyKeysForChord);
|
|
}
|
|
|
|
if (!validString && !validArray)
|
|
{
|
|
continue;
|
|
}
|
|
const auto keyChordString = keys.isString() ? winrt::to_hstring(keys.asString()) : winrt::to_hstring(keys[0].asString());
|
|
|
|
// If the action was null, "unbound", or something we didn't
|
|
// understand, this will return nullptr.
|
|
auto actionAndArgs = ActionAndArgs::FromJson(commandVal, warnings);
|
|
|
|
// Try parsing the chord
|
|
try
|
|
{
|
|
const auto chord = KeyChordSerialization::FromString(keyChordString);
|
|
|
|
// If we couldn't find the action they want to set the chord to,
|
|
// or the action was `null` or `"unbound"`, just clear out the
|
|
// keybinding. Otherwise, set the keybinding to the action we
|
|
// found.
|
|
if (actionAndArgs)
|
|
{
|
|
SetKeyBinding(*actionAndArgs, chord);
|
|
}
|
|
else
|
|
{
|
|
ClearKeyBinding(chord);
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
return warnings;
|
|
}
|