mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-25 23:52:52 +00:00
Compare commits
5 Commits
main
...
dev/duhowe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f25f0dc0f | ||
|
|
09ad716882 | ||
|
|
e32a96d947 | ||
|
|
6e5f5a973b | ||
|
|
46de6846bc |
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "winrt/Windows.Data.Json.h"
|
||||
#include <Windows.h>
|
||||
|
||||
#include <wrl.h>
|
||||
#include <winhttp.h>
|
||||
#include <wil/resource.h>
|
||||
|
||||
|
||||
@@ -160,6 +160,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
|
||||
@@ -408,12 +409,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());
|
||||
@@ -434,6 +438,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
|
||||
@@ -1939,7 +1960,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.
|
||||
@@ -1957,7 +1978,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() })
|
||||
{
|
||||
@@ -2922,4 +2943,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
_terminal->PreviewText(input);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,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 +93,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();
|
||||
@@ -263,6 +273,9 @@ 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);
|
||||
|
||||
RUNTIME_SETTING(float, Opacity, _settings.Opacity());
|
||||
@@ -341,7 +354,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();
|
||||
#pragma endregion
|
||||
@@ -375,7 +388,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;
|
||||
@@ -420,6 +433,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
std::atomic<bool> _initializedTerminal{ false };
|
||||
bool _isReadOnly{ false };
|
||||
bool _closing{ false };
|
||||
HookupMode _hookup{ HookupMode::ForComposition };
|
||||
|
||||
struct StashedColorScheme
|
||||
{
|
||||
|
||||
@@ -92,6 +92,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);
|
||||
@@ -182,6 +185,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();
|
||||
|
||||
@@ -54,6 +54,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
self->Attached.raise(*self, nullptr);
|
||||
}
|
||||
});
|
||||
|
||||
_createInteractivityTimers();
|
||||
}
|
||||
|
||||
uint64_t ControlInteractivity::Id()
|
||||
@@ -80,12 +82,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:
|
||||
@@ -117,12 +121,30 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void ControlInteractivity::Close()
|
||||
{
|
||||
Closed.raise(*this, nullptr);
|
||||
_destroyInteractivityTimers();
|
||||
if (_core)
|
||||
{
|
||||
_core->Close();
|
||||
}
|
||||
}
|
||||
|
||||
void ControlInteractivity::_createInteractivityTimers()
|
||||
{
|
||||
_autoScrollTimer = _core->Dispatcher().CreateTimer();
|
||||
static constexpr auto AutoScrollUpdateInterval = std::chrono::microseconds(static_cast<int>(1.0 / 30.0 * 1000000));
|
||||
_autoScrollTimer.Interval(AutoScrollUpdateInterval);
|
||||
_autoScrollTimer.Tick({ get_weak(), &ControlInteractivity::_updateAutoScroll });
|
||||
}
|
||||
|
||||
void ControlInteractivity::_destroyInteractivityTimers()
|
||||
{
|
||||
if (_autoScrollTimer)
|
||||
{
|
||||
_autoScrollTimer.Stop();
|
||||
_autoScrollTimer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns the number of clicks that occurred (double and triple click support).
|
||||
// Every call to this function registers a click.
|
||||
@@ -155,6 +177,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void ControlInteractivity::GotFocus()
|
||||
{
|
||||
_focused = true;
|
||||
|
||||
if (_uiaEngine.get())
|
||||
{
|
||||
THROW_IF_FAILED(_uiaEngine->Enable());
|
||||
@@ -167,6 +191,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void ControlInteractivity::LostFocus()
|
||||
{
|
||||
_focused = false;
|
||||
|
||||
if (_uiaEngine.get())
|
||||
{
|
||||
THROW_IF_FAILED(_uiaEngine->Disable());
|
||||
@@ -234,7 +260,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
PasteFromClipboard.raise(*this, std::move(args));
|
||||
}
|
||||
|
||||
void ControlInteractivity::PointerPressed(Control::MouseButtonState buttonState,
|
||||
void ControlInteractivity::PointerPressed(const uint32_t /*pointerId*/,
|
||||
Control::MouseButtonState buttonState,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const uint64_t timestamp,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
@@ -247,6 +274,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const auto shiftEnabled = modifiers.IsShiftPressed();
|
||||
const auto ctrlEnabled = modifiers.IsCtrlPressed();
|
||||
|
||||
// Mark that this pointer event actually started within our bounds.
|
||||
// We'll need this later, for PointerMoved events.
|
||||
_pointerPressedInBounds = true;
|
||||
|
||||
// GH#9396: we prioritize hyper-link over VT mouse events
|
||||
auto hyperlink = _core->GetHyperlink(terminalPosition.to_core_point());
|
||||
if (WI_IsFlagSet(buttonState, MouseButtonState::IsLeftButtonDown) &&
|
||||
@@ -327,24 +358,23 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void ControlInteractivity::TouchPressed(const winrt::Windows::Foundation::Point contactPoint)
|
||||
void ControlInteractivity::TouchPressed(const Core::Point contactPoint)
|
||||
{
|
||||
_touchAnchor = contactPoint;
|
||||
}
|
||||
|
||||
bool ControlInteractivity::PointerMoved(Control::MouseButtonState buttonState,
|
||||
bool ControlInteractivity::PointerMoved(const uint32_t pointerId,
|
||||
Control::MouseButtonState buttonState,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const bool focused,
|
||||
const Core::Point pixelPosition,
|
||||
const bool pointerPressedInBounds)
|
||||
const Core::Point pixelPosition)
|
||||
{
|
||||
const auto terminalPosition = _getTerminalPosition(til::point{ pixelPosition }, false);
|
||||
// Returning true from this function indicates that the caller should do no further processing of this movement.
|
||||
bool handledCompletely = false;
|
||||
|
||||
// Short-circuit isReadOnly check to avoid warning dialog
|
||||
if (focused && !_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers))
|
||||
if (_focused && !_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers))
|
||||
{
|
||||
_sendMouseEventHelper(terminalPosition, pointerUpdateKind, modifiers, 0, buttonState);
|
||||
handledCompletely = true;
|
||||
@@ -353,7 +383,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// actually start _in_ the control bounds. Case in point - someone drags
|
||||
// a file into the bounds of the control. That shouldn't send the
|
||||
// selection into space.
|
||||
else if (focused && pointerPressedInBounds && WI_IsFlagSet(buttonState, MouseButtonState::IsLeftButtonDown))
|
||||
else if (_focused && _pointerPressedInBounds && WI_IsFlagSet(buttonState, MouseButtonState::IsLeftButtonDown))
|
||||
{
|
||||
if (_singleClickTouchdownPos)
|
||||
{
|
||||
@@ -393,16 +423,49 @@ 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());
|
||||
return handledCompletely;
|
||||
}
|
||||
|
||||
void ControlInteractivity::TouchMoved(const winrt::Windows::Foundation::Point newTouchPoint,
|
||||
const bool focused)
|
||||
void ControlInteractivity::TouchMoved(const Core::Point newTouchPoint)
|
||||
{
|
||||
if (focused &&
|
||||
if (_focused &&
|
||||
_touchAnchor)
|
||||
{
|
||||
const auto anchor = _touchAnchor.value();
|
||||
@@ -436,11 +499,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void ControlInteractivity::PointerReleased(Control::MouseButtonState buttonState,
|
||||
void ControlInteractivity::PointerReleased(const uint32_t pointerId,
|
||||
Control::MouseButtonState buttonState,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const Core::Point pixelPosition)
|
||||
{
|
||||
_pointerPressedInBounds = false;
|
||||
|
||||
const auto terminalPosition = _getTerminalPosition(til::point{ pixelPosition }, false);
|
||||
// Short-circuit isReadOnly check to avoid warning dialog
|
||||
if (!_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers))
|
||||
@@ -464,6 +530,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
|
||||
_singleClickTouchdownPos = std::nullopt;
|
||||
_tryStopAutoScroll(pointerId);
|
||||
}
|
||||
|
||||
void ControlInteractivity::TouchReleased()
|
||||
@@ -757,4 +824,101 @@ 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 (!_autoScrollTimer.IsRunning())
|
||||
{
|
||||
_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 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
|
||||
if (_autoScrollTimer.IsRunning())
|
||||
{
|
||||
_autoScrollTimer.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called continuously to gradually scroll viewport when user is mouse
|
||||
// selecting outside it (to 'follow' the cursor).
|
||||
// Arguments:
|
||||
// - none
|
||||
void ControlInteractivity::_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;
|
||||
UpdateScrollbar(static_cast<float>(_core->ScrollOffset()) + static_cast<float>(_autoScrollVelocity * deltaTime) /* TODO(DH) */);
|
||||
|
||||
if (_autoScrollingPointerPoint)
|
||||
{
|
||||
SetEndSelectionPoint(*_autoScrollingPointerPoint);
|
||||
}
|
||||
}
|
||||
|
||||
_lastAutoScrollUpdateTime = timeNow;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,23 +51,23 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
::Microsoft::Console::Render::IRenderData* GetRenderData() const;
|
||||
|
||||
#pragma region Input Methods
|
||||
void PointerPressed(Control::MouseButtonState buttonState,
|
||||
void PointerPressed(const uint32_t pointerId,
|
||||
Control::MouseButtonState buttonState,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const uint64_t timestamp,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const Core::Point pixelPosition);
|
||||
void TouchPressed(const winrt::Windows::Foundation::Point contactPoint);
|
||||
void TouchPressed(const Core::Point contactPoint);
|
||||
|
||||
bool PointerMoved(Control::MouseButtonState buttonState,
|
||||
bool PointerMoved(const uint32_t pointerId,
|
||||
Control::MouseButtonState buttonState,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const bool focused,
|
||||
const Core::Point pixelPosition,
|
||||
const bool pointerPressedInBounds);
|
||||
void TouchMoved(const winrt::Windows::Foundation::Point newTouchPoint,
|
||||
const bool focused);
|
||||
const Core::Point pixelPosition);
|
||||
void TouchMoved(const Core::Point newTouchPoint);
|
||||
|
||||
void PointerReleased(Control::MouseButtonState buttonState,
|
||||
void PointerReleased(const uint32_t pointerId,
|
||||
Control::MouseButtonState buttonState,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const Core::Point pixelPosition);
|
||||
@@ -115,7 +115,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
// If this is set, then we assume we are in the middle of panning the
|
||||
// viewport via touch input.
|
||||
std::optional<winrt::Windows::Foundation::Point> _touchAnchor;
|
||||
std::optional<Core::Point> _touchAnchor;
|
||||
|
||||
using Timestamp = uint64_t;
|
||||
|
||||
@@ -142,6 +142,25 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
uint64_t _id;
|
||||
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;
|
||||
Windows::System::DispatcherQueueTimer _autoScrollTimer{ nullptr };
|
||||
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(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
|
||||
double _getAutoScrollSpeed(double cursorDistanceFromBorder) const;
|
||||
|
||||
void _createInteractivityTimers();
|
||||
void _destroyInteractivityTimers();
|
||||
|
||||
unsigned int _numberOfClicks(Core::Point clickPos, Timestamp clickTime);
|
||||
void _updateSystemParameterSettings() noexcept;
|
||||
|
||||
|
||||
@@ -36,24 +36,24 @@ namespace Microsoft.Terminal.Control
|
||||
void RequestPasteTextFromClipboard();
|
||||
void SetEndSelectionPoint(Microsoft.Terminal.Core.Point point);
|
||||
|
||||
void PointerPressed(MouseButtonState buttonState,
|
||||
void PointerPressed(UInt32 pointerId,
|
||||
MouseButtonState buttonState,
|
||||
UInt32 pointerUpdateKind,
|
||||
UInt64 timestamp,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers,
|
||||
Microsoft.Terminal.Core.Point pixelPosition);
|
||||
void TouchPressed(Windows.Foundation.Point contactPoint);
|
||||
void TouchPressed(Microsoft.Terminal.Core.Point contactPoint);
|
||||
|
||||
Boolean PointerMoved(MouseButtonState buttonState,
|
||||
Boolean PointerMoved(UInt32 pointerId,
|
||||
MouseButtonState buttonState,
|
||||
UInt32 pointerUpdateKind,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers,
|
||||
Boolean focused,
|
||||
Microsoft.Terminal.Core.Point pixelPosition,
|
||||
Boolean pointerPressedInBounds);
|
||||
Microsoft.Terminal.Core.Point pixelPosition);
|
||||
|
||||
void TouchMoved(Windows.Foundation.Point newTouchPoint,
|
||||
Boolean focused);
|
||||
void TouchMoved(Microsoft.Terminal.Core.Point newTouchPoint);
|
||||
|
||||
void PointerReleased(MouseButtonState buttonState,
|
||||
void PointerReleased(UInt32 pointerId,
|
||||
MouseButtonState buttonState,
|
||||
UInt32 pointerUpdateKind,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers,
|
||||
Microsoft.Terminal.Core.Point pixelPosition);
|
||||
|
||||
629
src/cascadia/TerminalControl/FlatC.cpp
Normal file
629
src/cascadia/TerminalControl/FlatC.cpp
Normal file
@@ -0,0 +1,629 @@
|
||||
#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 "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)
|
||||
{
|
||||
_TerminalOutputHandlers(winrt::to_hstring(data));
|
||||
}
|
||||
};
|
||||
|
||||
struct CsBridgeTerminalSettings : winrt::implements<CsBridgeTerminalSettings, IControlSettings, ICoreSettings, IControlAppearance, ICoreAppearance>
|
||||
{
|
||||
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;
|
||||
|
||||
winrt::Microsoft::Terminal::Core::Color GetColorTableEntry(int32_t index) noexcept
|
||||
{
|
||||
return til::color{ til::at(_theme.ColorTable, index) };
|
||||
}
|
||||
|
||||
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(winrt::hstring, ProfileName);
|
||||
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::Microsoft::Terminal::Control::IKeyBindings, KeyBindings, nullptr);
|
||||
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(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:
|
||||
if (_interactivity->MouseWheel(getControlKeyState(), GET_WHEEL_DELTA_WPARAM(wParam), 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;
|
||||
}
|
||||
|
||||
HRESULT SetCursorVisible(const bool visible)
|
||||
{
|
||||
_core->CursorOn(visible);
|
||||
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);
|
||||
|
||||
int blinkTime = GetCaretBlinkTime();
|
||||
auto animationsEnabled = TRUE;
|
||||
SystemParametersInfoW(SPI_GETCLIENTAREAANIMATION, 0, &animationsEnabled, 0);
|
||||
_core->CursorBlinkTime(std::chrono::milliseconds(blinkTime == INFINITE ? 0 : blinkTime));
|
||||
_core->VtBlinkEnabled(animationsEnabled);
|
||||
|
||||
_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());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
__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
|
||||
64
src/cascadia/TerminalControl/FlatC.h
Normal file
64
src/cascadia/TerminalControl/FlatC.h
Normal file
@@ -0,0 +1,64 @@
|
||||
// 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) \
|
||||
XX(SetCursorVisible, const bool, visible)
|
||||
|
||||
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);
|
||||
};
|
||||
@@ -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>();
|
||||
@@ -1942,21 +1935,19 @@ 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.
|
||||
// I suspect the point.Position() would be correct.
|
||||
const auto contactRect = point.Properties().ContactRect();
|
||||
_interactivity.TouchPressed({ contactRect.X, contactRect.Y });
|
||||
til::point newTouchPoint{ til::math::rounding, contactRect.X, contactRect.Y };
|
||||
_interactivity.TouchPressed(newTouchPoint.to_core_point());
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto cursorPosition = point.Position();
|
||||
_interactivity.PointerPressed(TermControl::GetPressedMouseButtons(point),
|
||||
_interactivity.PointerPressed(point.PointerId(),
|
||||
TermControl::GetPressedMouseButtons(point),
|
||||
TermControl::GetPointerUpdateKind(point),
|
||||
point.Timestamp(),
|
||||
ControlKeyStates{ args.KeyModifiers() },
|
||||
@@ -1995,51 +1986,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
if (type == Windows::Devices::Input::PointerDeviceType::Mouse ||
|
||||
type == Windows::Devices::Input::PointerDeviceType::Pen)
|
||||
{
|
||||
auto suppressFurtherHandling = _interactivity.PointerMoved(TermControl::GetPressedMouseButtons(point),
|
||||
auto suppressFurtherHandling = _interactivity.PointerMoved(point.PointerId(),
|
||||
TermControl::GetPressedMouseButtons(point),
|
||||
TermControl::GetPointerUpdateKind(point),
|
||||
ControlKeyStates(args.KeyModifiers()),
|
||||
_focused,
|
||||
pixelPosition,
|
||||
_pointerPressedInBounds);
|
||||
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
pixelPosition);
|
||||
/* TODO(DH) */ UNREFERENCED_PARAMETER(suppressFurtherHandling);
|
||||
}
|
||||
else if (type == Windows::Devices::Input::PointerDeviceType::Touch)
|
||||
{
|
||||
const auto contactRect = point.Properties().ContactRect();
|
||||
_interactivity.TouchMoved({ contactRect.X, contactRect.Y }, _focused);
|
||||
til::point newTouchPoint{ til::math::rounding, contactRect.X, contactRect.Y };
|
||||
|
||||
_interactivity.TouchMoved(newTouchPoint.to_core_point());
|
||||
}
|
||||
|
||||
args.Handled(true);
|
||||
@@ -2059,8 +2018,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();
|
||||
@@ -2072,7 +2029,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
if (type == Windows::Devices::Input::PointerDeviceType::Mouse ||
|
||||
type == Windows::Devices::Input::PointerDeviceType::Pen)
|
||||
{
|
||||
_interactivity.PointerReleased(TermControl::GetPressedMouseButtons(point),
|
||||
_interactivity.PointerReleased(point.PointerId(),
|
||||
TermControl::GetPressedMouseButtons(point),
|
||||
TermControl::GetPointerUpdateKind(point),
|
||||
ControlKeyStates(args.KeyModifiers()),
|
||||
pixelPosition);
|
||||
@@ -2082,8 +2040,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_interactivity.TouchReleased();
|
||||
}
|
||||
|
||||
_TryStopAutoScroll(ptr.PointerId());
|
||||
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
@@ -2238,86 +2194,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
|
||||
@@ -2618,7 +2494,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,
|
||||
@@ -2766,7 +2641,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);
|
||||
|
||||
@@ -3016,20 +2892,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
|
||||
|
||||
@@ -301,14 +301,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;
|
||||
@@ -386,8 +378,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);
|
||||
|
||||
@@ -396,10 +386,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;
|
||||
@@ -410,8 +396,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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -312,10 +312,13 @@ namespace ControlUnitTests
|
||||
|
||||
const til::size fontSize{ 9, 21 };
|
||||
|
||||
interactivity->GotFocus();
|
||||
|
||||
Log::Comment(L"Click on the terminal");
|
||||
const til::point terminalPosition0{ 0, 0 };
|
||||
const auto cursorPosition0 = terminalPosition0 * fontSize;
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -328,29 +331,28 @@ namespace ControlUnitTests
|
||||
// move not quite a whole cell, but enough to start a selection
|
||||
const til::point terminalPosition1{ 0, 0 };
|
||||
const til::point cursorPosition1{ 6, 0 };
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
cursorPosition1.to_core_point());
|
||||
Log::Comment(L"Verify that there's one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
|
||||
Log::Comment(L"Drag the mouse down a whole row");
|
||||
const til::point terminalPosition2{ 1, 1 };
|
||||
const auto cursorPosition2 = terminalPosition2 * fontSize;
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition2.to_core_point(),
|
||||
true);
|
||||
cursorPosition2.to_core_point());
|
||||
Log::Comment(L"Verify that there's now two selections (one on each row)");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
|
||||
Log::Comment(L"Release the mouse");
|
||||
interactivity->PointerReleased(noMouseDown,
|
||||
interactivity->PointerReleased(0,
|
||||
noMouseDown,
|
||||
WM_LBUTTONUP, //pointerUpdateKind
|
||||
modifiers,
|
||||
cursorPosition2.to_core_point());
|
||||
@@ -360,7 +362,8 @@ namespace ControlUnitTests
|
||||
Log::Comment(L"click outside the current selection");
|
||||
const til::point terminalPosition3{ 2, 2 };
|
||||
const auto cursorPosition3 = terminalPosition3 * fontSize;
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -371,12 +374,11 @@ namespace ControlUnitTests
|
||||
Log::Comment(L"Drag the mouse");
|
||||
const til::point terminalPosition4{ 3, 2 };
|
||||
const auto cursorPosition4 = terminalPosition4 * fontSize;
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition4.to_core_point(),
|
||||
true);
|
||||
cursorPosition4.to_core_point());
|
||||
Log::Comment(L"Verify that there's now one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
}
|
||||
@@ -407,10 +409,13 @@ namespace ControlUnitTests
|
||||
|
||||
const til::size fontSize{ 9, 21 };
|
||||
|
||||
interactivity->GotFocus();
|
||||
|
||||
Log::Comment(L"Click on the terminal");
|
||||
const til::point terminalPosition0{ 5, 5 };
|
||||
const auto cursorPosition0{ terminalPosition0 * fontSize };
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -425,12 +430,11 @@ namespace ControlUnitTests
|
||||
Log::Comment(L"Drag the mouse just a little");
|
||||
// move not quite a whole cell, but enough to start a selection
|
||||
const auto cursorPosition1{ cursorPosition0 + til::point{ 6, 0 } };
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
cursorPosition1.to_core_point());
|
||||
Log::Comment(L"Verify that there's one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
|
||||
@@ -558,9 +562,12 @@ namespace ControlUnitTests
|
||||
|
||||
const til::size fontSize{ 9, 21 };
|
||||
|
||||
interactivity->GotFocus();
|
||||
|
||||
Log::Comment(L"Click on the terminal");
|
||||
const til::point cursorPosition0{ 6, 0 };
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -574,12 +581,11 @@ namespace ControlUnitTests
|
||||
|
||||
Log::Comment(L"Drag the mouse a lot. This simulates dragging the mouse real fast.");
|
||||
const til::point cursorPosition1{ 6 + fontSize.width * 2, 0 };
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
cursorPosition1.to_core_point());
|
||||
Log::Comment(L"Verify that there's one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
|
||||
@@ -601,10 +607,13 @@ namespace ControlUnitTests
|
||||
const auto leftMouseDown{ Control::MouseButtonState::IsLeftButtonDown };
|
||||
const Control::MouseButtonState noMouseDown{};
|
||||
|
||||
interactivity->GotFocus();
|
||||
|
||||
const til::size fontSize{ 9, 21 };
|
||||
Log::Comment(L"Click on the terminal");
|
||||
const til::point cursorPosition0{ 6, 0 };
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -618,12 +627,11 @@ namespace ControlUnitTests
|
||||
|
||||
Log::Comment(L"Drag the mouse a lot. This simulates dragging the mouse real fast.");
|
||||
const til::point cursorPosition1{ 6 + fontSize.width * 2, 0 };
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
cursorPosition1.to_core_point());
|
||||
Log::Comment(L"Verify that there's one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
|
||||
@@ -633,7 +641,8 @@ namespace ControlUnitTests
|
||||
til::point expectedEnd{ 3, 0 }; // add 1 to x-coordinate because end is exclusive
|
||||
VERIFY_ARE_EQUAL(expectedEnd, core->_terminal->GetSelectionEnd());
|
||||
|
||||
interactivity->PointerReleased(noMouseDown,
|
||||
interactivity->PointerReleased(0,
|
||||
noMouseDown,
|
||||
WM_LBUTTONUP,
|
||||
modifiers,
|
||||
cursorPosition1.to_core_point());
|
||||
@@ -643,12 +652,11 @@ namespace ControlUnitTests
|
||||
|
||||
Log::Comment(L"Simulate dragging the mouse into the control, without first clicking into the control");
|
||||
const til::point cursorPosition2{ fontSize.width * 10, 0 };
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition2.to_core_point(),
|
||||
false);
|
||||
cursorPosition2.to_core_point());
|
||||
|
||||
Log::Comment(L"The selection should be unchanged.");
|
||||
VERIFY_ARE_EQUAL(expectedAnchor, core->_terminal->GetSelectionAnchor());
|
||||
@@ -675,6 +683,8 @@ namespace ControlUnitTests
|
||||
auto expectedViewHeight = 20;
|
||||
auto expectedBufferHeight = 20;
|
||||
|
||||
interactivity->GotFocus();
|
||||
|
||||
auto scrollChangedHandler = [&](auto&&, const Control::ScrollPositionChangedArgs& args) mutable {
|
||||
VERIFY_ARE_EQUAL(expectedTop, args.ViewTop());
|
||||
VERIFY_ARE_EQUAL(expectedViewHeight, args.ViewHeight());
|
||||
@@ -721,7 +731,8 @@ namespace ControlUnitTests
|
||||
Log::Comment(L"Click on the terminal");
|
||||
const til::point terminalPosition0{ 4, 4 };
|
||||
const auto cursorPosition0 = terminalPosition0 * fontSize;
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -734,12 +745,11 @@ namespace ControlUnitTests
|
||||
// move the mouse as if to make a selection
|
||||
const til::point terminalPosition1{ 10, 4 };
|
||||
const auto cursorPosition1 = terminalPosition1 * fontSize;
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
cursorPosition1.to_core_point());
|
||||
Log::Comment(L"Verify that there's still no selection");
|
||||
VERIFY_IS_FALSE(core->HasSelection());
|
||||
}
|
||||
@@ -769,10 +779,13 @@ namespace ControlUnitTests
|
||||
|
||||
const til::size fontSize{ 9, 21 };
|
||||
|
||||
interactivity->GotFocus();
|
||||
|
||||
Log::Comment(L"Click on the terminal");
|
||||
const til::point terminalPosition0{ 5, 5 };
|
||||
const auto cursorPosition0{ terminalPosition0 * fontSize };
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -787,12 +800,11 @@ namespace ControlUnitTests
|
||||
Log::Comment(L"Drag the mouse just a little");
|
||||
// move not quite a whole cell, but enough to start a selection
|
||||
const auto cursorPosition1{ cursorPosition0 + til::point{ 6, 0 } };
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
cursorPosition1.to_core_point());
|
||||
Log::Comment(L"Verify that there's one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
|
||||
@@ -849,12 +861,11 @@ namespace ControlUnitTests
|
||||
// character in the buffer (if, albeit in a new location).
|
||||
//
|
||||
// This helps test GH #14462, a regression from #10749.
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition0.to_core_point(),
|
||||
true);
|
||||
cursorPosition0.to_core_point());
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
{
|
||||
const auto anchor{ core->_terminal->GetSelectionAnchor() };
|
||||
@@ -875,12 +886,11 @@ namespace ControlUnitTests
|
||||
expectedAnchor.y -= 1;
|
||||
expectedEnd.y -= 1;
|
||||
VERIFY_ARE_EQUAL(scrollbackLength - 3, core->_terminal->GetScrollOffset());
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
cursorPosition1.to_core_point());
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
{
|
||||
const auto anchor{ core->_terminal->GetSelectionAnchor() };
|
||||
@@ -928,7 +938,8 @@ namespace ControlUnitTests
|
||||
const til::size fontSize{ 9, 21 };
|
||||
const til::point terminalPosition0{ 5, 5 };
|
||||
const auto cursorPosition0{ terminalPosition0 * fontSize };
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -977,7 +988,8 @@ namespace ControlUnitTests
|
||||
const til::size fontSize{ 9, 21 };
|
||||
const til::point terminalPosition0{ 5, 5 };
|
||||
const auto cursorPosition0{ terminalPosition0 * fontSize };
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -993,7 +1005,8 @@ namespace ControlUnitTests
|
||||
// The viewport is only 30 wide, so clamping 35 to the buffer size gets
|
||||
// us 29, which converted is (32 + 29 + 1) = 62 = '>'
|
||||
expectedOutput.push_back(L"\x1b[M >&");
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -1008,7 +1021,8 @@ namespace ControlUnitTests
|
||||
// will be clamped to the top line.
|
||||
|
||||
expectedOutput.push_back(L"\x1b[M &!"); // 5, 1
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -1024,7 +1038,8 @@ namespace ControlUnitTests
|
||||
VERIFY_ARE_EQUAL(0, core->ScrollOffset());
|
||||
Log::Comment(L" --- Click on a spot that's still outside the buffer ---");
|
||||
expectedOutput.push_back(L"\x1b[M >&");
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -1038,7 +1053,8 @@ namespace ControlUnitTests
|
||||
Log::Comment(L" --- Click on a spot that's NOW INSIDE the buffer ---");
|
||||
// (32 + 35 + 1) = 68 = 'D'
|
||||
expectedOutput.push_back(L"\x1b[M D&");
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
|
||||
@@ -85,18 +85,30 @@ try
|
||||
#endif
|
||||
return loader;
|
||||
}
|
||||
CATCH_FAIL_FAST()
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
return winrt::hstring{};
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
Reference in New Issue
Block a user