Only access ControlInteractivity through the projection (#10051)

## Summary of the Pull Request

This forces the `TermControl` to only use `ControlCore` and `ControlInteractivity` via their WinRT projections. We want this, because WinRT projections can be used across process boundaries. In the future, `ControlCore` and `ControlInteractivity` are going to be living in a different process entirely from `TermControl`. By enforcing this boundary now, we can make sure that they will work seamlessly in the future.

## References
* Tear-out: #1256
* Megathread: #5000
* Project: https://github.com/microsoft/terminal/projects/5

## PR Checklist
* [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760270
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated

## Detailed Description of the Pull Request / Additional comments

Most all this was just converting pure c++ types to winrt types when possible. I've added a couple helper projections with `til` converters, which made most of this really easy.

The "`MouseButtonState` needs to be composed of `Int32`s instead of `bool`s" is MENTAL. I have no idea why this is, but when I had the control OOP in the sample, that would crash when trying to de-marshal the bools. BODGY.

The biggest changes are in the way the UIA stuff is hooked up. The UiaEngine needs to be attached directly to the `Renderer`, and it can't be easily projected, so it needs to live next to the `ControlCore`. But the `TermControlAutomationPeer` needed the `UiaEngine` to help implement some interfaces.

Now, there's a new layer we've introduced. `InteractivityAutomationPeer` does the `ITextProvider`, `IControlAccessibilityInfo` and the `IUiaEventDispatcher` thing. `TermControlAutomationPeer` now has a 
`InteractivityAutomationPeer` stashed inside itself, so that it can ask the interactivity layer to do the real work. We still need the `TermControlAutomationPeer` though, to be able to attach to the real UI tree.

## Validation Steps Performed

The terminal behaves basically the same as before.

Most importantly, I whipped out Accessibility Insights, and the Terminal looks the same as before.
This commit is contained in:
Mike Griese 2021-07-19 11:59:30 -05:00 committed by GitHub
parent 8947909121
commit 7f3bc3cb04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 968 additions and 349 deletions

View File

@ -1129,7 +1129,7 @@ namespace winrt::TerminalApp::implementation
// - Gets the taskbar state value from the last active control
// Return Value:
// - The taskbar state of the last active control
size_t AppLogic::GetLastActiveControlTaskbarState()
uint64_t AppLogic::GetLastActiveControlTaskbarState()
{
if (_root)
{
@ -1142,7 +1142,7 @@ namespace winrt::TerminalApp::implementation
// - Gets the taskbar progress value from the last active control
// Return Value:
// - The taskbar progress of the last active control
size_t AppLogic::GetLastActiveControlTaskbarProgress()
uint64_t AppLogic::GetLastActiveControlTaskbarProgress()
{
if (_root)
{

View File

@ -89,8 +89,8 @@ namespace winrt::TerminalApp::implementation
void WindowCloseButtonClicked();
size_t GetLastActiveControlTaskbarState();
size_t GetLastActiveControlTaskbarProgress();
uint64_t GetLastActiveControlTaskbarState();
uint64_t GetLastActiveControlTaskbarProgress();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> ShowDialog(winrt::Windows::UI::Xaml::Controls::ContentDialog dialog);

View File

@ -2020,11 +2020,11 @@ namespace winrt::TerminalApp::implementation
// - Gets the taskbar state value from the last active control
// Return Value:
// - The taskbar state of the last active control
size_t TerminalPage::GetLastActiveControlTaskbarState()
uint64_t TerminalPage::GetLastActiveControlTaskbarState()
{
if (auto control{ _GetActiveControl() })
{
return gsl::narrow_cast<size_t>(control.TaskbarState());
return control.TaskbarState();
}
return {};
}
@ -2033,11 +2033,11 @@ namespace winrt::TerminalApp::implementation
// - Gets the taskbar progress value from the last active control
// Return Value:
// - The taskbar progress of the last active control
size_t TerminalPage::GetLastActiveControlTaskbarProgress()
uint64_t TerminalPage::GetLastActiveControlTaskbarProgress()
{
if (auto control{ _GetActiveControl() })
{
return gsl::narrow_cast<size_t>(control.TaskbarProgress());
return control.TaskbarProgress();
}
return {};
}

View File

@ -83,8 +83,8 @@ namespace winrt::TerminalApp::implementation
winrt::TerminalApp::IDialogPresenter DialogPresenter() const;
void DialogPresenter(winrt::TerminalApp::IDialogPresenter dialogPresenter);
size_t GetLastActiveControlTaskbarState();
size_t GetLastActiveControlTaskbarProgress();
uint64_t GetLastActiveControlTaskbarState();
uint64_t GetLastActiveControlTaskbarProgress();
void ShowKeyboardServiceWarning();
winrt::hstring KeyboardServiceDisabledText();

View File

@ -426,7 +426,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - Updates last hovered cell, renders / removes rendering of hyper-link if required
// Arguments:
// - terminalPosition: The terminal position of the pointer
void ControlCore::UpdateHoveredCell(const std::optional<til::point>& terminalPosition)
void ControlCore::SetHoveredCell(Core::Point pos)
{
_updateHoveredCell(std::optional<til::point>{ pos });
}
void ControlCore::ClearHoveredCell()
{
_updateHoveredCell(std::nullopt);
}
void ControlCore::_updateHoveredCell(const std::optional<til::point> terminalPosition)
{
if (terminalPosition == _lastHoveredCell)
{
@ -477,7 +486,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return winrt::hstring{ _terminal->GetHyperlinkAtPosition(pos) };
}
winrt::hstring ControlCore::GetHoveredUriText() const
winrt::hstring ControlCore::HoveredUriText() const
{
auto lock = _terminal->LockForReading(); // Lock for the duration of our reads.
if (_lastHoveredCell.has_value())
@ -487,9 +496,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return {};
}
std::optional<til::point> ControlCore::GetHoveredCell() const
Windows::Foundation::IReference<Core::Point> ControlCore::HoveredCell() const
{
return _lastHoveredCell;
return _lastHoveredCell.has_value() ? Windows::Foundation::IReference<Core::Point>{ _lastHoveredCell.value() } : nullptr;
}
// Method Description:
@ -895,6 +904,24 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _actualFont;
}
winrt::Windows::Foundation::Size ControlCore::FontSize() const noexcept
{
const auto fontSize = GetFont().GetSize();
return {
::base::saturated_cast<float>(fontSize.X),
::base::saturated_cast<float>(fontSize.Y)
};
}
winrt::hstring ControlCore::FontFaceName() const noexcept
{
return winrt::hstring{ GetFont().GetFaceName() };
}
uint16_t ControlCore::FontWeight() const noexcept
{
return static_cast<uint16_t>(GetFont().GetWeight());
}
til::size ControlCore::FontSizeInDips() const
{
const til::size fontSize{ GetFont().GetSize() };
@ -1077,10 +1104,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _settings.CopyOnSelect();
}
std::vector<std::wstring> ControlCore::SelectedText(bool trimTrailingWhitespace) const
Windows::Foundation::Collections::IVector<winrt::hstring> ControlCore::SelectedText(bool trimTrailingWhitespace) const
{
// RetrieveSelectedTextFromBuffer will lock while it's reading
return _terminal->RetrieveSelectedTextFromBuffer(trimTrailingWhitespace).text;
const auto internalResult{ _terminal->RetrieveSelectedTextFromBuffer(trimTrailingWhitespace).text };
auto result = winrt::single_threaded_vector<winrt::hstring>();
for (const auto& row : internalResult)
{
result.Append(winrt::hstring{ row });
}
return result;
}
::Microsoft::Console::Types::IUiaData* ControlCore::GetUiaData() const
@ -1124,7 +1159,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
void ControlCore::SetBackgroundOpacity(const float opacity)
void ControlCore::SetBackgroundOpacity(const double opacity)
{
if (_renderEngine)
{
@ -1176,7 +1211,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
HANDLE ControlCore::GetSwapChainHandle() const
uint64_t ControlCore::SwapChainHandle() const
{
// This is called by:
// * TermControl::RenderEngineSwapChainChanged, who is only registered
@ -1184,7 +1219,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// * TermControl::_InitializeTerminal, after the call to Initialize, for
// _AttachDxgiSwapChainToXaml.
// In both cases, we'll have a _renderEngine by then.
return _renderEngine->GetSwapChainHandle();
return reinterpret_cast<uint64_t>(_renderEngine->GetSwapChainHandle());
}
void ControlCore::_rendererWarning(const HRESULT hr)

View File

@ -48,15 +48,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void UpdateAppearance(const IControlAppearance& newAppearance);
void SizeChanged(const double width, const double height);
void ScaleChanged(const double scale);
HANDLE GetSwapChainHandle() const;
uint64_t SwapChainHandle() const;
void AdjustFontSize(int fontSizeDelta);
void ResetFontSize();
FontInfo GetFont() const;
til::size FontSizeInDips() const;
winrt::Windows::Foundation::Size FontSize() const noexcept;
winrt::hstring FontFaceName() const noexcept;
uint16_t FontWeight() const noexcept;
til::color BackgroundColor() const;
void SetBackgroundOpacity(const float opacity);
void SetBackgroundOpacity(const double opacity);
void SendInput(const winrt::hstring& wstr);
void PasteText(const winrt::hstring& hstr);
@ -67,10 +71,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void ResumeRendering();
void UpdatePatternLocations();
void UpdateHoveredCell(const std::optional<til::point>& terminalPosition);
void SetHoveredCell(Core::Point terminalPosition);
void ClearHoveredCell();
winrt::hstring GetHyperlink(const til::point position) const;
winrt::hstring GetHoveredUriText() const;
std::optional<til::point> GetHoveredCell() const;
winrt::hstring HoveredUriText() const;
Windows::Foundation::IReference<Core::Point> HoveredCell() const;
::Microsoft::Console::Types::IUiaData* GetUiaData() const;
@ -119,7 +124,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool HasSelection() const;
bool CopyOnSelect() const;
std::vector<std::wstring> SelectedText(bool trimTrailingWhitespace) const;
Windows::Foundation::Collections::IVector<winrt::hstring> SelectedText(bool trimTrailingWhitespace) const;
void SetSelectionAnchor(til::point const& position);
void SetEndSelectionPoint(til::point const& position);
@ -232,6 +237,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _raiseReadOnlyWarning();
void _updateAntiAliasingMode(::Microsoft::Console::Render::DxEngine* const dxEngine);
void _connectionOutputHandler(const hstring& hstr);
void _updateHoveredCell(const std::optional<til::point> terminalPosition);
friend class ControlUnitTests::ControlCoreTests;
friend class ControlUnitTests::ControlInteractivityTests;

View File

@ -8,9 +8,97 @@ import "EventArgs.idl";
namespace Microsoft.Terminal.Control
{
// This is a mirror of
// ::Microsoft::Console::VirtualTerminal::TerminalInput::MouseButtonState,
// but projectable.
// !! LOAD BEARING !! If you make this a struct with Booleans (like they
// make the most sense as), then the app will crash trying to toss one of
// these across the process boundary. I haven't the damndest idea why.
[flags]
enum MouseButtonState
{
IsLeftButtonDown = 0x1,
IsMiddleButtonDown = 0x2,
IsRightButtonDown = 0x4
};
[default_interface] runtimeclass ControlCore : ICoreState
{
ControlCore(IControlSettings settings,
Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
Boolean Initialize(Double actualWidth,
Double actualHeight,
Double compositionScale);
void UpdateSettings(IControlSettings settings);
void UpdateAppearance(IControlAppearance appearance);
UInt64 SwapChainHandle { get; };
Windows.Foundation.Size FontSize { get; };
String FontFaceName { get; };
UInt16 FontWeight { get; };
Boolean TrySendKeyEvent(Int16 vkey,
Int16 scanCode,
Microsoft.Terminal.Core.ControlKeyStates modifiers,
Boolean keyDown);
Boolean SendCharEvent(Char ch,
Int16 scanCode,
Microsoft.Terminal.Core.ControlKeyStates modifiers);
void SendInput(String text);
void PasteText(String text);
void SetHoveredCell(Microsoft.Terminal.Core.Point terminalPosition);
void ClearHoveredCell();
void ResetFontSize();
void AdjustFontSize(Int32 fontSizeDelta);
void SizeChanged(Double width, Double height);
void ScaleChanged(Double scale);
void ToggleShaderEffects();
void ToggleReadOnlyMode();
Microsoft.Terminal.Core.Point CursorPosition { get; };
void ResumeRendering();
void BlinkAttributeTick();
void UpdatePatternLocations();
void Search(String text, Boolean goForward, Boolean caseSensitive);
void SetBackgroundOpacity(Double opacity);
Microsoft.Terminal.Core.Color BackgroundColor { get; };
Boolean HasSelection { get; };
IVector<String> SelectedText(Boolean trimTrailingWhitespace);
String HoveredUriText { get; };
Windows.Foundation.IReference<Microsoft.Terminal.Core.Point> HoveredCell { get; };
void Close();
void BlinkCursor();
Boolean IsInReadOnlyMode { get; };
Boolean CursorOn;
void EnablePainting();
event FontSizeChangedEventArgs FontSizeChanged;
event Windows.Foundation.TypedEventHandler<Object, CopyToClipboardEventArgs> CopyToClipboard;
event Windows.Foundation.TypedEventHandler<Object, TitleChangedEventArgs> TitleChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> WarningBell;
event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> BackgroundColorChanged;
event Windows.Foundation.TypedEventHandler<Object, ScrollPositionChangedArgs> ScrollPositionChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> CursorPositionChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> TaskbarProgressChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> ConnectionStateChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> HoveredHyperlinkChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> RendererEnteredErrorState;
event Windows.Foundation.TypedEventHandler<Object, Object> SwapChainChanged;
event Windows.Foundation.TypedEventHandler<Object, RendererWarningArgs> RendererWarning;
event Windows.Foundation.TypedEventHandler<Object, NoticeEventArgs> RaiseNotice;
event Windows.Foundation.TypedEventHandler<Object, TransparencyChangedEventArgs> TransparencyChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> ReceivedOutput;
};
}

View File

@ -8,13 +8,15 @@
#include <unicode.hpp>
#include <Utf16Parser.hpp>
#include <Utils.h>
#include <WinUser.h>
#include <LibraryResources.h>
#include "../../types/inc/GlyphWidth.hpp"
#include "../../types/inc/Utils.hpp"
#include "../../buffer/out/search.h"
#include "InteractivityAutomationPeer.h"
#include "ControlInteractivity.g.cpp"
#include "TermControl.h"
using namespace ::Microsoft::Console::Types;
using namespace ::Microsoft::Console::VirtualTerminal;
@ -27,6 +29,15 @@ static constexpr unsigned int MAX_CLICK_COUNT = 3;
namespace winrt::Microsoft::Terminal::Control::implementation
{
static constexpr TerminalInput::MouseButtonState toInternalMouseState(const Control::MouseButtonState& state)
{
return TerminalInput::MouseButtonState{
WI_IsFlagSet(state, MouseButtonState::IsLeftButtonDown),
WI_IsFlagSet(state, MouseButtonState::IsMiddleButtonDown),
WI_IsFlagSet(state, MouseButtonState::IsRightButtonDown)
};
}
ControlInteractivity::ControlInteractivity(IControlSettings settings,
TerminalConnection::ITerminalConnection connection) :
_touchAnchor{ std::nullopt },
@ -37,6 +48,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_core = winrt::make_self<ControlCore>(settings, connection);
}
// Method Description:
// - Updates our internal settings. These settings should be
// interactivity-specific. Right now, we primarily update _rowsToScroll
// with the current value of SPI_GETWHEELSCROLLLINES.
// Arguments:
// - <none>
// Return Value:
// - <none>
void ControlInteractivity::UpdateSettings()
{
_updateSystemParameterSettings();
@ -50,9 +69,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_multiClickTimer = GetDoubleClickTime() * 1000;
}
winrt::com_ptr<ControlCore> ControlInteractivity::GetCore()
Control::ControlCore ControlInteractivity::Core()
{
return _core;
return *_core;
}
// Method Description:
@ -85,11 +104,24 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _multiClickCounter;
}
void ControlInteractivity::GainFocus()
void ControlInteractivity::GotFocus()
{
if (_uiaEngine.get())
{
THROW_IF_FAILED(_uiaEngine->Enable());
}
_updateSystemParameterSettings();
}
void ControlInteractivity::LostFocus()
{
if (_uiaEngine.get())
{
THROW_IF_FAILED(_uiaEngine->Disable());
}
}
// Method Description
// - Updates internal params based on system parameters
void ControlInteractivity::_updateSystemParameterSettings() noexcept
@ -156,7 +188,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_core->PasteText(winrt::hstring{ wstr });
}
void ControlInteractivity::PointerPressed(TerminalInput::MouseButtonState buttonState,
void ControlInteractivity::PointerPressed(Control::MouseButtonState buttonState,
const unsigned int pointerUpdateKind,
const uint64_t timestamp,
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
@ -170,7 +202,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// GH#9396: we prioritize hyper-link over VT mouse events
auto hyperlink = _core->GetHyperlink(terminalPosition);
if (buttonState.isLeftButtonDown &&
if (WI_IsFlagSet(buttonState, MouseButtonState::IsLeftButtonDown) &&
ctrlEnabled && !hyperlink.empty())
{
const auto clickCount = _numberOfClicks(pixelPosition, timestamp);
@ -182,9 +214,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
else if (_canSendVTMouseInput(modifiers))
{
_core->SendMouseEvent(terminalPosition, pointerUpdateKind, modifiers, 0, buttonState);
_core->SendMouseEvent(terminalPosition, pointerUpdateKind, modifiers, 0, toInternalMouseState(buttonState));
}
else if (buttonState.isLeftButtonDown)
else if (WI_IsFlagSet(buttonState, MouseButtonState::IsLeftButtonDown))
{
const auto clickCount = _numberOfClicks(pixelPosition, timestamp);
// This formula enables the number of clicks to cycle properly
@ -219,7 +251,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_singleClickTouchdownPos = std::nullopt;
}
}
else if (buttonState.isRightButtonDown)
else if (WI_IsFlagSet(buttonState, MouseButtonState::IsRightButtonDown))
{
// CopyOnSelect right click always pastes
if (_core->CopyOnSelect() || !_core->HasSelection())
@ -238,7 +270,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_touchAnchor = contactPoint;
}
void ControlInteractivity::PointerMoved(TerminalInput::MouseButtonState buttonState,
void ControlInteractivity::PointerMoved(Control::MouseButtonState buttonState,
const unsigned int pointerUpdateKind,
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
const bool focused,
@ -249,9 +281,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Short-circuit isReadOnly check to avoid warning dialog
if (focused && !_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers))
{
_core->SendMouseEvent(terminalPosition, pointerUpdateKind, modifiers, 0, buttonState);
_core->SendMouseEvent(terminalPosition, pointerUpdateKind, modifiers, 0, toInternalMouseState(buttonState));
}
else if (focused && buttonState.isLeftButtonDown)
else if (focused && WI_IsFlagSet(buttonState, MouseButtonState::IsLeftButtonDown))
{
if (_singleClickTouchdownPos)
{
@ -279,7 +311,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
SetEndSelectionPoint(pixelPosition);
}
_core->UpdateHoveredCell(terminalPosition);
_core->SetHoveredCell(terminalPosition);
}
void ControlInteractivity::TouchMoved(const til::point newTouchPoint,
@ -319,7 +351,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
void ControlInteractivity::PointerReleased(TerminalInput::MouseButtonState buttonState,
void ControlInteractivity::PointerReleased(Control::MouseButtonState buttonState,
const unsigned int pointerUpdateKind,
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
const til::point pixelPosition)
@ -328,7 +360,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Short-circuit isReadOnly check to avoid warning dialog
if (!_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers))
{
_core->SendMouseEvent(terminalPosition, pointerUpdateKind, modifiers, 0, buttonState);
_core->SendMouseEvent(terminalPosition, pointerUpdateKind, modifiers, 0, toInternalMouseState(buttonState));
return;
}
@ -366,7 +398,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool ControlInteractivity::MouseWheel(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
const int32_t delta,
const til::point pixelPosition,
const TerminalInput::MouseButtonState state)
const Control::MouseButtonState buttonState)
{
const til::point terminalPosition = _getTerminalPosition(pixelPosition);
@ -382,7 +414,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
WM_MOUSEWHEEL,
modifiers,
::base::saturated_cast<short>(delta),
state);
toInternalMouseState(buttonState));
}
const auto ctrlPressed = modifiers.IsCtrlPressed();
@ -398,7 +430,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
else
{
_mouseScrollHandler(delta, pixelPosition, state.isLeftButtonDown);
_mouseScrollHandler(delta, pixelPosition, WI_IsFlagSet(buttonState, MouseButtonState::IsLeftButtonDown));
}
return false;
}
@ -557,4 +589,36 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Convert the location in pixels to characters within the current viewport.
return til::point{ pixelPosition / fontSize };
}
// Method Description:
// - Creates an automation peer for the Terminal Control, enabling
// accessibility on our control.
// - Our implementation implements the ITextProvider pattern, and the
// IControlAccessibilityInfo, to connect to the UiaEngine, which must be
// attached to the core's renderer.
// - The TermControlAutomationPeer will connect this to the UI tree.
// Arguments:
// - None
// Return Value:
// - The automation peer for our control
Control::InteractivityAutomationPeer ControlInteractivity::OnCreateAutomationPeer()
try
{
auto autoPeer = winrt::make_self<implementation::InteractivityAutomationPeer>(this);
_uiaEngine = std::make_unique<::Microsoft::Console::Render::UiaEngine>(autoPeer.get());
_core->AttachUiaEngine(_uiaEngine.get());
return *autoPeer;
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
return nullptr;
}
::Microsoft::Console::Types::IUiaData* ControlInteractivity::GetUiaData() const
{
return _core->GetUiaData();
}
}

View File

@ -23,11 +23,6 @@
#include "ControlCore.h"
namespace Microsoft::Console::VirtualTerminal
{
struct MouseButtonState;
}
namespace ControlUnitTests
{
class ControlCoreTests;
@ -42,20 +37,24 @@ namespace winrt::Microsoft::Terminal::Control::implementation
ControlInteractivity(IControlSettings settings,
TerminalConnection::ITerminalConnection connection);
void GainFocus();
void GotFocus();
void LostFocus();
void UpdateSettings();
void Initialize();
winrt::com_ptr<ControlCore> GetCore();
Control::ControlCore Core();
Control::InteractivityAutomationPeer OnCreateAutomationPeer();
::Microsoft::Console::Types::IUiaData* GetUiaData() const;
#pragma region Input Methods
void PointerPressed(::Microsoft::Console::VirtualTerminal::TerminalInput::MouseButtonState buttonState,
void PointerPressed(Control::MouseButtonState buttonState,
const unsigned int pointerUpdateKind,
const uint64_t timestamp,
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
const til::point pixelPosition);
void TouchPressed(const til::point contactPoint);
void PointerMoved(::Microsoft::Console::VirtualTerminal::TerminalInput::MouseButtonState buttonState,
void PointerMoved(Control::MouseButtonState buttonState,
const unsigned int pointerUpdateKind,
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
const bool focused,
@ -63,7 +62,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void TouchMoved(const til::point newTouchPoint,
const bool focused);
void PointerReleased(::Microsoft::Console::VirtualTerminal::TerminalInput::MouseButtonState buttonState,
void PointerReleased(Control::MouseButtonState buttonState,
const unsigned int pointerUpdateKind,
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
const til::point pixelPosition);
@ -72,7 +71,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool MouseWheel(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
const int32_t delta,
const til::point pixelPosition,
const ::Microsoft::Console::VirtualTerminal::TerminalInput::MouseButtonState state);
const Control::MouseButtonState state);
void UpdateScrollbar(const double newValue);
@ -83,7 +82,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void RequestPasteTextFromClipboard();
void SetEndSelectionPoint(const til::point pixelPosition);
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs);
TYPED_EVENT(ScrollPositionChanged, IInspectable, Control::ScrollPositionChangedArgs);
private:
// NOTE: _uiaEngine must be ordered before _core.
//
// ControlCore::AttachUiaEngine receives a IRenderEngine as a raw pointer, which we own.
// We must ensure that we first destroy the ControlCore before the UiaEngine instance
// in order to safely resolve this unsafe pointer dependency. Otherwise a deallocated
// IRenderEngine is accessed when ControlCore calls Renderer::TriggerTeardown.
// (C++ class members are destroyed in reverse order.)
std::unique_ptr<::Microsoft::Console::Render::UiaEngine> _uiaEngine;
winrt::com_ptr<ControlCore> _core{ nullptr };
unsigned int _rowsToScroll;
double _internalScrollbarPosition{ 0.0 };
@ -129,10 +141,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _sendPastedTextToConnection(std::wstring_view wstr);
til::point _getTerminalPosition(const til::point& pixelPosition);
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs);
TYPED_EVENT(ScrollPositionChanged, IInspectable, Control::ScrollPositionChangedArgs);
friend class ControlUnitTests::ControlCoreTests;
friend class ControlUnitTests::ControlInteractivityTests;
};

View File

@ -5,6 +5,8 @@ import "ICoreState.idl";
import "IControlSettings.idl";
import "ControlCore.idl";
import "EventArgs.idl";
import "InteractivityAutomationPeer.idl";
namespace Microsoft.Terminal.Control
{
@ -13,5 +15,51 @@ namespace Microsoft.Terminal.Control
{
ControlInteractivity(IControlSettings settings,
Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
ControlCore Core { get; };
void UpdateSettings();
void Initialize();
void GotFocus();
void LostFocus();
InteractivityAutomationPeer OnCreateAutomationPeer();
Boolean CopySelectionToClipboard(Boolean singleLine, Windows.Foundation.IReference<CopyFormat> formats);
void RequestPasteTextFromClipboard();
void SetEndSelectionPoint(Microsoft.Terminal.Core.Point point);
void PointerPressed(MouseButtonState buttonState,
UInt32 pointerUpdateKind,
UInt64 timestamp,
Microsoft.Terminal.Core.ControlKeyStates modifiers,
Microsoft.Terminal.Core.Point pixelPosition);
void TouchPressed(Microsoft.Terminal.Core.Point contactPoint);
void PointerMoved(MouseButtonState buttonState,
UInt32 pointerUpdateKind,
Microsoft.Terminal.Core.ControlKeyStates modifiers,
Boolean focused,
Microsoft.Terminal.Core.Point pixelPosition);
void TouchMoved(Microsoft.Terminal.Core.Point newTouchPoint,
Boolean focused);
void PointerReleased(MouseButtonState buttonState,
UInt32 pointerUpdateKind,
Microsoft.Terminal.Core.ControlKeyStates modifiers,
Microsoft.Terminal.Core.Point pixelPosition);
void TouchReleased();
Boolean MouseWheel(Microsoft.Terminal.Core.ControlKeyStates modifiers,
Int32 delta,
Microsoft.Terminal.Core.Point pixelPosition,
MouseButtonState state);
void UpdateScrollbar(Double newValue);
event Windows.Foundation.TypedEventHandler<Object, OpenHyperlinkEventArgs> OpenHyperlink;
event Windows.Foundation.TypedEventHandler<Object, ScrollPositionChangedArgs> ScrollPositionChanged;
event Windows.Foundation.TypedEventHandler<Object, PasteFromClipboardEventArgs> PasteFromClipboard;
};
}

View File

@ -17,6 +17,7 @@ namespace Microsoft.Terminal.Control
Int32 ScrollOffset { get; };
Int32 ViewHeight { get; };
Int32 BufferHeight { get; };
Boolean BracketedPasteEnabled { get; };

View File

@ -0,0 +1,208 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include <UIAutomationCore.h>
#include <LibraryResources.h>
#include "InteractivityAutomationPeer.h"
#include "InteractivityAutomationPeer.g.cpp"
#include "XamlUiaTextRange.h"
#include "../types/UiaTracing.h"
using namespace Microsoft::Console::Types;
using namespace winrt::Windows::UI::Xaml::Automation::Peers;
using namespace winrt::Windows::Graphics::Display;
namespace UIA
{
using ::ITextRangeProvider;
using ::SupportedTextSelection;
}
namespace XamlAutomation
{
using winrt::Windows::UI::Xaml::Automation::SupportedTextSelection;
using winrt::Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple;
using winrt::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider;
}
namespace winrt::Microsoft::Terminal::Control::implementation
{
InteractivityAutomationPeer::InteractivityAutomationPeer(Control::implementation::ControlInteractivity* owner) :
_interactivity{ owner }
{
THROW_IF_FAILED(::Microsoft::WRL::MakeAndInitialize<::Microsoft::Terminal::TermControlUiaProvider>(&_uiaProvider, _interactivity->GetUiaData(), this));
};
void InteractivityAutomationPeer::SetControlBounds(const Windows::Foundation::Rect bounds)
{
_controlBounds = til::rectangle{ til::math::rounding, bounds };
}
void InteractivityAutomationPeer::SetControlPadding(const Core::Padding padding)
{
_controlPadding = padding;
}
// Method Description:
// - Signals the ui automation client that the terminal's selection has
// changed and should be updated
// - We will raise a new event, for out embedding control to be able to
// raise the event. AutomationPeer by itself doesn't hook up to the
// eventing mechanism, we need the FrameworkAutomationPeer to do that.
// Arguments:
// - <none>
// Return Value:
// - <none>
void InteractivityAutomationPeer::SignalSelectionChanged()
{
_SelectionChangedHandlers(*this, nullptr);
}
// Method Description:
// - Signals the ui automation client that the terminal's output has changed
// and should be updated
// - We will raise a new event, for out embedding control to be able to
// raise the event. AutomationPeer by itself doesn't hook up to the
// eventing mechanism, we need the FrameworkAutomationPeer to do that.
// Arguments:
// - <none>
// Return Value:
// - <none>
void InteractivityAutomationPeer::SignalTextChanged()
{
_TextChangedHandlers(*this, nullptr);
}
// Method Description:
// - Signals the ui automation client that the cursor's state has changed
// and should be updated
// - We will raise a new event, for out embedding control to be able to
// raise the event. AutomationPeer by itself doesn't hook up to the
// eventing mechanism, we need the FrameworkAutomationPeer to do that.
// Arguments:
// - <none>
// Return Value:
// - <none>
void InteractivityAutomationPeer::SignalCursorChanged()
{
_CursorChangedHandlers(*this, nullptr);
}
#pragma region ITextProvider
com_array<XamlAutomation::ITextRangeProvider> InteractivityAutomationPeer::GetSelection()
{
SAFEARRAY* pReturnVal;
THROW_IF_FAILED(_uiaProvider->GetSelection(&pReturnVal));
return WrapArrayOfTextRangeProviders(pReturnVal);
}
com_array<XamlAutomation::ITextRangeProvider> InteractivityAutomationPeer::GetVisibleRanges()
{
SAFEARRAY* pReturnVal;
THROW_IF_FAILED(_uiaProvider->GetVisibleRanges(&pReturnVal));
return WrapArrayOfTextRangeProviders(pReturnVal);
}
XamlAutomation::ITextRangeProvider InteractivityAutomationPeer::RangeFromChild(XamlAutomation::IRawElementProviderSimple childElement)
{
UIA::ITextRangeProvider* returnVal;
// ScreenInfoUiaProvider doesn't actually use parameter, so just pass in nullptr
THROW_IF_FAILED(_uiaProvider->RangeFromChild(/* IRawElementProviderSimple */ nullptr,
&returnVal));
const auto parentProvider = this->ProviderFromPeer(*this);
const auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
return xutr.as<XamlAutomation::ITextRangeProvider>();
}
XamlAutomation::ITextRangeProvider InteractivityAutomationPeer::RangeFromPoint(Windows::Foundation::Point screenLocation)
{
UIA::ITextRangeProvider* returnVal;
THROW_IF_FAILED(_uiaProvider->RangeFromPoint({ screenLocation.X, screenLocation.Y }, &returnVal));
const auto parentProvider = this->ProviderFromPeer(*this);
const auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
return xutr.as<XamlAutomation::ITextRangeProvider>();
}
XamlAutomation::ITextRangeProvider InteractivityAutomationPeer::DocumentRange()
{
UIA::ITextRangeProvider* returnVal;
THROW_IF_FAILED(_uiaProvider->get_DocumentRange(&returnVal));
const auto parentProvider = this->ProviderFromPeer(*this);
const auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
return xutr.as<XamlAutomation::ITextRangeProvider>();
}
XamlAutomation::SupportedTextSelection InteractivityAutomationPeer::SupportedTextSelection()
{
UIA::SupportedTextSelection returnVal;
THROW_IF_FAILED(_uiaProvider->get_SupportedTextSelection(&returnVal));
return static_cast<XamlAutomation::SupportedTextSelection>(returnVal);
}
#pragma endregion
#pragma region IControlAccessibilityInfo
COORD InteractivityAutomationPeer::GetFontSize() const
{
return til::size{ til::math::rounding, _interactivity->Core().FontSize() };
}
RECT InteractivityAutomationPeer::GetBounds() const
{
return _controlBounds;
}
HRESULT InteractivityAutomationPeer::GetHostUiaProvider(IRawElementProviderSimple** provider)
{
RETURN_HR_IF(E_INVALIDARG, provider == nullptr);
*provider = nullptr;
return S_OK;
}
RECT InteractivityAutomationPeer::GetPadding() const
{
return _controlPadding;
}
double InteractivityAutomationPeer::GetScaleFactor() const
{
return DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel();
}
void InteractivityAutomationPeer::ChangeViewport(const SMALL_RECT NewWindow)
{
_interactivity->UpdateScrollbar(NewWindow.Top);
}
#pragma endregion
// Method Description:
// - extracts the UiaTextRanges from the SAFEARRAY and converts them to Xaml ITextRangeProviders
// Arguments:
// - SAFEARRAY of UIA::UiaTextRange (ITextRangeProviders)
// Return Value:
// - com_array of Xaml Wrapped UiaTextRange (ITextRangeProviders)
com_array<XamlAutomation::ITextRangeProvider> InteractivityAutomationPeer::WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges)
{
// transfer ownership of UiaTextRanges to this new vector
auto providers = SafeArrayToOwningVector<::Microsoft::Terminal::TermControlUiaTextRange>(textRanges);
int count = gsl::narrow<int>(providers.size());
std::vector<XamlAutomation::ITextRangeProvider> vec;
vec.reserve(count);
auto parentProvider = this->ProviderFromPeer(*this);
for (int i = 0; i < count; i++)
{
auto xutr = make_self<XamlUiaTextRange>(providers[i].detach(), parentProvider);
vec.emplace_back(xutr.as<XamlAutomation::ITextRangeProvider>());
}
com_array<XamlAutomation::ITextRangeProvider> result{ vec };
return result;
}
}

View File

@ -0,0 +1,85 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- InteractivityAutomationPeer.h
Abstract:
- This module provides UI Automation access to the ControlInteractivity,
to support both automation tests and accessibility (screen
reading) applications.
- See TermControlAutomationPeer for more details on how UIA is implemented.
- This is the primary implementation of the ITextProvider interface, for the
TermControlAutomationPeer. The TermControlAutomationPeer will be attached to
the actual UI tree, via FrameworkElementAutomationPeer. However, the
ControlInteractivity is totally oblivious to the UI tree that might be hosting
it. So this class implements the actual text pattern for the buffer, because
it has access to the buffer. TermControlAutomationPeer can then call the
methods on this class to expose the implementation in the actual UI tree.
Author(s):
- Mike Griese (migrie), May 2021
--*/
#pragma once
#include "ControlInteractivity.h"
#include "InteractivityAutomationPeer.g.h"
#include "../types/TermControlUiaProvider.hpp"
#include "../types/IUiaEventDispatcher.h"
#include "../types/IControlAccessibilityInfo.h"
namespace winrt::Microsoft::Terminal::Control::implementation
{
struct InteractivityAutomationPeer :
public InteractivityAutomationPeerT<InteractivityAutomationPeer>,
::Microsoft::Console::Types::IUiaEventDispatcher,
::Microsoft::Console::Types::IControlAccessibilityInfo
{
public:
InteractivityAutomationPeer(Microsoft::Terminal::Control::implementation::ControlInteractivity* owner);
void SetControlBounds(const Windows::Foundation::Rect bounds);
void SetControlPadding(const Core::Padding padding);
#pragma region IUiaEventDispatcher
void SignalSelectionChanged() override;
void SignalTextChanged() override;
void SignalCursorChanged() override;
#pragma endregion
#pragma region ITextProvider Pattern
Windows::UI::Xaml::Automation::Provider::ITextRangeProvider RangeFromPoint(Windows::Foundation::Point screenLocation);
Windows::UI::Xaml::Automation::Provider::ITextRangeProvider RangeFromChild(Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple childElement);
com_array<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider> GetVisibleRanges();
com_array<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider> GetSelection();
Windows::UI::Xaml::Automation::SupportedTextSelection SupportedTextSelection();
Windows::UI::Xaml::Automation::Provider::ITextRangeProvider DocumentRange();
#pragma endregion
#pragma region IControlAccessibilityInfo Pattern
// Inherited via IControlAccessibilityInfo
virtual COORD GetFontSize() const override;
virtual RECT GetBounds() const override;
virtual RECT GetPadding() const override;
virtual double GetScaleFactor() const override;
virtual void ChangeViewport(SMALL_RECT NewWindow) override;
virtual HRESULT GetHostUiaProvider(IRawElementProviderSimple** provider) override;
#pragma endregion
TYPED_EVENT(SelectionChanged, IInspectable, IInspectable);
TYPED_EVENT(TextChanged, IInspectable, IInspectable);
TYPED_EVENT(CursorChanged, IInspectable, IInspectable);
private:
::Microsoft::WRL::ComPtr<::Microsoft::Terminal::TermControlUiaProvider> _uiaProvider;
winrt::Microsoft::Terminal::Control::implementation::ControlInteractivity* _interactivity;
til::rectangle _controlBounds{};
til::rectangle _controlPadding{};
winrt::com_array<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider> WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges);
};
}

View File

@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace Microsoft.Terminal.Control
{
[default_interface] runtimeclass InteractivityAutomationPeer :
Windows.UI.Xaml.Automation.Peers.AutomationPeer,
Windows.UI.Xaml.Automation.Provider.ITextProvider
{
void SetControlBounds(Windows.Foundation.Rect bounds);
void SetControlPadding(Microsoft.Terminal.Core.Padding padding);
event Windows.Foundation.TypedEventHandler<Object, Object> SelectionChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> TextChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> CursorChanged;
}
}

View File

@ -8,7 +8,6 @@
#include <unicode.hpp>
#include <Utf16Parser.hpp>
#include <Utils.h>
#include <WinUser.h>
#include <LibraryResources.h>
#include "../../types/inc/GlyphWidth.hpp"
#include "../../types/inc/Utils.hpp"
@ -44,6 +43,8 @@ constexpr const auto TerminalWarningBellInterval = std::chrono::milliseconds(100
DEFINE_ENUM_FLAG_OPERATORS(winrt::Microsoft::Terminal::Control::CopyFormat);
DEFINE_ENUM_FLAG_OPERATORS(winrt::Microsoft::Terminal::Control::MouseButtonState);
namespace winrt::Microsoft::Terminal::Control::implementation
{
TermControl::TermControl(IControlSettings settings,
@ -60,33 +61,33 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
InitializeComponent();
_interactivity = winrt::make_self<ControlInteractivity>(settings, connection);
_core = _interactivity->GetCore();
_interactivity = winrt::make<implementation::ControlInteractivity>(settings, connection);
_core = _interactivity.Core();
// Use a manual revoker on the output event, so we can immediately stop
// worrying about it on destruction.
_coreOutputEventToken = _core->ReceivedOutput({ this, &TermControl::_coreReceivedOutput });
_coreOutputEventToken = _core.ReceivedOutput({ this, &TermControl::_coreReceivedOutput });
// These events might all be triggered by the connection, but that
// should be drained and closed before we complete destruction. So these
// are safe.
_core->ScrollPositionChanged({ this, &TermControl::_ScrollPositionChanged });
_core->WarningBell({ this, &TermControl::_coreWarningBell });
_core->CursorPositionChanged({ this, &TermControl::_CursorPositionChanged });
_core.ScrollPositionChanged({ this, &TermControl::_ScrollPositionChanged });
_core.WarningBell({ this, &TermControl::_coreWarningBell });
_core.CursorPositionChanged({ this, &TermControl::_CursorPositionChanged });
// This event is specifically triggered by the renderer thread, a BG thread. Use a weak ref here.
_core->RendererEnteredErrorState({ get_weak(), &TermControl::_RendererEnteredErrorState });
_core.RendererEnteredErrorState({ get_weak(), &TermControl::_RendererEnteredErrorState });
// These callbacks can only really be triggered by UI interactions. So
// they don't need weak refs - they can't be triggered unless we're
// alive.
_core->BackgroundColorChanged({ this, &TermControl::_BackgroundColorChangedHandler });
_core->FontSizeChanged({ this, &TermControl::_coreFontSizeChanged });
_core->TransparencyChanged({ this, &TermControl::_coreTransparencyChanged });
_core->RaiseNotice({ this, &TermControl::_coreRaisedNotice });
_core->HoveredHyperlinkChanged({ this, &TermControl::_hoveredHyperlinkChanged });
_interactivity->OpenHyperlink({ this, &TermControl::_HyperlinkHandler });
_interactivity->ScrollPositionChanged({ this, &TermControl::_ScrollPositionChanged });
_core.BackgroundColorChanged({ this, &TermControl::_BackgroundColorChangedHandler });
_core.FontSizeChanged({ this, &TermControl::_coreFontSizeChanged });
_core.TransparencyChanged({ this, &TermControl::_coreTransparencyChanged });
_core.RaiseNotice({ this, &TermControl::_coreRaisedNotice });
_core.HoveredHyperlinkChanged({ this, &TermControl::_hoveredHyperlinkChanged });
_interactivity.OpenHyperlink({ this, &TermControl::_HyperlinkHandler });
_interactivity.ScrollPositionChanged({ this, &TermControl::_ScrollPositionChanged });
// Initialize the terminal only once the swapchainpanel is loaded - that
// way, we'll be able to query the real pixel size it got on layout
@ -128,7 +129,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
[weakThis = get_weak()]() {
if (auto control{ weakThis.get() }; !control->_IsClosing())
{
control->_core->UpdatePatternLocations();
control->_core.UpdatePatternLocations();
}
});
@ -187,16 +188,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// If a text is selected inside terminal, use it to populate the search box.
// If the search box already contains a value, it will be overridden.
if (_core->HasSelection())
if (_core.HasSelection())
{
// Currently we populate the search box only if a single line is selected.
// Empirically, multi-line selection works as well on sample scenarios,
// but since code paths differ, extra work is required to ensure correctness.
auto bufferText = _core->SelectedText(true);
if (bufferText.size() == 1)
auto bufferText = _core.SelectedText(true);
if (bufferText.Size() == 1)
{
const auto selectedLine{ til::at(bufferText, 0) };
_searchBox->PopulateTextbox(selectedLine.data());
const auto selectedLine{ bufferText.GetAt(0) };
_searchBox->PopulateTextbox(selectedLine);
}
}
@ -217,7 +218,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
else
{
_core->Search(_searchBox->TextBox().Text(), goForward, false);
_core.Search(_searchBox->TextBox().Text(), goForward, false);
}
}
@ -234,7 +235,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const bool goForward,
const bool caseSensitive)
{
_core->Search(text, goForward, caseSensitive);
_core.Search(text, goForward, caseSensitive);
}
// Method Description:
@ -303,7 +304,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return;
}
_core->UpdateSettings(_settings);
_core.UpdateSettings(_settings);
// Update our control settings
_ApplyUISettings(_settings);
@ -362,7 +363,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
foregroundBrush.Color(static_cast<til::color>(newAppearance.DefaultForeground()));
TSFInputControl().Foreground(foregroundBrush);
_core->UpdateAppearance(newAppearance);
_core.UpdateAppearance(newAppearance);
}
// Method Description:
@ -373,12 +374,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - <none>
void TermControl::SendInput(const winrt::hstring& wstr)
{
_core->SendInput(wstr);
_core.SendInput(wstr);
}
void TermControl::ToggleShaderEffects()
{
_core->ToggleShaderEffects();
_core.ToggleShaderEffects();
}
// Method Description:
@ -401,7 +402,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_changeBackgroundColor(bg);
// Apply padding as swapChainPanel's margin
auto newMargin = _ParseThicknessFromPadding(newSettings.Padding());
auto newMargin = ParseThicknessFromPadding(newSettings.Padding());
SwapChainPanel().Margin(newMargin);
TSFInputControl().Margin(newMargin);
@ -422,7 +423,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
ScrollBar().Visibility(Visibility::Visible);
}
_interactivity->UpdateSettings();
_interactivity.UpdateSettings();
if (_automationPeer)
{
_automationPeer.SetControlPadding(Core::Padding{ newMargin.Left,
newMargin.Top,
newMargin.Right,
newMargin.Bottom });
}
}
// Method Description:
@ -471,7 +479,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
// GH#5098: Inform the engine of the new opacity of the default text background.
_core->SetBackgroundOpacity(::base::saturated_cast<float>(_settings.TintOpacity()));
_core.SetBackgroundOpacity(::base::saturated_cast<float>(_settings.TintOpacity()));
}
else
{
@ -479,7 +487,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
RootGrid().Background(solidColor);
// GH#5098: Inform the engine of the new opacity of the default text background.
_core->SetBackgroundOpacity(1.0f);
_core.SetBackgroundOpacity(1.0f);
}
}
@ -492,7 +500,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void TermControl::_BackgroundColorChangedHandler(const IInspectable& /*sender*/,
const IInspectable& /*args*/)
{
til::color newBgColor{ _core->BackgroundColor() };
til::color newBgColor{ _core.BackgroundColor() };
_changeBackgroundColor(newBgColor);
}
@ -527,37 +535,25 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Return Value:
// - The automation peer for our control
Windows::UI::Xaml::Automation::Peers::AutomationPeer TermControl::OnCreateAutomationPeer()
try
{
if (_initializedTerminal && !_IsClosing()) // only set up the automation peer if we're ready to go live
{
// create a custom automation peer with this code pattern:
// (https://docs.microsoft.com/en-us/windows/uwp/design/accessibility/custom-automation-peers)
auto autoPeer = winrt::make_self<implementation::TermControlAutomationPeer>(this);
_uiaEngine = std::make_unique<::Microsoft::Console::Render::UiaEngine>(autoPeer.get());
_core->AttachUiaEngine(_uiaEngine.get());
_automationPeer = *autoPeer;
return _automationPeer;
if (const auto& interactivityAutoPeer = _interactivity.OnCreateAutomationPeer())
{
_automationPeer = winrt::make<implementation::TermControlAutomationPeer>(this, interactivityAutoPeer);
return _automationPeer;
}
}
return nullptr;
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
return nullptr;
}
::Microsoft::Console::Types::IUiaData* TermControl::GetUiaData() const
{
return _core->GetUiaData();
}
// This is needed for TermControlAutomationPeer. We probably could find a
// clever way around asking the core for this.
til::point TermControl::GetFontSize() const
{
return _core->GetFont().GetSize();
return til::point{ til::math::rounding, _core.FontSize().Width, _core.FontSize().Height };
}
const Windows::UI::Xaml::Thickness TermControl::GetPadding()
@ -567,7 +563,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TerminalConnection::ConnectionState TermControl::ConnectionState() const
{
return _core->ConnectionState();
return _core.ConnectionState();
}
winrt::fire_and_forget TermControl::RenderEngineSwapChainChanged(IInspectable /*sender*/, IInspectable /*args*/)
@ -581,7 +577,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (auto control{ weakThis.get() })
{
const auto chainHandle = _core->GetSwapChainHandle();
const HANDLE chainHandle = reinterpret_cast<HANDLE>(control->_core.SwapChainHandle());
_AttachDxgiSwapChainToXaml(chainHandle);
}
}
@ -658,23 +654,23 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// after Enable, then it'll be possible to paint the frame once
// _before_ the warning handler is set up, and then warnings from
// the first paint will be ignored!
_core->RendererWarning({ get_weak(), &TermControl::_RendererWarning });
_core.RendererWarning({ get_weak(), &TermControl::_RendererWarning });
const auto coreInitialized = _core->Initialize(panelWidth,
panelHeight,
panelScaleX);
const auto coreInitialized = _core.Initialize(panelWidth,
panelHeight,
panelScaleX);
if (!coreInitialized)
{
return false;
}
_interactivity->Initialize();
_interactivity.Initialize();
_AttachDxgiSwapChainToXaml(_core->GetSwapChainHandle());
_AttachDxgiSwapChainToXaml(reinterpret_cast<HANDLE>(_core.SwapChainHandle()));
// Tell the DX 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)
_core->SwapChainChanged({ get_weak(), &TermControl::RenderEngineSwapChainChanged });
_core.SwapChainChanged({ get_weak(), &TermControl::RenderEngineSwapChainChanged });
// !! LOAD BEARING !!
// Make sure you enable painting _AFTER_ calling _AttachDxgiSwapChainToXaml
@ -684,9 +680,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// issues where the Renderer starts trying to paint before we've
// actually attached the swapchain to anything, and the DxEngine is not
// prepared to handle that.
_core->EnablePainting();
_core.EnablePainting();
auto bufferHeight = _core->BufferHeight();
auto bufferHeight = _core.BufferHeight();
ScrollBar().Maximum(bufferHeight - bufferHeight);
ScrollBar().Minimum(0);
@ -763,7 +759,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
modifiers |= ControlKeyStates::EnhancedKey;
}
const bool handled = _core->SendCharEvent(ch, scanCode, modifiers);
const bool handled = _core.SendCharEvent(ch, scanCode, modifiers);
e.Handled(handled);
}
@ -775,7 +771,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool TermControl::OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down)
{
// Short-circuit isReadOnly check to avoid warning dialog
if (_core->IsInReadOnlyMode())
if (_core.IsInReadOnlyMode())
{
return false;
}
@ -861,7 +857,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto scanCode = gsl::narrow_cast<WORD>(e.KeyStatus().ScanCode);
// Short-circuit isReadOnly check to avoid warning dialog
if (_core->IsInReadOnlyMode())
if (_core.IsInReadOnlyMode())
{
e.Handled(!keyDown || _TryHandleKeyBinding(vkey, scanCode, modifiers));
return;
@ -993,17 +989,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// This will prevent the system from trying to get the character out
// of it and sending us a CharacterReceived event.
const auto handled = vkey ?
_core->TrySendKeyEvent(vkey,
scanCode,
modifiers,
keyDown) :
_core.TrySendKeyEvent(vkey,
scanCode,
modifiers,
keyDown) :
true;
if (_cursorTimer)
{
// Manually show the cursor when a key is pressed. Restarting
// the timer prevents flickering.
_core->CursorOn(true);
_core.CursorOn(true);
_cursorTimer->Start();
}
@ -1057,16 +1053,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
const auto contactRect = point.Properties().ContactRect();
auto anchor = til::point{ til::math::rounding, contactRect.X, contactRect.Y };
_interactivity->TouchPressed(anchor);
_interactivity.TouchPressed(anchor);
}
else
{
const auto cursorPosition = point.Position();
_interactivity->PointerPressed(TermControl::GetPressedMouseButtons(point),
TermControl::GetPointerUpdateKind(point),
point.Timestamp(),
ControlKeyStates{ args.KeyModifiers() },
_toTerminalOrigin(cursorPosition));
_interactivity.PointerPressed(TermControl::GetPressedMouseButtons(point),
TermControl::GetPointerUpdateKind(point),
point.Timestamp(),
ControlKeyStates{ args.KeyModifiers() },
_toTerminalOrigin(cursorPosition));
}
args.Handled(true);
@ -1101,11 +1097,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (type == Windows::Devices::Input::PointerDeviceType::Mouse ||
type == Windows::Devices::Input::PointerDeviceType::Pen)
{
_interactivity->PointerMoved(TermControl::GetPressedMouseButtons(point),
TermControl::GetPointerUpdateKind(point),
ControlKeyStates(args.KeyModifiers()),
_focused,
pixelPosition);
_interactivity.PointerMoved(TermControl::GetPressedMouseButtons(point),
TermControl::GetPointerUpdateKind(point),
ControlKeyStates(args.KeyModifiers()),
_focused,
pixelPosition);
if (_focused && point.Properties().IsLeftButtonPressed())
{
@ -1138,7 +1134,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto contactRect = point.Properties().ContactRect();
til::point newTouchPoint{ til::math::rounding, contactRect.X, contactRect.Y };
_interactivity->TouchMoved(newTouchPoint, _focused);
_interactivity.TouchMoved(newTouchPoint, _focused);
}
args.Handled(true);
@ -1169,14 +1165,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (type == Windows::Devices::Input::PointerDeviceType::Mouse ||
type == Windows::Devices::Input::PointerDeviceType::Pen)
{
_interactivity->PointerReleased(TermControl::GetPressedMouseButtons(point),
TermControl::GetPointerUpdateKind(point),
ControlKeyStates(args.KeyModifiers()),
pixelPosition);
_interactivity.PointerReleased(TermControl::GetPressedMouseButtons(point),
TermControl::GetPointerUpdateKind(point),
ControlKeyStates(args.KeyModifiers()),
pixelPosition);
}
else if (type == Windows::Devices::Input::PointerDeviceType::Touch)
{
_interactivity->TouchReleased();
_interactivity.TouchReleased();
}
_TryStopAutoScroll(ptr.PointerId());
@ -1204,10 +1200,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto point = args.GetCurrentPoint(*this);
auto result = _interactivity->MouseWheel(ControlKeyStates{ args.KeyModifiers() },
point.Properties().MouseWheelDelta(),
_toTerminalOrigin(point.Position()),
TermControl::GetPressedMouseButtons(point));
auto result = _interactivity.MouseWheel(ControlKeyStates{ args.KeyModifiers() },
point.Properties().MouseWheelDelta(),
_toTerminalOrigin(point.Position()),
TermControl::GetPressedMouseButtons(point));
if (result)
{
args.Handled(true);
@ -1231,10 +1227,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const bool rightButtonDown)
{
const auto modifiers = _GetPressedModifierKeys();
TerminalInput::MouseButtonState state{ leftButtonDown,
midButtonDown,
rightButtonDown };
return _interactivity->MouseWheel(modifiers, delta, _toTerminalOrigin(location), state);
Control::MouseButtonState state{};
WI_SetFlagIf(state, Control::MouseButtonState::IsLeftButtonDown, leftButtonDown);
WI_SetFlagIf(state, Control::MouseButtonState::IsMiddleButtonDown, midButtonDown);
WI_SetFlagIf(state, Control::MouseButtonState::IsRightButtonDown, rightButtonDown);
return _interactivity.MouseWheel(modifiers, delta, _toTerminalOrigin(location), state);
}
// Method Description:
@ -1282,7 +1281,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - none
void TermControl::ResetFontSize()
{
_core->ResetFontSize();
_core.ResetFontSize();
}
// Method Description:
@ -1291,7 +1290,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - fontSizeDelta: The amount to increase or decrease the font size by.
void TermControl::AdjustFontSize(int fontSizeDelta)
{
_core->AdjustFontSize(fontSizeDelta);
_core.AdjustFontSize(fontSizeDelta);
}
void TermControl::_ScrollbarChangeHandler(Windows::Foundation::IInspectable const& /*sender*/,
@ -1306,7 +1305,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
const auto newValue = args.NewValue();
_interactivity->UpdateScrollbar(newValue);
_interactivity.UpdateScrollbar(newValue);
// User input takes priority over terminal events so cancel
// any pending scroll bar update if the user scrolls.
@ -1452,10 +1451,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// GH#5421: Enable the UiaEngine before checking for the SearchBox
// That way, new selections are notified to automation clients.
if (_uiaEngine.get())
{
THROW_IF_FAILED(_uiaEngine->Enable());
}
// The _uiaEngine lives in _interactivity, so call into there to enable it.
_interactivity.GotFocus();
// If the searchbox is focused, we don't want TSFInputControl to think
// it has focus so it doesn't intercept IME input. We also don't want the
@ -1473,7 +1470,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (_cursorTimer)
{
// When the terminal focuses, show the cursor immediately
_core->CursorOn(true);
_core.CursorOn(true);
_cursorTimer->Start();
}
@ -1482,8 +1479,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_blinkTimer->Start();
}
_interactivity->GainFocus();
// Only update the appearance here if an unfocused config exists -
// if an unfocused config does not exist then we never would have switched
// appearances anyway so there's no need to switch back upon gaining focus
@ -1509,10 +1504,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_focused = false;
if (_uiaEngine.get())
{
THROW_IF_FAILED(_uiaEngine->Disable());
}
// This will disable the accessibility notifications, because the
// UiaEngine lives in ControlInteractivity
_interactivity.LostFocus();
if (TSFInputControl() != nullptr)
{
@ -1522,7 +1516,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (_cursorTimer)
{
_cursorTimer->Stop();
_core->CursorOn(false);
_core.CursorOn(false);
}
if (_blinkTimer)
@ -1552,7 +1546,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
const auto newSize = e.NewSize();
_core->SizeChanged(newSize.Width, newSize.Height);
_core.SizeChanged(newSize.Width, newSize.Height);
if (_automationPeer)
{
_automationPeer.UpdateControlBounds();
}
}
// Method Description:
@ -1587,7 +1586,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
const auto scaleX = sender.CompositionScaleX();
_core->ScaleChanged(scaleX);
_core.ScaleChanged(scaleX);
}
// Method Description:
@ -1600,7 +1599,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
if (!_IsClosing())
{
_core->BlinkCursor();
_core.BlinkCursor();
}
}
@ -1614,7 +1613,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
if (!_IsClosing())
{
_core->BlinkAttributeTick();
_core.BlinkAttributeTick();
}
}
@ -1624,7 +1623,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - cursorPosition: in pixels, relative to the origin of the control
void TermControl::_SetEndSelectionPointAtCursor(Windows::Foundation::Point const& cursorPosition)
{
_interactivity->SetEndSelectionPoint(_toTerminalOrigin(cursorPosition));
_interactivity.SetEndSelectionPoint(_toTerminalOrigin(cursorPosition));
}
// Method Description:
@ -1664,7 +1663,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
hstring TermControl::Title()
{
return _core->Title();
return _core.Title();
}
hstring TermControl::GetProfileName() const
@ -1674,12 +1673,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
hstring TermControl::WorkingDirectory() const
{
return _core->WorkingDirectory();
return _core.WorkingDirectory();
}
bool TermControl::BracketedPasteEnabled() const noexcept
{
return _core->BracketedPasteEnabled();
return _core.BracketedPasteEnabled();
}
// Method Description:
@ -1697,14 +1696,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return false;
}
return _interactivity->CopySelectionToClipboard(singleLine, formats);
return _interactivity.CopySelectionToClipboard(singleLine, formats);
}
// Method Description:
// - Initiate a paste operation.
void TermControl::PasteTextFromClipboard()
{
_interactivity->RequestPasteTextFromClipboard();
_interactivity.RequestPasteTextFromClipboard();
}
void TermControl::Close()
@ -1713,13 +1712,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
_closing = true;
_core->ReceivedOutput(_coreOutputEventToken);
_core.ReceivedOutput(_coreOutputEventToken);
_RestorePointerCursorHandlers(*this, nullptr);
// Disconnect the TSF input control so it doesn't receive EditContext events.
TSFInputControl().Close();
_autoScrollTimer.Stop();
_core->Close();
_core.Close();
}
}
@ -1732,9 +1731,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
ScrollBar().Value(viewTop);
}
int TermControl::ScrollOffset()
int TermControl::ScrollOffset() const
{
return _core->ScrollOffset();
return _core.ScrollOffset();
}
// Function Description:
@ -1743,7 +1742,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - The height of the terminal in lines of text
int TermControl::ViewHeight() const
{
return _core->ViewHeight();
return _core.ViewHeight();
}
int TermControl::BufferHeight() const
{
return _core.BufferHeight();
}
// Function Description:
@ -1844,7 +1848,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
double height = rows * fontSize.Y;
auto thickness = _ParseThicknessFromPadding(padding);
const auto thickness = ParseThicknessFromPadding(padding);
// GH#2061 - make sure to account for the size the padding _will be_ scaled to
width += scale * (thickness.Left + thickness.Right);
height += scale * (thickness.Top + thickness.Bottom);
@ -1862,8 +1866,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - The dimensions of a single character of this control, in DIPs
winrt::Windows::Foundation::Size TermControl::CharacterDimensions() const
{
const auto fontSize = _core->GetFont().GetSize();
return { gsl::narrow_cast<float>(fontSize.X), gsl::narrow_cast<float>(fontSize.Y) };
return _core.FontSize();
}
// Method Description:
@ -1879,9 +1882,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
if (_initializedTerminal)
{
const auto fontSize = _core->GetFont().GetSize();
double width = fontSize.X;
double height = fontSize.Y;
const auto fontSize = _core.FontSize();
double width = fontSize.Width;
double height = fontSize.Height;
// Reserve additional space if scrollbar is intended to be visible
if (_settings.ScrollState() == ScrollbarState::Visible)
{
@ -1924,8 +1927,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - A dimension that would be aligned to the character grid.
float TermControl::SnapDimensionToGrid(const bool widthOrHeight, const float dimension)
{
const auto fontSize = _core->GetFont().GetSize();
const auto fontDimension = widthOrHeight ? fontSize.X : fontSize.Y;
const auto fontSize = _core.FontSize();
const auto fontDimension = widthOrHeight ? fontSize.Width : fontSize.Height;
const auto padding = GetPadding();
auto nonTerminalArea = gsl::narrow_cast<float>(widthOrHeight ?
@ -1952,7 +1955,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Four Double values provide independent padding for 4 sides of the bounding rectangle
// Return Value:
// - Windows::UI::Xaml::Thickness object
Windows::UI::Xaml::Thickness TermControl::_ParseThicknessFromPadding(const hstring padding)
Windows::UI::Xaml::Thickness TermControl::ParseThicknessFromPadding(const hstring padding)
{
const wchar_t singleCharDelim = L',';
std::wstringstream tokenStream(padding.c_str());
@ -2085,7 +2088,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return;
}
_core->SendInput(text);
_core.SendInput(text);
}
// Method Description:
@ -2105,7 +2108,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return;
}
const til::point cursorPos = _core->CursorPosition();
const til::point cursorPos = _core.CursorPosition();
Windows::Foundation::Point p = { ::base::ClampedNumeric<float>(cursorPos.x()),
::base::ClampedNumeric<float>(cursorPos.y()) };
eventArgs.CurrentPosition(p);
@ -2121,11 +2124,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void TermControl::_FontInfoHandler(const IInspectable& /*sender*/,
const FontInfoEventArgs& eventArgs)
{
const auto fontInfo = _core->GetFont();
eventArgs.FontSize(CharacterDimensions());
eventArgs.FontFace(fontInfo.GetFaceName());
eventArgs.FontFace(_core.FontFaceName());
::winrt::Windows::UI::Text::FontWeight weight;
weight.Weight = static_cast<uint16_t>(fontInfo.GetWeight());
weight.Weight = _core.FontWeight();
eventArgs.FontWeight(weight);
}
@ -2167,7 +2169,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
try
{
Windows::Foundation::Uri link{ co_await e.DataView().GetApplicationLinkAsync() };
_core->PasteText(link.AbsoluteUri());
_core.PasteText(link.AbsoluteUri());
}
CATCH_LOG();
}
@ -2176,7 +2178,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
try
{
Windows::Foundation::Uri link{ co_await e.DataView().GetWebLinkAsync() };
_core->PasteText(link.AbsoluteUri());
_core.PasteText(link.AbsoluteUri());
}
CATCH_LOG();
}
@ -2185,7 +2187,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
try
{
auto text{ co_await e.DataView().GetTextAsync() };
_core->PasteText(text);
_core.PasteText(text);
}
CATCH_LOG();
}
@ -2226,7 +2228,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
allPaths += fullPath;
}
_core->PasteText(winrt::hstring{ allPaths });
_core.PasteText(winrt::hstring{ allPaths });
}
}
}
@ -2321,7 +2323,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
// It's already loaded if we get here, so just hide it.
RendererFailedNotice().Visibility(Visibility::Collapsed);
_core->ResumeRendering();
_core.ResumeRendering();
}
IControlSettings TermControl::Settings() const
@ -2340,25 +2342,25 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// hypothetical future where we allow an application to set the tab
// color with VT sequences like they're currently allowed to with the
// title.
return _core->TabColor();
return _core.TabColor();
}
// Method Description:
// - Gets the internal taskbar state value
// Return Value:
// - The taskbar state of this control
const size_t TermControl::TaskbarState() const noexcept
const uint64_t TermControl::TaskbarState() const noexcept
{
return _core->TaskbarState();
return _core.TaskbarState();
}
// Method Description:
// - Gets the internal taskbar progress value
// Return Value:
// - The taskbar progress of this control
const size_t TermControl::TaskbarProgress() const noexcept
const uint64_t TermControl::TaskbarProgress() const noexcept
{
return _core->TaskbarProgress();
return _core.TaskbarProgress();
}
void TermControl::BellLightOn()
@ -2418,15 +2420,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - True if the mode is read-only
bool TermControl::ReadOnly() const noexcept
{
return _core->IsInReadOnlyMode();
return _core.IsInReadOnlyMode();
}
// Method Description:
// - Toggles the read-only flag, raises event describing the value change
void TermControl::ToggleReadOnly()
{
_core->ToggleReadOnlyMode();
_ReadOnlyChangedHandlers(*this, winrt::box_value(_core->IsInReadOnlyMode()));
_core.ToggleReadOnlyMode();
_ReadOnlyChangedHandlers(*this, winrt::box_value(_core.IsInReadOnlyMode()));
}
// Method Description:
@ -2435,9 +2437,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Arguments:
// - sender: not used
// - args: event data
void TermControl::_PointerExitedHandler(Windows::Foundation::IInspectable const& /*sender*/, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& /*e*/)
void TermControl::_PointerExitedHandler(Windows::Foundation::IInspectable const& /*sender*/,
Windows::UI::Xaml::Input::PointerRoutedEventArgs const& /*e*/)
{
_core->UpdateHoveredCell(std::nullopt);
_core.ClearHoveredCell();
}
winrt::fire_and_forget TermControl::_hoveredHyperlinkChanged(IInspectable sender,
@ -2447,10 +2450,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
co_await resume_foreground(Dispatcher());
if (auto self{ weakThis.get() })
{
auto lastHoveredCell = _core->GetHoveredCell();
auto lastHoveredCell = _core.HoveredCell();
if (lastHoveredCell)
{
const auto uriText = _core->GetHoveredUriText();
const auto uriText = _core.HoveredUriText();
if (!uriText.empty())
{
// Update the tooltip with the URI
@ -2465,8 +2468,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Compute the location of the top left corner of the cell in DIPS
const til::size marginsInDips{ til::math::rounding, GetPadding().Left, GetPadding().Top };
const til::point startPos{ *lastHoveredCell };
const til::size fontSize{ _core->GetFont().GetSize() };
const til::point startPos{ lastHoveredCell.Value() };
const til::size fontSize{ til::math::rounding, _core.FontSize() };
const til::point posInPixels{ startPos * fontSize };
const til::point posInDIPs{ posInPixels / SwapChainPanel().CompositionScaleX() };
const til::point locationInDIPs{ posInDIPs + marginsInDips };
@ -2502,11 +2505,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_RaiseNoticeHandlers(*this, eventArgs);
}
TerminalInput::MouseButtonState TermControl::GetPressedMouseButtons(const winrt::Windows::UI::Input::PointerPoint point)
Control::MouseButtonState TermControl::GetPressedMouseButtons(const winrt::Windows::UI::Input::PointerPoint point)
{
return TerminalInput::MouseButtonState{ point.Properties().IsLeftButtonPressed(),
point.Properties().IsMiddleButtonPressed(),
point.Properties().IsRightButtonPressed() };
Control::MouseButtonState state{};
WI_SetFlagIf(state, Control::MouseButtonState::IsLeftButtonDown, point.Properties().IsLeftButtonPressed());
WI_SetFlagIf(state, Control::MouseButtonState::IsMiddleButtonDown, point.Properties().IsMiddleButtonPressed());
WI_SetFlagIf(state, Control::MouseButtonState::IsRightButtonDown, point.Properties().IsRightButtonPressed());
return state;
}
unsigned int TermControl::GetPointerUpdateKind(const winrt::Windows::UI::Input::PointerPoint point)

View File

@ -40,8 +40,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
float SnapDimensionToGrid(const bool widthOrHeight, const float dimension);
#pragma region ICoreState
const size_t TaskbarState() const noexcept;
const size_t TaskbarProgress() const noexcept;
const uint64_t TaskbarState() const noexcept;
const uint64_t TaskbarProgress() const noexcept;
hstring Title();
Windows::Foundation::IReference<winrt::Windows::UI::Color> TabColor() noexcept;
@ -49,7 +49,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TerminalConnection::ConnectionState ConnectionState() const;
int ScrollOffset();
int ScrollOffset() const;
int ViewHeight() const;
int BufferHeight() const;
@ -84,7 +84,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
~TermControl();
Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer();
::Microsoft::Console::Types::IUiaData* GetUiaData() const;
const Windows::UI::Xaml::Thickness GetPadding();
IControlSettings Settings() const;
@ -104,19 +103,21 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool ReadOnly() const noexcept;
void ToggleReadOnly();
static ::Microsoft::Console::VirtualTerminal::TerminalInput::MouseButtonState GetPressedMouseButtons(const winrt::Windows::UI::Input::PointerPoint point);
static Control::MouseButtonState GetPressedMouseButtons(const winrt::Windows::UI::Input::PointerPoint point);
static unsigned int GetPointerUpdateKind(const winrt::Windows::UI::Input::PointerPoint point);
static Windows::UI::Xaml::Thickness ParseThicknessFromPadding(const hstring padding);
// -------------------------------- WinRT Events ---------------------------------
// clang-format off
WINRT_CALLBACK(FontSizeChanged, Control::FontSizeChangedEventArgs);
FORWARDED_TYPED_EVENT(CopyToClipboard, IInspectable, Control::CopyToClipboardEventArgs, _core, CopyToClipboard);
FORWARDED_TYPED_EVENT(TitleChanged, IInspectable, Control::TitleChangedEventArgs, _core, TitleChanged);
FORWARDED_TYPED_EVENT(TabColorChanged, IInspectable, IInspectable, _core, TabColorChanged);
FORWARDED_TYPED_EVENT(SetTaskbarProgress, IInspectable, IInspectable, _core, TaskbarProgressChanged);
FORWARDED_TYPED_EVENT(ConnectionStateChanged, IInspectable, IInspectable, _core, ConnectionStateChanged);
FORWARDED_TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs, _interactivity, PasteFromClipboard);
PROJECTED_FORWARDED_TYPED_EVENT(CopyToClipboard, IInspectable, Control::CopyToClipboardEventArgs, _core, CopyToClipboard);
PROJECTED_FORWARDED_TYPED_EVENT(TitleChanged, IInspectable, Control::TitleChangedEventArgs, _core, TitleChanged);
PROJECTED_FORWARDED_TYPED_EVENT(TabColorChanged, IInspectable, IInspectable, _core, TabColorChanged);
PROJECTED_FORWARDED_TYPED_EVENT(SetTaskbarProgress, IInspectable, IInspectable, _core, TaskbarProgressChanged);
PROJECTED_FORWARDED_TYPED_EVENT(ConnectionStateChanged, IInspectable, IInspectable, _core, ConnectionStateChanged);
PROJECTED_FORWARDED_TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs, _interactivity, PasteFromClipboard);
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
TYPED_EVENT(RaiseNotice, IInspectable, Control::NoticeEventArgs);
@ -141,11 +142,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// IRenderEngine is accessed when ControlCore calls Renderer::TriggerTeardown.
// (C++ class members are destroyed in reverse order.)
// Further, the TermControlAutomationPeer must be destructed after _uiaEngine!
winrt::Windows::UI::Xaml::Automation::Peers::AutomationPeer _automationPeer{ nullptr };
std::unique_ptr<::Microsoft::Console::Render::UiaEngine> _uiaEngine;
Control::TermControlAutomationPeer _automationPeer{ nullptr };
Control::ControlInteractivity _interactivity{ nullptr };
Control::ControlCore _core{ nullptr };
winrt::com_ptr<ControlCore> _core;
winrt::com_ptr<ControlInteractivity> _interactivity;
winrt::com_ptr<SearchBoxControl> _searchBox;
IControlSettings _settings;
@ -240,8 +240,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _TryStopAutoScroll(const uint32_t pointerId);
void _UpdateAutoScroll(Windows::Foundation::IInspectable const& sender, Windows::Foundation::IInspectable const& e);
static Windows::UI::Xaml::Thickness _ParseThicknessFromPadding(const hstring padding);
void _KeyHandler(Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e, const bool keyDown);
::Microsoft::Terminal::Core::ControlKeyStates _GetPressedModifierKeys() const;
bool _TryHandleKeyBinding(const WORD vkey, const WORD scanCode, ::Microsoft::Terminal::Core::ControlKeyStates modifiers) const;

View File

@ -30,13 +30,42 @@ namespace XamlAutomation
namespace winrt::Microsoft::Terminal::Control::implementation
{
TermControlAutomationPeer::TermControlAutomationPeer(winrt::Microsoft::Terminal::Control::implementation::TermControl* owner) :
TermControlAutomationPeer::TermControlAutomationPeer(TermControl* owner,
Control::InteractivityAutomationPeer impl) :
TermControlAutomationPeerT<TermControlAutomationPeer>(*owner), // pass owner to FrameworkElementAutomationPeer
_termControl{ owner }
_termControl{ owner },
_contentAutomationPeer{ impl }
{
THROW_IF_FAILED(::Microsoft::WRL::MakeAndInitialize<::Microsoft::Terminal::TermControlUiaProvider>(&_uiaProvider, _termControl->GetUiaData(), this));
UpdateControlBounds();
// Listen for UIA signalling events from the implementation. We need to
// be the one to actually raise these automation events, so they go
// through the UI tree correctly.
_contentAutomationPeer.SelectionChanged([this](auto&&, auto&&) { SignalSelectionChanged(); });
_contentAutomationPeer.TextChanged([this](auto&&, auto&&) { SignalTextChanged(); });
_contentAutomationPeer.CursorChanged([this](auto&&, auto&&) { SignalCursorChanged(); });
};
// Method Description:
// - Inform the interactivity layer about the bounds of the control.
// IControlAccessibilityInfo needs to know this information, but it cannot
// ask us directly.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TermControlAutomationPeer::UpdateControlBounds()
{
// FrameworkElementAutomationPeer has this great GetBoundingRectangle
// method that's seemingly impossible to recreate just from the
// UserControl itself. Weird. But we can use it handily here!
_contentAutomationPeer.SetControlBounds(GetBoundingRectangle());
}
void TermControlAutomationPeer::SetControlPadding(const Core::Padding padding)
{
_contentAutomationPeer.SetControlPadding(padding);
}
// Method Description:
// - Signals the ui automation client that the terminal's selection has changed and should be updated
// Arguments:
@ -167,106 +196,36 @@ namespace winrt::Microsoft::Terminal::Control::implementation
#pragma region ITextProvider
com_array<XamlAutomation::ITextRangeProvider> TermControlAutomationPeer::GetSelection()
{
SAFEARRAY* pReturnVal;
THROW_IF_FAILED(_uiaProvider->GetSelection(&pReturnVal));
return WrapArrayOfTextRangeProviders(pReturnVal);
return _contentAutomationPeer.GetSelection();
}
com_array<XamlAutomation::ITextRangeProvider> TermControlAutomationPeer::GetVisibleRanges()
{
SAFEARRAY* pReturnVal;
THROW_IF_FAILED(_uiaProvider->GetVisibleRanges(&pReturnVal));
return WrapArrayOfTextRangeProviders(pReturnVal);
return _contentAutomationPeer.GetVisibleRanges();
}
XamlAutomation::ITextRangeProvider TermControlAutomationPeer::RangeFromChild(XamlAutomation::IRawElementProviderSimple childElement)
{
UIA::ITextRangeProvider* returnVal;
// ScreenInfoUiaProvider doesn't actually use parameter, so just pass in nullptr
THROW_IF_FAILED(_uiaProvider->RangeFromChild(/* IRawElementProviderSimple */ nullptr,
&returnVal));
auto parentProvider = this->ProviderFromPeer(*this);
auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
return xutr.as<XamlAutomation::ITextRangeProvider>();
return _contentAutomationPeer.RangeFromChild(childElement);
}
XamlAutomation::ITextRangeProvider TermControlAutomationPeer::RangeFromPoint(Windows::Foundation::Point screenLocation)
{
UIA::ITextRangeProvider* returnVal;
THROW_IF_FAILED(_uiaProvider->RangeFromPoint({ screenLocation.X, screenLocation.Y }, &returnVal));
auto parentProvider = this->ProviderFromPeer(*this);
auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
return xutr.as<XamlAutomation::ITextRangeProvider>();
return _contentAutomationPeer.RangeFromPoint(screenLocation);
}
XamlAutomation::ITextRangeProvider TermControlAutomationPeer::DocumentRange()
{
UIA::ITextRangeProvider* returnVal;
THROW_IF_FAILED(_uiaProvider->get_DocumentRange(&returnVal));
auto parentProvider = this->ProviderFromPeer(*this);
auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
return xutr.as<XamlAutomation::ITextRangeProvider>();
return _contentAutomationPeer.DocumentRange();
}
XamlAutomation::SupportedTextSelection TermControlAutomationPeer::SupportedTextSelection()
{
UIA::SupportedTextSelection returnVal;
THROW_IF_FAILED(_uiaProvider->get_SupportedTextSelection(&returnVal));
return static_cast<XamlAutomation::SupportedTextSelection>(returnVal);
return _contentAutomationPeer.SupportedTextSelection();
}
#pragma endregion
#pragma region IControlAccessibilityInfo
COORD TermControlAutomationPeer::GetFontSize() const
{
return _termControl->GetFontSize();
}
RECT TermControlAutomationPeer::GetBounds() const
{
auto rect = GetBoundingRectangle();
return {
gsl::narrow_cast<LONG>(rect.X),
gsl::narrow_cast<LONG>(rect.Y),
gsl::narrow_cast<LONG>(rect.X + rect.Width),
gsl::narrow_cast<LONG>(rect.Y + rect.Height)
};
}
HRESULT TermControlAutomationPeer::GetHostUiaProvider(IRawElementProviderSimple** provider)
{
RETURN_HR_IF(E_INVALIDARG, provider == nullptr);
*provider = nullptr;
return S_OK;
}
RECT TermControlAutomationPeer::GetPadding() const
{
auto padding = _termControl->GetPadding();
return {
gsl::narrow_cast<LONG>(padding.Left),
gsl::narrow_cast<LONG>(padding.Top),
gsl::narrow_cast<LONG>(padding.Right),
gsl::narrow_cast<LONG>(padding.Bottom)
};
}
double TermControlAutomationPeer::GetScaleFactor() const
{
return DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel();
}
void TermControlAutomationPeer::ChangeViewport(const SMALL_RECT NewWindow)
{
_termControl->ScrollViewport(NewWindow.Top);
}
#pragma endregion
// Method Description:
// - extracts the UiaTextRanges from the SAFEARRAY and converts them to Xaml ITextRangeProviders
// Arguments:

View File

@ -20,13 +20,17 @@ Abstract:
Author(s):
- Carlos Zamora (CaZamor) 2019
Modifications:
- May 2021: Pulled the core logic of ITextProvider implementation into the
InteractivityAutomationPeer, to support tab tear out.
--*/
#pragma once
#include "TermControl.h"
#include "ControlInteractivity.h"
#include "TermControlAutomationPeer.g.h"
#include <winrt/Microsoft.Terminal.Control.h>
#include "../types/TermControlUiaProvider.hpp"
#include "../types/IUiaEventDispatcher.h"
#include "../types/IControlAccessibilityInfo.h"
@ -35,11 +39,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
struct TermControlAutomationPeer :
public TermControlAutomationPeerT<TermControlAutomationPeer>,
::Microsoft::Console::Types::IUiaEventDispatcher,
::Microsoft::Console::Types::IControlAccessibilityInfo
::Microsoft::Console::Types::IUiaEventDispatcher
{
public:
TermControlAutomationPeer(Microsoft::Terminal::Control::implementation::TermControl* owner);
TermControlAutomationPeer(Microsoft::Terminal::Control::implementation::TermControl* owner,
Control::InteractivityAutomationPeer implementation);
void UpdateControlBounds();
void SetControlPadding(const Core::Padding padding);
#pragma region FrameworkElementAutomationPeer
hstring GetClassNameCore() const;
@ -67,21 +74,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
Windows::UI::Xaml::Automation::Provider::ITextRangeProvider DocumentRange();
#pragma endregion
#pragma region IControlAccessibilityInfo Pattern
// Inherited via IControlAccessibilityInfo
virtual COORD GetFontSize() const override;
virtual RECT GetBounds() const override;
virtual RECT GetPadding() const override;
virtual double GetScaleFactor() const override;
virtual void ChangeViewport(SMALL_RECT NewWindow) override;
virtual HRESULT GetHostUiaProvider(IRawElementProviderSimple** provider) override;
#pragma endregion
RECT GetBoundingRectWrapped();
private:
::Microsoft::WRL::ComPtr<::Microsoft::Terminal::TermControlUiaProvider> _uiaProvider;
winrt::Microsoft::Terminal::Control::implementation::TermControl* _termControl;
Control::InteractivityAutomationPeer _contentAutomationPeer;
winrt::com_array<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider> WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges);
};
}

View File

@ -9,5 +9,8 @@ namespace Microsoft.Terminal.Control
Windows.UI.Xaml.Automation.Peers.FrameworkElementAutomationPeer,
Windows.UI.Xaml.Automation.Provider.ITextProvider
{
void UpdateControlBounds();
void SetControlPadding(Microsoft.Terminal.Core.Padding padding);
}
}

View File

@ -52,6 +52,9 @@
<ClInclude Include="TermControlAutomationPeer.h">
<DependentUpon>TermControlAutomationPeer.idl</DependentUpon>
</ClInclude>
<ClInclude Include="InteractivityAutomationPeer.h">
<DependentUpon>InteractivityAutomationPeer.idl</DependentUpon>
</ClInclude>
<ClInclude Include="TSFInputControl.h">
<DependentUpon>TSFInputControl.xaml</DependentUpon>
</ClInclude>
@ -91,6 +94,9 @@
<ClCompile Include="TermControlAutomationPeer.cpp">
<DependentUpon>TermControlAutomationPeer.idl</DependentUpon>
</ClCompile>
<ClCompile Include="InteractivityAutomationPeer.cpp">
<DependentUpon>InteractivityAutomationPeer.idl</DependentUpon>
</ClCompile>
<ClCompile Include="XamlUiaTextRange.cpp" />
</ItemGroup>
<!-- ========================= idl Files ======================== -->
@ -112,6 +118,7 @@
<DependentUpon>TermControl.xaml</DependentUpon>
</Midl>
<Midl Include="TermControlAutomationPeer.idl" />
<Midl Include="InteractivityAutomationPeer.idl" />
<Midl Include="IMouseWheelListener.idl" />
<Midl Include="TSFInputControl.idl">
<DependentUpon>TSFInputControl.xaml</DependentUpon>

View File

@ -57,6 +57,8 @@
TRACELOGGING_DECLARE_PROVIDER(g_hTerminalControlProvider);
#include <telemetry/ProjectTelemetry.h>
#include <WinUser.h>
#include "til.h"
#include "ThrottledFunc.h"

View File

@ -82,6 +82,20 @@ public:
}
#endif
#ifdef WINRT_Microsoft_Terminal_Core_H
constexpr ControlKeyStates(const winrt::Microsoft::Terminal::Core::ControlKeyStates& projKeyStates) :
ControlKeyStates(projKeyStates.Value)
{
}
operator winrt::Microsoft::Terminal::Core::ControlKeyStates() const noexcept
{
winrt::Microsoft::Terminal::Core::ControlKeyStates ret;
ret.Value = _value;
return ret;
}
#endif
constexpr DWORD Value() const noexcept
{
return _value;

View File

@ -24,11 +24,38 @@ namespace Microsoft.Terminal.Core
UInt8 A;
};
// TerminalCore declares its own Color struct to avoid depending on
// Windows.UI. Windows.Foundation.Point also exists, but it's composed of
// floating-point coordinates, when we almost always need integer coordinates.
// It is supported by til::point for conversions in and out of WinRT land.
struct Point
{
Int32 X;
Int32 Y;
};
// Same thing here, but with padding. Can't use Windows.UI.Thickness, so
// we'll declare our own.
struct Padding {
Double Left;
Double Top;
Double Right;
Double Bottom;
};
// This is a projection of Microsoft::Terminal::Core::ControlKeyStates,
// for conversions in and out of WinRT land.
struct ControlKeyStates
{
UInt32 Value;
};
declare
{
// Forward declare this parameterized specialization so that it lives
// in TerminalCore instead of being flung to the winds of all IDL dependents.
interface Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>;
interface Windows.Foundation.IReference<Microsoft.Terminal.Core.Point>;
}
interface ICoreAppearance

View File

@ -118,6 +118,7 @@ namespace ControlUnitTests
core->TransparencyChanged(opacityCallback);
const auto modifiers = ControlKeyStates(ControlKeyStates::RightCtrlPressed | ControlKeyStates::ShiftPressed);
const Control::MouseButtonState buttonState{};
Log::Comment(L"Scroll in the positive direction, increasing opacity");
// Scroll more than enough times to get to 1.0 from .5.
@ -134,7 +135,7 @@ namespace ControlUnitTests
interactivity->MouseWheel(modifiers,
30,
til::point{ 0, 0 },
{ false, false, false });
buttonState);
}
Log::Comment(L"Scroll in the negative direction, decreasing opacity");
@ -152,7 +153,7 @@ namespace ControlUnitTests
interactivity->MouseWheel(modifiers,
30,
til::point{ 0, 0 },
{ false, false, false });
buttonState);
}
}
@ -197,6 +198,7 @@ namespace ControlUnitTests
VERIFY_ARE_EQUAL(41, core->BufferHeight());
Log::Comment(L"Scroll up a line");
const Control::MouseButtonState buttonState{};
const auto modifiers = ControlKeyStates();
expectedBufferHeight = 41;
expectedTop = 20;
@ -204,7 +206,7 @@ namespace ControlUnitTests
interactivity->MouseWheel(modifiers,
WHEEL_DELTA,
til::point{ 0, 0 },
{ false, false, false });
buttonState);
Log::Comment(L"Scroll up 19 more times, to the top");
for (int i = 0; i < 20; ++i)
@ -213,18 +215,18 @@ namespace ControlUnitTests
interactivity->MouseWheel(modifiers,
WHEEL_DELTA,
til::point{ 0, 0 },
{ false, false, false });
buttonState);
}
Log::Comment(L"Scrolling up more should do nothing");
expectedTop = 0;
interactivity->MouseWheel(modifiers,
WHEEL_DELTA,
til::point{ 0, 0 },
{ false, false, false });
buttonState);
interactivity->MouseWheel(modifiers,
WHEEL_DELTA,
til::point{ 0, 0 },
{ false, false, false });
buttonState);
Log::Comment(L"Scroll down 21 more times, to the bottom");
for (int i = 0; i < 21; ++i)
@ -234,7 +236,7 @@ namespace ControlUnitTests
interactivity->MouseWheel(modifiers,
-WHEEL_DELTA,
til::point{ 0, 0 },
{ false, false, false });
buttonState);
Log::Comment(NoThrowString().Format(L"internal scrollbar pos:%f", interactivity->_internalScrollbarPosition));
}
Log::Comment(L"Scrolling up more should do nothing");
@ -242,11 +244,11 @@ namespace ControlUnitTests
interactivity->MouseWheel(modifiers,
-WHEEL_DELTA,
til::point{ 0, 0 },
{ false, false, false });
buttonState);
interactivity->MouseWheel(modifiers,
-WHEEL_DELTA,
til::point{ 0, 0 },
{ false, false, false });
buttonState);
}
void ControlInteractivityTests::CreateSubsequentSelectionWithDragging()
@ -260,8 +262,8 @@ namespace ControlUnitTests
// For this test, don't use any modifiers
const auto modifiers = ControlKeyStates();
const TerminalInput::MouseButtonState leftMouseDown{ true, false, false };
const TerminalInput::MouseButtonState noMouseDown{ false, false, false };
const Control::MouseButtonState leftMouseDown{ Control::MouseButtonState::IsLeftButtonDown };
const Control::MouseButtonState noMouseDown{};
const til::size fontSize{ 9, 21 };
@ -358,8 +360,8 @@ namespace ControlUnitTests
// For this test, don't use any modifiers
const auto modifiers = ControlKeyStates();
const TerminalInput::MouseButtonState leftMouseDown{ true, false, false };
const TerminalInput::MouseButtonState noMouseDown{ false, false, false };
const Control::MouseButtonState leftMouseDown{ Control::MouseButtonState::IsLeftButtonDown };
const Control::MouseButtonState noMouseDown{};
const til::size fontSize{ 9, 21 };
@ -401,7 +403,7 @@ namespace ControlUnitTests
interactivity->MouseWheel(modifiers,
WHEEL_DELTA,
cursorPosition1,
{ true, false, false });
leftMouseDown);
Log::Comment(L"Verify the location of the selection");
// The viewport is now on row 20, so the selection will be on:
@ -444,7 +446,7 @@ namespace ControlUnitTests
const int delta = WHEEL_DELTA / 5;
const til::point mousePos{ 0, 0 };
TerminalInput::MouseButtonState state{ false, false, false };
Control::MouseButtonState state{};
interactivity->MouseWheel(modifiers, delta, mousePos, state); // 1/5
VERIFY_ARE_EQUAL(21, core->ScrollOffset());
@ -508,8 +510,8 @@ namespace ControlUnitTests
// For this test, don't use any modifiers
const auto modifiers = ControlKeyStates();
const TerminalInput::MouseButtonState leftMouseDown{ true, false, false };
const TerminalInput::MouseButtonState noMouseDown{ false, false, false };
const Control::MouseButtonState leftMouseDown{ Control::MouseButtonState::IsLeftButtonDown };
const Control::MouseButtonState noMouseDown{};
const til::size fontSize{ 9, 21 };

View File

@ -96,6 +96,12 @@ public:
winrt::event_token name(Windows::Foundation::TypedEventHandler<sender, args> const& h) { return handler->handlerName(h); } \
void name(winrt::event_token const& token) noexcept { handler->handlerName(token); }
// Same thing, but handler is a projected type, not an implementation
#define PROJECTED_FORWARDED_TYPED_EVENT(name, sender, args, handler, handlerName) \
public: \
winrt::event_token name(Windows::Foundation::TypedEventHandler<sender, args> const& h) { return handler.handlerName(h); } \
void name(winrt::event_token const& token) noexcept { handler.handlerName(token); }
// Use this macro to quick implement both the getter and setter for a property.
// This should only be used for simple types where there's no logic in the
// getter/setter beyond just accessing/updating the value.

View File

@ -338,6 +338,21 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
}
#endif
#ifdef WINRT_Microsoft_Terminal_Core_H
constexpr point(const winrt::Microsoft::Terminal::Core::Point& corePoint) :
point(corePoint.X, corePoint.Y)
{
}
operator winrt::Microsoft::Terminal::Core::Point() const
{
winrt::Microsoft::Terminal::Core::Point ret;
ret.X = x<int>();
ret.Y = y<int>();
return ret;
}
#endif
std::wstring to_string() const
{
return wil::str_printf<std::wstring>(L"(X:%td, Y:%td)", x(), y());

View File

@ -183,6 +183,14 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
{
}
// This template will convert to rectangle from anything that has a X, Y, Width, and Height field that are floating-point;
// a math type is required.
template<typename TilMath, typename TOther>
constexpr rectangle(TilMath, const TOther& other, std::enable_if_t<std::is_floating_point_v<decltype(std::declval<TOther>().X)> && std::is_floating_point_v<decltype(std::declval<TOther>().Y)> && std::is_floating_point_v<decltype(std::declval<TOther>().Width)> && std::is_floating_point_v<decltype(std::declval<TOther>().Height)>, int> /*sentinel*/ = 0) :
rectangle(til::point{ TilMath::template cast<ptrdiff_t>(other.X), TilMath::template cast<ptrdiff_t>(other.Y) }, til::size{ TilMath::template cast<ptrdiff_t>(other.Width), TilMath::template cast<ptrdiff_t>(other.Height) })
{
}
// This template will convert to rectangle from anything that has a left, top, right, and bottom field that are floating-point;
// a math type is required.
template<typename TilMath, typename TOther>
@ -875,6 +883,22 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
}
#endif
#ifdef WINRT_Microsoft_Terminal_Core_H
operator winrt::Microsoft::Terminal::Core::Padding() const
{
winrt::Microsoft::Terminal::Core::Padding ret;
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(left()).AssignIfValid(&ret.Left));
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(top()).AssignIfValid(&ret.Top));
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(right()).AssignIfValid(&ret.Right));
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(bottom()).AssignIfValid(&ret.Bottom));
return ret;
}
constexpr rectangle(const winrt::Microsoft::Terminal::Core::Padding& padding) :
rectangle(til::math::rounding, padding)
{
}
#endif
std::wstring to_string() const
{
return wil::str_printf<std::wstring>(L"(L:%td, T:%td, R:%td, B:%td) [W:%td, H:%td]", left(), top(), right(), bottom(), width(), height());