Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly represent block selections in UIA #4991

Merged
3 commits merged into from
Mar 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/cascadia/TerminalCore/Terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ class Microsoft::Terminal::Core::Terminal final :
#pragma region IUiaData
std::vector<Microsoft::Console::Types::Viewport> GetSelectionRects() noexcept override;
const bool IsSelectionActive() const noexcept override;
const bool IsBlockSelection() const noexcept override;
void ClearSelection() override;
void SelectNewRegion(const COORD coordStart, const COORD coordEnd) override;
const COORD GetSelectionAnchor() const noexcept override;
Expand Down
5 changes: 5 additions & 0 deletions src/cascadia/TerminalCore/TerminalSelection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ const bool Terminal::IsSelectionActive() const noexcept
return _selection.has_value();
}

const bool Terminal::IsBlockSelection() const noexcept
{
return _blockSelection;
}

// Method Description:
// - Checks if the CopyOnSelect setting is active
// Return Value:
Expand Down
5 changes: 5 additions & 0 deletions src/host/renderData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,11 @@ const bool RenderData::IsSelectionActive() const
return Selection::Instance().IsAreaSelected();
}

const bool RenderData::IsBlockSelection() const noexcept
{
return !Selection::Instance().IsLineSelection();
}

// Routine Description:
// - If a selection exists, clears it and restores the state.
// Will also unblock a blocked write if one exists.
Expand Down
1 change: 1 addition & 0 deletions src/host/renderData.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class RenderData final :

#pragma region IUiaData
const bool IsSelectionActive() const override;
const bool IsBlockSelection() const noexcept override;
void ClearSelection() override;
void SelectNewRegion(const COORD coordStart, const COORD coordEnd) override;
const COORD GetSelectionAnchor() const noexcept;
Expand Down
4 changes: 2 additions & 2 deletions src/interactivity/win32/screenInfoUiaProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ HRESULT ScreenInfoUiaProvider::GetSelectionRange(_In_ IRawElementProviderSimple*

// TODO GH #4509: Box Selection is misrepresented here as a line selection.
UiaTextRange* result;
RETURN_IF_FAILED(MakeAndInitialize<UiaTextRange>(&result, _pData, pProvider, start, end, wordDelimiters));
RETURN_IF_FAILED(MakeAndInitialize<UiaTextRange>(&result, _pData, pProvider, start, end, _pData->IsBlockSelection(), wordDelimiters));
*ppUtr = result;
return S_OK;
}
Expand Down Expand Up @@ -147,7 +147,7 @@ HRESULT ScreenInfoUiaProvider::CreateTextRange(_In_ IRawElementProviderSimple* c
RETURN_HR_IF_NULL(E_INVALIDARG, ppUtr);
*ppUtr = nullptr;
UiaTextRange* result = nullptr;
RETURN_IF_FAILED(MakeAndInitialize<UiaTextRange>(&result, _pData, pProvider, start, end, wordDelimiters));
RETURN_IF_FAILED(MakeAndInitialize<UiaTextRange>(&result, _pData, pProvider, start, end, false, wordDelimiters));
*ppUtr = result;
return S_OK;
}
Expand Down
3 changes: 2 additions & 1 deletion src/interactivity/win32/uiaTextRange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ HRESULT UiaTextRange::RuntimeClassInitialize(_In_ IUiaData* pData,
_In_ IRawElementProviderSimple* const pProvider,
const COORD start,
const COORD end,
bool blockRange,
const std::wstring_view wordDelimiters) noexcept
{
return UiaTextRangeBase::RuntimeClassInitialize(pData, pProvider, start, end, wordDelimiters);
return UiaTextRangeBase::RuntimeClassInitialize(pData, pProvider, start, end, blockRange, wordDelimiters);
}

// returns a degenerate text range of the start of the row closest to the y value of point
Expand Down
1 change: 1 addition & 0 deletions src/interactivity/win32/uiaTextRange.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ namespace Microsoft::Console::Interactivity::Win32
_In_ IRawElementProviderSimple* const pProvider,
_In_ const COORD start,
_In_ const COORD end,
_In_ bool blockRange = false,
_In_ const std::wstring_view wordDelimiters = DefaultWordDelimiter) noexcept override;

// range from a UiaPoint
Expand Down
1 change: 1 addition & 0 deletions src/types/IUiaData.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ namespace Microsoft::Console::Types

public:
virtual const bool IsSelectionActive() const = 0;
virtual const bool IsBlockSelection() const = 0;
virtual void ClearSelection() = 0;
virtual void SelectNewRegion(const COORD coordStart, const COORD coordEnd) = 0;
virtual const COORD GetSelectionAnchor() const noexcept = 0;
Expand Down
5 changes: 2 additions & 3 deletions src/types/TermControlUiaProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,8 @@ HRESULT TermControlUiaProvider::GetSelectionRange(_In_ IRawElementProviderSimple
auto end = _pData->GetSelectionEnd();
_pData->GetTextBuffer().GetSize().IncrementInBounds(end, true);

// TODO GH #4509: Box Selection is misrepresented here as a line selection.
TermControlUiaTextRange* result = nullptr;
RETURN_IF_FAILED(MakeAndInitialize<TermControlUiaTextRange>(&result, _pData, pProvider, start, end, wordDelimiters));
RETURN_IF_FAILED(MakeAndInitialize<TermControlUiaTextRange>(&result, _pData, pProvider, start, end, _pData->IsBlockSelection(), wordDelimiters));
*ppUtr = result;
return S_OK;
}
Expand Down Expand Up @@ -167,7 +166,7 @@ HRESULT TermControlUiaProvider::CreateTextRange(_In_ IRawElementProviderSimple*
RETURN_HR_IF_NULL(E_INVALIDARG, ppUtr);
*ppUtr = nullptr;
TermControlUiaTextRange* result = nullptr;
RETURN_IF_FAILED(MakeAndInitialize<TermControlUiaTextRange>(&result, _pData, pProvider, start, end, wordDelimiters));
RETURN_IF_FAILED(MakeAndInitialize<TermControlUiaTextRange>(&result, _pData, pProvider, start, end, false, wordDelimiters));
*ppUtr = result;
return S_OK;
}
Expand Down
3 changes: 2 additions & 1 deletion src/types/TermControlUiaTextRange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ HRESULT TermControlUiaTextRange::RuntimeClassInitialize(_In_ IUiaData* pData,
_In_ IRawElementProviderSimple* const pProvider,
const COORD start,
const COORD end,
bool blockRange,
const std::wstring_view wordDelimiters) noexcept
{
return UiaTextRangeBase::RuntimeClassInitialize(pData, pProvider, start, end, wordDelimiters);
return UiaTextRangeBase::RuntimeClassInitialize(pData, pProvider, start, end, blockRange, wordDelimiters);
}

// returns a degenerate text range of the start of the row closest to the y value of point
Expand Down
1 change: 1 addition & 0 deletions src/types/TermControlUiaTextRange.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ namespace Microsoft::Terminal
_In_ IRawElementProviderSimple* const pProvider,
const COORD start,
const COORD end,
bool blockRange = false,
const std::wstring_view wordDelimiters = DefaultWordDelimiter) noexcept override;

// range from a UiaPoint
Expand Down
57 changes: 18 additions & 39 deletions src/types/UiaTextRangeBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ try
_pData = pData;
_start = pData->GetViewport().Origin();
_end = pData->GetViewport().Origin();
_blockRange = false;
_wordDelimiters = wordDelimiters;

_id = id;
Expand Down Expand Up @@ -55,6 +56,7 @@ HRESULT UiaTextRangeBase::RuntimeClassInitialize(_In_ IUiaData* pData,
_In_ IRawElementProviderSimple* const pProvider,
_In_ const COORD start,
_In_ const COORD end,
_In_ bool blockRange,
_In_ std::wstring_view wordDelimiters) noexcept
try
{
Expand All @@ -73,6 +75,10 @@ try
_end = start;
}

// This should be the only way to set if we are a blockRange
// This is used for blockSelection
_blockRange = blockRange;

UiaTracing::TextRange::Constructor(*this);
return S_OK;
}
Expand Down Expand Up @@ -429,25 +435,11 @@ IFACEMETHODIMP UiaTextRangeBase::GetBoundingRectangles(_Outptr_result_maybenull_
}
else
{
for (auto row = startAnchor.Y; row <= endAnchor.Y; ++row)
{
// assume that we are going to draw the entire row
COORD startCoord = { 0, row };
COORD endCoord = { viewport.RightInclusive(), row };

if (row == startAnchor.Y)
{
// first row --> reduce left side
startCoord.X = startAnchor.X;
}

if (row == endAnchor.Y)
{
// last row --> reduce right side
endCoord.X = endAnchor.X;
}
const auto textRects = _pData->GetTextBuffer().GetTextRects(startAnchor, endAnchor, _blockRange);

_getBoundingRect(startCoord, endCoord, coords);
for (const auto& rect : textRects)
{
_getBoundingRect(rect, coords);
}
}

Expand Down Expand Up @@ -537,7 +529,7 @@ try
auto inclusiveEnd{ _end };
bufferSize.DecrementInBounds(inclusiveEnd, true);

const auto textRects = buffer.GetTextRects(_start, inclusiveEnd);
const auto textRects = buffer.GetTextRects(_start, inclusiveEnd, _blockRange);
const auto bufferData = buffer.GetText(true,
false,
textRects);
Expand Down Expand Up @@ -860,33 +852,20 @@ const Viewport UiaTextRangeBase::_getBufferSize() const noexcept
// - coords - vector to add the calculated coords to
// Return Value:
// - <none>
void UiaTextRangeBase::_getBoundingRect(_In_ const COORD startAnchor, _In_ const COORD endAnchor, _Inout_ std::vector<double>& coords) const
void UiaTextRangeBase::_getBoundingRect(const til::rectangle textRect, _Inout_ std::vector<double>& coords) const
{
FAIL_FAST_IF(startAnchor.Y != endAnchor.Y);
FAIL_FAST_IF(startAnchor.X > endAnchor.X);

const auto viewport = _pData->GetViewport();
const auto currentFontSize = _getScreenFontSize();
const til::size currentFontSize = _getScreenFontSize();

POINT topLeft{ 0 };
POINT bottomRight{ 0 };

// startAnchor is converted to the viewport coordinate space
#pragma warning(suppress : 26496) // analysis can't see this, TODO GH: 4015 to improve Viewport to be less bad because it'd go away if ConvertToOrigin returned instead of inout'd.
auto startCoord = startAnchor;
viewport.ConvertToOrigin(&startCoord);

// we want to clamp to a long (output type), not a short (input type)
// so we need to explicitly say <long,long>
topLeft.x = base::ClampMul<long, long>(startCoord.X, currentFontSize.X);
topLeft.y = base::ClampMul<long, long>(startCoord.Y, currentFontSize.Y);

// endAnchor is converted to the viewport coordinate space
#pragma warning(suppress : 26496) // analysis can't see this, TODO GH: 4015 to improve Viewport to be less bad because it'd go away if ConvertToOrigin returned instead of inout'd.
auto endCoord = endAnchor;
viewport.ConvertToOrigin(&endCoord);
bottomRight.x = base::ClampMul<long, long>(base::ClampAdd(endCoord.X, 1), currentFontSize.X);
bottomRight.y = base::ClampMul<long, long>(base::ClampAdd(endCoord.Y, 1), currentFontSize.Y);
topLeft.x = base::ClampMul(textRect.left(), currentFontSize.width());
topLeft.y = base::ClampMul(textRect.top(), currentFontSize.height());

bottomRight.x = base::ClampMul(textRect.right(), currentFontSize.width());
bottomRight.y = base::ClampMul(textRect.bottom(), currentFontSize.height());

// convert the coords to be relative to the screen instead of
// the client window
Expand Down
4 changes: 3 additions & 1 deletion src/types/UiaTextRangeBase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ namespace Microsoft::Console::Types
_In_ IRawElementProviderSimple* const pProvider,
_In_ const COORD start,
_In_ const COORD end,
_In_ bool blockRange = false,
_In_ std::wstring_view wordDelimiters = DefaultWordDelimiter) noexcept;

virtual HRESULT RuntimeClassInitialize(const UiaTextRangeBase& a) noexcept;
Expand Down Expand Up @@ -149,6 +150,7 @@ namespace Microsoft::Console::Types
// NOTE: _start is inclusive, but _end is exclusive
COORD _start{};
COORD _end{};
bool _blockRange;

// This is used by tracing to extract the text value
// that the UiaTextRange currently encompasses.
Expand All @@ -162,7 +164,7 @@ namespace Microsoft::Console::Types
const unsigned int _getViewportHeight(const SMALL_RECT viewport) const noexcept;
const Viewport _getBufferSize() const noexcept;

void _getBoundingRect(_In_ const COORD startAnchor, _In_ const COORD endAnchor, _Inout_ std::vector<double>& coords) const;
void _getBoundingRect(const til::rectangle textRect, _Inout_ std::vector<double>& coords) const;

void
_moveEndpointByUnitCharacter(_In_ const int moveCount,
Expand Down