stunned that this remotely works as well as it does
This commit is contained in:
parent
4f6f3b98b8
commit
efe42d1742
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -33,5 +33,7 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
void SetParent(TerminalSettings parent);
|
||||
TerminalSettings GetParent();
|
||||
void ApplyColorScheme(ColorScheme scheme);
|
||||
|
||||
Boolean Elevate;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue