6e70c4ae07
#### ⚠️ targets #10051 ## Summary of the Pull Request This PR does one big, primary thing. It removes all the constructors from any TerminalConnections, and changes them to use an `Initialize` method that accepts a `ValueSet` of properties. Why? For the upcoming window/content process work, we'll need the content process to be able to initialize the connection _in the content process_. However, the window process will be the one that knows what type of connection to make. Enter `ConnectionInformation`. This class will let us specify the class name of the type we want to create, and a set of settings to use when initializing that connection. **IMPORTANT**: As a part of this, the constructor for a connection must have 0 arguments. `RoActivateInstance` lets you just conjure a WinRT type just by class name, but that class must have a 0 arg ctor. Hence the need for `Initialize`, to actually pass the settings. We're using a `ValueSet` here because it's basically a json blob, with more steps. In the future, when extension authors want to have custom connections, we can always deserialize the json into a `ValueSet`, pass it to their connection's `Initialize`, and let then get what they need out of it. ## References * Tear-out: #1256 * Megathread: #5000 * Project: https://github.com/microsoft/terminal/projects/5 ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760298 * [x] I work here * [n/a] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments `ConnectionInformation` was included as a part of this PR, to demonstrate how this will eventually be used. `ConnectionInformation` is not _currently_ used. ## Validation Steps Performed It still builds and runs.
109 lines
3.9 KiB
C++
109 lines
3.9 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#include "pch.h"
|
|
#include "winrt/Microsoft.Terminal.TerminalConnection.h"
|
|
#include "ConsoleInputReader.h"
|
|
|
|
using namespace winrt;
|
|
using namespace winrt::Windows::Foundation;
|
|
using namespace winrt::Microsoft::Terminal::TerminalConnection;
|
|
|
|
static COORD GetConsoleScreenSize(HANDLE outputHandle)
|
|
{
|
|
CONSOLE_SCREEN_BUFFER_INFOEX csbiex{};
|
|
csbiex.cbSize = sizeof(csbiex);
|
|
GetConsoleScreenBufferInfoEx(outputHandle, &csbiex);
|
|
return {
|
|
(csbiex.srWindow.Right - csbiex.srWindow.Left) + 1,
|
|
(csbiex.srWindow.Bottom - csbiex.srWindow.Top) + 1
|
|
};
|
|
}
|
|
|
|
static ConnectionState RunConnectionToCompletion(const ITerminalConnection& connection, HANDLE outputHandle, HANDLE inputHandle)
|
|
{
|
|
connection.TerminalOutput([outputHandle](const winrt::hstring& output) {
|
|
WriteConsoleW(outputHandle, output.data(), output.size(), nullptr, nullptr);
|
|
});
|
|
|
|
// Detach a thread to spin the console read indefinitely.
|
|
// This application exits when the connection is closed, so
|
|
// the connection's lifetime will outlast this thread.
|
|
std::thread([connection, outputHandle, inputHandle] {
|
|
ConsoleInputReader reader{ inputHandle };
|
|
reader.SetWindowSizeChangedCallback([&]() {
|
|
const auto size = GetConsoleScreenSize(outputHandle);
|
|
|
|
connection.Resize(size.Y, size.X);
|
|
});
|
|
|
|
while (true)
|
|
{
|
|
auto input = reader.Read();
|
|
if (input)
|
|
{
|
|
connection.WriteInput(*input);
|
|
}
|
|
}
|
|
}).detach();
|
|
|
|
std::condition_variable stateChangeVar;
|
|
std::optional<ConnectionState> state;
|
|
std::mutex stateMutex;
|
|
|
|
connection.StateChanged([&](auto&& /*s*/, auto&& /*e*/) {
|
|
std::unique_lock<std::mutex> lg{ stateMutex };
|
|
state = connection.State();
|
|
stateChangeVar.notify_all();
|
|
});
|
|
|
|
connection.Start();
|
|
|
|
std::unique_lock<std::mutex> lg{ stateMutex };
|
|
stateChangeVar.wait(lg, [&]() {
|
|
if (!state.has_value())
|
|
{
|
|
return false;
|
|
}
|
|
return state.value() == ConnectionState::Closed || state.value() == ConnectionState::Failed;
|
|
});
|
|
|
|
return state.value();
|
|
}
|
|
|
|
int wmain(int /*argc*/, wchar_t** /*argv*/)
|
|
{
|
|
winrt::init_apartment(winrt::apartment_type::single_threaded);
|
|
|
|
DWORD inputMode{}, outputMode{};
|
|
HANDLE conIn{ GetStdHandle(STD_INPUT_HANDLE) }, conOut{ GetStdHandle(STD_OUTPUT_HANDLE) };
|
|
UINT codepage{ GetConsoleCP() }, outputCodepage{ GetConsoleOutputCP() };
|
|
|
|
RETURN_IF_WIN32_BOOL_FALSE(GetConsoleMode(conIn, &inputMode));
|
|
RETURN_IF_WIN32_BOOL_FALSE(GetConsoleMode(conOut, &outputMode));
|
|
|
|
RETURN_IF_WIN32_BOOL_FALSE(SetConsoleMode(conIn, ENABLE_WINDOW_INPUT | ENABLE_VIRTUAL_TERMINAL_INPUT));
|
|
RETURN_IF_WIN32_BOOL_FALSE(SetConsoleMode(conOut, ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_WRAP_AT_EOL_OUTPUT | DISABLE_NEWLINE_AUTO_RETURN));
|
|
RETURN_IF_WIN32_BOOL_FALSE(SetConsoleCP(CP_UTF8));
|
|
RETURN_IF_WIN32_BOOL_FALSE(SetConsoleOutputCP(CP_UTF8));
|
|
|
|
auto restoreConsoleModes = wil::scope_exit([&]() {
|
|
SetConsoleMode(conIn, inputMode);
|
|
SetConsoleMode(conOut, outputMode);
|
|
SetConsoleCP(codepage);
|
|
SetConsoleOutputCP(outputCodepage);
|
|
});
|
|
|
|
const auto size = GetConsoleScreenSize(conOut);
|
|
|
|
AzureConnection azureConn{};
|
|
winrt::Windows::Foundation::Collections::ValueSet vs{};
|
|
vs.Insert(L"initialRows", winrt::Windows::Foundation::PropertyValue::CreateUInt32(gsl::narrow_cast<uint32_t>(size.Y)));
|
|
vs.Insert(L"initialCols", winrt::Windows::Foundation::PropertyValue::CreateUInt32(gsl::narrow_cast<uint32_t>(size.X)));
|
|
azureConn.Initialize(vs);
|
|
|
|
const auto state = RunConnectionToCompletion(azureConn, conOut, conIn);
|
|
|
|
return state == ConnectionState::Closed ? 0 : 1;
|
|
}
|