Fire UIA Events for Output and Cursor Movement (#4826)

## Summary of the Pull Request
This notifies automation clients (i.e.: NVDA, narrator, etc...) of new output being rendered to the screen.

## References
Close #2447 - Signaling for new output and cursor
Close #3791 - fixed by signaling cursor changes

## Detailed Description of the Pull Request / Additional comments
- Added tracing for UiaRenderer. This makes it easier to debug issues with notifying an automation client.
- Fire TextChanged automation events when new content is output to the screen.

## Validation Steps Performed
Verified with NVDA [1]

## Narrator
Narrator works _better_, but is unable to detect new output consistently. There is no harm for narrator when this change goes in.

[1] https://github.com/microsoft/terminal/issues/2447#issuecomment-595879890
This commit is contained in:
Carlos Zamora 2020-03-18 11:01:05 -07:00 committed by GitHub
parent cddac25726
commit eca0c6b327
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 84 additions and 5 deletions

View file

@ -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);
});
}

View file

@ -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:
@ -68,6 +71,7 @@ UiaEngine::UiaEngine(IUiaEventDispatcher* dispatcher) :
// - S_FALSE
[[nodiscard]] HRESULT UiaEngine::InvalidateCursor(const COORD* const /*pcoordCursor*/) noexcept
{
_cursorChanged = true;
return S_FALSE;
}
@ -150,7 +154,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 +197,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,8 +226,26 @@ UiaEngine::UiaEngine(IUiaEventDispatcher* dispatcher) :
}
CATCH_LOG();
}
if (_textBufferChanged)
{
try
{
_dispatcher->SignalTextChanged();
}
CATCH_LOG();
}
if (_cursorChanged)
{
try
{
_dispatcher->SignalCursorChanged();
}
CATCH_LOG();
}
_selectionChanged = false;
_textBufferChanged = false;
_cursorChanged = false;
_prevSelection.clear();
_isPainting = false;

View file

@ -82,6 +82,8 @@ namespace Microsoft::Console::Render
bool _isEnabled;
bool _isPainting;
bool _selectionChanged;
bool _textBufferChanged;
bool _cursorChanged;
Microsoft::Console::Types::IUiaEventDispatcher* _dispatcher;

View file

@ -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)

View file

@ -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