Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UIA Operation Abstraction lib: implement support for CallExtension / IsExtensionSupported #84

Merged
merged 9 commits into from
Mar 22, 2022
150 changes: 150 additions & 0 deletions src/UIAutomation/FunctionalTests/UiaOperationAbstractionTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2565,5 +2565,155 @@ namespace UiaOperationAbstractionTests
{
IsOpcodeSupportedTest_BeforeImport(false);
}

// Test equality of UiaGuid objects.
void UiaGuidEqualityTest(const bool useRemoteOperations)
{
auto guard = InitializeUiaOperationAbstraction(useRemoteOperations);

ModernApp app(L"Microsoft.WindowsCalculator_8wekyb3d8bbwe!App");
app.Activate();
auto calc = WaitForElementFocus(L"Display is 0");
UiaElement element = calc;

auto scope = UiaOperationScope::StartNew();
scope.BindInput(element);

// Some UiaGuids from actual local GUID values
UiaGuid nameGuid{Name_Property_GUID};
UiaGuid controlTypeGuid{ControlType_Property_GUID};

// Find out if these UiaGuids are equal or not,
// They should b different
auto areNameAndControlTypeGuidsSame = nameGuid == controlTypeGuid;
scope.BindResult(areNameAndControlTypeGuidsSame);
auto areNameAndControlTypeGuidsDifferent = nameGuid != controlTypeGuid;
scope.BindResult(areNameAndControlTypeGuidsDifferent);

// Make copies of these UiaGuids
// Deliberately initializing with a NULL guid and then copying by assignment, not constructing by reference,
// As we do want them to be physically different objects.
winrt::guid GUID_NULL{0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
UiaGuid nameGuid_copy{GUID_NULL};
nameGuid_copy = nameGuid;
scope.BindResult(nameGuid_copy);
UiaGuid controlTypeGuid_copy{GUID_NULL};
controlTypeGuid_copy = controlTypeGuid;
scope.BindResult(controlTypeGuid_copy);

//Find out if the original and its copy are equal.
// They should be.
auto areNameGuidAndCopySame = nameGuid == nameGuid_copy;
scope.BindResult(areNameGuidAndCopySame);
auto areNameGuidAndCopyDifferent = nameGuid != nameGuid_copy;
scope.BindResult(areNameGuidAndCopyDifferent);

// Find out if the copies are different from each other,
// They should be.
auto areGuidCopiesSame = nameGuid_copy == controlTypeGuid_copy;
scope.BindResult(areGuidCopiesSame);
auto areGuidCopiesDifferent = nameGuid_copy != controlTypeGuid_copy;
scope.BindResult(areGuidCopiesDifferent);

// Actually execute
scope.Resolve();

// Assert all our remote findings
Assert::IsFalse(areNameAndControlTypeGuidsSame);
Assert::IsTrue(areNameAndControlTypeGuidsDifferent);
Assert::IsTrue(areNameGuidAndCopySame);
Assert::IsFalse(areNameGuidAndCopyDifferent);
Assert::IsFalse(areGuidCopiesSame);
Assert::IsTrue(areGuidCopiesDifferent);

// Make a new local GUID from one of the generated copies,
// And ensure it holds the correct GUID value
winrt::guid nameGuid_final = nameGuid_copy;
Assert::IsTrue(IsEqualGUID(nameGuid_final, Name_Property_GUID));
}

TEST_METHOD(UiaGuidEquality_Remote)
{
UiaGuidEqualityTest(true);
}

TEST_METHOD(UiaGuidEquality_Local)
{
UiaGuidEqualityTest(false);
}

// UiaGuid: test looking up property IDs
void UiaGuidLookupPropertyIdTest(const bool useRemoteOperations)
{
auto guard = InitializeUiaOperationAbstraction(useRemoteOperations);

ModernApp app(L"Microsoft.WindowsCalculator_8wekyb3d8bbwe!App");
app.Activate();
auto calc = WaitForElementFocus(L"Display is 0");
UiaElement element = calc;

auto scope = UiaOperationScope::StartNew();
scope.BindInput(element);

UiaGuid propGuid{Name_Property_GUID};
auto propId = propGuid.LookupPropertyId();

auto isNamePropertyId = propId == UiaPropertyId(UIA_NamePropertyId);
scope.BindResult(isNamePropertyId);
auto isControlTypePropertyId = propId == UiaPropertyId(UIA_ControlTypePropertyId);
scope.BindResult(isControlTypePropertyId);

scope.Resolve();

Assert::IsTrue(isNamePropertyId);
Assert::IsFalse(isControlTypePropertyId);
}

TEST_METHOD(UiaGuidLookupPropertyId_Remote)
{
UiaGuidLookupPropertyIdTest(true);
}

TEST_METHOD(UiaGuidLookupPropertyId_Local)
{
UiaGuidLookupPropertyIdTest(false);
}

// UiaGuid: test looking up annotation type IDs
void UiaGuidLookupAnnotationTypeIdTest(const bool useRemoteOperations)
{
auto guard = InitializeUiaOperationAbstraction(useRemoteOperations);

ModernApp app(L"Microsoft.WindowsCalculator_8wekyb3d8bbwe!App");
app.Activate();
auto calc = WaitForElementFocus(L"Display is 0");
UiaElement element = calc;

auto scope = UiaOperationScope::StartNew();
scope.BindInput(element);

UiaGuid annotationTypeGuid{Annotation_SpellingError_GUID};
auto annotationTypeId = annotationTypeGuid.LookupAnnotationType();

auto isSpellingErrorAnnotationTypeId = annotationTypeId == UiaAnnotationType(AnnotationType_SpellingError);
scope.BindResult(isSpellingErrorAnnotationTypeId);
auto isCommentAnnotationTypeId = annotationTypeId == UiaAnnotationType(AnnotationType_Comment);
scope.BindResult(isCommentAnnotationTypeId);

scope.Resolve();

Assert::IsTrue(isSpellingErrorAnnotationTypeId);
Assert::IsFalse(isCommentAnnotationTypeId);
}

TEST_METHOD(UiaGuidLookupAnnotationTypeId_Remote)
{
UiaGuidLookupAnnotationTypeIdTest(true);
}

TEST_METHOD(UiaGuidLookupAnnotationTypeId_Local)
{
UiaGuidLookupAnnotationTypeIdTest(false);
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,81 @@ namespace UiaOperationAbstraction
}
}

UiaGuid::UiaGuid(const winrt::guid& value):
UiaTypeBase(value)
{
ToRemote();
}

UiaGuid::UiaGuid(winrt::Microsoft::UI::UIAutomation::AutomationRemoteGuid remoteValue):
UiaTypeBase(remoteValue)
{
}

UiaGuid::UiaGuid(winrt::Microsoft::UI::UIAutomation::AutomationRemoteAnyObject remoteValue):
UiaTypeBase(remoteValue.AsGuid())
{
}

UiaGuid& UiaGuid::operator=(const UiaGuid& other)
{
AssignCopyTo<UiaGuid>(this->m_member, other.m_member);
return *this;
}

UiaBool UiaGuid::operator==(const UiaGuid& rhs) const
{
return BinaryOperator<UiaGuid, Equal>(this->m_member, rhs.m_member);
}

UiaBool UiaGuid::operator!=(const UiaGuid& rhs) const
{
return BinaryOperator<UiaGuid, NotEqual>(this->m_member, rhs.m_member);
}

UiaAnnotationType UiaGuid::LookupAnnotationType()
{
if (ShouldUseRemoteApi())
{
ToRemote();
auto remoteValue = std::get_if<RemoteType>(&m_member);
if (remoteValue)
{
return remoteValue->LookupAnnotationType();
}
}

GUID localValue = std::get<LocalType>(m_member);
return UiaLookupId(AutomationIdentifierType_Annotation, &localValue);
}

UiaPropertyId UiaGuid::LookupPropertyId()
{
if (ShouldUseRemoteApi())
{
ToRemote();
auto remoteValue = std::get_if<RemoteType>(&m_member);
if (remoteValue)
{
return remoteValue->LookupPropertyId();
}
}

GUID localValue = std::get<LocalType>(m_member);
return UiaLookupId(AutomationIdentifierType_Property, &localValue);
}

UiaGuid::operator winrt::guid() const
{
return std::get<winrt::guid>(m_member);
}

void UiaGuid::FromRemoteResult(const winrt::Windows::Foundation::IInspectable& result)
{
m_member = winrt::unbox_value<GUID>(result);
}


namespace impl
{
template <>
Expand Down Expand Up @@ -1008,6 +1083,17 @@ namespace UiaOperationAbstraction
}
}

void UiaOperationDelegator::ConvertVariantDataToRemote(std::variant<winrt::guid,
winrt::Microsoft::UI::UIAutomation::AutomationRemoteGuid>& localGuidVariant) const
{
if (m_useRemoteApi && m_remoteOperation)
{
if (auto localGuid = std::get_if<winrt::guid>(&localGuidVariant))
{
localGuidVariant = m_remoteOperation.NewGuid(*localGuid);
}
}
}


UiaBool::UiaBool(bool value):
Expand Down
21 changes: 21 additions & 0 deletions src/UIAutomation/UiaOperationAbstraction/UiaOperationAbstraction.h
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,9 @@ namespace UiaOperationAbstraction
void ConvertVariantDataToRemote(std::variant<
winrt::com_ptr<IUIAutomationTextRange>,
winrt::Microsoft::UI::UIAutomation::AutomationRemoteTextRange>& localTextRangeVariant) const;
void ConvertVariantDataToRemote(std::variant<
winrt::guid,
winrt::Microsoft::UI::UIAutomation::AutomationRemoteGuid>& localGuidVariant) const;

template <class ItemWrapperType>
void ConvertVariantDataToRemote(std::variant<
Expand Down Expand Up @@ -2180,6 +2183,24 @@ namespace UiaOperationAbstraction
void AddPattern(UiaPatternId patternId);
};

class UiaGuid : public UiaTypeBase<winrt::guid, winrt::Microsoft::UI::UIAutomation::AutomationRemoteGuid>
{
public:
static constexpr auto c_anyTest = &winrt::Microsoft::UI::UIAutomation::AutomationRemoteAnyObject::IsGuid;
static constexpr auto c_anyCast = &winrt::Microsoft::UI::UIAutomation::AutomationRemoteAnyObject::AsGuid;
UiaGuid(const winrt::guid& value);
UiaGuid(winrt::Microsoft::UI::UIAutomation::AutomationRemoteGuid remoteValue);
UiaGuid(winrt::Microsoft::UI::UIAutomation::AutomationRemoteAnyObject remoteValue);
UiaGuid& operator=(const UiaGuid& other);
UiaBool operator==(const UiaGuid& rhs) const;
UiaBool operator!=(const UiaGuid& rhs) const;
UiaAnnotationType LookupAnnotationType();
UiaPropertyId LookupPropertyId();
operator winrt::guid() const;
void FromRemoteResult(const winrt::Windows::Foundation::IInspectable& result);
};


#include "UiaTypeAbstraction.g.h"

class UiaOperationScope;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalDependencies>uiAutomationCore.lib</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
Expand All @@ -116,6 +119,9 @@
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalDependencies>uiAutomationCore.lib</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
Expand All @@ -131,6 +137,9 @@
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalDependencies>uiAutomationCore.lib</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
Expand All @@ -150,6 +159,9 @@
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalDependencies>uiAutomationCore.lib</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
Expand Down Expand Up @@ -194,4 +206,4 @@
<Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.200703.9\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.200703.9\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.200703.9\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.200703.9\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>
</Project>
18 changes: 18 additions & 0 deletions src/UIAutomation/UiaOperationAbstraction/UiaTypeAbstraction.g.h
Original file line number Diff line number Diff line change
Expand Up @@ -2154,6 +2154,24 @@

UiaVariant GetMetadataValue(UiaPropertyId propertyId, UiaMetadata metadataId);

UiaBool IsExtensionSupported(UiaGuid guid);

template<typename... ArgTypes> void CallExtension(UiaGuid guid, ArgTypes&... args)
{
if (UiaOperationAbstraction::ShouldUseRemoteApi())
{
this->ToRemote();
guid.ToRemote();
auto remoteValue = std::get<winrt::Microsoft::UI::UIAutomation::AutomationRemoteElement>(m_member);
(args.ToRemote(),...);
remoteValue.CallExtension(guid, {static_cast<winrt::Microsoft::UI::UIAutomation::AutomationRemoteObject>(args)...});
return;
}

// No local equivalent
throw winrt::hresult_not_implemented();
}

void FromRemoteResult(const winrt::Windows::Foundation::IInspectable& result)
{
m_member = result.as<IUIAutomationElement>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7223,3 +7223,17 @@

return metadataValue;
}

UiaBool UiaElement::IsExtensionSupported(UiaGuid guid)
{
if (UiaOperationAbstraction::ShouldUseRemoteApi())
{
this->ToRemote();
guid.ToRemote();
auto remoteValue = std::get<winrt::Microsoft::UI::UIAutomation::AutomationRemoteElement>(m_member);
return remoteValue.IsExtensionSupported(guid);
}

// No local equivalent
throw winrt::hresult_not_implemented();
}