mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-08 07:11:08 +00:00
Compare commits
38 Commits
dev/duhowe
...
v1.6.10571
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
507a84664e | ||
|
|
35a9314aa5 | ||
|
|
68887fc94e | ||
|
|
83d35c1191 | ||
|
|
b54429823e | ||
|
|
d7fcc56b90 | ||
|
|
b6927b24e8 | ||
|
|
d33dd1ffce | ||
|
|
da5ec7b2a2 | ||
|
|
ba534aaad6 | ||
|
|
7541b71de8 | ||
|
|
ac9d3dcfbe | ||
|
|
f7b205fa78 | ||
|
|
ff126c5a2f | ||
|
|
91f68e2914 | ||
|
|
245a244f1b | ||
|
|
fc57c82f80 | ||
|
|
c24194a3f3 | ||
|
|
3ab1d724d2 | ||
|
|
e13d1a7b61 | ||
|
|
48543bb3e7 | ||
|
|
91b867102c | ||
|
|
4014100b2d | ||
|
|
3778924aa4 | ||
|
|
c01573b5d3 | ||
|
|
62a12eeb79 | ||
|
|
e457a1a868 | ||
|
|
1c0bbe72d3 | ||
|
|
cf694747a0 | ||
|
|
9444617bc6 | ||
|
|
b80f6de58c | ||
|
|
34bb1cbd01 | ||
|
|
b656fdd34f | ||
|
|
41e9c59879 | ||
|
|
680c7deb2f | ||
|
|
e9548969e4 | ||
|
|
7fe98a0344 | ||
|
|
5b1137ccff |
@@ -2406,8 +2406,6 @@ Global
|
||||
{21B7EA5E-1EF8-49B6-AC07-11714AF0E37D}.Release|x86.ActiveCfg = Release|Win32
|
||||
{21B7EA5E-1EF8-49B6-AC07-11714AF0E37D}.Release|x86.Build.0 = Release|Win32
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|Any CPU.Build.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|ARM.ActiveCfg = Debug|ARM
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|ARM.Build.0 = Debug|ARM
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|ARM.Deploy.0 = Debug|ARM
|
||||
@@ -2415,11 +2413,7 @@ Global
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|ARM64.Build.0 = Debug|ARM64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|ARM64.Deploy.0 = Debug|ARM64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|DotNet_x64Test.ActiveCfg = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|DotNet_x64Test.Build.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|DotNet_x64Test.Deploy.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|DotNet_x86Test.ActiveCfg = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|DotNet_x86Test.Build.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|DotNet_x86Test.Deploy.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|x64.ActiveCfg = Debug|x64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|x64.Build.0 = Debug|x64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|x64.Deploy.0 = Debug|x64
|
||||
@@ -2427,8 +2421,6 @@ Global
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|x86.Build.0 = Debug|x86
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|x86.Deploy.0 = Debug|x86
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|ARM.ActiveCfg = Debug|ARM
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|ARM.Build.0 = Debug|ARM
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|ARM.Deploy.0 = Debug|ARM
|
||||
@@ -2436,11 +2428,7 @@ Global
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|ARM64.Deploy.0 = Debug|ARM64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|DotNet_x64Test.ActiveCfg = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|DotNet_x64Test.Build.0 = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|DotNet_x64Test.Deploy.0 = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|DotNet_x86Test.ActiveCfg = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|DotNet_x86Test.Build.0 = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|DotNet_x86Test.Deploy.0 = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|x64.Build.0 = Debug|x64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|x64.Deploy.0 = Debug|x64
|
||||
@@ -2448,8 +2436,6 @@ Global
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|x86.Build.0 = Debug|x86
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|ARM.ActiveCfg = Release|ARM
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|ARM.Build.0 = Release|ARM
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|ARM.Deploy.0 = Release|ARM
|
||||
@@ -2457,11 +2443,7 @@ Global
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|ARM64.Deploy.0 = Release|ARM64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|DotNet_x64Test.ActiveCfg = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|DotNet_x64Test.Build.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|DotNet_x64Test.Deploy.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|DotNet_x86Test.ActiveCfg = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|DotNet_x86Test.Build.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|DotNet_x86Test.Deploy.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|x64.ActiveCfg = Release|x64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|x64.Build.0 = Release|x64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|x64.Deploy.0 = Release|x64
|
||||
|
||||
@@ -93,6 +93,8 @@
|
||||
"scrollDownPage",
|
||||
"scrollUp",
|
||||
"scrollUpPage",
|
||||
"scrollToBottom",
|
||||
"scrollToTop",
|
||||
"sendInput",
|
||||
"setColorScheme",
|
||||
"setTabColor",
|
||||
|
||||
BIN
res/Cascadia.ttf
BIN
res/Cascadia.ttf
Binary file not shown.
Binary file not shown.
@@ -17,5 +17,5 @@ Please consult the [license](https://raw.githubusercontent.com/microsoft/cascadi
|
||||
|
||||
### Fonts Included
|
||||
|
||||
* Cascadia Code, Cascadia Mono (2009.21)
|
||||
* from microsoft/cascadia-code@32f84124db1970fa5d032f0fe9019e6922961beb
|
||||
* Cascadia Code, Cascadia Mono (2102.25)
|
||||
* from microsoft/cascadia-code@911dc421f333e3b72b97381d16fee5b71eb48f04
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
<AppxOSMaxVersionTestedReplaceManifestVersion>false</AppxOSMaxVersionTestedReplaceManifestVersion>
|
||||
<OCExecutionAliasName Condition="'$(WindowsTerminalBranding)'==''">wtd</OCExecutionAliasName>
|
||||
<OCExecutionAliasName Condition="'$(OCExecutionAliasName)'==''">wt</OCExecutionAliasName>
|
||||
<!-- VS 16.8 causes WAP projects to accidentally package System.Core.dll (from the CLR).
|
||||
This has been fixed in VS 16.9 using the property below. It's safe for us to include
|
||||
it here, even after 16.9 comes out. -->
|
||||
<AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>CA5CAD1A-224A-4171-B13A-F16E576FDD12</ProjectGuid>
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace SettingsModelLocalTests
|
||||
TEST_METHOD(CanLayerColorScheme);
|
||||
TEST_METHOD(LayerColorSchemeProperties);
|
||||
TEST_METHOD(LayerColorSchemesOnArray);
|
||||
TEST_METHOD(UpdateSchemeReferences);
|
||||
|
||||
TEST_CLASS_SETUP(ClassSetup)
|
||||
{
|
||||
@@ -290,4 +291,81 @@ namespace SettingsModelLocalTests
|
||||
VERIFY_ARE_EQUAL(ARGB(0, 7, 7, 7), scheme2->_Background);
|
||||
}
|
||||
}
|
||||
|
||||
void ColorSchemeTests::UpdateSchemeReferences()
|
||||
{
|
||||
const std::string settingsString{ R"json({
|
||||
"defaultProfile": "Inherited reference",
|
||||
"profiles": {
|
||||
"defaults": {
|
||||
"colorScheme": "Scheme 1"
|
||||
},
|
||||
"list": [
|
||||
{
|
||||
"name": "Explicit scheme reference",
|
||||
"colorScheme": "Scheme 1"
|
||||
},
|
||||
{
|
||||
"name": "Explicit reference; hidden",
|
||||
"colorScheme": "Scheme 1",
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"name": "Inherited reference"
|
||||
},
|
||||
{
|
||||
"name": "Different reference",
|
||||
"colorScheme": "Scheme 2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"schemes": [
|
||||
{ "name": "Scheme 1" },
|
||||
{ "name": "Scheme 2" },
|
||||
{ "name": "Scheme 1 (renamed)" }
|
||||
]
|
||||
})json" };
|
||||
|
||||
auto settings{ winrt::make_self<CascadiaSettings>(false) };
|
||||
settings->_ParseJsonString(settingsString, false);
|
||||
settings->_ApplyDefaultsFromUserSettings();
|
||||
settings->LayerJson(settings->_userSettings);
|
||||
settings->_ValidateSettings();
|
||||
|
||||
// update all references to "Scheme 1"
|
||||
const auto newName{ L"Scheme 1 (renamed)" };
|
||||
settings->UpdateColorSchemeReferences(L"Scheme 1", newName);
|
||||
|
||||
// verify profile defaults
|
||||
Log::Comment(L"Profile Defaults");
|
||||
VERIFY_ARE_EQUAL(newName, settings->ProfileDefaults().ColorSchemeName());
|
||||
VERIFY_IS_TRUE(settings->ProfileDefaults().HasColorSchemeName());
|
||||
|
||||
// verify all other profiles
|
||||
const auto& profiles{ settings->AllProfiles() };
|
||||
{
|
||||
const auto& prof{ profiles.GetAt(0) };
|
||||
Log::Comment(prof.Name().c_str());
|
||||
VERIFY_ARE_EQUAL(newName, prof.ColorSchemeName());
|
||||
VERIFY_IS_TRUE(prof.HasColorSchemeName());
|
||||
}
|
||||
{
|
||||
const auto& prof{ profiles.GetAt(1) };
|
||||
Log::Comment(prof.Name().c_str());
|
||||
VERIFY_ARE_EQUAL(newName, prof.ColorSchemeName());
|
||||
VERIFY_IS_TRUE(prof.HasColorSchemeName());
|
||||
}
|
||||
{
|
||||
const auto& prof{ profiles.GetAt(2) };
|
||||
Log::Comment(prof.Name().c_str());
|
||||
VERIFY_ARE_EQUAL(newName, prof.ColorSchemeName());
|
||||
VERIFY_IS_FALSE(prof.HasColorSchemeName());
|
||||
}
|
||||
{
|
||||
const auto& prof{ profiles.GetAt(3) };
|
||||
Log::Comment(prof.Name().c_str());
|
||||
VERIFY_ARE_EQUAL(L"Scheme 2", prof.ColorSchemeName());
|
||||
VERIFY_IS_TRUE(prof.HasColorSchemeName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,6 +226,7 @@ namespace SettingsModelLocalTests
|
||||
const std::string settingsString{ R"({
|
||||
"$schema": "https://aka.ms/terminal-profiles-schema",
|
||||
"defaultProfile": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
|
||||
"disabledProfileSources": [ "Windows.Terminal.Wsl" ],
|
||||
|
||||
"profiles": {
|
||||
"defaults": {
|
||||
|
||||
@@ -266,7 +266,16 @@ std::wstring OpenTerminalHere::_GetPathFromExplorer() const
|
||||
return path;
|
||||
}
|
||||
|
||||
auto shell = create_instance<IShellWindows>(CLSID_ShellWindows);
|
||||
com_ptr<IShellWindows> shell;
|
||||
try
|
||||
{
|
||||
shell = create_instance<IShellWindows>(CLSID_ShellWindows, CLSCTX_ALL);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
//look like try_create_instance is not available no more
|
||||
}
|
||||
|
||||
if (shell == nullptr)
|
||||
{
|
||||
return path;
|
||||
@@ -285,6 +294,7 @@ std::wstring OpenTerminalHere::_GetPathFromExplorer() const
|
||||
com_ptr<IWebBrowserApp> tmp;
|
||||
if (FAILED(disp->QueryInterface(tmp.put())))
|
||||
{
|
||||
disp = nullptr; // get rid of DEBUG non-nullptr warning
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -293,8 +303,11 @@ std::wstring OpenTerminalHere::_GetPathFromExplorer() const
|
||||
if (hwnd == tmpHWND)
|
||||
{
|
||||
browser = tmp;
|
||||
disp = nullptr; // get rid of DEBUG non-nullptr warning
|
||||
break; //found
|
||||
}
|
||||
|
||||
disp = nullptr; // get rid of DEBUG non-nullptr warning
|
||||
}
|
||||
|
||||
if (browser != nullptr)
|
||||
|
||||
@@ -841,7 +841,8 @@ namespace winrt::TerminalApp::implementation
|
||||
// editors, who will write a temp file, then rename it to be the
|
||||
// actual file you wrote. So listen for that too.
|
||||
if (!(event == wil::FolderChangeEvent::Modified ||
|
||||
event == wil::FolderChangeEvent::RenameNewName))
|
||||
event == wil::FolderChangeEvent::RenameNewName ||
|
||||
event == wil::FolderChangeEvent::Removed))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</Style>
|
||||
</Flyout.FlyoutPresenterStyle>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<StackPanel>
|
||||
<StackPanel XYFocusKeyboardNavigation="Enabled">
|
||||
<VariableSizedWrapGrid Orientation="Horizontal" MaximumRowsOrColumns="4" HorizontalAlignment="Center" Margin="0, 3, 0, 0">
|
||||
<VariableSizedWrapGrid.Resources>
|
||||
<Style TargetType="Rectangle">
|
||||
|
||||
@@ -243,6 +243,9 @@ namespace winrt::TerminalApp::implementation
|
||||
Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e)
|
||||
{
|
||||
auto key = e.OriginalKey();
|
||||
auto const ctrlDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Control), CoreVirtualKeyStates::Down);
|
||||
auto const altDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Menu), CoreVirtualKeyStates::Down);
|
||||
auto const shiftDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Shift), CoreVirtualKeyStates::Down);
|
||||
|
||||
// Some keypresses such as Tab, Return, Esc, and Arrow Keys are ignored by controls because
|
||||
// they're not considered input key presses. While they don't raise KeyDown events,
|
||||
@@ -253,10 +256,6 @@ namespace winrt::TerminalApp::implementation
|
||||
// a really widely used keyboard navigation key.
|
||||
if (_currentMode == CommandPaletteMode::TabSwitchMode && _keymap)
|
||||
{
|
||||
auto const ctrlDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Control), CoreVirtualKeyStates::Down);
|
||||
auto const altDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Menu), CoreVirtualKeyStates::Down);
|
||||
auto const shiftDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Shift), CoreVirtualKeyStates::Down);
|
||||
|
||||
winrt::Microsoft::Terminal::TerminalControl::KeyChord kc{ ctrlDown, altDown, shiftDown, static_cast<int32_t>(key) };
|
||||
const auto action = _keymap.TryLookup(kc);
|
||||
if (action)
|
||||
@@ -265,48 +264,28 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
SelectNextItem(false);
|
||||
e.Handled(true);
|
||||
return;
|
||||
}
|
||||
else if (action.Action() == ShortcutAction::NextTab)
|
||||
{
|
||||
SelectNextItem(true);
|
||||
e.Handled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (key == VirtualKey::Home)
|
||||
{
|
||||
auto const state = CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Control);
|
||||
if (WI_IsFlagSet(state, CoreVirtualKeyStates::Down))
|
||||
{
|
||||
ScrollToTop();
|
||||
e.Handled(true);
|
||||
}
|
||||
}
|
||||
else if (key == VirtualKey::End)
|
||||
{
|
||||
auto const state = CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Control);
|
||||
if (WI_IsFlagSet(state, CoreVirtualKeyStates::Down))
|
||||
{
|
||||
ScrollToBottom();
|
||||
e.Handled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Process keystrokes in the input box. This is used for moving focus up
|
||||
// and down the list of commands in Action mode, and for executing
|
||||
// commands in both Action mode and Commandline mode.
|
||||
// Arguments:
|
||||
// - e: the KeyRoutedEventArgs containing info about the keystroke.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void CommandPalette::_keyDownHandler(IInspectable const& /*sender*/,
|
||||
Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e)
|
||||
{
|
||||
auto key = e.OriginalKey();
|
||||
|
||||
if (key == VirtualKey::Up)
|
||||
if (key == VirtualKey::Home && ctrlDown)
|
||||
{
|
||||
ScrollToTop();
|
||||
e.Handled(true);
|
||||
}
|
||||
else if (key == VirtualKey::End && ctrlDown)
|
||||
{
|
||||
ScrollToBottom();
|
||||
e.Handled(true);
|
||||
}
|
||||
else if (key == VirtualKey::Up)
|
||||
{
|
||||
// Action Mode: Move focus to the next item in the list.
|
||||
SelectNextItem(false);
|
||||
@@ -352,16 +331,22 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
e.Handled(true);
|
||||
}
|
||||
else if (key == VirtualKey::Back)
|
||||
else if (key == VirtualKey::Back && _searchBox().Text().empty() && _lastFilterTextWasEmpty && _currentMode == CommandPaletteMode::ActionMode)
|
||||
{
|
||||
// If the last filter text was empty, and we're backspacing from
|
||||
// that state, then the user "backspaced" the virtual '>' we're
|
||||
// using as the action mode indicator. Switch into commandline mode.
|
||||
if (_searchBox().Text().empty() && _lastFilterTextWasEmpty && _currentMode == CommandPaletteMode::ActionMode)
|
||||
{
|
||||
_switchToMode(CommandPaletteMode::CommandlineMode);
|
||||
}
|
||||
|
||||
_switchToMode(CommandPaletteMode::CommandlineMode);
|
||||
e.Handled(true);
|
||||
}
|
||||
else if (key == VirtualKey::C && ctrlDown)
|
||||
{
|
||||
_searchBox().CopySelectionToClipboard();
|
||||
e.Handled(true);
|
||||
}
|
||||
else if (key == VirtualKey::V && ctrlDown)
|
||||
{
|
||||
_searchBox().PasteFromClipboard();
|
||||
e.Handled(true);
|
||||
}
|
||||
}
|
||||
@@ -451,6 +436,12 @@ namespace winrt::TerminalApp::implementation
|
||||
void CommandPalette::_lostFocusHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
||||
Windows::UI::Xaml::RoutedEventArgs const& /*args*/)
|
||||
{
|
||||
const auto flyout = _searchBox().ContextFlyout();
|
||||
if (flyout && flyout.IsOpen())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto focusedElementOrAncestor = Input::FocusManager::GetFocusedElement(this->XamlRoot()).try_as<DependencyObject>();
|
||||
while (focusedElementOrAncestor)
|
||||
{
|
||||
|
||||
@@ -75,8 +75,7 @@ namespace winrt::TerminalApp::implementation
|
||||
Windows::UI::Xaml::RoutedEventArgs const& args);
|
||||
void _previewKeyDownHandler(Windows::Foundation::IInspectable const& sender,
|
||||
Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
|
||||
void _keyDownHandler(Windows::Foundation::IInspectable const& sender,
|
||||
Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
|
||||
|
||||
void _keyUpHandler(Windows::Foundation::IInspectable const& sender,
|
||||
Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
AllowFocusOnInteraction="True"
|
||||
PointerPressed="_rootPointerPressed"
|
||||
PreviewKeyDown="_previewKeyDownHandler"
|
||||
KeyDown="_keyDownHandler"
|
||||
PreviewKeyUp="_keyUpHandler"
|
||||
LostFocus="_lostFocusHandler"
|
||||
mc:Ignorable="d"
|
||||
@@ -34,6 +33,7 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
<local:EmptyStringVisibilityConverter x:Key="ParsedCommandLineTextVisibilityConverter"/>
|
||||
<local:EmptyStringVisibilityConverter x:Key="ParentCommandVisibilityConverter"/>
|
||||
<local:HasNestedCommandsVisibilityConverter x:Key="HasNestedCommandsVisibilityConverter"/>
|
||||
<local:HasNestedCommandsHelpTextConverter x:Key="HasNestedCommandsHelpTextConverter"/>
|
||||
<model:IconPathConverter x:Key="IconSourceConverter"/>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
@@ -278,7 +278,6 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
AllowDrop="False"
|
||||
IsItemClickEnabled="True"
|
||||
ItemClick="_listItemClicked"
|
||||
PreviewKeyDown="_keyDownHandler"
|
||||
ItemsSource="{x:Bind FilteredActions}">
|
||||
|
||||
<ItemsControl.ItemTemplate >
|
||||
@@ -287,9 +286,9 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
<!-- This HorizontalContentAlignment="Stretch" is important
|
||||
to make sure it takes the entire width of the line -->
|
||||
<ListViewItem HorizontalContentAlignment="Stretch"
|
||||
IsTabStop="False"
|
||||
AutomationProperties.Name="{x:Bind Item.Name, Mode=OneWay}"
|
||||
AutomationProperties.AcceleratorKey="{x:Bind Item.KeyChordText, Mode=OneWay}">
|
||||
AutomationProperties.AcceleratorKey="{x:Bind Item.KeyChordText, Mode=OneWay}"
|
||||
AutomationProperties.HelpText="{x:Bind Item, Mode=OneWay, Converter={StaticResource HasNestedCommandsHelpTextConverter}}">
|
||||
|
||||
<Grid HorizontalAlignment="Stretch" ColumnSpacing="8" >
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -314,7 +313,13 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
|
||||
<!-- The block for the key chord is only visible
|
||||
when there's actual text set as the label. See
|
||||
CommandKeyChordVisibilityConverter for details. -->
|
||||
CommandKeyChordVisibilityConverter for details.
|
||||
|
||||
We're setting the accessibility view on the
|
||||
border and text block to Raw because otherwise,
|
||||
Narrator will read out the key chord. Problem is,
|
||||
it already did that because it was the list item's
|
||||
"AcceleratorKey". It's redundant. -->
|
||||
<Border
|
||||
Grid.Column="2"
|
||||
Visibility="{x:Bind Item.KeyChordText,
|
||||
@@ -323,12 +328,14 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
Style="{ThemeResource KeyChordBorderStyle}"
|
||||
Padding="2,0,2,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center">
|
||||
VerticalAlignment="Center"
|
||||
AutomationProperties.AccessibilityView="Raw">
|
||||
|
||||
<TextBlock
|
||||
Style="{ThemeResource KeyChordTextBlockStyle}"
|
||||
FontSize="12"
|
||||
Text="{x:Bind Item.KeyChordText, Mode=OneWay}" />
|
||||
Text="{x:Bind Item.KeyChordText, Mode=OneWay}"
|
||||
AutomationProperties.AccessibilityView="Raw" />
|
||||
</Border>
|
||||
|
||||
<!-- xE70E is ChevronUp. Rotated 90 degrees, it's _ChevronRight_ -->
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#include "pch.h"
|
||||
#include "HasNestedCommandsVisibilityConverter.h"
|
||||
#include "HasNestedCommandsVisibilityConverter.g.cpp"
|
||||
#include "HasNestedCommandsHelpTextConverter.g.cpp"
|
||||
|
||||
#include "LibraryResources.h"
|
||||
|
||||
using namespace winrt::Windows;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
@@ -36,4 +39,23 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
throw hresult_not_implemented();
|
||||
}
|
||||
|
||||
Foundation::IInspectable HasNestedCommandsHelpTextConverter::Convert(Foundation::IInspectable const& value,
|
||||
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
|
||||
Foundation::IInspectable const& /* parameter */,
|
||||
hstring const& /* language */)
|
||||
{
|
||||
const auto paletteItem{ value.try_as<winrt::TerminalApp::ActionPaletteItem>() };
|
||||
const auto hasNestedCommands = paletteItem && paletteItem.Command().HasNestedCommands();
|
||||
return winrt::box_value(hasNestedCommands ? RS_(L"CommandPalette_MoreOptions/[using:Windows.UI.Xaml.Automation]AutomationProperties/HelpText") : L"");
|
||||
}
|
||||
|
||||
// unused for one-way bindings
|
||||
Foundation::IInspectable HasNestedCommandsHelpTextConverter::ConvertBack(Foundation::IInspectable const& /* value */,
|
||||
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
|
||||
Foundation::IInspectable const& /* parameter */,
|
||||
hstring const& /* language */)
|
||||
{
|
||||
throw hresult_not_implemented();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "HasNestedCommandsVisibilityConverter.g.h"
|
||||
#include "HasNestedCommandsHelpTextConverter.g.h"
|
||||
#include "../inc/cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
@@ -19,9 +20,25 @@ namespace winrt::TerminalApp::implementation
|
||||
Windows::Foundation::IInspectable const& parameter,
|
||||
hstring const& language);
|
||||
};
|
||||
|
||||
struct HasNestedCommandsHelpTextConverter : HasNestedCommandsHelpTextConverterT<HasNestedCommandsHelpTextConverter>
|
||||
{
|
||||
HasNestedCommandsHelpTextConverter() = default;
|
||||
|
||||
Windows::Foundation::IInspectable Convert(Windows::Foundation::IInspectable const& value,
|
||||
Windows::UI::Xaml::Interop::TypeName const& targetType,
|
||||
Windows::Foundation::IInspectable const& parameter,
|
||||
hstring const& language);
|
||||
|
||||
Windows::Foundation::IInspectable ConvertBack(Windows::Foundation::IInspectable const& value,
|
||||
Windows::UI::Xaml::Interop::TypeName const& targetType,
|
||||
Windows::Foundation::IInspectable const& parameter,
|
||||
hstring const& language);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(HasNestedCommandsVisibilityConverter);
|
||||
BASIC_FACTORY(HasNestedCommandsHelpTextConverter);
|
||||
}
|
||||
|
||||
@@ -16,4 +16,9 @@ namespace TerminalApp
|
||||
HasNestedCommandsVisibilityConverter();
|
||||
};
|
||||
|
||||
runtimeclass HasNestedCommandsHelpTextConverter : [default] Windows.UI.Xaml.Data.IValueConverter
|
||||
{
|
||||
HasNestedCommandsHelpTextConverter();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1550,9 +1550,9 @@ void Pane::Restore(std::shared_ptr<Pane> zoomedPane)
|
||||
// otherwise the ID value will not make sense (leaves have IDs, parents do not)
|
||||
// Return Value:
|
||||
// - The ID of this pane
|
||||
uint16_t Pane::Id() noexcept
|
||||
std::optional<uint16_t> Pane::Id() noexcept
|
||||
{
|
||||
return _id.value();
|
||||
return _id;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
void Maximize(std::shared_ptr<Pane> zoomedPane);
|
||||
void Restore(std::shared_ptr<Pane> zoomedPane);
|
||||
|
||||
uint16_t Id() noexcept;
|
||||
std::optional<uint16_t> Id() noexcept;
|
||||
void Id(uint16_t id) noexcept;
|
||||
void FocusPane(const uint16_t id);
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
@@ -26,36 +26,36 @@
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
@@ -436,7 +436,7 @@
|
||||
</data>
|
||||
<data name="CommandPalette_ParsedCommandLine" xml:space="preserve">
|
||||
<value>Executing command line will invoke the following commands:</value>
|
||||
<comment>Will be followed by a list of strings describing parsed commands</comment>
|
||||
<comment>Will be followed by a list of strings describing parsed commands</comment>
|
||||
</data>
|
||||
<data name="CommandPalette_FailedParsingCommandLine" xml:space="preserve">
|
||||
<value>Failed parsing command line:</value>
|
||||
@@ -544,4 +544,7 @@
|
||||
<data name="ClipboardTextHeader.Text" xml:space="preserve">
|
||||
<value>Clipboard contents (preview):</value>
|
||||
</data>
|
||||
<data name="CommandPalette_MoreOptions.[using:Windows.UI.Xaml.Automation]AutomationProperties.HelpText" xml:space="preserve">
|
||||
<value>More options</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -62,7 +62,6 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
// Build the menu
|
||||
Controls::MenuFlyout newTabFlyout;
|
||||
newTabFlyout.Items().Append(_CreateCloseSubMenu());
|
||||
newTabFlyout.Items().Append(closeTabMenuItem);
|
||||
TabViewItem().ContextFlyout(newTabFlyout);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace winrt::TerminalApp::implementation
|
||||
"TabRenamerOpened",
|
||||
TraceLoggingDescription("Event emitted when the tab renamer is opened"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -75,6 +75,14 @@ namespace winrt::TerminalApp::implementation
|
||||
void TabHeaderControl::RenameBoxLostFocusHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
||||
Windows::UI::Xaml::RoutedEventArgs const& /*e*/)
|
||||
{
|
||||
// If the context menu associated with the renamer text box is open we know it gained the focus.
|
||||
// In this case we ignore this event (we will regain the focus once the menu will be closed).
|
||||
const auto flyout = HeaderRenamerTextBox().ContextFlyout();
|
||||
if (flyout && flyout.IsOpen())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Log the data here, rather than in _CloseRenameBox. If we do it there,
|
||||
// it'll get fired twice, once when the key is pressed to commit/cancel,
|
||||
// and then again when the focus is lost
|
||||
@@ -85,7 +93,7 @@ namespace winrt::TerminalApp::implementation
|
||||
TraceLoggingDescription("Event emitted when the tab renamer is closed"),
|
||||
TraceLoggingBoolean(_renameCancelled, "CancelledRename", "True if the user cancelled the rename, false if they committed."),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
_CloseRenameBox();
|
||||
if (!_renameCancelled)
|
||||
@@ -98,7 +106,11 @@ namespace winrt::TerminalApp::implementation
|
||||
// - Hides the rename box and displays the title text block
|
||||
void TabHeaderControl::_CloseRenameBox()
|
||||
{
|
||||
HeaderRenamerTextBox().Visibility(Windows::UI::Xaml::Visibility::Collapsed);
|
||||
HeaderTextBlock().Visibility(Windows::UI::Xaml::Visibility::Visible);
|
||||
if (HeaderRenamerTextBox().Visibility() == Windows::UI::Xaml::Visibility::Visible)
|
||||
{
|
||||
HeaderRenamerTextBox().Visibility(Windows::UI::Xaml::Visibility::Collapsed);
|
||||
HeaderTextBlock().Visibility(Windows::UI::Xaml::Visibility::Visible);
|
||||
_RenameEndedHandlers(*this, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace winrt::TerminalApp::implementation
|
||||
OBSERVABLE_GETSET_PROPERTY(bool, BellIndicator, _PropertyChangedHandlers);
|
||||
OBSERVABLE_GETSET_PROPERTY(uint32_t, ProgressValue, _PropertyChangedHandlers);
|
||||
|
||||
TYPED_EVENT(RenameEnded, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
|
||||
private:
|
||||
bool _receivedKeyDown{ false };
|
||||
bool _renameCancelled{ false };
|
||||
|
||||
@@ -19,5 +19,6 @@ namespace TerminalApp
|
||||
void BeginRename();
|
||||
|
||||
event TitleChangeRequestedArgs TitleChangeRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> RenameEnded;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +135,8 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
_tabRow.PointerMoved({ this, &TerminalPage::_RestorePointerCursorHandler });
|
||||
|
||||
_tabView.CanReorderTabs(!isElevated);
|
||||
_tabView.CanDragTabs(!isElevated);
|
||||
|
||||
@@ -815,6 +817,19 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
});
|
||||
|
||||
newTabImpl->TabRenamerDeactivated([weakThis{ get_weak() }](auto&& /*s*/, auto&& /*e*/) {
|
||||
if (const auto page{ weakThis.get() })
|
||||
{
|
||||
if (!page->_newTabButton.Flyout().IsOpen())
|
||||
{
|
||||
if (const auto tab{ page->_GetFocusedTab() })
|
||||
{
|
||||
tab.Focus(FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (debugConnection) // this will only be set if global debugging is on and tap is active
|
||||
{
|
||||
TermControl newControl{ settings, debugConnection };
|
||||
@@ -1065,8 +1080,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
auto newTabTitle = tab.Title();
|
||||
|
||||
if (_settings.GlobalSettings().ShowTitleInTitlebar() &&
|
||||
tab.FocusState() != FocusState::Unfocused)
|
||||
if (_settings.GlobalSettings().ShowTitleInTitlebar() && tab == _GetFocusedTab())
|
||||
{
|
||||
_titleChangeHandlers(*this, newTabTitle);
|
||||
}
|
||||
@@ -2252,7 +2266,10 @@ namespace winrt::TerminalApp::implementation
|
||||
tab.TabViewItem().StartBringIntoView();
|
||||
|
||||
// Raise an event that our title changed
|
||||
_titleChangeHandlers(*this, tab.Title());
|
||||
if (_settings.GlobalSettings().ShowTitleInTitlebar())
|
||||
{
|
||||
_titleChangeHandlers(*this, tab.Title());
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
@@ -2410,7 +2427,7 @@ namespace winrt::TerminalApp::implementation
|
||||
IVectorView<Profile> profiles,
|
||||
IMapView<winrt::hstring, ColorScheme> schemes)
|
||||
{
|
||||
IVector<SettingsLoadWarnings> warnings;
|
||||
IVector<SettingsLoadWarnings> warnings{ winrt::single_threaded_vector<SettingsLoadWarnings>() };
|
||||
|
||||
std::vector<ColorScheme> sortedSchemes;
|
||||
sortedSchemes.reserve(schemes.Size());
|
||||
|
||||
@@ -351,6 +351,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
// Update the control to reflect the changed title
|
||||
_headerControl.Title(activeTitle);
|
||||
Automation::AutomationProperties::SetName(tab->TabViewItem(), activeTitle);
|
||||
_UpdateToolTip();
|
||||
}
|
||||
}
|
||||
@@ -390,9 +391,19 @@ namespace winrt::TerminalApp::implementation
|
||||
// Make sure to take the ID before calling Split() - Split() will clear out the active pane's ID
|
||||
const auto activePaneId = _activePane->Id();
|
||||
auto [first, second] = _activePane->Split(splitType, splitSize, profile, control);
|
||||
first->Id(activePaneId);
|
||||
second->Id(_nextPaneId);
|
||||
++_nextPaneId;
|
||||
if (activePaneId)
|
||||
{
|
||||
first->Id(activePaneId.value());
|
||||
second->Id(_nextPaneId);
|
||||
++_nextPaneId;
|
||||
}
|
||||
else
|
||||
{
|
||||
first->Id(_nextPaneId);
|
||||
++_nextPaneId;
|
||||
second->Id(_nextPaneId);
|
||||
++_nextPaneId;
|
||||
}
|
||||
_activePane = first;
|
||||
_AttachEventHandlersToControl(control);
|
||||
|
||||
@@ -610,16 +621,18 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
// We need to move the pane to the top of our mru list
|
||||
// If its already somewhere in the list, remove it first
|
||||
const auto paneId = pane->Id();
|
||||
for (auto i = _mruPanes.begin(); i != _mruPanes.end(); ++i)
|
||||
if (const auto paneId = pane->Id())
|
||||
{
|
||||
if (*i == paneId)
|
||||
for (auto i = _mruPanes.begin(); i != _mruPanes.end(); ++i)
|
||||
{
|
||||
_mruPanes.erase(i);
|
||||
break;
|
||||
if (*i == paneId.value())
|
||||
{
|
||||
_mruPanes.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_mruPanes.insert(_mruPanes.begin(), paneId.value());
|
||||
}
|
||||
_mruPanes.insert(_mruPanes.begin(), paneId);
|
||||
// Raise our own ActivePaneChanged event.
|
||||
_ActivePaneChangedHandlers();
|
||||
}
|
||||
@@ -696,25 +709,26 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
});
|
||||
|
||||
// Add a PaneRaiseVisualBell event handler to the Pane. When the pane emits this event,
|
||||
// we need to bubble it all the way to app host. In this part of the chain we bubble it
|
||||
// from the hosting tab to the page.
|
||||
// Add a PaneRaiseBell event handler to the Pane
|
||||
pane->PaneRaiseBell([weakThis](auto&& /*s*/, auto&& visual) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
if (visual)
|
||||
{
|
||||
// If visual is set, we need to bubble this event all the way to app host to flash the taskbar
|
||||
// In this part of the chain we bubble it from the hosting tab to the page
|
||||
tab->_TabRaiseVisualBellHandlers();
|
||||
}
|
||||
|
||||
tab->ShowBellIndicator(true);
|
||||
// Show the bell indicator in the tab header
|
||||
tab->ShowBellIndicator(true);
|
||||
|
||||
// If this tab is focused, activate the bell indicator timer, which will
|
||||
// remove the bell indicator once it fires
|
||||
// (otherwise, the indicator is removed when the tab gets focus)
|
||||
if (tab->_focusState != WUX::FocusState::Unfocused)
|
||||
{
|
||||
tab->ActivateBellIndicatorTimer();
|
||||
}
|
||||
// If this tab is focused, activate the bell indicator timer, which will
|
||||
// remove the bell indicator once it fires
|
||||
// (otherwise, the indicator is removed when the tab gets focus)
|
||||
if (tab->_focusState != WUX::FocusState::Unfocused)
|
||||
{
|
||||
tab->ActivateBellIndicatorTimer();
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -800,7 +814,6 @@ namespace winrt::TerminalApp::implementation
|
||||
newTabFlyout.Items().Append(chooseColorMenuItem);
|
||||
newTabFlyout.Items().Append(renameTabMenuItem);
|
||||
newTabFlyout.Items().Append(menuSeparator);
|
||||
newTabFlyout.Items().Append(_CreateCloseSubMenu());
|
||||
newTabFlyout.Items().Append(closeTabMenuItem);
|
||||
TabViewItem().ContextFlyout(newTabFlyout);
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ namespace winrt::TerminalApp::implementation
|
||||
DECLARE_EVENT(ColorSelected, _colorSelected, winrt::delegate<winrt::Windows::UI::Color>);
|
||||
DECLARE_EVENT(ColorCleared, _colorCleared, winrt::delegate<>);
|
||||
DECLARE_EVENT(TabRaiseVisualBell, _TabRaiseVisualBellHandlers, winrt::delegate<>);
|
||||
FORWARDED_TYPED_EVENT(TabRenamerDeactivated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, (&_headerControl), RenameEnded);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Pane> _rootPane{ nullptr };
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "ConptyConnection.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <userenv.h>
|
||||
|
||||
#include "ConptyConnection.g.cpp"
|
||||
|
||||
@@ -94,11 +93,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
environment.clear();
|
||||
});
|
||||
|
||||
{
|
||||
const auto newEnvironmentBlock{ Utils::CreateEnvironmentBlock() };
|
||||
// Populate the environment map with the current environment.
|
||||
RETURN_IF_FAILED(Utils::UpdateEnvironmentMapW(environment, newEnvironmentBlock.get()));
|
||||
}
|
||||
// Populate the environment map with the current environment.
|
||||
RETURN_IF_FAILED(Utils::UpdateEnvironmentMapW(environment));
|
||||
|
||||
{
|
||||
// Convert connection Guid to string and ignore the enclosing '{}'.
|
||||
|
||||
@@ -188,7 +188,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
_autoScrollTimer.Interval(AutoScrollUpdateInterval);
|
||||
_autoScrollTimer.Tick({ this, &TermControl::_UpdateAutoScroll });
|
||||
|
||||
_ApplyUISettings();
|
||||
_ApplyUISettings(_settings);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -274,6 +274,73 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
this->Focus(FocusState::Programmatic);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Given new settings for this profile, applies the settings to the current terminal.
|
||||
// - This method is separate from UpdateSettings because there is an apparent optimizer
|
||||
// issue that causes one of our hstring -> wstring_view conversions to result in garbage,
|
||||
// but only from a coroutine context. See GH#8723.
|
||||
// - INVARIANT: This method must be called from the UI thread.
|
||||
// Arguments:
|
||||
// - newSettings: New settings values for the profile in this terminal.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TermControl::_UpdateSettingsOnUIThread(const IControlSettings& newSettings)
|
||||
{
|
||||
if (_closing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = _terminal->LockForWriting();
|
||||
|
||||
// First, store the new settings in the instance.
|
||||
_settings = newSettings;
|
||||
|
||||
// Update our control settings
|
||||
_ApplyUISettings(_settings);
|
||||
|
||||
// Update the terminal core with its new Core settings
|
||||
_terminal->UpdateSettings(_settings);
|
||||
|
||||
if (!_initializedTerminal)
|
||||
{
|
||||
// If we haven't initialized, there's no point in continuing.
|
||||
// Initialization will handle the renderer settings.
|
||||
return;
|
||||
}
|
||||
|
||||
// Update DxEngine settings under the lock
|
||||
_renderEngine->SetSelectionBackground(_settings.SelectionBackground());
|
||||
|
||||
_renderEngine->SetRetroTerminalEffect(_settings.RetroTerminalEffect());
|
||||
_renderEngine->SetPixelShaderPath(_settings.PixelShaderPath());
|
||||
_renderEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering());
|
||||
_renderEngine->SetSoftwareRendering(_settings.SoftwareRendering());
|
||||
|
||||
switch (_settings.AntialiasingMode())
|
||||
{
|
||||
case TextAntialiasingMode::Cleartype:
|
||||
_renderEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE);
|
||||
break;
|
||||
case TextAntialiasingMode::Aliased:
|
||||
_renderEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED);
|
||||
break;
|
||||
case TextAntialiasingMode::Grayscale:
|
||||
default:
|
||||
_renderEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
|
||||
break;
|
||||
}
|
||||
|
||||
// Refresh our font with the renderer
|
||||
const auto actualFontOldSize = _actualFont.GetSize();
|
||||
_UpdateFont();
|
||||
const auto actualFontNewSize = _actualFont.GetSize();
|
||||
if (actualFontNewSize != actualFontOldSize)
|
||||
{
|
||||
_RefreshSizeUnderLock();
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Given new settings for this profile, applies the settings to the current terminal.
|
||||
// Arguments:
|
||||
@@ -282,7 +349,6 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
// - <none>
|
||||
winrt::fire_and_forget TermControl::UpdateSettings(IControlSettings newSettings)
|
||||
{
|
||||
_settings = newSettings;
|
||||
auto weakThis{ get_weak() };
|
||||
|
||||
// Dispatch a call to the UI thread to apply the new settings to the
|
||||
@@ -292,49 +358,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
// If 'weakThis' is locked, then we can safely work with 'this'
|
||||
if (auto control{ weakThis.get() })
|
||||
{
|
||||
if (_closing)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
// Update our control settings
|
||||
_ApplyUISettings();
|
||||
|
||||
// Update the terminal core with its new Core settings
|
||||
_terminal->UpdateSettings(_settings);
|
||||
|
||||
auto lock = _terminal->LockForWriting();
|
||||
|
||||
// Update DxEngine settings under the lock
|
||||
_renderEngine->SetSelectionBackground(_settings.SelectionBackground());
|
||||
|
||||
_renderEngine->SetRetroTerminalEffect(_settings.RetroTerminalEffect());
|
||||
_renderEngine->SetPixelShaderPath(_settings.PixelShaderPath());
|
||||
_renderEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering());
|
||||
_renderEngine->SetSoftwareRendering(_settings.SoftwareRendering());
|
||||
|
||||
switch (_settings.AntialiasingMode())
|
||||
{
|
||||
case TextAntialiasingMode::Cleartype:
|
||||
_renderEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE);
|
||||
break;
|
||||
case TextAntialiasingMode::Aliased:
|
||||
_renderEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED);
|
||||
break;
|
||||
case TextAntialiasingMode::Grayscale:
|
||||
default:
|
||||
_renderEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
|
||||
break;
|
||||
}
|
||||
|
||||
// Refresh our font with the renderer
|
||||
const auto actualFontOldSize = _actualFont.GetSize();
|
||||
_UpdateFont();
|
||||
const auto actualFontNewSize = _actualFont.GetSize();
|
||||
if (actualFontNewSize != actualFontOldSize)
|
||||
{
|
||||
_RefreshSizeUnderLock();
|
||||
}
|
||||
_UpdateSettingsOnUIThread(newSettings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,21 +408,21 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TermControl::_ApplyUISettings()
|
||||
void TermControl::_ApplyUISettings(const IControlSettings& newSettings)
|
||||
{
|
||||
_InitializeBackgroundBrush();
|
||||
|
||||
COLORREF bg = _settings.DefaultBackground();
|
||||
COLORREF bg = newSettings.DefaultBackground();
|
||||
_BackgroundColorChanged(bg);
|
||||
|
||||
// Apply padding as swapChainPanel's margin
|
||||
auto newMargin = _ParseThicknessFromPadding(_settings.Padding());
|
||||
auto newMargin = _ParseThicknessFromPadding(newSettings.Padding());
|
||||
SwapChainPanel().Margin(newMargin);
|
||||
|
||||
// Initialize our font information.
|
||||
const auto fontFace = _settings.FontFace();
|
||||
const short fontHeight = gsl::narrow_cast<short>(_settings.FontSize());
|
||||
const auto fontWeight = _settings.FontWeight();
|
||||
const auto fontFace = newSettings.FontFace();
|
||||
const short fontHeight = gsl::narrow_cast<short>(newSettings.FontSize());
|
||||
const auto fontWeight = newSettings.FontWeight();
|
||||
// The font width doesn't terribly matter, we'll only be using the
|
||||
// height to look it up
|
||||
// The other params here also largely don't matter.
|
||||
@@ -410,12 +434,12 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
|
||||
// set TSF Foreground
|
||||
Media::SolidColorBrush foregroundBrush{};
|
||||
foregroundBrush.Color(static_cast<til::color>(_settings.DefaultForeground()));
|
||||
foregroundBrush.Color(static_cast<til::color>(newSettings.DefaultForeground()));
|
||||
TSFInputControl().Foreground(foregroundBrush);
|
||||
TSFInputControl().Margin(newMargin);
|
||||
|
||||
// Apply settings for scrollbar
|
||||
if (_settings.ScrollState() == ScrollbarState::Hidden)
|
||||
if (newSettings.ScrollState() == ScrollbarState::Hidden)
|
||||
{
|
||||
// In the scenario where the user has turned off the OS setting to automatically hide scrollbars, the
|
||||
// Terminal scrollbar would still be visible; so, we need to set the control's visibility accordingly to
|
||||
@@ -1089,8 +1113,18 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
// selection.
|
||||
if (_terminal->IsSelectionActive() && !KeyEvent::IsModifierKey(vkey) && vkey != VK_SNAPSHOT)
|
||||
{
|
||||
_terminal->ClearSelection();
|
||||
_renderer->TriggerSelection();
|
||||
const CoreWindow window = CoreWindow::GetForCurrentThread();
|
||||
const auto leftWinKeyState = window.GetKeyState(VirtualKey::LeftWindows);
|
||||
const auto rightWinKeyState = window.GetKeyState(VirtualKey::RightWindows);
|
||||
const auto isLeftWinKeyDown = WI_IsFlagSet(leftWinKeyState, CoreVirtualKeyStates::Down);
|
||||
const auto isRightWinKeyDown = WI_IsFlagSet(rightWinKeyState, CoreVirtualKeyStates::Down);
|
||||
|
||||
// GH#8791 - don't dismiss selection if Windows key was also pressed as a key-combination.
|
||||
if (!isLeftWinKeyDown && !isRightWinKeyDown)
|
||||
{
|
||||
_terminal->ClearSelection();
|
||||
_renderer->TriggerSelection();
|
||||
}
|
||||
|
||||
if (vkey == VK_ESCAPE)
|
||||
{
|
||||
@@ -1353,22 +1387,16 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
const auto cursorPosition = point.Position();
|
||||
const auto terminalPosition = _GetTerminalPosition(cursorPosition);
|
||||
|
||||
if (!_focused && (_terminal->GetHyperlinkAtPosition(terminalPosition).empty()))
|
||||
{
|
||||
args.Handled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ptr.PointerDeviceType() == Windows::Devices::Input::PointerDeviceType::Mouse || ptr.PointerDeviceType() == Windows::Devices::Input::PointerDeviceType::Pen)
|
||||
{
|
||||
if (_CanSendVTMouseInput())
|
||||
if (_focused && _CanSendVTMouseInput())
|
||||
{
|
||||
_TrySendMouseEvent(point);
|
||||
args.Handled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (point.Properties().IsLeftButtonPressed())
|
||||
if (_focused && point.Properties().IsLeftButtonPressed())
|
||||
{
|
||||
auto lock = _terminal->LockForWriting();
|
||||
|
||||
@@ -1414,50 +1442,9 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
}
|
||||
}
|
||||
|
||||
if (terminalPosition != _lastHoveredCell)
|
||||
{
|
||||
const auto uri = _terminal->GetHyperlinkAtPosition(terminalPosition);
|
||||
if (!uri.empty())
|
||||
{
|
||||
// Update the tooltip with the URI
|
||||
HoveredUri().Text(uri);
|
||||
|
||||
// Set the border thickness so it covers the entire cell
|
||||
const auto charSizeInPixels = CharacterDimensions();
|
||||
const auto htInDips = charSizeInPixels.Height / SwapChainPanel().CompositionScaleY();
|
||||
const auto wtInDips = charSizeInPixels.Width / SwapChainPanel().CompositionScaleX();
|
||||
const Thickness newThickness{ wtInDips, htInDips, 0, 0 };
|
||||
HyperlinkTooltipBorder().BorderThickness(newThickness);
|
||||
|
||||
// Compute the location of the top left corner of the cell in DIPS
|
||||
const til::size marginsInDips{ til::math::rounding, GetPadding().Left, GetPadding().Top };
|
||||
const til::point startPos{ terminalPosition.X, terminalPosition.Y };
|
||||
const til::size fontSize{ _actualFont.GetSize() };
|
||||
const til::point posInPixels{ startPos * fontSize };
|
||||
const til::point posInDIPs{ posInPixels / SwapChainPanel().CompositionScaleX() };
|
||||
const til::point locationInDIPs{ posInDIPs + marginsInDips };
|
||||
|
||||
// Move the border to the top left corner of the cell
|
||||
OverlayCanvas().SetLeft(HyperlinkTooltipBorder(), (locationInDIPs.x() - SwapChainPanel().ActualOffset().x));
|
||||
OverlayCanvas().SetTop(HyperlinkTooltipBorder(), (locationInDIPs.y() - SwapChainPanel().ActualOffset().y));
|
||||
}
|
||||
_lastHoveredCell = terminalPosition;
|
||||
|
||||
const auto newId = _terminal->GetHyperlinkIdAtPosition(terminalPosition);
|
||||
const auto newInterval = _terminal->GetHyperlinkIntervalFromPosition(terminalPosition);
|
||||
// If the hyperlink ID changed or the interval changed, trigger a redraw all
|
||||
// (so this will happen both when we move onto a link and when we move off a link)
|
||||
if (newId != _lastHoveredId || (newInterval != _lastHoveredInterval))
|
||||
{
|
||||
_lastHoveredId = newId;
|
||||
_lastHoveredInterval = newInterval;
|
||||
_renderEngine->UpdateHyperlinkHoveredId(newId);
|
||||
_renderer->UpdateLastHoveredInterval(newInterval);
|
||||
_renderer->TriggerRedrawAll();
|
||||
}
|
||||
}
|
||||
_UpdateHoveredCell(terminalPosition);
|
||||
}
|
||||
else if (ptr.PointerDeviceType() == Windows::Devices::Input::PointerDeviceType::Touch && _touchAnchor)
|
||||
else if (_focused && ptr.PointerDeviceType() == Windows::Devices::Input::PointerDeviceType::Touch && _touchAnchor)
|
||||
{
|
||||
const auto contactRect = point.Properties().ContactRect();
|
||||
winrt::Windows::Foundation::Point newTouchPoint{ contactRect.X, contactRect.Y };
|
||||
@@ -2598,6 +2585,17 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
// closed. We can just do it whenever.
|
||||
_AsyncCloseConnection();
|
||||
|
||||
{
|
||||
// GH#8734:
|
||||
// We lock the terminal here to make sure it isn't still being
|
||||
// used in the connection thread before we destroy the renderer.
|
||||
// However, we must unlock it again prior to triggering the
|
||||
// teardown, to avoid the render thread being deadlocked. The
|
||||
// renderer may be waiting to acquire the terminal lock, while
|
||||
// we're waiting for the renderer to finish.
|
||||
auto lock = _terminal->LockForWriting();
|
||||
}
|
||||
|
||||
if (auto localRenderEngine{ std::exchange(_renderEngine, nullptr) })
|
||||
{
|
||||
if (auto localRenderer{ std::exchange(_renderer, nullptr) })
|
||||
@@ -2896,7 +2894,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
// - The Microsoft::Terminal::Core::ControlKeyStates representing the modifier key states.
|
||||
ControlKeyStates TermControl::_GetPressedModifierKeys() const
|
||||
{
|
||||
CoreWindow window = CoreWindow::GetForCurrentThread();
|
||||
const CoreWindow window = CoreWindow::GetForCurrentThread();
|
||||
// DONT USE
|
||||
// != CoreVirtualKeyStates::None
|
||||
// OR
|
||||
@@ -3279,6 +3277,74 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
return _terminal->GetTaskbarProgress();
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - Updates last hovered cell, renders / removes rendering of hyper-link if required
|
||||
// Arguments:
|
||||
// - terminalPosition: The terminal position of the pointer
|
||||
void TermControl::_UpdateHoveredCell(const std::optional<COORD>& terminalPosition)
|
||||
{
|
||||
if (terminalPosition == _lastHoveredCell)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastHoveredCell = terminalPosition;
|
||||
|
||||
if (terminalPosition.has_value())
|
||||
{
|
||||
const auto uri = _terminal->GetHyperlinkAtPosition(*terminalPosition);
|
||||
if (!uri.empty())
|
||||
{
|
||||
// Update the tooltip with the URI
|
||||
HoveredUri().Text(uri);
|
||||
|
||||
// Set the border thickness so it covers the entire cell
|
||||
const auto charSizeInPixels = CharacterDimensions();
|
||||
const auto htInDips = charSizeInPixels.Height / SwapChainPanel().CompositionScaleY();
|
||||
const auto wtInDips = charSizeInPixels.Width / SwapChainPanel().CompositionScaleX();
|
||||
const Thickness newThickness{ wtInDips, htInDips, 0, 0 };
|
||||
HyperlinkTooltipBorder().BorderThickness(newThickness);
|
||||
|
||||
// Compute the location of the top left corner of the cell in DIPS
|
||||
const til::size marginsInDips{ til::math::rounding, GetPadding().Left, GetPadding().Top };
|
||||
const til::point startPos{ terminalPosition->X, terminalPosition->Y };
|
||||
const til::size fontSize{ _actualFont.GetSize() };
|
||||
const til::point posInPixels{ startPos * fontSize };
|
||||
const til::point posInDIPs{ posInPixels / SwapChainPanel().CompositionScaleX() };
|
||||
const til::point locationInDIPs{ posInDIPs + marginsInDips };
|
||||
|
||||
// Move the border to the top left corner of the cell
|
||||
OverlayCanvas().SetLeft(HyperlinkTooltipBorder(), (locationInDIPs.x() - SwapChainPanel().ActualOffset().x));
|
||||
OverlayCanvas().SetTop(HyperlinkTooltipBorder(), (locationInDIPs.y() - SwapChainPanel().ActualOffset().y));
|
||||
}
|
||||
}
|
||||
|
||||
const uint16_t newId = terminalPosition.has_value() ? _terminal->GetHyperlinkIdAtPosition(*terminalPosition) : 0u;
|
||||
const auto newInterval = terminalPosition.has_value() ? _terminal->GetHyperlinkIntervalFromPosition(*terminalPosition) : std::nullopt;
|
||||
|
||||
// If the hyperlink ID changed or the interval changed, trigger a redraw all
|
||||
// (so this will happen both when we move onto a link and when we move off a link)
|
||||
if (newId != _lastHoveredId || (newInterval != _lastHoveredInterval))
|
||||
{
|
||||
_lastHoveredId = newId;
|
||||
_lastHoveredInterval = newInterval;
|
||||
_renderEngine->UpdateHyperlinkHoveredId(newId);
|
||||
_renderer->UpdateLastHoveredInterval(newInterval);
|
||||
_renderer->TriggerRedrawAll();
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Handle a mouse exited event, specifically clearing last hovered cell
|
||||
// and removing selection from hyper link if exists
|
||||
// Arguments:
|
||||
// - sender: not used
|
||||
// - args: event data
|
||||
void TermControl::_PointerExitedHandler(Windows::Foundation::IInspectable const& /*sender*/, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& /*e*/)
|
||||
{
|
||||
_UpdateHoveredCell(std::nullopt);
|
||||
}
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
// Winrt events need a method for adding a callback to the event and removing the callback.
|
||||
// These macros will define them both for you.
|
||||
|
||||
@@ -240,7 +240,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
std::optional<winrt::Windows::Foundation::Point> _touchAnchor;
|
||||
|
||||
// Track the last cell we hovered over (used in pointerMovedHandler)
|
||||
COORD _lastHoveredCell;
|
||||
std::optional<COORD> _lastHoveredCell;
|
||||
// Track the last hyperlink ID we hovered over
|
||||
uint16_t _lastHoveredId;
|
||||
|
||||
@@ -263,7 +263,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
|
||||
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
|
||||
|
||||
void _ApplyUISettings();
|
||||
void _ApplyUISettings(const IControlSettings&);
|
||||
void _UpdateSettingsOnUIThread(const IControlSettings& newSettings);
|
||||
void _UpdateSystemParameterSettings() noexcept;
|
||||
void _InitializeBackgroundBrush();
|
||||
winrt::fire_and_forget _BackgroundColorChanged(const COLORREF color);
|
||||
@@ -277,6 +278,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
void _PointerPressedHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
|
||||
void _PointerMovedHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
|
||||
void _PointerReleasedHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
|
||||
void _PointerExitedHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
|
||||
void _MouseWheelHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
|
||||
void _ScrollbarChangeHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs const& e);
|
||||
void _GotFocusHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
@@ -337,6 +339,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
void _FontInfoHandler(const IInspectable& sender, const FontInfoEventArgs& eventArgs);
|
||||
|
||||
winrt::fire_and_forget _AsyncCloseConnection();
|
||||
|
||||
void _UpdateHoveredCell(const std::optional<COORD>& terminalPosition);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@
|
||||
Background="Transparent"
|
||||
PointerPressed="_PointerPressedHandler"
|
||||
PointerMoved="_PointerMovedHandler"
|
||||
PointerReleased="_PointerReleasedHandler">
|
||||
PointerReleased="_PointerReleasedHandler"
|
||||
PointerExited="_PointerExitedHandler">
|
||||
|
||||
<SwapChainPanel x:Name="SwapChainPanel"
|
||||
SizeChanged="_SwapChainSizeChanged"
|
||||
|
||||
@@ -474,7 +474,19 @@ bool TerminalDispatch::DoConEmuAction(const std::wstring_view string) noexcept
|
||||
{
|
||||
if (parts.size() >= 2)
|
||||
{
|
||||
return _terminalApi.SetWorkingDirectory(til::at(parts, 1));
|
||||
const auto path = til::at(parts, 1);
|
||||
// The path should be surrounded with '"' according to the documentation of ConEmu.
|
||||
// An example: 9;"D:/"
|
||||
if (path.at(0) == L'"' && path.at(path.size() - 1) == L'"' && path.size() >= 3)
|
||||
{
|
||||
return _terminalApi.SetWorkingDirectory(path.substr(1, path.size() - 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we fail to find the surrounding quotation marks, we'll give the path a try anyway.
|
||||
// ConEmu also does this.
|
||||
return _terminalApi.SetWorkingDirectory(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
<!--Tab Switcher Mode-->
|
||||
<ContentPresenter Style="{StaticResource SettingContainerStyle}">
|
||||
<muxc:RadioButtons x:Uid="Globals_TabSwitcherMode"
|
||||
SelectedItem="{x:Bind CurrentTabSwitcherMode}"
|
||||
SelectedItem="{x:Bind CurrentTabSwitcherMode, Mode=TwoWay}"
|
||||
ItemsSource="{x:Bind TabSwitcherModeList}"
|
||||
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"/>
|
||||
</ContentPresenter>
|
||||
|
||||
@@ -77,7 +77,7 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
<!--Launch Mode-->
|
||||
<ContentPresenter Style="{StaticResource SettingContainerStyle}">
|
||||
<muxc:RadioButtons x:Uid="Globals_LaunchMode"
|
||||
SelectedItem="{x:Bind CurrentLaunchMode}"
|
||||
SelectedItem="{x:Bind CurrentLaunchMode, Mode=TwoWay}"
|
||||
ItemsSource="{x:Bind LaunchModeList}"
|
||||
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"/>
|
||||
</ContentPresenter>
|
||||
|
||||
@@ -874,10 +874,18 @@ winrt::Microsoft::Terminal::Settings::Model::ColorScheme CascadiaSettings::GetCo
|
||||
// - <none>
|
||||
void CascadiaSettings::UpdateColorSchemeReferences(const hstring oldName, const hstring newName)
|
||||
{
|
||||
// update profiles.defaults, if necessary
|
||||
if (_userDefaultProfileSettings &&
|
||||
_userDefaultProfileSettings->HasColorSchemeName() &&
|
||||
_userDefaultProfileSettings->ColorSchemeName() == oldName)
|
||||
{
|
||||
_userDefaultProfileSettings->ColorSchemeName(newName);
|
||||
}
|
||||
|
||||
// update all profiles referencing this color scheme
|
||||
for (const auto& profile : _allProfiles)
|
||||
{
|
||||
if (profile.ColorSchemeName() == oldName)
|
||||
if (profile.HasColorSchemeName() && profile.ColorSchemeName() == oldName)
|
||||
{
|
||||
profile.ColorSchemeName(newName);
|
||||
}
|
||||
|
||||
@@ -1078,9 +1078,13 @@ void CascadiaSettings::WriteSettingsToDisk() const
|
||||
Json::Value CascadiaSettings::ToJson() const
|
||||
{
|
||||
// top-level json object
|
||||
// directly inject "globals" and "$schema" into here
|
||||
// directly inject "globals", "$schema", and "disabledProfileSources" into here
|
||||
Json::Value json{ _globals->ToJson() };
|
||||
JsonUtils::SetValueForKey(json, SchemaKey, JsonKey(SchemaValue));
|
||||
if (_userSettings.isMember(JsonKey(DisabledProfileSourcesKey)))
|
||||
{
|
||||
json[JsonKey(DisabledProfileSourcesKey)] = _userSettings[JsonKey(DisabledProfileSourcesKey)];
|
||||
}
|
||||
|
||||
// "profiles" will always be serialized as an object
|
||||
Json::Value profiles{ Json::ValueType::objectValue };
|
||||
|
||||
@@ -375,11 +375,10 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::SplitType)
|
||||
|
||||
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::SettingsTarget)
|
||||
{
|
||||
JSON_MAPPINGS(4) = {
|
||||
JSON_MAPPINGS(3) = {
|
||||
pair_type{ "settingsFile", ValueType::SettingsFile },
|
||||
pair_type{ "defaultsFile", ValueType::DefaultsFile },
|
||||
pair_type{ "allFiles", ValueType::AllFiles },
|
||||
pair_type{ "settingsUI", ValueType::SettingsUI },
|
||||
pair_type{ "allFiles", ValueType::AllFiles }
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace TerminalCoreUnitTests
|
||||
TEST_METHOD(AddHyperlinkCustomIdDifferentUri);
|
||||
|
||||
TEST_METHOD(SetTaskbarProgress);
|
||||
TEST_METHOD(SetWorkingDirectory);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -388,3 +389,59 @@ void TerminalCoreUnitTests::TerminalApiTest::SetTaskbarProgress()
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(1));
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(80));
|
||||
}
|
||||
|
||||
void TerminalCoreUnitTests::TerminalApiTest::SetWorkingDirectory()
|
||||
{
|
||||
Terminal term;
|
||||
DummyRenderTarget emptyRT;
|
||||
term.Create({ 100, 100 }, 0, emptyRT);
|
||||
|
||||
auto& stateMachine = *(term._stateMachine);
|
||||
|
||||
// Test setting working directory using OSC 9;9
|
||||
// Initial CWD should be empty
|
||||
VERIFY_IS_TRUE(term.GetWorkingDirectory().empty());
|
||||
|
||||
// Invalid sequences should not change CWD
|
||||
stateMachine.ProcessString(L"\x1b]9;9\x9c");
|
||||
VERIFY_IS_TRUE(term.GetWorkingDirectory().empty());
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;9\"\x9c");
|
||||
VERIFY_IS_TRUE(term.GetWorkingDirectory().empty());
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;9\"C:\\\"\x9c");
|
||||
VERIFY_IS_TRUE(term.GetWorkingDirectory().empty());
|
||||
|
||||
// Valid sequences should change CWD
|
||||
stateMachine.ProcessString(L"\x1b]9;9;\"C:\\\"\x9c");
|
||||
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"C:\\");
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;9;\"C:\\Program Files\"\x9c");
|
||||
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"C:\\Program Files");
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;9;\"D:\\中文\"\x9c");
|
||||
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"D:\\中文");
|
||||
|
||||
// Test OSC 9;9 sequences without quotation marks
|
||||
stateMachine.ProcessString(L"\x1b]9;9;C:\\\x9c");
|
||||
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"C:\\");
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;9;C:\\Program Files\x9c");
|
||||
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"C:\\Program Files");
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;9;D:\\中文\x9c");
|
||||
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"D:\\中文");
|
||||
|
||||
// These OSC 9;9 sequences will result in invalid CWD. We shouldn't crash on these.
|
||||
stateMachine.ProcessString(L"\x1b]9;9;\"\x9c");
|
||||
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"\"");
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;9;\"\"\x9c");
|
||||
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"\"\"");
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;9;\"\"\"\x9c");
|
||||
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"\"");
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;9;\"\"\"\"\x9c");
|
||||
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"\"\"");
|
||||
}
|
||||
|
||||
@@ -138,7 +138,9 @@ namespace Microsoft.Terminal.Wpf
|
||||
|
||||
NativeMethods.TerminalSetTheme(this.terminal, theme, fontFamily, fontSize, (int)dpiScale.PixelsPerInchX);
|
||||
|
||||
if (!this.RenderSize.IsEmpty && !this.TerminalControlSize.IsEmpty)
|
||||
// Validate before resizing that we have a non-zero size.
|
||||
if (!this.RenderSize.IsEmpty && !this.TerminalControlSize.IsEmpty
|
||||
&& this.TerminalControlSize.Width != 0 && this.TerminalControlSize.Height != 0)
|
||||
{
|
||||
this.Resize(this.TerminalControlSize);
|
||||
}
|
||||
@@ -166,7 +168,7 @@ namespace Microsoft.Terminal.Wpf
|
||||
{
|
||||
if (renderSize.Width == 0 || renderSize.Height == 0)
|
||||
{
|
||||
throw new ArgumentException(nameof(renderSize), "Terminal column or row count cannot be 0.");
|
||||
throw new ArgumentException("Terminal column or row count cannot be 0.", nameof(renderSize));
|
||||
}
|
||||
|
||||
NativeMethods.TerminalTriggerResize(
|
||||
@@ -191,11 +193,11 @@ namespace Microsoft.Terminal.Wpf
|
||||
{
|
||||
if (rows == 0)
|
||||
{
|
||||
throw new ArgumentException(nameof(rows), "Terminal row count cannot be 0.");
|
||||
throw new ArgumentException("Terminal row count cannot be 0.", nameof(rows));
|
||||
}
|
||||
else if (columns == 0)
|
||||
{
|
||||
throw new ArgumentException(nameof(columns), "Terminal column count cannot be 0.");
|
||||
throw new ArgumentException("Terminal column count cannot be 0.", nameof(columns));
|
||||
}
|
||||
|
||||
NativeMethods.SIZE dimensionsInPixels;
|
||||
|
||||
@@ -133,6 +133,11 @@ namespace Microsoft.Terminal.Wpf
|
||||
rendersize.Width *= dpiScale.DpiScaleX;
|
||||
rendersize.Height *= dpiScale.DpiScaleY;
|
||||
|
||||
if (rendersize.Width == 0 || rendersize.Height == 0)
|
||||
{
|
||||
return (0, 0);
|
||||
}
|
||||
|
||||
this.termContainer.Resize(rendersize);
|
||||
|
||||
return (this.Rows, this.Columns);
|
||||
|
||||
@@ -41,6 +41,16 @@ HRESULT RenderEngineBase::PrepareRenderInfo(const RenderFrameInfo& /*info*/) noe
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - By default, no one should need continuous redraw. It ruins performance
|
||||
// in terms of CPU, memory, and battery life to just paint forever.
|
||||
// That's why we sleep when there's nothing to draw.
|
||||
// But if you REALLY WANT to do special effects... you need to keep painting.
|
||||
[[nodiscard]] bool RenderEngineBase::RequiresContinuousRedraw() noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Blocks until the engine is able to render without blocking.
|
||||
void RenderEngineBase::WaitUntilCanRender() noexcept
|
||||
|
||||
@@ -133,6 +133,14 @@ try
|
||||
|
||||
auto endPaint = wil::scope_exit([&]() {
|
||||
LOG_IF_FAILED(pEngine->EndPaint());
|
||||
|
||||
// If the engine tells us it really wants to redraw immediately,
|
||||
// tell the thread so it doesn't go to sleep and ticks again
|
||||
// at the next opportunity.
|
||||
if (pEngine->RequiresContinuousRedraw())
|
||||
{
|
||||
_NotifyPaintFrame();
|
||||
}
|
||||
});
|
||||
|
||||
// A. Prep Colors
|
||||
|
||||
@@ -411,6 +411,8 @@ HRESULT DxEngine::_SetupTerminalEffects()
|
||||
pixelShaderSettingsBufferDesc.ByteWidth = sizeof(_pixelShaderSettings);
|
||||
pixelShaderSettingsBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
|
||||
_shaderStartTime = std::chrono::steady_clock::now();
|
||||
|
||||
_ComputePixelShaderSettings();
|
||||
|
||||
D3D11_SUBRESOURCE_DATA pixelShaderSettingsInitData{};
|
||||
@@ -454,9 +456,8 @@ void DxEngine::_ComputePixelShaderSettings() noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
// Set the time
|
||||
// TODO:GH#7013 Grab timestamp
|
||||
_pixelShaderSettings.Time = 0.0f;
|
||||
// Set the time (seconds since the shader was loaded)
|
||||
_pixelShaderSettings.Time = std::chrono::duration_cast<std::chrono::duration<float>>(std::chrono::steady_clock::now() - _shaderStartTime).count();
|
||||
|
||||
// Set the UI Scale
|
||||
_pixelShaderSettings.Scale = _scale;
|
||||
@@ -1438,6 +1439,28 @@ CATCH_RETURN()
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - When the shaders are on, say that we need to keep redrawing every
|
||||
// possible frame in case they have some smooth action on every frame tick.
|
||||
// It is presumed that if you're using shaders, you're not about performance...
|
||||
// You're instead about OOH SHINY. And that's OK. But returning true here is 100%
|
||||
// a perf detriment.
|
||||
[[nodiscard]] bool DxEngine::RequiresContinuousRedraw() noexcept
|
||||
{
|
||||
// We're only going to request continuous redraw if someone is using
|
||||
// a pixel shader from a path because we cannot tell if those are using the
|
||||
// time parameter or not.
|
||||
// And if they are using time, they probably need it to tick continuously.
|
||||
//
|
||||
// By contrast, the in-built retro effect does NOT need it,
|
||||
// so let's not tick for it and save some amount of performance.
|
||||
//
|
||||
// Finally... if we're not using effects at all... let the render thread
|
||||
// go to sleep. It deserves it. That thread works hard. Also it sleeping
|
||||
// saves battery power and all sorts of related perf things.
|
||||
return _terminalEffectsEnabled && !_pixelShaderPath.empty();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Blocks until the engine is able to render without blocking.
|
||||
// - See https://docs.microsoft.com/en-us/windows/uwp/gaming/reduce-latency-with-dxgi-1-3-swap-chains.
|
||||
|
||||
@@ -84,6 +84,8 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] HRESULT StartPaint() noexcept override;
|
||||
[[nodiscard]] HRESULT EndPaint() noexcept override;
|
||||
|
||||
[[nodiscard]] bool RequiresContinuousRedraw() noexcept override;
|
||||
|
||||
void WaitUntilCanRender() noexcept override;
|
||||
[[nodiscard]] HRESULT Present() noexcept override;
|
||||
|
||||
@@ -246,6 +248,8 @@ namespace Microsoft::Console::Render
|
||||
std::wstring _pixelShaderPath;
|
||||
bool _pixelShaderLoaded{ false };
|
||||
|
||||
std::chrono::steady_clock::time_point _shaderStartTime;
|
||||
|
||||
// DX resources needed for terminal effects
|
||||
::Microsoft::WRL::ComPtr<ID3D11RenderTargetView> _renderTargetView;
|
||||
::Microsoft::WRL::ComPtr<ID3D11VertexShader> _vertexShader;
|
||||
|
||||
@@ -55,6 +55,7 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] virtual HRESULT StartPaint() noexcept = 0;
|
||||
[[nodiscard]] virtual HRESULT EndPaint() noexcept = 0;
|
||||
|
||||
[[nodiscard]] virtual bool RequiresContinuousRedraw() noexcept = 0;
|
||||
virtual void WaitUntilCanRender() noexcept = 0;
|
||||
[[nodiscard]] virtual HRESULT Present() noexcept = 0;
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@ namespace Microsoft::Console::Render
|
||||
|
||||
[[nodiscard]] HRESULT PrepareRenderInfo(const RenderFrameInfo& info) noexcept override;
|
||||
|
||||
[[nodiscard]] virtual bool RequiresContinuousRedraw() noexcept override;
|
||||
|
||||
void WaitUntilCanRender() noexcept override;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -3,50 +3,36 @@
|
||||
|
||||
#include "precomp.h"
|
||||
#include "inc/Environment.hpp"
|
||||
#include "wil/token_helpers.h"
|
||||
|
||||
using namespace ::Microsoft::Console::Utils;
|
||||
|
||||
// We cannot use spand or not_null because we're dealing with \0\0-terminated buffers of unknown length
|
||||
#pragma warning(disable : 26481 26429)
|
||||
|
||||
// Function Description:
|
||||
// - Wraps win32's CreateEnvironmentBlock to return a smart pointer.
|
||||
EnvironmentBlockPtr Microsoft::Console::Utils::CreateEnvironmentBlock()
|
||||
{
|
||||
void* newEnvironmentBlock{ nullptr };
|
||||
auto processToken{ wil::open_current_access_token(TOKEN_QUERY | TOKEN_DUPLICATE) };
|
||||
if (!::CreateEnvironmentBlock(&newEnvironmentBlock, processToken.get(), FALSE))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return EnvironmentBlockPtr{ newEnvironmentBlock };
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Updates an EnvironmentVariableMapW with the current process's unicode
|
||||
// environment variables ignoring ones already set in the provided map.
|
||||
// Arguments:
|
||||
// - map: The map to populate with the current processes's environment variables.
|
||||
// - environmentBlock: Optional environment block to use when filling map. If omitted,
|
||||
// defaults to the current environment.
|
||||
// Return Value:
|
||||
// - S_OK if we succeeded, or an appropriate HRESULT for failing
|
||||
HRESULT Microsoft::Console::Utils::UpdateEnvironmentMapW(EnvironmentVariableMapW& map, void* environmentBlock) noexcept
|
||||
HRESULT Microsoft::Console::Utils::UpdateEnvironmentMapW(EnvironmentVariableMapW& map) noexcept
|
||||
try
|
||||
{
|
||||
wchar_t const* activeEnvironmentBlock{ static_cast<wchar_t const*>(environmentBlock) };
|
||||
LPWCH currentEnvVars{};
|
||||
auto freeCurrentEnv = wil::scope_exit([&] {
|
||||
if (currentEnvVars)
|
||||
{
|
||||
FreeEnvironmentStringsW(currentEnvVars);
|
||||
currentEnvVars = nullptr;
|
||||
}
|
||||
});
|
||||
|
||||
wil::unique_environstrings_ptr currentEnvVars;
|
||||
if (!activeEnvironmentBlock)
|
||||
{
|
||||
currentEnvVars.reset(::GetEnvironmentStringsW());
|
||||
RETURN_HR_IF_NULL(E_OUTOFMEMORY, currentEnvVars);
|
||||
activeEnvironmentBlock = currentEnvVars.get();
|
||||
}
|
||||
currentEnvVars = ::GetEnvironmentStringsW();
|
||||
RETURN_HR_IF_NULL(E_OUTOFMEMORY, currentEnvVars);
|
||||
|
||||
// Each entry is NULL-terminated; block is guaranteed to be double-NULL terminated at a minimum.
|
||||
for (wchar_t const* lastCh{ activeEnvironmentBlock }; *lastCh != '\0'; ++lastCh)
|
||||
for (wchar_t const* lastCh{ currentEnvVars }; *lastCh != '\0'; ++lastCh)
|
||||
{
|
||||
// Copy current entry into temporary map.
|
||||
const size_t cchEntry{ ::wcslen(lastCh) };
|
||||
|
||||
@@ -21,12 +21,9 @@ namespace Microsoft::Console::Utils
|
||||
}
|
||||
};
|
||||
|
||||
using EnvironmentBlockPtr = wil::unique_any<void*, decltype(::DestroyEnvironmentBlock), ::DestroyEnvironmentBlock>;
|
||||
[[nodiscard]] EnvironmentBlockPtr CreateEnvironmentBlock();
|
||||
|
||||
using EnvironmentVariableMapW = std::map<std::wstring, std::wstring, WStringCaseInsensitiveCompare>;
|
||||
|
||||
[[nodiscard]] HRESULT UpdateEnvironmentMapW(EnvironmentVariableMapW& map, void* environmentBlock = nullptr) noexcept;
|
||||
[[nodiscard]] HRESULT UpdateEnvironmentMapW(EnvironmentVariableMapW& map) noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT EnvironmentMapToEnvironmentStringsW(EnvironmentVariableMapW& map,
|
||||
std::vector<wchar_t>& newEnvVars) noexcept;
|
||||
|
||||
@@ -29,7 +29,6 @@ Abstract:
|
||||
|
||||
// Windows Header Files:
|
||||
#include <windows.h>
|
||||
#include <userenv.h>
|
||||
#include <combaseapi.h>
|
||||
#include <UIAutomation.h>
|
||||
#include <objbase.h>
|
||||
|
||||
Reference in New Issue
Block a user