Introduce UiaTextRangeBase::FindText() for Accessibility (#4373)

Moved `FindText` to `UiaTextRangeBase`. Now that Search is a shared component (thanks #3279), I can just reuse it basically as-is.

#3279 - Make Search a shared component
#4018 - UiaTextRange Refactor

I removed it from the two different kinds of UiaTextRange and put it in the base class.

I needed a very minor change to ensure we convert from an inclusive end (from Search) to an exclusive end (in UTR).

Worked with `FindText` was globally messed with in windows.h. So we had to do a few weird things there (thanks Michael).

No need for additional tests because it _literally_ just sets up a Searcher and calls it.
This commit is contained in:
Carlos Zamora 2020-01-31 15:26:19 -08:00 committed by GitHub
parent 29df540174
commit 55b638801b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 79 additions and 87 deletions

View file

@ -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()

View file

@ -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;

View file

@ -4,6 +4,7 @@
#include "pch.h"
#include "XamlUiaTextRange.h"
#include "UiaTextRange.hpp"
#include <UIAutomationClient.h>
// 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<XamlUiaTextRange>(pReturn, _parentProvider);
return *xutr;
}
winrt::Windows::Foundation::IInspectable XamlUiaTextRange::GetAttributeValue(int32_t textAttributeId) const

View file

@ -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

View file

@ -19,7 +19,8 @@ Author(s):
#pragma once
#include "precomp.h"
#include <UIAutomationCore.h>
#include "..\types\ScreenInfoUiaProviderBase.h"
#include "..\types\UiaTextRangeBase.hpp"
#include "uiaTextRange.hpp"

View file

@ -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<UiaTextRange&>(**ppRetVal);
range._start = start;
range._end = end;
}
}
}
return hr;
}
CATCH_RETURN();
}
void UiaTextRange::_ChangeViewport(const SMALL_RECT NewWindow)
{
auto provider = static_cast<ScreenInfoUiaProvider*>(_pProvider);

View file

@ -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;

View file

@ -21,11 +21,12 @@ Author(s):
#pragma once
#include "precomp.h"
#include "../buffer/out/textBuffer.hpp"
#include "UiaTextRangeBase.hpp"
#include "IUiaData.h"
#include <UIAutomationCore.h>
#include <wrl/implements.h>
namespace Microsoft::Console::Types

View file

@ -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<UiaTextRangeBase&>(**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<double>& 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();

View file

@ -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 <UIAutomationCore.h>
#include <deque>
#include <tuple>
#include <wrl/implements.h>
@ -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;

View file

@ -20,7 +20,7 @@ Author(s):
#pragma once
#include "precomp.h"
#include <UIAutomationCore.h>
#include <wrl/implements.h>