Skip to content

Commit

Permalink
Expose Text Attributes to UI Automation
Browse files Browse the repository at this point in the history
  • Loading branch information
carlos-zamora committed Jun 23, 2021
1 parent 8c00dd7 commit b764ee4
Show file tree
Hide file tree
Showing 10 changed files with 1,070 additions and 27 deletions.
14 changes: 14 additions & 0 deletions src/buffer/out/textBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,20 @@ TextBufferCellIterator TextBuffer::GetCellDataAt(const COORD at, const Viewport
return TextBufferCellIterator(*this, at, limit);
}

// Routine Description:
// - Retrieves read-only cell iterator at the given buffer location
// but restricted to operate only inside the given viewport.
// Arguments:
// - at - X,Y position in buffer for iterator start position
// - limit - boundaries for the iterator to operate within
// - until - X,Y position in buffer for last position for the iterator to read (inclusive)
// Return Value:
// - Read-only iterator of cell data.
TextBufferCellIterator TextBuffer::GetCellDataAt(const COORD at, const Viewport limit, const COORD until) const
{
return TextBufferCellIterator(*this, at, limit, until);
}

//Routine Description:
// - Corrects and enforces consistent double byte character state (KAttrs line) within a row of the text buffer.
// - This will take the given double byte information and check that it will be consistent when inserted into the buffer
Expand Down
1 change: 1 addition & 0 deletions src/buffer/out/textBuffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class TextBuffer final
TextBufferCellIterator GetCellDataAt(const COORD at) const;
TextBufferCellIterator GetCellLineDataAt(const COORD at) const;
TextBufferCellIterator GetCellDataAt(const COORD at, const Microsoft::Console::Types::Viewport limit) const;
TextBufferCellIterator GetCellDataAt(const COORD at, const Microsoft::Console::Types::Viewport limit, const COORD until) const;
TextBufferTextIterator GetTextDataAt(const COORD at) const;
TextBufferTextIterator GetTextLineDataAt(const COORD at) const;
TextBufferTextIterator GetTextDataAt(const COORD at, const Microsoft::Console::Types::Viewport limit) const;
Expand Down
45 changes: 42 additions & 3 deletions src/buffer/out/textBufferCellIterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,25 @@ TextBufferCellIterator::TextBufferCellIterator(const TextBuffer& buffer, COORD p
_GenerateView();
}

// Routine Description:
// - Creates a new read-only iterator to seek through cell data stored within a screen buffer
// Arguments:
// - buffer - Text buffer to seek through
// - pos - Starting position to retrieve text data from (within screen buffer bounds)
// - limits - Viewport limits to restrict the iterator within the buffer bounds (smaller than the buffer itself)
// - endPosInclusive - last position to iterate through (inclusive)
TextBufferCellIterator::TextBufferCellIterator(const TextBuffer& buffer, COORD pos, const Viewport limits, const COORD endPosInclusive) :
TextBufferCellIterator(buffer, pos, limits)
{
// Throw if the coordinate is not limited to the inside of the given buffer.
THROW_HR_IF(E_INVALIDARG, !_bounds.IsInBounds(endPosInclusive));

// Throw if pos is past endPos
THROW_HR_IF(E_INVALIDARG, _bounds.CompareInBounds(pos, endPosInclusive) > 0);

_endPosInclusive = endPosInclusive;
}

// Routine Description:
// - Tells if the iterator is still valid (hasn't exceeded boundaries of underlying text buffer)
// Return Value:
Expand All @@ -72,7 +91,8 @@ bool TextBufferCellIterator::operator==(const TextBufferCellIterator& it) const
_exceeded == it._exceeded &&
_bounds == it._bounds &&
_pRow == it._pRow &&
_attrIter == it._attrIter;
_attrIter == it._attrIter &&
_endPosInclusive == _endPosInclusive;
}

// Routine Description:
Expand All @@ -98,12 +118,26 @@ TextBufferCellIterator& TextBufferCellIterator::operator+=(const ptrdiff_t& move
auto newPos = _pos;
while (move > 0 && !_exceeded)
{
_exceeded = !_bounds.IncrementInBounds(newPos);
// If we have an endPos, check if we've exceeded it
if (_endPosInclusive.has_value())
{
_exceeded = _bounds.CompareInBounds(newPos, *_endPosInclusive) > 0;
}

// If we already exceeded from endPos, we'll short-circuit and _not_ increment
_exceeded |= !_bounds.IncrementInBounds(newPos);
move--;
}
while (move < 0 && !_exceeded)
{
_exceeded = !_bounds.DecrementInBounds(newPos);
// If we have an endPos, check if we've exceeded it
if (_endPosInclusive.has_value())
{
_exceeded = _bounds.CompareInBounds(newPos, *_endPosInclusive) < 0;
}

// If we already exceeded from endPos, we'll short-circuit and _not_ decrement
_exceeded |= !_bounds.DecrementInBounds(newPos);
move++;
}
_SetPos(newPos);
Expand Down Expand Up @@ -265,3 +299,8 @@ const OutputCellView* TextBufferCellIterator::operator->() const noexcept
{
return &_view;
}

COORD TextBufferCellIterator::Pos() const noexcept
{
return _pos;
}
4 changes: 4 additions & 0 deletions src/buffer/out/textBufferCellIterator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class TextBufferCellIterator
public:
TextBufferCellIterator(const TextBuffer& buffer, COORD pos);
TextBufferCellIterator(const TextBuffer& buffer, COORD pos, const Microsoft::Console::Types::Viewport limits);
TextBufferCellIterator(const TextBuffer& buffer, COORD pos, const Microsoft::Console::Types::Viewport limits, const COORD endPosInclusive);

operator bool() const noexcept;

Expand All @@ -47,6 +48,8 @@ class TextBufferCellIterator
const OutputCellView& operator*() const noexcept;
const OutputCellView* operator->() const noexcept;

COORD Pos() const noexcept;

protected:
void _SetPos(const COORD newPos);
void _GenerateView();
Expand All @@ -60,6 +63,7 @@ class TextBufferCellIterator
const Microsoft::Console::Types::Viewport _bounds;
bool _exceeded;
COORD _pos;
std::optional<COORD> _endPosInclusive;

#if UNIT_TESTING
friend class TextBufferIteratorTests;
Expand Down
54 changes: 50 additions & 4 deletions src/cascadia/TerminalControl/XamlUiaTextRange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "XamlUiaTextRange.h"
#include "../types/TermControlUiaTextRange.hpp"
#include <UIAutomationClient.h>
#include <UIAutomationCoreApi.h>

// the same as COR_E_NOTSUPPORTED
// we don't want to import the CLR headers to get it
Expand Down Expand Up @@ -89,12 +90,56 @@ namespace winrt::Microsoft::Terminal::Control::implementation

winrt::Windows::Foundation::IInspectable XamlUiaTextRange::GetAttributeValue(int32_t textAttributeId) const
{
// Copied functionality from Types::UiaTextRange.cpp
if (textAttributeId == UIA_IsReadOnlyAttributeId)
// Call the function off of the underlying UiaTextRange.
VARIANT result;
THROW_IF_FAILED(_uiaProvider->GetAttributeValue(textAttributeId, &result));

// Convert the resulting VARIANT into a format that is consumable by XAML.
switch (result.vt)
{
case VT_BSTR:
{
return box_value(result.bstrVal);
}
case VT_I4:
{
return box_value(result.iVal);
}
case VT_R8:
{
return box_value(result.dblVal);
}
case VT_BOOL:
{
return box_value(result.boolVal);
}
case VT_UNKNOWN:
{
return winrt::box_value(false);
// 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.

IUnknown* notSupportedVal;
UiaGetReservedNotSupportedValue(&notSupportedVal);
if (result.punkVal == notSupportedVal)
{
// See below for why we need to throw this special value.
winrt::throw_hresult(XAML_E_NOT_SUPPORTED);
}

IUnknown* mixedAttributeVal;
UiaGetReservedMixedAttributeValue(&mixedAttributeVal);
if (result.punkVal == mixedAttributeVal)
{
return Windows::UI::Xaml::DependencyProperty::UnsetValue();
}

__fallthrough;
}
else
default:
{
// We _need_ to return XAML_E_NOT_SUPPORTED here.
// Returning nullptr is an improper implementation of it being unsupported.
Expand All @@ -103,6 +148,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Magically, this doesn't affect other forms of navigation...
winrt::throw_hresult(XAML_E_NOT_SUPPORTED);
}
}
}

void XamlUiaTextRange::GetBoundingRectangles(com_array<double>& returnValue) const
Expand Down
Loading

0 comments on commit b764ee4

Please sign in to comment.