Skip accessibility notifier and all event calculations when we're in PTY mode (#10569)

Change accessibility notifier creation so we do not create one when we're in PTY mode. (Guard all call sites to skip math/event work when the notifier is null.) MSAA events are legacy events that are registered for globally and used by some screen readers to find content in the conhost window. The PTY mode is not responsible for hosting the display content or input window, so it makes sense for it to not broadcast these events and delegate the accessibility requirement to the connected terminal.

## References
- #10537 

## PR Checklist
* [x] Closes #10568
* [x] I work here
* [x] Manual test launches passed.
This commit is contained in:
Michael Niksa 2021-07-09 11:45:44 -07:00 committed by GitHub
parent 6409ab91fa
commit 91b454ac95
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 111 additions and 45 deletions

View file

@ -70,7 +70,7 @@ void CursorBlinker::TimerRoutine(SCREEN_INFORMATION& ScreenInfo)
auto& buffer = ScreenInfo.GetTextBuffer();
auto& cursor = buffer.GetCursor();
const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
auto* const _pAccessibilityNotifier = ServiceLocator::LocateAccessibilityNotifier();
auto* const pAccessibilityNotifier = ServiceLocator::LocateAccessibilityNotifier();
if (!WI_IsFlagSet(gci.Flags, CONSOLE_HAS_FOCUS))
{
@ -78,7 +78,8 @@ void CursorBlinker::TimerRoutine(SCREEN_INFORMATION& ScreenInfo)
}
// Update the cursor pos in USER so accessibility will work.
if (cursor.HasMoved())
// Don't do all this work or send events if we don't have a notifier target.
if (pAccessibilityNotifier && cursor.HasMoved())
{
// Convert the buffer position to the equivalent screen coordinates
// required by the notifier, taking line rendition into account.
@ -93,7 +94,7 @@ void CursorBlinker::TimerRoutine(SCREEN_INFORMATION& ScreenInfo)
rc.right = rc.left + fontSize.X;
rc.bottom = rc.top + fontSize.Y;
_pAccessibilityNotifier->NotifyConsoleCaretEvent(rc);
pAccessibilityNotifier->NotifyConsoleCaretEvent(rc);
// Send accessibility information
{
@ -109,7 +110,7 @@ void CursorBlinker::TimerRoutine(SCREEN_INFORMATION& ScreenInfo)
flags = IAccessibilityNotifier::ConsoleCaretEventFlags::CaretVisible;
}
_pAccessibilityNotifier->NotifyConsoleCaretEvent(flags, MAKELONG(position.X, position.Y));
pAccessibilityNotifier->NotifyConsoleCaretEvent(flags, MAKELONG(position.X, position.Y));
}
}

View file

@ -224,10 +224,13 @@ void WriteToScreen(SCREEN_INFORMATION& screenInfo, const Viewport& region)
cellsModified = done.GetCellDistance(it);
// Notify accessibility
auto endingCoordinate = startingCoordinate;
bufferSize.MoveInBounds(cellsModified, endingCoordinate);
screenBuffer.NotifyAccessibilityEventing(startingCoordinate.X, startingCoordinate.Y, endingCoordinate.X, endingCoordinate.Y);
if (screenBuffer.HasAccessibilityEventing())
{
// Notify accessibility
auto endingCoordinate = startingCoordinate;
bufferSize.MoveInBounds(cellsModified, endingCoordinate);
screenBuffer.NotifyAccessibilityEventing(startingCoordinate.X, startingCoordinate.Y, endingCoordinate.X, endingCoordinate.Y);
}
}
CATCH_RETURN();
@ -284,9 +287,12 @@ void WriteToScreen(SCREEN_INFORMATION& screenInfo, const Viewport& region)
cellsModified = done.GetInputDistance(it);
// Notify accessibility
auto endingCoordinate = startingCoordinate;
bufferSize.MoveInBounds(cellsModified, endingCoordinate);
screenInfo.NotifyAccessibilityEventing(startingCoordinate.X, startingCoordinate.Y, endingCoordinate.X, endingCoordinate.Y);
if (screenInfo.HasAccessibilityEventing())
{
auto endingCoordinate = startingCoordinate;
bufferSize.MoveInBounds(cellsModified, endingCoordinate);
screenInfo.NotifyAccessibilityEventing(startingCoordinate.X, startingCoordinate.Y, endingCoordinate.X, endingCoordinate.Y);
}
// GH#3126 - This is a shim for powershell's `Clear-Host` function. In
// the vintage console, `Clear-Host` is supposed to clear the entire

View file

@ -557,7 +557,10 @@ constexpr unsigned int LOCAL_BUFFER_SIZE = 100;
const auto itEnd = screenInfo.Write(it);
// Notify accessibility
screenInfo.NotifyAccessibilityEventing(CursorPosition.X, CursorPosition.Y, CursorPosition.X + gsl::narrow<SHORT>(i - 1), CursorPosition.Y);
if (screenInfo.HasAccessibilityEventing())
{
screenInfo.NotifyAccessibilityEventing(CursorPosition.X, CursorPosition.Y, CursorPosition.X + gsl::narrow<SHORT>(i - 1), CursorPosition.Y);
}
// The number of "spaces" or "cells" we have consumed needs to be reported and stored for later
// when/if we need to erase the command line.

View file

@ -376,7 +376,10 @@ std::vector<OutputCell>::const_iterator ConsoleImeInfo::_WriteConversionArea(con
area.Paint();
// Notify accessibility that we have updated the text in this display region within the viewport.
screenInfo.NotifyAccessibilityEventing(insertionPos.X, insertionPos.Y, gsl::narrow<SHORT>(insertionPos.X + lineVec.size() - 1), insertionPos.Y);
if (screenInfo.HasAccessibilityEventing())
{
screenInfo.NotifyAccessibilityEventing(insertionPos.X, insertionPos.Y, gsl::narrow<SHORT>(insertionPos.X + lineVec.size() - 1), insertionPos.Y);
}
// Hand back the iterator representing the end of what we used to be fed into the beginning of the next call.
return lineEnd;

View file

@ -2210,10 +2210,14 @@ void DoSrvPrivateMoveToBottom(SCREEN_INFORMATION& screenInfo)
screenInfo.Write(fillData, startPosition, false);
// Notify accessibility
auto endPosition = startPosition;
const auto bufferSize = screenInfo.GetBufferSize();
bufferSize.MoveInBounds(fillLength - 1, endPosition);
screenInfo.NotifyAccessibilityEventing(startPosition.X, startPosition.Y, endPosition.X, endPosition.Y);
if (screenInfo.HasAccessibilityEventing())
{
auto endPosition = startPosition;
const auto bufferSize = screenInfo.GetBufferSize();
bufferSize.MoveInBounds(fillLength - 1, endPosition);
screenInfo.NotifyAccessibilityEventing(startPosition.X, startPosition.Y, endPosition.X, endPosition.Y);
}
return S_OK;
}
CATCH_RETURN();

View file

@ -106,8 +106,9 @@ SCREEN_INFORMATION::~SCREEN_INFORMATION()
THROW_HR_IF_NULL(E_FAIL, pMetrics);
IAccessibilityNotifier* pNotifier = ServiceLocator::LocateAccessibilityNotifier();
THROW_HR_IF_NULL(E_FAIL, pNotifier);
// It is possible for pNotifier to be null and that's OK.
// For instance, the PTY doesn't need to send events. Just pass it along
// and be sure that `SCREEN_INFORMATION` bypasses all event work if it's not there.
SCREEN_INFORMATION* const pScreen = new SCREEN_INFORMATION(pMetrics, pNotifier, popupAttributes, fontInfo);
// Set up viewport
@ -564,6 +565,19 @@ void SCREEN_INFORMATION::UpdateFont(const FontInfo* const pfiNewFont)
}
}
// Routine Description:
// - Informs clients whether we have accessibility eventing so they can
// save themselves the work of performing math or lookups before calling
// `NotifyAccessibilityEventing`.
// Arguments:
// - <none>
// Return Value:
// - True if we have an accessibility listener. False otherwise.
bool SCREEN_INFORMATION::HasAccessibilityEventing() const noexcept
{
return _pAccessibilityNotifier;
}
// NOTE: This method was historically used to notify accessibility apps AND
// to aggregate drawing metadata to determine whether or not to use PolyTextOut.
// After the Nov 2015 graphics refactor, the metadata drawing flag calculation is no longer necessary.
@ -573,8 +587,7 @@ void SCREEN_INFORMATION::NotifyAccessibilityEventing(const short sStartX,
const short sEndX,
const short sEndY)
{
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
if (gci.IsInVtIoMode())
if (!_pAccessibilityNotifier)
{
return;
}
@ -680,7 +693,10 @@ VOID SCREEN_INFORMATION::InternalUpdateScrollBars()
}
// Fire off an event to let accessibility apps know the layout has changed.
_pAccessibilityNotifier->NotifyConsoleLayoutEvent();
if (_pAccessibilityNotifier)
{
_pAccessibilityNotifier->NotifyConsoleLayoutEvent();
}
ResizingWindow--;
}
@ -1526,7 +1542,10 @@ bool SCREEN_INFORMATION::IsMaximizedY() const
if (NT_SUCCESS(status))
{
NotifyAccessibilityEventing(0, 0, (SHORT)(coordNewScreenSize.X - 1), (SHORT)(coordNewScreenSize.Y - 1));
if (HasAccessibilityEventing())
{
NotifyAccessibilityEventing(0, 0, (SHORT)(coordNewScreenSize.X - 1), (SHORT)(coordNewScreenSize.Y - 1));
}
if ((!ConvScreenInfo))
{
@ -1538,7 +1557,7 @@ bool SCREEN_INFORMATION::IsMaximizedY() const
}
// Fire off an event to let accessibility apps know the layout has changed.
if (IsActiveScreenBuffer())
if (_pAccessibilityNotifier && IsActiveScreenBuffer())
{
_pAccessibilityNotifier->NotifyConsoleLayoutEvent();
}

View file

@ -99,6 +99,7 @@ public:
[[nodiscard]] NTSTATUS ResizeScreenBuffer(const COORD coordNewScreenSize, const bool fDoScrollBarUpdate);
bool HasAccessibilityEventing() const noexcept;
void NotifyAccessibilityEventing(const short sStartX, const short sStartY, const short sEndX, const short sEndY);
void UpdateScrollBars();

View file

@ -160,7 +160,11 @@ void Selection::InitializeMouseSelection(const COORD coordBufferPos)
}
// Fire off an event to let accessibility apps know the selection has changed.
ServiceLocator::LocateAccessibilityNotifier()->NotifyConsoleCaretEvent(IAccessibilityNotifier::ConsoleCaretEventFlags::CaretSelection, PACKCOORD(coordBufferPos));
auto pNotifier = ServiceLocator::LocateAccessibilityNotifier();
if (pNotifier)
{
pNotifier->NotifyConsoleCaretEvent(IAccessibilityNotifier::ConsoleCaretEventFlags::CaretSelection, PACKCOORD(coordBufferPos));
}
}
// Routine Description:
@ -258,7 +262,11 @@ void Selection::ExtendSelection(_In_ COORD coordBufferPos)
_PaintSelection();
// Fire off an event to let accessibility apps know the selection has changed.
ServiceLocator::LocateAccessibilityNotifier()->NotifyConsoleCaretEvent(IAccessibilityNotifier::ConsoleCaretEventFlags::CaretSelection, PACKCOORD(coordBufferPos));
auto pNotifier = ServiceLocator::LocateAccessibilityNotifier();
if (pNotifier)
{
pNotifier->NotifyConsoleCaretEvent(IAccessibilityNotifier::ConsoleCaretEventFlags::CaretSelection, PACKCOORD(coordBufferPos));
}
LOG_IF_FAILED(ServiceLocator::LocateConsoleWindow()->SignalUia(UIA_Text_TextSelectionChangedEventId));
}

View file

@ -76,6 +76,17 @@ try
}
}
// Create the accessibility notifier early in the startup process.
// Only create if we're not in PTY mode.
// The notifiers use expensive legacy MSAA events and the PTY isn't even responsible
// for the terminal user interface, so we should set ourselves up to skip all
// those notifications and the mathematical calculations required to send those events
// for performance reasons.
if (!args->InConptyMode())
{
RETURN_IF_FAILED(ServiceLocator::CreateAccessibilityNotifier());
}
// Removed allocation of scroll buffer here.
return S_OK;
}

View file

@ -100,6 +100,24 @@ void ServiceLocator::RundownAndExit(const HRESULT hr)
return status;
}
[[nodiscard]] HRESULT ServiceLocator::CreateAccessibilityNotifier()
{
// Can't create if we've already created.
if (s_accessibilityNotifier)
{
return E_UNEXPECTED;
}
if (!s_interactivityFactory)
{
RETURN_IF_NTSTATUS_FAILED(ServiceLocator::LoadInteractivityFactory());
}
RETURN_IF_NTSTATUS_FAILED(s_interactivityFactory->CreateAccessibilityNotifier(s_accessibilityNotifier));
return S_OK;
}
#pragma endregion
#pragma region Set Methods
@ -224,23 +242,6 @@ IWindowMetrics* ServiceLocator::LocateWindowMetrics()
IAccessibilityNotifier* ServiceLocator::LocateAccessibilityNotifier()
{
NTSTATUS status = STATUS_SUCCESS;
if (!s_accessibilityNotifier)
{
if (s_interactivityFactory.get() == nullptr)
{
status = ServiceLocator::LoadInteractivityFactory();
}
if (NT_SUCCESS(status))
{
status = s_interactivityFactory->CreateAccessibilityNotifier(s_accessibilityNotifier);
}
}
LOG_IF_NTSTATUS_FAILED(status);
return s_accessibilityNotifier.get();
}

View file

@ -37,6 +37,7 @@ namespace Microsoft::Console::Interactivity
// In case the on-demand creation fails, the return value
// is nullptr and a message is logged.
[[nodiscard]] static HRESULT CreateAccessibilityNotifier();
static IAccessibilityNotifier* LocateAccessibilityNotifier();
[[nodiscard]] static NTSTATUS SetConsoleControlInstance(_In_ std::unique_ptr<IConsoleControl>&& control);

View file

@ -365,7 +365,11 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleHandleConnectionRequest(_In_ PCONSOLE_API
LOG_IF_FAILED(ServiceLocator::LocateConsoleControl()->NotifyConsoleApplication(dwProcessId));
}
ServiceLocator::LocateAccessibilityNotifier()->NotifyConsoleStartApplicationEvent(dwProcessId);
auto pNotifier = ServiceLocator::LocateAccessibilityNotifier();
if (pNotifier)
{
pNotifier->NotifyConsoleStartApplicationEvent(dwProcessId);
}
if (WI_IsFlagClear(gci.Flags, CONSOLE_INITIALIZED))
{
@ -460,7 +464,11 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleClientDisconnectRoutine(_In_ PCONSOLE_API
ConsoleProcessHandle* const pProcessData = pMessage->GetProcessHandle();
ServiceLocator::LocateAccessibilityNotifier()->NotifyConsoleEndApplicationEvent(pProcessData->dwProcessId);
auto pNotifier = ServiceLocator::LocateAccessibilityNotifier();
if (pNotifier)
{
pNotifier->NotifyConsoleEndApplicationEvent(pProcessData->dwProcessId);
}
LOG_IF_FAILED(RemoveConsole(pProcessData));