Skip to content

Conversation

lhecker
Copy link
Member

@lhecker lhecker commented Sep 12, 2025

Goal: Remove CursorBlinker.
Problem: Spooky action at a distance via Cursor::HasMoved.
Solution: Moved all the a11y event raising into _stream.cpp and pray for the best.

Goal: Prevent node.js from tanking conhost performance via MSAA (WHY).
Problem: ServiceLocator.
Solution: Unserviced the locator. Debounced event raising. Performance increased by >10x.
Problem 2: Lots of files changed.

This PR is a prerequisite for #19330

Validation Steps Performed

Ran NVDA with and without UIA enabled and with different delays. ✅

This comment has been minimized.

Copy link
Member

@DHowett DHowett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

55/70

@@ -253,12 +253,13 @@ static FillConsoleResult FillConsoleImpl(SCREEN_INFORMATION& screenInfo, FillCon
ImageSlice::EraseCells(screenInfo.GetTextBuffer(), startingCoordinate, result.cellsModified);
}

if (screenBuffer.HasAccessibilityEventing())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we did this check to explicitly avoid doing any extra work in the ConPTY case

Copy link
Member Author

@lhecker lhecker Sep 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It still skips the work, but inside the class. I think that putting the work for checks like this into the caller's responsibility is bad. It's repetitive, you can accidentally forget it and doesn't even meaningfully improve performance over doing the check inside the callsite.

IMO good performance improvements address "big picture" issues. This then frees us up to do "cleaner" code like this which is technically wasteful but not practically so.

const auto& bufferBefore = gci.GetActiveOutputBuffer();
const auto cursorBefore = bufferBefore.GetTextBuffer().GetCursor().GetPosition();

auto raise = wil::scope_exit([&bufferBefore, cursorBefore] {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hit this with AVRF please. I'm worried about capturing this reference by reference.

can we just capture the pointer itself, since all we do is compare it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK lambda captures behave like auto so bufferBefore would capture a copy, not a reference. But I agree that capturing a pointer would be easier to read and understand.

notifier->NotifyConsoleUpdateScrollEvent(0, -1);
}
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
an.ScrollBuffer(-1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this used to be skipped in conpty - note to self to verify it still is

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(a11y eventing is disabled in ConPTY because the Window class doesn't get instantiated.)

// Flags is expected to be 2, 1, or 0. 2 in selecting (whether or not visible), 1 if just visible, 0 if invisible/noselect.
if (WI_IsFlagSet(gci.Flags, CONSOLE_SELECTING))
{
flags = IAccessibilityNotifier::ConsoleCaretEventFlags::CaretSelection;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 watch where Selection/Invisible/Visible go

@@ -47,6 +47,7 @@
<ClCompile Include="..\writeData.cpp" />
<ClCompile Include="..\_output.cpp" />
<ClCompile Include="..\_stream.cpp" />
<ClCompile Include="..\AccessibilityNotifier.cpp" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add to sources.inc

Comment on lines +17 to +25
void RemoteConsoleControl::Control(ControlType, PVOID, DWORD) noexcept
{
WI_ASSERT_FAIL();
}

void RemoteConsoleControl::NotifyWinEvent(DWORD, HWND, LONG, LONG) noexcept
{
WI_ASSERT_FAIL();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need to test this out as a handoff recipient to verify these asserts never hit

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do. Theoretically nothing will happen because AccessibilityNotifier only exists if the Window class has been loaded.

@@ -16,7 +16,6 @@
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\AccessibilityNotifier.cpp" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update sources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants