mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-06 14:19:45 +00:00
Compare commits
17 Commits
v1.0.1401.
...
release-0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fe7df4918 | ||
|
|
875680a3f1 | ||
|
|
8de952ca06 | ||
|
|
869bcb6ec4 | ||
|
|
1fe836eeca | ||
|
|
c97f336f54 | ||
|
|
ad80cffedf | ||
|
|
1bcc85a60b | ||
|
|
0b8b0b9d94 | ||
|
|
b4dae1238e | ||
|
|
7deaf6b5aa | ||
|
|
266402a2d6 | ||
|
|
3d7b455bb7 | ||
|
|
a6dedbb25a | ||
|
|
37d417c07d | ||
|
|
91503e0c96 | ||
|
|
9516372a8a |
@@ -1260,6 +1260,94 @@ bool TextBuffer::MoveToPreviousWord(COORD& pos, std::wstring_view wordDelimiters
|
||||
return true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Update pos to be the beginning of the current glyph/character. This is used for accessibility
|
||||
// Arguments:
|
||||
// - pos - a COORD on the word you are currently on
|
||||
// Return Value:
|
||||
// - pos - The COORD for the first cell of the current glyph (inclusive)
|
||||
const til::point TextBuffer::GetGlyphStart(const til::point pos) const
|
||||
{
|
||||
COORD resultPos = pos;
|
||||
|
||||
const auto bufferSize = GetSize();
|
||||
if (resultPos != bufferSize.EndExclusive() && GetCellDataAt(resultPos)->DbcsAttr().IsTrailing())
|
||||
{
|
||||
bufferSize.DecrementInBounds(resultPos, true);
|
||||
}
|
||||
|
||||
return resultPos;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Update pos to be the end of the current glyph/character. This is used for accessibility
|
||||
// Arguments:
|
||||
// - pos - a COORD on the word you are currently on
|
||||
// Return Value:
|
||||
// - pos - The COORD for the last cell of the current glyph (exclusive)
|
||||
const til::point TextBuffer::GetGlyphEnd(const til::point pos) const
|
||||
{
|
||||
COORD resultPos = pos;
|
||||
|
||||
const auto bufferSize = GetSize();
|
||||
if (resultPos != bufferSize.EndExclusive() && GetCellDataAt(resultPos)->DbcsAttr().IsLeading())
|
||||
{
|
||||
bufferSize.IncrementInBounds(resultPos, true);
|
||||
}
|
||||
|
||||
// increment one more time to become exclusive
|
||||
bufferSize.IncrementInBounds(resultPos, true);
|
||||
return resultPos;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Update pos to be the beginning of the next glyph/character. This is used for accessibility
|
||||
// Arguments:
|
||||
// - pos - a COORD on the word you are currently on
|
||||
// - allowBottomExclusive - allow the nonexistent end-of-buffer cell to be encountered
|
||||
// Return Value:
|
||||
// - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary)
|
||||
// - pos - The COORD for the first cell of the current glyph (inclusive)
|
||||
bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowBottomExclusive) const
|
||||
{
|
||||
COORD resultPos = pos;
|
||||
|
||||
// try to move. If we can't, we're done.
|
||||
const auto bufferSize = GetSize();
|
||||
const bool success = bufferSize.IncrementInBounds(resultPos, allowBottomExclusive);
|
||||
if (resultPos != bufferSize.EndExclusive() && GetCellDataAt(resultPos)->DbcsAttr().IsTrailing())
|
||||
{
|
||||
bufferSize.IncrementInBounds(resultPos, allowBottomExclusive);
|
||||
}
|
||||
|
||||
pos = resultPos;
|
||||
return success;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Update pos to be the beginning of the previous glyph/character. This is used for accessibility
|
||||
// Arguments:
|
||||
// - pos - a COORD on the word you are currently on
|
||||
// - allowBottomExclusive - allow the nonexistent end-of-buffer cell to be encountered
|
||||
// Return Value:
|
||||
// - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary)
|
||||
// - pos - The COORD for the first cell of the previous glyph (inclusive)
|
||||
bool TextBuffer::MoveToPreviousGlyph(til::point& pos, bool allowBottomExclusive) const
|
||||
{
|
||||
COORD resultPos = pos;
|
||||
|
||||
// try to move. If we can't, we're done.
|
||||
const auto bufferSize = GetSize();
|
||||
const bool success = bufferSize.DecrementInBounds(resultPos, allowBottomExclusive);
|
||||
if (resultPos != bufferSize.EndExclusive() && GetCellDataAt(resultPos)->DbcsAttr().IsLeading())
|
||||
{
|
||||
bufferSize.DecrementInBounds(resultPos, allowBottomExclusive);
|
||||
}
|
||||
|
||||
pos = resultPos;
|
||||
return success;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Determines the line-by-line rectangles based on two COORDs
|
||||
// - expands the rectangles to support wide glyphs
|
||||
|
||||
@@ -134,6 +134,11 @@ public:
|
||||
bool MoveToNextWord(COORD& pos, const std::wstring_view wordDelimiters, COORD lastCharPos) const;
|
||||
bool MoveToPreviousWord(COORD& pos, const std::wstring_view wordDelimiters) const;
|
||||
|
||||
const til::point GetGlyphStart(const til::point pos) const;
|
||||
const til::point GetGlyphEnd(const til::point pos) const;
|
||||
bool MoveToNextGlyph(til::point& pos, bool allowBottomExclusive = false) const;
|
||||
bool MoveToPreviousGlyph(til::point& pos, bool allowBottomExclusive = false) const;
|
||||
|
||||
const std::vector<SMALL_RECT> GetTextRects(COORD start, COORD end, bool blockSelection = false) const;
|
||||
|
||||
class TextAndColor
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
Version="1.0.0.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>ms-resource:AppName</DisplayName>
|
||||
<DisplayName>Windows Terminal</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
|
||||
<Logo>Images\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
|
||||
@@ -516,7 +516,7 @@ std::vector<::TerminalApp::SettingsLoadWarnings> winrt::TerminalApp::implementat
|
||||
warnings.insert(warnings.end(), parseWarnings.begin(), parseWarnings.end());
|
||||
|
||||
// if an arg parser was registered, but failed, bail
|
||||
if (args == nullptr)
|
||||
if (pfn && args == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -803,10 +803,10 @@ void Pane::_CreateRowColDefinitions(const Size& rootSize)
|
||||
const auto paneSizes = _CalcChildrenSizes(rootSize.Width);
|
||||
|
||||
auto firstColDef = Controls::ColumnDefinition();
|
||||
firstColDef.Width(GridLengthHelper::FromPixels(paneSizes.first));
|
||||
firstColDef.Width(GridLengthHelper::FromValueAndType(paneSizes.first, GridUnitType::Star));
|
||||
|
||||
auto secondColDef = Controls::ColumnDefinition();
|
||||
secondColDef.Width(GridLengthHelper::FromPixels(paneSizes.second));
|
||||
secondColDef.Width(GridLengthHelper::FromValueAndType(paneSizes.second, GridUnitType::Star));
|
||||
|
||||
_root.ColumnDefinitions().Append(firstColDef);
|
||||
_root.ColumnDefinitions().Append(secondColDef);
|
||||
@@ -819,10 +819,10 @@ void Pane::_CreateRowColDefinitions(const Size& rootSize)
|
||||
const auto paneSizes = _CalcChildrenSizes(rootSize.Height);
|
||||
|
||||
auto firstRowDef = Controls::RowDefinition();
|
||||
firstRowDef.Height(GridLengthHelper::FromPixels(paneSizes.first));
|
||||
firstRowDef.Height(GridLengthHelper::FromValueAndType(paneSizes.first, GridUnitType::Star));
|
||||
|
||||
auto secondRowDef = Controls::RowDefinition();
|
||||
secondRowDef.Height(GridLengthHelper::FromPixels(paneSizes.second));
|
||||
secondRowDef.Height(GridLengthHelper::FromValueAndType(paneSizes.second, GridUnitType::Star));
|
||||
|
||||
_root.RowDefinitions().Append(firstRowDef);
|
||||
_root.RowDefinitions().Append(secondRowDef);
|
||||
|
||||
@@ -63,13 +63,13 @@ std::vector<TerminalApp::Profile> WslDistroGenerator::GenerateProfiles()
|
||||
nullptr,
|
||||
&si,
|
||||
&pi));
|
||||
switch (WaitForSingleObject(pi.hProcess, INFINITE))
|
||||
switch (WaitForSingleObject(pi.hProcess, 2000))
|
||||
{
|
||||
case WAIT_OBJECT_0:
|
||||
break;
|
||||
case WAIT_ABANDONED:
|
||||
case WAIT_TIMEOUT:
|
||||
THROW_HR(ERROR_CHILD_NOT_COMPLETE);
|
||||
return profiles;
|
||||
case WAIT_FAILED:
|
||||
THROW_LAST_ERROR();
|
||||
default:
|
||||
|
||||
@@ -164,4 +164,10 @@
|
||||
<data name="SearchBox_Close.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Close Search Box</value>
|
||||
</data>
|
||||
</root>
|
||||
<data name="TermControl_RendererFailedTextBlock.Text" xml:space="preserve">
|
||||
<value>This terminal has encountered an issue with the graphics driver and it could not recover in time. It has been suspended.</value>
|
||||
</data>
|
||||
<data name="TermControl_RendererRetryButton.Content" xml:space="preserve">
|
||||
<value>Resume</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -522,6 +522,13 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
_renderer = std::make_unique<::Microsoft::Console::Render::Renderer>(_terminal.get(), nullptr, 0, std::move(renderThread));
|
||||
::Microsoft::Console::Render::IRenderTarget& renderTarget = *_renderer;
|
||||
|
||||
_renderer->SetRendererEnteredErrorStateCallback([weakThis = get_weak()]() {
|
||||
if (auto strongThis{ weakThis.get() })
|
||||
{
|
||||
strongThis->_RendererEnteredErrorState();
|
||||
}
|
||||
});
|
||||
|
||||
THROW_IF_FAILED(localPointerToThread->Initialize(_renderer.get()));
|
||||
|
||||
// Set up the DX Engine
|
||||
@@ -724,6 +731,16 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
const auto scanCode = gsl::narrow_cast<WORD>(e.KeyStatus().ScanCode);
|
||||
bool handled = false;
|
||||
|
||||
// Alt-Numpad# input will send us a character once the user releases Alt, so we should be ignoring the individual keydowns.
|
||||
// The character will be sent through the TSFInputControl.
|
||||
// See GH#1401 for more details
|
||||
if (modifiers.IsAltPressed() && (e.OriginalKey() >= VirtualKey::NumberPad0 && e.OriginalKey() <= VirtualKey::NumberPad9))
|
||||
|
||||
{
|
||||
e.Handled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// GH#2235: Terminal::Settings hasn't been modified to differentiate between AltGr and Ctrl+Alt yet.
|
||||
// -> Don't check for key bindings if this is an AltGr key combination.
|
||||
if (!modifiers.IsAltGrPressed())
|
||||
@@ -2352,6 +2369,31 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
e.DragUIOverride().IsGlyphVisible(false);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Produces the error dialog that notifies the user that rendering cannot proceed.
|
||||
winrt::fire_and_forget TermControl::_RendererEnteredErrorState()
|
||||
{
|
||||
auto strongThis{ get_strong() };
|
||||
co_await Dispatcher(); // pop up onto the UI thread
|
||||
|
||||
if (auto loadedUiElement{ FindName(L"RendererFailedNotice") })
|
||||
{
|
||||
if (auto uiElement{ loadedUiElement.try_as<::winrt::Windows::UI::Xaml::UIElement>() })
|
||||
{
|
||||
uiElement.Visibility(Visibility::Visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Responds to the Click event on the button that will re-enable the renderer.
|
||||
void TermControl::_RenderRetryButton_Click(IInspectable const& /*sender*/, IInspectable const& /*args*/)
|
||||
{
|
||||
// It's already loaded if we get here, so just hide it.
|
||||
RendererFailedNotice().Visibility(Visibility::Collapsed);
|
||||
_renderer->ResetErrorStateAndResume();
|
||||
}
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
// Winrt events need a method for adding a callback to the event and removing the callback.
|
||||
// These macros will define them both for you.
|
||||
|
||||
@@ -78,6 +78,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
void ResetFontSize();
|
||||
|
||||
winrt::fire_and_forget SwapChainChanged();
|
||||
winrt::fire_and_forget _RendererEnteredErrorState();
|
||||
void _RenderRetryButton_Click(IInspectable const& button, IInspectable const& args);
|
||||
|
||||
void CreateSearchBoxControl();
|
||||
|
||||
|
||||
@@ -77,6 +77,23 @@
|
||||
CurrentCursorPosition="_CurrentCursorPositionHandler"
|
||||
CurrentFontInfo="_FontInfoHandler" />
|
||||
|
||||
<Grid x:Name="RendererFailedNotice"
|
||||
x:Load="False"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
<Border Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
|
||||
BorderBrush="{ThemeResource SystemAccentColor}"
|
||||
Margin="8,8,8,8"
|
||||
Padding="8,8,8,8"
|
||||
BorderThickness="2,2,2,2"
|
||||
CornerRadius="{ThemeResource OverlayCornerRadius}">
|
||||
<StackPanel>
|
||||
<TextBlock HorizontalAlignment="Center" x:Uid="TermControl_RendererFailedTextBlock" TextWrapping="WrapWholeWords"/>
|
||||
<Button Click="_RenderRetryButton_Click" x:Uid="TermControl_RendererRetryButton" HorizontalAlignment="Right" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "TermControlAutomationPeer.g.cpp"
|
||||
|
||||
#include "XamlUiaTextRange.h"
|
||||
#include "..\types\UiaTracing.h"
|
||||
|
||||
using namespace Microsoft::Console::Types;
|
||||
using namespace winrt::Windows::UI::Xaml::Automation::Peers;
|
||||
@@ -44,6 +45,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
// - <none>
|
||||
void TermControlAutomationPeer::SignalSelectionChanged()
|
||||
{
|
||||
UiaTracing::Signal::SelectionChanged();
|
||||
Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [&]() {
|
||||
// The event that is raised when the text selection is modified.
|
||||
RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged);
|
||||
@@ -58,6 +60,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
// - <none>
|
||||
void TermControlAutomationPeer::SignalTextChanged()
|
||||
{
|
||||
UiaTracing::Signal::TextChanged();
|
||||
Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [&]() {
|
||||
// The event that is raised when textual content is modified.
|
||||
RaiseAutomationEvent(AutomationEvents::TextPatternOnTextChanged);
|
||||
@@ -72,9 +75,15 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
// - <none>
|
||||
void TermControlAutomationPeer::SignalCursorChanged()
|
||||
{
|
||||
UiaTracing::Signal::CursorChanged();
|
||||
Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [&]() {
|
||||
// The event that is raised when the text was changed in an edit control.
|
||||
RaiseAutomationEvent(AutomationEvents::TextEditTextChanged);
|
||||
// Do NOT fire a TextEditTextChanged. Generally, an app on the other side
|
||||
// will expect more information. Though you can dispatch that event
|
||||
// on its own, it may result in a nullptr exception on the other side
|
||||
// because no additional information was provided. Crashing the screen
|
||||
// reader.
|
||||
RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -173,15 +173,17 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
const auto dx = viewportSize.X - oldDimensions.X;
|
||||
|
||||
const auto dx = ::base::ClampSub(viewportSize.X, oldDimensions.X);
|
||||
|
||||
const auto oldTop = _mutableViewport.Top();
|
||||
|
||||
const short newBufferHeight = viewportSize.Y + _scrollbackLines;
|
||||
const short newBufferHeight = ::base::ClampAdd(viewportSize.Y, _scrollbackLines);
|
||||
|
||||
COORD bufferSize{ viewportSize.X, newBufferHeight };
|
||||
|
||||
// Save cursor's relative height versus the viewport
|
||||
const short sCursorHeightInViewportBefore = _buffer->GetCursor().GetPosition().Y - _mutableViewport.Top();
|
||||
const short sCursorHeightInViewportBefore = ::base::ClampSub(_buffer->GetCursor().GetPosition().Y, _mutableViewport.Top());
|
||||
|
||||
// This will be used to determine where the viewport should be in the new buffer.
|
||||
const short oldViewportTop = _mutableViewport.Top();
|
||||
@@ -266,7 +268,7 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting
|
||||
|
||||
const auto maxRow = std::max(newLastChar.Y, newCursorPos.Y);
|
||||
|
||||
const short proposedTopFromLastLine = ::base::saturated_cast<short>(maxRow - viewportSize.Y + 1);
|
||||
const short proposedTopFromLastLine = ::base::ClampAdd(::base::ClampSub(maxRow, viewportSize.Y), 1);
|
||||
const short proposedTopFromScrollback = newViewportTop;
|
||||
|
||||
short proposedTop = std::max(proposedTopFromLastLine,
|
||||
@@ -294,7 +296,7 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting
|
||||
{
|
||||
try
|
||||
{
|
||||
auto row = newTextBuffer->GetRowByOffset(::base::saturated_cast<short>(proposedTop - 1));
|
||||
auto row = newTextBuffer->GetRowByOffset(::base::ClampSub(proposedTop, 1));
|
||||
if (row.GetCharRow().WasWrapForced())
|
||||
{
|
||||
proposedTop--;
|
||||
@@ -324,7 +326,7 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting
|
||||
const auto proposedBottom = newView.BottomExclusive();
|
||||
if (proposedBottom > bufferSize.Y)
|
||||
{
|
||||
proposedTop = ::base::saturated_cast<short>(proposedTop - (proposedBottom - bufferSize.Y));
|
||||
proposedTop = ::base::ClampSub(proposedTop, ::base::ClampSub(proposedBottom, bufferSize.Y));
|
||||
}
|
||||
|
||||
_mutableViewport = Viewport::FromDimensions({ 0, proposedTop }, viewportSize);
|
||||
@@ -339,7 +341,7 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting
|
||||
|
||||
// If the old scrolloffset was 0, then we weren't scrolled back at all
|
||||
// before, and shouldn't be now either.
|
||||
_scrollOffset = originalOffsetWasZero ? 0 : _mutableViewport.Top() - newVisibleTop;
|
||||
_scrollOffset = originalOffsetWasZero ? 0 : ::base::ClampSub(_mutableViewport.Top(), newVisibleTop);
|
||||
_NotifyScrollEvent();
|
||||
|
||||
return S_OK;
|
||||
|
||||
@@ -156,6 +156,7 @@ public:
|
||||
#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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
using namespace winrt::Microsoft::Terminal::Settings;
|
||||
using namespace Microsoft::Terminal::Core;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::TestExecution;
|
||||
using namespace WEX::Common;
|
||||
|
||||
namespace TerminalCoreUnitTests
|
||||
{
|
||||
@@ -21,66 +24,109 @@ namespace TerminalCoreUnitTests
|
||||
{
|
||||
TEST_CLASS(ScreenSizeLimitsTest);
|
||||
|
||||
TEST_METHOD(ScreenWidthAndHeightAreClampedToBounds)
|
||||
{
|
||||
DummyRenderTarget emptyRenderTarget;
|
||||
TEST_METHOD(ScreenWidthAndHeightAreClampedToBounds);
|
||||
TEST_METHOD(ScrollbackHistorySizeIsClampedToBounds);
|
||||
|
||||
// Negative values for initial visible row count or column count
|
||||
// are clamped to 1. Too-large positive values are clamped to SHRT_MAX.
|
||||
auto negativeColumnsSettings = winrt::make<MockTermSettings>(10000, 9999999, -1234);
|
||||
Terminal negativeColumnsTerminal;
|
||||
negativeColumnsTerminal.CreateFromSettings(negativeColumnsSettings, emptyRenderTarget);
|
||||
COORD actualDimensions = negativeColumnsTerminal.GetViewport().Dimensions();
|
||||
VERIFY_ARE_EQUAL(actualDimensions.Y, SHRT_MAX, L"Row count clamped to SHRT_MAX == " WCS(SHRT_MAX));
|
||||
VERIFY_ARE_EQUAL(actualDimensions.X, 1, L"Column count clamped to 1");
|
||||
|
||||
// Zero values are clamped to 1 as well.
|
||||
auto zeroRowsSettings = winrt::make<MockTermSettings>(10000, 0, 9999999);
|
||||
Terminal zeroRowsTerminal;
|
||||
zeroRowsTerminal.CreateFromSettings(zeroRowsSettings, emptyRenderTarget);
|
||||
actualDimensions = zeroRowsTerminal.GetViewport().Dimensions();
|
||||
VERIFY_ARE_EQUAL(actualDimensions.Y, 1, L"Row count clamped to 1");
|
||||
VERIFY_ARE_EQUAL(actualDimensions.X, SHRT_MAX, L"Column count clamped to SHRT_MAX == " WCS(SHRT_MAX));
|
||||
}
|
||||
|
||||
TEST_METHOD(ScrollbackHistorySizeIsClampedToBounds)
|
||||
{
|
||||
// What is actually clamped is the number of rows in the internal history buffer,
|
||||
// which is the *sum* of the history size plus the number of rows
|
||||
// actually visible on screen at the moment.
|
||||
|
||||
const unsigned int visibleRowCount = 100;
|
||||
DummyRenderTarget emptyRenderTarget;
|
||||
|
||||
// Zero history size is acceptable.
|
||||
auto noHistorySettings = winrt::make<MockTermSettings>(0, visibleRowCount, 100);
|
||||
Terminal noHistoryTerminal;
|
||||
noHistoryTerminal.CreateFromSettings(noHistorySettings, emptyRenderTarget);
|
||||
VERIFY_ARE_EQUAL(noHistoryTerminal.GetTextBuffer().TotalRowCount(), visibleRowCount, L"History size of 0 is accepted");
|
||||
|
||||
// Negative history sizes are clamped to zero.
|
||||
auto negativeHistorySizeSettings = winrt::make<MockTermSettings>(-100, visibleRowCount, 100);
|
||||
Terminal negativeHistorySizeTerminal;
|
||||
negativeHistorySizeTerminal.CreateFromSettings(negativeHistorySizeSettings, emptyRenderTarget);
|
||||
VERIFY_ARE_EQUAL(negativeHistorySizeTerminal.GetTextBuffer().TotalRowCount(), visibleRowCount, L"Negative history size is clamped to 0");
|
||||
|
||||
// History size + initial visible rows == SHRT_MAX is acceptable.
|
||||
auto maxHistorySizeSettings = winrt::make<MockTermSettings>(SHRT_MAX - visibleRowCount, visibleRowCount, 100);
|
||||
Terminal maxHistorySizeTerminal;
|
||||
maxHistorySizeTerminal.CreateFromSettings(maxHistorySizeSettings, emptyRenderTarget);
|
||||
VERIFY_ARE_EQUAL(maxHistorySizeTerminal.GetTextBuffer().TotalRowCount(), static_cast<unsigned int>(SHRT_MAX), L"History size == SHRT_MAX - initial row count is accepted");
|
||||
|
||||
// History size + initial visible rows == SHRT_MAX + 1 will be clamped slightly.
|
||||
auto justTooBigHistorySizeSettings = winrt::make<MockTermSettings>(SHRT_MAX - visibleRowCount + 1, visibleRowCount, 100);
|
||||
Terminal justTooBigHistorySizeTerminal;
|
||||
justTooBigHistorySizeTerminal.CreateFromSettings(justTooBigHistorySizeSettings, emptyRenderTarget);
|
||||
VERIFY_ARE_EQUAL(justTooBigHistorySizeTerminal.GetTextBuffer().TotalRowCount(), static_cast<unsigned int>(SHRT_MAX), L"History size == 1 + SHRT_MAX - initial row count is clamped to SHRT_MAX - initial row count");
|
||||
|
||||
// Ridiculously large history sizes are also clamped.
|
||||
auto farTooBigHistorySizeSettings = winrt::make<MockTermSettings>(99999999, visibleRowCount, 100);
|
||||
Terminal farTooBigHistorySizeTerminal;
|
||||
farTooBigHistorySizeTerminal.CreateFromSettings(farTooBigHistorySizeSettings, emptyRenderTarget);
|
||||
VERIFY_ARE_EQUAL(farTooBigHistorySizeTerminal.GetTextBuffer().TotalRowCount(), static_cast<unsigned int>(SHRT_MAX), L"History size that is far too large is clamped to SHRT_MAX - initial row count");
|
||||
}
|
||||
TEST_METHOD(ResizeIsClampedToBounds);
|
||||
};
|
||||
}
|
||||
|
||||
using namespace TerminalCoreUnitTests;
|
||||
|
||||
void ScreenSizeLimitsTest::ScreenWidthAndHeightAreClampedToBounds()
|
||||
{
|
||||
DummyRenderTarget emptyRenderTarget;
|
||||
|
||||
// Negative values for initial visible row count or column count
|
||||
// are clamped to 1. Too-large positive values are clamped to SHRT_MAX.
|
||||
auto negativeColumnsSettings = winrt::make<MockTermSettings>(10000, 9999999, -1234);
|
||||
Terminal negativeColumnsTerminal;
|
||||
negativeColumnsTerminal.CreateFromSettings(negativeColumnsSettings, emptyRenderTarget);
|
||||
COORD actualDimensions = negativeColumnsTerminal.GetViewport().Dimensions();
|
||||
VERIFY_ARE_EQUAL(actualDimensions.Y, SHRT_MAX, L"Row count clamped to SHRT_MAX == " WCS(SHRT_MAX));
|
||||
VERIFY_ARE_EQUAL(actualDimensions.X, 1, L"Column count clamped to 1");
|
||||
|
||||
// Zero values are clamped to 1 as well.
|
||||
auto zeroRowsSettings = winrt::make<MockTermSettings>(10000, 0, 9999999);
|
||||
Terminal zeroRowsTerminal;
|
||||
zeroRowsTerminal.CreateFromSettings(zeroRowsSettings, emptyRenderTarget);
|
||||
actualDimensions = zeroRowsTerminal.GetViewport().Dimensions();
|
||||
VERIFY_ARE_EQUAL(actualDimensions.Y, 1, L"Row count clamped to 1");
|
||||
VERIFY_ARE_EQUAL(actualDimensions.X, SHRT_MAX, L"Column count clamped to SHRT_MAX == " WCS(SHRT_MAX));
|
||||
}
|
||||
|
||||
void ScreenSizeLimitsTest::ScrollbackHistorySizeIsClampedToBounds()
|
||||
{
|
||||
// What is actually clamped is the number of rows in the internal history buffer,
|
||||
// which is the *sum* of the history size plus the number of rows
|
||||
// actually visible on screen at the moment.
|
||||
|
||||
const unsigned int visibleRowCount = 100;
|
||||
DummyRenderTarget emptyRenderTarget;
|
||||
|
||||
// Zero history size is acceptable.
|
||||
auto noHistorySettings = winrt::make<MockTermSettings>(0, visibleRowCount, 100);
|
||||
Terminal noHistoryTerminal;
|
||||
noHistoryTerminal.CreateFromSettings(noHistorySettings, emptyRenderTarget);
|
||||
VERIFY_ARE_EQUAL(noHistoryTerminal.GetTextBuffer().TotalRowCount(), visibleRowCount, L"History size of 0 is accepted");
|
||||
|
||||
// Negative history sizes are clamped to zero.
|
||||
auto negativeHistorySizeSettings = winrt::make<MockTermSettings>(-100, visibleRowCount, 100);
|
||||
Terminal negativeHistorySizeTerminal;
|
||||
negativeHistorySizeTerminal.CreateFromSettings(negativeHistorySizeSettings, emptyRenderTarget);
|
||||
VERIFY_ARE_EQUAL(negativeHistorySizeTerminal.GetTextBuffer().TotalRowCount(), visibleRowCount, L"Negative history size is clamped to 0");
|
||||
|
||||
// History size + initial visible rows == SHRT_MAX is acceptable.
|
||||
auto maxHistorySizeSettings = winrt::make<MockTermSettings>(SHRT_MAX - visibleRowCount, visibleRowCount, 100);
|
||||
Terminal maxHistorySizeTerminal;
|
||||
maxHistorySizeTerminal.CreateFromSettings(maxHistorySizeSettings, emptyRenderTarget);
|
||||
VERIFY_ARE_EQUAL(maxHistorySizeTerminal.GetTextBuffer().TotalRowCount(), static_cast<unsigned int>(SHRT_MAX), L"History size == SHRT_MAX - initial row count is accepted");
|
||||
|
||||
// History size + initial visible rows == SHRT_MAX + 1 will be clamped slightly.
|
||||
auto justTooBigHistorySizeSettings = winrt::make<MockTermSettings>(SHRT_MAX - visibleRowCount + 1, visibleRowCount, 100);
|
||||
Terminal justTooBigHistorySizeTerminal;
|
||||
justTooBigHistorySizeTerminal.CreateFromSettings(justTooBigHistorySizeSettings, emptyRenderTarget);
|
||||
VERIFY_ARE_EQUAL(justTooBigHistorySizeTerminal.GetTextBuffer().TotalRowCount(), static_cast<unsigned int>(SHRT_MAX), L"History size == 1 + SHRT_MAX - initial row count is clamped to SHRT_MAX - initial row count");
|
||||
|
||||
// Ridiculously large history sizes are also clamped.
|
||||
auto farTooBigHistorySizeSettings = winrt::make<MockTermSettings>(99999999, visibleRowCount, 100);
|
||||
Terminal farTooBigHistorySizeTerminal;
|
||||
farTooBigHistorySizeTerminal.CreateFromSettings(farTooBigHistorySizeSettings, emptyRenderTarget);
|
||||
VERIFY_ARE_EQUAL(farTooBigHistorySizeTerminal.GetTextBuffer().TotalRowCount(), static_cast<unsigned int>(SHRT_MAX), L"History size that is far too large is clamped to SHRT_MAX - initial row count");
|
||||
}
|
||||
|
||||
void ScreenSizeLimitsTest::ResizeIsClampedToBounds()
|
||||
{
|
||||
// What is actually clamped is the number of rows in the internal history buffer,
|
||||
// which is the *sum* of the history size plus the number of rows
|
||||
// actually visible on screen at the moment.
|
||||
//
|
||||
// This is a test for GH#2630, GH#2815.
|
||||
|
||||
const unsigned int initialVisibleColCount = 50;
|
||||
const unsigned int initialVisibleRowCount = 50;
|
||||
const auto historySize = SHRT_MAX - (initialVisibleRowCount * 2);
|
||||
DummyRenderTarget emptyRenderTarget;
|
||||
|
||||
Log::Comment(L"Watch out - this test takes a while on debug, because "
|
||||
L"ResizeWithReflow takes a while on debug. This is expected.");
|
||||
|
||||
auto settings = winrt::make<MockTermSettings>(historySize, initialVisibleRowCount, initialVisibleColCount);
|
||||
Log::Comment(L"First create a terminal with fewer than SHRT_MAX lines");
|
||||
Terminal terminal;
|
||||
terminal.CreateFromSettings(settings, emptyRenderTarget);
|
||||
VERIFY_ARE_EQUAL(terminal.GetTextBuffer().TotalRowCount(), static_cast<unsigned int>(historySize + initialVisibleRowCount));
|
||||
|
||||
Log::Comment(L"Resize the terminal to have exactly SHRT_MAX lines");
|
||||
VERIFY_SUCCEEDED(terminal.UserResize({ initialVisibleColCount, initialVisibleRowCount * 2 }));
|
||||
|
||||
VERIFY_ARE_EQUAL(terminal.GetTextBuffer().TotalRowCount(), static_cast<unsigned int>(SHRT_MAX));
|
||||
|
||||
Log::Comment(L"Resize the terminal to have MORE than SHRT_MAX lines - we should clamp to SHRT_MAX");
|
||||
VERIFY_SUCCEEDED(terminal.UserResize({ initialVisibleColCount, initialVisibleRowCount * 3 }));
|
||||
VERIFY_ARE_EQUAL(terminal.GetTextBuffer().TotalRowCount(), static_cast<unsigned int>(SHRT_MAX));
|
||||
|
||||
Log::Comment(L"Resize back down to the original size");
|
||||
VERIFY_SUCCEEDED(terminal.UserResize({ initialVisibleColCount, initialVisibleRowCount }));
|
||||
VERIFY_ARE_EQUAL(terminal.GetTextBuffer().TotalRowCount(), static_cast<unsigned int>(historySize + initialVisibleRowCount));
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -60,6 +60,7 @@ public:
|
||||
|
||||
#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;
|
||||
|
||||
@@ -113,6 +113,7 @@ class ConptyOutputTests
|
||||
TEST_METHOD(SimpleWriteOutputTest);
|
||||
TEST_METHOD(WriteTwoLinesUsesNewline);
|
||||
TEST_METHOD(WriteAFewSimpleLines);
|
||||
TEST_METHOD(InvalidateUntilOneBeforeEnd);
|
||||
|
||||
private:
|
||||
bool _writeCallback(const char* const pch, size_t const cch);
|
||||
@@ -124,10 +125,14 @@ private:
|
||||
|
||||
bool ConptyOutputTests::_writeCallback(const char* const pch, size_t const cch)
|
||||
{
|
||||
// Since rendering happens on a background thread that doesn't have the exception handler on it
|
||||
// we need to rely on VERIFY's return codes instead of exceptions.
|
||||
const WEX::TestExecution::DisableVerifyExceptions disableExceptionsScope;
|
||||
|
||||
std::string actualString = std::string(pch, cch);
|
||||
VERIFY_IS_GREATER_THAN(expectedOutput.size(),
|
||||
static_cast<size_t>(0),
|
||||
NoThrowString().Format(L"writing=\"%hs\", expecting %u strings", actualString.c_str(), expectedOutput.size()));
|
||||
RETURN_BOOL_IF_FALSE(VERIFY_IS_GREATER_THAN(expectedOutput.size(),
|
||||
static_cast<size_t>(0),
|
||||
NoThrowString().Format(L"writing=\"%hs\", expecting %u strings", actualString.c_str(), expectedOutput.size())));
|
||||
|
||||
std::string first = expectedOutput.front();
|
||||
expectedOutput.pop_front();
|
||||
@@ -135,8 +140,8 @@ bool ConptyOutputTests::_writeCallback(const char* const pch, size_t const cch)
|
||||
Log::Comment(NoThrowString().Format(L"Expected =\t\"%hs\"", first.c_str()));
|
||||
Log::Comment(NoThrowString().Format(L"Actual =\t\"%hs\"", actualString.c_str()));
|
||||
|
||||
VERIFY_ARE_EQUAL(first.length(), cch);
|
||||
VERIFY_ARE_EQUAL(first, actualString);
|
||||
RETURN_BOOL_IF_FALSE(VERIFY_ARE_EQUAL(first.length(), cch));
|
||||
RETURN_BOOL_IF_FALSE(VERIFY_ARE_EQUAL(first, actualString));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -314,3 +319,55 @@ void ConptyOutputTests::WriteAFewSimpleLines()
|
||||
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
}
|
||||
|
||||
void ConptyOutputTests::InvalidateUntilOneBeforeEnd()
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Make sure we don't use EL and wipe out the last column of text"));
|
||||
VERIFY_IS_NOT_NULL(_pVtRenderEngine.get());
|
||||
|
||||
auto& g = ServiceLocator::LocateGlobals();
|
||||
auto& renderer = *g.pRender;
|
||||
auto& gci = g.getConsoleInformation();
|
||||
auto& si = gci.GetActiveOutputBuffer();
|
||||
auto& sm = si.GetStateMachine();
|
||||
auto& tb = si.GetTextBuffer();
|
||||
|
||||
_flushFirstFrame();
|
||||
|
||||
// Move the cursor to width-15, draw 15 characters
|
||||
sm.ProcessString(L"\x1b[1;66H");
|
||||
sm.ProcessString(L"ABCDEFGHIJKLMNO");
|
||||
|
||||
{
|
||||
auto iter = tb.GetCellDataAt({ 78, 0 });
|
||||
VERIFY_ARE_EQUAL(L"N", (iter++)->Chars());
|
||||
VERIFY_ARE_EQUAL(L"O", (iter++)->Chars());
|
||||
}
|
||||
|
||||
expectedOutput.push_back("\x1b[65C");
|
||||
expectedOutput.push_back("ABCDEFGHIJKLMNO");
|
||||
expectedOutput.push_back("\x1b[1;80H"); // we move the cursor to the end of the line after paint
|
||||
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
// overstrike the first with X and the middle 8 with spaces
|
||||
sm.ProcessString(L"\x1b[1;66H");
|
||||
// ABCDEFGHIJKLMNO
|
||||
sm.ProcessString(L"X ");
|
||||
|
||||
{
|
||||
auto iter = tb.GetCellDataAt({ 78, 0 });
|
||||
VERIFY_ARE_EQUAL(L" ", (iter++)->Chars());
|
||||
VERIFY_ARE_EQUAL(L"O", (iter++)->Chars());
|
||||
}
|
||||
|
||||
expectedOutput.push_back("\x1b[1;66H");
|
||||
expectedOutput.push_back("X"); // sequence optimizer should choose ECH here
|
||||
expectedOutput.push_back("\x1b[13X");
|
||||
expectedOutput.push_back("\x1b[13C");
|
||||
|
||||
expectedOutput.push_back("\x1b[?25h"); // we turn the cursor back on for good measure
|
||||
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
}
|
||||
|
||||
@@ -148,6 +148,7 @@ class TextBufferTests
|
||||
|
||||
void WriteLinesToBuffer(const std::vector<std::wstring>& text, TextBuffer& buffer);
|
||||
TEST_METHOD(GetWordBoundaries);
|
||||
TEST_METHOD(GetGlyphBoundaries);
|
||||
|
||||
TEST_METHOD(GetTextRects);
|
||||
TEST_METHOD(GetText);
|
||||
@@ -2153,6 +2154,59 @@ void TextBufferTests::GetWordBoundaries()
|
||||
}
|
||||
}
|
||||
|
||||
void TextBufferTests::GetGlyphBoundaries()
|
||||
{
|
||||
struct ExpectedResult
|
||||
{
|
||||
std::wstring name;
|
||||
til::point start;
|
||||
til::point wideGlyphEnd;
|
||||
til::point normalEnd;
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
const std::vector<ExpectedResult> expected = {
|
||||
{ L"Buffer Start", { 0, 0 }, { 2, 0 }, { 1, 0 } },
|
||||
{ L"Line Start", { 0, 1 }, { 2, 1 }, { 1, 1 } },
|
||||
{ L"General Case", { 1, 1 }, { 3, 1 }, { 2, 1 } },
|
||||
{ L"Line End", { 9, 1 }, { 0, 2 }, { 0, 2 } },
|
||||
{ L"Buffer End", { 9, 9 }, { 0, 10 }, { 0, 10 } },
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
BEGIN_TEST_METHOD_PROPERTIES()
|
||||
TEST_METHOD_PROPERTY(L"Data:wideGlyph", L"{false, true}")
|
||||
END_TEST_METHOD_PROPERTIES();
|
||||
|
||||
bool wideGlyph;
|
||||
VERIFY_SUCCEEDED(TestData::TryGetValue(L"wideGlyph", wideGlyph), L"Get wide glyph variant");
|
||||
|
||||
COORD bufferSize{ 10, 10 };
|
||||
UINT cursorSize = 12;
|
||||
TextAttribute attr{ 0x7f };
|
||||
auto _buffer = std::make_unique<TextBuffer>(bufferSize, attr, cursorSize, _renderTarget);
|
||||
|
||||
// This is the burrito emoji: 🌯
|
||||
// It's encoded in UTF-16, as needed by the buffer.
|
||||
const auto burrito = L"\xD83C\xDF2F";
|
||||
const wchar_t* const output = wideGlyph ? burrito : L"X";
|
||||
|
||||
const OutputCellIterator iter{ output };
|
||||
|
||||
for (const auto& test : expected)
|
||||
{
|
||||
Log::Comment(test.name.c_str());
|
||||
auto target = test.start;
|
||||
_buffer->Write(iter, target);
|
||||
|
||||
auto start = _buffer->GetGlyphStart(target);
|
||||
auto end = _buffer->GetGlyphEnd(target);
|
||||
|
||||
VERIFY_ARE_EQUAL(test.start, start);
|
||||
VERIFY_ARE_EQUAL(wideGlyph ? test.wideGlyphEnd : test.normalEnd, end);
|
||||
}
|
||||
}
|
||||
|
||||
void TextBufferTests::GetTextRects()
|
||||
{
|
||||
// GetTextRects() is used to...
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,6 +11,8 @@ using namespace Microsoft::Console::Render;
|
||||
using namespace Microsoft::Console::Types;
|
||||
|
||||
static constexpr auto maxRetriesForRenderEngine = 3;
|
||||
// The renderer will wait this number of milliseconds * how many tries have elapsed before trying again.
|
||||
static constexpr auto renderBackoffBaseTimeMilliseconds{ 150 };
|
||||
|
||||
// Routine Description:
|
||||
// - Creates a new renderer controller for a console.
|
||||
@@ -78,8 +80,20 @@ Renderer::~Renderer()
|
||||
{
|
||||
if (--tries == 0)
|
||||
{
|
||||
FAIL_FAST_HR_MSG(E_UNEXPECTED, "A rendering engine required too many retries.");
|
||||
// Stop trying.
|
||||
_pThread->DisablePainting();
|
||||
if (_pfnRendererEnteredErrorState)
|
||||
{
|
||||
_pfnRendererEnteredErrorState();
|
||||
}
|
||||
// If there's no callback, we still don't want to FAIL_FAST: the renderer going black
|
||||
// isn't near as bad as the entire application aborting. We're a component. We shouldn't
|
||||
// abort applications that host us.
|
||||
return S_FALSE;
|
||||
}
|
||||
// Add a bit of backoff.
|
||||
// Sleep 150ms, 300ms, 450ms before failing out and disabling the renderer.
|
||||
Sleep(renderBackoffBaseTimeMilliseconds * (maxRetriesForRenderEngine - tries));
|
||||
continue;
|
||||
}
|
||||
LOG_IF_FAILED(hr);
|
||||
@@ -1016,3 +1030,23 @@ void Renderer::AddRenderEngine(_In_ IRenderEngine* const pEngine)
|
||||
THROW_HR_IF_NULL(E_INVALIDARG, pEngine);
|
||||
_rgpEngines.push_back(pEngine);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Registers a callback that will be called when this renderer gives up.
|
||||
// An application consuming a renderer can use this to display auxiliary Retry UI
|
||||
// Arguments:
|
||||
// - pfn: the callback
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Renderer::SetRendererEnteredErrorStateCallback(std::function<void()> pfn)
|
||||
{
|
||||
_pfnRendererEnteredErrorState = std::move(pfn);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempts to restart the renderer.
|
||||
void Renderer::ResetErrorStateAndResume()
|
||||
{
|
||||
// because we're not stateful (we could be in the future), all we want to do is reenable painting.
|
||||
EnablePainting();
|
||||
}
|
||||
|
||||
@@ -76,6 +76,9 @@ namespace Microsoft::Console::Render
|
||||
|
||||
void AddRenderEngine(_In_ IRenderEngine* const pEngine) override;
|
||||
|
||||
void SetRendererEnteredErrorStateCallback(std::function<void()> pfn);
|
||||
void ResetErrorStateAndResume();
|
||||
|
||||
private:
|
||||
std::deque<IRenderEngine*> _rgpEngines;
|
||||
|
||||
@@ -127,6 +130,8 @@ namespace Microsoft::Console::Render
|
||||
// These are only actually effective/on in Debug builds when the flag is set using an attached debugger.
|
||||
bool _fDebug = false;
|
||||
|
||||
std::function<void()> _pfnRendererEnteredErrorState;
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class ConptyOutputTests;
|
||||
#endif
|
||||
|
||||
@@ -26,6 +26,7 @@ RenderThread::~RenderThread()
|
||||
if (_hThread)
|
||||
{
|
||||
_fKeepRunning = false; // stop loop after final run
|
||||
EnablePainting(); // if we want to get the last frame out, we need to make sure it's enabled
|
||||
SignalObjectAndWait(_hEvent, _hThread, INFINITE, FALSE); // signal final paint and wait for thread to finish.
|
||||
|
||||
CloseHandle(_hThread);
|
||||
@@ -231,6 +232,11 @@ void RenderThread::EnablePainting()
|
||||
SetEvent(_hPaintEnabledEvent);
|
||||
}
|
||||
|
||||
void RenderThread::DisablePainting()
|
||||
{
|
||||
ResetEvent(_hPaintEnabledEvent);
|
||||
}
|
||||
|
||||
void RenderThread::WaitForPaintCompletionAndDisable(const DWORD dwTimeoutMs)
|
||||
{
|
||||
// When rendering takes place via DirectX, and a console application
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace Microsoft::Console::Render
|
||||
void NotifyPaint() override;
|
||||
|
||||
void EnablePainting() override;
|
||||
void DisablePainting() override;
|
||||
void WaitForPaintCompletionAndDisable(const DWORD dwTimeoutMs) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -273,7 +273,12 @@ using namespace Microsoft::Console::Render;
|
||||
rect.right = std::accumulate(advancesSpan.cbegin(), advancesSpan.cend(), rect.right);
|
||||
|
||||
// Clip all drawing in this glyph run to where we expect.
|
||||
d2dContext->PushAxisAlignedClip(rect, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
|
||||
// We need the AntialiasMode here to be Aliased to ensure
|
||||
// that background boxes line up with each other and don't leave behind
|
||||
// stray colors.
|
||||
// See GH#3626 for more details.
|
||||
d2dContext->PushAxisAlignedClip(rect, D2D1_ANTIALIAS_MODE_ALIASED);
|
||||
|
||||
// Ensure we pop it on the way out
|
||||
auto popclip = wil::scope_exit([&d2dContext]() noexcept {
|
||||
d2dContext->PopAxisAlignedClip();
|
||||
|
||||
@@ -533,6 +533,11 @@ void DxEngine::_ComputePixelShaderSettings() noexcept
|
||||
&props,
|
||||
&_d2dRenderTarget));
|
||||
|
||||
// We need the AntialiasMode for non-text object to be Aliased to ensure
|
||||
// that background boxes line up with each other and don't leave behind
|
||||
// stray colors.
|
||||
// See GH#3626 for more details.
|
||||
_d2dRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
|
||||
_d2dRenderTarget->SetTextAntialiasMode(_antialiasingMode);
|
||||
|
||||
RETURN_IF_FAILED(_d2dRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::DarkRed),
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace Microsoft::Console::Render
|
||||
|
||||
virtual void NotifyPaint() = 0;
|
||||
virtual void EnablePainting() = 0;
|
||||
virtual void DisablePainting() = 0;
|
||||
virtual void WaitForPaintCompletionAndDisable(const DWORD dwTimeoutMs) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -17,6 +17,8 @@ UiaEngine::UiaEngine(IUiaEventDispatcher* dispatcher) :
|
||||
_dispatcher{ THROW_HR_IF_NULL(E_INVALIDARG, dispatcher) },
|
||||
_isPainting{ false },
|
||||
_selectionChanged{ false },
|
||||
_textBufferChanged{ false },
|
||||
_cursorChanged{ false },
|
||||
_isEnabled{ true },
|
||||
_prevSelection{},
|
||||
RenderEngineBase()
|
||||
@@ -56,7 +58,8 @@ UiaEngine::UiaEngine(IUiaEventDispatcher* dispatcher) :
|
||||
// - S_OK, else an appropriate HRESULT for failing to allocate or write.
|
||||
[[nodiscard]] HRESULT UiaEngine::Invalidate(const SMALL_RECT* const /*psrRegion*/) noexcept
|
||||
{
|
||||
return S_FALSE;
|
||||
_textBufferChanged = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -65,11 +68,21 @@ UiaEngine::UiaEngine(IUiaEventDispatcher* dispatcher) :
|
||||
// Arguments:
|
||||
// - pcoordCursor - the new position of the cursor
|
||||
// Return Value:
|
||||
// - S_FALSE
|
||||
[[nodiscard]] HRESULT UiaEngine::InvalidateCursor(const COORD* const /*pcoordCursor*/) noexcept
|
||||
// - S_OK
|
||||
[[nodiscard]] HRESULT UiaEngine::InvalidateCursor(const COORD* const pcoordCursor) noexcept
|
||||
try
|
||||
{
|
||||
return S_FALSE;
|
||||
RETURN_HR_IF_NULL(E_INVALIDARG, pcoordCursor);
|
||||
|
||||
// check if cursor moved
|
||||
if (*pcoordCursor != _prevCursorPos)
|
||||
{
|
||||
_prevCursorPos = *pcoordCursor;
|
||||
_cursorChanged = true;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
// Routine Description:
|
||||
// - Invalidates a rectangle describing a pixel area on the display
|
||||
@@ -150,7 +163,8 @@ UiaEngine::UiaEngine(IUiaEventDispatcher* dispatcher) :
|
||||
// - S_OK, else an appropriate HRESULT for failing to allocate or write.
|
||||
[[nodiscard]] HRESULT UiaEngine::InvalidateAll() noexcept
|
||||
{
|
||||
return S_FALSE;
|
||||
_textBufferChanged = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -192,10 +206,10 @@ UiaEngine::UiaEngine(IUiaEventDispatcher* dispatcher) :
|
||||
RETURN_HR_IF(S_FALSE, !_isEnabled);
|
||||
|
||||
// add more events here
|
||||
// bool somethingToDo = _selectionChanged;
|
||||
const bool somethingToDo = _selectionChanged || _textBufferChanged || _cursorChanged;
|
||||
|
||||
// If there's nothing to do, quick return
|
||||
RETURN_HR_IF(S_FALSE, !_selectionChanged);
|
||||
RETURN_HR_IF(S_FALSE, !somethingToDo);
|
||||
|
||||
_isPainting = true;
|
||||
return S_OK;
|
||||
@@ -221,9 +235,26 @@ UiaEngine::UiaEngine(IUiaEventDispatcher* dispatcher) :
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
if (_textBufferChanged)
|
||||
{
|
||||
try
|
||||
{
|
||||
_dispatcher->SignalTextChanged();
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
if (_cursorChanged)
|
||||
{
|
||||
try
|
||||
{
|
||||
_dispatcher->SignalCursorChanged();
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
|
||||
_selectionChanged = false;
|
||||
_prevSelection.clear();
|
||||
_textBufferChanged = false;
|
||||
_cursorChanged = false;
|
||||
_isPainting = false;
|
||||
|
||||
return S_OK;
|
||||
|
||||
@@ -82,9 +82,12 @@ namespace Microsoft::Console::Render
|
||||
bool _isEnabled;
|
||||
bool _isPainting;
|
||||
bool _selectionChanged;
|
||||
bool _textBufferChanged;
|
||||
bool _cursorChanged;
|
||||
|
||||
Microsoft::Console::Types::IUiaEventDispatcher* _dispatcher;
|
||||
|
||||
std::vector<SMALL_RECT> _prevSelection;
|
||||
til::point _prevCursorPos;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -529,7 +529,7 @@ using namespace Microsoft::Console::Types;
|
||||
// before we need to print new text.
|
||||
_deferredCursorPos = { _lastText.X + sNumSpaces, _lastText.Y };
|
||||
|
||||
if (_deferredCursorPos.X < _lastViewport.RightInclusive())
|
||||
if (_deferredCursorPos.X <= _lastViewport.RightInclusive())
|
||||
{
|
||||
RETURN_IF_FAILED(_EraseCharacter(sNumSpaces));
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ public:
|
||||
TEST_METHOD(TerminalInputModifierKeyTests);
|
||||
TEST_METHOD(TerminalInputNullKeyTests);
|
||||
TEST_METHOD(DifferentModifiersTest);
|
||||
TEST_METHOD(CtrlNumTest);
|
||||
|
||||
wchar_t GetModifierChar(const bool fShift, const bool fAlt, const bool fCtrl)
|
||||
{
|
||||
@@ -511,6 +512,13 @@ void InputTest::TerminalInputModifierKeyTests()
|
||||
s_pwsInputBuffer[1] = wchShifted;
|
||||
fExpectedKeyHandled = true;
|
||||
}
|
||||
else if (ControlPressed(uiKeystate) && (vkey >= '1' && vkey <= '9'))
|
||||
{
|
||||
// The C-# keys get translated into very specific control
|
||||
// characters that don't play nicely with this test. These keys
|
||||
// are tested in the CtrlNumTest Test instead.
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
fExpectedKeyHandled = false;
|
||||
@@ -684,4 +692,79 @@ void InputTest::DifferentModifiersTest()
|
||||
TestKey(pInput, uiKeystate, vkey, L'/');
|
||||
uiKeystate = RIGHT_ALT_PRESSED;
|
||||
TestKey(pInput, uiKeystate, vkey, L'/');
|
||||
|
||||
// See https://github.com/microsoft/terminal/pull/4947#issuecomment-600382856
|
||||
// C-? -> DEL -> 0x7f
|
||||
Log::Comment(NoThrowString().Format(L"Checking C-?"));
|
||||
// Use SHIFT_PRESSED to force us into differentiating between '/' and '?'
|
||||
vkey = LOBYTE(VkKeyScan(L'?'));
|
||||
s_pwszInputExpected = L"\x7f";
|
||||
TestKey(pInput, SHIFT_PRESSED | LEFT_CTRL_PRESSED, vkey, L'?');
|
||||
TestKey(pInput, SHIFT_PRESSED | RIGHT_CTRL_PRESSED, vkey, L'?');
|
||||
|
||||
// C-M-/ -> 0x1b0x1f
|
||||
Log::Comment(NoThrowString().Format(L"Checking C-M-/"));
|
||||
uiKeystate = LEFT_CTRL_PRESSED | LEFT_ALT_PRESSED;
|
||||
vkey = LOBYTE(VkKeyScan(L'/'));
|
||||
s_pwszInputExpected = L"\x1b\x1f";
|
||||
TestKey(pInput, LEFT_CTRL_PRESSED | LEFT_ALT_PRESSED, vkey, L'/');
|
||||
TestKey(pInput, RIGHT_CTRL_PRESSED | LEFT_ALT_PRESSED, vkey, L'/');
|
||||
// LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED is skipped because that's AltGr
|
||||
TestKey(pInput, RIGHT_CTRL_PRESSED | RIGHT_ALT_PRESSED, vkey, L'/');
|
||||
|
||||
// C-M-? -> 0x1b0x7f
|
||||
Log::Comment(NoThrowString().Format(L"Checking C-M-?"));
|
||||
uiKeystate = LEFT_CTRL_PRESSED | LEFT_ALT_PRESSED;
|
||||
vkey = LOBYTE(VkKeyScan(L'?'));
|
||||
s_pwszInputExpected = L"\x1b\x7f";
|
||||
TestKey(pInput, SHIFT_PRESSED | LEFT_CTRL_PRESSED | LEFT_ALT_PRESSED, vkey, L'?');
|
||||
TestKey(pInput, SHIFT_PRESSED | RIGHT_CTRL_PRESSED | LEFT_ALT_PRESSED, vkey, L'?');
|
||||
// LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED is skipped because that's AltGr
|
||||
TestKey(pInput, SHIFT_PRESSED | RIGHT_CTRL_PRESSED | RIGHT_ALT_PRESSED, vkey, L'?');
|
||||
}
|
||||
|
||||
void InputTest::CtrlNumTest()
|
||||
{
|
||||
Log::Comment(L"Starting test...");
|
||||
|
||||
const TerminalInput* const pInput = new TerminalInput(s_TerminalInputTestCallback);
|
||||
|
||||
Log::Comment(L"Sending the various Ctrl+Num keys.");
|
||||
|
||||
unsigned int uiKeystate = LEFT_CTRL_PRESSED;
|
||||
BYTE vkey = static_cast<WORD>('1');
|
||||
s_pwszInputExpected = L"1";
|
||||
TestKey(pInput, uiKeystate, vkey);
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Skipping Ctrl+2, since that's supposed to send NUL, and doesn't play "
|
||||
L"nicely with this test. Ctrl+2 is covered by other tests in this class."));
|
||||
|
||||
vkey = static_cast<WORD>('3');
|
||||
s_pwszInputExpected = L"\x1b";
|
||||
TestKey(pInput, uiKeystate, vkey);
|
||||
|
||||
vkey = static_cast<WORD>('4');
|
||||
s_pwszInputExpected = L"\x1c";
|
||||
TestKey(pInput, uiKeystate, vkey);
|
||||
|
||||
vkey = static_cast<WORD>('5');
|
||||
s_pwszInputExpected = L"\x1d";
|
||||
TestKey(pInput, uiKeystate, vkey);
|
||||
|
||||
vkey = static_cast<WORD>('6');
|
||||
s_pwszInputExpected = L"\x1e";
|
||||
TestKey(pInput, uiKeystate, vkey);
|
||||
|
||||
vkey = static_cast<WORD>('7');
|
||||
s_pwszInputExpected = L"\x1f";
|
||||
TestKey(pInput, uiKeystate, vkey);
|
||||
|
||||
vkey = static_cast<WORD>('8');
|
||||
s_pwszInputExpected = L"\x7f";
|
||||
TestKey(pInput, uiKeystate, vkey);
|
||||
|
||||
vkey = static_cast<WORD>('9');
|
||||
s_pwszInputExpected = L"9";
|
||||
TestKey(pInput, uiKeystate, vkey);
|
||||
}
|
||||
|
||||
@@ -185,19 +185,40 @@ static constexpr std::array<TermKeyMap, 22> s_modifierKeyMapping{
|
||||
// These sequences are not later updated to encode the modifier state in the
|
||||
// sequence itself, they are just weird exceptional cases to the general
|
||||
// rules above.
|
||||
static constexpr std::array<TermKeyMap, 6> s_simpleModifiedKeyMapping{
|
||||
static constexpr std::array<TermKeyMap, 14> s_simpleModifiedKeyMapping{
|
||||
TermKeyMap{ VK_BACK, CTRL_PRESSED, L"\x8" },
|
||||
TermKeyMap{ VK_BACK, ALT_PRESSED, L"\x1b\x7f" },
|
||||
TermKeyMap{ VK_BACK, CTRL_PRESSED | ALT_PRESSED, L"\x1b\x8" },
|
||||
TermKeyMap{ VK_TAB, CTRL_PRESSED, L"\t" },
|
||||
TermKeyMap{ VK_TAB, SHIFT_PRESSED, L"\x1b[Z" },
|
||||
TermKeyMap{ VK_DIVIDE, CTRL_PRESSED, L"\x1F" },
|
||||
|
||||
// GH#3507 - We should also be encoding Ctrl+# according to the following table:
|
||||
// https://vt100.net/docs/vt220-rm/table3-5.html
|
||||
// * 1 and 9 do not send any special characters, but they _should_ send
|
||||
// through the character unmodified.
|
||||
// * 0 doesn't seem to send even an unmodified '0' through.
|
||||
// * Ctrl+2 is already special-cased below in `HandleKey`, so it's not
|
||||
// included here.
|
||||
TermKeyMap{ static_cast<WORD>('1'), CTRL_PRESSED, L"1" },
|
||||
// TermKeyMap{ static_cast<WORD>('2'), CTRL_PRESSED, L"\x00" },
|
||||
TermKeyMap{ static_cast<WORD>('3'), CTRL_PRESSED, L"\x1B" },
|
||||
TermKeyMap{ static_cast<WORD>('4'), CTRL_PRESSED, L"\x1C" },
|
||||
TermKeyMap{ static_cast<WORD>('5'), CTRL_PRESSED, L"\x1D" },
|
||||
TermKeyMap{ static_cast<WORD>('6'), CTRL_PRESSED, L"\x1E" },
|
||||
TermKeyMap{ static_cast<WORD>('7'), CTRL_PRESSED, L"\x1F" },
|
||||
TermKeyMap{ static_cast<WORD>('8'), CTRL_PRESSED, L"\x7F" },
|
||||
TermKeyMap{ static_cast<WORD>('9'), CTRL_PRESSED, L"9" },
|
||||
|
||||
// These two are not implemented here, because they are system keys.
|
||||
// TermKeyMap{ VK_TAB, ALT_PRESSED, L""}, This is the Windows system shortcut for switching windows.
|
||||
// TermKeyMap{ VK_ESCAPE, ALT_PRESSED, L""}, This is another Windows system shortcut for switching windows.
|
||||
};
|
||||
|
||||
const wchar_t* const CTRL_SLASH_SEQUENCE = L"\x1f";
|
||||
const wchar_t* const CTRL_QUESTIONMARK_SEQUENCE = L"\x7F";
|
||||
const wchar_t* const CTRL_ALT_SLASH_SEQUENCE = L"\x1b\x1f";
|
||||
const wchar_t* const CTRL_ALT_QUESTIONMARK_SEQUENCE = L"\x1b\x7F";
|
||||
|
||||
void TerminalInput::ChangeKeypadMode(const bool applicationMode) noexcept
|
||||
{
|
||||
@@ -323,13 +344,73 @@ static bool _searchWithModifier(const KeyEvent& keyEvent, InputSender sender)
|
||||
}
|
||||
else
|
||||
{
|
||||
// One last check: C-/ is supposed to be C-_
|
||||
// But '/' is not the same VKEY on all keyboards. So we have to
|
||||
// figure out the vkey at runtime.
|
||||
const BYTE slashVkey = LOBYTE(VkKeyScan(L'/'));
|
||||
if (keyEvent.GetVirtualKeyCode() == slashVkey && keyEvent.IsCtrlPressed())
|
||||
// One last check:
|
||||
// * C-/ is supposed to be ^_ (the C0 character US)
|
||||
// * C-? is supposed to be DEL
|
||||
// * C-M-/ is supposed to be ^[^_
|
||||
// * C-M-? is supposed to be ^[^?
|
||||
//
|
||||
// But this whole scenario is tricky. '/' is not the same VKEY on
|
||||
// all keyboards. On USASCII keyboards, '/' and '?' share the _same_
|
||||
// key. So we have to figure out the vkey at runtime, and we have to
|
||||
// determine if the key that was pressed was '?' with some
|
||||
// modifiers, or '/' with some modifiers.
|
||||
//
|
||||
// These translations are not in s_simpleModifiedKeyMapping, because
|
||||
// the aformentioned fact that they aren't the same VKEY on all
|
||||
// keyboards.
|
||||
//
|
||||
// See GH#3079 for details.
|
||||
// Also see https://github.com/microsoft/terminal/pull/4947#issuecomment-600382856
|
||||
|
||||
// VkKeyScan will give us both the Vkey of the key needed for this
|
||||
// character, and the modifiers the user might need to press to get
|
||||
// this character.
|
||||
const auto slashKeyScan = VkKeyScan(L'/'); // On USASCII: 0x00bf
|
||||
const auto questionMarkKeyScan = VkKeyScan(L'?'); //On USASCII: 0x01bf
|
||||
|
||||
const auto slashVkey = LOBYTE(slashKeyScan);
|
||||
const auto questionMarkVkey = LOBYTE(questionMarkKeyScan);
|
||||
|
||||
const auto ctrl = keyEvent.IsCtrlPressed();
|
||||
const auto alt = keyEvent.IsAltPressed();
|
||||
const bool shift = keyEvent.IsShiftPressed();
|
||||
|
||||
// From the KeyEvent we're translating, synthesize the equivalent VkKeyScan result
|
||||
const auto vkey = keyEvent.GetVirtualKeyCode();
|
||||
const short keyScanFromEvent = vkey |
|
||||
(shift ? 0x100 : 0) |
|
||||
(ctrl ? 0x200 : 0) |
|
||||
(alt ? 0x400 : 0);
|
||||
|
||||
// Make sure the VKEY is an _exact_ match, and that the modifier
|
||||
// bits also match. This handles the hypothetical case we get a
|
||||
// keyscan back that's ctrl+alt+some_random_VK, and some_random_VK
|
||||
// has bits that are a superset of the bits set for question mark.
|
||||
const bool wasQuestionMark = vkey == questionMarkVkey && WI_AreAllFlagsSet(keyScanFromEvent, questionMarkKeyScan);
|
||||
const bool wasSlash = vkey == slashVkey && WI_AreAllFlagsSet(keyScanFromEvent, slashKeyScan);
|
||||
|
||||
// If the key pressed was exactly the ? key, then try to send the
|
||||
// appropriate sequence for a modified '?'. Otherwise, check if this
|
||||
// was a modified '/' keypress. These mappings don't need to be
|
||||
// changed at all.
|
||||
if ((ctrl && alt) && wasQuestionMark)
|
||||
{
|
||||
sender(CTRL_ALT_QUESTIONMARK_SEQUENCE);
|
||||
success = true;
|
||||
}
|
||||
else if (ctrl && wasQuestionMark)
|
||||
{
|
||||
sender(CTRL_QUESTIONMARK_SEQUENCE);
|
||||
success = true;
|
||||
}
|
||||
else if ((ctrl && alt) && wasSlash)
|
||||
{
|
||||
sender(CTRL_ALT_SLASH_SEQUENCE);
|
||||
success = true;
|
||||
}
|
||||
else if (ctrl && wasSlash)
|
||||
{
|
||||
// This mapping doesn't need to be changed at all.
|
||||
sender(CTRL_SLASH_SEQUENCE);
|
||||
success = true;
|
||||
}
|
||||
|
||||
@@ -319,29 +319,47 @@ CodepointWidthDetector::CodepointWidthDetector() noexcept :
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - returns the width type of codepoint by searching the map generated from the unicode spec
|
||||
// - returns the width type of codepoint as fast as we can by using quick lookup table and fallback cache.
|
||||
// Arguments:
|
||||
// - glyph - the utf16 encoded codepoint to search for
|
||||
// Return Value:
|
||||
// - the width type of the codepoint
|
||||
CodepointWidth CodepointWidthDetector::GetWidth(const std::wstring_view glyph) const
|
||||
{
|
||||
if (glyph.empty())
|
||||
THROW_HR_IF(E_INVALIDARG, glyph.empty());
|
||||
if (glyph.size() == 1)
|
||||
{
|
||||
return CodepointWidth::Invalid;
|
||||
// We first attempt to look at our custom quick lookup table of char width preferences.
|
||||
const auto width = GetQuickCharWidth(glyph.front());
|
||||
|
||||
// If it's invalid, the quick width had no opinion, so go to the lookup table.
|
||||
if (width == CodepointWidth::Invalid)
|
||||
{
|
||||
return _lookupGlyphWidthWithCache(glyph);
|
||||
}
|
||||
// If it's ambiguous, the quick width wanted us to ask the font directly, try that if we can.
|
||||
// If not, go to the lookup table.
|
||||
else if (width == CodepointWidth::Ambiguous)
|
||||
{
|
||||
if (_pfnFallbackMethod)
|
||||
{
|
||||
return _checkFallbackViaCache(glyph) ? CodepointWidth::Wide : CodepointWidth::Ambiguous;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _lookupGlyphWidthWithCache(glyph);
|
||||
}
|
||||
}
|
||||
// Otherwise, return Width as it is.
|
||||
else
|
||||
{
|
||||
return width;
|
||||
}
|
||||
}
|
||||
|
||||
const auto codepoint = _extractCodepoint(glyph);
|
||||
const auto it = std::lower_bound(s_wideAndAmbiguousTable.begin(), s_wideAndAmbiguousTable.end(), codepoint);
|
||||
|
||||
// For characters that are not _in_ the table, lower_bound will return the nearest item that is.
|
||||
// We must check its bounds to make sure that our hit was a true hit.
|
||||
if (it != s_wideAndAmbiguousTable.end() && codepoint >= it->lowerBound && codepoint <= it->upperBound)
|
||||
else
|
||||
{
|
||||
return it->width;
|
||||
return _lookupGlyphWidthWithCache(glyph);
|
||||
}
|
||||
|
||||
return CodepointWidth::Narrow;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -369,74 +387,71 @@ bool CodepointWidthDetector::IsWide(const wchar_t wch) const noexcept
|
||||
// - true if codepoint is wide
|
||||
bool CodepointWidthDetector::IsWide(const std::wstring_view glyph) const
|
||||
{
|
||||
THROW_HR_IF(E_INVALIDARG, glyph.empty());
|
||||
if (glyph.size() == 1)
|
||||
{
|
||||
// We first attempt to look at our custom quick lookup table of char width preferences.
|
||||
const auto width = GetQuickCharWidth(glyph.front());
|
||||
|
||||
// If it's invalid, the quick width had no opinion, so go to the lookup table.
|
||||
if (width == CodepointWidth::Invalid)
|
||||
{
|
||||
return _lookupIsWide(glyph);
|
||||
}
|
||||
// If it's ambiguous, the quick width wanted us to ask the font directly, try that if we can.
|
||||
// If not, go to the lookup table.
|
||||
else if (width == CodepointWidth::Ambiguous)
|
||||
{
|
||||
if (_pfnFallbackMethod)
|
||||
{
|
||||
return _checkFallbackViaCache(glyph);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _lookupIsWide(glyph);
|
||||
}
|
||||
}
|
||||
// Otherwise, return Wide as True and Narrow as False.
|
||||
else
|
||||
{
|
||||
return width == CodepointWidth::Wide;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return _lookupIsWide(glyph);
|
||||
}
|
||||
return GetWidth(glyph) == CodepointWidth::Wide;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - checks if codepoint is wide using fallback methods.
|
||||
// - returns the width type of codepoint by searching the map generated from the unicode spec
|
||||
// Arguments:
|
||||
// - glyph - the utf16 encoded codepoint to search for
|
||||
// Return Value:
|
||||
// - the width type of the codepoint
|
||||
CodepointWidth CodepointWidthDetector::_lookupGlyphWidth(const std::wstring_view glyph) const
|
||||
{
|
||||
if (glyph.empty())
|
||||
{
|
||||
return CodepointWidth::Invalid;
|
||||
}
|
||||
|
||||
const auto codepoint = _extractCodepoint(glyph);
|
||||
const auto it = std::lower_bound(s_wideAndAmbiguousTable.begin(), s_wideAndAmbiguousTable.end(), codepoint);
|
||||
|
||||
// For characters that are not _in_ the table, lower_bound will return the nearest item that is.
|
||||
// We must check its bounds to make sure that our hit was a true hit.
|
||||
if (it != s_wideAndAmbiguousTable.end() && codepoint >= it->lowerBound && codepoint <= it->upperBound)
|
||||
{
|
||||
return it->width;
|
||||
}
|
||||
|
||||
return CodepointWidth::Narrow;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - returns the width type of codepoint using fallback methods.
|
||||
// Arguments:
|
||||
// - glyph - the utf16 encoded codepoint to check width of
|
||||
// Return Value:
|
||||
// - true if codepoint is wide or if it can't be confirmed to be narrow
|
||||
bool CodepointWidthDetector::_lookupIsWide(const std::wstring_view glyph) const noexcept
|
||||
// - the width type of the codepoint
|
||||
CodepointWidth CodepointWidthDetector::_lookupGlyphWidthWithCache(const std::wstring_view glyph) const noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
// Use our generated table to try to lookup the width based on the Unicode standard.
|
||||
const CodepointWidth width = GetWidth(glyph);
|
||||
const CodepointWidth width = _lookupGlyphWidth(glyph);
|
||||
|
||||
// If it's ambiguous, then ask the font if we can.
|
||||
if (width == CodepointWidth::Ambiguous)
|
||||
{
|
||||
if (_pfnFallbackMethod)
|
||||
{
|
||||
return _checkFallbackViaCache(glyph);
|
||||
return _checkFallbackViaCache(glyph) ? CodepointWidth::Wide : CodepointWidth::Ambiguous;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CodepointWidth::Ambiguous;
|
||||
}
|
||||
}
|
||||
// If it's not ambiguous, it should say wide or narrow. Turn that into True = Wide or False = Narrow.
|
||||
// If it's not ambiguous, it should say wide or narrow.
|
||||
else
|
||||
{
|
||||
return width == CodepointWidth::Wide;
|
||||
return width;
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
// If we got this far, we couldn't figure it out.
|
||||
// It's better to be too wide than too narrow.
|
||||
return true;
|
||||
return CodepointWidth::Wide;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -256,6 +256,8 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetSelection(_Outptr_result_maybenull_
|
||||
return hr;
|
||||
}
|
||||
|
||||
UiaTracing::TextProvider::GetSelection(*this, *range.Get());
|
||||
|
||||
LONG currentIndex = 0;
|
||||
hr = SafeArrayPutElement(*ppRetVal, ¤tIndex, range.Detach());
|
||||
if (FAILED(hr))
|
||||
@@ -265,7 +267,6 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetSelection(_Outptr_result_maybenull_
|
||||
return hr;
|
||||
}
|
||||
|
||||
UiaTracing::TextProvider::GetSelection(*this, *range.Get());
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -23,6 +23,7 @@ try
|
||||
_pData = pData;
|
||||
_start = pData->GetViewport().Origin();
|
||||
_end = pData->GetViewport().Origin();
|
||||
_blockRange = false;
|
||||
_wordDelimiters = wordDelimiters;
|
||||
|
||||
_id = id;
|
||||
@@ -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
|
||||
{
|
||||
@@ -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;
|
||||
}
|
||||
@@ -257,8 +263,8 @@ IFACEMETHODIMP UiaTextRangeBase::ExpandToEnclosingUnit(_In_ TextUnit unit) noexc
|
||||
|
||||
if (unit == TextUnit_Character)
|
||||
{
|
||||
_end = _start;
|
||||
bufferSize.IncrementInBounds(_end, true);
|
||||
_start = buffer.GetGlyphStart(_start);
|
||||
_end = buffer.GetGlyphEnd(_start);
|
||||
}
|
||||
else if (unit <= TextUnit_Word)
|
||||
{
|
||||
@@ -429,25 +435,11 @@ IFACEMETHODIMP UiaTextRangeBase::GetBoundingRectangles(_Outptr_result_maybenull_
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto row = startAnchor.Y; row <= endAnchor.Y; ++row)
|
||||
const auto textRects = _pData->GetTextBuffer().GetTextRects(startAnchor, endAnchor, _blockRange);
|
||||
|
||||
for (const auto& rect : textRects)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
_getBoundingRect(startCoord, endCoord, coords);
|
||||
_getBoundingRect(rect, coords);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,10 +526,10 @@ try
|
||||
const auto bufferSize = buffer.GetSize();
|
||||
|
||||
// convert _end to be inclusive
|
||||
auto inclusiveEnd{ _end };
|
||||
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);
|
||||
@@ -695,9 +687,9 @@ try
|
||||
}
|
||||
else
|
||||
{
|
||||
auto temp = _end;
|
||||
_pData->GetTextBuffer().GetSize().DecrementInBounds(temp);
|
||||
_pData->SelectNewRegion(_start, temp);
|
||||
auto inclusiveEnd = _end;
|
||||
_pData->GetTextBuffer().GetSize().DecrementInBounds(inclusiveEnd);
|
||||
_pData->SelectNewRegion(_start, inclusiveEnd);
|
||||
}
|
||||
|
||||
UiaTracing::TextRange::Select(*this);
|
||||
@@ -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);
|
||||
topLeft.x = base::ClampMul(textRect.left(), currentFontSize.width());
|
||||
topLeft.y = base::ClampMul(textRect.top(), currentFontSize.height());
|
||||
|
||||
// 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);
|
||||
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
|
||||
@@ -918,7 +897,7 @@ void UiaTextRangeBase::_getBoundingRect(_In_ const COORD startAnchor, _In_ const
|
||||
void UiaTextRangeBase::_moveEndpointByUnitCharacter(_In_ const int moveCount,
|
||||
_In_ const TextPatternRangeEndpoint endpoint,
|
||||
_Out_ gsl::not_null<int*> const pAmountMoved,
|
||||
_In_ const bool preventBufferEnd) noexcept
|
||||
_In_ const bool preventBufferEnd)
|
||||
{
|
||||
*pAmountMoved = 0;
|
||||
|
||||
@@ -929,23 +908,23 @@ void UiaTextRangeBase::_moveEndpointByUnitCharacter(_In_ const int moveCount,
|
||||
|
||||
const bool allowBottomExclusive = !preventBufferEnd;
|
||||
const MovementDirection moveDirection = (moveCount > 0) ? MovementDirection::Forward : MovementDirection::Backward;
|
||||
const auto bufferSize = _getBufferSize();
|
||||
const auto& buffer = _pData->GetTextBuffer();
|
||||
|
||||
bool success = true;
|
||||
auto target = GetEndpoint(endpoint);
|
||||
til::point target = GetEndpoint(endpoint);
|
||||
while (std::abs(*pAmountMoved) < std::abs(moveCount) && success)
|
||||
{
|
||||
switch (moveDirection)
|
||||
{
|
||||
case MovementDirection::Forward:
|
||||
success = bufferSize.IncrementInBounds(target, allowBottomExclusive);
|
||||
success = buffer.MoveToNextGlyph(target, allowBottomExclusive);
|
||||
if (success)
|
||||
{
|
||||
(*pAmountMoved)++;
|
||||
}
|
||||
break;
|
||||
case MovementDirection::Backward:
|
||||
success = bufferSize.DecrementInBounds(target, allowBottomExclusive);
|
||||
success = buffer.MoveToPreviousGlyph(target, allowBottomExclusive);
|
||||
if (success)
|
||||
{
|
||||
(*pAmountMoved)--;
|
||||
|
||||
@@ -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;
|
||||
@@ -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.
|
||||
@@ -162,13 +164,13 @@ 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,
|
||||
_In_ const TextPatternRangeEndpoint endpoint,
|
||||
gsl::not_null<int*> const pAmountMoved,
|
||||
_In_ const bool preventBufferEnd = false) noexcept;
|
||||
_In_ const bool preventBufferEnd = false);
|
||||
|
||||
void
|
||||
_moveEndpointByUnitWord(_In_ const int moveCount,
|
||||
|
||||
@@ -88,9 +88,9 @@ inline std::wstring UiaTracing::_getValue(const TextUnit unit) noexcept
|
||||
|
||||
void UiaTracing::TextRange::Constructor(const UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::Constructor",
|
||||
@@ -101,9 +101,9 @@ void UiaTracing::TextRange::Constructor(const UiaTextRangeBase& result) noexcept
|
||||
|
||||
void UiaTracing::TextRange::Clone(const UiaTextRangeBase& utr, const UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::Clone",
|
||||
@@ -115,9 +115,9 @@ void UiaTracing::TextRange::Clone(const UiaTextRangeBase& utr, const UiaTextRang
|
||||
|
||||
void UiaTracing::TextRange::Compare(const UiaTextRangeBase& utr, const UiaTextRangeBase& other, bool result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::Compare",
|
||||
@@ -130,9 +130,9 @@ void UiaTracing::TextRange::Compare(const UiaTextRangeBase& utr, const UiaTextRa
|
||||
|
||||
void UiaTracing::TextRange::CompareEndpoints(const UiaTextRangeBase& utr, const TextPatternRangeEndpoint endpoint, const UiaTextRangeBase& other, TextPatternRangeEndpoint otherEndpoint, int result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::CompareEndpoints",
|
||||
@@ -147,9 +147,9 @@ void UiaTracing::TextRange::CompareEndpoints(const UiaTextRangeBase& utr, const
|
||||
|
||||
void UiaTracing::TextRange::ExpandToEnclosingUnit(TextUnit unit, const UiaTextRangeBase& utr) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::ExpandToEnclosingUnit",
|
||||
@@ -161,9 +161,9 @@ void UiaTracing::TextRange::ExpandToEnclosingUnit(TextUnit unit, const UiaTextRa
|
||||
|
||||
void UiaTracing::TextRange::FindAttribute(const UiaTextRangeBase& utr) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::FindAttribute (UNSUPPORTED)",
|
||||
@@ -174,9 +174,9 @@ void UiaTracing::TextRange::FindAttribute(const UiaTextRangeBase& utr) noexcept
|
||||
|
||||
void UiaTracing::TextRange::FindText(const UiaTextRangeBase& base, std::wstring text, bool searchBackward, bool ignoreCase, const UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::FindText",
|
||||
@@ -191,9 +191,9 @@ void UiaTracing::TextRange::FindText(const UiaTextRangeBase& base, std::wstring
|
||||
|
||||
void UiaTracing::TextRange::GetAttributeValue(const UiaTextRangeBase& base, TEXTATTRIBUTEID id, VARIANT result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::GetAttributeValue",
|
||||
@@ -206,9 +206,9 @@ void UiaTracing::TextRange::GetAttributeValue(const UiaTextRangeBase& base, TEXT
|
||||
|
||||
void UiaTracing::TextRange::GetBoundingRectangles(const UiaTextRangeBase& utr) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::GetBoundingRectangles",
|
||||
@@ -219,9 +219,9 @@ void UiaTracing::TextRange::GetBoundingRectangles(const UiaTextRangeBase& utr) n
|
||||
|
||||
void UiaTracing::TextRange::GetEnclosingElement(const UiaTextRangeBase& utr) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::GetEnclosingElement",
|
||||
@@ -232,9 +232,9 @@ void UiaTracing::TextRange::GetEnclosingElement(const UiaTextRangeBase& utr) noe
|
||||
|
||||
void UiaTracing::TextRange::GetText(const UiaTextRangeBase& utr, int maxLength, std::wstring result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::GetText",
|
||||
@@ -247,9 +247,9 @@ void UiaTracing::TextRange::GetText(const UiaTextRangeBase& utr, int maxLength,
|
||||
|
||||
void UiaTracing::TextRange::Move(TextUnit unit, int count, int resultCount, const UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::Move",
|
||||
@@ -263,9 +263,9 @@ void UiaTracing::TextRange::Move(TextUnit unit, int count, int resultCount, cons
|
||||
|
||||
void UiaTracing::TextRange::MoveEndpointByUnit(TextPatternRangeEndpoint endpoint, TextUnit unit, int count, int resultCount, const UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::MoveEndpointByUnit",
|
||||
@@ -280,9 +280,9 @@ void UiaTracing::TextRange::MoveEndpointByUnit(TextPatternRangeEndpoint endpoint
|
||||
|
||||
void UiaTracing::TextRange::MoveEndpointByRange(TextPatternRangeEndpoint endpoint, const UiaTextRangeBase& other, TextPatternRangeEndpoint otherEndpoint, const UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::MoveEndpointByRange",
|
||||
@@ -296,9 +296,9 @@ void UiaTracing::TextRange::MoveEndpointByRange(TextPatternRangeEndpoint endpoin
|
||||
|
||||
void UiaTracing::TextRange::Select(const UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::Select",
|
||||
@@ -309,9 +309,9 @@ void UiaTracing::TextRange::Select(const UiaTextRangeBase& result) noexcept
|
||||
|
||||
void UiaTracing::TextRange::AddToSelection(const UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::AddToSelection (UNSUPPORTED)",
|
||||
@@ -322,9 +322,9 @@ void UiaTracing::TextRange::AddToSelection(const UiaTextRangeBase& result) noexc
|
||||
|
||||
void UiaTracing::TextRange::RemoveFromSelection(const UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::RemoveFromSelection (UNSUPPORTED)",
|
||||
@@ -335,9 +335,9 @@ void UiaTracing::TextRange::RemoveFromSelection(const UiaTextRangeBase& result)
|
||||
|
||||
void UiaTracing::TextRange::ScrollIntoView(bool alignToTop, const UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::ScrollIntoView",
|
||||
@@ -349,9 +349,9 @@ void UiaTracing::TextRange::ScrollIntoView(bool alignToTop, const UiaTextRangeBa
|
||||
|
||||
void UiaTracing::TextRange::GetChildren(const UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::AddToSelection (UNSUPPORTED)",
|
||||
@@ -362,9 +362,9 @@ void UiaTracing::TextRange::GetChildren(const UiaTextRangeBase& result) noexcept
|
||||
|
||||
void UiaTracing::TextProvider::Constructor(const ScreenInfoUiaProviderBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"ScreenInfoUiaProvider::Constructor",
|
||||
@@ -375,6 +375,7 @@ void UiaTracing::TextProvider::Constructor(const ScreenInfoUiaProviderBase& resu
|
||||
|
||||
void UiaTracing::TextProvider::get_ProviderOptions(const ScreenInfoUiaProviderBase& siup, ProviderOptions options) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
auto getOptions = [options]() {
|
||||
@@ -387,7 +388,6 @@ void UiaTracing::TextProvider::get_ProviderOptions(const ScreenInfoUiaProviderBa
|
||||
}
|
||||
};
|
||||
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"ScreenInfoUiaProvider::get_ProviderOptions",
|
||||
@@ -399,6 +399,7 @@ void UiaTracing::TextProvider::get_ProviderOptions(const ScreenInfoUiaProviderBa
|
||||
|
||||
void UiaTracing::TextProvider::GetPatternProvider(const ScreenInfoUiaProviderBase& siup, PATTERNID patternId) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
auto getPattern = [patternId]() {
|
||||
@@ -411,7 +412,6 @@ void UiaTracing::TextProvider::GetPatternProvider(const ScreenInfoUiaProviderBas
|
||||
}
|
||||
};
|
||||
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"ScreenInfoUiaProvider::get_ProviderOptions",
|
||||
@@ -423,6 +423,7 @@ void UiaTracing::TextProvider::GetPatternProvider(const ScreenInfoUiaProviderBas
|
||||
|
||||
void UiaTracing::TextProvider::GetPropertyValue(const ScreenInfoUiaProviderBase& siup, PROPERTYID propertyId) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
auto getProperty = [propertyId]() {
|
||||
@@ -451,7 +452,6 @@ void UiaTracing::TextProvider::GetPropertyValue(const ScreenInfoUiaProviderBase&
|
||||
}
|
||||
};
|
||||
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"ScreenInfoUiaProvider::GetPropertyValue",
|
||||
@@ -463,9 +463,9 @@ void UiaTracing::TextProvider::GetPropertyValue(const ScreenInfoUiaProviderBase&
|
||||
|
||||
void UiaTracing::TextProvider::get_HostRawElementProvider(const ScreenInfoUiaProviderBase& siup) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"ScreenInfoUiaProvider::get_HostRawElementProvider (UNSUPPORTED)",
|
||||
@@ -476,9 +476,9 @@ void UiaTracing::TextProvider::get_HostRawElementProvider(const ScreenInfoUiaPro
|
||||
|
||||
void UiaTracing::TextProvider::GetRuntimeId(const ScreenInfoUiaProviderBase& siup) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"ScreenInfoUiaProvider::GetRuntimeId",
|
||||
@@ -489,9 +489,9 @@ void UiaTracing::TextProvider::GetRuntimeId(const ScreenInfoUiaProviderBase& siu
|
||||
|
||||
void UiaTracing::TextProvider::GetEmbeddedFragmentRoots(const ScreenInfoUiaProviderBase& siup) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"ScreenInfoUiaProvider::GetEmbeddedFragmentRoots (UNSUPPORTED)",
|
||||
@@ -502,9 +502,9 @@ void UiaTracing::TextProvider::GetEmbeddedFragmentRoots(const ScreenInfoUiaProvi
|
||||
|
||||
void UiaTracing::TextProvider::SetFocus(const ScreenInfoUiaProviderBase& siup) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"ScreenInfoUiaProvider::SetFocus",
|
||||
@@ -515,9 +515,9 @@ void UiaTracing::TextProvider::SetFocus(const ScreenInfoUiaProviderBase& siup) n
|
||||
|
||||
void UiaTracing::TextProvider::GetSelection(const ScreenInfoUiaProviderBase& siup, const UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"ScreenInfoUiaProvider::GetSelection",
|
||||
@@ -529,9 +529,9 @@ void UiaTracing::TextProvider::GetSelection(const ScreenInfoUiaProviderBase& siu
|
||||
|
||||
void UiaTracing::TextProvider::GetVisibleRanges(const ScreenInfoUiaProviderBase& siup, const UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"ScreenInfoUiaProvider::GetVisibleRanges",
|
||||
@@ -543,9 +543,9 @@ void UiaTracing::TextProvider::GetVisibleRanges(const ScreenInfoUiaProviderBase&
|
||||
|
||||
void UiaTracing::TextProvider::RangeFromChild(const ScreenInfoUiaProviderBase& siup, const UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"ScreenInfoUiaProvider::GetVisibleRanges",
|
||||
@@ -557,6 +557,7 @@ void UiaTracing::TextProvider::RangeFromChild(const ScreenInfoUiaProviderBase& s
|
||||
|
||||
void UiaTracing::TextProvider::RangeFromPoint(const ScreenInfoUiaProviderBase& siup, UiaPoint point, const UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
auto getPoint = [point]() {
|
||||
@@ -565,7 +566,6 @@ void UiaTracing::TextProvider::RangeFromPoint(const ScreenInfoUiaProviderBase& s
|
||||
return stream.str();
|
||||
};
|
||||
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"ScreenInfoUiaProvider::RangeFromPoint",
|
||||
@@ -578,9 +578,9 @@ void UiaTracing::TextProvider::RangeFromPoint(const ScreenInfoUiaProviderBase& s
|
||||
|
||||
void UiaTracing::TextProvider::get_DocumentRange(const ScreenInfoUiaProviderBase& siup, const UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"ScreenInfoUiaProvider::GetVisibleRanges",
|
||||
@@ -592,6 +592,7 @@ void UiaTracing::TextProvider::get_DocumentRange(const ScreenInfoUiaProviderBase
|
||||
|
||||
void UiaTracing::TextProvider::get_SupportedTextSelection(const ScreenInfoUiaProviderBase& siup, SupportedTextSelection result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
auto getResult = [result]() {
|
||||
@@ -604,7 +605,6 @@ void UiaTracing::TextProvider::get_SupportedTextSelection(const ScreenInfoUiaPro
|
||||
}
|
||||
};
|
||||
|
||||
EnsureRegistration();
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"ScreenInfoUiaProvider::get_SupportedTextSelection",
|
||||
@@ -613,4 +613,41 @@ void UiaTracing::TextProvider::get_SupportedTextSelection(const ScreenInfoUiaPro
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
}
|
||||
|
||||
void UiaTracing::Signal::SelectionChanged() noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"Signal::SelectionChanged",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
}
|
||||
|
||||
void UiaTracing::Signal::TextChanged() noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"Signal::TextChanged",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
}
|
||||
|
||||
void UiaTracing::Signal::CursorChanged() noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"Signal::CursorChanged",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
@@ -72,6 +72,14 @@ namespace Microsoft::Console::Types
|
||||
static void get_SupportedTextSelection(const ScreenInfoUiaProviderBase& base, SupportedTextSelection result) noexcept;
|
||||
};
|
||||
|
||||
class Signal final
|
||||
{
|
||||
public:
|
||||
static void SelectionChanged() noexcept;
|
||||
static void TextChanged() noexcept;
|
||||
static void CursorChanged() noexcept;
|
||||
};
|
||||
|
||||
private:
|
||||
// Implement this as a singleton class.
|
||||
static UiaTracing& EnsureRegistration() noexcept
|
||||
|
||||
@@ -41,7 +41,8 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool _lookupIsWide(const std::wstring_view glyph) const noexcept;
|
||||
CodepointWidth _lookupGlyphWidth(const std::wstring_view glyph) const;
|
||||
CodepointWidth _lookupGlyphWidthWithCache(const std::wstring_view glyph) const noexcept;
|
||||
bool _checkFallbackViaCache(const std::wstring_view glyph) const;
|
||||
static unsigned int _extractCodepoint(const std::wstring_view glyph) noexcept;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user