Add more object ID tracing for Accessibility (#5215)
## Summary of the Pull Request In preparation for getting more accessibility-related issues, I added an ID to the `ScreenInfoUiaProvider` (SIUP) and abstracted the one from `UiaTextRange`. Using this, I noticed that we are creating SIUPs when a new tab/pane is created. This is _good_. This means that we need to somehow notify a UIA Client that out structure has changed, and we need to use the new SIUP because the old one has been removed. I'll be investigating that more after this PR lands.
This commit is contained in:
parent
9513d543b7
commit
286af380c9
54
src/types/IUiaTraceable.h
Normal file
54
src/types/IUiaTraceable.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- IUiaTraceable.hpp
|
||||
|
||||
Abstract:
|
||||
- This module is used for assigning and retrieving IDs to UIA objects
|
||||
|
||||
Author(s):
|
||||
- Carlos Zamora (cazamor) Apr 2020
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Microsoft::Console::Types
|
||||
{
|
||||
typedef unsigned long long IdType;
|
||||
constexpr IdType InvalidId = 0;
|
||||
|
||||
class IUiaTraceable
|
||||
{
|
||||
public:
|
||||
const IdType GetId() const noexcept
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - assigns an ID to the IUiaTraceable object if it doesn't have one
|
||||
// Arguments:
|
||||
// - id - the id value that we are trying to assign
|
||||
// Return Value:
|
||||
// - true if the assignment was successful, false otherwise (it already has an id).
|
||||
bool AssignId(IdType id) noexcept
|
||||
{
|
||||
if (_id == InvalidId)
|
||||
{
|
||||
_id = id;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// used to debug objects passed back and forth
|
||||
// between the provider and the client
|
||||
IdType _id{};
|
||||
};
|
||||
}
|
|
@ -38,30 +38,31 @@ try
|
|||
RETURN_HR_IF_NULL(E_INVALIDARG, pData);
|
||||
_pData = pData;
|
||||
_wordDelimiters = wordDelimiters;
|
||||
|
||||
UiaTracing::TextProvider::Constructor(*this);
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
[[nodiscard]] HRESULT ScreenInfoUiaProviderBase::Signal(_In_ EVENTID id)
|
||||
[[nodiscard]] HRESULT ScreenInfoUiaProviderBase::Signal(_In_ EVENTID eventId)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
// check to see if we're already firing this particular event
|
||||
if (_signalFiringMapping.find(id) != _signalFiringMapping.end() &&
|
||||
_signalFiringMapping[id] == true)
|
||||
if (_signalFiringMapping.find(eventId) != _signalFiringMapping.end() &&
|
||||
_signalFiringMapping[eventId] == true)
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_signalFiringMapping[id] = true;
|
||||
_signalFiringMapping[eventId] = true;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
IRawElementProviderSimple* pProvider = this;
|
||||
hr = UiaRaiseAutomationEvent(pProvider, id);
|
||||
_signalFiringMapping[id] = false;
|
||||
hr = UiaRaiseAutomationEvent(pProvider, eventId);
|
||||
_signalFiringMapping[eventId] = false;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ Author(s):
|
|||
#include "../buffer/out/textBuffer.hpp"
|
||||
#include "UiaTextRangeBase.hpp"
|
||||
#include "IUiaData.h"
|
||||
#include "IUiaTraceable.h"
|
||||
|
||||
#include <UIAutomationCore.h>
|
||||
|
||||
|
@ -35,7 +36,8 @@ namespace Microsoft::Console::Types
|
|||
class Viewport;
|
||||
|
||||
class ScreenInfoUiaProviderBase :
|
||||
public WRL::RuntimeClass<WRL::RuntimeClassFlags<WRL::ClassicCom | WRL::InhibitFtmBase>, IRawElementProviderSimple, IRawElementProviderFragment, ITextProvider>
|
||||
public WRL::RuntimeClass<WRL::RuntimeClassFlags<WRL::ClassicCom | WRL::InhibitFtmBase>, IRawElementProviderSimple, IRawElementProviderFragment, ITextProvider>,
|
||||
public IUiaTraceable
|
||||
{
|
||||
public:
|
||||
virtual HRESULT RuntimeClassInitialize(_In_ IUiaData* pData, _In_ std::wstring_view wordDelimiters = UiaTextRangeBase::DefaultWordDelimiter) noexcept;
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
|
||||
using namespace Microsoft::Console::Types;
|
||||
|
||||
IdType UiaTextRangeBase::id = 1;
|
||||
|
||||
// degenerate range constructor.
|
||||
#pragma warning(suppress : 26434) // WRL RuntimeClassInitialize base is a no-op and we need this for MakeAndInitialize
|
||||
HRESULT UiaTextRangeBase::RuntimeClassInitialize(_In_ IUiaData* pData, _In_ IRawElementProviderSimple* const pProvider, _In_ std::wstring_view wordDelimiters) noexcept
|
||||
|
@ -26,9 +24,6 @@ try
|
|||
_blockRange = false;
|
||||
_wordDelimiters = wordDelimiters;
|
||||
|
||||
_id = id;
|
||||
++id;
|
||||
|
||||
UiaTracing::TextRange::Constructor(*this);
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -123,19 +118,11 @@ try
|
|||
_pData = a._pData;
|
||||
_wordDelimiters = a._wordDelimiters;
|
||||
|
||||
_id = id;
|
||||
++id;
|
||||
|
||||
UiaTracing::TextRange::Constructor(*this);
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
const IdType UiaTextRangeBase::GetId() const noexcept
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
const COORD UiaTextRangeBase::GetEndpoint(TextPatternRangeEndpoint endpoint) const noexcept
|
||||
{
|
||||
switch (endpoint)
|
||||
|
|
|
@ -22,6 +22,7 @@ Author(s):
|
|||
#include "../buffer/out/textBuffer.hpp"
|
||||
#include "IUiaData.h"
|
||||
#include "unicode.hpp"
|
||||
#include "IUiaTraceable.h"
|
||||
|
||||
#include <UIAutomationCore.h>
|
||||
#include <deque>
|
||||
|
@ -32,18 +33,10 @@ Author(s):
|
|||
class UiaTextRangeTests;
|
||||
#endif
|
||||
|
||||
typedef unsigned long long IdType;
|
||||
constexpr IdType InvalidId = 0;
|
||||
|
||||
namespace Microsoft::Console::Types
|
||||
{
|
||||
class UiaTracing;
|
||||
|
||||
class UiaTextRangeBase : public WRL::RuntimeClass<WRL::RuntimeClassFlags<WRL::ClassicCom | WRL::InhibitFtmBase>, ITextRangeProvider>
|
||||
class UiaTextRangeBase : public WRL::RuntimeClass<WRL::RuntimeClassFlags<WRL::ClassicCom | WRL::InhibitFtmBase>, ITextRangeProvider>, public IUiaTraceable
|
||||
{
|
||||
private:
|
||||
static IdType id;
|
||||
|
||||
protected:
|
||||
// indicates which direction a movement operation
|
||||
// is going
|
||||
|
@ -84,7 +77,6 @@ namespace Microsoft::Console::Types
|
|||
UiaTextRangeBase& operator=(UiaTextRangeBase&&) = delete;
|
||||
~UiaTextRangeBase() = default;
|
||||
|
||||
const IdType GetId() const noexcept;
|
||||
const COORD GetEndpoint(TextPatternRangeEndpoint endpoint) const noexcept;
|
||||
bool SetEndpoint(TextPatternRangeEndpoint endpoint, const COORD val) noexcept;
|
||||
const bool IsDegenerate() const noexcept;
|
||||
|
@ -141,10 +133,6 @@ namespace Microsoft::Console::Types
|
|||
|
||||
void Initialize(_In_ const UiaPoint point);
|
||||
|
||||
// used to debug objects passed back and forth
|
||||
// between the provider and the client
|
||||
IdType _id{};
|
||||
|
||||
// measure units in the form [_start, _end).
|
||||
// These are in the TextBuffer coordinate space.
|
||||
// NOTE: _start is inclusive, but _end is exclusive
|
||||
|
|
|
@ -15,6 +15,44 @@ TRACELOGGING_DEFINE_PROVIDER(g_UiaProviderTraceProvider,
|
|||
|
||||
using namespace Microsoft::Console::Types;
|
||||
|
||||
// The first valid ID is 1 for each of our traced UIA object types
|
||||
// ID assignment is handled between UiaTracing and IUiaTraceable to...
|
||||
// - prevent multiple objects with the same ID
|
||||
// - only assign IDs if UiaTracing is enabled
|
||||
// - ensure objects are only assigned an ID once
|
||||
IdType UiaTracing::_utrId = 1;
|
||||
IdType UiaTracing::_siupId = 1;
|
||||
|
||||
// Routine Description:
|
||||
// - assign an ID to the UiaTextRange, if it doesn't have one already
|
||||
// Arguments:
|
||||
// - utr - the UiaTextRange we are assigning an ID to
|
||||
// Return Value:
|
||||
// - N/A
|
||||
void UiaTracing::_assignId(UiaTextRangeBase& utr) noexcept
|
||||
{
|
||||
auto temp = utr.AssignId(_utrId);
|
||||
if (temp)
|
||||
{
|
||||
++_utrId;
|
||||
}
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - assign an ID to the ScreenInfoUiaProvider, if it doesn't have one already
|
||||
// Arguments:
|
||||
// - siup - the ScreenInfoUiaProvider we are assigning an ID to
|
||||
// Return Value:
|
||||
// - N/A
|
||||
void UiaTracing::_assignId(ScreenInfoUiaProviderBase& siup) noexcept
|
||||
{
|
||||
auto temp = siup.AssignId(_siupId);
|
||||
if (temp)
|
||||
{
|
||||
++_siupId;
|
||||
}
|
||||
}
|
||||
|
||||
UiaTracing::UiaTracing() noexcept
|
||||
{
|
||||
TraceLoggingRegister(g_UiaProviderTraceProvider);
|
||||
|
@ -25,9 +63,11 @@ UiaTracing::~UiaTracing() noexcept
|
|||
TraceLoggingUnregister(g_UiaProviderTraceProvider);
|
||||
}
|
||||
|
||||
inline std::wstring UiaTracing::_getValue(const ScreenInfoUiaProviderBase& /*siup*/) noexcept
|
||||
inline std::wstring UiaTracing::_getValue(const ScreenInfoUiaProviderBase& siup) noexcept
|
||||
{
|
||||
return L" NO IDENTIFYING DATA";
|
||||
std::wstringstream stream;
|
||||
stream << "_id: " << siup.GetId();
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
inline std::wstring UiaTracing::_getValue(const UiaTextRangeBase& utr) noexcept
|
||||
|
@ -86,11 +126,12 @@ inline std::wstring UiaTracing::_getValue(const TextUnit unit) noexcept
|
|||
}
|
||||
}
|
||||
|
||||
void UiaTracing::TextRange::Constructor(const UiaTextRangeBase& result) noexcept
|
||||
void UiaTracing::TextRange::Constructor(UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
_assignId(result);
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::Constructor",
|
||||
|
@ -99,11 +140,12 @@ void UiaTracing::TextRange::Constructor(const UiaTextRangeBase& result) noexcept
|
|||
}
|
||||
}
|
||||
|
||||
void UiaTracing::TextRange::Clone(const UiaTextRangeBase& utr, const UiaTextRangeBase& result) noexcept
|
||||
void UiaTracing::TextRange::Clone(const UiaTextRangeBase& utr, UiaTextRangeBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
_assignId(result);
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"UiaTextRange::Clone",
|
||||
|
@ -360,11 +402,12 @@ void UiaTracing::TextRange::GetChildren(const UiaTextRangeBase& result) noexcept
|
|||
}
|
||||
}
|
||||
|
||||
void UiaTracing::TextProvider::Constructor(const ScreenInfoUiaProviderBase& result) noexcept
|
||||
void UiaTracing::TextProvider::Constructor(ScreenInfoUiaProviderBase& result) noexcept
|
||||
{
|
||||
EnsureRegistration();
|
||||
if (TraceLoggingProviderEnabled(g_UiaProviderTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
|
||||
{
|
||||
_assignId(result);
|
||||
TraceLoggingWrite(
|
||||
g_UiaProviderTraceProvider,
|
||||
"ScreenInfoUiaProvider::Constructor",
|
||||
|
|
|
@ -32,8 +32,8 @@ namespace Microsoft::Console::Types
|
|||
class TextRange final
|
||||
{
|
||||
public:
|
||||
static void Constructor(const UiaTextRangeBase& result) noexcept;
|
||||
static void Clone(const UiaTextRangeBase& base, const UiaTextRangeBase& result) noexcept;
|
||||
static void Constructor(UiaTextRangeBase& result) noexcept;
|
||||
static void Clone(const UiaTextRangeBase& base, UiaTextRangeBase& result) noexcept;
|
||||
static void Compare(const UiaTextRangeBase& base, const UiaTextRangeBase& other, bool result) noexcept;
|
||||
static void CompareEndpoints(const UiaTextRangeBase& base, const TextPatternRangeEndpoint endpoint, const UiaTextRangeBase& other, TextPatternRangeEndpoint otherEndpoint, int result) noexcept;
|
||||
static void ExpandToEnclosingUnit(TextUnit unit, const UiaTextRangeBase& result) noexcept;
|
||||
|
@ -56,7 +56,7 @@ namespace Microsoft::Console::Types
|
|||
class TextProvider final
|
||||
{
|
||||
public:
|
||||
static void Constructor(const ScreenInfoUiaProviderBase& result) noexcept;
|
||||
static void Constructor(ScreenInfoUiaProviderBase& result) noexcept;
|
||||
static void get_ProviderOptions(const ScreenInfoUiaProviderBase& base, ProviderOptions options) noexcept;
|
||||
static void GetPatternProvider(const ScreenInfoUiaProviderBase& base, PATTERNID patternId) noexcept;
|
||||
static void GetPropertyValue(const ScreenInfoUiaProviderBase& base, PROPERTYID propertyId) noexcept;
|
||||
|
@ -100,5 +100,12 @@ namespace Microsoft::Console::Types
|
|||
static inline std::wstring _getValue(const UiaTextRangeBase& utr) noexcept;
|
||||
static inline std::wstring _getValue(const TextPatternRangeEndpoint endpoint) noexcept;
|
||||
static inline std::wstring _getValue(const TextUnit unit) noexcept;
|
||||
|
||||
// these are used to assign IDs to new UiaTextRanges and ScreenInfoUiaProviders respectively
|
||||
static IdType _utrId;
|
||||
static IdType _siupId;
|
||||
|
||||
static void _assignId(UiaTextRangeBase& utr) noexcept;
|
||||
static void _assignId(ScreenInfoUiaProviderBase& siup) noexcept;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
<ClInclude Include="..\inc\Utf16Parser.hpp" />
|
||||
<ClInclude Include="..\IUiaData.h" />
|
||||
<ClInclude Include="..\IUiaEventDispatcher.h" />
|
||||
<ClInclude Include="..\IUiaTraceable.h" />
|
||||
<ClInclude Include="..\IUiaWindow.h" />
|
||||
<ClInclude Include="..\TermControlUiaTextRange.hpp" />
|
||||
<ClInclude Include="..\TermControlUiaProvider.hpp" />
|
||||
|
|
|
@ -176,6 +176,9 @@
|
|||
<ClInclude Include="..\UiaTracing.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\IUiaTraceable.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||
|
|
Loading…
Reference in a new issue