mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
[FHL] Make VTApiRoutines, which does VT translation for output (#11264)
Make a VTApiRoutines servicer that does minimal translations instead of environmental simulation for some output methods. Remaining methods are backed on the existing console host infrastructure (primarily input related methods). ## PR Checklist * [x] I work here * [x] It's Fix-Hack-Learn quality so it's behind a feature gate so we can keep refining it. But it's a start! To turn this on, you will have to be in the Dev or Preview rings (feature staged). Then add `experimental.connection.passthroughMode: true` to a profile and on the next launch, the flags will propagate down through the `ConptyConnection` into the underlying `Openconsole.exe` startup and tell it to use the passthrough mode instead of the full simulation mode. ## Validation Steps Performed - Played with it manually in CMD.exe, it seems to work mostly. - Played with it manually in Ubuntu WSL, it seems to work. - Played with it manually in Powershell and it's mostly sad. It'll get there. Starts #1173
This commit is contained in:
parent
a24d419b7b
commit
2c2f4f9be2
3
.github/actions/spelling/allow/apis.txt
vendored
3
.github/actions/spelling/allow/apis.txt
vendored
@ -95,11 +95,12 @@ lround
|
||||
Lsa
|
||||
lsass
|
||||
LSHIFT
|
||||
memchr
|
||||
memicmp
|
||||
MENUCOMMAND
|
||||
MENUDATA
|
||||
MENUINFO
|
||||
MENUITEMINFOW
|
||||
MENUINFO
|
||||
MOUSELEAVE
|
||||
mov
|
||||
mptt
|
||||
|
||||
2
.github/actions/spelling/expect/expect.txt
vendored
2
.github/actions/spelling/expect/expect.txt
vendored
@ -519,6 +519,7 @@ DECAUPSS
|
||||
DECAWM
|
||||
DECCKM
|
||||
DECCOLM
|
||||
DECCRA
|
||||
DECDHL
|
||||
decdld
|
||||
DECDLD
|
||||
@ -2632,6 +2633,7 @@ VSTS
|
||||
VSTT
|
||||
vstudio
|
||||
vswhere
|
||||
vtapi
|
||||
vtapp
|
||||
VTE
|
||||
VTID
|
||||
|
||||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@ -94,7 +94,11 @@
|
||||
"xlocinfo": "cpp",
|
||||
"xmemory": "cpp",
|
||||
"xstddef": "cpp",
|
||||
"xtr1common": "cpp"
|
||||
"xtr1common": "cpp",
|
||||
"coroutine": "cpp",
|
||||
"format": "cpp",
|
||||
"forward_list": "cpp",
|
||||
"latch": "cpp"
|
||||
},
|
||||
"files.exclude": {
|
||||
"**/bin/**": true,
|
||||
|
||||
@ -2051,6 +2051,10 @@
|
||||
"default": false,
|
||||
"description": "When true, this profile should always open in an elevated context. If the window isn't running as an Administrator, then a new elevated window will be created."
|
||||
},
|
||||
"experimental.connection.passthroughMode": {
|
||||
"description": "When set to true, directs the PTY for this connection to use pass-through mode instead of the original Conhost PTY simulation engine. This is an experimental feature, and its continued existence is not guaranteed.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"experimental.retroTerminalEffect": {
|
||||
"description": "When set to true, enable retro terminal effects. This is an experimental feature, and its continued existence is not guaranteed.",
|
||||
"type": "boolean"
|
||||
|
||||
@ -242,7 +242,7 @@ HRESULT HwndTerminal::Initialize()
|
||||
_terminal->Create(COORD{ 80, 25 }, 1000, *_renderer);
|
||||
_terminal->SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, RGB(12, 12, 12));
|
||||
_terminal->SetColorTableEntry(TextColor::DEFAULT_FOREGROUND, RGB(204, 204, 204));
|
||||
_terminal->SetWriteInputCallback([=](std::wstring& input) noexcept { _WriteTextToConnection(input); });
|
||||
_terminal->SetWriteInputCallback([=](std::wstring_view input) noexcept { _WriteTextToConnection(input); });
|
||||
localPointerToThread->EnablePainting();
|
||||
|
||||
_multiClickTime = std::chrono::milliseconds{ GetDoubleClickTime() };
|
||||
@ -282,7 +282,7 @@ void HwndTerminal::RegisterScrollCallback(std::function<void(int, int, int)> cal
|
||||
_terminal->SetScrollPositionChangedCallback(callback);
|
||||
}
|
||||
|
||||
void HwndTerminal::_WriteTextToConnection(const std::wstring& input) noexcept
|
||||
void HwndTerminal::_WriteTextToConnection(const std::wstring_view input) noexcept
|
||||
{
|
||||
if (!_pfnWriteCallback)
|
||||
{
|
||||
|
||||
@ -108,7 +108,7 @@ private:
|
||||
friend void _stdcall TerminalKillFocus(void* terminal);
|
||||
|
||||
void _UpdateFont(int newDpi);
|
||||
void _WriteTextToConnection(const std::wstring& text) noexcept;
|
||||
void _WriteTextToConnection(const std::wstring_view text) noexcept;
|
||||
HRESULT _CopyTextToSystemClipboard(const TextBuffer::TextAndColor& rows, bool const fAlsoCopyFormatting);
|
||||
HRESULT _CopyToSystemClipboard(std::string stringToCopy, LPCWSTR lpszFormat);
|
||||
void _PasteTextFromClipboard() noexcept;
|
||||
|
||||
@ -1070,13 +1070,20 @@ namespace winrt::TerminalApp::implementation
|
||||
std::filesystem::path azBridgePath{ wil::GetModuleFileNameW<std::wstring>(nullptr) };
|
||||
azBridgePath.replace_filename(L"TerminalAzBridge.exe");
|
||||
connection = TerminalConnection::ConptyConnection();
|
||||
connection.Initialize(TerminalConnection::ConptyConnection::CreateSettings(azBridgePath.wstring(),
|
||||
L".",
|
||||
L"Azure",
|
||||
nullptr,
|
||||
::base::saturated_cast<uint32_t>(settings.InitialRows()),
|
||||
::base::saturated_cast<uint32_t>(settings.InitialCols()),
|
||||
winrt::guid()));
|
||||
auto valueSet = TerminalConnection::ConptyConnection::CreateSettings(azBridgePath.wstring(),
|
||||
L".",
|
||||
L"Azure",
|
||||
nullptr,
|
||||
::base::saturated_cast<uint32_t>(settings.InitialRows()),
|
||||
::base::saturated_cast<uint32_t>(settings.InitialCols()),
|
||||
winrt::guid());
|
||||
|
||||
if constexpr (Feature_VtPassthroughMode::IsEnabled())
|
||||
{
|
||||
valueSet.Insert(L"passthroughMode", Windows::Foundation::PropertyValue::CreateBoolean(settings.VtPassthrough()));
|
||||
}
|
||||
|
||||
connection.Initialize(valueSet);
|
||||
}
|
||||
|
||||
else
|
||||
@ -1114,13 +1121,17 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
auto conhostConn = TerminalConnection::ConptyConnection();
|
||||
conhostConn.Initialize(TerminalConnection::ConptyConnection::CreateSettings(settings.Commandline(),
|
||||
newWorkingDirectory,
|
||||
settings.StartingTitle(),
|
||||
envMap.GetView(),
|
||||
::base::saturated_cast<uint32_t>(settings.InitialRows()),
|
||||
::base::saturated_cast<uint32_t>(settings.InitialCols()),
|
||||
winrt::guid()));
|
||||
auto valueSet = TerminalConnection::ConptyConnection::CreateSettings(settings.Commandline(),
|
||||
newWorkingDirectory,
|
||||
settings.StartingTitle(),
|
||||
envMap.GetView(),
|
||||
::base::saturated_cast<uint32_t>(settings.InitialRows()),
|
||||
::base::saturated_cast<uint32_t>(settings.InitialCols()),
|
||||
winrt::guid());
|
||||
|
||||
valueSet.Insert(L"passthroughMode", Windows::Foundation::PropertyValue::CreateBoolean(settings.VtPassthrough()));
|
||||
|
||||
conhostConn.Initialize(valueSet);
|
||||
|
||||
sessionGuid = conhostConn.Guid();
|
||||
connection = conhostConn;
|
||||
|
||||
@ -266,6 +266,10 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
_initialCols = winrt::unbox_value_or<uint32_t>(settings.TryLookup(L"initialCols").try_as<Windows::Foundation::IPropertyValue>(), _initialCols);
|
||||
_guid = winrt::unbox_value_or<winrt::guid>(settings.TryLookup(L"guid").try_as<Windows::Foundation::IPropertyValue>(), _guid);
|
||||
_environment = settings.TryLookup(L"environment").try_as<Windows::Foundation::Collections::ValueSet>();
|
||||
if constexpr (Feature_VtPassthroughMode::IsEnabled())
|
||||
{
|
||||
_passthroughMode = winrt::unbox_value_or<bool>(settings.TryLookup(L"passthroughMode").try_as<Windows::Foundation::IPropertyValue>(), _passthroughMode);
|
||||
}
|
||||
}
|
||||
|
||||
if (_guid == guid{})
|
||||
@ -295,7 +299,17 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// handoff from an already-started PTY process.
|
||||
if (!_inPipe)
|
||||
{
|
||||
THROW_IF_FAILED(_CreatePseudoConsoleAndPipes(dimensions, PSEUDOCONSOLE_RESIZE_QUIRK | PSEUDOCONSOLE_WIN32_INPUT_MODE, &_inPipe, &_outPipe, &_hPC));
|
||||
DWORD flags = PSEUDOCONSOLE_RESIZE_QUIRK | PSEUDOCONSOLE_WIN32_INPUT_MODE;
|
||||
|
||||
if constexpr (Feature_VtPassthroughMode::IsEnabled())
|
||||
{
|
||||
if (_passthroughMode)
|
||||
{
|
||||
WI_SetFlag(flags, PSEUDOCONSOLE_PASSTHROUGH_MODE);
|
||||
}
|
||||
}
|
||||
|
||||
THROW_IF_FAILED(_CreatePseudoConsoleAndPipes(dimensions, flags, &_inPipe, &_outPipe, &_hPC));
|
||||
THROW_IF_FAILED(_LaunchAttachedClient());
|
||||
}
|
||||
// But if it was an inbound handoff... attempt to synchronize the size of it with what our connection
|
||||
|
||||
@ -85,6 +85,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
til::u8state _u8State{};
|
||||
std::wstring _u16Str{};
|
||||
std::array<char, 4096> _buffer{};
|
||||
bool _passthroughMode{};
|
||||
|
||||
DWORD _OutputThread();
|
||||
};
|
||||
|
||||
@ -77,7 +77,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// This event is explicitly revoked in the destructor: does not need weak_ref
|
||||
_connectionOutputEventToken = _connection.TerminalOutput({ this, &ControlCore::_connectionOutputHandler });
|
||||
|
||||
_terminal->SetWriteInputCallback([this](std::wstring& wstr) {
|
||||
_terminal->SetWriteInputCallback([this](std::wstring_view wstr) {
|
||||
_sendInputToConnection(wstr);
|
||||
});
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@ namespace Microsoft.Terminal.Core
|
||||
Boolean ForceVTInput;
|
||||
Boolean TrimBlockSelection;
|
||||
Boolean DetectURLs;
|
||||
Boolean VtPassthrough;
|
||||
|
||||
Windows.Foundation.IReference<Microsoft.Terminal.Core.Color> TabColor;
|
||||
Windows.Foundation.IReference<Microsoft.Terminal.Core.Color> StartingTabColor;
|
||||
|
||||
@ -21,6 +21,8 @@ namespace Microsoft::Terminal::Core
|
||||
|
||||
virtual void PrintString(std::wstring_view string) = 0;
|
||||
|
||||
virtual bool ReturnResponse(std::wstring_view responseString) = 0;
|
||||
|
||||
virtual TextAttribute GetTextAttributes() const = 0;
|
||||
virtual void SetTextAttributes(const TextAttribute& attrs) = 0;
|
||||
|
||||
|
||||
@ -1164,7 +1164,7 @@ void Terminal::_NotifyTerminalCursorPositionChanged() noexcept
|
||||
}
|
||||
}
|
||||
|
||||
void Terminal::SetWriteInputCallback(std::function<void(std::wstring&)> pfn) noexcept
|
||||
void Terminal::SetWriteInputCallback(std::function<void(std::wstring_view)> pfn) noexcept
|
||||
{
|
||||
_pfnWriteInput.swap(pfn);
|
||||
}
|
||||
|
||||
@ -77,10 +77,10 @@ public:
|
||||
void UpdateAppearance(const winrt::Microsoft::Terminal::Core::ICoreAppearance& appearance);
|
||||
void SetFontInfo(const FontInfo& fontInfo);
|
||||
|
||||
// Write goes through the parser
|
||||
// Write comes from the PTY and goes to our parser to be stored in the output buffer
|
||||
void Write(std::wstring_view stringView);
|
||||
|
||||
// WritePastedText goes directly to the connection
|
||||
// WritePastedText comes from our input and goes back to the PTY's input channel
|
||||
void WritePastedText(std::wstring_view stringView);
|
||||
|
||||
[[nodiscard]] std::unique_lock<til::ticket_lock> LockForReading();
|
||||
@ -97,6 +97,7 @@ public:
|
||||
#pragma region ITerminalApi
|
||||
// These methods are defined in TerminalApi.cpp
|
||||
void PrintString(std::wstring_view stringView) override;
|
||||
bool ReturnResponse(std::wstring_view responseString) override;
|
||||
TextAttribute GetTextAttributes() const override;
|
||||
void SetTextAttributes(const TextAttribute& attrs) override;
|
||||
Microsoft::Console::Types::Viewport GetBufferSize() override;
|
||||
@ -197,7 +198,7 @@ public:
|
||||
const bool IsUiaDataInitialized() const noexcept override;
|
||||
#pragma endregion
|
||||
|
||||
void SetWriteInputCallback(std::function<void(std::wstring&)> pfn) noexcept;
|
||||
void SetWriteInputCallback(std::function<void(std::wstring_view)> pfn) noexcept;
|
||||
void SetWarningBellCallback(std::function<void()> pfn) noexcept;
|
||||
void SetTitleChangedCallback(std::function<void(std::wstring_view)> pfn) noexcept;
|
||||
void SetTabColorChangedCallback(std::function<void(const std::optional<til::color>)> pfn) noexcept;
|
||||
@ -252,7 +253,7 @@ public:
|
||||
#pragma endregion
|
||||
|
||||
private:
|
||||
std::function<void(std::wstring&)> _pfnWriteInput;
|
||||
std::function<void(std::wstring_view)> _pfnWriteInput;
|
||||
std::function<void()> _pfnWarningBell;
|
||||
std::function<void(std::wstring_view)> _pfnTitleChanged;
|
||||
std::function<void(std::wstring_view)> _pfnCopyToClipboard;
|
||||
|
||||
@ -21,6 +21,16 @@ TextAttribute Terminal::GetTextAttributes() const
|
||||
return _buffer->GetCurrentAttributes();
|
||||
}
|
||||
|
||||
bool Terminal::ReturnResponse(std::wstring_view responseString)
|
||||
{
|
||||
if (!_pfnWriteInput)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_pfnWriteInput(responseString);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Terminal::SetTextAttributes(const TextAttribute& attrs)
|
||||
{
|
||||
_buffer->SetCurrentAttributes(attrs);
|
||||
|
||||
@ -442,6 +442,58 @@ bool TerminalDispatch::ResetMode(const DispatchTypes::ModeParams param)
|
||||
return _ModeParamsHelper(param, false);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - DSR - Reports status of a console property back to the STDIN based on the type of status requested.
|
||||
// - This particular routine responds to ANSI status patterns only (CSI # n), not the DEC format (CSI ? # n)
|
||||
// Arguments:
|
||||
// - statusType - ANSI status type indicating what property we should report back
|
||||
// Return Value:
|
||||
// - True if handled successfully. False otherwise.
|
||||
bool TerminalDispatch::DeviceStatusReport(const DispatchTypes::AnsiStatusType statusType)
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
switch (statusType)
|
||||
{
|
||||
case DispatchTypes::AnsiStatusType::OS_OperatingStatus:
|
||||
success = _OperatingStatus();
|
||||
break;
|
||||
case DispatchTypes::AnsiStatusType::CPR_CursorPositionReport:
|
||||
success = _CursorPositionReport();
|
||||
break;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - DSR-OS - Reports the operating status back to the input channel
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - True if handled successfully. False otherwise.
|
||||
bool TerminalDispatch::_OperatingStatus() const
|
||||
{
|
||||
// We always report a good operating condition.
|
||||
return _WriteResponse(L"\x1b[0n");
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - DSR-CPR - Reports the current cursor position within the viewport back to the input channel
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - True if handled successfully. False otherwise.
|
||||
bool TerminalDispatch::_CursorPositionReport() const
|
||||
{
|
||||
// Now send it back into the input channel of the console.
|
||||
// First format the response string.
|
||||
const auto pos = _terminalApi.GetCursorPosition();
|
||||
// VT has origin at 1,1 where as we use 0,0 internally
|
||||
const auto response = wil::str_printf<std::wstring>(L"\x1b[%d;%dR", pos.Y + 1, pos.X + 1);
|
||||
return _WriteResponse(response);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Start a hyperlink
|
||||
// Arguments:
|
||||
@ -545,6 +597,18 @@ bool TerminalDispatch::DoConEmuAction(const std::wstring_view string)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Helper to send a string reply to the input stream of the console.
|
||||
// - Used by various commands where the program attached would like a reply to one of the commands issued.
|
||||
// Arguments:
|
||||
// - reply - The reply string to transmit back to the input stream
|
||||
// Return Value:
|
||||
// - True if the string was sent to the connected application. False otherwise.
|
||||
bool TerminalDispatch::_WriteResponse(const std::wstring_view reply) const
|
||||
{
|
||||
return _terminalApi.ReturnResponse(reply);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Support routine for routing private mode parameters to be set/reset as flags
|
||||
// Arguments:
|
||||
|
||||
@ -75,6 +75,8 @@ public:
|
||||
bool SetMode(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::ModeParams /*param*/) override; // DECSET
|
||||
bool ResetMode(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::ModeParams /*param*/) override; // DECRST
|
||||
|
||||
bool DeviceStatusReport(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::AnsiStatusType /*statusType*/) override; // DSR, DSR-OS, DSR-CPR
|
||||
|
||||
bool AddHyperlink(const std::wstring_view uri, const std::wstring_view params) override;
|
||||
bool EndHyperlink() override;
|
||||
|
||||
@ -90,8 +92,12 @@ private:
|
||||
TextAttribute& attr,
|
||||
const bool isForeground);
|
||||
|
||||
bool _WriteResponse(const std::wstring_view reply) const;
|
||||
bool _ModeParamsHelper(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::ModeParams param, const bool enable);
|
||||
|
||||
bool _OperatingStatus() const;
|
||||
bool _CursorPositionReport() const;
|
||||
|
||||
void _ClearSingleTabStop();
|
||||
void _ClearAllTabStops();
|
||||
void _ResetTabStops();
|
||||
|
||||
@ -298,6 +298,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
return Feature_AtlasEngine::IsEnabled();
|
||||
}
|
||||
|
||||
bool ProfileViewModel::VtPassthroughAvailable() const noexcept
|
||||
{
|
||||
return Feature_VtPassthroughMode::IsEnabled();
|
||||
}
|
||||
|
||||
bool ProfileViewModel::UseParentProcessDirectory()
|
||||
{
|
||||
return StartingDirectory().empty();
|
||||
|
||||
@ -73,6 +73,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void CreateUnfocusedAppearance();
|
||||
void DeleteUnfocusedAppearance();
|
||||
bool AtlasEngineAvailable() const noexcept;
|
||||
bool VtPassthroughAvailable() const noexcept;
|
||||
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(ProfileSubPage, CurrentPage);
|
||||
|
||||
@ -103,6 +104,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, BellStyle);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, UseAtlasEngine);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, Elevate);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, VtPassthrough)
|
||||
|
||||
WINRT_PROPERTY(bool, IsBaseLayer, false);
|
||||
WINRT_PROPERTY(IHostedInWindow, WindowRoot, nullptr);
|
||||
|
||||
@ -63,6 +63,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
Boolean ShowUnfocusedAppearance { get; };
|
||||
AppearanceViewModel UnfocusedAppearance { get; };
|
||||
Boolean AtlasEngineAvailable { get; };
|
||||
Boolean VtPassthroughAvailable { get; };
|
||||
|
||||
void CreateUnfocusedAppearance();
|
||||
void DeleteUnfocusedAppearance();
|
||||
@ -94,5 +95,6 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Settings.Model.BellStyle, BellStyle);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, UseAtlasEngine);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, Elevate);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, VtPassthrough);
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,6 +127,16 @@
|
||||
<ToggleSwitch IsOn="{x:Bind Profile.UseAtlasEngine, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- VtPassthrough -->
|
||||
<local:SettingContainer x:Uid="Profile_VtPassthrough"
|
||||
ClearSettingValue="{x:Bind Profile.ClearVtPassthrough}"
|
||||
HasSettingValue="{x:Bind Profile.HasVtPassthrough, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.VtPassthroughOverrideSource, Mode=OneWay}"
|
||||
Visibility="{x:Bind Profile.VtPassthroughAvailable}">
|
||||
<ToggleSwitch IsOn="{x:Bind Profile.VtPassthrough, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
@ -1043,6 +1043,10 @@
|
||||
<value>Enable experimental text rendering engine</value>
|
||||
<comment>An option to enable an experimental text rendering engine</comment>
|
||||
</data>
|
||||
<data name="Profile_VtPassthrough.Header" xml:space="preserve">
|
||||
<value>Enable experimental virtual terminal passthrough</value>
|
||||
<comment>An option to enable experimental virtual terminal passthrough connectivity option with the underlying ConPTY</comment>
|
||||
</data>
|
||||
<data name="Profile_BellStyleAudible.Content" xml:space="preserve">
|
||||
<value>Audible</value>
|
||||
<comment>An option to choose from for the "bell style" setting. When selected, an audible cue is used to notify the user.</comment>
|
||||
|
||||
@ -76,7 +76,8 @@ Author(s):
|
||||
X(Model::BellStyle, BellStyle, "bellStyle", BellStyle::Audible) \
|
||||
X(bool, UseAtlasEngine, "experimental.useAtlasEngine", false) \
|
||||
X(Windows::Foundation::Collections::IVector<winrt::hstring>, BellSound, "bellSound", nullptr) \
|
||||
X(bool, Elevate, "elevate", false)
|
||||
X(bool, Elevate, "elevate", false) \
|
||||
X(bool, VtPassthrough, "experimental.connection.passthroughMode", false)
|
||||
|
||||
// Intentionally omitted Profile settings:
|
||||
// * Name
|
||||
|
||||
@ -64,6 +64,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
INHERITABLE_PROFILE_SETTING(Microsoft.Terminal.Control.ScrollbarState, ScrollState);
|
||||
INHERITABLE_PROFILE_SETTING(String, Padding);
|
||||
INHERITABLE_PROFILE_SETTING(String, Commandline);
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, VtPassthrough);
|
||||
|
||||
INHERITABLE_PROFILE_SETTING(String, StartingDirectory);
|
||||
String EvaluatedStartingDirectory { get; };
|
||||
|
||||
@ -241,6 +241,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
_Padding = profile.Padding();
|
||||
|
||||
_Commandline = profile.Commandline();
|
||||
_VtPassthrough = profile.VtPassthrough();
|
||||
|
||||
_StartingDirectory = profile.EvaluatedStartingDirectory();
|
||||
|
||||
|
||||
@ -91,6 +91,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, FocusFollowMouse, false);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, TrimBlockSelection, true);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, DetectURLs, true);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, VtPassthrough, false);
|
||||
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, Windows::Foundation::IReference<Microsoft::Terminal::Core::Color>, TabColor, nullptr);
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ namespace TerminalCoreUnitTests
|
||||
TEST_METHOD(AltShiftKey);
|
||||
TEST_METHOD(InvalidKeyEvent);
|
||||
|
||||
void _VerifyExpectedInput(std::wstring& actualInput)
|
||||
void _VerifyExpectedInput(std::wstring_view actualInput)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(expectedinput.size(), actualInput.size());
|
||||
VERIFY_ARE_EQUAL(expectedinput, actualInput);
|
||||
|
||||
@ -45,7 +45,8 @@
|
||||
X(bool, SuppressApplicationTitle) \
|
||||
X(bool, ForceVTInput, false) \
|
||||
X(winrt::hstring, StartingTitle) \
|
||||
X(bool, DetectURLs, true)
|
||||
X(bool, DetectURLs, true) \
|
||||
X(bool, VtPassthrough, false)
|
||||
|
||||
// --------------------------- Control Settings ---------------------------
|
||||
// All of these settings are defined in IControlSettings.
|
||||
|
||||
@ -84,4 +84,15 @@
|
||||
<brandingToken>Dev</brandingToken>
|
||||
</alwaysEnabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
<feature>
|
||||
<name>Feature_VtPassthroughMode</name>
|
||||
<description>Enables passthrough option per profile in Terminal and ConPTY ability to use passthrough API dispatch engine</description>
|
||||
<stage>AlwaysDisabled</stage>
|
||||
<!-- Did it this way instead of "release tokens" to ensure it won't go into Windows Inbox either... -->
|
||||
<alwaysEnabledBrandingTokens>
|
||||
<brandingToken>Dev</brandingToken>
|
||||
<brandingToken>Preview</brandingToken>
|
||||
</alwaysEnabledBrandingTokens>
|
||||
</feature>
|
||||
</featureStaging>
|
||||
|
||||
@ -342,7 +342,7 @@ void CommandListPopup::_drawList()
|
||||
WriteCoord.Y += 1i16;
|
||||
}
|
||||
|
||||
auto& api = Microsoft::Console::Interactivity::ServiceLocator::LocateGlobals().api;
|
||||
auto api = Microsoft::Console::Interactivity::ServiceLocator::LocateGlobals().api;
|
||||
|
||||
WriteCoord.Y = _region.Top + 1i16;
|
||||
SHORT i = std::max(gsl::narrow<SHORT>(_bottomIndex - Height() + 1), 0i16);
|
||||
@ -379,10 +379,10 @@ void CommandListPopup::_drawList()
|
||||
|
||||
WriteCoord.X = _region.Left + 1i16;
|
||||
|
||||
LOG_IF_FAILED(api.WriteConsoleOutputCharacterAImpl(_screenInfo,
|
||||
{ CommandNumberPtr, CommandNumberLength },
|
||||
WriteCoord,
|
||||
CommandNumberLength));
|
||||
LOG_IF_FAILED(api->WriteConsoleOutputCharacterAImpl(_screenInfo,
|
||||
{ CommandNumberPtr, CommandNumberLength },
|
||||
WriteCoord,
|
||||
CommandNumberLength));
|
||||
|
||||
// write command to screen
|
||||
auto command = _history.GetNth(i);
|
||||
@ -417,10 +417,10 @@ void CommandListPopup::_drawList()
|
||||
|
||||
WriteCoord.X = gsl::narrow<SHORT>(WriteCoord.X + CommandNumberLength);
|
||||
size_t used;
|
||||
LOG_IF_FAILED(api.WriteConsoleOutputCharacterWImpl(_screenInfo,
|
||||
{ command.data(), lStringLength },
|
||||
WriteCoord,
|
||||
used));
|
||||
LOG_IF_FAILED(api->WriteConsoleOutputCharacterWImpl(_screenInfo,
|
||||
{ command.data(), lStringLength },
|
||||
WriteCoord,
|
||||
used));
|
||||
|
||||
// write attributes to screen
|
||||
if (i == _currentCommand)
|
||||
|
||||
@ -24,6 +24,7 @@ const std::wstring_view ConsoleArguments::WIN32_INPUT_MODE = L"--win32input";
|
||||
const std::wstring_view ConsoleArguments::FEATURE_ARG = L"--feature";
|
||||
const std::wstring_view ConsoleArguments::FEATURE_PTY_ARG = L"pty";
|
||||
const std::wstring_view ConsoleArguments::COM_SERVER_ARG = L"-Embedding";
|
||||
const std::wstring_view ConsoleArguments::PASSTHROUGH_ARG = L"--passthrough";
|
||||
|
||||
std::wstring EscapeArgument(std::wstring_view ac)
|
||||
{
|
||||
@ -461,6 +462,12 @@ void ConsoleArguments::s_ConsumeArg(_Inout_ std::vector<std::wstring>& args, _In
|
||||
s_ConsumeArg(args, i);
|
||||
hr = S_OK;
|
||||
}
|
||||
else if (arg == PASSTHROUGH_ARG)
|
||||
{
|
||||
_passthroughMode = true;
|
||||
s_ConsumeArg(args, i);
|
||||
hr = S_OK;
|
||||
}
|
||||
else if (arg.substr(0, FILEPATH_LEADER_PREFIX.length()) == FILEPATH_LEADER_PREFIX)
|
||||
{
|
||||
// beginning of command line -- includes file path
|
||||
@ -596,6 +603,11 @@ bool ConsoleArguments::ShouldRunAsComServer() const
|
||||
return _runAsComServer;
|
||||
}
|
||||
|
||||
bool ConsoleArguments::IsPassthroughMode() const noexcept
|
||||
{
|
||||
return _passthroughMode;
|
||||
}
|
||||
|
||||
HANDLE ConsoleArguments::GetServerHandle() const
|
||||
{
|
||||
return ULongToHandle(_serverHandle);
|
||||
|
||||
@ -36,6 +36,7 @@ public:
|
||||
bool IsHeadless() const;
|
||||
bool ShouldCreateServerHandle() const;
|
||||
bool ShouldRunAsComServer() const;
|
||||
bool IsPassthroughMode() const noexcept;
|
||||
|
||||
HANDLE GetServerHandle() const;
|
||||
HANDLE GetVtInHandle() const;
|
||||
@ -77,6 +78,7 @@ public:
|
||||
static const std::wstring_view FEATURE_ARG;
|
||||
static const std::wstring_view FEATURE_PTY_ARG;
|
||||
static const std::wstring_view COM_SERVER_ARG;
|
||||
static const std::wstring_view PASSTHROUGH_ARG;
|
||||
|
||||
private:
|
||||
#ifdef UNIT_TESTING
|
||||
@ -95,7 +97,8 @@ private:
|
||||
const DWORD serverHandle,
|
||||
const DWORD signalHandle,
|
||||
const bool inheritCursor,
|
||||
const bool runAsComServer) :
|
||||
const bool runAsComServer,
|
||||
const bool passthroughMode) :
|
||||
_commandline(commandline),
|
||||
_clientCommandline(clientCommandline),
|
||||
_vtInHandle(vtInHandle),
|
||||
@ -111,7 +114,8 @@ private:
|
||||
_signalHandle(signalHandle),
|
||||
_inheritCursor(inheritCursor),
|
||||
_resizeQuirk(false),
|
||||
_runAsComServer{ runAsComServer }
|
||||
_runAsComServer{ runAsComServer },
|
||||
_passthroughMode{ passthroughMode }
|
||||
{
|
||||
}
|
||||
#endif
|
||||
@ -133,6 +137,7 @@ private:
|
||||
short _width;
|
||||
short _height;
|
||||
|
||||
bool _passthroughMode{ false };
|
||||
bool _runAsComServer;
|
||||
bool _createServerHandle;
|
||||
DWORD _serverHandle;
|
||||
@ -189,6 +194,7 @@ namespace WEX
|
||||
L"Signal Handle: '0x%x'\r\n",
|
||||
L"Inherit Cursor: '%ws'\r\n",
|
||||
L"Run As Com Server: '%ws'\r\n",
|
||||
L"Passthrough Mode: '%ws'\r\n",
|
||||
ci.GetClientCommandline().c_str(),
|
||||
s_ToBoolString(ci.HasVtHandles()),
|
||||
ci.GetVtInHandle(),
|
||||
@ -203,7 +209,8 @@ namespace WEX
|
||||
s_ToBoolString(ci.HasSignalHandle()),
|
||||
ci.GetSignalHandle(),
|
||||
s_ToBoolString(ci.GetInheritCursor()),
|
||||
s_ToBoolString(ci.ShouldRunAsComServer()));
|
||||
s_ToBoolString(ci.ShouldRunAsComServer()),
|
||||
s_ToBoolString(ci.IsPassthroughMode()));
|
||||
}
|
||||
|
||||
private:
|
||||
@ -232,7 +239,9 @@ namespace WEX
|
||||
expected.GetServerHandle() == actual.GetServerHandle() &&
|
||||
expected.HasSignalHandle() == actual.HasSignalHandle() &&
|
||||
expected.GetSignalHandle() == actual.GetSignalHandle() &&
|
||||
expected.GetInheritCursor() == actual.GetInheritCursor();
|
||||
expected.GetInheritCursor() == actual.GetInheritCursor() &&
|
||||
expected.ShouldRunAsComServer() == actual.ShouldRunAsComServer() &&
|
||||
expected.IsPassthroughMode() == actual.IsPassthroughMode();
|
||||
}
|
||||
|
||||
static bool AreSame(const ConsoleArguments& expected, const ConsoleArguments& actual)
|
||||
@ -257,7 +266,9 @@ namespace WEX
|
||||
!object.ShouldCreateServerHandle() &&
|
||||
object.GetServerHandle() == 0 &&
|
||||
(object.GetSignalHandle() == 0 || object.GetSignalHandle() == INVALID_HANDLE_VALUE) &&
|
||||
!object.GetInheritCursor();
|
||||
!object.GetInheritCursor() &&
|
||||
!object.ShouldRunAsComServer() &&
|
||||
!object.IsPassthroughMode();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
863
src/host/VtApiRoutines.cpp
Normal file
863
src/host/VtApiRoutines.cpp
Normal file
@ -0,0 +1,863 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "VtApiRoutines.h"
|
||||
#include "../interactivity/inc/ServiceLocator.hpp"
|
||||
#include "../types/inc/convert.hpp"
|
||||
|
||||
using namespace Microsoft::Console::Interactivity;
|
||||
|
||||
// When someone attempts to use the console APIs to do a "read back"
|
||||
// of the console buffer, we have to give them **something**.
|
||||
// These two structures are just some gaudy-colored replacement character
|
||||
// text to give them data but represent they've done something that cannot
|
||||
// be supported under VT passthrough mode.
|
||||
// ----
|
||||
// They can't be supported because in passthrough we maintain no internal
|
||||
// buffer to answer these questions, and there is no VT sequence that lets
|
||||
// us query the final terminal's buffer state. Even if a VT sequence did exist
|
||||
// (and we personally believe it shouldn't), there's a possibility that it would
|
||||
// read a massive amount of data and cause severe perf issues as applications coded
|
||||
// to this old API are likely leaning on it heavily and asking for this data in a
|
||||
// loop via VT would be a nightmare of parsing and formatting and over-the-wire transmission.
|
||||
|
||||
static constexpr CHAR_INFO s_readBackUnicode{
|
||||
{ UNICODE_REPLACEMENT },
|
||||
FOREGROUND_INTENSITY | FOREGROUND_RED | BACKGROUND_GREEN
|
||||
};
|
||||
|
||||
static constexpr CHAR_INFO s_readBackAscii{
|
||||
{ L'?' },
|
||||
FOREGROUND_INTENSITY | FOREGROUND_RED | BACKGROUND_GREEN
|
||||
};
|
||||
|
||||
VtApiRoutines::VtApiRoutines() :
|
||||
m_inputCodepage(ServiceLocator::LocateGlobals().getConsoleInformation().CP),
|
||||
m_outputCodepage(ServiceLocator::LocateGlobals().getConsoleInformation().OutputCP),
|
||||
m_inputMode(),
|
||||
m_outputMode(),
|
||||
m_pUsualRoutines(),
|
||||
m_pVtEngine(),
|
||||
m_listeningForDSR(false)
|
||||
{
|
||||
}
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4100) // unreferenced param
|
||||
|
||||
void VtApiRoutines::GetConsoleInputCodePageImpl(ULONG& codepage) noexcept
|
||||
{
|
||||
codepage = m_inputCodepage;
|
||||
return;
|
||||
}
|
||||
|
||||
void VtApiRoutines::GetConsoleOutputCodePageImpl(ULONG& codepage) noexcept
|
||||
{
|
||||
codepage = m_outputCodepage;
|
||||
return;
|
||||
}
|
||||
|
||||
void VtApiRoutines::GetConsoleInputModeImpl(InputBuffer& context,
|
||||
ULONG& mode) noexcept
|
||||
{
|
||||
mode = m_inputMode;
|
||||
return;
|
||||
}
|
||||
|
||||
void VtApiRoutines::GetConsoleOutputModeImpl(SCREEN_INFORMATION& context,
|
||||
ULONG& mode) noexcept
|
||||
{
|
||||
mode = m_outputMode;
|
||||
return;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::SetConsoleInputModeImpl(InputBuffer& context,
|
||||
const ULONG mode) noexcept
|
||||
{
|
||||
m_inputMode = mode;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::SetConsoleOutputModeImpl(SCREEN_INFORMATION& context,
|
||||
const ULONG Mode) noexcept
|
||||
{
|
||||
m_outputMode = Mode;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetNumberOfConsoleInputEventsImpl(const InputBuffer& context,
|
||||
ULONG& events) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->GetNumberOfConsoleInputEventsImpl(context, events);
|
||||
}
|
||||
|
||||
void VtApiRoutines::_SynchronizeCursor(std::unique_ptr<IWaitRoutine>& waiter) noexcept
|
||||
{
|
||||
// If we're about to tell the caller to wait, let's synchronize the cursor we have with what
|
||||
// the terminal is presenting in case there's a cooked read going on.
|
||||
// TODO GH#10001: we only need to do this in cooked read mode.
|
||||
if (waiter)
|
||||
{
|
||||
m_listeningForDSR = true;
|
||||
(void)m_pVtEngine->_ListenForDSR();
|
||||
(void)m_pVtEngine->RequestCursor();
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::PeekConsoleInputAImpl(IConsoleInputObject& context,
|
||||
std::deque<std::unique_ptr<IInputEvent>>& outEvents,
|
||||
const size_t eventsToRead,
|
||||
INPUT_READ_HANDLE_DATA& readHandleState,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept
|
||||
{
|
||||
const auto hr = m_pUsualRoutines->PeekConsoleInputAImpl(context, outEvents, eventsToRead, readHandleState, waiter);
|
||||
_SynchronizeCursor(waiter);
|
||||
return hr;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::PeekConsoleInputWImpl(IConsoleInputObject& context,
|
||||
std::deque<std::unique_ptr<IInputEvent>>& outEvents,
|
||||
const size_t eventsToRead,
|
||||
INPUT_READ_HANDLE_DATA& readHandleState,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept
|
||||
{
|
||||
const auto hr = m_pUsualRoutines->PeekConsoleInputWImpl(context, outEvents, eventsToRead, readHandleState, waiter);
|
||||
_SynchronizeCursor(waiter);
|
||||
return hr;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::ReadConsoleInputAImpl(IConsoleInputObject& context,
|
||||
std::deque<std::unique_ptr<IInputEvent>>& outEvents,
|
||||
const size_t eventsToRead,
|
||||
INPUT_READ_HANDLE_DATA& readHandleState,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept
|
||||
{
|
||||
const auto hr = m_pUsualRoutines->ReadConsoleInputAImpl(context, outEvents, eventsToRead, readHandleState, waiter);
|
||||
_SynchronizeCursor(waiter);
|
||||
return hr;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::ReadConsoleInputWImpl(IConsoleInputObject& context,
|
||||
std::deque<std::unique_ptr<IInputEvent>>& outEvents,
|
||||
const size_t eventsToRead,
|
||||
INPUT_READ_HANDLE_DATA& readHandleState,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept
|
||||
{
|
||||
const auto hr = m_pUsualRoutines->ReadConsoleInputWImpl(context, outEvents, eventsToRead, readHandleState, waiter);
|
||||
_SynchronizeCursor(waiter);
|
||||
return hr;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::ReadConsoleAImpl(IConsoleInputObject& context,
|
||||
gsl::span<char> buffer,
|
||||
size_t& written,
|
||||
std::unique_ptr<IWaitRoutine>& waiter,
|
||||
const std::string_view initialData,
|
||||
const std::wstring_view exeName,
|
||||
INPUT_READ_HANDLE_DATA& readHandleState,
|
||||
const HANDLE clientHandle,
|
||||
const DWORD controlWakeupMask,
|
||||
DWORD& controlKeyState) noexcept
|
||||
{
|
||||
const auto hr = m_pUsualRoutines->ReadConsoleAImpl(context, buffer, written, waiter, initialData, exeName, readHandleState, clientHandle, controlWakeupMask, controlKeyState);
|
||||
// If we're about to tell the caller to wait, let's synchronize the cursor we have with what
|
||||
// the terminal is presenting in case there's a cooked read going on.
|
||||
// TODO GH10001: we only need to do this in cooked read mode.
|
||||
if (clientHandle)
|
||||
{
|
||||
m_listeningForDSR = true;
|
||||
(void)m_pVtEngine->_ListenForDSR();
|
||||
(void)m_pVtEngine->RequestCursor();
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::ReadConsoleWImpl(IConsoleInputObject& context,
|
||||
gsl::span<char> buffer,
|
||||
size_t& written,
|
||||
std::unique_ptr<IWaitRoutine>& waiter,
|
||||
const std::string_view initialData,
|
||||
const std::wstring_view exeName,
|
||||
INPUT_READ_HANDLE_DATA& readHandleState,
|
||||
const HANDLE clientHandle,
|
||||
const DWORD controlWakeupMask,
|
||||
DWORD& controlKeyState) noexcept
|
||||
{
|
||||
const auto hr = m_pUsualRoutines->ReadConsoleWImpl(context, buffer, written, waiter, initialData, exeName, readHandleState, clientHandle, controlWakeupMask, controlKeyState);
|
||||
// If we're about to tell the caller to wait, let's synchronize the cursor we have with what
|
||||
// the terminal is presenting in case there's a cooked read going on.
|
||||
// TODO GH10001: we only need to do this in cooked read mode.
|
||||
if (clientHandle)
|
||||
{
|
||||
m_listeningForDSR = true;
|
||||
(void)m_pVtEngine->_ListenForDSR();
|
||||
(void)m_pVtEngine->RequestCursor();
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::WriteConsoleAImpl(IConsoleOutputObject& context,
|
||||
const std::string_view buffer,
|
||||
size_t& read,
|
||||
bool requiresVtQuirk,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept
|
||||
{
|
||||
if (CP_UTF8 == m_outputCodepage)
|
||||
{
|
||||
(void)m_pVtEngine->WriteTerminalUtf8(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)m_pVtEngine->WriteTerminalW(ConvertToW(m_outputCodepage, buffer));
|
||||
}
|
||||
|
||||
(void)m_pVtEngine->_Flush();
|
||||
read = buffer.size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::WriteConsoleWImpl(IConsoleOutputObject& context,
|
||||
const std::wstring_view buffer,
|
||||
size_t& read,
|
||||
bool requiresVtQuirk,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept
|
||||
{
|
||||
(void)m_pVtEngine->WriteTerminalW(buffer);
|
||||
(void)m_pVtEngine->_Flush();
|
||||
read = buffer.size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleLangIdImpl(LANGID& langId) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->GetConsoleLangIdImpl(langId);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::FillConsoleOutputAttributeImpl(IConsoleOutputObject& OutContext,
|
||||
const WORD attribute,
|
||||
const size_t lengthToWrite,
|
||||
const COORD startingCoordinate,
|
||||
size_t& cellsModified) noexcept
|
||||
{
|
||||
(void)m_pVtEngine->_CursorPosition(startingCoordinate);
|
||||
(void)m_pVtEngine->_SetGraphicsRendition16Color(static_cast<BYTE>(attribute), true);
|
||||
(void)m_pVtEngine->_SetGraphicsRendition16Color(static_cast<BYTE>(attribute >> 4), false);
|
||||
(void)m_pVtEngine->_WriteFill(lengthToWrite, s_readBackAscii.Char.AsciiChar);
|
||||
(void)m_pVtEngine->_Flush();
|
||||
cellsModified = lengthToWrite;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::FillConsoleOutputCharacterAImpl(IConsoleOutputObject& OutContext,
|
||||
const char character,
|
||||
const size_t lengthToWrite,
|
||||
const COORD startingCoordinate,
|
||||
size_t& cellsModified) noexcept
|
||||
{
|
||||
// I mean... if you get your jollies by using UTF8 for single byte codepoints...
|
||||
// we may as well skip a lot of conversion work and just write it out.
|
||||
if (m_outputCodepage == CP_UTF8 && character <= 0x7F)
|
||||
{
|
||||
(void)m_pVtEngine->_CursorPosition(startingCoordinate);
|
||||
(void)m_pVtEngine->_WriteFill(lengthToWrite, character);
|
||||
(void)m_pVtEngine->_Flush();
|
||||
cellsModified = lengthToWrite;
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto wstr = ConvertToW(m_outputCodepage, std::string_view{ &character, 1 });
|
||||
return FillConsoleOutputCharacterWImpl(OutContext, wstr.front(), lengthToWrite, startingCoordinate, cellsModified);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::FillConsoleOutputCharacterWImpl(IConsoleOutputObject& OutContext,
|
||||
const wchar_t character,
|
||||
const size_t lengthToWrite,
|
||||
const COORD startingCoordinate,
|
||||
size_t& cellsModified,
|
||||
const bool enablePowershellShim) noexcept
|
||||
{
|
||||
(void)m_pVtEngine->_CursorPosition(startingCoordinate);
|
||||
const std::wstring_view sv{ &character, 1 };
|
||||
|
||||
// TODO GH10001: horrible. it'll WC2MB over and over...we should do that once then emit... and then rep...
|
||||
// TODO GH10001: there's probably an optimization for if ((character & 0x7F) == character) --> call the UTF8 one.
|
||||
for (size_t i = 0; i < lengthToWrite; ++i)
|
||||
{
|
||||
(void)m_pVtEngine->WriteTerminalW(sv);
|
||||
}
|
||||
|
||||
(void)m_pVtEngine->_Flush();
|
||||
cellsModified = lengthToWrite;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//// Process based. Restrict in protocol side?
|
||||
//HRESULT GenerateConsoleCtrlEventImpl(const ULONG ProcessGroupFilter,
|
||||
// const ULONG ControlEvent);
|
||||
|
||||
void VtApiRoutines::SetConsoleActiveScreenBufferImpl(SCREEN_INFORMATION& newContext) noexcept
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void VtApiRoutines::FlushConsoleInputBuffer(InputBuffer& context) noexcept
|
||||
{
|
||||
m_pUsualRoutines->FlushConsoleInputBuffer(context);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::SetConsoleInputCodePageImpl(const ULONG codepage) noexcept
|
||||
{
|
||||
m_inputCodepage = codepage;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::SetConsoleOutputCodePageImpl(const ULONG codepage) noexcept
|
||||
{
|
||||
m_outputCodepage = codepage;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void VtApiRoutines::GetConsoleCursorInfoImpl(const SCREEN_INFORMATION& context,
|
||||
ULONG& size,
|
||||
bool& isVisible) noexcept
|
||||
{
|
||||
// TODO GH10001: good luck capturing this out of the input buffer when it comes back in.
|
||||
//m_pVtEngine->RequestCursor();
|
||||
return;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::SetConsoleCursorInfoImpl(SCREEN_INFORMATION& context,
|
||||
const ULONG size,
|
||||
const bool isVisible) noexcept
|
||||
{
|
||||
isVisible ? (void)m_pVtEngine->_ShowCursor() : (void)m_pVtEngine->_HideCursor();
|
||||
(void)m_pVtEngine->_Flush();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//// driver will pare down for non-Ex method
|
||||
void VtApiRoutines::GetConsoleScreenBufferInfoExImpl(const SCREEN_INFORMATION& context,
|
||||
CONSOLE_SCREEN_BUFFER_INFOEX& data) noexcept
|
||||
{
|
||||
// TODO GH10001: this is technically full of potentially incorrect data. do we care? should we store it in here with set?
|
||||
return m_pUsualRoutines->GetConsoleScreenBufferInfoExImpl(context, data);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::SetConsoleScreenBufferInfoExImpl(SCREEN_INFORMATION& context,
|
||||
const CONSOLE_SCREEN_BUFFER_INFOEX& data) noexcept
|
||||
{
|
||||
(void)m_pVtEngine->_ResizeWindow(data.srWindow.Right - data.srWindow.Left, data.srWindow.Bottom - data.srWindow.Top);
|
||||
(void)m_pVtEngine->_CursorPosition(data.dwCursorPosition);
|
||||
(void)m_pVtEngine->_SetGraphicsRendition16Color(static_cast<BYTE>(data.wAttributes), true);
|
||||
(void)m_pVtEngine->_SetGraphicsRendition16Color(static_cast<BYTE>(data.wAttributes >> 4), false);
|
||||
//color table?
|
||||
// popup attributes... hold internally?
|
||||
// TODO GH10001: popups are gonna erase the stuff behind them... deal with that somehow.
|
||||
(void)m_pVtEngine->_Flush();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::SetConsoleScreenBufferSizeImpl(SCREEN_INFORMATION& context,
|
||||
const COORD size) noexcept
|
||||
{
|
||||
// Don't transmit. The terminal figures out its own buffer size.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::SetConsoleCursorPositionImpl(SCREEN_INFORMATION& context,
|
||||
const COORD position) noexcept
|
||||
{
|
||||
if (m_listeningForDSR)
|
||||
{
|
||||
context.GetActiveBuffer().GetTextBuffer().GetCursor().SetPosition(position);
|
||||
m_pVtEngine->SetTerminalCursorTextPosition(position);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)m_pVtEngine->_CursorPosition(position);
|
||||
(void)m_pVtEngine->_Flush();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void VtApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& context,
|
||||
COORD& size) noexcept
|
||||
{
|
||||
m_pUsualRoutines->GetLargestConsoleWindowSizeImpl(context, size); // This is likely super weird but not weirder than existing ConPTY answers.
|
||||
return;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::ScrollConsoleScreenBufferAImpl(SCREEN_INFORMATION& context,
|
||||
const SMALL_RECT& source,
|
||||
const COORD target,
|
||||
std::optional<SMALL_RECT> clip,
|
||||
const char fillCharacter,
|
||||
const WORD fillAttribute) noexcept
|
||||
{
|
||||
// TODO GH10001: Use DECCRA
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::ScrollConsoleScreenBufferWImpl(SCREEN_INFORMATION& context,
|
||||
const SMALL_RECT& source,
|
||||
const COORD target,
|
||||
std::optional<SMALL_RECT> clip,
|
||||
const wchar_t fillCharacter,
|
||||
const WORD fillAttribute,
|
||||
const bool enableCmdShim) noexcept
|
||||
{
|
||||
// TODO GH10001: Use DECCRA
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::SetConsoleTextAttributeImpl(SCREEN_INFORMATION& context,
|
||||
const WORD attribute) noexcept
|
||||
{
|
||||
(void)m_pVtEngine->_SetGraphicsRendition16Color(static_cast<BYTE>(attribute), true);
|
||||
(void)m_pVtEngine->_SetGraphicsRendition16Color(static_cast<BYTE>(attribute >> 4), false);
|
||||
(void)m_pVtEngine->_Flush();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::SetConsoleWindowInfoImpl(SCREEN_INFORMATION& context,
|
||||
const bool isAbsolute,
|
||||
const SMALL_RECT& windowRect) noexcept
|
||||
{
|
||||
(void)m_pVtEngine->_ResizeWindow(windowRect.Right - windowRect.Left, windowRect.Bottom - windowRect.Top);
|
||||
(void)m_pVtEngine->_Flush();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::ReadConsoleOutputAttributeImpl(const SCREEN_INFORMATION& context,
|
||||
const COORD origin,
|
||||
gsl::span<WORD> buffer,
|
||||
size_t& written) noexcept
|
||||
{
|
||||
std::fill_n(buffer.data(), buffer.size(), s_readBackUnicode.Attributes); // should be same as the ascii one.
|
||||
written = buffer.size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::ReadConsoleOutputCharacterAImpl(const SCREEN_INFORMATION& context,
|
||||
const COORD origin,
|
||||
gsl::span<char> buffer,
|
||||
size_t& written) noexcept
|
||||
{
|
||||
std::fill_n(buffer.data(), buffer.size(), s_readBackAscii.Char.AsciiChar);
|
||||
written = buffer.size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::ReadConsoleOutputCharacterWImpl(const SCREEN_INFORMATION& context,
|
||||
const COORD origin,
|
||||
gsl::span<wchar_t> buffer,
|
||||
size_t& written) noexcept
|
||||
{
|
||||
std::fill_n(buffer.data(), buffer.size(), s_readBackUnicode.Char.UnicodeChar);
|
||||
written = buffer.size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::WriteConsoleInputAImpl(InputBuffer& context,
|
||||
const gsl::span<const INPUT_RECORD> buffer,
|
||||
size_t& written,
|
||||
const bool append) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->WriteConsoleInputAImpl(context, buffer, written, append);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::WriteConsoleInputWImpl(InputBuffer& context,
|
||||
const gsl::span<const INPUT_RECORD> buffer,
|
||||
size_t& written,
|
||||
const bool append) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->WriteConsoleInputWImpl(context, buffer, written, append);
|
||||
}
|
||||
|
||||
extern HRESULT _ConvertCellsToWInplace(const UINT codepage,
|
||||
gsl::span<CHAR_INFO> buffer,
|
||||
const Viewport& rectangle) noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::WriteConsoleOutputAImpl(SCREEN_INFORMATION& context,
|
||||
gsl::span<CHAR_INFO> buffer,
|
||||
const Microsoft::Console::Types::Viewport& requestRectangle,
|
||||
Microsoft::Console::Types::Viewport& writtenRectangle) noexcept
|
||||
{
|
||||
// No UTF8 optimization because the entire `CHAR_INFO` grid system doesn't make sense for UTF-8
|
||||
// with up to 4 bytes per cell...or more!
|
||||
|
||||
RETURN_IF_FAILED(_ConvertCellsToWInplace(m_outputCodepage, buffer, requestRectangle));
|
||||
return WriteConsoleOutputWImpl(context, buffer, requestRectangle, writtenRectangle);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::WriteConsoleOutputWImpl(SCREEN_INFORMATION& context,
|
||||
gsl::span<CHAR_INFO> buffer,
|
||||
const Microsoft::Console::Types::Viewport& requestRectangle,
|
||||
Microsoft::Console::Types::Viewport& writtenRectangle) noexcept
|
||||
{
|
||||
COORD cursor{ requestRectangle.Left(), requestRectangle.Top() };
|
||||
|
||||
const size_t width = requestRectangle.Width();
|
||||
size_t pos = 0;
|
||||
|
||||
while (pos < buffer.size())
|
||||
{
|
||||
(void)m_pVtEngine->_CursorPosition(cursor);
|
||||
|
||||
const auto subspan = buffer.subspan(pos, width);
|
||||
|
||||
for (const auto& ci : subspan)
|
||||
{
|
||||
(void)m_pVtEngine->_SetGraphicsRendition16Color(static_cast<BYTE>(ci.Attributes), true);
|
||||
(void)m_pVtEngine->_SetGraphicsRendition16Color(static_cast<BYTE>(ci.Attributes >> 4), false);
|
||||
(void)m_pVtEngine->WriteTerminalW(std::wstring_view{ &ci.Char.UnicodeChar, 1 });
|
||||
}
|
||||
|
||||
++cursor.Y;
|
||||
pos += width;
|
||||
}
|
||||
|
||||
(void)m_pVtEngine->_Flush();
|
||||
|
||||
//TODO GH10001: trim to buffer size?
|
||||
writtenRectangle = requestRectangle;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::WriteConsoleOutputAttributeImpl(IConsoleOutputObject& OutContext,
|
||||
const gsl::span<const WORD> attrs,
|
||||
const COORD target,
|
||||
size_t& used) noexcept
|
||||
{
|
||||
(void)m_pVtEngine->_CursorPosition(target);
|
||||
|
||||
for (const auto& attr : attrs)
|
||||
{
|
||||
(void)m_pVtEngine->_SetGraphicsRendition16Color(static_cast<BYTE>(attr), true);
|
||||
(void)m_pVtEngine->_SetGraphicsRendition16Color(static_cast<BYTE>(attr >> 4), false);
|
||||
(void)m_pVtEngine->WriteTerminalUtf8(std::string_view{ &s_readBackAscii.Char.AsciiChar, 1 });
|
||||
}
|
||||
|
||||
(void)m_pVtEngine->_Flush();
|
||||
|
||||
used = attrs.size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::WriteConsoleOutputCharacterAImpl(IConsoleOutputObject& OutContext,
|
||||
const std::string_view text,
|
||||
const COORD target,
|
||||
size_t& used) noexcept
|
||||
{
|
||||
if (m_outputCodepage == CP_UTF8)
|
||||
{
|
||||
(void)m_pVtEngine->_CursorPosition(target);
|
||||
(void)m_pVtEngine->WriteTerminalUtf8(text);
|
||||
(void)m_pVtEngine->_Flush();
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return WriteConsoleOutputCharacterWImpl(OutContext, ConvertToW(m_outputCodepage, text), target, used);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::WriteConsoleOutputCharacterWImpl(IConsoleOutputObject& OutContext,
|
||||
const std::wstring_view text,
|
||||
const COORD target,
|
||||
size_t& used) noexcept
|
||||
{
|
||||
(void)m_pVtEngine->_CursorPosition(target);
|
||||
(void)m_pVtEngine->WriteTerminalW(text);
|
||||
(void)m_pVtEngine->_Flush();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::ReadConsoleOutputAImpl(const SCREEN_INFORMATION& context,
|
||||
gsl::span<CHAR_INFO> buffer,
|
||||
const Microsoft::Console::Types::Viewport& sourceRectangle,
|
||||
Microsoft::Console::Types::Viewport& readRectangle) noexcept
|
||||
{
|
||||
std::fill_n(buffer.data(), buffer.size(), s_readBackAscii);
|
||||
// TODO GH10001: do we need to constrict readRectangle to within the known buffer size... probably.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::ReadConsoleOutputWImpl(const SCREEN_INFORMATION& context,
|
||||
gsl::span<CHAR_INFO> buffer,
|
||||
const Microsoft::Console::Types::Viewport& sourceRectangle,
|
||||
Microsoft::Console::Types::Viewport& readRectangle) noexcept
|
||||
{
|
||||
std::fill_n(buffer.data(), buffer.size(), s_readBackUnicode);
|
||||
// TODO GH10001: do we need to constrict readRectangle to within the known buffer size... probably.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleTitleAImpl(gsl::span<char> title,
|
||||
size_t& written,
|
||||
size_t& needed) noexcept
|
||||
{
|
||||
written = 0;
|
||||
needed = 0;
|
||||
|
||||
if (!title.empty())
|
||||
{
|
||||
title.front() = ANSI_NULL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleTitleWImpl(gsl::span<wchar_t> title,
|
||||
size_t& written,
|
||||
size_t& needed) noexcept
|
||||
{
|
||||
written = 0;
|
||||
needed = 0;
|
||||
|
||||
if (!title.empty())
|
||||
{
|
||||
title.front() = UNICODE_NULL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleOriginalTitleAImpl(gsl::span<char> title,
|
||||
size_t& written,
|
||||
size_t& needed) noexcept
|
||||
{
|
||||
written = 0;
|
||||
needed = 0;
|
||||
|
||||
if (!title.empty())
|
||||
{
|
||||
title.front() = ANSI_NULL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleOriginalTitleWImpl(gsl::span<wchar_t> title,
|
||||
size_t& written,
|
||||
size_t& needed) noexcept
|
||||
{
|
||||
written = 0;
|
||||
needed = 0;
|
||||
|
||||
if (!title.empty())
|
||||
{
|
||||
title.front() = UNICODE_NULL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::SetConsoleTitleAImpl(const std::string_view title) noexcept
|
||||
{
|
||||
return SetConsoleTitleWImpl(ConvertToW(m_inputCodepage, title));
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::SetConsoleTitleWImpl(const std::wstring_view title) noexcept
|
||||
{
|
||||
(void)m_pVtEngine->UpdateTitle(title);
|
||||
(void)m_pVtEngine->_Flush();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void VtApiRoutines::GetNumberOfConsoleMouseButtonsImpl(ULONG& buttons) noexcept
|
||||
{
|
||||
buttons = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleFontSizeImpl(const SCREEN_INFORMATION& context,
|
||||
const DWORD index,
|
||||
COORD& size) noexcept
|
||||
{
|
||||
size.X = 8;
|
||||
size.Y = 12;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//// driver will pare down for non-Ex method
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetCurrentConsoleFontExImpl(const SCREEN_INFORMATION& context,
|
||||
const bool isForMaximumWindowSize,
|
||||
CONSOLE_FONT_INFOEX& consoleFontInfoEx) noexcept
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::SetConsoleDisplayModeImpl(SCREEN_INFORMATION& context,
|
||||
const ULONG flags,
|
||||
COORD& newSize) noexcept
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void VtApiRoutines::GetConsoleDisplayModeImpl(ULONG& flags) noexcept
|
||||
{
|
||||
flags = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::AddConsoleAliasAImpl(const std::string_view source,
|
||||
const std::string_view target,
|
||||
const std::string_view exeName) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->AddConsoleAliasAImpl(source, target, exeName);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::AddConsoleAliasWImpl(const std::wstring_view source,
|
||||
const std::wstring_view target,
|
||||
const std::wstring_view exeName) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->AddConsoleAliasWImpl(source, target, exeName);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleAliasAImpl(const std::string_view source,
|
||||
gsl::span<char> target,
|
||||
size_t& written,
|
||||
const std::string_view exeName) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->GetConsoleAliasAImpl(source, target, written, exeName);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleAliasWImpl(const std::wstring_view source,
|
||||
gsl::span<wchar_t> target,
|
||||
size_t& written,
|
||||
const std::wstring_view exeName) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->GetConsoleAliasWImpl(source, target, written, exeName);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleAliasesLengthAImpl(const std::string_view exeName,
|
||||
size_t& bufferRequired) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->GetConsoleAliasesLengthAImpl(exeName, bufferRequired);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleAliasesLengthWImpl(const std::wstring_view exeName,
|
||||
size_t& bufferRequired) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->GetConsoleAliasesLengthWImpl(exeName, bufferRequired);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleAliasExesLengthAImpl(size_t& bufferRequired) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->GetConsoleAliasExesLengthAImpl(bufferRequired);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleAliasExesLengthWImpl(size_t& bufferRequired) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->GetConsoleAliasExesLengthWImpl(bufferRequired);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleAliasesAImpl(const std::string_view exeName,
|
||||
gsl::span<char> alias,
|
||||
size_t& written) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->GetConsoleAliasesAImpl(exeName, alias, written);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleAliasesWImpl(const std::wstring_view exeName,
|
||||
gsl::span<wchar_t> alias,
|
||||
size_t& written) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->GetConsoleAliasesWImpl(exeName, alias, written);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleAliasExesAImpl(gsl::span<char> aliasExes,
|
||||
size_t& written) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->GetConsoleAliasExesAImpl(aliasExes, written);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleAliasExesWImpl(gsl::span<wchar_t> aliasExes,
|
||||
size_t& written) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->GetConsoleAliasExesWImpl(aliasExes, written);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::ExpungeConsoleCommandHistoryAImpl(const std::string_view exeName) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->ExpungeConsoleCommandHistoryAImpl(exeName);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::ExpungeConsoleCommandHistoryWImpl(const std::wstring_view exeName) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->ExpungeConsoleCommandHistoryWImpl(exeName);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::SetConsoleNumberOfCommandsAImpl(const std::string_view exeName,
|
||||
const size_t numberOfCommands) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->SetConsoleNumberOfCommandsAImpl(exeName, numberOfCommands);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::SetConsoleNumberOfCommandsWImpl(const std::wstring_view exeName,
|
||||
const size_t numberOfCommands) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->SetConsoleNumberOfCommandsWImpl(exeName, numberOfCommands);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleCommandHistoryLengthAImpl(const std::string_view exeName,
|
||||
size_t& length) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->GetConsoleCommandHistoryLengthAImpl(exeName, length);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleCommandHistoryLengthWImpl(const std::wstring_view exeName,
|
||||
size_t& length) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->GetConsoleCommandHistoryLengthWImpl(exeName, length);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleCommandHistoryAImpl(const std::string_view exeName,
|
||||
gsl::span<char> commandHistory,
|
||||
size_t& written) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->GetConsoleCommandHistoryAImpl(exeName, commandHistory, written);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::GetConsoleCommandHistoryWImpl(const std::wstring_view exeName,
|
||||
gsl::span<wchar_t> commandHistory,
|
||||
size_t& written) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->GetConsoleCommandHistoryWImpl(exeName, commandHistory, written);
|
||||
}
|
||||
|
||||
void VtApiRoutines::GetConsoleWindowImpl(HWND& hwnd) noexcept
|
||||
{
|
||||
hwnd = ServiceLocator::LocatePseudoWindow();
|
||||
return;
|
||||
}
|
||||
|
||||
void VtApiRoutines::GetConsoleSelectionInfoImpl(CONSOLE_SELECTION_INFO& consoleSelectionInfo) noexcept
|
||||
{
|
||||
consoleSelectionInfo = { 0 };
|
||||
return;
|
||||
}
|
||||
|
||||
void VtApiRoutines::GetConsoleHistoryInfoImpl(CONSOLE_HISTORY_INFO& consoleHistoryInfo) noexcept
|
||||
{
|
||||
m_pUsualRoutines->GetConsoleHistoryInfoImpl(consoleHistoryInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::SetConsoleHistoryInfoImpl(const CONSOLE_HISTORY_INFO& consoleHistoryInfo) noexcept
|
||||
{
|
||||
return m_pUsualRoutines->SetConsoleHistoryInfoImpl(consoleHistoryInfo);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT VtApiRoutines::SetCurrentConsoleFontExImpl(IConsoleOutputObject& context,
|
||||
const bool isForMaximumWindowSize,
|
||||
const CONSOLE_FONT_INFOEX& consoleFontInfoEx) noexcept
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#pragma warning(pop)
|
||||
392
src/host/VtApiRoutines.h
Normal file
392
src/host/VtApiRoutines.h
Normal file
@ -0,0 +1,392 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- VtApiRoutines.h
|
||||
|
||||
Abstract:
|
||||
- This file defines the interface to respond to all API calls by using VT on behalf of the client
|
||||
|
||||
Author:
|
||||
- Michael Niksa (miniksa) 26-Jul-2021
|
||||
|
||||
Revision History:
|
||||
- Adapted from original items in srvinit.cpp, getset.cpp, directio.cpp, stream.cpp
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../server/IApiRoutines.h"
|
||||
#include "../renderer/vt/Xterm256Engine.hpp"
|
||||
|
||||
class VtApiRoutines : public IApiRoutines
|
||||
{
|
||||
public:
|
||||
VtApiRoutines();
|
||||
|
||||
#pragma region ObjectManagement
|
||||
/*HRESULT CreateInitialObjects(_Out_ InputBuffer** const ppInputObject,
|
||||
_Out_ SCREEN_INFORMATION** const ppOutputObject);
|
||||
*/
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region L1
|
||||
void GetConsoleInputCodePageImpl(ULONG& codepage) noexcept override;
|
||||
|
||||
void GetConsoleOutputCodePageImpl(ULONG& codepage) noexcept override;
|
||||
|
||||
void GetConsoleInputModeImpl(InputBuffer& context,
|
||||
ULONG& mode) noexcept override;
|
||||
|
||||
void GetConsoleOutputModeImpl(SCREEN_INFORMATION& context,
|
||||
ULONG& mode) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT SetConsoleInputModeImpl(InputBuffer& context,
|
||||
const ULONG mode) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT SetConsoleOutputModeImpl(SCREEN_INFORMATION& context,
|
||||
const ULONG Mode) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetNumberOfConsoleInputEventsImpl(const InputBuffer& context,
|
||||
ULONG& events) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT PeekConsoleInputAImpl(IConsoleInputObject& context,
|
||||
std::deque<std::unique_ptr<IInputEvent>>& outEvents,
|
||||
const size_t eventsToRead,
|
||||
INPUT_READ_HANDLE_DATA& readHandleState,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT PeekConsoleInputWImpl(IConsoleInputObject& context,
|
||||
std::deque<std::unique_ptr<IInputEvent>>& outEvents,
|
||||
const size_t eventsToRead,
|
||||
INPUT_READ_HANDLE_DATA& readHandleState,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT ReadConsoleInputAImpl(IConsoleInputObject& context,
|
||||
std::deque<std::unique_ptr<IInputEvent>>& outEvents,
|
||||
const size_t eventsToRead,
|
||||
INPUT_READ_HANDLE_DATA& readHandleState,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT ReadConsoleInputWImpl(IConsoleInputObject& context,
|
||||
std::deque<std::unique_ptr<IInputEvent>>& outEvents,
|
||||
const size_t eventsToRead,
|
||||
INPUT_READ_HANDLE_DATA& readHandleState,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT ReadConsoleAImpl(IConsoleInputObject& context,
|
||||
gsl::span<char> buffer,
|
||||
size_t& written,
|
||||
std::unique_ptr<IWaitRoutine>& waiter,
|
||||
const std::string_view initialData,
|
||||
const std::wstring_view exeName,
|
||||
INPUT_READ_HANDLE_DATA& readHandleState,
|
||||
const HANDLE clientHandle,
|
||||
const DWORD controlWakeupMask,
|
||||
DWORD& controlKeyState) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT ReadConsoleWImpl(IConsoleInputObject& context,
|
||||
gsl::span<char> buffer,
|
||||
size_t& written,
|
||||
std::unique_ptr<IWaitRoutine>& waiter,
|
||||
const std::string_view initialData,
|
||||
const std::wstring_view exeName,
|
||||
INPUT_READ_HANDLE_DATA& readHandleState,
|
||||
const HANDLE clientHandle,
|
||||
const DWORD controlWakeupMask,
|
||||
DWORD& controlKeyState) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT WriteConsoleAImpl(IConsoleOutputObject& context,
|
||||
const std::string_view buffer,
|
||||
size_t& read,
|
||||
bool requiresVtQuirk,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT WriteConsoleWImpl(IConsoleOutputObject& context,
|
||||
const std::wstring_view buffer,
|
||||
size_t& read,
|
||||
bool requiresVtQuirk,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept override;
|
||||
|
||||
#pragma region ThreadCreationInfo
|
||||
[[nodiscard]] HRESULT GetConsoleLangIdImpl(LANGID& langId) noexcept override;
|
||||
#pragma endregion
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region L2
|
||||
|
||||
[[nodiscard]] HRESULT FillConsoleOutputAttributeImpl(IConsoleOutputObject& OutContext,
|
||||
const WORD attribute,
|
||||
const size_t lengthToWrite,
|
||||
const COORD startingCoordinate,
|
||||
size_t& cellsModified) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT FillConsoleOutputCharacterAImpl(IConsoleOutputObject& OutContext,
|
||||
const char character,
|
||||
const size_t lengthToWrite,
|
||||
const COORD startingCoordinate,
|
||||
size_t& cellsModified) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT FillConsoleOutputCharacterWImpl(IConsoleOutputObject& OutContext,
|
||||
const wchar_t character,
|
||||
const size_t lengthToWrite,
|
||||
const COORD startingCoordinate,
|
||||
size_t& cellsModified,
|
||||
const bool enablePowershellShim = false) noexcept override;
|
||||
|
||||
//// Process based. Restrict in protocol side?
|
||||
//HRESULT GenerateConsoleCtrlEventImpl(const ULONG ProcessGroupFilter,
|
||||
// const ULONG ControlEvent);
|
||||
|
||||
void SetConsoleActiveScreenBufferImpl(SCREEN_INFORMATION& newContext) noexcept override;
|
||||
|
||||
void FlushConsoleInputBuffer(InputBuffer& context) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT SetConsoleInputCodePageImpl(const ULONG codepage) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT SetConsoleOutputCodePageImpl(const ULONG codepage) noexcept override;
|
||||
|
||||
void GetConsoleCursorInfoImpl(const SCREEN_INFORMATION& context,
|
||||
ULONG& size,
|
||||
bool& isVisible) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT SetConsoleCursorInfoImpl(SCREEN_INFORMATION& context,
|
||||
const ULONG size,
|
||||
const bool isVisible) noexcept override;
|
||||
|
||||
//// driver will pare down for non-Ex method
|
||||
void GetConsoleScreenBufferInfoExImpl(const SCREEN_INFORMATION& context,
|
||||
CONSOLE_SCREEN_BUFFER_INFOEX& data) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT SetConsoleScreenBufferInfoExImpl(SCREEN_INFORMATION& context,
|
||||
const CONSOLE_SCREEN_BUFFER_INFOEX& data) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT SetConsoleScreenBufferSizeImpl(SCREEN_INFORMATION& context,
|
||||
const COORD size) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT SetConsoleCursorPositionImpl(SCREEN_INFORMATION& context,
|
||||
const COORD position) noexcept override;
|
||||
|
||||
void GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& context,
|
||||
COORD& size) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT ScrollConsoleScreenBufferAImpl(SCREEN_INFORMATION& context,
|
||||
const SMALL_RECT& source,
|
||||
const COORD target,
|
||||
std::optional<SMALL_RECT> clip,
|
||||
const char fillCharacter,
|
||||
const WORD fillAttribute) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT ScrollConsoleScreenBufferWImpl(SCREEN_INFORMATION& context,
|
||||
const SMALL_RECT& source,
|
||||
const COORD target,
|
||||
std::optional<SMALL_RECT> clip,
|
||||
const wchar_t fillCharacter,
|
||||
const WORD fillAttribute,
|
||||
const bool enableCmdShim = false) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT SetConsoleTextAttributeImpl(SCREEN_INFORMATION& context,
|
||||
const WORD attribute) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT SetConsoleWindowInfoImpl(SCREEN_INFORMATION& context,
|
||||
const bool isAbsolute,
|
||||
const SMALL_RECT& windowRect) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT ReadConsoleOutputAttributeImpl(const SCREEN_INFORMATION& context,
|
||||
const COORD origin,
|
||||
gsl::span<WORD> buffer,
|
||||
size_t& written) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT ReadConsoleOutputCharacterAImpl(const SCREEN_INFORMATION& context,
|
||||
const COORD origin,
|
||||
gsl::span<char> buffer,
|
||||
size_t& written) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT ReadConsoleOutputCharacterWImpl(const SCREEN_INFORMATION& context,
|
||||
const COORD origin,
|
||||
gsl::span<wchar_t> buffer,
|
||||
size_t& written) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT WriteConsoleInputAImpl(InputBuffer& context,
|
||||
const gsl::span<const INPUT_RECORD> buffer,
|
||||
size_t& written,
|
||||
const bool append) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT WriteConsoleInputWImpl(InputBuffer& context,
|
||||
const gsl::span<const INPUT_RECORD> buffer,
|
||||
size_t& written,
|
||||
const bool append) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT WriteConsoleOutputAImpl(SCREEN_INFORMATION& context,
|
||||
gsl::span<CHAR_INFO> buffer,
|
||||
const Microsoft::Console::Types::Viewport& requestRectangle,
|
||||
Microsoft::Console::Types::Viewport& writtenRectangle) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT WriteConsoleOutputWImpl(SCREEN_INFORMATION& context,
|
||||
gsl::span<CHAR_INFO> buffer,
|
||||
const Microsoft::Console::Types::Viewport& requestRectangle,
|
||||
Microsoft::Console::Types::Viewport& writtenRectangle) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT WriteConsoleOutputAttributeImpl(IConsoleOutputObject& OutContext,
|
||||
const gsl::span<const WORD> attrs,
|
||||
const COORD target,
|
||||
size_t& used) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT WriteConsoleOutputCharacterAImpl(IConsoleOutputObject& OutContext,
|
||||
const std::string_view text,
|
||||
const COORD target,
|
||||
size_t& used) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT WriteConsoleOutputCharacterWImpl(IConsoleOutputObject& OutContext,
|
||||
const std::wstring_view text,
|
||||
const COORD target,
|
||||
size_t& used) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT ReadConsoleOutputAImpl(const SCREEN_INFORMATION& context,
|
||||
gsl::span<CHAR_INFO> buffer,
|
||||
const Microsoft::Console::Types::Viewport& sourceRectangle,
|
||||
Microsoft::Console::Types::Viewport& readRectangle) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT ReadConsoleOutputWImpl(const SCREEN_INFORMATION& context,
|
||||
gsl::span<CHAR_INFO> buffer,
|
||||
const Microsoft::Console::Types::Viewport& sourceRectangle,
|
||||
Microsoft::Console::Types::Viewport& readRectangle) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleTitleAImpl(gsl::span<char> title,
|
||||
size_t& written,
|
||||
size_t& needed) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleTitleWImpl(gsl::span<wchar_t> title,
|
||||
size_t& written,
|
||||
size_t& needed) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleOriginalTitleAImpl(gsl::span<char> title,
|
||||
size_t& written,
|
||||
size_t& needed) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleOriginalTitleWImpl(gsl::span<wchar_t> title,
|
||||
size_t& written,
|
||||
size_t& needed) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT SetConsoleTitleAImpl(const std::string_view title) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT SetConsoleTitleWImpl(const std::wstring_view title) noexcept override;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region L3
|
||||
void GetNumberOfConsoleMouseButtonsImpl(ULONG& buttons) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleFontSizeImpl(const SCREEN_INFORMATION& context,
|
||||
const DWORD index,
|
||||
COORD& size) noexcept override;
|
||||
|
||||
//// driver will pare down for non-Ex method
|
||||
[[nodiscard]] HRESULT GetCurrentConsoleFontExImpl(const SCREEN_INFORMATION& context,
|
||||
const bool isForMaximumWindowSize,
|
||||
CONSOLE_FONT_INFOEX& consoleFontInfoEx) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT SetConsoleDisplayModeImpl(SCREEN_INFORMATION& context,
|
||||
const ULONG flags,
|
||||
COORD& newSize) noexcept override;
|
||||
|
||||
void GetConsoleDisplayModeImpl(ULONG& flags) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT AddConsoleAliasAImpl(const std::string_view source,
|
||||
const std::string_view target,
|
||||
const std::string_view exeName) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT AddConsoleAliasWImpl(const std::wstring_view source,
|
||||
const std::wstring_view target,
|
||||
const std::wstring_view exeName) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleAliasAImpl(const std::string_view source,
|
||||
gsl::span<char> target,
|
||||
size_t& written,
|
||||
const std::string_view exeName) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleAliasWImpl(const std::wstring_view source,
|
||||
gsl::span<wchar_t> target,
|
||||
size_t& written,
|
||||
const std::wstring_view exeName) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleAliasesLengthAImpl(const std::string_view exeName,
|
||||
size_t& bufferRequired) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleAliasesLengthWImpl(const std::wstring_view exeName,
|
||||
size_t& bufferRequired) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleAliasExesLengthAImpl(size_t& bufferRequired) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleAliasExesLengthWImpl(size_t& bufferRequired) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleAliasesAImpl(const std::string_view exeName,
|
||||
gsl::span<char> alias,
|
||||
size_t& written) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleAliasesWImpl(const std::wstring_view exeName,
|
||||
gsl::span<wchar_t> alias,
|
||||
size_t& written) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleAliasExesAImpl(gsl::span<char> aliasExes,
|
||||
size_t& written) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleAliasExesWImpl(gsl::span<wchar_t> aliasExes,
|
||||
size_t& written) noexcept override;
|
||||
|
||||
#pragma region CMDext Private API
|
||||
|
||||
[[nodiscard]] HRESULT ExpungeConsoleCommandHistoryAImpl(const std::string_view exeName) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT ExpungeConsoleCommandHistoryWImpl(const std::wstring_view exeName) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT SetConsoleNumberOfCommandsAImpl(const std::string_view exeName,
|
||||
const size_t numberOfCommands) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT SetConsoleNumberOfCommandsWImpl(const std::wstring_view exeName,
|
||||
const size_t numberOfCommands) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleCommandHistoryLengthAImpl(const std::string_view exeName,
|
||||
size_t& length) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleCommandHistoryLengthWImpl(const std::wstring_view exeName,
|
||||
size_t& length) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleCommandHistoryAImpl(const std::string_view exeName,
|
||||
gsl::span<char> commandHistory,
|
||||
size_t& written) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetConsoleCommandHistoryWImpl(const std::wstring_view exeName,
|
||||
gsl::span<wchar_t> commandHistory,
|
||||
size_t& written) noexcept override;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
void GetConsoleWindowImpl(HWND& hwnd) noexcept override;
|
||||
|
||||
void GetConsoleSelectionInfoImpl(CONSOLE_SELECTION_INFO& consoleSelectionInfo) noexcept override;
|
||||
|
||||
void GetConsoleHistoryInfoImpl(CONSOLE_HISTORY_INFO& consoleHistoryInfo) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT SetConsoleHistoryInfoImpl(const CONSOLE_HISTORY_INFO& consoleHistoryInfo) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT SetCurrentConsoleFontExImpl(IConsoleOutputObject& context,
|
||||
const bool isForMaximumWindowSize,
|
||||
const CONSOLE_FONT_INFOEX& consoleFontInfoEx) noexcept override;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
IApiRoutines* m_pUsualRoutines;
|
||||
UINT& m_inputCodepage;
|
||||
UINT& m_outputCodepage;
|
||||
ULONG m_inputMode;
|
||||
ULONG m_outputMode;
|
||||
bool m_listeningForDSR;
|
||||
Microsoft::Console::Render::Xterm256Engine* m_pVtEngine;
|
||||
|
||||
private:
|
||||
void _SynchronizeCursor(std::unique_ptr<IWaitRoutine>& waiter) noexcept;
|
||||
};
|
||||
@ -31,7 +31,8 @@ VtInputThread::VtInputThread(_In_ wil::unique_hfile hPipe,
|
||||
_u8State{},
|
||||
_dwThreadId{ 0 },
|
||||
_exitRequested{ false },
|
||||
_exitResult{ S_OK }
|
||||
_exitResult{ S_OK },
|
||||
_pfnSetLookingForDSR{}
|
||||
{
|
||||
THROW_HR_IF(E_HANDLE, _hFile.get() == INVALID_HANDLE_VALUE);
|
||||
|
||||
@ -50,6 +51,9 @@ VtInputThread::VtInputThread(_In_ wil::unique_hfile hPipe,
|
||||
// we need this callback to be able to flush an unknown input sequence to the app
|
||||
auto flushCallback = std::bind(&StateMachine::FlushToTerminal, _pInputStateMachine.get());
|
||||
engineRef->SetFlushToInputQueueCallback(flushCallback);
|
||||
|
||||
// we need this callback to capture the reply if someone requests a status from the terminal
|
||||
_pfnSetLookingForDSR = std::bind(&InputStateMachineEngine::SetLookingForDSR, engineRef, std::placeholders::_1);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@ -138,6 +142,14 @@ void VtInputThread::DoReadInput(const bool throwOnFail)
|
||||
}
|
||||
}
|
||||
|
||||
void VtInputThread::SetLookingForDSR(const bool looking) noexcept
|
||||
{
|
||||
if (_pfnSetLookingForDSR)
|
||||
{
|
||||
_pfnSetLookingForDSR(looking);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - The ThreadProc for the VT Input Thread. Reads input from the pipe, and
|
||||
// passes it to _HandleRunInput to be processed by the
|
||||
|
||||
@ -26,6 +26,7 @@ namespace Microsoft::Console
|
||||
[[nodiscard]] HRESULT Start();
|
||||
static DWORD WINAPI StaticVtInputThreadProc(_In_ LPVOID lpParameter);
|
||||
void DoReadInput(const bool throwOnFail);
|
||||
void SetLookingForDSR(const bool looking) noexcept;
|
||||
|
||||
private:
|
||||
[[nodiscard]] HRESULT _HandleRunInput(const std::string_view u8Str);
|
||||
@ -38,6 +39,8 @@ namespace Microsoft::Console
|
||||
bool _exitRequested;
|
||||
HRESULT _exitResult;
|
||||
|
||||
std::function<void(bool)> _pfnSetLookingForDSR;
|
||||
|
||||
std::unique_ptr<Microsoft::Console::VirtualTerminal::StateMachine> _pInputStateMachine;
|
||||
til::u8state _u8State;
|
||||
};
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
#include "input.h" // ProcessCtrlEvents
|
||||
#include "output.h" // CloseConsoleProcessState
|
||||
|
||||
#include "VtApiRoutines.h"
|
||||
|
||||
using namespace Microsoft::Console;
|
||||
using namespace Microsoft::Console::Render;
|
||||
using namespace Microsoft::Console::VirtualTerminal;
|
||||
@ -71,6 +73,7 @@ VtIo::VtIo() :
|
||||
_lookingForCursorPosition = pArgs->GetInheritCursor();
|
||||
_resizeQuirk = pArgs->IsResizeQuirkEnabled();
|
||||
_win32InputMode = pArgs->IsWin32InputModeEnabled();
|
||||
_passthroughMode = pArgs->IsPassthroughMode();
|
||||
|
||||
// If we were already given VT handles, set up the VT IO engine to use those.
|
||||
if (pArgs->InConptyMode())
|
||||
@ -137,8 +140,9 @@ VtIo::VtIo() :
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
auto& globals = ServiceLocator::LocateGlobals();
|
||||
|
||||
const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
const CONSOLE_INFORMATION& gci = globals.getConsoleInformation();
|
||||
|
||||
try
|
||||
{
|
||||
@ -155,22 +159,60 @@ VtIo::VtIo() :
|
||||
switch (_IoMode)
|
||||
{
|
||||
case VtIoMode::XTERM_256:
|
||||
_pVtRenderEngine = std::make_unique<Xterm256Engine>(std::move(_hOutput),
|
||||
initialViewport);
|
||||
{
|
||||
auto xterm256Engine = std::make_unique<Xterm256Engine>(std::move(_hOutput),
|
||||
initialViewport);
|
||||
if constexpr (Feature_VtPassthroughMode::IsEnabled())
|
||||
{
|
||||
if (_passthroughMode)
|
||||
{
|
||||
auto vtapi = new VtApiRoutines();
|
||||
vtapi->m_pVtEngine = xterm256Engine.get();
|
||||
vtapi->m_pUsualRoutines = globals.api;
|
||||
|
||||
xterm256Engine->SetPassthroughMode(true);
|
||||
|
||||
if (_pVtInputThread)
|
||||
{
|
||||
auto pfnSetListenForDSR = std::bind(&VtInputThread::SetLookingForDSR, _pVtInputThread.get(), std::placeholders::_1);
|
||||
xterm256Engine->SetLookingForDSRCallback(pfnSetListenForDSR);
|
||||
}
|
||||
|
||||
globals.api = vtapi;
|
||||
}
|
||||
}
|
||||
|
||||
_pVtRenderEngine = std::move(xterm256Engine);
|
||||
break;
|
||||
}
|
||||
case VtIoMode::XTERM:
|
||||
{
|
||||
_pVtRenderEngine = std::make_unique<XtermEngine>(std::move(_hOutput),
|
||||
initialViewport,
|
||||
false);
|
||||
if (_passthroughMode)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VtIoMode::XTERM_ASCII:
|
||||
{
|
||||
_pVtRenderEngine = std::make_unique<XtermEngine>(std::move(_hOutput),
|
||||
initialViewport,
|
||||
true);
|
||||
|
||||
if (_passthroughMode)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
if (_pVtRenderEngine)
|
||||
{
|
||||
_pVtRenderEngine->SetTerminalOwner(this);
|
||||
|
||||
@ -66,6 +66,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
|
||||
bool _resizeQuirk{ false };
|
||||
bool _win32InputMode{ false };
|
||||
bool _passthroughMode{ false };
|
||||
|
||||
std::unique_ptr<Microsoft::Console::Render::VtEngine> _pVtRenderEngine;
|
||||
std::unique_ptr<Microsoft::Console::VtInputThread> _pVtInputThread;
|
||||
|
||||
@ -604,9 +604,9 @@ void EventsToUnicode(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& inEvents,
|
||||
// - rectangle - This is the rectangle describing the region that the buffer covers.
|
||||
// Return Value:
|
||||
// - Generally S_OK. Could be a memory or math error code.
|
||||
[[nodiscard]] static HRESULT _ConvertCellsToWInplace(const UINT codepage,
|
||||
gsl::span<CHAR_INFO> buffer,
|
||||
const Viewport& rectangle) noexcept
|
||||
[[nodiscard]] HRESULT _ConvertCellsToWInplace(const UINT codepage,
|
||||
gsl::span<CHAR_INFO> buffer,
|
||||
const Viewport& rectangle) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@ -7,6 +7,11 @@
|
||||
|
||||
#pragma hdrstop
|
||||
|
||||
Globals::Globals()
|
||||
{
|
||||
api = &defaultApiRoutines;
|
||||
}
|
||||
|
||||
CONSOLE_INFORMATION& Globals::getConsoleInformation()
|
||||
{
|
||||
return ciConsoleInformation;
|
||||
|
||||
@ -34,6 +34,8 @@ TRACELOGGING_DECLARE_PROVIDER(g_hConhostV2EventTraceProvider);
|
||||
class Globals
|
||||
{
|
||||
public:
|
||||
Globals();
|
||||
|
||||
UINT uiOEMCP = GetOEMCP();
|
||||
UINT uiWindowsCP = GetACP();
|
||||
HINSTANCE hInstance;
|
||||
@ -65,7 +67,7 @@ public:
|
||||
|
||||
bool IsHeadless() const;
|
||||
|
||||
ApiRoutines api;
|
||||
IApiRoutines* api;
|
||||
|
||||
bool handoffTarget = false;
|
||||
|
||||
@ -80,4 +82,5 @@ public:
|
||||
|
||||
private:
|
||||
CONSOLE_INFORMATION ciConsoleInformation;
|
||||
ApiRoutines defaultApiRoutines;
|
||||
};
|
||||
|
||||
@ -52,6 +52,7 @@
|
||||
<ClCompile Include="..\tracing.cpp" />
|
||||
<ClCompile Include="..\utils.cpp" />
|
||||
<ClCompile Include="..\utf8ToWideCharParser.cpp" />
|
||||
<ClCompile Include="..\VtApiRoutines.cpp" />
|
||||
<ClCompile Include="..\VtInputThread.cpp" />
|
||||
<ClCompile Include="..\VtIo.cpp" />
|
||||
<ClCompile Include="..\writeData.cpp" />
|
||||
@ -110,6 +111,7 @@
|
||||
<ClInclude Include="..\tracing.hpp" />
|
||||
<ClInclude Include="..\utils.hpp" />
|
||||
<ClInclude Include="..\utf8ToWideCharParser.hpp" />
|
||||
<ClInclude Include="..\VtApiRoutines.h" />
|
||||
<ClInclude Include="..\VtInputThread.hpp" />
|
||||
<ClInclude Include="..\VtIo.hpp" />
|
||||
<ClInclude Include="..\writeData.hpp" />
|
||||
|
||||
@ -177,6 +177,9 @@
|
||||
<ClCompile Include="..\CursorBlinker.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\VtApiRoutines.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\precomp.h">
|
||||
@ -347,8 +350,11 @@
|
||||
<ClInclude Include="..\IIoProvider.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\VtApiRoutines.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@ -65,7 +65,7 @@ void ConhostInternalGetSet::PrintString(const std::wstring_view string)
|
||||
// - <none>
|
||||
void ConhostInternalGetSet::GetConsoleScreenBufferInfoEx(CONSOLE_SCREEN_BUFFER_INFOEX& screenBufferInfo) const
|
||||
{
|
||||
ServiceLocator::LocateGlobals().api.GetConsoleScreenBufferInfoExImpl(_io.GetActiveOutputBuffer(), screenBufferInfo);
|
||||
ServiceLocator::LocateGlobals().api->GetConsoleScreenBufferInfoExImpl(_io.GetActiveOutputBuffer(), screenBufferInfo);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@ -76,7 +76,7 @@ void ConhostInternalGetSet::GetConsoleScreenBufferInfoEx(CONSOLE_SCREEN_BUFFER_I
|
||||
// - <none>
|
||||
void ConhostInternalGetSet::SetConsoleScreenBufferInfoEx(const CONSOLE_SCREEN_BUFFER_INFOEX& screenBufferInfo)
|
||||
{
|
||||
THROW_IF_FAILED(ServiceLocator::LocateGlobals().api.SetConsoleScreenBufferInfoExImpl(_io.GetActiveOutputBuffer(), screenBufferInfo));
|
||||
THROW_IF_FAILED(ServiceLocator::LocateGlobals().api->SetConsoleScreenBufferInfoExImpl(_io.GetActiveOutputBuffer(), screenBufferInfo));
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@ -89,7 +89,7 @@ void ConhostInternalGetSet::SetCursorPosition(const COORD position)
|
||||
{
|
||||
auto& info = _io.GetActiveOutputBuffer();
|
||||
const auto clampedPosition = info.GetTextBuffer().ClampPositionWithinLine(position);
|
||||
THROW_IF_FAILED(ServiceLocator::LocateGlobals().api.SetConsoleCursorPositionImpl(info, clampedPosition));
|
||||
THROW_IF_FAILED(ServiceLocator::LocateGlobals().api->SetConsoleCursorPositionImpl(info, clampedPosition));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@ -177,7 +177,7 @@ void ConhostInternalGetSet::WriteInput(std::deque<std::unique_ptr<IInputEvent>>&
|
||||
// - <none>
|
||||
void ConhostInternalGetSet::SetWindowInfo(const bool absolute, const SMALL_RECT& window)
|
||||
{
|
||||
THROW_IF_FAILED(ServiceLocator::LocateGlobals().api.SetConsoleWindowInfoImpl(_io.GetActiveOutputBuffer(), absolute, window));
|
||||
THROW_IF_FAILED(ServiceLocator::LocateGlobals().api->SetConsoleWindowInfoImpl(_io.GetActiveOutputBuffer(), absolute, window));
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
||||
@ -169,10 +169,10 @@ void Popup::_DrawPrompt(const UINT id)
|
||||
}
|
||||
|
||||
size_t used;
|
||||
LOG_IF_FAILED(ServiceLocator::LocateGlobals().api.WriteConsoleOutputCharacterWImpl(_screenInfo,
|
||||
text,
|
||||
WriteCoord,
|
||||
used));
|
||||
LOG_IF_FAILED(ServiceLocator::LocateGlobals().api->WriteConsoleOutputCharacterWImpl(_screenInfo,
|
||||
text,
|
||||
WriteCoord,
|
||||
used));
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
||||
@ -93,6 +93,7 @@ SOURCES = \
|
||||
..\CommandListPopup.cpp \
|
||||
..\CopyFromCharPopup.cpp \
|
||||
..\CopyToCharPopup.cpp \
|
||||
..\VtApiRoutines.cpp \
|
||||
|
||||
|
||||
# -------------------------------------
|
||||
|
||||
@ -944,7 +944,7 @@ DWORD WINAPI ConsoleIoThread(LPVOID lpParameter)
|
||||
auto& globals = ServiceLocator::LocateGlobals();
|
||||
|
||||
CONSOLE_API_MSG ReceiveMsg;
|
||||
ReceiveMsg._pApiRoutines = &globals.api;
|
||||
ReceiveMsg._pApiRoutines = globals.api;
|
||||
ReceiveMsg._pDeviceComm = globals.pDeviceComm;
|
||||
PCONSOLE_API_MSG ReplyMsg = nullptr;
|
||||
|
||||
@ -956,7 +956,7 @@ DWORD WINAPI ConsoleIoThread(LPVOID lpParameter)
|
||||
std::unique_ptr<CONSOLE_API_MSG> capturedMessage{ static_cast<PCONSOLE_API_MSG>(lpParameter) };
|
||||
|
||||
ReceiveMsg = *capturedMessage.get();
|
||||
ReceiveMsg._pApiRoutines = &globals.api;
|
||||
ReceiveMsg._pApiRoutines = globals.api;
|
||||
ReceiveMsg._pDeviceComm = globals.pDeviceComm;
|
||||
IoSorter::ServiceIoOperation(&ReceiveMsg, &ReplyMsg);
|
||||
}
|
||||
@ -984,7 +984,7 @@ DWORD WINAPI ConsoleIoThread(LPVOID lpParameter)
|
||||
ReplyMsg = nullptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
ReceiveMsg._pApiRoutines = globals.api;
|
||||
IoSorter::ServiceIoOperation(&ReceiveMsg, &ReplyMsg);
|
||||
}
|
||||
|
||||
|
||||
@ -83,7 +83,8 @@ void ConsoleArgumentsTests::ArgSplittingTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe \"this is the commandline\"";
|
||||
@ -105,7 +106,8 @@ void ConsoleArgumentsTests::ArgSplittingTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --headless \"--vtmode bar this is the commandline\"";
|
||||
@ -127,7 +129,8 @@ void ConsoleArgumentsTests::ArgSplittingTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --headless --server 0x4 this is the commandline";
|
||||
@ -149,7 +152,8 @@ void ConsoleArgumentsTests::ArgSplittingTests()
|
||||
0x4, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --headless\t--vtmode\txterm\tthis\tis\tthe\tcommandline";
|
||||
@ -171,7 +175,8 @@ void ConsoleArgumentsTests::ArgSplittingTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --headless\\ foo\\ --outpipe\\ bar\\ this\\ is\\ the\\ commandline";
|
||||
@ -193,7 +198,8 @@ void ConsoleArgumentsTests::ArgSplittingTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --headless\\\tfoo\\\t--outpipe\\\tbar\\\tthis\\\tis\\\tthe\\\tcommandline";
|
||||
@ -215,7 +221,8 @@ void ConsoleArgumentsTests::ArgSplittingTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --vtmode a\\\\\\\\\"b c\" d e";
|
||||
@ -237,7 +244,8 @@ void ConsoleArgumentsTests::ArgSplittingTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe this is the commandline";
|
||||
@ -259,7 +267,8 @@ void ConsoleArgumentsTests::ArgSplittingTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
}
|
||||
|
||||
@ -286,7 +295,8 @@ void ConsoleArgumentsTests::ClientCommandlineTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe foo";
|
||||
@ -308,7 +318,8 @@ void ConsoleArgumentsTests::ClientCommandlineTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe foo -- bar";
|
||||
@ -330,7 +341,8 @@ void ConsoleArgumentsTests::ClientCommandlineTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --vtmode foo foo -- bar";
|
||||
@ -352,7 +364,8 @@ void ConsoleArgumentsTests::ClientCommandlineTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe console --vtmode foo foo -- bar";
|
||||
@ -374,7 +387,8 @@ void ConsoleArgumentsTests::ClientCommandlineTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe console --vtmode foo --outpipe foo -- bar";
|
||||
@ -396,7 +410,8 @@ void ConsoleArgumentsTests::ClientCommandlineTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --vtmode foo -- --outpipe foo bar";
|
||||
@ -418,7 +433,8 @@ void ConsoleArgumentsTests::ClientCommandlineTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --vtmode -- --headless bar";
|
||||
@ -440,7 +456,8 @@ void ConsoleArgumentsTests::ClientCommandlineTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --";
|
||||
@ -462,7 +479,8 @@ void ConsoleArgumentsTests::ClientCommandlineTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe";
|
||||
@ -484,7 +502,8 @@ void ConsoleArgumentsTests::ClientCommandlineTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
}
|
||||
|
||||
@ -511,7 +530,8 @@ void ConsoleArgumentsTests::LegacyFormatsTests()
|
||||
4ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --server 0x4";
|
||||
@ -533,7 +553,8 @@ void ConsoleArgumentsTests::LegacyFormatsTests()
|
||||
4ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe 0x4 0x8";
|
||||
@ -555,7 +576,8 @@ void ConsoleArgumentsTests::LegacyFormatsTests()
|
||||
4ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
false); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --server 0x4 0x8";
|
||||
@ -577,7 +599,8 @@ void ConsoleArgumentsTests::LegacyFormatsTests()
|
||||
4ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
false); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe 0x4 --server 0x8";
|
||||
@ -599,7 +622,8 @@ void ConsoleArgumentsTests::LegacyFormatsTests()
|
||||
4ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
false); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --server 0x4 --server 0x8";
|
||||
@ -621,7 +645,8 @@ void ConsoleArgumentsTests::LegacyFormatsTests()
|
||||
4ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
false); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe 0x4 -ForceV1";
|
||||
@ -643,7 +668,8 @@ void ConsoleArgumentsTests::LegacyFormatsTests()
|
||||
4ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe -ForceV1";
|
||||
@ -665,7 +691,8 @@ void ConsoleArgumentsTests::LegacyFormatsTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe 0x4 -ForceNoHandoff";
|
||||
@ -687,7 +714,8 @@ void ConsoleArgumentsTests::LegacyFormatsTests()
|
||||
4ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe -ForceNoHandoff";
|
||||
@ -709,7 +737,8 @@ void ConsoleArgumentsTests::LegacyFormatsTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
}
|
||||
|
||||
@ -760,7 +789,8 @@ void ConsoleArgumentsTests::CombineVtPipeHandleTests()
|
||||
0ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --vtmode xterm-256color";
|
||||
@ -782,7 +812,8 @@ void ConsoleArgumentsTests::CombineVtPipeHandleTests()
|
||||
0ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
}
|
||||
|
||||
@ -819,7 +850,8 @@ void ConsoleArgumentsTests::InitialSizeTests()
|
||||
0ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --width 120";
|
||||
@ -841,7 +873,8 @@ void ConsoleArgumentsTests::InitialSizeTests()
|
||||
0ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --height 30";
|
||||
@ -863,7 +896,8 @@ void ConsoleArgumentsTests::InitialSizeTests()
|
||||
0ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --width 0";
|
||||
@ -885,7 +919,8 @@ void ConsoleArgumentsTests::InitialSizeTests()
|
||||
0ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --width -1";
|
||||
@ -907,7 +942,8 @@ void ConsoleArgumentsTests::InitialSizeTests()
|
||||
0ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --width foo";
|
||||
@ -929,7 +965,8 @@ void ConsoleArgumentsTests::InitialSizeTests()
|
||||
0ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
false); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --width 2foo";
|
||||
@ -951,7 +988,8 @@ void ConsoleArgumentsTests::InitialSizeTests()
|
||||
0ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
false); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --width 65535";
|
||||
@ -973,7 +1011,8 @@ void ConsoleArgumentsTests::InitialSizeTests()
|
||||
0ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
false); // successful parse?
|
||||
}
|
||||
|
||||
@ -1000,7 +1039,8 @@ void ConsoleArgumentsTests::HeadlessArgTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --headless 0x4";
|
||||
@ -1022,7 +1062,8 @@ void ConsoleArgumentsTests::HeadlessArgTests()
|
||||
4ul, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --headless --headless";
|
||||
@ -1044,7 +1085,8 @@ void ConsoleArgumentsTests::HeadlessArgTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe -- foo.exe --headless";
|
||||
@ -1066,7 +1108,8 @@ void ConsoleArgumentsTests::HeadlessArgTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
}
|
||||
|
||||
@ -1097,7 +1140,8 @@ void ConsoleArgumentsTests::SignalHandleTests()
|
||||
4ul, // serverHandle
|
||||
8ul, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --server 0x4 --signal ASDF";
|
||||
@ -1119,7 +1163,8 @@ void ConsoleArgumentsTests::SignalHandleTests()
|
||||
4ul, // serverHandle
|
||||
0ul, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
false); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --signal --server 0x4";
|
||||
@ -1141,7 +1186,8 @@ void ConsoleArgumentsTests::SignalHandleTests()
|
||||
0ul, // serverHandle
|
||||
0ul, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
false); // successful parse?
|
||||
}
|
||||
|
||||
@ -1172,7 +1218,8 @@ void ConsoleArgumentsTests::FeatureArgTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
commandline = L"conhost.exe --feature tty";
|
||||
ArgTestsRunner(L"#2 Error case, pass an unsupported feature",
|
||||
@ -1193,7 +1240,8 @@ void ConsoleArgumentsTests::FeatureArgTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
false); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --feature pty --feature pty";
|
||||
@ -1215,7 +1263,8 @@ void ConsoleArgumentsTests::FeatureArgTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
true); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --feature pty --feature tty";
|
||||
@ -1237,7 +1286,8 @@ void ConsoleArgumentsTests::FeatureArgTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
false); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --feature pty --feature";
|
||||
@ -1259,7 +1309,8 @@ void ConsoleArgumentsTests::FeatureArgTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
false); // successful parse?
|
||||
|
||||
commandline = L"conhost.exe --feature pty --feature --signal foo";
|
||||
@ -1281,6 +1332,7 @@ void ConsoleArgumentsTests::FeatureArgTests()
|
||||
0, // serverHandle
|
||||
0, // signalHandle
|
||||
false, // inheritCursor
|
||||
false), // runAsComServer
|
||||
false, // runAsComServer
|
||||
false), // passthroughMode
|
||||
false); // successful parse?
|
||||
}
|
||||
|
||||
@ -1863,7 +1863,7 @@ void ScreenBufferTests::ResizeAltBufferGetScreenBufferInfo()
|
||||
altBuffer.SetViewportSize(&newBufferSize);
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFOEX csbiex{ 0 };
|
||||
g.api.GetConsoleScreenBufferInfoExImpl(mainBuffer, csbiex);
|
||||
g.api->GetConsoleScreenBufferInfoExImpl(mainBuffer, csbiex);
|
||||
const auto newActualMainView = mainBuffer.GetViewport();
|
||||
const auto newActualAltView = altBuffer.GetViewport();
|
||||
|
||||
@ -4973,7 +4973,7 @@ void ScreenBufferTests::SnapCursorWithTerminalScrolling()
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Call SetConsoleCursorPosition to snap to the cursor"));
|
||||
VERIFY_SUCCEEDED(g.api.SetConsoleCursorPositionImpl(si, secondWindowOrigin));
|
||||
VERIFY_SUCCEEDED(g.api->SetConsoleCursorPositionImpl(si, secondWindowOrigin));
|
||||
|
||||
const auto fourthView = si._viewport;
|
||||
const auto fourthVirtualBottom = si._virtualBottom;
|
||||
@ -5049,12 +5049,12 @@ void ScreenBufferTests::ClearAlternateBuffer()
|
||||
|
||||
#pragma region Test ScrollConsoleScreenBufferWImpl()
|
||||
// Clear text of alt buffer (same params as in CMD)
|
||||
VERIFY_SUCCEEDED(g.api.ScrollConsoleScreenBufferWImpl(siMain,
|
||||
{ 0, 0, 120, 9001 },
|
||||
{ 0, -9001 },
|
||||
std::nullopt,
|
||||
L' ',
|
||||
7));
|
||||
VERIFY_SUCCEEDED(g.api->ScrollConsoleScreenBufferWImpl(siMain,
|
||||
{ 0, 0, 120, 9001 },
|
||||
{ 0, -9001 },
|
||||
std::nullopt,
|
||||
L' ',
|
||||
7));
|
||||
|
||||
// Verify text is now gone
|
||||
VERIFY_ARE_EQUAL(L" ", altBuffer.GetTextBuffer().GetCellDataAt({ 0, 0 })->Chars());
|
||||
@ -5062,7 +5062,7 @@ void ScreenBufferTests::ClearAlternateBuffer()
|
||||
|
||||
#pragma region Test SetConsoleCursorPositionImpl()
|
||||
// Reset cursor position as we do with CLS command (same params as in CMD)
|
||||
VERIFY_SUCCEEDED(g.api.SetConsoleCursorPositionImpl(siMain, { 0 }));
|
||||
VERIFY_SUCCEEDED(g.api->SetConsoleCursorPositionImpl(siMain, { 0 }));
|
||||
|
||||
// Verify state of alt buffer
|
||||
auto& altBufferCursor = altBuffer.GetTextBuffer().GetCursor();
|
||||
|
||||
@ -17,6 +17,7 @@ extern "C" {
|
||||
|
||||
#define PSEUDOCONSOLE_RESIZE_QUIRK (2u)
|
||||
#define PSEUDOCONSOLE_WIN32_INPUT_MODE (4u)
|
||||
#define PSEUDOCONSOLE_PASSTHROUGH_MODE (8u)
|
||||
|
||||
HRESULT WINAPI ConptyCreatePseudoConsole(COORD size, HANDLE hInput, HANDLE hOutput, DWORD dwFlags, HPCON* phPC);
|
||||
|
||||
|
||||
@ -565,11 +565,11 @@ BOOL HandleSysKeyEvent(const HWND hWnd, const UINT Message, const WPARAM wParam,
|
||||
CONSOLE_FONT_INFOEX font = { 0 };
|
||||
font.cbSize = sizeof(font);
|
||||
|
||||
RETURN_IF_FAILED(globals.api.GetCurrentConsoleFontExImpl(screenInfo, false, font));
|
||||
RETURN_IF_FAILED(globals.api->GetCurrentConsoleFontExImpl(screenInfo, false, font));
|
||||
|
||||
font.dwFontSize.Y += delta;
|
||||
|
||||
RETURN_IF_FAILED(globals.api.SetCurrentConsoleFontExImpl(screenInfo, false, font));
|
||||
RETURN_IF_FAILED(globals.api->SetCurrentConsoleFontExImpl(screenInfo, false, font));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@ -30,8 +30,10 @@ Xterm256Engine::Xterm256Engine(_In_ wil::unique_hfile hPipe,
|
||||
const RenderSettings& /*renderSettings*/,
|
||||
const gsl::not_null<IRenderData*> pData,
|
||||
const bool /*usingSoftFont*/,
|
||||
const bool /*isSettingDefaultBrushes*/) noexcept
|
||||
const bool isSettingDefaultBrushes) noexcept
|
||||
{
|
||||
RETURN_HR_IF(S_FALSE, _passthrough && isSettingDefaultBrushes);
|
||||
|
||||
RETURN_IF_FAILED(VtEngine::_RgbUpdateDrawingBrushes(textAttributes));
|
||||
|
||||
RETURN_IF_FAILED(_UpdateHyperlinkAttr(textAttributes, pData));
|
||||
|
||||
@ -18,6 +18,8 @@ Author(s):
|
||||
|
||||
#include "XtermEngine.hpp"
|
||||
|
||||
class VtApiRoutines;
|
||||
|
||||
namespace Microsoft::Console::Render
|
||||
{
|
||||
class Xterm256Engine : public XtermEngine
|
||||
@ -36,6 +38,8 @@ namespace Microsoft::Console::Render
|
||||
|
||||
[[nodiscard]] HRESULT ManuallyClearScrollback() noexcept override;
|
||||
|
||||
friend class ::VtApiRoutines;
|
||||
|
||||
private:
|
||||
[[nodiscard]] HRESULT _UpdateExtendedAttrs(const TextAttribute& textAttributes) noexcept;
|
||||
[[nodiscard]] HRESULT _UpdateHyperlinkAttr(const TextAttribute& textAttributes,
|
||||
|
||||
@ -46,6 +46,16 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe,
|
||||
// during the frame.
|
||||
_nextCursorIsVisible = false;
|
||||
|
||||
// Do not perform synchronization clearing in passthrough mode.
|
||||
// In passthrough, the terminal leads and we follow what it is
|
||||
// handling from the client application.
|
||||
// (This is in contrast to full PTY mode where WE, the ConPTY, lead and
|
||||
// it follows our state.)
|
||||
if (_passthrough)
|
||||
{
|
||||
_firstPaint = false;
|
||||
}
|
||||
|
||||
if (_firstPaint)
|
||||
{
|
||||
// MSFT:17815688
|
||||
|
||||
@ -54,7 +54,8 @@ VtEngine::VtEngine(_In_ wil::unique_hfile pipe,
|
||||
_bufferLine{},
|
||||
_buffer{},
|
||||
_formatBuffer{},
|
||||
_conversionBuffer{}
|
||||
_conversionBuffer{},
|
||||
_pfnSetLookingForDSR{}
|
||||
{
|
||||
#ifndef UNIT_TESTING
|
||||
// When unit testing, we can instantiate a VtEngine without a pipe.
|
||||
@ -65,6 +66,37 @@ VtEngine::VtEngine(_In_ wil::unique_hfile pipe,
|
||||
#endif
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Writes a fill of characters to our file handle (repeat of same character over and over)
|
||||
[[nodiscard]] HRESULT VtEngine::_WriteFill(const size_t n, const char c) noexcept
|
||||
try
|
||||
{
|
||||
_trace.TraceStringFill(n, c);
|
||||
#ifdef UNIT_TESTING
|
||||
if (_usingTestCallback)
|
||||
{
|
||||
const std::string str(n, c);
|
||||
// Try to get the last error. If that wasn't set, then the test probably
|
||||
// doesn't set last error. No matter. We'll just return with E_FAIL
|
||||
// then. This is a unit test, we don't particularly care.
|
||||
const auto succeeded = _pfnTestCallback(str.data(), str.size());
|
||||
auto hr = E_FAIL;
|
||||
if (!succeeded)
|
||||
{
|
||||
const auto err = ::GetLastError();
|
||||
// If there wasn't an error in GLE, just use E_FAIL
|
||||
hr = SUCCEEDED_WIN32(err) ? hr : HRESULT_FROM_WIN32(err);
|
||||
}
|
||||
return succeeded ? S_OK : hr;
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO GH10001: Replace me with REP
|
||||
_buffer.append(n, c);
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
// Method Description:
|
||||
// - Writes the characters to our file handle. If we're building the unit tests,
|
||||
// we can instead write to the test callback, in order to avoid needing to
|
||||
@ -379,6 +411,23 @@ HRESULT VtEngine::RequestCursor() noexcept
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sends a notification through to the `VtInputThread` that it should
|
||||
// watch for and capture the response from a DSR message we're about to send.
|
||||
// This is typically `RequestCursor` at the time of writing this, but in theory
|
||||
// could be another DSR as well.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - S_OK if all goes well. Invalid state error if no notification function is installed.
|
||||
// (see `SetLookingForDSRCallback` to install one.)
|
||||
[[nodiscard]] HRESULT VtEngine::_ListenForDSR() noexcept
|
||||
{
|
||||
RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), !_pfnSetLookingForDSR);
|
||||
_pfnSetLookingForDSR(true);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Tell the vt renderer to begin a resize operation. During a resize
|
||||
// operation, the vt renderer should _not_ request to be repainted during a
|
||||
@ -415,7 +464,7 @@ void VtEngine::EndResizeRequest()
|
||||
// conpty scenario.
|
||||
// - See also: GH#3490, #4354, #4741
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// - resizeQuirk - True to turn on the quirk. False otherwise.
|
||||
// Return Value:
|
||||
// - true iff we were started with the `--resizeQuirk` flag enabled.
|
||||
void VtEngine::SetResizeQuirk(const bool resizeQuirk)
|
||||
@ -423,6 +472,29 @@ void VtEngine::SetResizeQuirk(const bool resizeQuirk)
|
||||
_resizeQuirk = resizeQuirk;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Configure the renderer to understand that we're operating in limited-draw
|
||||
// passthrough mode. We do not need to handle full responsibility for replicating
|
||||
// buffer state to the attached terminal.
|
||||
// Arguments:
|
||||
// - passthrough - True to turn on passthrough mode. False otherwise.
|
||||
// Return Value:
|
||||
// - true iff we were started with an output mode for passthrough. false otherwise.
|
||||
void VtEngine::SetPassthroughMode(const bool passthrough) noexcept
|
||||
{
|
||||
_passthrough = passthrough;
|
||||
}
|
||||
|
||||
void VtEngine::SetLookingForDSRCallback(std::function<void(bool)> pfnLooking) noexcept
|
||||
{
|
||||
_pfnSetLookingForDSR = pfnLooking;
|
||||
}
|
||||
|
||||
void VtEngine::SetTerminalCursorTextPosition(const COORD cursor) noexcept
|
||||
{
|
||||
_lastText = cursor;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Manually emit a "Erase Scrollback" sequence to the connected terminal. We
|
||||
// need to do this in certain cases that we've identified where we believe the
|
||||
|
||||
@ -64,6 +64,23 @@ std::string toPrintableString(const std::string_view& inString)
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
void RenderTracing::TraceStringFill(const size_t n, const char c) const
|
||||
{
|
||||
#ifndef UNIT_TESTING
|
||||
if (TraceLoggingProviderEnabled(g_hConsoleVtRendererTraceProvider, WINEVENT_LEVEL_VERBOSE, TIL_KEYWORD_TRACE))
|
||||
{
|
||||
TraceLoggingWrite(g_hConsoleVtRendererTraceProvider,
|
||||
"VtEngine_TraceStringFill",
|
||||
TraceLoggingUInt64(gsl::narrow_cast<uint64_t>(n)),
|
||||
TraceLoggingChar(c),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
#else
|
||||
UNREFERENCED_PARAMETER(n);
|
||||
UNREFERENCED_PARAMETER(c);
|
||||
#endif UNIT_TESTING
|
||||
}
|
||||
void RenderTracing::TraceString(const std::string_view& instr) const
|
||||
{
|
||||
#ifndef UNIT_TESTING
|
||||
|
||||
@ -26,6 +26,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
public:
|
||||
RenderTracing();
|
||||
~RenderTracing();
|
||||
void TraceStringFill(const size_t n, const char c) const;
|
||||
void TraceString(const std::string_view& str) const;
|
||||
void TraceInvalidate(const til::rect& view) const;
|
||||
void TraceLastText(const til::point lastText) const;
|
||||
|
||||
@ -80,6 +80,9 @@ namespace Microsoft::Console::Render
|
||||
void BeginResizeRequest();
|
||||
void EndResizeRequest();
|
||||
void SetResizeQuirk(const bool resizeQuirk);
|
||||
void SetPassthroughMode(const bool passthrough) noexcept;
|
||||
void SetLookingForDSRCallback(std::function<void(bool)> pfnLooking) noexcept;
|
||||
void SetTerminalCursorTextPosition(const COORD coordCursor) noexcept;
|
||||
[[nodiscard]] virtual HRESULT ManuallyClearScrollback() noexcept;
|
||||
[[nodiscard]] HRESULT RequestWin32Input() noexcept;
|
||||
|
||||
@ -92,6 +95,8 @@ namespace Microsoft::Console::Render
|
||||
|
||||
TextAttribute _lastTextAttributes;
|
||||
|
||||
std::function<void(bool)> _pfnSetLookingForDSR;
|
||||
|
||||
Microsoft::Console::Types::Viewport _lastViewport;
|
||||
|
||||
std::pmr::unsynchronized_pool_resource _pool;
|
||||
@ -126,8 +131,10 @@ namespace Microsoft::Console::Render
|
||||
bool _delayedEolWrap{ false };
|
||||
|
||||
bool _resizeQuirk{ false };
|
||||
bool _passthrough{ false };
|
||||
std::optional<TextColor> _newBottomLineBG{ std::nullopt };
|
||||
|
||||
[[nodiscard]] HRESULT _WriteFill(const size_t n, const char c) noexcept;
|
||||
[[nodiscard]] HRESULT _Write(std::string_view const str) noexcept;
|
||||
[[nodiscard]] HRESULT _Flush() noexcept;
|
||||
|
||||
@ -186,6 +193,7 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] HRESULT _EndHyperlink() noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT _RequestCursor() noexcept;
|
||||
[[nodiscard]] HRESULT _ListenForDSR() noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT _RequestWin32Input() noexcept;
|
||||
|
||||
|
||||
@ -44,6 +44,8 @@ public:
|
||||
|
||||
#pragma endregion
|
||||
|
||||
virtual ~IApiRoutines(){};
|
||||
|
||||
#pragma region L1
|
||||
virtual void GetConsoleInputCodePageImpl(ULONG& codepage) noexcept = 0;
|
||||
|
||||
|
||||
@ -101,6 +101,11 @@ InputStateMachineEngine::InputStateMachineEngine(std::unique_ptr<IInteractDispat
|
||||
THROW_HR_IF_NULL(E_INVALIDARG, _pDispatch.get());
|
||||
}
|
||||
|
||||
void InputStateMachineEngine::SetLookingForDSR(const bool looking) noexcept
|
||||
{
|
||||
_lookingForDSR = looking;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Triggers the Execute action to indicate that the listener should
|
||||
// immediately respond to a C0 control character.
|
||||
|
||||
@ -131,6 +131,8 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
InputStateMachineEngine(std::unique_ptr<IInteractDispatch> pDispatch,
|
||||
const bool lookingForDSR);
|
||||
|
||||
void SetLookingForDSR(const bool looking) noexcept;
|
||||
|
||||
bool ActionExecute(const wchar_t wch) override;
|
||||
bool ActionExecuteFromEscape(const wchar_t wch) override;
|
||||
|
||||
|
||||
@ -298,6 +298,7 @@ static std::vector<DWORD> getConsoleProcessList()
|
||||
const DWORD count1 = GetConsoleProcessList(&ret[0], (DWORD)ret.size());
|
||||
assert(count1 >= 1 && "GetConsoleProcessList failed");
|
||||
ret.resize(count1);
|
||||
#pragma warning(suppress : 4189) // It's used in the assert
|
||||
const DWORD count2 = GetConsoleProcessList(&ret[0], (DWORD)ret.size());
|
||||
assert(count1 == count2 && "GetConsoleProcessList failed");
|
||||
return ret;
|
||||
@ -373,7 +374,7 @@ static void spawnChildTree(DWORD masterPid, const std::vector<std::wstring>& ext
|
||||
PROCESS_INFORMATION pi{};
|
||||
success = CreateProcessW(exeName().c_str(), &cmdline[0], nullptr, nullptr, FALSE, 0, nullptr, nullptr, &sui, &pi);
|
||||
assert(success && "CreateProcessW failed");
|
||||
|
||||
#pragma warning(suppress : 4189) // It's used in the assert
|
||||
const DWORD waitRet = WaitForSingleObject(readyEvent, INFINITE);
|
||||
assert(waitRet == WAIT_OBJECT_0 && "WaitForSingleObject failed");
|
||||
CloseHandle(readyEvent);
|
||||
@ -483,6 +484,7 @@ static BOOL WINAPI ctrlHandler(DWORD type)
|
||||
static HANDLE duplicateHandle(HANDLE srcProc, HANDLE srcHandle)
|
||||
{
|
||||
HANDLE ret{};
|
||||
#pragma warning(suppress : 4189) // It's used in the assert
|
||||
const auto success =
|
||||
DuplicateHandle(srcProc, srcHandle, GetCurrentProcess(), &ret, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||
assert(success && "DuplicateHandle failed");
|
||||
@ -603,6 +605,7 @@ static int doChild(std::deque<std::wstring> argv)
|
||||
// Assign self to a job object.
|
||||
if (jobHandle != nullptr)
|
||||
{
|
||||
#pragma warning(suppress : 4189) // It's used in the assert
|
||||
const BOOL success =
|
||||
AssignProcessToJobObject(jobHandle, GetCurrentProcess());
|
||||
assert(success && "AssignProcessToJobObject failed");
|
||||
|
||||
@ -94,12 +94,13 @@ HRESULT _CreatePseudoConsole(const HANDLE hToken,
|
||||
RETURN_IF_WIN32_BOOL_FALSE(SetHandleInformation(signalPipeConhostSide.get(), HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT));
|
||||
|
||||
// GH4061: Ensure that the path to executable in the format is escaped so C:\Program.exe cannot collide with C:\Program Files
|
||||
const wchar_t* pwszFormat = L"\"%s\" --headless %s%s%s--width %hu --height %hu --signal 0x%x --server 0x%x";
|
||||
const wchar_t* pwszFormat = L"\"%s\" --headless %s%s%s%s--width %hu --height %hu --signal 0x%x --server 0x%x";
|
||||
// This is plenty of space to hold the formatted string
|
||||
wchar_t cmd[MAX_PATH]{};
|
||||
const BOOL bInheritCursor = (dwFlags & PSEUDOCONSOLE_INHERIT_CURSOR) == PSEUDOCONSOLE_INHERIT_CURSOR;
|
||||
const BOOL bResizeQuirk = (dwFlags & PSEUDOCONSOLE_RESIZE_QUIRK) == PSEUDOCONSOLE_RESIZE_QUIRK;
|
||||
const BOOL bWin32InputMode = (dwFlags & PSEUDOCONSOLE_WIN32_INPUT_MODE) == PSEUDOCONSOLE_WIN32_INPUT_MODE;
|
||||
const BOOL bPassthroughMode = (dwFlags & PSEUDOCONSOLE_PASSTHROUGH_MODE) == PSEUDOCONSOLE_PASSTHROUGH_MODE;
|
||||
swprintf_s(cmd,
|
||||
MAX_PATH,
|
||||
pwszFormat,
|
||||
@ -107,6 +108,7 @@ HRESULT _CreatePseudoConsole(const HANDLE hToken,
|
||||
bInheritCursor ? L"--inheritcursor " : L"",
|
||||
bWin32InputMode ? L"--win32input " : L"",
|
||||
bResizeQuirk ? L"--resizeQuirk " : L"",
|
||||
bPassthroughMode ? L"--passthrough " : L"",
|
||||
size.X,
|
||||
size.Y,
|
||||
signalPipeConhostSide.get(),
|
||||
|
||||
@ -25,6 +25,7 @@ typedef struct _PseudoConsole
|
||||
// #define PSEUDOCONSOLE_INHERIT_CURSOR (0x1)
|
||||
#define PSEUDOCONSOLE_RESIZE_QUIRK (0x2)
|
||||
#define PSEUDOCONSOLE_WIN32_INPUT_MODE (0x4)
|
||||
#define PSEUDOCONSOLE_PASSTHROUGH_MODE (0x8)
|
||||
|
||||
// Implementations of the various PseudoConsole functions.
|
||||
HRESULT _CreatePseudoConsole(const HANDLE hToken,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user