Merge remote-tracking branch 'origin/dev/duhowett/stop-using-projection-for-control-innards' into HEAD

# Conflicts:
#	src/cascadia/TerminalControl/TermControl.cpp
This commit is contained in:
Dustin L. Howett
2026-09-25 14:49:50 -05:00
16 changed files with 389 additions and 721 deletions

View File

@@ -2034,7 +2034,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_lastSwapChainHandle = std::move(duplicatedHandle);
// Now bubble the event up to the control.
SwapChainChanged.raise(*this, winrt::box_value<uint64_t>(reinterpret_cast<uint64_t>(_lastSwapChainHandle.get())));
SwapChainChanged.raise(*this, nullptr);
}
}
@@ -2331,13 +2331,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _renderer.get();
}
uint64_t ControlCore::SwapChainHandle() const
HANDLE ControlCore::SwapChainHandle() const
{
// This is only ever called by TermControl::AttachContent, which occurs
// when we're taking an existing core and moving it to a new control.
// Otherwise, we only ever use the value from the SwapChainChanged
// event.
return reinterpret_cast<uint64_t>(_lastSwapChainHandle.get());
return _lastSwapChainHandle.get();
}
// Method Description:

View File

@@ -107,7 +107,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void SetOverrideColorScheme(const Core::ICoreScheme&);
::Microsoft::Console::Render::Renderer* GetRenderer() const noexcept;
uint64_t SwapChainHandle() const;
HANDLE SwapChainHandle() const;
void AttachToNewControl();
void SizeChanged(const float width, const float height);

View File

@@ -111,8 +111,6 @@ namespace Microsoft.Terminal.Control
void SetOverrideColorScheme(Microsoft.Terminal.Core.ICoreScheme scheme);
UInt64 SwapChainHandle { get; };
Windows.Foundation.Size FontSize { get; };
Windows.Foundation.Size FontSizeInDips { get; };
UInt16 FontWeight { get; };

View File

@@ -10,8 +10,6 @@
#include "../../types/inc/Utils.hpp"
#include "../../buffer/out/search.h"
#include "InteractivityAutomationPeer.h"
#include "ControlInteractivity.g.cpp"
using namespace ::Microsoft::Console::Types;
@@ -831,23 +829,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - None
// Return Value:
// - The automation peer for our control
Control::InteractivityAutomationPeer ControlInteractivity::OnCreateAutomationPeer()
void ControlInteractivity::SetUiaEventDispatcher(IUiaEventDispatcher* uiaEventDispatcher)
try
{
const auto autoPeer = winrt::make_self<implementation::InteractivityAutomationPeer>(this);
if (_uiaEngine)
{
_core->DetachUiaEngine(_uiaEngine.get());
}
_uiaEngine = std::make_unique<::Microsoft::Console::Render::UiaEngine>(autoPeer.get());
_uiaEngine = std::make_unique<::Microsoft::Console::Render::UiaEngine>(uiaEventDispatcher);
_core->AttachUiaEngine(_uiaEngine.get());
return *autoPeer;
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
return nullptr;
}
CATCH_LOG()
::Microsoft::Console::Render::IRenderData* ControlInteractivity::GetRenderData() const
{

View File

@@ -48,7 +48,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void Close();
void Detach();
Control::InteractivityAutomationPeer OnCreateAutomationPeer();
void SetUiaEventDispatcher(::Microsoft::Console::Types::IUiaEventDispatcher* uiaEventDispatcher);
::Microsoft::Console::Render::IRenderData* GetRenderData() const;
#pragma region Input Methods

View File

@@ -5,8 +5,6 @@ import "ICoreState.idl";
import "IControlSettings.idl";
import "ControlCore.idl";
import "EventArgs.idl";
import "InteractivityAutomationPeer.idl";
namespace Microsoft.Terminal.Control
{
@@ -30,8 +28,6 @@ namespace Microsoft.Terminal.Control
void Close();
InteractivityAutomationPeer OnCreateAutomationPeer();
Boolean CopySelectionToClipboard(Boolean singleLine, Boolean withControlSequences, CopyFormat formats);
void RequestPasteTextFromClipboard();
void SetEndSelectionPoint(Microsoft.Terminal.Core.Point point);

View File

@@ -1,223 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include <UIAutomationCore.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->GetRenderData(), this));
};
// Bounds is expected to be in pixels.
void InteractivityAutomationPeer::SetControlBounds(const Windows::Foundation::Rect bounds)
{
_controlBounds = { til::math::rounding, bounds };
}
// Padding is expected to be in DIPs.
void InteractivityAutomationPeer::SetControlPadding(const Core::Padding padding)
{
const auto scale = static_cast<float>(DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel());
_controlPadding = { til::math::rounding, padding.Left * scale, padding.Top * scale, padding.Right * scale, padding.Bottom * scale };
}
void InteractivityAutomationPeer::ParentProvider(AutomationPeer parentProvider)
{
// LOAD-BEARING: use _parentProvider->ProviderFromPeer(_parentProvider) instead of this->ProviderFromPeer(*this).
// Since we split the automation peer into TermControlAutomationPeer and InteractivityAutomationPeer,
// using "this" returns null. This can cause issues with some UIA Client scenarios like any navigation in Narrator.
_parentProvider = parentProvider ? parentProvider.as<IAutomationPeerProtected>().ProviderFromPeer(parentProvider) : nullptr;
}
// 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()
{
SelectionChanged.raise(*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()
{
TextChanged.raise(*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()
{
CursorChanged.raise(*this, nullptr);
}
void InteractivityAutomationPeer::NotifyNewOutput(std::wstring_view newOutput)
{
NewOutput.raise(*this, hstring{ newOutput });
}
#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));
return _CreateXamlUiaTextRange(returnVal);
}
XamlAutomation::ITextRangeProvider InteractivityAutomationPeer::RangeFromPoint(Windows::Foundation::Point screenLocation)
{
UIA::ITextRangeProvider* returnVal;
THROW_IF_FAILED(_uiaProvider->RangeFromPoint({ screenLocation.X, screenLocation.Y }, &returnVal));
return _CreateXamlUiaTextRange(returnVal);
}
XamlAutomation::ITextRangeProvider InteractivityAutomationPeer::DocumentRange()
{
UIA::ITextRangeProvider* returnVal;
THROW_IF_FAILED(_uiaProvider->get_DocumentRange(&returnVal));
return _CreateXamlUiaTextRange(returnVal);
}
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
til::size InteractivityAutomationPeer::GetFontSize() const noexcept
{
return { til::math::rounding, _interactivity->Core().FontSize() };
}
til::rect InteractivityAutomationPeer::GetBounds() const noexcept
{
return _controlBounds;
}
HRESULT InteractivityAutomationPeer::GetHostUiaProvider(IRawElementProviderSimple** provider)
{
RETURN_HR_IF(E_INVALIDARG, provider == nullptr);
*provider = nullptr;
return S_OK;
}
til::rect InteractivityAutomationPeer::GetPadding() const noexcept
{
return _controlPadding;
}
void InteractivityAutomationPeer::ChangeViewport(const til::inclusive_rect& NewWindow)
{
_interactivity->UpdateScrollbar(static_cast<float>(NewWindow.top));
}
#pragma endregion
XamlAutomation::ITextRangeProvider InteractivityAutomationPeer::_CreateXamlUiaTextRange(UIA::ITextRangeProvider* returnVal) const
{
if (!_parentProvider)
{
return nullptr;
}
const auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, _parentProvider);
return xutr.as<XamlAutomation::ITextRangeProvider>();
};
// 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)
{
if (!_parentProvider)
{
return {};
}
// transfer ownership of UiaTextRanges to this new vector
auto providers = SafeArrayToOwningVector<::Microsoft::Terminal::TermControlUiaTextRange>(textRanges);
const auto len = gsl::narrow<uint32_t>(providers.size());
com_array<XamlAutomation::ITextRangeProvider> result{ len };
for (uint32_t i = 0; i < len; ++i)
{
if (auto xutr = _CreateXamlUiaTextRange(providers[i].detach()))
{
result[i] = std::move(xutr);
}
}
return result;
}
}

View File

@@ -1,90 +0,0 @@
/*++
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);
void ParentProvider(Windows::UI::Xaml::Automation::Peers::AutomationPeer parentProvider);
#pragma region IUiaEventDispatcher
void SignalSelectionChanged() override;
void SignalTextChanged() override;
void SignalCursorChanged() override;
void NotifyNewOutput(std::wstring_view newOutput) 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 til::size GetFontSize() const noexcept override;
virtual til::rect GetBounds() const noexcept override;
virtual til::rect GetPadding() const noexcept override;
virtual void ChangeViewport(const til::inclusive_rect& NewWindow) override;
virtual HRESULT GetHostUiaProvider(IRawElementProviderSimple** provider) override;
#pragma endregion
til::typed_event<IInspectable, IInspectable> SelectionChanged;
til::typed_event<IInspectable, IInspectable> TextChanged;
til::typed_event<IInspectable, IInspectable> CursorChanged;
til::typed_event<IInspectable, hstring> NewOutput;
private:
Windows::UI::Xaml::Automation::Provider::ITextRangeProvider _CreateXamlUiaTextRange(::ITextRangeProvider* returnVal) const;
::Microsoft::WRL::ComPtr<::Microsoft::Terminal::TermControlUiaProvider> _uiaProvider;
winrt::Microsoft::Terminal::Control::implementation::ControlInteractivity* _interactivity;
winrt::Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple _parentProvider{ nullptr };
til::rect _controlBounds{};
til::rect _controlPadding{};
winrt::com_array<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider> WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges);
};
}

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -10,8 +10,6 @@
#include "../../renderer/uia/UiaRenderer.hpp"
#include "../../tsf/Handle.h"
#include "ControlInteractivity.h"
namespace Microsoft::Console::VirtualTerminal
{
struct MouseButtonState;
@@ -19,7 +17,10 @@ namespace Microsoft::Console::VirtualTerminal
namespace winrt::Microsoft::Terminal::Control::implementation
{
struct ControlCore;
struct ControlInteractivity;
struct TermControl;
struct TermControlAutomationPeer;
struct TsfDataProvider : ::Microsoft::Console::TSF::IDataProvider
{
@@ -195,9 +196,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
Control::CursorDisplayState CursorVisibility() const noexcept;
void CursorVisibility(Control::CursorDisplayState cursorVisibility);
void ApplyPreviewColorScheme(const Core::ICoreScheme& scheme) { _core.ApplyPreviewColorScheme(scheme); }
void ResetPreviewColorScheme() { _core.ResetPreviewColorScheme(); }
void SetOverrideColorScheme(const Core::ICoreScheme& scheme) { _core.SetOverrideColorScheme(scheme); }
void ApplyPreviewColorScheme(const Core::ICoreScheme& scheme);
void ResetPreviewColorScheme();
void SetOverrideColorScheme(const Core::ICoreScheme& scheme);
// -------------------------------- WinRT Events ---------------------------------
// clang-format off
@@ -238,6 +239,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
private:
friend struct TermControlT<TermControl>; // friend our parent so it can bind private event handlers
friend struct TermControlAutomationPeer;
friend struct TsfDataProvider;
// NOTE: _uiaEngine must be ordered before _core.
@@ -248,9 +250,9 @@ 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!
Control::TermControlAutomationPeer _automationPeer{ nullptr };
Control::ControlInteractivity _interactivity{ nullptr };
Control::ControlCore _core{ nullptr };
winrt::com_ptr<Control::implementation::TermControlAutomationPeer> _automationPeer{ nullptr };
winrt::com_ptr<Control::implementation::ControlInteractivity> _interactivity{ nullptr };
winrt::com_ptr<Control::implementation::ControlCore> _core{ nullptr };
Control::IKeyBindings _keyBindings{ nullptr };
TsfDataProvider _tsfDataProvider{ this };
winrt::com_ptr<SearchBoxControl> _searchBox;

View File

@@ -5,7 +5,6 @@
#include <UIAutomationCore.h>
#include "TermControlAutomationPeer.h"
#include "TermControl.h"
#include "TermControlAutomationPeer.g.cpp"
#include "XamlUiaTextRange.h"
#include "../types/UiaTracing.h"
@@ -66,45 +65,13 @@ static constexpr bool IsReadable(std::wstring_view text)
namespace winrt::Microsoft::Terminal::Control::implementation
{
TermControlAutomationPeer::TermControlAutomationPeer(winrt::com_ptr<TermControl> owner,
const Core::Padding padding,
Control::InteractivityAutomationPeer impl) :
TermControlAutomationPeerT<TermControlAutomationPeer>(*owner.get()), // pass owner to FrameworkElementAutomationPeer
_termControl{ owner },
_contentAutomationPeer{ impl }
TermControlAutomationPeer::TermControlAutomationPeer(winrt::com_ptr<TermControl> owner) :
FrameworkElementAutomationPeerT(*owner.get()), // pass owner to FrameworkElementAutomationPeer
_termControl{ owner }
{
UpdateControlBounds();
SetControlPadding(padding);
// 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(); });
_contentAutomationPeer.NewOutput([this](auto&&, hstring newOutput) { NotifyNewOutput(newOutput); });
_contentAutomationPeer.ParentProvider(*this);
THROW_IF_FAILED(::Microsoft::WRL::MakeAndInitialize<::Microsoft::Terminal::TermControlUiaProvider>(&_uiaProvider, owner->_core->GetRenderData(), this));
};
// 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);
}
void TermControlAutomationPeer::RecordKeyEvent(const WORD vkey)
{
if (const auto charCode{ MapVirtualKey(vkey, MAPVK_VK_TO_CHAR) })
@@ -121,9 +88,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// GH#13978: If the TermControl has already been removed from the UI tree, XAML might run into weird bugs.
// This will prevent the `dispatcher.RunAsync` calls below from raising UIA events on the main thread.
_termControl = {};
// Solve the circular reference between us and the content automation peer.
_contentAutomationPeer.ParentProvider(nullptr);
}
// Method Description:
@@ -341,33 +305,126 @@ namespace winrt::Microsoft::Terminal::Control::implementation
#pragma region ITextProvider
com_array<XamlAutomation::ITextRangeProvider> TermControlAutomationPeer::GetSelection()
{
return _contentAutomationPeer.GetSelection();
SAFEARRAY* pReturnVal;
THROW_IF_FAILED(_uiaProvider->GetSelection(&pReturnVal));
return WrapArrayOfTextRangeProviders(pReturnVal);
}
com_array<XamlAutomation::ITextRangeProvider> TermControlAutomationPeer::GetVisibleRanges()
{
return _contentAutomationPeer.GetVisibleRanges();
SAFEARRAY* pReturnVal;
THROW_IF_FAILED(_uiaProvider->GetVisibleRanges(&pReturnVal));
return WrapArrayOfTextRangeProviders(pReturnVal);
}
XamlAutomation::ITextRangeProvider TermControlAutomationPeer::RangeFromChild(XamlAutomation::IRawElementProviderSimple childElement)
XamlAutomation::ITextRangeProvider TermControlAutomationPeer::RangeFromChild(XamlAutomation::IRawElementProviderSimple /*childElement*/)
{
return _contentAutomationPeer.RangeFromChild(childElement);
UIA::ITextRangeProvider* returnVal;
// ScreenInfoUiaProvider doesn't actually use parameter, so just pass in nullptr
THROW_IF_FAILED(_uiaProvider->RangeFromChild(/* IRawElementProviderSimple */ nullptr,
&returnVal));
return _CreateXamlUiaTextRange(returnVal);
}
XamlAutomation::ITextRangeProvider TermControlAutomationPeer::RangeFromPoint(Windows::Foundation::Point screenLocation)
{
return _contentAutomationPeer.RangeFromPoint(screenLocation);
UIA::ITextRangeProvider* returnVal;
THROW_IF_FAILED(_uiaProvider->RangeFromPoint({ screenLocation.X, screenLocation.Y }, &returnVal));
return _CreateXamlUiaTextRange(returnVal);
}
XamlAutomation::ITextRangeProvider TermControlAutomationPeer::DocumentRange()
{
return _contentAutomationPeer.DocumentRange();
UIA::ITextRangeProvider* returnVal;
THROW_IF_FAILED(_uiaProvider->get_DocumentRange(&returnVal));
return _CreateXamlUiaTextRange(returnVal);
}
XamlAutomation::SupportedTextSelection TermControlAutomationPeer::SupportedTextSelection()
{
return _contentAutomationPeer.SupportedTextSelection();
UIA::SupportedTextSelection returnVal;
THROW_IF_FAILED(_uiaProvider->get_SupportedTextSelection(&returnVal));
return static_cast<XamlAutomation::SupportedTextSelection>(returnVal);
}
#pragma endregion
#pragma region IControlAccessibilityInfo
til::size TermControlAutomationPeer::GetFontSize() const noexcept
{
if (const auto control{ _termControl.get() })
{
return { til::math::rounding, control->_core->FontSize() };
}
return {};
}
til::rect TermControlAutomationPeer::GetBounds() const noexcept
{
return { til::math::rounding, GetBoundingRectangle() };
}
HRESULT TermControlAutomationPeer::GetHostUiaProvider(IRawElementProviderSimple** provider)
{
RETURN_HR_IF(E_INVALIDARG, provider == nullptr);
*provider = nullptr;
return S_OK;
}
til::rect TermControlAutomationPeer::GetPadding() const noexcept
{
if (const auto control{ _termControl.get() })
{
const auto padding{ control->GetPadding() };
return {
til::math::rounding,
padding.Left,
padding.Top,
padding.Right,
padding.Bottom,
};
}
return {};
}
void TermControlAutomationPeer::ChangeViewport(const til::inclusive_rect& NewWindow)
{
if (const auto control{ _termControl.get() })
{
control->_interactivity->UpdateScrollbar(static_cast<float>(NewWindow.top));
}
}
#pragma endregion
XamlAutomation::ITextRangeProvider TermControlAutomationPeer::_CreateXamlUiaTextRange(UIA::ITextRangeProvider* returnVal) const
{
const auto provider = ProviderFromPeer(*this);
const auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, provider);
return xutr.as<XamlAutomation::ITextRangeProvider>();
};
// 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> TermControlAutomationPeer::WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges)
{
// transfer ownership of UiaTextRanges to this new vector
auto providers = SafeArrayToOwningVector<::Microsoft::Terminal::TermControlUiaTextRange>(textRanges);
const auto len = gsl::narrow<uint32_t>(providers.size());
com_array<XamlAutomation::ITextRangeProvider> result{ len };
for (uint32_t i = 0; i < len; ++i)
{
if (auto xutr = _CreateXamlUiaTextRange(providers[i].detach()))
{
result[i] = std::move(xutr);
}
}
return result;
}
}

View File

@@ -20,16 +20,11 @@ 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 "ControlInteractivity.h"
#include "TermControlAutomationPeer.g.h"
#include "../types/TermControlUiaProvider.hpp"
#include "../types/IUiaEventDispatcher.h"
#include "../types/IControlAccessibilityInfo.h"
@@ -39,16 +34,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
struct TermControl;
struct TermControlAutomationPeer :
public TermControlAutomationPeerT<TermControlAutomationPeer>,
::Microsoft::Console::Types::IUiaEventDispatcher
public winrt::Windows::UI::Xaml::Automation::Peers::FrameworkElementAutomationPeerT<TermControlAutomationPeer,
winrt::Windows::UI::Xaml::Automation::Provider::ITextProvider>,
::Microsoft::Console::Types::IUiaEventDispatcher,
::Microsoft::Console::Types::IControlAccessibilityInfo
{
public:
TermControlAutomationPeer(winrt::com_ptr<Microsoft::Terminal::Control::implementation::TermControl> owner,
const Core::Padding padding,
Control::InteractivityAutomationPeer implementation);
TermControlAutomationPeer(winrt::com_ptr<Microsoft::Terminal::Control::implementation::TermControl> owner);
void UpdateControlBounds();
void SetControlPadding(const Core::Padding padding);
void RecordKeyEvent(const WORD vkey);
void Close();
@@ -79,9 +72,23 @@ namespace winrt::Microsoft::Terminal::Control::implementation
Windows::UI::Xaml::Automation::Provider::ITextRangeProvider DocumentRange();
#pragma endregion
#pragma region IControlAccessibilityInfo Pattern
// Inherited via IControlAccessibilityInfo
virtual til::size GetFontSize() const noexcept override;
virtual til::rect GetBounds() const noexcept override;
virtual til::rect GetPadding() const noexcept override;
virtual void ChangeViewport(const til::inclusive_rect& NewWindow) override;
virtual HRESULT GetHostUiaProvider(IRawElementProviderSimple** provider) override;
#pragma endregion
private:
Windows::UI::Xaml::Automation::Provider::ITextRangeProvider _CreateXamlUiaTextRange(::ITextRangeProvider* returnVal) const;
winrt::com_array<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider> WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges);
winrt::weak_ref<Microsoft::Terminal::Control::implementation::TermControl> _termControl;
Control::InteractivityAutomationPeer _contentAutomationPeer;
::Microsoft::WRL::ComPtr<::Microsoft::Terminal::TermControlUiaProvider> _uiaProvider;
til::rect _controlPadding{};
til::shared_mutex<std::deque<wchar_t>> _keyEvents;
};
}

View File

@@ -1,16 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "TermControl.idl";
namespace Microsoft.Terminal.Control
{
[default_interface] runtimeclass TermControlAutomationPeer :
Windows.UI.Xaml.Automation.Peers.FrameworkElementAutomationPeer,
Windows.UI.Xaml.Automation.Provider.ITextProvider
{
void UpdateControlBounds();
void SetControlPadding(Microsoft.Terminal.Core.Padding padding);
}
}

View File

@@ -54,12 +54,7 @@
<ClInclude Include="TermControl.h">
<DependentUpon>TermControl.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="TermControlAutomationPeer.h">
<DependentUpon>TermControlAutomationPeer.idl</DependentUpon>
</ClInclude>
<ClInclude Include="InteractivityAutomationPeer.h">
<DependentUpon>InteractivityAutomationPeer.idl</DependentUpon>
</ClInclude>
<ClInclude Include="TermControlAutomationPeer.h" />
<ClInclude Include="XamlUiaTextRange.h" />
<ClInclude Include="HwndTerminal.hpp" />
<ClInclude Include="HwndTerminalAutomationPeer.hpp" />
@@ -95,12 +90,7 @@
<DependentUpon>TermControl.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="TermControlAutomationPeer.cpp">
<DependentUpon>TermControlAutomationPeer.idl</DependentUpon>
</ClCompile>
<ClCompile Include="InteractivityAutomationPeer.cpp">
<DependentUpon>InteractivityAutomationPeer.idl</DependentUpon>
</ClCompile>
<ClCompile Include="TermControlAutomationPeer.cpp" />
<ClCompile Include="XamlUiaTextRange.cpp" />
<ClCompile Include="HwndTerminal.cpp" />
<ClCompile Include="HwndTerminalAutomationPeer.cpp" />
@@ -123,8 +113,6 @@
<Midl Include="TermControl.idl">
<DependentUpon>TermControl.xaml</DependentUpon>
</Midl>
<Midl Include="TermControlAutomationPeer.idl" />
<Midl Include="InteractivityAutomationPeer.idl" />
<Midl Include="IMouseWheelListener.idl" />
</ItemGroup>
<!-- ========================= XAML Files ======================== -->
@@ -183,4 +171,4 @@
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
</Project>
</Project>

View File

@@ -35,6 +35,7 @@
#include <winrt/Windows.UI.ViewManagement.h>
#include <winrt/Windows.UI.Xaml.h>
#include <winrt/Windows.UI.Xaml.Automation.Peers.h>
#include <winrt/Windows.UI.Xaml.Automation.Provider.h>
#include <winrt/Windows.UI.Text.Core.h>
#include <winrt/Windows.UI.Xaml.Controls.h>
#include <winrt/Windows.UI.Xaml.Controls.Primitives.h>