diff --git a/src/cascadia/TerminalControl/InteractivityAutomationPeer.cpp b/src/cascadia/TerminalControl/InteractivityAutomationPeer.cpp index 61db7ccb75..c6b5cf890e 100644 --- a/src/cascadia/TerminalControl/InteractivityAutomationPeer.cpp +++ b/src/cascadia/TerminalControl/InteractivityAutomationPeer.cpp @@ -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().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(returnVal, parent.as().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 InteractivityAutomationPeer::WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges) { - // transfer ownership of UiaTextRanges to this new vector - auto providers = SafeArrayToOwningVector<::Microsoft::Terminal::TermControlUiaTextRange>(textRanges); - auto count = gsl::narrow(providers.size()); - - std::vector 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 result{ vec }; + // transfer ownership of UiaTextRanges to this new vector + auto providers = SafeArrayToOwningVector<::Microsoft::Terminal::TermControlUiaTextRange>(textRanges); + const auto len = gsl::narrow(providers.size()); + com_array result{ len }; + + for (uint32_t i = 0; i < len; ++i) + { + result[i] = XamlUiaTextRange::Create(providers[i].detach(), _parentProvider); + } return result; } diff --git a/src/cascadia/TerminalControl/InteractivityAutomationPeer.h b/src/cascadia/TerminalControl/InteractivityAutomationPeer.h index 4f5b4a79c6..d69d19d16e 100644 --- a/src/cascadia/TerminalControl/InteractivityAutomationPeer.h +++ b/src/cascadia/TerminalControl/InteractivityAutomationPeer.h @@ -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 _parentProvider; + winrt::Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple _parentProvider{ nullptr }; til::rect _controlBounds{}; til::rect _controlPadding{}; diff --git a/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp b/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp index aaf6cfaf58..bcdac36e3c 100644 --- a/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp +++ b/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp @@ -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 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 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() diff --git a/src/cascadia/TerminalControl/XamlUiaTextRange.cpp b/src/cascadia/TerminalControl/XamlUiaTextRange.cpp index be6f3aeb6d..27b9762311 100644 --- a/src/cascadia/TerminalControl/XamlUiaTextRange.cpp +++ b/src/cascadia/TerminalControl/XamlUiaTextRange.cpp @@ -33,6 +33,14 @@ static std::atomic 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(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(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(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(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(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(pTargetRange); + RETURN_HR_IF_NULL(E_INVALIDARG, result); + *result = 0; + RETURN_HR_IF_NULL(E_INVALIDARG, textRangeProvider); + + auto self = static_cast(textRangeProvider); int32_t returnVal; - THROW_IF_FAILED(_uiaProvider->CompareEndpoints(static_cast(endpoint), - self->_uiaProvider.get(), - static_cast(targetEndpoint), - &returnVal)); - return returnVal; + RETURN_IF_FAILED(_uiaProvider->CompareEndpoints(static_cast(endpoint), + self->_uiaProvider.get(), + static_cast(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(unit))); + RETURN_IF_FAILED(_uiaProvider->ExpandToEnclosingUnit(static_cast(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(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(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(result.lVal); + auto value = winrt::box_value(varResult.lVal); + *result = static_cast(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(winrt::detach_abi(value)); + return S_OK; } case VT_BOOL: { - return box_value(result.boolVal); + auto value = winrt::box_value(varResult.boolVal); + *result = static_cast(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 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(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& 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(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 vec; - vec.reserve(count); - for (auto i = 0; i < count; i++) - { - auto element = pVals[i]; - vec.push_back(element); - } - - winrt::com_array 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(unit), - count, - &returnVal)); - return returnVal; + RETURN_IF_FAILED(_uiaProvider->Move(static_cast(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(endpoint), - static_cast(unit), - count, - &returnVal)); - return returnVal; + RETURN_IF_FAILED(_uiaProvider->MoveEndpointByUnit(static_cast(endpoint), + static_cast(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(pTargetRange); - THROW_IF_FAILED(_uiaProvider->MoveEndpointByRange(static_cast(endpoint), - /*pTargetRange*/ self->_uiaProvider.get(), - static_cast(targetEndpoint))); - } + RETURN_HR_IF_NULL(E_INVALIDARG, textRangeProvider); - void XamlUiaTextRange::Select() const + auto self = static_cast(textRangeProvider); + RETURN_IF_FAILED(_uiaProvider->MoveEndpointByRange(static_cast(endpoint), + self->_uiaProvider.get(), + static_cast(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 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; } } diff --git a/src/cascadia/TerminalControl/XamlUiaTextRange.h b/src/cascadia/TerminalControl/XamlUiaTextRange.h index b6ecac3823..5f4faea8c4 100644 --- a/src/cascadia/TerminalControl/XamlUiaTextRange.h +++ b/src/cascadia/TerminalControl/XamlUiaTextRange.h @@ -23,50 +23,68 @@ Author(s): #include "TermControlAutomationPeer.h" #include #include "../types/TermControlUiaTextRange.hpp" +#include namespace winrt::Microsoft::Terminal::Control::implementation { - class XamlUiaTextRange : - public winrt::implements + 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& 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 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 _refCount{ 1 }; }; }