Compare commits

...

7 Commits

Author SHA1 Message Date
Dustin L. Howett
8a5d2ae730 fixup! Update for recent changes - ICoreScheme, new settings, ScopedResLoader, side-to-side wheel, AvoidBuggyTSFConsoleFlags 2026-04-29 00:13:27 -05:00
Dustin L. Howett
904eb9ec07 add MOUSEHWHEEL support 2026-04-29 00:09:01 -05:00
Dustin L. Howett
236038a110 Update for recent changes - ICoreScheme, new settings, ScopedResLoader, side-to-side wheel, AvoidBuggyTSFConsoleFlags 2026-04-29 00:06:49 -05:00
Dustin L. Howett
6525ceeb8f HAX to make it crash less 2026-04-29 00:06:00 -05:00
Dustin L. Howett
b8629c366b Squash of all other Win7WPF work 2026-04-29 00:05:59 -05:00
Dustin L. Howett
ba2b0af843 WpfTest: Add a more complicated test string 2026-04-29 00:05:27 -05:00
Dustin L. Howett
d1da3c06c6 Move AutoScroll down into Interactivity 2026-04-29 00:05:25 -05:00
23 changed files with 1175 additions and 245 deletions

View File

@@ -26,7 +26,7 @@
</PropertyGroup>
<PropertyGroup Condition="!Exists('CascadiaPackage_TemporaryKey.pfx')">
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled>
<AppxBundle>Never</AppxBundle>
<!--<AppxBundle>Never</AppxBundle>-->
</PropertyGroup>
<PropertyGroup Condition="Exists('CascadiaPackage_TemporaryKey.pfx')">
<AppxPackageSigningEnabled>true</AppxPackageSigningEnabled>

View File

@@ -78,6 +78,7 @@
<Project>{18D09A24-8240-42D6-8CB6-236EEE820263}</Project>
</ProjectReference>
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\WinRTUtils\WinRTUtils.vcxproj">
<Private>true</Private>
<Project>{CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>

View File

@@ -29,6 +29,7 @@
#include "winrt/Windows.Data.Json.h"
#include <Windows.h>
#include <wrl.h>
#include <winhttp.h>
#include <wil/resource.h>

View File

@@ -179,6 +179,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void ControlCore::_setupDispatcherAndCallbacks()
{
///* TODO(DH) */ return;
// Get our dispatcher. If we're hosted in-proc with XAML, this will get
// us the same dispatcher as TermControl::Dispatcher(). If we're out of
// proc, this'll return null. We'll need to instead make a new
@@ -433,12 +434,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_terminal->Create(viewportSize, Utils::ClampToShortMax(_settings.HistorySize(), 0), *_renderer);
_terminal->UpdateSettings(_settings);
// Tell the render engine to notify us when the swap chain changes.
// We do this after we initially set the swapchain so as to avoid
// unnecessary callbacks (and locking problems)
_renderEngine->SetCallback([this](HANDLE handle) {
_renderEngineSwapChainChanged(handle);
});
if (_hookup == HookupMode::ForComposition)
{
// Tell the render engine to notify us when the swap chain changes.
// We do this after we initially set the swapchain so as to avoid
// unnecessary callbacks (and locking problems)
_renderEngine->SetCallback([this](HANDLE handle) {
_renderEngineSwapChainChanged(handle);
});
}
_renderEngine->SetRetroTerminalEffect(_settings.RetroTerminalEffect());
_renderEngine->SetPixelShaderPath(_settings.PixelShaderPath());
@@ -459,6 +463,23 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return true;
}
bool ControlCore::InitializeWithHwnd(const float actualWidth,
const float actualHeight,
const float compositionScale,
const uint64_t hwnd)
{
_owningHwnd = hwnd;
_hookup = HookupMode::ForHwnd;
auto i = Initialize(actualWidth, actualHeight, compositionScale);
if (i)
{
auto lock = _terminal->LockForWriting();
(void)_renderEngine->SetHwnd(reinterpret_cast<HWND>(hwnd));
}
return i;
}
// Method Description:
// - Tell the renderer to start painting.
// - !! IMPORTANT !! Make sure that we've attached our swap chain to an
@@ -1959,7 +1980,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
RendererWarning.raise(*this, winrt::make<RendererWarningArgs>(hr, winrt::hstring{ parameter }));
}
safe_void_coroutine ControlCore::_renderEngineSwapChainChanged(const HANDLE sourceHandle)
/* TODO(DH) */ void ControlCore::_renderEngineSwapChainChanged(const HANDLE sourceHandle)
{
// `sourceHandle` is a weak ref to a HANDLE that's ultimately owned by the
// render engine's own unique_handle. We'll add another ref to it here.
@@ -1977,7 +1998,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Concurrent read of _dispatcher is safe, because Detach() calls TriggerTeardown()
// which blocks until this call returns. _dispatcher will only be changed afterwards.
co_await wil::resume_foreground(_dispatcher);
// TODO(DH) co_await wil::resume_foreground(_dispatcher);
if (auto core{ weakThis.get() })
{
@@ -2941,4 +2962,39 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
_terminal->PreviewText(input);
}
ControlCore::TimerHandle ControlCore::RegisterTimer(const char* name, std::function<void()> callback)
{
return _renderer->RegisterTimer(name, [cb = std::move(callback)](auto&&, auto&&) {
cb();
});
}
bool ControlCore::IsTimerRunning(TimerHandle h)
{
return _renderer->IsTimerRunning(h);
}
void ControlCore::StartRepeatingTimer(TimerHandle h, uint64_t micros)
{
_renderer->StartRepeatingTimer(h, std::chrono::microseconds(micros));
}
void ControlCore::StopTimer(TimerHandle h)
{
_renderer->StopTimer(h);
}
winrt::Windows::Foundation::Size ControlCore::RenderedSize()
{
return { _panelWidth, _panelHeight };
}
void ControlCore::ResizeToDimensions(uint32_t width, uint32_t height, winrt::Windows::Foundation::Size& newSizeInPixels)
{
if (!_renderEngine)
{
throw winrt::hresult_error(E_INVALIDARG);
}
auto pixelSize = _renderEngine->GetViewportInPixels(Viewport::FromDimensions({ 0, 0 }, til::size{ static_cast<til::CoordType>(width), static_cast<til::CoordType>(height) }));
SizeOrScaleChanged(static_cast<float>(pixelSize.Width()), static_cast<float>(pixelSize.Height()), _compositionScale);
newSizeInPixels = RenderedSize();
}
}

View File

@@ -24,6 +24,8 @@
#include "../../cascadia/TerminalCore/Terminal.hpp"
#include "../../renderer/inc/FontInfoDesired.hpp"
#include <functional>
namespace Microsoft::Console::Render::Atlas
{
class AtlasEngine;
@@ -78,6 +80,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
struct ControlCore : ControlCoreT<ControlCore>
{
private:
enum class HookupMode
{
ForHwnd = 0x0,
ForComposition = 0x1,
};
public:
ControlCore(Control::IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
@@ -87,6 +95,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool Initialize(const float actualWidth,
const float actualHeight,
const float compositionScale);
bool InitializeWithHwnd(const float actualWidth,
const float actualHeight,
const float compositionScale,
const uint64_t hwnd);
void EnablePainting();
void Detach();
@@ -262,8 +274,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool ShouldShowSelectCommand();
bool ShouldShowSelectOutput();
winrt::Windows::Foundation::Size RenderedSize();
void ResizeToDimensions(uint32_t width, uint32_t height, winrt::Windows::Foundation::Size& newSizeInPixels);
void PreviewInput(std::wstring_view input);
using TimerHandle = ::Microsoft::Console::Render::TimerHandle;
TimerHandle RegisterTimer(const char* name, std::function<void()> callback);
bool IsTimerRunning(TimerHandle h);
void StartRepeatingTimer(TimerHandle h, uint64_t micros);
void StopTimer(TimerHandle h);
RUNTIME_SETTING(float, Opacity, _settings.Opacity());
RUNTIME_SETTING(float, FocusedOpacity, FocusedAppearance().Opacity());
RUNTIME_SETTING(bool, UseAcrylic, _settings.UseAcrylic());
@@ -340,7 +361,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
#pragma region RendererCallbacks
void _rendererWarning(const HRESULT hr, wil::zwstring_view parameter);
safe_void_coroutine _renderEngineSwapChainChanged(const HANDLE handle);
/* TODO(DH) */ void _renderEngineSwapChainChanged(const HANDLE handle);
void _rendererBackgroundColorChanged();
void _rendererTabColorChanged();
void _rendererEnteredErrorState();
@@ -375,7 +396,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
//
// Though, the unit tests don't actually run in TAEF's main
// thread, so we don't care when we're running in tests.
assert(_inUnitTests || _dispatcher.HasThreadAccess());
assert(_hookup == HookupMode::ForHwnd || _inUnitTests || _dispatcher.HasThreadAccess());
}
#endif
return _closing;
@@ -421,6 +442,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
std::atomic<bool> _initializedTerminal{ false };
bool _isReadOnly{ false };
bool _closing{ false };
HookupMode _hookup{ HookupMode::ForComposition };
struct StashedColorScheme
{

View File

@@ -93,6 +93,9 @@ namespace Microsoft.Terminal.Control
Boolean Initialize(Single actualWidth,
Single actualHeight,
Single compositionScale);
Boolean InitializeWithHwnd(Single actualWidth,
Single actualHeight,
Single compositionScale, UInt64 hwnd);
void UpdateSettings(IControlSettings settings, IControlAppearance appearance);
void ApplyAppearance(Boolean focused);
@@ -184,6 +187,9 @@ namespace Microsoft.Terminal.Control
Boolean ShouldShowSelectCommand();
Boolean ShouldShowSelectOutput();
Windows.Foundation.Size RenderedSize { get; };
void ResizeToDimensions(UInt32 width, UInt32 height, out Windows.Foundation.Size newSizeInPixels);
void OpenCWD();
void ClearQuickFix();

View File

@@ -68,6 +68,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
});
_createInteractivityTimers();
}
uint64_t ControlInteractivity::Id()
@@ -94,12 +96,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
LOG_IF_FAILED(_uiaEngine->Disable());
_core->DetachUiaEngine(_uiaEngine.get());
}
_destroyInteractivityTimers();
_core->Detach();
}
void ControlInteractivity::AttachToNewControl()
{
_core->AttachToNewControl();
//_createInteractivityTimers();
}
// Method Description:
@@ -131,12 +135,31 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void ControlInteractivity::Close()
{
Closed.raise(*this, nullptr);
_destroyInteractivityTimers();
if (_core)
{
_core->Close();
}
}
void ControlInteractivity::_createInteractivityTimers()
{
_autoScrollTimer = _core->RegisterTimer("autoscroll", [weak = get_weak()]() {
if (auto strong = weak.get())
{
strong->_updateAutoScroll();
}
});
}
void ControlInteractivity::_destroyInteractivityTimers()
{
if (_autoScrollTimer)
{
_core->StopTimer(_autoScrollTimer);
}
}
// Method Description:
// - Returns the number of clicks that occurred (double and triple click support).
// Every call to this function registers a click.
@@ -369,7 +392,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_touchAnchor = contactPoint;
}
bool ControlInteractivity::PointerMoved(const uint32_t /*pointerId*/,
bool ControlInteractivity::PointerMoved(const uint32_t pointerId,
Control::MouseButtonState buttonState,
const unsigned int pointerUpdateKind,
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
@@ -429,6 +452,40 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
SetEndSelectionPoint(pixelPosition);
// GH#9109 - Only start an auto-scroll when the drag actually
// started within our bounds. Otherwise, someone could start a drag
// outside the terminal control, drag into the padding, and trick us
// into starting to scroll.
{
// We want to find the distance relative to the bounds of the
// SwapChainPanel, not the entire control. If they drag out of
// the bounds of the text, into the padding, we still what that
// to auto-scroll
const auto height = _core->ViewHeight() * _core->FontSize().Height;
const auto cursorBelowBottomDist = pixelPosition.Y - height;
const auto cursorAboveTopDist = -1 * pixelPosition.Y;
constexpr auto MinAutoScrollDist = 2.0; // Arbitrary value
auto newAutoScrollVelocity = 0.0;
if (cursorBelowBottomDist > MinAutoScrollDist)
{
newAutoScrollVelocity = _getAutoScrollSpeed(cursorBelowBottomDist);
}
else if (cursorAboveTopDist > MinAutoScrollDist)
{
newAutoScrollVelocity = -1.0 * _getAutoScrollSpeed(cursorAboveTopDist);
}
if (newAutoScrollVelocity != 0)
{
_tryStartAutoScroll(pointerId, pixelPosition, newAutoScrollVelocity);
}
else
{
_tryStopAutoScroll(pointerId);
}
}
}
_core->SetHoveredCell(terminalPosition.to_core_point());
@@ -471,7 +528,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
void ControlInteractivity::PointerReleased(const uint32_t /*pointerId*/,
void ControlInteractivity::PointerReleased(const uint32_t pointerId,
Control::MouseButtonState buttonState,
const unsigned int pointerUpdateKind,
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
@@ -502,6 +559,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
_singleClickTouchdownPos = std::nullopt;
_tryStopAutoScroll(pointerId);
}
void ControlInteractivity::TouchReleased()
@@ -797,4 +855,97 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
return _core->GetRenderData();
}
// Method Description:
// - Calculates speed of single axis of auto scrolling. It has to allow for both
// fast and precise selection.
// Arguments:
// - cursorDistanceFromBorder: distance from viewport border to cursor, in pixels. Must be non-negative.
// Return Value:
// - positive speed in characters / sec
double ControlInteractivity::_getAutoScrollSpeed(double cursorDistanceFromBorder) const
{
// The numbers below just feel well, feel free to change.
// TODO: Maybe account for space beyond border that user has available
return std::pow(cursorDistanceFromBorder, 2.0) / 25.0 + 2.0;
}
// Method Description:
// - Starts new pointer related auto scroll behavior, or continues existing one.
// Does nothing when there is already auto scroll associated with another pointer.
// Arguments:
// - pointerId, point: info about pointer that causes auto scroll. Pointer's position
// is later used to update selection.
// - scrollVelocity: target velocity of scrolling in characters / sec
void ControlInteractivity::_tryStartAutoScroll(const uint32_t pointerId, const Core::Point& point, const double scrollVelocity)
{
// Allow only one pointer at the time
if (!_autoScrollingPointerId ||
_autoScrollingPointerId == pointerId)
{
_autoScrollingPointerId = pointerId;
_autoScrollingPointerPoint = point;
_autoScrollVelocity = scrollVelocity;
// If this is first time the auto scroll update is about to be called,
// kick-start it by initializing its time delta as if it started now
if (!_lastAutoScrollUpdateTime)
{
_lastAutoScrollUpdateTime = std::chrono::high_resolution_clock::now();
}
// Apparently this check is not necessary but greatly improves performance
if (!_core->IsTimerRunning(_autoScrollTimer))
{
static constexpr auto AutoScrollUpdateInterval = std::chrono::microseconds(static_cast<int>(1.0 / 30.0 * 1000000));
_core->StartRepeatingTimer(_autoScrollTimer, AutoScrollUpdateInterval.count());
}
}
}
// Method Description:
// - Stops auto scroll if it's active and is associated with supplied pointer id.
// Arguments:
// - pointerId: id of pointer for which to stop auto scroll
void ControlInteractivity::_tryStopAutoScroll(const uint32_t pointerId)
{
if (_autoScrollingPointerId &&
pointerId == _autoScrollingPointerId)
{
_autoScrollingPointerId = std::nullopt;
_autoScrollingPointerPoint = std::nullopt;
_autoScrollVelocity = 0;
_lastAutoScrollUpdateTime = std::nullopt;
// Apparently this check is not necessary but greatly improves performance
_core->StopTimer(_autoScrollTimer);
}
}
// Method Description:
// - Called continuously to gradually scroll viewport when user is mouse
// selecting outside it (to 'follow' the cursor).
// Arguments:
// - none
void ControlInteractivity::_updateAutoScroll()
{
if (_autoScrollVelocity != 0)
{
const auto timeNow = std::chrono::high_resolution_clock::now();
if (_lastAutoScrollUpdateTime)
{
static constexpr auto microSecPerSec = 1000000.0;
const auto deltaTime = std::chrono::duration_cast<std::chrono::microseconds>(timeNow - *_lastAutoScrollUpdateTime).count() / microSecPerSec;
UpdateScrollbar(static_cast<float>(_core->ScrollOffset()) + static_cast<float>(_autoScrollVelocity * deltaTime) /* TODO(DH) */);
if (_autoScrollingPointerPoint)
{
SetEndSelectionPoint(*_autoScrollingPointerPoint);
}
}
_lastAutoScrollUpdateTime = timeNow;
}
}
}

View File

@@ -143,8 +143,24 @@ namespace winrt::Microsoft::Terminal::Control::implementation
static std::atomic<uint64_t> _nextId;
bool _focused{ false };
// Auto scroll occurs when user, while selecting, drags cursor outside
// viewport. View is then scrolled to 'follow' the cursor.
double _autoScrollVelocity;
std::optional<uint32_t> _autoScrollingPointerId;
std::optional<Core::Point> _autoScrollingPointerPoint;
ControlCore::TimerHandle _autoScrollTimer;
std::optional<std::chrono::high_resolution_clock::time_point> _lastAutoScrollUpdateTime;
bool _pointerPressedInBounds{ false };
void _tryStartAutoScroll(const uint32_t id, const Core::Point& point, const double scrollVelocity);
void _tryStopAutoScroll(const uint32_t pointerId);
void _updateAutoScroll();
double _getAutoScrollSpeed(double cursorDistanceFromBorder) const;
void _createInteractivityTimers();
void _destroyInteractivityTimers();
unsigned int _numberOfClicks(Core::Point clickPos, Timestamp clickTime);
void _updateSystemParameterSettings() noexcept;

View File

@@ -0,0 +1,641 @@
#include "pch.h"
#include "FlatC.h"
#include "winrt/Microsoft.Terminal.Control.h"
#include "winrt/Microsoft.Terminal.Core.h"
#include "../TerminalCore/ControlKeyStates.hpp"
#include "../types/inc/colorTable.hpp"
#include "../inc/DefaultSettings.h"
#include "../inc/cppwinrt_utils.h"
#include "../../tsf/Handle.h"
#include "ControlCore.h"
#include "ControlInteractivity.h"
#include <windowsx.h>
#pragma warning(disable : 4100)
#define HARDCODED_PROPERTY(type, name, ...) \
type name() const \
{ \
return type{ __VA_ARGS__ }; \
} \
void name(const type&) \
{ \
}
using namespace winrt::Microsoft::Terminal::Control;
using namespace winrt::Microsoft::Terminal::Core;
using CKS = ::Microsoft::Terminal::Core::ControlKeyStates;
static CKS getControlKeyState() noexcept
{
struct KeyModifier
{
int vkey;
CKS flags;
};
constexpr std::array<KeyModifier, 5> modifiers{ {
{ VK_RMENU, CKS::RightAltPressed },
{ VK_LMENU, CKS::LeftAltPressed },
{ VK_RCONTROL, CKS::RightCtrlPressed },
{ VK_LCONTROL, CKS::LeftCtrlPressed },
{ VK_SHIFT, CKS::ShiftPressed },
} };
CKS flags;
for (const auto& mod : modifiers)
{
const auto state = GetKeyState(mod.vkey);
const auto isDown = state < 0;
if (isDown)
{
flags |= mod.flags;
}
}
return flags;
}
static MouseButtonState MouseButtonStateFromWParam(WPARAM wParam)
{
MouseButtonState state{};
WI_UpdateFlag(state, MouseButtonState::IsLeftButtonDown, WI_IsFlagSet(wParam, MK_LBUTTON));
WI_UpdateFlag(state, MouseButtonState::IsMiddleButtonDown, WI_IsFlagSet(wParam, MK_MBUTTON));
WI_UpdateFlag(state, MouseButtonState::IsRightButtonDown, WI_IsFlagSet(wParam, MK_RBUTTON));
return state;
}
static Point PointFromLParam(LPARAM lParam)
{
return { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
}
struct CsBridgeConnection : public winrt::implements<CsBridgeConnection, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection>
{
void Initialize(IInspectable x) {}
void Start() {}
void WriteInput(winrt::array_view<const char16_t> d)
{
if (_pfnWriteCallback)
{
_pfnWriteCallback(reinterpret_cast<const wchar_t*>(d.data()));
}
}
void Resize(uint32_t r, uint32_t c) {}
void Close() {}
winrt::Microsoft::Terminal::TerminalConnection::ConnectionState State() const noexcept { return winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::Connected; }
WINRT_CALLBACK(TerminalOutput, winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler);
TYPED_EVENT(StateChanged, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection, winrt::Windows::Foundation::IInspectable);
public:
HARDCODED_PROPERTY(winrt::guid, SessionId, winrt::guid{});
public:
PWRITECB _pfnWriteCallback{ nullptr };
void OriginateOutputFromConnection(const wchar_t* data)
{
std::wstring_view wsv{ data };
_TerminalOutputHandlers(winrt::array_view<const char16_t>(reinterpret_cast<const char16_t*>(wsv.data()), static_cast<uint32_t>(wsv.size())));
}
};
struct CsBridgeTerminalSettings : winrt::implements<CsBridgeTerminalSettings, IControlSettings, ICoreSettings, IControlAppearance, ICoreAppearance, ICoreScheme>
{
using IFontAxesMap = winrt::Windows::Foundation::Collections::IMap<winrt::hstring, float>;
using IFontFeatureMap = winrt::Windows::Foundation::Collections::IMap<winrt::hstring, float>;
CsBridgeTerminalSettings()
{
const auto campbellSpan = Microsoft::Console::Utils::CampbellColorTable();
std::transform(campbellSpan.begin(), campbellSpan.end(), std::begin(_theme.ColorTable), [](auto&& color) {
return color;
});
}
~CsBridgeTerminalSettings() = default;
void GetColorTable(winrt::com_array<::winrt::Microsoft::Terminal::Core::Color>& table) noexcept
{
std::array<winrt::Microsoft::Terminal::Core::Color, COLOR_TABLE_SIZE> colorTable{};
std::transform(&_theme.ColorTable[0], &_theme.ColorTable[16], colorTable.begin(), [](auto&& color) {
return static_cast<winrt::Microsoft::Terminal::Core::Color>(til::color{ color });
});
table = winrt::com_array(colorTable.begin(), colorTable.end());
}
til::color DefaultForeground() const
{
return _theme.DefaultForeground;
}
til::color DefaultBackground() const
{
return _theme.DefaultBackground;
}
til::color SelectionBackground() const
{
return til::color{ _theme.DefaultSelectionBackground };
}
winrt::hstring FontFace() const
{
return _fontFace;
}
float FontSize() const
{
return _fontSize;
}
winrt::Microsoft::Terminal::Core::CursorStyle CursorShape() const
{
return static_cast<winrt::Microsoft::Terminal::Core::CursorStyle>(_theme.CursorStyle);
}
void DefaultForeground(const til::color&) {}
void DefaultBackground(const til::color&) {}
void SelectionBackground(const til::color&) {}
void FontFace(const winrt::hstring&) {}
void FontSize(const float&) {}
void CursorShape(const winrt::Microsoft::Terminal::Core::CursorStyle&) {}
HARDCODED_PROPERTY(int32_t, HistorySize, DEFAULT_HISTORY_SIZE);
HARDCODED_PROPERTY(int32_t, InitialRows, 30);
HARDCODED_PROPERTY(int32_t, InitialCols, 80);
HARDCODED_PROPERTY(bool, SnapOnInput, true);
HARDCODED_PROPERTY(bool, AltGrAliasing, true);
HARDCODED_PROPERTY(til::color, CursorColor, DEFAULT_CURSOR_COLOR);
HARDCODED_PROPERTY(uint32_t, CursorHeight, DEFAULT_CURSOR_HEIGHT);
HARDCODED_PROPERTY(winrt::hstring, WordDelimiters, DEFAULT_WORD_DELIMITERS);
HARDCODED_PROPERTY(bool, CopyOnSelect, false);
HARDCODED_PROPERTY(bool, InputServiceWarning, true);
HARDCODED_PROPERTY(bool, FocusFollowMouse, false);
HARDCODED_PROPERTY(bool, TrimBlockSelection, false);
HARDCODED_PROPERTY(bool, DetectURLs, true);
HARDCODED_PROPERTY(winrt::Windows::Foundation::IReference<winrt::Microsoft::Terminal::Core::Color>, TabColor, nullptr);
HARDCODED_PROPERTY(winrt::Windows::Foundation::IReference<winrt::Microsoft::Terminal::Core::Color>, StartingTabColor, nullptr);
HARDCODED_PROPERTY(bool, UseAcrylic, false);
HARDCODED_PROPERTY(float, Opacity, 1.0);
HARDCODED_PROPERTY(winrt::hstring, Padding, DEFAULT_PADDING);
HARDCODED_PROPERTY(winrt::Windows::UI::Text::FontWeight, FontWeight, winrt::Windows::UI::Text::FontWeight{ 400 });
HARDCODED_PROPERTY(IFontAxesMap, FontAxes);
HARDCODED_PROPERTY(IFontFeatureMap, FontFeatures);
HARDCODED_PROPERTY(winrt::hstring, BackgroundImage);
HARDCODED_PROPERTY(float, BackgroundImageOpacity, 1.0);
HARDCODED_PROPERTY(winrt::Windows::UI::Xaml::Media::Stretch, BackgroundImageStretchMode, winrt::Windows::UI::Xaml::Media::Stretch::UniformToFill);
HARDCODED_PROPERTY(winrt::Windows::UI::Xaml::HorizontalAlignment, BackgroundImageHorizontalAlignment, winrt::Windows::UI::Xaml::HorizontalAlignment::Center);
HARDCODED_PROPERTY(winrt::Windows::UI::Xaml::VerticalAlignment, BackgroundImageVerticalAlignment, winrt::Windows::UI::Xaml::VerticalAlignment::Center);
HARDCODED_PROPERTY(winrt::hstring, Commandline);
HARDCODED_PROPERTY(winrt::hstring, StartingDirectory);
HARDCODED_PROPERTY(winrt::hstring, StartingTitle);
HARDCODED_PROPERTY(bool, SuppressApplicationTitle);
HARDCODED_PROPERTY(winrt::hstring, EnvironmentVariables);
HARDCODED_PROPERTY(winrt::Microsoft::Terminal::Control::ScrollbarState, ScrollState, winrt::Microsoft::Terminal::Control::ScrollbarState::Visible);
HARDCODED_PROPERTY(winrt::Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, winrt::Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale);
HARDCODED_PROPERTY(bool, RetroTerminalEffect, false);
HARDCODED_PROPERTY(bool, ForceFullRepaintRendering, false);
HARDCODED_PROPERTY(bool, SoftwareRendering, false);
HARDCODED_PROPERTY(bool, ForceVTInput, false);
HARDCODED_PROPERTY(winrt::hstring, PixelShaderPath);
HARDCODED_PROPERTY(winrt::hstring, PixelShaderImagePath);
HARDCODED_PROPERTY(bool, IntenseIsBright);
HARDCODED_PROPERTY(bool, IntenseIsBold);
HARDCODED_PROPERTY(bool, ShowMarks);
HARDCODED_PROPERTY(bool, UseBackgroundImageForWindow);
HARDCODED_PROPERTY(bool, AutoMarkPrompts);
HARDCODED_PROPERTY(bool, VtPassthrough);
HARDCODED_PROPERTY(bool, UseAtlasEngine, false);
HARDCODED_PROPERTY(AdjustTextMode, AdjustIndistinguishableColors, AdjustTextMode::Never);
HARDCODED_PROPERTY(bool, RightClickContextMenu, false);
HARDCODED_PROPERTY(winrt::hstring, CellWidth, L"");
HARDCODED_PROPERTY(winrt::hstring, CellHeight, L"");
HARDCODED_PROPERTY(bool, RepositionCursorWithMouse, false);
HARDCODED_PROPERTY(bool, EnableUnfocusedAcrylic, false);
HARDCODED_PROPERTY(bool, RainbowSuggestions, false);
HARDCODED_PROPERTY(bool, AllowVtClipboardWrite, true);
HARDCODED_PROPERTY(bool, AllowVtChecksumReport, false);
HARDCODED_PROPERTY(winrt::hstring, AnswerbackMessage, L"");
HARDCODED_PROPERTY(winrt::Microsoft::Terminal::Control::PathTranslationStyle, PathTranslationStyle, winrt::Microsoft::Terminal::Control::PathTranslationStyle::None);
HARDCODED_PROPERTY(winrt::Microsoft::Terminal::Control::DefaultInputScope, DefaultInputScope, winrt::Microsoft::Terminal::Control::DefaultInputScope::Default);
HARDCODED_PROPERTY(winrt::Microsoft::Terminal::Control::TextMeasurement, TextMeasurement, winrt::Microsoft::Terminal::Control::TextMeasurement::Graphemes);
HARDCODED_PROPERTY(bool, DisablePartialInvalidation, false);
HARDCODED_PROPERTY(winrt::Microsoft::Terminal::Control::GraphicsAPI, GraphicsAPI, winrt::Microsoft::Terminal::Control::GraphicsAPI::Automatic);
HARDCODED_PROPERTY(winrt::Microsoft::Terminal::Control::CopyFormat, CopyFormatting, winrt::Microsoft::Terminal::Control::CopyFormat::All);
HARDCODED_PROPERTY(bool, EnableColorGlyphs, true);
HARDCODED_PROPERTY(bool, EnableBuiltinGlyphs, true);
HARDCODED_PROPERTY(bool, AllowKittyKeyboardMode, true);
HARDCODED_PROPERTY(winrt::hstring, DragDropDelimiter, L" ");
HARDCODED_PROPERTY(winrt::Microsoft::Terminal::Control::AmbiguousWidth, AmbiguousWidth, winrt::Microsoft::Terminal::Control::AmbiguousWidth::Narrow);
HARDCODED_PROPERTY(bool, ScrollToChangeOpacity, false);
HARDCODED_PROPERTY(bool, ScrollToZoom, false);
HARDCODED_PROPERTY(winrt::guid, SessionId, winrt::guid{});
public:
void SetTheme(TerminalTheme theme, LPCWSTR fontFamily, til::CoordType fontSize, int newDpi)
{
_theme = std::move(theme);
_fontFace = fontFamily;
_fontSize = static_cast<float>(fontSize);
}
private:
TerminalTheme _theme;
winrt::hstring _fontFace{ L"Cascadia Mono" };
float _fontSize = 12.0f;
};
struct HwndTerminal
{
static constexpr LPCWSTR term_window_class = L"HwndTerminalClass";
static LRESULT CALLBACK HwndTerminalWndProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam) noexcept
try
{
#pragma warning(suppress : 26490) // Win32 APIs can only store void*, have to use reinterpret_cast
HwndTerminal* terminal = reinterpret_cast<HwndTerminal*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
if (terminal)
{
return terminal->WindowProc(hwnd, uMsg, wParam, lParam);
}
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
return 0;
}
static bool RegisterTermClass(HINSTANCE hInstance) noexcept
{
WNDCLASSW wc;
if (GetClassInfoW(hInstance, term_window_class, &wc))
{
return true;
}
wc.style = 0;
wc.lpfnWndProc = HwndTerminal::HwndTerminalWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = nullptr;
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hbrBackground = nullptr;
wc.lpszMenuName = nullptr;
wc.lpszClassName = term_window_class;
return RegisterClassW(&wc) != 0;
}
LRESULT WindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam) noexcept
{
switch (uMsg)
{
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
SetCapture(_hwnd.get());
_interactivity->PointerPressed(
0, // Mouse
MouseButtonStateFromWParam(wParam),
uMsg,
std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count(),
getControlKeyState(),
PointFromLParam(lParam));
return 0;
case WM_MOUSEMOVE:
_interactivity->PointerMoved(
0, // Mouse
MouseButtonStateFromWParam(wParam),
WM_MOUSEMOVE,
getControlKeyState(),
PointFromLParam(lParam));
return 0;
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
_interactivity->PointerReleased(
0, // Mouse
MouseButtonStateFromWParam(wParam),
uMsg,
getControlKeyState(),
PointFromLParam(lParam));
ReleaseCapture();
return 0;
case WM_POINTERDOWN:
if (!IS_POINTER_INCONTACT_WPARAM(wParam))
{
break;
}
SetCapture(_hwnd.get());
_interactivity->TouchPressed(PointFromLParam(lParam));
return 0;
case WM_POINTERUPDATE:
if (!IS_POINTER_INCONTACT_WPARAM(wParam))
{
break;
}
_interactivity->TouchMoved(PointFromLParam(lParam));
return 0;
case WM_POINTERUP:
if (!IS_POINTER_INCONTACT_WPARAM(wParam))
{
break;
}
_interactivity->TouchReleased();
ReleaseCapture();
return 0;
case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL:
{
winrt::Microsoft::Terminal::Core::Point delta{ 0, GET_WHEEL_DELTA_WPARAM(wParam) };
if (uMsg == WM_MOUSEHWHEEL)
{
std::swap(delta.X, delta.Y);
}
if (_interactivity->MouseWheel(getControlKeyState(), delta, PointFromLParam(lParam), MouseButtonStateFromWParam(wParam)))
{
return 0;
}
break;
}
case WM_SETFOCUS:
_interactivity->GotFocus();
_focused = true;
_core->ApplyAppearance(_focused);
break;
case WM_KILLFOCUS:
_interactivity->LostFocus();
_focused = true;
_core->ApplyAppearance(_focused);
break;
}
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
wil::unique_hwnd _hwnd;
HwndTerminal(HWND parentHwnd)
{
HINSTANCE hInstance = wil::GetModuleInstanceHandle();
if (RegisterTermClass(hInstance))
{
_hwnd.reset(CreateWindowExW(
0,
term_window_class,
nullptr,
WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE,
0,
0,
0,
0,
parentHwnd,
nullptr,
hInstance,
nullptr));
#pragma warning(suppress : 26490) // Win32 APIs can only store void*, so we have to use reinterpret_cast
SetWindowLongPtr(_hwnd.get(), GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
}
_settingsBridge = winrt::make_self<CsBridgeTerminalSettings>();
_connection = winrt::make_self<CsBridgeConnection>();
_interactivity = winrt::make_self<implementation::ControlInteractivity>(*_settingsBridge, nullptr, *_connection);
_core.copy_from(winrt::get_self<implementation::ControlCore>(_interactivity->Core()));
_core->ScrollPositionChanged({ this, &HwndTerminal::_scrollPositionChanged });
_interactivity->ScrollPositionChanged({ this, &HwndTerminal::_scrollPositionChanged });
}
/*( PUBLIC API )*/
HRESULT SendOutput(LPCWSTR data)
{
_connection->OriginateOutputFromConnection(data);
return S_OK;
}
HRESULT RegisterScrollCallback(PSCROLLCB callback)
{
_scrollCallback = callback;
return S_OK;
}
HRESULT TriggerResize(_In_ til::CoordType width, _In_ til::CoordType height, _Out_ til::size* dimensions)
{
if (!_initialized)
return S_FALSE;
SetWindowPos(_hwnd.get(), nullptr, 0, 0, width, height, 0);
// **NOTE** The sizes we get here are unscaled ...
auto dpi = GetDpiForWindow(_hwnd.get());
float w = static_cast<float>(width * USER_DEFAULT_SCREEN_DPI) / dpi;
float h = static_cast<float>(height * USER_DEFAULT_SCREEN_DPI) / dpi;
// ... but ControlCore expects scaled sizes.
_core->SizeChanged(w, h);
// TODO(DH): ControlCore has no API that returns the new size in cells
//wil::assign_to_opt_param(dimensions, /*thing*/);
return S_OK;
}
HRESULT TriggerResizeWithDimension(_In_ til::size dimensions, _Out_ til::size* dimensionsInPixels)
{
if (!_initialized)
return S_FALSE;
winrt::Windows::Foundation::Size outSizeInPixels;
_core->ResizeToDimensions(dimensions.width, dimensions.height, outSizeInPixels);
wil::assign_to_opt_param(dimensionsInPixels, til::size{ til::math::rounding, outSizeInPixels });
return S_OK;
}
HRESULT CalculateResize(_In_ til::CoordType width, _In_ til::CoordType height, _Out_ til::size* dimensions)
{
// TODO(DH): It seems weird to have to do this manually.
auto fontSizeInPx = _core->FontSize();
wil::assign_to_opt_param(dimensions, til::size{
static_cast<til::CoordType>(width / fontSizeInPx.Width),
static_cast<til::CoordType>(height / fontSizeInPx.Height),
});
return S_OK;
}
HRESULT DpiChanged(int newDpi)
{
_core->ScaleChanged((float)newDpi / 96.0f);
return S_OK;
}
HRESULT UserScroll(int viewTop)
{
_interactivity->UpdateScrollbar(static_cast<float>(viewTop) /* TODO(DH) */);
return S_OK;
}
HRESULT GetSelection(const wchar_t** out)
{
auto strings = _core->SelectedText(true);
auto concatenated = std::accumulate(std::begin(strings), std::end(strings), std::wstring{}, [](auto&& l, auto&& r) {
return l + r;
});
auto returnText = wil::make_cotaskmem_string_nothrow(concatenated.c_str());
*out = returnText.release();
return S_OK;
}
HRESULT IsSelectionActive(bool* out)
{
*out = _core->HasSelection();
return S_OK;
}
HRESULT SetTheme(TerminalTheme theme, LPCWSTR fontFamily, til::CoordType fontSize, int newDpi)
{
_settingsBridge->SetTheme(theme, fontFamily, fontSize, newDpi);
_core->UpdateSettings(*_settingsBridge, nullptr);
_interactivity->UpdateSettings();
_core->ScaleChanged((static_cast<float>(newDpi) / USER_DEFAULT_SCREEN_DPI));
_core->ApplyAppearance(_focused);
return S_OK;
}
HRESULT RegisterWriteCallback(PWRITECB callback)
{
_connection->_pfnWriteCallback = callback;
return S_OK;
}
HRESULT SendKeyEvent(WORD vkey, WORD scanCode, WORD flags, bool keyDown)
{
_core->TrySendKeyEvent(vkey, scanCode, getControlKeyState(), keyDown);
return S_OK;
}
HRESULT SendCharEvent(wchar_t ch, WORD flags, WORD scanCode)
{
_core->SendCharEvent(ch, scanCode, getControlKeyState());
return S_OK;
}
void Initialize()
{
RECT windowRect;
GetWindowRect(_hwnd.get(), &windowRect);
auto dpi = GetDpiForWindow(_hwnd.get());
// BODGY: the +/-1 is because ControlCore will ignore an Initialize with zero size (oops)
// because in the old days, TermControl would accidentally try to resize the Swap Chain to 0x0 (oops)
// and therefore resize the connection to 0x0 (oops)
_core->InitializeWithHwnd(
gsl::narrow_cast<float>(windowRect.right - windowRect.left + 1),
gsl::narrow_cast<float>(windowRect.bottom - windowRect.top + 1),
(static_cast<float>(dpi) / USER_DEFAULT_SCREEN_DPI),
reinterpret_cast<uint64_t>(_hwnd.get()));
_interactivity->Initialize();
_core->ApplyAppearance(_focused);
_core->EnablePainting();
_initialized = true;
}
private:
winrt::com_ptr<CsBridgeConnection> _connection;
winrt::com_ptr<CsBridgeTerminalSettings> _settingsBridge;
winrt::com_ptr<implementation::ControlInteractivity> _interactivity{ nullptr };
winrt::com_ptr<implementation::ControlCore> _core{ nullptr };
bool _initialized{ false };
bool _focused{ false };
PSCROLLCB _scrollCallback{};
void _scrollPositionChanged(const winrt::Windows::Foundation::IInspectable& i, const ScrollPositionChangedArgs& update)
{
if (_scrollCallback)
{
_scrollCallback(update.ViewTop(), update.ViewHeight(), update.BufferSize());
}
}
};
extern "C" void _stdcall AvoidBuggyTSFConsoleFlags()
{
Microsoft::Console::TSF::Handle::AvoidBuggyTSFConsoleFlags();
}
__declspec(dllexport) HRESULT _stdcall CreateTerminal(HWND parentHwnd, _Out_ void** hwnd, _Out_ PTERM* terminal)
{
auto inner = new HwndTerminal{ parentHwnd };
*terminal = inner;
*hwnd = inner->_hwnd.get();
inner->Initialize();
return S_OK;
}
__declspec(dllexport) void _stdcall DestroyTerminal(PTERM terminal)
{
delete (HwndTerminal*)terminal;
}
// Generate all of the C->C++ bridge functions.
#define API_NAME(name) Terminal##name
#define GENERATOR_0(name) \
__declspec(dllexport) HRESULT _stdcall API_NAME(name)(PTERM terminal) \
try \
{ \
return ((HwndTerminal*)(terminal))->name(); \
} \
CATCH_RETURN()
#define GENERATOR_1(name, t1, a1) \
__declspec(dllexport) HRESULT _stdcall API_NAME(name)(PTERM terminal, t1 a1) \
try \
{ \
return ((HwndTerminal*)(terminal))->name(a1); \
} \
CATCH_RETURN()
#define GENERATOR_2(name, t1, a1, t2, a2) \
__declspec(dllexport) HRESULT _stdcall API_NAME(name)(PTERM terminal, t1 a1, t2 a2) \
try \
{ \
return ((HwndTerminal*)(terminal))->name(a1, a2); \
} \
CATCH_RETURN()
#define GENERATOR_3(name, t1, a1, t2, a2, t3, a3) \
__declspec(dllexport) HRESULT _stdcall API_NAME(name)(PTERM terminal, t1 a1, t2 a2, t3 a3) \
try \
{ \
return ((HwndTerminal*)(terminal))->name(a1, a2, a3); \
} \
CATCH_RETURN()
#define GENERATOR_4(name, t1, a1, t2, a2, t3, a3, t4, a4) \
__declspec(dllexport) HRESULT _stdcall API_NAME(name)(PTERM terminal, t1 a1, t2 a2, t3 a3, t4 a4) \
try \
{ \
return ((HwndTerminal*)(terminal))->name(a1, a2, a3, a4); \
} \
CATCH_RETURN()
#define GENERATOR_N(name, t1, a1, t2, a2, t3, a3, t4, a4, MACRO, ...) MACRO
#define GENERATOR(...) \
GENERATOR_N(__VA_ARGS__, GENERATOR_4, GENERATOR_4, GENERATOR_3, GENERATOR_3, GENERATOR_2, GENERATOR_2, GENERATOR_1, GENERATOR_1, GENERATOR_0) \
(__VA_ARGS__)
TERMINAL_API_TABLE(GENERATOR)
#undef GENERATOR_0
#undef GENERATOR_1
#undef GENERATOR_2
#undef GENERATOR_3
#undef GENERATOR_4
#undef GENERATOR_N
#undef GENERATOR
#undef API_NAME

View File

@@ -0,0 +1,63 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
// Keep in sync with TerminalTheme.cs
typedef struct _TerminalTheme
{
COLORREF DefaultBackground;
COLORREF DefaultForeground;
COLORREF DefaultSelectionBackground;
uint32_t CursorStyle; // This will be converted to DispatchTypes::CursorStyle (size_t), but C# cannot marshal an enum type and have it fit in a size_t.
COLORREF ColorTable[16];
} TerminalTheme;
using PTERM = void*;
using PSCROLLCB = void(_stdcall*)(int, int, int);
using PWRITECB = void(_stdcall*)(const wchar_t*);
#define TERMINAL_API_TABLE(XX) \
XX(SendOutput, LPCWSTR, data) \
XX(RegisterScrollCallback, PSCROLLCB, callback) \
XX(TriggerResize, _In_ til::CoordType, width, _In_ til::CoordType, height, _Out_ til::size*, dimensions) \
XX(TriggerResizeWithDimension, _In_ til::size, dimensions, _Out_ til::size*, dimensionsInPixels) \
XX(CalculateResize, _In_ til::CoordType, width, _In_ til::CoordType, height, _Out_ til::size*, dimensions) \
XX(DpiChanged, int, newDpi) \
XX(UserScroll, int, viewTop) \
XX(GetSelection, const wchar_t**, out) \
XX(IsSelectionActive, bool*, out) \
XX(SetTheme, TerminalTheme, theme, LPCWSTR, fontFamily, til::CoordType, fontSize, int, newDpi) \
XX(RegisterWriteCallback, PWRITECB, callback) \
XX(SendKeyEvent, WORD, vkey, WORD, scanCode, WORD, flags, bool, keyDown) \
XX(SendCharEvent, wchar_t, ch, WORD, flags, WORD, scanCode)
extern "C" {
#define API_NAME(name) Terminal##name
#define GENERATOR_0(name) \
__declspec(dllexport) HRESULT _stdcall API_NAME(name)(PTERM);
#define GENERATOR_1(name, t1, a1) \
__declspec(dllexport) HRESULT _stdcall API_NAME(name)(PTERM, t1);
#define GENERATOR_2(name, t1, a1, t2, a2) \
__declspec(dllexport) HRESULT _stdcall API_NAME(name)(PTERM, t1, t2);
#define GENERATOR_3(name, t1, a1, t2, a2, t3, a3) \
__declspec(dllexport) HRESULT _stdcall API_NAME(name)(PTERM, t1, t2, t3);
#define GENERATOR_4(name, t1, a1, t2, a2, t3, a3, t4, a4) \
__declspec(dllexport) HRESULT _stdcall API_NAME(name)(PTERM, t1, t2, t3, t4);
#define GENERATOR_N(name, t1, a1, t2, a2, t3, a3, t4, a4, MACRO, ...) MACRO
#define GENERATOR(...) \
GENERATOR_N(__VA_ARGS__, GENERATOR_4, GENERATOR_4, GENERATOR_3, GENERATOR_3, GENERATOR_2, GENERATOR_2, GENERATOR_1, GENERATOR_1, GENERATOR_0) \
(__VA_ARGS__)
TERMINAL_API_TABLE(GENERATOR)
#undef GENERATOR
#undef GENERATOR_0
#undef GENERATOR_1
#undef GENERATOR_2
#undef GENERATOR_3
#undef GENERATOR_4
#undef GENERATOR_N
#undef API_NAME
__declspec(dllexport) HRESULT _stdcall CreateTerminal(HWND parentHwnd, _Out_ void** hwnd, _Out_ PTERM* terminal);
__declspec(dllexport) void _stdcall DestroyTerminal(PTERM terminal);
};

View File

@@ -272,9 +272,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TermControl::TermControl(Control::ControlInteractivity content) :
_interactivity{ content },
_isInternalScrollBarUpdate{ false },
_autoScrollVelocity{ 0 },
_autoScrollingPointerPoint{ std::nullopt },
_lastAutoScrollUpdateTime{ std::nullopt },
_searchBox{ nullptr }
{
InitializeComponent();
@@ -394,10 +391,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_revokers.coreScrollPositionChanged = _core.ScrollPositionChanged(winrt::auto_revoke, { get_weak(), &TermControl::_ScrollPositionChanged });
_revokers.WarningBell = _core.WarningBell(winrt::auto_revoke, { get_weak(), &TermControl::_coreWarningBell });
static constexpr auto AutoScrollUpdateInterval = std::chrono::microseconds(static_cast<int>(1.0 / 30.0 * 1000000));
_autoScrollTimer.Interval(AutoScrollUpdateInterval);
_autoScrollTimer.Tick({ get_weak(), &TermControl::_UpdateAutoScroll });
_ApplyUISettings();
_originalPrimaryElements = winrt::single_threaded_observable_vector<Controls::ICommandBarElement>();
@@ -1981,10 +1974,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
Focus(FocusState::Pointer);
}
// Mark that this pointer event actually started within our bounds.
// We'll need this later, for PointerMoved events.
_pointerPressedInBounds = true;
if (type == Windows::Devices::Input::PointerDeviceType::Touch)
{
// NB: I don't think this is correct because the touch should be in the center of the rect.
@@ -2041,40 +2030,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TermControl::GetPointerUpdateKind(point),
ControlKeyStates(args.KeyModifiers()),
pixelPosition);
// GH#9109 - Only start an auto-scroll when the drag actually
// started within our bounds. Otherwise, someone could start a drag
// outside the terminal control, drag into the padding, and trick us
// into starting to scroll.
if (!suppressFurtherHandling && _focused && _pointerPressedInBounds && point.Properties().IsLeftButtonPressed())
{
// We want to find the distance relative to the bounds of the
// SwapChainPanel, not the entire control. If they drag out of
// the bounds of the text, into the padding, we still what that
// to auto-scroll
const auto cursorBelowBottomDist = cursorPosition.Y - SwapChainPanel().Margin().Top - SwapChainPanel().ActualHeight();
const auto cursorAboveTopDist = -1 * cursorPosition.Y + SwapChainPanel().Margin().Top;
constexpr auto MinAutoScrollDist = 2.0; // Arbitrary value
auto newAutoScrollVelocity = 0.0;
if (cursorBelowBottomDist > MinAutoScrollDist)
{
newAutoScrollVelocity = _GetAutoScrollSpeed(cursorBelowBottomDist);
}
else if (cursorAboveTopDist > MinAutoScrollDist)
{
newAutoScrollVelocity = -1.0 * _GetAutoScrollSpeed(cursorAboveTopDist);
}
if (newAutoScrollVelocity != 0)
{
_TryStartAutoScroll(point, newAutoScrollVelocity);
}
else
{
_TryStopAutoScroll(ptr.PointerId());
}
}
/* TODO(DH) */ UNREFERENCED_PARAMETER(suppressFurtherHandling);
}
else if (type == Windows::Devices::Input::PointerDeviceType::Touch)
{
@@ -2101,8 +2057,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return;
}
_pointerPressedInBounds = false;
const auto ptr = args.Pointer();
const auto point = args.GetCurrentPoint(*this);
const auto cursorPosition = point.Position();
@@ -2125,8 +2079,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_interactivity.TouchReleased();
}
_TryStopAutoScroll(ptr.PointerId());
args.Handled(true);
}
@@ -2281,86 +2233,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return false;
}
// Method Description:
// - Starts new pointer related auto scroll behavior, or continues existing one.
// Does nothing when there is already auto scroll associated with another pointer.
// Arguments:
// - pointerPoint: info about pointer that causes auto scroll. Pointer's position
// is later used to update selection.
// - scrollVelocity: target velocity of scrolling in characters / sec
void TermControl::_TryStartAutoScroll(const Windows::UI::Input::PointerPoint& pointerPoint, const double scrollVelocity)
{
// Allow only one pointer at the time
if (!_autoScrollingPointerPoint ||
_autoScrollingPointerPoint->PointerId() == pointerPoint.PointerId())
{
_autoScrollingPointerPoint = pointerPoint;
_autoScrollVelocity = scrollVelocity;
// If this is first time the auto scroll update is about to be called,
// kick-start it by initializing its time delta as if it started now
if (!_lastAutoScrollUpdateTime)
{
_lastAutoScrollUpdateTime = std::chrono::high_resolution_clock::now();
}
// Apparently this check is not necessary but greatly improves performance
if (!_autoScrollTimer.IsEnabled())
{
_autoScrollTimer.Start();
}
}
}
// Method Description:
// - Stops auto scroll if it's active and is associated with supplied pointer id.
// Arguments:
// - pointerId: id of pointer for which to stop auto scroll
void TermControl::_TryStopAutoScroll(const uint32_t pointerId)
{
if (_autoScrollingPointerPoint &&
pointerId == _autoScrollingPointerPoint->PointerId())
{
_autoScrollingPointerPoint = std::nullopt;
_autoScrollVelocity = 0;
_lastAutoScrollUpdateTime = std::nullopt;
// Apparently this check is not necessary but greatly improves performance
if (_autoScrollTimer.IsEnabled())
{
_autoScrollTimer.Stop();
}
}
}
// Method Description:
// - Called continuously to gradually scroll viewport when user is mouse
// selecting outside it (to 'follow' the cursor).
// Arguments:
// - none
void TermControl::_UpdateAutoScroll(const Windows::Foundation::IInspectable& /* sender */,
const Windows::Foundation::IInspectable& /* e */)
{
if (_autoScrollVelocity != 0)
{
const auto timeNow = std::chrono::high_resolution_clock::now();
if (_lastAutoScrollUpdateTime)
{
static constexpr auto microSecPerSec = 1000000.0;
const auto deltaTime = std::chrono::duration_cast<std::chrono::microseconds>(timeNow - *_lastAutoScrollUpdateTime).count() / microSecPerSec;
ScrollBar().Value(ScrollBar().Value() + _autoScrollVelocity * deltaTime);
if (_autoScrollingPointerPoint)
{
_SetEndSelectionPointAtCursor(_autoScrollingPointerPoint->Position());
}
}
_lastAutoScrollUpdateTime = timeNow;
}
}
// Method Description:
// - Event handler for the GotFocus event. This is used to...
// - enable accessibility notifications for this TermControl
@@ -2495,15 +2367,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_core.ScaleChanged(scaleX);
}
// Method Description:
// - Sets selection's end position to match supplied cursor position, e.g. while mouse dragging.
// Arguments:
// - cursorPosition: in pixels, relative to the origin of the control
void TermControl::_SetEndSelectionPointAtCursor(const Windows::Foundation::Point& cursorPosition)
{
_interactivity.SetEndSelectionPoint(_toTerminalOrigin(cursorPosition));
}
// Method Description:
// - Update the position and size of the scrollbar to match the given
// viewport top, viewport height, and buffer size.
@@ -2661,7 +2524,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// On Win10 we don't destroy window threads due to bugs in DesktopWindowXamlSource.
// In turn, we leak TermControl instances. This results in constant HWND messages
// while the thread is supposed to be idle. Stop these timers avoids this.
_autoScrollTimer.Stop();
_bellLightTimer.Stop();
// This is absolutely crucial, as the TSF code tries to hold a strong reference to _tsfDataProvider,
@@ -2809,7 +2671,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// UWP XAML scrollbars aren't guaranteed to be the same size as the
// ComCtl scrollbars, but it's certainly close enough.
const auto scrollbarSize = GetSystemMetricsForDpi(SM_CXVSCROLL, dpi);
auto scrollbarSize = GetSystemMetrics(SM_CXVSCROLL);
scrollbarSize = gsl::narrow_cast<decltype(scrollbarSize)>(scrollbarSize * (dpi / 96));
float width = cols * static_cast<float>(actualFontSize.width);
@@ -3059,20 +2922,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
};
}
// Method Description:
// - Calculates speed of single axis of auto scrolling. It has to allow for both
// fast and precise selection.
// Arguments:
// - cursorDistanceFromBorder: distance from viewport border to cursor, in pixels. Must be non-negative.
// Return Value:
// - positive speed in characters / sec
double TermControl::_GetAutoScrollSpeed(double cursorDistanceFromBorder) const
{
// The numbers below just feel well, feel free to change.
// TODO: Maybe account for space beyond border that user has available
return std::pow(cursorDistanceFromBorder, 2.0) / 25.0 + 2.0;
}
// Method Description:
// - Async handler for the "Drop" event. If a file was dropped onto our
// root, we'll try to get the path of the file dropped onto us, and write

View File

@@ -300,14 +300,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool _isInternalScrollBarUpdate;
// Auto scroll occurs when user, while selecting, drags cursor outside
// viewport. View is then scrolled to 'follow' the cursor.
double _autoScrollVelocity;
std::optional<Windows::UI::Input::PointerPoint> _autoScrollingPointerPoint;
SafeDispatcherTimer _autoScrollTimer;
std::optional<std::chrono::high_resolution_clock::time_point> _lastAutoScrollUpdateTime;
bool _pointerPressedInBounds{ false };
winrt::Windows::UI::Composition::ScalarKeyFrameAnimation _bellLightAnimation{ nullptr };
winrt::Windows::UI::Composition::ScalarKeyFrameAnimation _bellDarkAnimation{ nullptr };
SafeDispatcherTimer _bellLightTimer;
@@ -385,8 +377,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _BellLightOff(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
void _SetEndSelectionPointAtCursor(const Windows::Foundation::Point& cursorPosition);
void _SwapChainSizeChanged(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::SizeChangedEventArgs& e);
void _SwapChainScaleChanged(const Windows::UI::Xaml::Controls::SwapChainPanel& sender, const Windows::Foundation::IInspectable& args);
@@ -395,10 +385,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool _CapturePointer(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e);
bool _ReleasePointerCapture(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e);
void _TryStartAutoScroll(const Windows::UI::Input::PointerPoint& pointerPoint, const double scrollVelocity);
void _TryStopAutoScroll(const uint32_t pointerId);
void _UpdateAutoScroll(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
void _KeyHandler(const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e, const bool keyDown);
bool _KeyHandler(WORD vkey, WORD scanCode, ::Microsoft::Terminal::Core::ControlKeyStates modifiers, bool keyDown);
static ::Microsoft::Terminal::Core::ControlKeyStates _GetPressedModifierKeys() noexcept;
@@ -409,8 +395,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::Windows::Foundation::Point _toControlOrigin(const til::point terminalPosition);
Core::Point _toTerminalOrigin(winrt::Windows::Foundation::Point cursorPosition);
double _GetAutoScrollSpeed(double cursorDistanceFromBorder) const;
void _Search(const winrt::hstring& text, const bool goForward, const bool caseSensitive, const bool regularExpression);
void _SearchChanged(const winrt::hstring& text, const bool goForward, const bool caseSensitive, const bool regularExpression);
void _CloseSearchBoxControl(const winrt::Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);

View File

@@ -30,6 +30,7 @@
<!-- ========================= Headers ======================== -->
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="FlatC.h" />
<ClInclude Include="ControlCore.h">
<DependentUpon>ControlCore.idl</DependentUpon>
</ClInclude>
@@ -61,14 +62,13 @@
<DependentUpon>InteractivityAutomationPeer.idl</DependentUpon>
</ClInclude>
<ClInclude Include="XamlUiaTextRange.h" />
<ClInclude Include="HwndTerminal.hpp" />
<ClInclude Include="HwndTerminalAutomationPeer.hpp" />
</ItemGroup>
<!-- ========================= Cpp Files ======================== -->
<ItemGroup>
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="FlatC.cpp" />
<ClCompile Include="ControlCore.cpp">
<DependentUpon>ControlCore.idl</DependentUpon>
</ClCompile>
@@ -102,8 +102,6 @@
<DependentUpon>InteractivityAutomationPeer.idl</DependentUpon>
</ClCompile>
<ClCompile Include="XamlUiaTextRange.cpp" />
<ClCompile Include="HwndTerminal.cpp" />
<ClCompile Include="HwndTerminalAutomationPeer.cpp" />
</ItemGroup>
<!-- ========================= idl Files ======================== -->
<ItemGroup>
@@ -160,6 +158,7 @@
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
</ProjectReference>
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\WinRTUtils\WinRTUtils.vcxproj">
<Private>true</Private>
<Project>{CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>

View File

@@ -7,17 +7,16 @@ EXPORTS
AvoidBuggyTSFConsoleFlags
CreateTerminal
DestroyTerminal
TerminalCalculateResize
TerminalDpiChanged
TerminalGetSelection
TerminalIsSelectionActive
TerminalRegisterScrollCallback
TerminalRegisterWriteCallback
TerminalSendCharEvent
TerminalSendKeyEvent
TerminalSendOutput
TerminalSetFocused
TerminalSetTheme
TerminalRegisterScrollCallback
TerminalTriggerResize
TerminalTriggerResizeWithDimension
TerminalCalculateResize
TerminalDpiChanged
TerminalUserScroll
TerminalGetSelection
TerminalIsSelectionActive
TerminalSetTheme
TerminalRegisterWriteCallback
TerminalSendKeyEvent
TerminalSendCharEvent

View File

@@ -115,4 +115,12 @@
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
<!--LATE LATE LATE-->
<ItemDefinitionGroup>
<Link>
<AdditionalDependencies>delayimp.lib;uiautomationcore.lib;oleaut32.lib;onecoreuap.lib;user32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>uiautomationcore.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
</Project>

View File

@@ -76,6 +76,7 @@ static void EnsureAllResourcesArePresent(const ScopedResourceLoader& loader)
#endif
static ScopedResourceLoader no_resources{ ScopedResourceLoader::NoResourcesT{} };
const ScopedResourceLoader& GetLibraryResourceLoader()
try
{
@@ -85,18 +86,30 @@ try
#endif
return loader;
}
CATCH_FAIL_FAST()
catch (...)
{
LOG_CAUGHT_EXCEPTION();
return no_resources;
}
winrt::hstring GetLibraryResourceString(const std::wstring_view key)
try
{
return GetLibraryResourceLoader().GetLocalizedString(key);
}
CATCH_FAIL_FAST()
catch (...)
{
LOG_CAUGHT_EXCEPTION();
return winrt::hstring{};
}
bool HasLibraryResourceWithName(const std::wstring_view key)
try
{
return GetLibraryResourceLoader().HasResourceWithName(key);
}
CATCH_FAIL_FAST()
catch (...)
{
LOG_CAUGHT_EXCEPTION();
return false;
}

View File

@@ -6,7 +6,12 @@
class ScopedResourceLoader
{
public:
struct NoResourcesT
{
};
ScopedResourceLoader(const std::wstring_view resourceLocatorBase);
ScopedResourceLoader(const NoResourcesT&) :
_resourceMap{ nullptr }, _resourceContext{ nullptr } {}
winrt::Windows::ApplicationModel::Resources::Core::ResourceMap GetResourceMap() const noexcept;
winrt::hstring GetLocalizedString(const std::wstring_view resourceName) const;
bool HasResourceWithName(const std::wstring_view resourceName) const;

View File

@@ -3,8 +3,8 @@
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Castle.Core" publicKeyToken="407dd0808d44fbdc" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
<assemblyIdentity name="Castle.Core" publicKeyToken="407dd0808d44fbdc" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />

View File

@@ -177,7 +177,10 @@ namespace Microsoft.Terminal.Wpf
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = false)]
public static extern void CreateTerminal(IntPtr parent, out IntPtr hwnd, out IntPtr terminal);
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = true)]
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern void DestroyTerminal(IntPtr terminal);
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = false)]
public static extern void TerminalSendOutput(IntPtr terminal, string lpdata);
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = false)]
@@ -189,44 +192,44 @@ namespace Microsoft.Terminal.Wpf
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = false)]
public static extern void TerminalCalculateResize(IntPtr terminal, int width, int height, out TilSize dimensions);
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = true)]
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = false)]
public static extern void TerminalDpiChanged(IntPtr terminal, int newDpi);
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = true)]
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = false)]
public static extern void TerminalRegisterScrollCallback(IntPtr terminal, [MarshalAs(UnmanagedType.FunctionPtr)] ScrollCallback callback);
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = true)]
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = false)]
public static extern void TerminalRegisterWriteCallback(IntPtr terminal, [MarshalAs(UnmanagedType.FunctionPtr)] WriteCallback callback);
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = true)]
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = false)]
public static extern void TerminalUserScroll(IntPtr terminal, int viewTop);
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = true)]
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = false)]
[return: MarshalAs(UnmanagedType.LPWStr)]
public static extern string TerminalGetSelection(IntPtr terminal);
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = true)]
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = false)]
[return: MarshalAs(UnmanagedType.I1)]
public static extern bool TerminalIsSelectionActive(IntPtr terminal);
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern void DestroyTerminal(IntPtr terminal);
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = true)]
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = false)]
public static extern void TerminalSendKeyEvent(IntPtr terminal, ushort vkey, ushort scanCode, ushort flags, bool keyDown);
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = true)]
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = false)]
public static extern void TerminalSendCharEvent(IntPtr terminal, char ch, ushort scanCode, ushort flags);
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = true)]
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = false)]
public static extern void TerminalSetTheme(IntPtr terminal, [MarshalAs(UnmanagedType.Struct)] TerminalTheme theme, string fontFamily, short fontSize, int newDpi);
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = true)]
public static extern void TerminalSetFocused(IntPtr terminal, bool focused);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetFocus(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetFocus();
[DllImport("user32.dll", SetLastError = true)]
public static extern short GetKeyState(int keyCode);
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPOS
{

View File

@@ -37,7 +37,6 @@ namespace Microsoft.Terminal.Wpf
NativeMethods.AvoidBuggyTSFConsoleFlags();
this.MessageHook += this.TerminalContainer_MessageHook;
this.GotFocus += this.TerminalContainer_GotFocus;
this.Focusable = true;
}
@@ -324,24 +323,12 @@ namespace Microsoft.Terminal.Wpf
character = (char)vKey;
}
private void TerminalContainer_GotFocus(object sender, RoutedEventArgs e)
{
e.Handled = true;
NativeMethods.SetFocus(this.hwnd);
}
private IntPtr TerminalContainer_MessageHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (hwnd == this.hwnd)
{
switch ((NativeMethods.WindowMessage)msg)
{
case NativeMethods.WindowMessage.WM_SETFOCUS:
NativeMethods.TerminalSetFocused(this.terminal, true);
break;
case NativeMethods.WindowMessage.WM_KILLFOCUS:
NativeMethods.TerminalSetFocused(this.terminal, false);
break;
case NativeMethods.WindowMessage.WM_MOUSEACTIVATE:
this.Focus();
NativeMethods.SetFocus(this.hwnd);
@@ -349,6 +336,7 @@ namespace Microsoft.Terminal.Wpf
case NativeMethods.WindowMessage.WM_SYSKEYDOWN: // fallthrough
case NativeMethods.WindowMessage.WM_KEYDOWN:
{
// WM_KEYDOWN lParam layout documentation: https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-keydown
UnpackKeyMessage(wParam, lParam, out ushort vkey, out ushort scanCode, out ushort flags);
NativeMethods.TerminalSendKeyEvent(this.terminal, vkey, scanCode, flags, true);
break;
@@ -403,10 +391,10 @@ namespace Microsoft.Terminal.Wpf
this.Connection?.Resize((uint)dimensions.Y, (uint)dimensions.X);
break;
case NativeMethods.WindowMessage.WM_MOUSEWHEEL:
var delta = (short)(((long)wParam) >> 16);
this.UserScrolled?.Invoke(this, delta);
break;
//case NativeMethods.WindowMessage.WM_MOUSEWHEEL:
//var delta = (short)(((long)wParam) >> 16);
//this.UserScrolled?.Invoke(this, delta);
//break;
}
}

View File

@@ -11,6 +11,117 @@ namespace WpfTerminalTestNetCore
{
public class EchoConnection : Microsoft.Terminal.Wpf.ITerminalConnection
{
byte[] __foo_txt = {
0x1b, 0x5b, 0x48, 0x1b, 0x5b, 0x32, 0x4a, 0x1b, 0x5b, 0x33, 0x4a, 0x0d,
0x0a, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x31, 0x38, 0x6d,
0x54, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x31, 0x35, 0x34, 0x6d, 0x68, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x35, 0x34, 0x6d, 0x61, 0x1b, 0x5b, 0x30,
0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x35, 0x34, 0x6d,
0x6e, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x31, 0x34, 0x38, 0x6d, 0x6b, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x34, 0x6d, 0x73, 0x1b, 0x5b, 0x30,
0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x34, 0x6d,
0x20, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x31, 0x38, 0x34, 0x6d, 0x66, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x37, 0x38, 0x6d, 0x6f, 0x1b, 0x5b, 0x30,
0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x31, 0x34, 0x6d,
0x72, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x32, 0x31, 0x34, 0x6d, 0x20, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x31, 0x34, 0x6d, 0x76, 0x1b, 0x5b, 0x30,
0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x30, 0x38, 0x6d,
0x69, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x32, 0x30, 0x38, 0x6d, 0x73, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x30, 0x38, 0x6d, 0x69, 0x1b, 0x5b, 0x30,
0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x30, 0x33, 0x6d,
0x74, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x32, 0x30, 0x33, 0x6d, 0x69, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x30, 0x33, 0x6d, 0x6e, 0x1b, 0x5b, 0x30,
0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x30, 0x33, 0x6d,
0x67, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x31, 0x39, 0x38, 0x6d, 0x20, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x39, 0x38, 0x6d, 0x6d, 0x1b, 0x5b, 0x30,
0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x39, 0x38, 0x6d,
0x79, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x31, 0x39, 0x39, 0x6d, 0x20, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x39, 0x39, 0x6d, 0x77, 0x1b, 0x5b, 0x30,
0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x39, 0x39, 0x6d,
0x65, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x31, 0x36, 0x33, 0x6d, 0x62, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x36, 0x34, 0x6d, 0x73, 0x1b, 0x5b, 0x30,
0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x36, 0x34, 0x6d,
0x69, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x31, 0x36, 0x34, 0x6d, 0x74, 0x1b, 0x5b, 0x30, 0x6d, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x32, 0x38, 0x6d, 0x65, 0x1b, 0x5b, 0x30,
0x6d, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x32, 0x39, 0x6d,
0x21, 0x1b, 0x5b, 0x30, 0x6d, 0x0d, 0x0a, 0x0d, 0x0a, 0x54, 0x68, 0x69,
0x73, 0x20, 0x69, 0x73, 0x20, 0x6d, 0x79, 0x20, 0x63, 0x6f, 0x6f, 0x6c,
0x20, 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x20, 0x61, 0x62, 0x6f,
0x75, 0x74, 0x20, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x73,
0x0d, 0x0a, 0x48, 0x65, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20,
0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x63, 0x6f, 0x6f, 0x6c,
0x20, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x73, 0x0d, 0x0a,
0x2a, 0x20, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x54, 0x65,
0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x20, 0x28, 0x68, 0x74, 0x74, 0x70,
0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74,
0x2f, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x29, 0x0d, 0x0a,
0x0d, 0x0a, 0x1b, 0x5b, 0x35, 0x6d, 0x5b, 0x55, 0x4e, 0x44, 0x45, 0x52,
0x20, 0x43, 0x4f, 0x4e, 0x53, 0x54, 0x52, 0x55, 0x43, 0x54, 0x49, 0x4f,
0x4e, 0x5d, 0x1b, 0x5b, 0x6d, 0x0d, 0x0a, 0x0d, 0x0a, 0x59, 0x6f, 0x75,
0x20, 0x61, 0x72, 0x65, 0x20, 0x76, 0x69, 0x73, 0x69, 0x74, 0x6f, 0x72,
0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x1b, 0x5b, 0x35, 0x33,
0x3b, 0x34, 0x3b, 0x39, 0x32, 0x6d, 0x30, 0x30, 0x30, 0x30, 0x32, 0x1b,
0x5b, 0x6d, 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x79, 0x20, 0x77, 0x65, 0x62,
0x73, 0x69, 0x74, 0x65, 0x2e, 0x0d, 0x0a, 0x0d, 0x0a, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x34, 0x34, 0x6d, 0x1b, 0x5b, 0x35, 0x33,
0x6d, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x70, 0x61,
0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x6f,
0x6f, 0x6c, 0x20, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x73,
0x20, 0x77, 0x65, 0x62, 0x72, 0x69, 0x6e, 0x67, 0x21, 0x20, 0x1b, 0x5b,
0x35, 0x35, 0x6d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x56, 0x69, 0x73, 0x69,
0x74, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x69, 0x74, 0x65,
0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x65, 0x62,
0x20, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x2e, 0x2e, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x1b, 0x5b, 0x39, 0x34, 0x6d, 0x1b, 0x5d, 0x38, 0x3b,
0x69, 0x64, 0x3d, 0x70, 0x72, 0x65, 0x76, 0x3b, 0x68, 0x74, 0x74, 0x70,
0x73, 0x3a, 0x2f, 0x2f, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c,
0x2e, 0x73, 0x69, 0x74, 0x65, 0x2f, 0x3f, 0x70, 0x72, 0x65, 0x76, 0x69,
0x6f, 0x75, 0x73, 0x3d, 0x31, 0x1b, 0x5c, 0x50, 0x72, 0x65, 0x76, 0x69,
0x6f, 0x75, 0x73, 0x1b, 0x5d, 0x38, 0x3b, 0x3b, 0x1b, 0x5c, 0x1b, 0x5b,
0x6d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x39, 0x34, 0x6d, 0x1b,
0x5d, 0x38, 0x3b, 0x69, 0x64, 0x3d, 0x72, 0x61, 0x6e, 0x64, 0x3b, 0x68,
0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x74, 0x65, 0x72, 0x6d, 0x69,
0x6e, 0x61, 0x6c, 0x2e, 0x73, 0x69, 0x74, 0x65, 0x2f, 0x3f, 0x72, 0x61,
0x6e, 0x64, 0x6f, 0x6d, 0x3d, 0x31, 0x1b, 0x5c, 0x52, 0x61, 0x6e, 0x64,
0x6f, 0x6d, 0x1b, 0x5d, 0x38, 0x3b, 0x3b, 0x1b, 0x5c, 0x1b, 0x5b, 0x6d,
0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x39, 0x34, 0x6d, 0x1b, 0x5d,
0x38, 0x3b, 0x69, 0x64, 0x3d, 0x6e, 0x65, 0x78, 0x74, 0x3b, 0x68, 0x74,
0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e,
0x61, 0x6c, 0x2e, 0x73, 0x69, 0x74, 0x65, 0x2f, 0x3f, 0x6e, 0x65, 0x78,
0x74, 0x3d, 0x31, 0x1b, 0x5c, 0x4e, 0x65, 0x78, 0x74, 0x1b, 0x5d, 0x38,
0x3b, 0x3b, 0x1b, 0x5c, 0x1b, 0x5b, 0x6d, 0x20, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x39, 0x34, 0x6d, 0x1b, 0x5d,
0x38, 0x3b, 0x69, 0x64, 0x3d, 0x70, 0x72, 0x65, 0x76, 0x3b, 0x68, 0x74,
0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e,
0x61, 0x6c, 0x2e, 0x73, 0x69, 0x74, 0x65, 0x2f, 0x3f, 0x70, 0x72, 0x65,
0x76, 0x69, 0x6f, 0x75, 0x73, 0x3d, 0x31, 0x1b, 0x5c, 0x20, 0x20, 0x53,
0x69, 0x74, 0x65, 0x20, 0x20, 0x1b, 0x5d, 0x38, 0x3b, 0x3b, 0x1b, 0x5c,
0x1b, 0x5b, 0x6d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x39, 0x34, 0x6d,
0x1b, 0x5d, 0x38, 0x3b, 0x69, 0x64, 0x3d, 0x6e, 0x65, 0x78, 0x74, 0x3b,
0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x74, 0x65, 0x72, 0x6d,
0x69, 0x6e, 0x61, 0x6c, 0x2e, 0x73, 0x69, 0x74, 0x65, 0x2f, 0x3f, 0x6e,
0x65, 0x78, 0x74, 0x3d, 0x31, 0x1b, 0x5c, 0x53, 0x69, 0x74, 0x65, 0x1b,
0x5d, 0x38, 0x3b, 0x3b, 0x1b, 0x5c, 0x1b, 0x5b, 0x6d, 0x20, 0x0d, 0x0a,
0x1b, 0x5b, 0x34, 0x3b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x34, 0x34,
0x6d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b,
0x6d, 0x0d, 0x0a
};
public event EventHandler<TerminalOutputEventArgs> TerminalOutput;
public void Resize(uint rows, uint columns)
@@ -18,10 +129,15 @@ namespace WpfTerminalTestNetCore
return;
}
private void _preamble()
{
_print(System.Text.Encoding.UTF8.GetString(__foo_txt));
_print("^A: prt esc ^B: sgrmouse ^C: win32im ^D: again!\r\n");
return;
}
public void Start()
{
TerminalOutput.Invoke(this, new TerminalOutputEventArgs("ECHO CONNECTION\r\n^A: toggle printable ESC\r\n^B: toggle SGR mouse mode\r\n^C: toggle win32 input mode\r\n\r\n"));
return;
_preamble();
}
private bool _escapeMode;
@@ -62,18 +178,27 @@ namespace WpfTerminalTestNetCore
TerminalOutput.Invoke(this, new TerminalOutputEventArgs($"Printable ESC mode: {_escapeMode}\r\n"));
}
}
else if (data[0] == '\x04')
{
_preamble();
}
else
{
// Echo back to the terminal, but make backspace/newline work properly.
var str = data.Replace("\r", "\r\n").Replace("\x7f", "\x08 \x08");
if (_escapeMode)
{
str = str.Replace("\x1b", "\u241b");
}
TerminalOutput.Invoke(this, new TerminalOutputEventArgs(str));
_print(str);
}
}
private void _print(string str)
{
if (_escapeMode)
{
str = str.Replace("\x1b", "\u241b");
}
TerminalOutput.Invoke(this, new TerminalOutputEventArgs(str));
}
public void Close()
{
return;

View File

@@ -137,7 +137,7 @@
This diagnostic is broken in VS 17.7 which our CI currently uses. It's fixed in 17.8.
-->
<DisableSpecificWarnings>4201;4312;4467;5105;26434;26445;26456;26478;26494;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<PreprocessorDefinitions>_WINDOWS;EXTERNAL_BUILD;_SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING;_WINDOWS;EXTERNAL_BUILD;_SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>

View File

@@ -3,8 +3,8 @@
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Castle.Core" publicKeyToken="407dd0808d44fbdc" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
<assemblyIdentity name="Castle.Core" publicKeyToken="407dd0808d44fbdc" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />