diff --git a/src/cascadia/TerminalControl/UiaTextRange.cpp b/src/cascadia/TerminalControl/UiaTextRange.cpp index 9b82aa1e8..45e907bd8 100644 --- a/src/cascadia/TerminalControl/UiaTextRange.cpp +++ b/src/cascadia/TerminalControl/UiaTextRange.cpp @@ -105,15 +105,6 @@ IFACEMETHODIMP UiaTextRange::Clone(_Outptr_result_maybenull_ ITextRangeProvider* return S_OK; } -IFACEMETHODIMP UiaTextRange::FindText(_In_ BSTR /*text*/, - _In_ BOOL /*searchBackward*/, - _In_ BOOL /*ignoreCase*/, - _Outptr_result_maybenull_ ITextRangeProvider** /*ppRetVal*/) -{ - // TODO GitHub #605: Search functionality - return E_NOTIMPL; -} - void UiaTextRange::_ChangeViewport(const SMALL_RECT /*NewWindow*/) { // TODO GitHub #2361: Update viewport when calling UiaTextRangeBase::ScrollIntoView() diff --git a/src/cascadia/TerminalControl/UiaTextRange.hpp b/src/cascadia/TerminalControl/UiaTextRange.hpp index 0113b485e..8f70b2411 100644 --- a/src/cascadia/TerminalControl/UiaTextRange.hpp +++ b/src/cascadia/TerminalControl/UiaTextRange.hpp @@ -57,10 +57,6 @@ namespace Microsoft::Terminal HRESULT RuntimeClassInitialize(const UiaTextRange& a); IFACEMETHODIMP Clone(_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) override; - IFACEMETHODIMP FindText(_In_ BSTR text, - _In_ BOOL searchBackward, - _In_ BOOL ignoreCase, - _Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) override; protected: void _ChangeViewport(const SMALL_RECT NewWindow) override; diff --git a/src/cascadia/TerminalControl/XamlUiaTextRange.cpp b/src/cascadia/TerminalControl/XamlUiaTextRange.cpp index d282eedd0..c727df68a 100644 --- a/src/cascadia/TerminalControl/XamlUiaTextRange.cpp +++ b/src/cascadia/TerminalControl/XamlUiaTextRange.cpp @@ -4,6 +4,7 @@ #include "pch.h" #include "XamlUiaTextRange.h" #include "UiaTextRange.hpp" +#include // the same as COR_E_NOTSUPPORTED // we don't want to import the CLR headers to get it @@ -73,14 +74,17 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation throw winrt::hresult_not_implemented(); } - XamlAutomation::ITextRangeProvider XamlUiaTextRange::FindText(winrt::hstring /*text*/, - bool /*searchBackward*/, - bool /*ignoreCase*/) + XamlAutomation::ITextRangeProvider XamlUiaTextRange::FindText(winrt::hstring text, + bool searchBackward, + bool ignoreCase) { - // TODO GitHub #605: Search functionality - // we need to wrap this around the UiaTextRange FindText() function - // but right now it returns E_NOTIMPL, so let's just return nullptr for now. - return nullptr; + UIA::ITextRangeProvider* pReturn; + const auto queryText = wil::make_bstr(text.c_str()); + + THROW_IF_FAILED(_uiaProvider->FindText(queryText.get(), searchBackward, ignoreCase, &pReturn)); + + auto xutr = winrt::make_self(pReturn, _parentProvider); + return *xutr; } winrt::Windows::Foundation::IInspectable XamlUiaTextRange::GetAttributeValue(int32_t textAttributeId) const diff --git a/src/inc/HostAndPropsheetIncludes.h b/src/inc/HostAndPropsheetIncludes.h index 9aaf241c7..d0ede2a3a 100644 --- a/src/inc/HostAndPropsheetIncludes.h +++ b/src/inc/HostAndPropsheetIncludes.h @@ -4,6 +4,10 @@ // clang-format off +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // If this is not defined, windows.h includes commdlg.h which defines FindText globally and conflicts with UIAutomation ITextRangeProvider. +#endif + // Define and then undefine WIN32_NO_STATUS because windows.h has no guard to prevent it from double defing certain statuses // when included with ntstatus.h #define WIN32_NO_STATUS diff --git a/src/interactivity/win32/screenInfoUiaProvider.hpp b/src/interactivity/win32/screenInfoUiaProvider.hpp index bf53dbcd5..3b39a32ee 100644 --- a/src/interactivity/win32/screenInfoUiaProvider.hpp +++ b/src/interactivity/win32/screenInfoUiaProvider.hpp @@ -19,7 +19,8 @@ Author(s): #pragma once -#include "precomp.h" +#include + #include "..\types\ScreenInfoUiaProviderBase.h" #include "..\types\UiaTextRangeBase.hpp" #include "uiaTextRange.hpp" diff --git a/src/interactivity/win32/uiaTextRange.cpp b/src/interactivity/win32/uiaTextRange.cpp index dcbabcf71..c5b7f6458 100644 --- a/src/interactivity/win32/uiaTextRange.cpp +++ b/src/interactivity/win32/uiaTextRange.cpp @@ -5,7 +5,6 @@ #include "uiaTextRange.hpp" #include "screenInfoUiaProvider.hpp" -#include "..\buffer\out\search.h" #include "..\interactivity\inc\ServiceLocator.hpp" using namespace Microsoft::Console::Types; @@ -105,58 +104,6 @@ IFACEMETHODIMP UiaTextRange::Clone(_Outptr_result_maybenull_ ITextRangeProvider* return S_OK; } -IFACEMETHODIMP UiaTextRange::FindText(_In_ BSTR text, - _In_ BOOL searchBackward, - _In_ BOOL ignoreCase, - _Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) -{ - // TODO GitHub #1914: Re-attach Tracing to UIA Tree - //Tracing::s_TraceUia(this, ApiCall::FindText, nullptr); - RETURN_HR_IF(E_INVALIDARG, ppRetVal == nullptr); - *ppRetVal = nullptr; - try - { - const std::wstring wstr{ text, SysStringLen(text) }; - const auto sensitivity = ignoreCase ? Search::Sensitivity::CaseInsensitive : Search::Sensitivity::CaseSensitive; - - auto searchDirection = Search::Direction::Forward; - auto searchAnchor = _start; - if (searchBackward) - { - searchDirection = Search::Direction::Backward; - searchAnchor = _end; - } - - CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); - THROW_HR_IF(E_POINTER, !gci.HasActiveOutputBuffer()); - Search searcher{ gci.renderData, wstr, searchDirection, sensitivity, searchAnchor }; - - HRESULT hr = S_OK; - if (searcher.FindNext()) - { - const auto foundLocation = searcher.GetFoundLocation(); - const auto start = foundLocation.first; - const auto end = foundLocation.second; - const auto bufferSize = _pData->GetTextBuffer().GetSize(); - - // make sure what was found is within the bounds of the current range - if ((searchDirection == Search::Direction::Forward && bufferSize.CompareInBounds(end, _end) < 0) || - (searchDirection == Search::Direction::Backward && bufferSize.CompareInBounds(start, _start) > 0)) - { - hr = Clone(ppRetVal); - if (SUCCEEDED(hr)) - { - UiaTextRange& range = static_cast(**ppRetVal); - range._start = start; - range._end = end; - } - } - } - return hr; - } - CATCH_RETURN(); -} - void UiaTextRange::_ChangeViewport(const SMALL_RECT NewWindow) { auto provider = static_cast(_pProvider); diff --git a/src/interactivity/win32/uiaTextRange.hpp b/src/interactivity/win32/uiaTextRange.hpp index c6755499f..660746230 100644 --- a/src/interactivity/win32/uiaTextRange.hpp +++ b/src/interactivity/win32/uiaTextRange.hpp @@ -58,10 +58,6 @@ namespace Microsoft::Console::Interactivity::Win32 HRESULT RuntimeClassInitialize(const UiaTextRange& a); IFACEMETHODIMP Clone(_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) override; - IFACEMETHODIMP FindText(_In_ BSTR text, - _In_ BOOL searchBackward, - _In_ BOOL ignoreCase, - _Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) override; protected: void _ChangeViewport(const SMALL_RECT NewWindow) override; diff --git a/src/types/ScreenInfoUiaProviderBase.h b/src/types/ScreenInfoUiaProviderBase.h index 50f4f76b5..82bdd31fc 100644 --- a/src/types/ScreenInfoUiaProviderBase.h +++ b/src/types/ScreenInfoUiaProviderBase.h @@ -21,11 +21,12 @@ Author(s): #pragma once -#include "precomp.h" #include "../buffer/out/textBuffer.hpp" #include "UiaTextRangeBase.hpp" #include "IUiaData.h" +#include + #include namespace Microsoft::Console::Types diff --git a/src/types/UiaTextRangeBase.cpp b/src/types/UiaTextRangeBase.cpp index d226263e5..ee3af2609 100644 --- a/src/types/UiaTextRangeBase.cpp +++ b/src/types/UiaTextRangeBase.cpp @@ -4,6 +4,7 @@ #include "precomp.h" #include "UiaTextRangeBase.hpp" #include "ScreenInfoUiaProviderBase.h" +#include "..\buffer\out\search.h" using namespace Microsoft::Console::Types; using namespace Microsoft::Console::Types::UiaTextRangeBaseTracing; @@ -346,6 +347,58 @@ IFACEMETHODIMP UiaTextRangeBase::FindAttribute(_In_ TEXTATTRIBUTEID /*textAttrib return E_NOTIMPL; } +IFACEMETHODIMP UiaTextRangeBase::FindText(_In_ BSTR text, + _In_ BOOL searchBackward, + _In_ BOOL ignoreCase, + _Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) noexcept +try +{ + // TODO GitHub #1914: Re-attach Tracing to UIA Tree + //Tracing::s_TraceUia(this, ApiCall::FindText, nullptr); + RETURN_HR_IF(E_INVALIDARG, ppRetVal == nullptr); + *ppRetVal = nullptr; + + const std::wstring queryText{ text, SysStringLen(text) }; + const auto bufferSize = _pData->GetTextBuffer().GetSize(); + const auto sensitivity = ignoreCase ? Search::Sensitivity::CaseInsensitive : Search::Sensitivity::CaseSensitive; + + auto searchDirection = Search::Direction::Forward; + auto searchAnchor = _start; + if (searchBackward) + { + searchDirection = Search::Direction::Backward; + + // we need to convert the end to inclusive + // because Search operates with an inclusive COORD + searchAnchor = _end; + bufferSize.DecrementInBounds(searchAnchor, true); + } + + Search searcher{ *_pData, queryText, searchDirection, sensitivity, searchAnchor }; + + if (searcher.FindNext()) + { + const auto foundLocation = searcher.GetFoundLocation(); + const auto start = foundLocation.first; + + // we need to increment the position of end because it's exclusive + auto end = foundLocation.second; + bufferSize.IncrementInBounds(end, true); + + // make sure what was found is within the bounds of the current range + if ((searchDirection == Search::Direction::Forward && bufferSize.CompareInBounds(end, _end, true) < 0) || + (searchDirection == Search::Direction::Backward && bufferSize.CompareInBounds(start, _start) > 0)) + { + RETURN_IF_FAILED(Clone(ppRetVal)); + UiaTextRangeBase& range = static_cast(**ppRetVal); + range._start = start; + range._end = end; + } + } + return S_OK; +} +CATCH_RETURN(); + IFACEMETHODIMP UiaTextRangeBase::GetAttributeValue(_In_ TEXTATTRIBUTEID textAttributeId, _Out_ VARIANT* pRetVal) noexcept { @@ -930,7 +983,7 @@ const unsigned int UiaTextRangeBase::_getViewportHeight(const SMALL_RECT viewpor void UiaTextRangeBase::_getBoundingRect(_In_ const COORD startAnchor, _In_ const COORD endAnchor, _Inout_ std::vector& coords) const { FAIL_FAST_IF(startAnchor.Y != endAnchor.Y); - FAIL_FAST_IF(startAnchor.X <= endAnchor.X); + FAIL_FAST_IF(startAnchor.X >= endAnchor.X); const auto viewport = _pData->GetViewport(); const auto currentFontSize = _getScreenFontSize(); diff --git a/src/types/UiaTextRangeBase.hpp b/src/types/UiaTextRangeBase.hpp index 6ba481dc4..389807b0d 100644 --- a/src/types/UiaTextRangeBase.hpp +++ b/src/types/UiaTextRangeBase.hpp @@ -18,13 +18,12 @@ Author(s): #pragma once -#include "precomp.h" - #include "inc/viewport.hpp" #include "../buffer/out/textBuffer.hpp" #include "IUiaData.h" #include "unicode.hpp" +#include #include #include #include @@ -103,10 +102,10 @@ namespace Microsoft::Console::Types _In_ VARIANT val, _In_ BOOL searchBackward, _Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) noexcept override; - virtual IFACEMETHODIMP FindText(_In_ BSTR text, - _In_ BOOL searchBackward, - _In_ BOOL ignoreCase, - _Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) = 0; + IFACEMETHODIMP FindText(_In_ BSTR text, + _In_ BOOL searchBackward, + _In_ BOOL ignoreCase, + _Outptr_result_maybenull_ ITextRangeProvider** ppRetVal) noexcept override; IFACEMETHODIMP GetAttributeValue(_In_ TEXTATTRIBUTEID textAttributeId, _Out_ VARIANT* pRetVal) noexcept override; IFACEMETHODIMP GetBoundingRectangles(_Outptr_result_maybenull_ SAFEARRAY** ppRetVal) noexcept override; diff --git a/src/types/WindowUiaProviderBase.hpp b/src/types/WindowUiaProviderBase.hpp index 606ed6085..d14a9e0db 100644 --- a/src/types/WindowUiaProviderBase.hpp +++ b/src/types/WindowUiaProviderBase.hpp @@ -20,7 +20,7 @@ Author(s): #pragma once -#include "precomp.h" +#include #include