stunned that this remotely works as well as it does

This commit is contained in:
Mike Griese 2021-09-02 12:56:27 -05:00
parent 4f6f3b98b8
commit efe42d1742
13 changed files with 432 additions and 7 deletions

View file

@ -44,6 +44,8 @@ namespace TerminalAppLocalTests
TEST_METHOD(TestIterableColorSchemeCommands);
TEST_METHOD(TestElevateArg);
TEST_CLASS_SETUP(ClassSetup)
{
return true;
@ -1202,4 +1204,247 @@ namespace TerminalAppLocalTests
}
}
void SettingsTests::TestElevateArg()
{
const std::string settingsJson{ R"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
{
"name": "profile0",
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"commandline": "cmd.exe"
},
{
"name": "profile1",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"elevate": true,
"commandline": "pwsh.exe"
},
{
"name": "profile2",
"guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
"elevate": false,
"commandline": "wsl.exe"
}
],
"keybindings": [
{ "keys": ["ctrl+a"], "command": { "action": "newTab", "profile": "profile0" } },
{ "keys": ["ctrl+b"], "command": { "action": "newTab", "profile": "profile1" } },
{ "keys": ["ctrl+c"], "command": { "action": "newTab", "profile": "profile2" } },
{ "keys": ["ctrl+d"], "command": { "action": "newTab", "profile": "profile0", "elevate": false } },
{ "keys": ["ctrl+e"], "command": { "action": "newTab", "profile": "profile1", "elevate": false } },
{ "keys": ["ctrl+f"], "command": { "action": "newTab", "profile": "profile2", "elevate": false } },
{ "keys": ["ctrl+g"], "command": { "action": "newTab", "profile": "profile0", "elevate": true } },
{ "keys": ["ctrl+h"], "command": { "action": "newTab", "profile": "profile1", "elevate": true } },
{ "keys": ["ctrl+i"], "command": { "action": "newTab", "profile": "profile2", "elevate": true } },
]
})" };
const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}") };
const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}") };
const winrt::guid guid2{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}") };
CascadiaSettings settings{ til::u8u16(settingsJson) };
auto keymap = settings.GlobalSettings().KeyMap();
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
const auto profile2Guid = settings.ActiveProfiles().GetAt(2).Guid();
VERIFY_ARE_NOT_EQUAL(winrt::guid{}, profile2Guid);
VERIFY_ARE_EQUAL(9u, keymap.Size());
{
KeyChord kc{ true, false, false, static_cast<int32_t>('A') };
auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, 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.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile0", realArgs.TerminalArgs().Profile());
VERIFY_IS_NULL(realArgs.TerminalArgs().Elevate());
const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr);
VERIFY_ARE_EQUAL(guid0, guid);
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
VERIFY_ARE_EQUAL(false, termSettings.Elevate());
}
{
KeyChord kc{ true, false, false, static_cast<int32_t>('B') };
auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, 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.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
VERIFY_IS_NULL(realArgs.TerminalArgs().Elevate());
const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr);
VERIFY_ARE_EQUAL(guid1, guid);
VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline());
VERIFY_ARE_EQUAL(true, termSettings.Elevate());
}
{
KeyChord kc{ true, false, false, static_cast<int32_t>('C') };
auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, 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.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
VERIFY_IS_NULL(realArgs.TerminalArgs().Elevate());
const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr);
VERIFY_ARE_EQUAL(guid2, guid);
VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline());
VERIFY_ARE_EQUAL(false, termSettings.Elevate());
}
{
KeyChord kc{ true, false, false, static_cast<int32_t>('D') };
auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, 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.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile0", realArgs.TerminalArgs().Profile());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Elevate().Value());
const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr);
VERIFY_ARE_EQUAL(guid0, guid);
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
VERIFY_ARE_EQUAL(false, termSettings.Elevate());
}
{
KeyChord kc{ true, false, false, static_cast<int32_t>('E') };
auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, 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.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Elevate().Value());
const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr);
VERIFY_ARE_EQUAL(guid1, guid);
VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline());
VERIFY_ARE_EQUAL(false, termSettings.Elevate());
}
{
KeyChord kc{ true, false, false, static_cast<int32_t>('F') };
auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, 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.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Elevate().Value());
const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr);
VERIFY_ARE_EQUAL(guid2, guid);
VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline());
VERIFY_ARE_EQUAL(false, termSettings.Elevate());
}
{
KeyChord kc{ true, false, false, static_cast<int32_t>('G') };
auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, 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.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile0", realArgs.TerminalArgs().Profile());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Elevate().Value());
const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr);
VERIFY_ARE_EQUAL(guid0, guid);
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
VERIFY_ARE_EQUAL(true, termSettings.Elevate());
}
{
KeyChord kc{ true, false, false, static_cast<int32_t>('H') };
auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, 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.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Elevate().Value());
const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr);
VERIFY_ARE_EQUAL(guid1, guid);
VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline());
VERIFY_ARE_EQUAL(true, termSettings.Elevate());
}
{
KeyChord kc{ true, false, false, static_cast<int32_t>('I') };
auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, 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.TerminalArgs());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Elevate().Value());
const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr);
VERIFY_ARE_EQUAL(guid2, guid);
VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline());
VERIFY_ARE_EQUAL(true, termSettings.Elevate());
}
}
}

View file

@ -65,6 +65,26 @@ namespace winrt::TerminalApp::implementation
const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) };
const auto settings{ TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings) };
// Try to handle auto-elevation
const bool requestedElevation = settings.DefaultSettings().Elevate();
const bool currentlyElevated = _isElevated();
// We aren't elevated, but we want to be.
if (requestedElevation && !currentlyElevated)
{
// Manually set the Profile of the NewTerminalArgs to the guid we've
// resolved to. If there was a profile in the NewTerminalArgs, this
// will be that profile's GUID. If there wasn't, then we'll use
// whatever the default profile's GUID is.
newTerminalArgs.Profile(::Microsoft::Console::Utils::GuidToString(profile.Guid()));
_OpenElevatedWT(newTerminalArgs);
return S_OK;
}
// We can't go in the other direction (elevated->unelevated)
// unfortunately. This seems to be due to Centennial quirks. It works
// unpackaged, but not packaged.
_CreateNewTabWithProfileAndSettings(profile, settings, existingConnection);
const uint32_t tabCount = _tabs.Size();

View file

@ -12,6 +12,8 @@
#include "TerminalPage.g.cpp"
#include <winrt/Windows.Storage.h>
#include "../WinRTUtils/inc/WtExeUtils.h"
#include "TabRowControl.h"
#include "ColorHelper.h"
#include "DebugTapConnection.h"
@ -118,6 +120,29 @@ namespace winrt::TerminalApp::implementation
_systemRowsToScroll = _ReadSystemRowsToScroll();
}
bool TerminalPage::_isElevated() const noexcept
{
// use C++11 magic statics to make sure we only do this once.
// This won't change over the lifetime of the application
static const bool isElevated = []() {
// *** THIS IS A SINGLETON ***
auto result = false;
// GH#2455 - Make sure to try/catch calls to Application::Current,
// because that _won't_ be an instance of TerminalApp::App in the
// LocalTests
try
{
result = ::winrt::Windows::UI::Xaml::Application::Current().as<::winrt::TerminalApp::App>().Logic().IsElevated();
}
CATCH_LOG();
return result;
}();
return isElevated;
}
void TerminalPage::Create()
{
// Hookup the key bindings
@ -480,10 +505,43 @@ namespace winrt::TerminalApp::implementation
// - <none>
// Return Value:
// - <none>
void TerminalPage::_CompleteInitialization()
winrt::fire_and_forget TerminalPage::_CompleteInitialization()
{
_startupState = StartupState::Initialized;
_InitializedHandlers(*this, nullptr);
// GH#632 - It's possible that the user tried to create the terminal
// with only one tab, with only an elevated profile. If that happens,
// we'll create _another_ process to host the elevated version of that
// profile. This can happen from the jumplist, or if the default profile
// is `elevate:true`, or from the commandline.
//
// However, we need to make sure to close this window in that scenario.
// Since there aren't any _tabs_ in this window, we won't ever get a
// closed event. So do it manually.
auto weakThis{ get_weak() };
if (_tabs.Size() == 0)
{
// This is MENTAL. If we exit right away after spawning the elevated
// WT, then ShellExecute might not successfully complete the
// elevation. What's even more, the Terminal will mysteriously crash
// somewhere in XAML land.
//
// So I'm introducing a 5s delay here for the Shell to complete the
// execution, and _then_ close the window.
//
// TODO! There's no way this is the right answer, right?
co_await winrt::resume_background();
if (auto page{ weakThis.get() })
{
Sleep(5000);
co_await winrt::resume_foreground(page->Dispatcher(), CoreDispatcherPriority::Normal);
page->_LastTabClosedHandlers(*page, nullptr);
}
}
else
{
_InitializedHandlers(*this, nullptr);
}
}
// Method Description:
@ -1391,6 +1449,23 @@ namespace winrt::TerminalApp::implementation
controlSettings = TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings);
}
// Try to handle auto-elevation
const bool requestedElevation = controlSettings.DefaultSettings().Elevate();
const bool currentlyElevated = _isElevated();
// We aren't elevated, but we want to be.
if (requestedElevation && !currentlyElevated)
{
// Manually set the Profile of the NewTerminalArgs to the guid we've
// resolved to. If there was a profile in the NewTerminalArgs, this
// will be that profile's GUID. If there wasn't, then we'll use
// whatever the default profile's GUID is.
newTerminalArgs.Profile(::Microsoft::Console::Utils::GuidToString(profile.Guid()));
_OpenElevatedWT(newTerminalArgs);
return;
}
const auto controlConnection = _CreateConnectionFromSettings(profile, controlSettings.DefaultSettings());
const float contentWidth = ::base::saturated_cast<float>(_tabContent.ActualWidth());
@ -3069,4 +3144,51 @@ namespace winrt::TerminalApp::implementation
}
return profile;
}
// Function Description:
// - Helper to launch a new WT instance elevated. It'll do this by asking
// the shell to elevate the process for us. This might cause a UAC prompt.
// The elevation is performed on a background thread, as to not block the
// UI thread.
// Arguments:
// - newTerminalArgs: A NewTerminalArgs describing the terminal instance
// that should be spawned. The Profile should be filled in with the GUID
// of the profile we want to launch.
// Return Value:
// - <none>
// Important: Don't take the param by reference, since we'll be doing work
// on another thread.
fire_and_forget TerminalPage::_OpenElevatedWT(NewTerminalArgs newTerminalArgs)
{
// Hop to the BG thread
co_await winrt::resume_background();
// This will get us the correct exe for dev/preview/release. If you
// don't stick this in a local, it'll get mangled by ShellExecute. I
// have no idea why.
const auto exePath{ GetWtExePath() };
// Build the commandline to pass to wt for this set of NewTerminalArgs
winrt::hstring cmdline{
fmt::format(L"new-tab {}", newTerminalArgs.ToCommandline().c_str())
};
// Build the args to ShellExecuteEx. We need to use ShellExecuteEx so we
// can pass the SEE_MASK_NOASYNC flag. That flag allows us to safely
// call this on the background thread, and have ShellExecute _not_ call
// back to us on the main thread. Without this, if you close the
// Terminal quickly after the UAC prompt, the elevated WT will never
// actually spawn.
SHELLEXECUTEINFOW seInfo{ 0 };
seInfo.cbSize = sizeof(seInfo);
seInfo.fMask = SEE_MASK_NOASYNC;
seInfo.lpVerb = L"runas";
seInfo.lpFile = exePath.c_str();
seInfo.lpParameters = cmdline.c_str();
seInfo.nShow = SW_SHOWNORMAL;
LOG_IF_WIN32_BOOL_FALSE(ShellExecuteExW(&seInfo));
co_return;
}
}

View file

@ -320,7 +320,7 @@ namespace winrt::TerminalApp::implementation
void _StartInboundListener();
void _CompleteInitialization();
winrt::fire_and_forget _CompleteInitialization();
void _FocusActiveControl(IInspectable sender, IInspectable eventArgs);
@ -361,6 +361,9 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::Settings::Model::Profile GetClosestProfileForDuplicationOfProfile(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile) const noexcept;
bool _isElevated() const noexcept;
winrt::fire_and_forget _OpenElevatedWT(winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs);
#pragma region ActionHandlers
// These are all defined in AppActionHandlers.cpp
#define ON_ALL_ACTIONS(action) DECLARE_ACTION_HANDLER(action);

View file

@ -110,6 +110,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
ACTION_ARG(winrt::hstring, Profile, L"");
ACTION_ARG(Windows::Foundation::IReference<bool>, SuppressApplicationTitle, nullptr);
ACTION_ARG(winrt::hstring, ColorScheme);
ACTION_ARG(Windows::Foundation::IReference<bool>, Elevate, nullptr);
static constexpr std::string_view CommandlineKey{ "commandline" };
static constexpr std::string_view StartingDirectoryKey{ "startingDirectory" };
@ -119,6 +120,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
static constexpr std::string_view ProfileKey{ "profile" };
static constexpr std::string_view SuppressApplicationTitleKey{ "suppressApplicationTitle" };
static constexpr std::string_view ColorSchemeKey{ "colorScheme" };
static constexpr std::string_view ElevateKey{ "elevate" };
public:
hstring GenerateName() const;
@ -133,6 +135,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
other.ProfileIndex() == _ProfileIndex &&
other.Profile() == _Profile &&
other.SuppressApplicationTitle() == _SuppressApplicationTitle &&
other.Elevate() == _Elevate &&
other.ColorScheme() == _ColorScheme;
};
static Model::NewTerminalArgs FromJson(const Json::Value& json)
@ -147,6 +150,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
JsonUtils::GetValueForKey(json, TabColorKey, args->_TabColor);
JsonUtils::GetValueForKey(json, SuppressApplicationTitleKey, args->_SuppressApplicationTitle);
JsonUtils::GetValueForKey(json, ColorSchemeKey, args->_ColorScheme);
JsonUtils::GetValueForKey(json, ElevateKey, args->_Elevate);
return *args;
}
static Json::Value ToJson(const Model::NewTerminalArgs& val)
@ -165,6 +169,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
JsonUtils::SetValueForKey(json, TabColorKey, args->_TabColor);
JsonUtils::SetValueForKey(json, SuppressApplicationTitleKey, args->_SuppressApplicationTitle);
JsonUtils::SetValueForKey(json, ColorSchemeKey, args->_ColorScheme);
JsonUtils::SetValueForKey(json, ElevateKey, args->_Elevate);
return json;
}
Model::NewTerminalArgs Copy() const
@ -178,6 +183,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
copy->_Profile = _Profile;
copy->_SuppressApplicationTitle = _SuppressApplicationTitle;
copy->_ColorScheme = _ColorScheme;
copy->_Elevate = _Elevate;
return *copy;
}
size_t Hash() const

View file

@ -117,14 +117,16 @@ namespace Microsoft.Terminal.Settings.Model
// 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; };
Windows.Foundation.IReference<Boolean> SuppressApplicationTitle;
String ColorScheme;
// This needs to be an optional so that the default value (null) does
// not modifiy whatever the profile's value is (either true or false)
Windows.Foundation.IReference<Boolean> Elevate { get; };
Boolean Equals(NewTerminalArgs other);
String GenerateName();
String ToCommandline();
UInt64 Hash();
};

View file

@ -47,6 +47,7 @@ static constexpr std::string_view AntialiasingModeKey{ "antialiasingMode" };
static constexpr std::string_view TabColorKey{ "tabColor" };
static constexpr std::string_view BellStyleKey{ "bellStyle" };
static constexpr std::string_view UnfocusedAppearanceKey{ "unfocusedAppearance" };
static constexpr std::string_view ElevateKey{ "elevate" };
static constexpr std::wstring_view DesktopWallpaperEnum{ L"desktopWallpaper" };
@ -373,6 +374,7 @@ void Profile::LayerJson(const Json::Value& json)
JsonUtils::GetValueForKey(json, AntialiasingModeKey, _AntialiasingMode);
JsonUtils::GetValueForKey(json, TabColorKey, _TabColor);
JsonUtils::GetValueForKey(json, BellStyleKey, _BellStyle);
JsonUtils::GetValueForKey(json, ElevateKey, _Elevate);
if (json.isMember(JsonKey(UnfocusedAppearanceKey)))
{
@ -575,5 +577,7 @@ Json::Value Profile::ToJson() const
json[JsonKey(UnfocusedAppearanceKey)] = winrt::get_self<AppearanceConfig>(_UnfocusedAppearance.value())->ToJson();
}
JsonUtils::SetValueForKey(json, ElevateKey, _Elevate);
return json;
}

View file

@ -141,6 +141,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::Profile, bool, AltGrAliasing, true);
INHERITABLE_SETTING(Model::Profile, Model::BellStyle, BellStyle, BellStyle::Audible);
INHERITABLE_SETTING(Model::Profile, bool, Elevate, false);
INHERITABLE_SETTING(Model::Profile, Model::IAppearanceConfig, UnfocusedAppearance, nullptr);

View file

@ -88,5 +88,6 @@ namespace Microsoft.Terminal.Settings.Model
INHERITABLE_PROFILE_SETTING(Boolean, SnapOnInput);
INHERITABLE_PROFILE_SETTING(Boolean, AltGrAliasing);
INHERITABLE_PROFILE_SETTING(BellStyle, BellStyle);
INHERITABLE_PROFILE_SETTING(Boolean, Elevate);
}
}

View file

@ -155,6 +155,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
defaultSettings.ApplyColorScheme(scheme);
}
}
// Elevate on NewTerminalArgs is an optional value, so the default
// value (null) doesn't override a profile's value. Note that
// elevate:false in an already elevated terminal does nothing - the
// profile will still be launched elevated.
if (newTerminalArgs.Elevate())
{
defaultSettings.Elevate(newTerminalArgs.Elevate().Value());
}
}
return settingsPair;
@ -304,6 +312,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
const til::color colorRef{ profile.TabColor().Value() };
_TabColor = static_cast<winrt::Microsoft::Terminal::Core::Color>(colorRef);
}
_Elevate = profile.Elevate();
}
// Method Description:

View file

@ -154,6 +154,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::TerminalSettings, hstring, PixelShaderPath);
INHERITABLE_SETTING(Model::TerminalSettings, bool, IntenseIsBold);
INHERITABLE_SETTING(Model::TerminalSettings, bool, Elevate, false);
private:
std::optional<std::array<Microsoft::Terminal::Core::Color, COLOR_TABLE_SIZE>> _ColorTable;
gsl::span<Microsoft::Terminal::Core::Color> _getColorTableImpl();

View file

@ -33,5 +33,7 @@ namespace Microsoft.Terminal.Settings.Model
void SetParent(TerminalSettings parent);
TerminalSettings GetParent();
void ApplyColorScheme(ColorScheme scheme);
Boolean Elevate;
};
}

View file

@ -95,8 +95,15 @@ AppHost::~AppHost()
{
// destruction order is important for proper teardown here
_window = nullptr;
_app.Close();
_app = nullptr;
try
{
if (_app)
{
_app.Close();
_app = nullptr;
}
}
CATCH_LOG();
}
bool AppHost::OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down)