Custom WinRT implementation

This commit is contained in:
Leonard Hecker 2025-12-09 16:40:21 +01:00
parent 62312a8943
commit f02bfe06dc
5 changed files with 397 additions and 181 deletions

View File

@ -49,7 +49,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void InteractivityAutomationPeer::ParentProvider(AutomationPeer parentProvider)
{
_parentProvider = 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:
@ -181,15 +184,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
XamlAutomation::ITextRangeProvider InteractivityAutomationPeer::_CreateXamlUiaTextRange(UIA::ITextRangeProvider* returnVal) const
{
// 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.
const auto parent{ _parentProvider.get() };
if (!parent)
if (!_parentProvider)
{
return nullptr;
}
return winrt::make<XamlUiaTextRange>(returnVal, parent.as<IAutomationPeerProtected>().ProviderFromPeer(parent));
return XamlUiaTextRange::Create(returnVal, _parentProvider);
};
// Method Description:
@ -200,21 +199,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - 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);
auto count = gsl::narrow<int>(providers.size());
std::vector<XamlAutomation::ITextRangeProvider> vec;
vec.reserve(count);
for (auto i = 0; i < count; i++)
if (!_parentProvider)
{
if (auto xutr = _CreateXamlUiaTextRange(providers[i].detach()))
{
vec.emplace_back(std::move(xutr));
}
return {};
}
com_array<XamlAutomation::ITextRangeProvider> result{ vec };
// 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)
{
result[i] = XamlUiaTextRange::Create(providers[i].detach(), _parentProvider);
}
return result;
}

View File

@ -80,7 +80,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
::Microsoft::WRL::ComPtr<::Microsoft::Terminal::TermControlUiaProvider> _uiaProvider;
winrt::Microsoft::Terminal::Control::implementation::ControlInteractivity* _interactivity;
weak_ref<Windows::UI::Xaml::Automation::Peers::AutomationPeer> _parentProvider;
winrt::Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple _parentProvider{ nullptr };
til::rect _controlBounds{};
til::rect _controlPadding{};

View File

@ -121,6 +121,9 @@ 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:
@ -338,27 +341,43 @@ namespace winrt::Microsoft::Terminal::Control::implementation
#pragma region ITextProvider
com_array<XamlAutomation::ITextRangeProvider> TermControlAutomationPeer::GetSelection()
{
return _contentAutomationPeer.GetSelection();
auto ret = _contentAutomationPeer.GetSelection();
for (const auto& r : ret)
{
assert(((XamlUiaTextRange*)winrt::get_abi(r))->_refCount.load(std::memory_order_relaxed) == 1);
}
return ret;
}
com_array<XamlAutomation::ITextRangeProvider> TermControlAutomationPeer::GetVisibleRanges()
{
return _contentAutomationPeer.GetVisibleRanges();
auto ret = _contentAutomationPeer.GetVisibleRanges();
for (const auto& r : ret)
{
assert(((XamlUiaTextRange*)winrt::get_abi(r))->_refCount.load(std::memory_order_relaxed) == 1);
}
return ret;
}
XamlAutomation::ITextRangeProvider TermControlAutomationPeer::RangeFromChild(XamlAutomation::IRawElementProviderSimple childElement)
{
return _contentAutomationPeer.RangeFromChild(childElement);
auto r = _contentAutomationPeer.RangeFromChild(childElement);
assert(((XamlUiaTextRange*)winrt::get_abi(r))->_refCount.load(std::memory_order_relaxed) == 1);
return r;
}
XamlAutomation::ITextRangeProvider TermControlAutomationPeer::RangeFromPoint(Windows::Foundation::Point screenLocation)
{
return _contentAutomationPeer.RangeFromPoint(screenLocation);
auto r = _contentAutomationPeer.RangeFromPoint(screenLocation);
assert(((XamlUiaTextRange*)winrt::get_abi(r))->_refCount.load(std::memory_order_relaxed) == 1);
return r;
}
XamlAutomation::ITextRangeProvider TermControlAutomationPeer::DocumentRange()
{
return _contentAutomationPeer.DocumentRange();
auto r = _contentAutomationPeer.DocumentRange();
assert(((XamlUiaTextRange*)winrt::get_abi(r))->_refCount.load(std::memory_order_relaxed) == 1);
return r;
}
XamlAutomation::SupportedTextSelection TermControlAutomationPeer::SupportedTextSelection()

View File

@ -33,6 +33,14 @@ static std::atomic<int64_t> refCount_XamlUiaTextRange;
namespace winrt::Microsoft::Terminal::Control::implementation
{
XamlAutomation::ITextRangeProvider XamlUiaTextRange::Create(::ITextRangeProvider* uiaProvider, Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple parentProvider)
{
const auto self = new XamlUiaTextRange(uiaProvider, parentProvider);
XamlAutomation::ITextRangeProvider provider{ nullptr };
winrt::attach_abi(provider, (ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider*)self);
return provider;
}
XamlUiaTextRange::XamlUiaTextRange(::ITextRangeProvider* uiaProvider, Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple parentProvider) :
_parentProvider{ std::move(parentProvider) }
{
@ -46,225 +54,398 @@ namespace winrt::Microsoft::Terminal::Control::implementation
refCount_XamlUiaTextRange.fetch_sub(1, std::memory_order_relaxed);
}
XamlAutomation::ITextRangeProvider XamlUiaTextRange::Clone() const
IFACEMETHODIMP_(ULONG) XamlUiaTextRange::AddRef() noexcept
{
UIA::ITextRangeProvider* pReturn;
THROW_IF_FAILED(_uiaProvider->Clone(&pReturn));
return winrt::make<XamlUiaTextRange>(pReturn, _parentProvider);
return _refCount.fetch_add(1, std::memory_order_relaxed) + 1;
}
bool XamlUiaTextRange::Compare(XamlAutomation::ITextRangeProvider pRange) const
IFACEMETHODIMP_(ULONG) XamlUiaTextRange::Release() noexcept
{
auto self = winrt::get_self<XamlUiaTextRange>(pRange);
const auto count = _refCount.fetch_sub(1, std::memory_order_release) - 1;
if (count == 0)
{
std::atomic_thread_fence(std::memory_order_acquire);
delete this;
}
return count;
}
IFACEMETHODIMP XamlUiaTextRange::QueryInterface(REFIID riid, void** ppvObject) noexcept
{
if (!ppvObject)
{
return E_INVALIDARG;
}
*ppvObject = nullptr;
if (riid == __uuidof(ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider) ||
riid == __uuidof(IInspectable) ||
riid == __uuidof(IUnknown))
{
*ppvObject = static_cast<ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider*>(this);
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
IFACEMETHODIMP XamlUiaTextRange::GetIids(ULONG* iidCount, IID** iids) noexcept
{
if (!iidCount || !iids)
{
return E_INVALIDARG;
}
*iidCount = 1;
*iids = static_cast<IID*>(CoTaskMemAlloc(sizeof(IID)));
if (!*iids)
{
return E_OUTOFMEMORY;
}
(*iids)[0] = __uuidof(ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider);
return S_OK;
}
IFACEMETHODIMP XamlUiaTextRange::GetRuntimeClassName(HSTRING* className) noexcept
{
if (!className)
{
return E_INVALIDARG;
}
return WindowsCreateString(L"Microsoft.Terminal.Control.XamlUiaTextRange", 47, className);
}
IFACEMETHODIMP XamlUiaTextRange::GetTrustLevel(TrustLevel* trustLevel) noexcept
{
if (!trustLevel)
{
return E_INVALIDARG;
}
*trustLevel = TrustLevel::BaseTrust;
return S_OK;
}
IFACEMETHODIMP XamlUiaTextRange::Clone(ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider** result) noexcept
try
{
RETURN_HR_IF_NULL(E_INVALIDARG, result);
*result = nullptr;
UIA::ITextRangeProvider* pReturn;
RETURN_IF_FAILED(_uiaProvider->Clone(&pReturn));
auto xamlRange = new (std::nothrow) XamlUiaTextRange(pReturn, _parentProvider);
RETURN_IF_NULL_ALLOC(xamlRange);
*result = xamlRange;
return S_OK;
}
CATCH_RETURN();
IFACEMETHODIMP XamlUiaTextRange::Compare(ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider* textRangeProvider, boolean* result) noexcept
try
{
RETURN_HR_IF_NULL(E_INVALIDARG, result);
*result = false;
RETURN_HR_IF_NULL(E_INVALIDARG, textRangeProvider);
auto self = static_cast<XamlUiaTextRange*>(textRangeProvider);
BOOL returnVal;
THROW_IF_FAILED(_uiaProvider->Compare(self->_uiaProvider.get(), &returnVal));
return returnVal;
RETURN_IF_FAILED(_uiaProvider->Compare(self->_uiaProvider.get(), &returnVal));
*result = !!returnVal;
return S_OK;
}
CATCH_RETURN();
int32_t XamlUiaTextRange::CompareEndpoints(XamlAutomation::TextPatternRangeEndpoint endpoint,
XamlAutomation::ITextRangeProvider pTargetRange,
XamlAutomation::TextPatternRangeEndpoint targetEndpoint)
IFACEMETHODIMP XamlUiaTextRange::CompareEndpoints(ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint,
ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider* textRangeProvider,
ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint targetEndpoint,
INT32* result) noexcept
try
{
auto self = winrt::get_self<XamlUiaTextRange>(pTargetRange);
RETURN_HR_IF_NULL(E_INVALIDARG, result);
*result = 0;
RETURN_HR_IF_NULL(E_INVALIDARG, textRangeProvider);
auto self = static_cast<XamlUiaTextRange*>(textRangeProvider);
int32_t returnVal;
THROW_IF_FAILED(_uiaProvider->CompareEndpoints(static_cast<UIA::TextPatternRangeEndpoint>(endpoint),
self->_uiaProvider.get(),
static_cast<UIA::TextPatternRangeEndpoint>(targetEndpoint),
&returnVal));
return returnVal;
RETURN_IF_FAILED(_uiaProvider->CompareEndpoints(static_cast<UIA::TextPatternRangeEndpoint>(endpoint),
self->_uiaProvider.get(),
static_cast<UIA::TextPatternRangeEndpoint>(targetEndpoint),
&returnVal));
*result = returnVal;
return S_OK;
}
CATCH_RETURN();
void XamlUiaTextRange::ExpandToEnclosingUnit(XamlAutomation::TextUnit unit) const
IFACEMETHODIMP XamlUiaTextRange::ExpandToEnclosingUnit(ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit) noexcept
try
{
THROW_IF_FAILED(_uiaProvider->ExpandToEnclosingUnit(static_cast<UIA::TextUnit>(unit)));
RETURN_IF_FAILED(_uiaProvider->ExpandToEnclosingUnit(static_cast<UIA::TextUnit>(unit)));
return S_OK;
}
CATCH_RETURN();
XamlAutomation::ITextRangeProvider XamlUiaTextRange::FindAttribute(int32_t /*textAttributeId*/,
winrt::Windows::Foundation::IInspectable /*val*/,
bool /*searchBackward*/)
IFACEMETHODIMP XamlUiaTextRange::FindAttribute(INT32 /*attributeId*/,
IInspectable* /*value*/,
boolean /*backward*/,
ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider** result) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, result);
*result = nullptr;
// TODO GitHub #2161: potential accessibility improvement
// we don't support this currently
throw winrt::hresult_not_implemented();
return E_NOTIMPL;
}
XamlAutomation::ITextRangeProvider XamlUiaTextRange::FindText(winrt::hstring text,
bool searchBackward,
bool ignoreCase)
IFACEMETHODIMP XamlUiaTextRange::FindText(HSTRING text,
boolean searchBackward,
boolean ignoreCase,
ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider** result) noexcept
try
{
RETURN_HR_IF_NULL(E_INVALIDARG, result);
*result = nullptr;
UIA::ITextRangeProvider* pReturn;
const auto queryText = wil::make_bstr(text.c_str());
uint32_t length;
const auto textPtr = WindowsGetStringRawBuffer(text, &length);
const auto queryText = wil::unique_bstr{ SysAllocStringLen(textPtr, length) };
THROW_IF_FAILED(_uiaProvider->FindText(queryText.get(), searchBackward, ignoreCase, &pReturn));
RETURN_IF_FAILED(_uiaProvider->FindText(queryText.get(), searchBackward, ignoreCase, &pReturn));
return winrt::make<XamlUiaTextRange>(pReturn, _parentProvider);
if (pReturn)
{
auto xamlRange = new (std::nothrow) XamlUiaTextRange(pReturn, _parentProvider);
RETURN_IF_NULL_ALLOC(xamlRange);
*result = xamlRange;
}
return S_OK;
}
CATCH_RETURN();
winrt::Windows::Foundation::IInspectable XamlUiaTextRange::GetAttributeValue(int32_t textAttributeId) const
IFACEMETHODIMP XamlUiaTextRange::GetAttributeValue(INT32 attributeId, IInspectable** result) noexcept
try
{
RETURN_HR_IF_NULL(E_INVALIDARG, result);
*result = nullptr;
// Call the function off of the underlying UiaTextRange.
wil::unique_variant result;
THROW_IF_FAILED(_uiaProvider->GetAttributeValue(textAttributeId, result.addressof()));
wil::unique_variant varResult;
RETURN_IF_FAILED(_uiaProvider->GetAttributeValue(attributeId, varResult.addressof()));
// Convert the resulting VARIANT into a format that is consumable by XAML.
switch (result.vt)
switch (varResult.vt)
{
case VT_BSTR:
{
return box_value(result.bstrVal);
auto value = winrt::box_value(varResult.bstrVal);
*result = static_cast<IInspectable*>(winrt::detach_abi(value));
return S_OK;
}
case VT_I4:
{
// Surprisingly, `long` is _not_ a WinRT type.
// So we have to use `int32_t` to make sure this is output properly.
// Otherwise, you'll get "Attribute does not exist" out the other end.
return box_value<int32_t>(result.lVal);
auto value = winrt::box_value<int32_t>(varResult.lVal);
*result = static_cast<IInspectable*>(winrt::detach_abi(value));
return S_OK;
}
case VT_R8:
{
return box_value(result.dblVal);
auto value = winrt::box_value(varResult.dblVal);
*result = static_cast<IInspectable*>(winrt::detach_abi(value));
return S_OK;
}
case VT_BOOL:
{
return box_value<bool>(result.boolVal);
auto value = winrt::box_value<bool>(varResult.boolVal);
*result = static_cast<IInspectable*>(winrt::detach_abi(value));
return S_OK;
}
case VT_UNKNOWN:
{
// This one is particularly special.
// We might return a special value like UiaGetReservedMixedAttributeValue
// or UiaGetReservedNotSupportedValue.
// Some text attributes may return a real value, however, none of those
// are supported at this time.
// So we need to figure out what was actually intended to be returned.
com_ptr<IUnknown> mixedAttributeVal;
UiaGetReservedMixedAttributeValue(mixedAttributeVal.put());
if (result.punkVal == mixedAttributeVal.get())
if (varResult.punkVal == mixedAttributeVal.get())
{
return Windows::UI::Xaml::DependencyProperty::UnsetValue();
auto value = Windows::UI::Xaml::DependencyProperty::UnsetValue();
*result = static_cast<IInspectable*>(winrt::detach_abi(value));
return S_OK;
}
[[fallthrough]];
}
default:
{
// We _need_ to return XAML_E_NOT_SUPPORTED here.
// Returning nullptr is an improper implementation of it being unsupported.
// UIA Clients rely on this HRESULT to signify that the requested attribute is undefined.
// Anything else will result in the UIA Client refusing to read when navigating by word
// Magically, this doesn't affect other forms of navigation...
winrt::throw_hresult(XAML_E_NOT_SUPPORTED);
}
return XAML_E_NOT_SUPPORTED;
}
}
CATCH_RETURN();
void XamlUiaTextRange::GetBoundingRectangles(com_array<double>& returnValue) const
IFACEMETHODIMP XamlUiaTextRange::GetBoundingRectangles(UINT32* returnValueLength, DOUBLE** returnValue) noexcept
try
{
returnValue = {};
try
RETURN_HR_IF_NULL(E_INVALIDARG, returnValueLength);
RETURN_HR_IF_NULL(E_INVALIDARG, returnValue);
*returnValueLength = 0;
*returnValue = nullptr;
SAFEARRAY* pReturnVal;
RETURN_IF_FAILED(_uiaProvider->GetBoundingRectangles(&pReturnVal));
double* pVals;
RETURN_IF_FAILED(SafeArrayAccessData(pReturnVal, (void**)&pVals));
long lBound, uBound;
RETURN_IF_FAILED(SafeArrayGetLBound(pReturnVal, 1, &lBound));
RETURN_IF_FAILED(SafeArrayGetUBound(pReturnVal, 1, &uBound));
auto count = uBound - lBound + 1;
auto result = static_cast<DOUBLE*>(CoTaskMemAlloc(sizeof(DOUBLE) * count));
if (!result)
{
SAFEARRAY* pReturnVal;
THROW_IF_FAILED(_uiaProvider->GetBoundingRectangles(&pReturnVal));
double* pVals;
THROW_IF_FAILED(SafeArrayAccessData(pReturnVal, (void**)&pVals));
long lBound, uBound;
THROW_IF_FAILED(SafeArrayGetLBound(pReturnVal, 1, &lBound));
THROW_IF_FAILED(SafeArrayGetUBound(pReturnVal, 1, &uBound));
auto count = uBound - lBound + 1;
std::vector<double> vec;
vec.reserve(count);
for (auto i = 0; i < count; i++)
{
auto element = pVals[i];
vec.push_back(element);
}
winrt::com_array<double> result{ vec };
returnValue = std::move(result);
THROW_IF_FAILED(SafeArrayUnaccessData(pReturnVal));
THROW_IF_FAILED(SafeArrayDestroy(pReturnVal));
SafeArrayUnaccessData(pReturnVal);
SafeArrayDestroy(pReturnVal);
return E_OUTOFMEMORY;
}
CATCH_LOG();
}
XamlAutomation::IRawElementProviderSimple XamlUiaTextRange::GetEnclosingElement()
for (auto i = 0; i < count; i++)
{
result[i] = pVals[i];
}
*returnValueLength = count;
*returnValue = result;
RETURN_IF_FAILED(SafeArrayUnaccessData(pReturnVal));
RETURN_IF_FAILED(SafeArrayDestroy(pReturnVal));
return S_OK;
}
CATCH_RETURN();
IFACEMETHODIMP XamlUiaTextRange::GetEnclosingElement(ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple** result) noexcept
try
{
RETURN_HR_IF_NULL(E_INVALIDARG, result);
*result = nullptr;
::Microsoft::Console::Types::UiaTracing::TextRange::GetEnclosingElement(*static_cast<::Microsoft::Console::Types::UiaTextRangeBase*>(_uiaProvider.get()));
return _parentProvider;
winrt::copy_to_abi(_parentProvider, (void*&)*result);
return S_OK;
}
CATCH_RETURN();
winrt::hstring XamlUiaTextRange::GetText(int32_t maxLength) const
IFACEMETHODIMP XamlUiaTextRange::GetText(INT32 maxLength, HSTRING* result) noexcept
try
{
RETURN_HR_IF_NULL(E_INVALIDARG, result);
*result = nullptr;
wil::unique_bstr returnVal;
THROW_IF_FAILED(_uiaProvider->GetText(maxLength, returnVal.put()));
return winrt::hstring{ returnVal.get(), SysStringLen(returnVal.get()) };
}
RETURN_IF_FAILED(_uiaProvider->GetText(maxLength, returnVal.put()));
int32_t XamlUiaTextRange::Move(XamlAutomation::TextUnit unit,
int32_t count)
RETURN_IF_FAILED(WindowsCreateString(returnVal.get(), SysStringLen(returnVal.get()), result));
return S_OK;
}
CATCH_RETURN();
IFACEMETHODIMP XamlUiaTextRange::Move(ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit,
INT32 count,
INT32* result) noexcept
try
{
RETURN_HR_IF_NULL(E_INVALIDARG, result);
*result = 0;
int returnVal;
THROW_IF_FAILED(_uiaProvider->Move(static_cast<UIA::TextUnit>(unit),
count,
&returnVal));
return returnVal;
RETURN_IF_FAILED(_uiaProvider->Move(static_cast<UIA::TextUnit>(unit),
count,
&returnVal));
*result = returnVal;
return S_OK;
}
CATCH_RETURN();
int32_t XamlUiaTextRange::MoveEndpointByUnit(XamlAutomation::TextPatternRangeEndpoint endpoint,
XamlAutomation::TextUnit unit,
int32_t count) const
IFACEMETHODIMP XamlUiaTextRange::MoveEndpointByUnit(ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint,
ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit,
INT32 count,
INT32* result) noexcept
try
{
RETURN_HR_IF_NULL(E_INVALIDARG, result);
*result = 0;
int returnVal;
THROW_IF_FAILED(_uiaProvider->MoveEndpointByUnit(static_cast<UIA::TextPatternRangeEndpoint>(endpoint),
static_cast<UIA::TextUnit>(unit),
count,
&returnVal));
return returnVal;
RETURN_IF_FAILED(_uiaProvider->MoveEndpointByUnit(static_cast<UIA::TextPatternRangeEndpoint>(endpoint),
static_cast<UIA::TextUnit>(unit),
count,
&returnVal));
*result = returnVal;
return S_OK;
}
CATCH_RETURN();
void XamlUiaTextRange::MoveEndpointByRange(XamlAutomation::TextPatternRangeEndpoint endpoint,
XamlAutomation::ITextRangeProvider pTargetRange,
XamlAutomation::TextPatternRangeEndpoint targetEndpoint) const
IFACEMETHODIMP XamlUiaTextRange::MoveEndpointByRange(ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint,
ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider* textRangeProvider,
ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint targetEndpoint) noexcept
try
{
auto self = winrt::get_self<XamlUiaTextRange>(pTargetRange);
THROW_IF_FAILED(_uiaProvider->MoveEndpointByRange(static_cast<UIA::TextPatternRangeEndpoint>(endpoint),
/*pTargetRange*/ self->_uiaProvider.get(),
static_cast<UIA::TextPatternRangeEndpoint>(targetEndpoint)));
}
RETURN_HR_IF_NULL(E_INVALIDARG, textRangeProvider);
void XamlUiaTextRange::Select() const
auto self = static_cast<XamlUiaTextRange*>(textRangeProvider);
RETURN_IF_FAILED(_uiaProvider->MoveEndpointByRange(static_cast<UIA::TextPatternRangeEndpoint>(endpoint),
self->_uiaProvider.get(),
static_cast<UIA::TextPatternRangeEndpoint>(targetEndpoint)));
return S_OK;
}
CATCH_RETURN();
IFACEMETHODIMP XamlUiaTextRange::Select() noexcept
try
{
THROW_IF_FAILED(_uiaProvider->Select());
RETURN_IF_FAILED(_uiaProvider->Select());
return S_OK;
}
CATCH_RETURN();
void XamlUiaTextRange::AddToSelection() const
IFACEMETHODIMP XamlUiaTextRange::AddToSelection() noexcept
{
// we don't support this
throw winrt::hresult_not_implemented();
return E_NOTIMPL;
}
void XamlUiaTextRange::RemoveFromSelection() const
IFACEMETHODIMP XamlUiaTextRange::RemoveFromSelection() noexcept
{
// we don't support this
throw winrt::hresult_not_implemented();
return E_NOTIMPL;
}
void XamlUiaTextRange::ScrollIntoView(bool alignToTop) const
IFACEMETHODIMP XamlUiaTextRange::ScrollIntoView(boolean alignToTop) noexcept
try
{
THROW_IF_FAILED(_uiaProvider->ScrollIntoView(alignToTop));
RETURN_IF_FAILED(_uiaProvider->ScrollIntoView(alignToTop));
return S_OK;
}
CATCH_RETURN();
winrt::com_array<XamlAutomation::IRawElementProviderSimple> XamlUiaTextRange::GetChildren() const
IFACEMETHODIMP XamlUiaTextRange::GetChildren(UINT32* resultLength,
ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple*** result) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, resultLength);
RETURN_HR_IF_NULL(E_INVALIDARG, result);
// we don't have any children
return {};
*resultLength = 0;
*result = nullptr;
return S_OK;
}
}

View File

@ -23,50 +23,68 @@ Author(s):
#include "TermControlAutomationPeer.h"
#include <UIAutomationCore.h>
#include "../types/TermControlUiaTextRange.hpp"
#include <windows.ui.xaml.automation.provider.h>
namespace winrt::Microsoft::Terminal::Control::implementation
{
class XamlUiaTextRange :
public winrt::implements<XamlUiaTextRange, Windows::UI::Xaml::Automation::Provider::ITextRangeProvider>
class XamlUiaTextRange : public ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider
{
public:
static winrt::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider Create(::ITextRangeProvider* uiaProvider, Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple parentProvider);
XamlUiaTextRange(::ITextRangeProvider* uiaProvider, Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple parentProvider);
~XamlUiaTextRange();
// IUnknown
IFACEMETHODIMP_(ULONG) AddRef() noexcept override;
IFACEMETHODIMP_(ULONG) Release() noexcept override;
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppvObject) noexcept override;
// IInspectable
IFACEMETHODIMP GetIids(ULONG* iidCount, IID** iids) noexcept override;
IFACEMETHODIMP GetRuntimeClassName(HSTRING* className) noexcept override;
IFACEMETHODIMP GetTrustLevel(TrustLevel* trustLevel) noexcept override;
#pragma region ITextRangeProvider
Windows::UI::Xaml::Automation::Provider::ITextRangeProvider Clone() const;
bool Compare(Windows::UI::Xaml::Automation::Provider::ITextRangeProvider pRange) const;
int32_t CompareEndpoints(Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint,
Windows::UI::Xaml::Automation::Provider::ITextRangeProvider pTargetRange,
Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint targetEndpoint);
void ExpandToEnclosingUnit(Windows::UI::Xaml::Automation::Text::TextUnit unit) const;
Windows::UI::Xaml::Automation::Provider::ITextRangeProvider FindAttribute(int32_t textAttributeId,
winrt::Windows::Foundation::IInspectable val,
bool searchBackward);
Windows::UI::Xaml::Automation::Provider::ITextRangeProvider FindText(winrt::hstring text,
bool searchBackward,
bool ignoreCase);
winrt::Windows::Foundation::IInspectable GetAttributeValue(int32_t textAttributeId) const;
void GetBoundingRectangles(winrt::com_array<double>& returnValue) const;
Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple GetEnclosingElement();
winrt::hstring GetText(int32_t maxLength) const;
int32_t Move(Windows::UI::Xaml::Automation::Text::TextUnit unit,
int32_t count);
int32_t MoveEndpointByUnit(Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint,
Windows::UI::Xaml::Automation::Text::TextUnit unit,
int32_t count) const;
void MoveEndpointByRange(Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint,
Windows::UI::Xaml::Automation::Provider::ITextRangeProvider pTargetRange,
Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint targetEndpoint) const;
void Select() const;
void AddToSelection() const;
void RemoveFromSelection() const;
void ScrollIntoView(bool alignToTop) const;
winrt::com_array<Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple> GetChildren() const;
IFACEMETHODIMP Clone(ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider** result) noexcept override;
IFACEMETHODIMP Compare(ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider* textRangeProvider, boolean* result) noexcept override;
IFACEMETHODIMP CompareEndpoints(ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint,
ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider* textRangeProvider,
ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint targetEndpoint,
INT32* result) noexcept override;
IFACEMETHODIMP ExpandToEnclosingUnit(ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit) noexcept override;
IFACEMETHODIMP FindAttribute(INT32 attributeId,
IInspectable* value,
boolean backward,
ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider** result) noexcept override;
IFACEMETHODIMP FindText(HSTRING text,
boolean backward,
boolean ignoreCase,
ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider** result) noexcept override;
IFACEMETHODIMP GetAttributeValue(INT32 attributeId, IInspectable** result) noexcept override;
IFACEMETHODIMP GetBoundingRectangles(UINT32* returnValueLength, DOUBLE** returnValue) noexcept override;
IFACEMETHODIMP GetEnclosingElement(ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple** result) noexcept override;
IFACEMETHODIMP GetText(INT32 maxLength, HSTRING* result) noexcept override;
IFACEMETHODIMP Move(ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit,
INT32 count,
INT32* result) noexcept override;
IFACEMETHODIMP MoveEndpointByUnit(ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint,
ABI::Windows::UI::Xaml::Automation::Text::TextUnit unit,
INT32 count,
INT32* result) noexcept override;
IFACEMETHODIMP MoveEndpointByRange(ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint endpoint,
ABI::Windows::UI::Xaml::Automation::Provider::ITextRangeProvider* textRangeProvider,
ABI::Windows::UI::Xaml::Automation::Text::TextPatternRangeEndpoint targetEndpoint) noexcept override;
IFACEMETHODIMP Select() noexcept override;
IFACEMETHODIMP AddToSelection() noexcept override;
IFACEMETHODIMP RemoveFromSelection() noexcept override;
IFACEMETHODIMP ScrollIntoView(boolean alignToTop) noexcept override;
IFACEMETHODIMP GetChildren(UINT32* resultLength,
ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple*** result) noexcept override;
#pragma endregion ITextRangeProvider
private:
wil::com_ptr<::ITextRangeProvider> _uiaProvider;
Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple _parentProvider;
std::atomic<ULONG> _refCount{ 1 };
};
}