Merge pull request #558 from CommunityToolkit/user/adpa-ms/lottie_island_uia

Add UIA support
This commit is contained in:
getrou 2024-05-09 10:11:44 -07:00 коммит произвёл GitHub
Родитель 750f44cad4 eac0dc2bf6
Коммит 0945863e88
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
24 изменённых файлов: 1150 добавлений и 54 удалений

Просмотреть файл

@ -14,7 +14,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.0.4" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240404000" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240428000" />
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.0.7" />
</ItemGroup>

Просмотреть файл

@ -17,7 +17,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.0.4" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240404000" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240428000" />
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.0.7" />
</ItemGroup>

Просмотреть файл

@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
#include "AutomationBase.h"
namespace AutomationHelpers
{
void AutomationBase::RemoveHandler(
IAutomationCallbackHandler const* const handler)
{
std::unique_lock lock{ m_mutex };
auto iterator = std::remove_if(
m_handlers.begin(), m_handlers.end(), [handler](auto const& handlerEntry)
{
return handlerEntry.Match(handler);
});
m_handlers.erase(iterator, m_handlers.end());
}
void AutomationBase::AddHandler(
AutomationCallbackHandlerType const& type,
IAutomationCallbackHandler* const handler)
{
// Remove any existing handler of the same type.
auto iterator = std::remove_if(
m_handlers.begin(), m_handlers.end(), [type](auto const& handlerEntry)
{
return handlerEntry.Match(type);
});
m_handlers.erase(iterator, m_handlers.end());
if (nullptr != handler)
{
m_handlers.emplace_back(AutomationCallbackHandlerEntry{ type, handler });
}
}
}

Просмотреть файл

@ -0,0 +1,100 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#include <mutex>
#include "AutomationCallbackHandler.h"
namespace AutomationHelpers
{
struct AutomationBase : winrt::implements<AutomationBase, winrt::Windows::Foundation::IInspectable>
{
[[nodiscard]] winrt::weak_ref<AutomationBase> GetWeak() const noexcept
{
try
{
return const_cast<AutomationBase*>(this)->get_weak();
}
catch (...) {}
return nullptr;
}
template <typename DerivedT>
[[nodiscard]] inline static winrt::com_ptr<DerivedT> LockWeak(
winrt::weak_ref<AutomationBase> const& weakRef) noexcept
{
static_assert(std::is_base_of_v<AutomationBase, DerivedT>);
try
{
if (nullptr != weakRef)
{
winrt::com_ptr<AutomationBase> weakRefGet = weakRef.get();
if (nullptr != weakRefGet)
{
winrt::com_ptr<DerivedT> strongRef{ nullptr };
strongRef.copy_from(static_cast<DerivedT*>(weakRefGet.get()));
return strongRef;
}
}
}
catch (...) {}
return nullptr;
}
template <typename DerivedT>
[[nodiscard]] winrt::com_ptr<DerivedT> GetStrong() const noexcept
{
static_assert(std::is_base_of_v<AutomationBase, DerivedT>);
try
{
return static_cast<DerivedT*>(const_cast<AutomationBase*>(this))->get_strong();
}
catch (...) {}
return nullptr;
}
template <typename DerivedT>
[[nodiscard]] IUnknown* GetIUnknown() const noexcept
{
static_assert(std::is_base_of_v<AutomationBase, DerivedT>);
try
{
return GetStrong<DerivedT>().as<IUnknown>().get();
}
catch (...) {}
return nullptr;
}
void RemoveHandler(
IAutomationCallbackHandler const* const handler);
protected:
void AddHandler(
AutomationCallbackHandlerType const& type,
IAutomationCallbackHandler* const handler);
template <typename HandlerT>
[[nodiscard]] HandlerT* GetHandler(
AutomationCallbackHandlerType const& type) const
{
static_assert(std::is_base_of_v<IAutomationCallbackHandler, HandlerT>);
auto iterator = std::find_if(
m_handlers.cbegin(), m_handlers.cend(), [&type](auto const& handlerEntry)
{
return handlerEntry.Match(type);
});
return (m_handlers.cend() != iterator) ? iterator->Get<HandlerT>() : nullptr;
}
mutable std::mutex m_mutex{};
private:
std::vector<AutomationCallbackHandlerEntry> m_handlers{};
};
}

Просмотреть файл

@ -0,0 +1,75 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#include <UIAutomation.h>
#include <wil/cppwinrt.h>
#include <winrt/Windows.Graphics.h>
namespace AutomationHelpers
{
enum class AutomationCallbackHandlerType : unsigned char
{
None,
Fragment,
FragmentRoot,
Invoke
};
struct IAutomationCallbackHandler
{
virtual ~IAutomationCallbackHandler() noexcept = default;
};
struct IAutomationFragmentCallbackHandler : IAutomationCallbackHandler
{
virtual winrt::Windows::Graphics::RectInt32 GetBoundingRectangleInScreenSpaceForAutomation(
::IUnknown const* const sender) const = 0;
virtual void HandleSetFocusForAutomation(
::IUnknown const* const sender) = 0;
};
struct IAutomationFragmentRootCallbackHandler : IAutomationCallbackHandler
{
virtual winrt::com_ptr<::IRawElementProviderFragment> GetFragmentFromPointForAutomation(
double x,
double y,
::IUnknown const* const sender) const = 0;
virtual winrt::com_ptr<::IRawElementProviderFragment> GetFragmentInFocusForAutomation(
::IUnknown const* const sender) const = 0;
};
struct IAutomationInvokeCallbackHandler : IAutomationCallbackHandler
{
virtual void HandleInvokeForAutomation(
::IUnknown const* const sender) = 0;
};
struct AutomationCallbackHandlerEntry
{
explicit AutomationCallbackHandlerEntry(
AutomationCallbackHandlerType const& type,
IAutomationCallbackHandler* const handler) :
_type{ type }, _handler{ handler } {}
bool Match(
AutomationCallbackHandlerType const& type) const { return type == _type; }
bool Match(
IAutomationCallbackHandler const* const handler) const { return handler == _handler; }
template <typename DerivedT>
DerivedT* Get() const
{
static_assert(std::is_base_of_v<IAutomationCallbackHandler, DerivedT>);
return static_cast<DerivedT*>(_handler);
}
private:
AutomationCallbackHandlerType _type{ AutomationCallbackHandlerType::None };
IAutomationCallbackHandler* _handler{ nullptr };
};
}

Просмотреть файл

@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#include "AutomationBase.h"
namespace AutomationHelpers
{
struct AutomationCallbackRevoker
{
[[nodiscard]] static std::unique_ptr<AutomationCallbackRevoker> Create(
winrt::weak_ref<AutomationBase> const& automationObject,
IAutomationCallbackHandler* const handler) noexcept
{
try
{
auto newRevoker = std::make_unique<AutomationCallbackRevoker>();
newRevoker->Initialize(automationObject, handler);
return newRevoker;
}
catch (...) {}
return nullptr;
}
explicit AutomationCallbackRevoker() noexcept = default;
~AutomationCallbackRevoker() noexcept
{
if (auto strongAutomationObject = _automationObject.get())
{
if (nullptr != _handler)
{
strongAutomationObject->RemoveHandler(_handler);
}
}
}
// Disable move and copy.
explicit AutomationCallbackRevoker(AutomationCallbackRevoker const&) = delete;
explicit AutomationCallbackRevoker(AutomationCallbackRevoker&&) = delete;
AutomationCallbackRevoker& operator=(AutomationCallbackRevoker const&) = delete;
AutomationCallbackRevoker& operator=(AutomationCallbackRevoker&&) = delete;
private:
void Initialize(
winrt::weak_ref<AutomationBase> const& automationObject,
IAutomationCallbackHandler* const handler)
{
_automationObject = automationObject;
_handler = handler;
}
winrt::weak_ref<AutomationBase> _automationObject{ nullptr };
IAutomationCallbackHandler* _handler{ nullptr };
};
}

Просмотреть файл

@ -0,0 +1,116 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
#include "AutomationElement.h"
#include <wil/resource.h>
namespace AutomationHelpers
{
HRESULT __stdcall AutomationElement::get_ProviderOptions(
_Out_ ::ProviderOptions* providerOptions)
{
try
{
std::unique_lock lock{ m_mutex };
if (nullptr != providerOptions)
{
*providerOptions = m_providerOptions;
}
}
catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; }
return S_OK;
}
HRESULT __stdcall AutomationElement::GetPatternProvider(
_In_ PATTERNID patternId,
_COM_Outptr_opt_result_maybenull_ ::IUnknown** patternProvider)
{
try
{
std::unique_lock lock{ m_mutex };
if (nullptr != patternProvider)
{
*patternProvider = nullptr;
switch (patternId)
{
case UIA_InvokePatternId:
{
if (auto invokeProvider = get_strong().try_as<::IInvokeProvider>())
{
invokeProvider.as<::IUnknown>().copy_to(patternProvider);
}
break;
}
}
}
}
catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; }
return S_OK;
}
HRESULT __stdcall AutomationElement::GetPropertyValue(
_In_ PROPERTYID propertyId,
_Out_ VARIANT* propertyValue)
{
try
{
std::unique_lock lock{ m_mutex };
if (nullptr != propertyValue)
{
::VariantInit(propertyValue);
switch (propertyId)
{
case UIA_NamePropertyId:
{
propertyValue->bstrVal = wil::make_bstr(m_name.c_str()).release();
propertyValue->vt = VT_BSTR;
break;
}
case UIA_IsContentElementPropertyId:
{
propertyValue->boolVal = m_isContent ? VARIANT_TRUE : VARIANT_FALSE;
propertyValue->vt = VT_BOOL;
break;
}
case UIA_IsControlElementPropertyId:
{
propertyValue->boolVal = m_isControl ? VARIANT_TRUE : VARIANT_FALSE;
propertyValue->vt = VT_BOOL;
break;
}
case UIA_ControlTypePropertyId:
{
if (m_isControl)
{
propertyValue->vt = VT_I4;
propertyValue->lVal = m_uiaControlTypeId;
}
break;
}
}
}
}
catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; }
return S_OK;
}
HRESULT __stdcall AutomationElement::get_HostRawElementProvider(
_COM_Outptr_opt_result_maybenull_ ::IRawElementProviderSimple** hostRawElementProviderSimple)
{
try
{
std::unique_lock lock{ m_mutex };
if (nullptr != hostRawElementProviderSimple)
{
m_hostProvider.copy_to(hostRawElementProviderSimple);
}
}
catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; }
return S_OK;
}
}

Просмотреть файл

@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#include "AutomationBase.h"
namespace AutomationHelpers
{
struct AutomationElement : winrt::implements<AutomationElement, AutomationBase, ::IRawElementProviderSimple>
{
// Settable properties.
void ProviderOptions(::ProviderOptions const& providerOptions) { std::unique_lock lock{ m_mutex }; m_providerOptions = providerOptions; }
void Name(std::wstring_view const& name) { std::unique_lock lock{ m_mutex }; m_name = name; }
void IsContent(bool const& isContent) { std::unique_lock lock{ m_mutex }; m_isContent = isContent; }
void IsControl(bool const& isControl) { std::unique_lock lock{ m_mutex }; m_isControl = isControl; }
void UiaControlTypeId(long const& uiaControlTypeId) { std::unique_lock lock{ m_mutex }; m_uiaControlTypeId = uiaControlTypeId; }
void HostProvider(winrt::com_ptr<::IRawElementProviderSimple> const& hostProvider) { std::unique_lock lock{ m_mutex }; m_hostProvider = hostProvider; }
// IRawElementProviderSimple implementation.
HRESULT __stdcall get_ProviderOptions(
_Out_ ::ProviderOptions* providerOptions) final override;
HRESULT __stdcall GetPatternProvider(
_In_ PATTERNID patternId,
_COM_Outptr_opt_result_maybenull_ ::IUnknown** patternProvider) final override;
HRESULT __stdcall GetPropertyValue(
_In_ PROPERTYID propertyId,
_Out_ VARIANT* propertyValue) final override;
HRESULT __stdcall get_HostRawElementProvider(
_COM_Outptr_opt_result_maybenull_ ::IRawElementProviderSimple** hostRawElementProviderSimple) final override;
private:
::ProviderOptions m_providerOptions{ ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading };
std::wstring m_name{ L"" };
bool m_isContent{ true };
bool m_isControl{ true };
long m_uiaControlTypeId{ UIA_CustomControlTypeId };
winrt::com_ptr<::IRawElementProviderSimple> m_hostProvider{ nullptr };
};
}

Просмотреть файл

@ -0,0 +1,294 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
#include "AutomationFragment.h"
#include <wil/resource.h>
using unique_safearray = wil::unique_any<SAFEARRAY*, decltype(&::SafeArrayDestroy), ::SafeArrayDestroy>;
namespace AutomationHelpers
{
std::unique_ptr<AutomationCallbackRevoker> AutomationFragment::SetFragmentCallbackHandler(
IAutomationFragmentCallbackHandler* const handler)
{
AddHandler(AutomationCallbackHandlerType::Fragment, handler);
return AutomationCallbackRevoker::Create(GetWeak(), handler);
}
void AutomationFragment::AddChildToEnd(
winrt::com_ptr<AutomationFragment> const& child)
{
std::unique_lock lock{ m_mutex };
if (nullptr == child)
{
// Nothing to do.
return;
}
// The child should not already have a parent.
winrt::check_bool(nullptr == child->Parent());
// Set us up as the parent for the new child.
child->Parent(GetWeak());
// Set up the sibling relationships.
if (!m_children.empty())
{
auto& previousSiblingForNewChild = m_children.back();
previousSiblingForNewChild->NextSibling(child);
child->PreviousSibling(previousSiblingForNewChild);
}
// Finally add the child.
m_children.push_back(child);
}
void AutomationFragment::RemoveChild(
winrt::com_ptr<AutomationFragment> const& child)
{
std::unique_lock lock{ m_mutex };
if (nullptr == child)
{
// Nothing to do.
return;
}
auto iterator = std::find_if(
m_children.begin(), m_children.end(), [&child](auto const& childEntry)
{
// See if we find a matching child entry in our children.
return (childEntry.as<::IUnknown>().get() == child.as<::IUnknown>().get());
});
// We cannot remove a child that isn't ours.
winrt::check_bool(m_children.end() != iterator);
// Remove us from the parent relationship with the child.
child->Parent(nullptr);
// Reset the sibling relationships.
auto previousSibling = child->PreviousSibling();
auto nextSibling = child->NextSibling();
if (nullptr != previousSibling)
{
previousSibling->NextSibling(nextSibling);
}
if (nullptr != nextSibling)
{
nextSibling->PreviousSibling(previousSibling);
}
child->PreviousSibling(nullptr);
child->NextSibling(nullptr);
// Finally, remove the child.
m_children.erase(iterator);
}
void AutomationFragment::RemoveAllChildren()
{
std::unique_lock lock{ m_mutex };
for (auto& child : m_children)
{
// Disconnect the relationships from all our children.
child->Parent(nullptr);
child->PreviousSibling(nullptr);
child->NextSibling(nullptr);
}
// Remove all the children.
m_children.clear();
}
HRESULT __stdcall AutomationFragment::Navigate(
_In_ NavigateDirection direction,
_COM_Outptr_opt_result_maybenull_ IRawElementProviderFragment** fragment)
{
try
{
std::unique_lock lock{ m_mutex };
if (nullptr != fragment)
{
*fragment = nullptr;
switch (direction)
{
case NavigateDirection_Parent:
{
if (auto strongParent = LockWeak<AutomationFragment>(m_parent))
{
strongParent.as<IRawElementProviderFragment>().copy_to(fragment);
}
break;
}
case NavigateDirection_NextSibling:
{
if (auto strongSibling = LockWeak<AutomationFragment>(m_nextSibling))
{
strongSibling.as<IRawElementProviderFragment>().copy_to(fragment);
}
break;
}
case NavigateDirection_PreviousSibling:
{
if (auto strongSibling = LockWeak<AutomationFragment>(m_previousSibling))
{
strongSibling.as<IRawElementProviderFragment>().copy_to(fragment);
}
break;
}
case NavigateDirection_FirstChild:
{
if (!m_children.empty())
{
m_children.front().as<IRawElementProviderFragment>().copy_to(fragment);
}
break;
}
case NavigateDirection_LastChild:
{
if (!m_children.empty())
{
m_children.back().as<IRawElementProviderFragment>().copy_to(fragment);
}
break;
}
}
}
}
catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; }
return S_OK;
}
HRESULT __stdcall AutomationFragment::GetRuntimeId(
_Outptr_opt_result_maybenull_ SAFEARRAY** runtimeId)
{
try
{
std::unique_lock lock{ m_mutex };
if (nullptr != runtimeId)
{
*runtimeId = nullptr;
unsigned long arraySizeAsUnsignedLong = static_cast<unsigned long>(m_runtimeId.size());
unique_safearray runtimeIdArray{ ::SafeArrayCreateVector(VT_I4, 0, arraySizeAsUnsignedLong) };
SAFEARRAY* rawPointerToSafeArray = runtimeIdArray.get();
winrt::check_pointer(rawPointerToSafeArray);
for (long i = 0; i < static_cast<long>(arraySizeAsUnsignedLong); ++i)
{
winrt::check_hresult(::SafeArrayPutElement(rawPointerToSafeArray, &i, &(m_runtimeId[i])));
}
*runtimeId = runtimeIdArray.release();
}
}
catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; }
return S_OK;
}
HRESULT __stdcall AutomationFragment::get_BoundingRectangle(
_Out_ UiaRect* boundingRectangle)
{
try
{
std::unique_lock lock{ m_mutex };
if (nullptr != boundingRectangle)
{
*boundingRectangle = { 0, 0, 0, 0 };
if (auto handler = GetHandler<IAutomationFragmentCallbackHandler>(AutomationCallbackHandlerType::Fragment))
{
auto screenRectangle =
handler->GetBoundingRectangleInScreenSpaceForAutomation(GetIUnknown<AutomationFragment>());
boundingRectangle->left = screenRectangle.X;
boundingRectangle->top = screenRectangle.Y;
boundingRectangle->width = screenRectangle.Width;
boundingRectangle->height = screenRectangle.Height;
}
}
}
catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; }
return S_OK;
}
HRESULT __stdcall AutomationFragment::GetEmbeddedFragmentRoots(
_Outptr_opt_result_maybenull_ SAFEARRAY** embeddedFragmentRoots)
{
try
{
std::unique_lock lock{ m_mutex };
if (nullptr != embeddedFragmentRoots)
{
*embeddedFragmentRoots = nullptr;
if (!m_embeddedFragments.empty())
{
unsigned long vectorSizeAsUnsignedLong = static_cast<unsigned long>(m_embeddedFragments.size());
unique_safearray embeddedFragmentRootsArray{ ::SafeArrayCreateVector(VT_UNKNOWN, 0, vectorSizeAsUnsignedLong) };
SAFEARRAY* rawPointerToSafeArray = embeddedFragmentRootsArray.get();
winrt::check_pointer(rawPointerToSafeArray);
for (long i = 0; i < static_cast<long>(vectorSizeAsUnsignedLong); ++i)
{
winrt::check_hresult(::SafeArrayPutElement(rawPointerToSafeArray, &i, m_embeddedFragments.at(i).as<::IUnknown>().get()));
}
*embeddedFragmentRoots = embeddedFragmentRootsArray.release();
}
}
}
catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; }
return S_OK;
}
HRESULT __stdcall AutomationFragment::SetFocus()
{
try
{
std::unique_lock lock{ m_mutex };
if (auto handler = GetHandler<IAutomationFragmentCallbackHandler>(AutomationCallbackHandlerType::Fragment))
{
handler->HandleSetFocusForAutomation(GetIUnknown<AutomationFragment>());
}
}
catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; }
return S_OK;
}
HRESULT __stdcall AutomationFragment::get_FragmentRoot(
_COM_Outptr_opt_result_maybenull_ IRawElementProviderFragmentRoot** fragmentRoot)
{
try
{
std::unique_lock lock{ m_mutex };
if (nullptr != fragmentRoot)
{
*fragmentRoot = nullptr;
// Walk up our fragment tree until we find our fragment root.
auto fragmentRootCandidate = GetStrong<AutomationFragment>();
bool currentCandidateIsThisObject = true;
while (nullptr != fragmentRootCandidate && nullptr == fragmentRootCandidate.try_as<IRawElementProviderFragmentRoot>())
{
// Haven't found the fragment root yet, keep walking up our tree.
fragmentRootCandidate = currentCandidateIsThisObject ? LockWeak<AutomationFragment>(m_parent) : fragmentRootCandidate->Parent();
currentCandidateIsThisObject = false;
}
if (nullptr != fragmentRootCandidate)
{
// Found the fragment root, return it.
fragmentRootCandidate.as<IRawElementProviderFragmentRoot>().copy_to(fragmentRoot);
}
}
}
catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; }
return S_OK;
}
}

Просмотреть файл

@ -0,0 +1,68 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#include "AutomationElement.h"
#include "AutomationCallbackRevoker.h"
namespace AutomationHelpers
{
struct AutomationFragment : winrt::implements<AutomationFragment, AutomationElement, ::IRawElementProviderFragment>
{
// Automation callback handler.
[[nodiscard]] std::unique_ptr<AutomationCallbackRevoker> SetFragmentCallbackHandler(
IAutomationFragmentCallbackHandler* const handler);
// Methods.
void AddChildToEnd(
winrt::com_ptr<AutomationFragment> const& child);
void RemoveChild(
winrt::com_ptr<AutomationFragment> const& child);
void RemoveAllChildren();
// IRawElementProviderFragment implementation.
HRESULT __stdcall Navigate(
_In_ NavigateDirection direction,
_COM_Outptr_opt_result_maybenull_ ::IRawElementProviderFragment** fragment) final override;
HRESULT __stdcall GetRuntimeId(
_Outptr_opt_result_maybenull_ SAFEARRAY** runtimeId) final override;
HRESULT __stdcall get_BoundingRectangle(
_Out_ UiaRect* boundingRectangle) final override;
HRESULT __stdcall GetEmbeddedFragmentRoots(
_Outptr_opt_result_maybenull_ SAFEARRAY** embeddedFragmentRoots) final override;
HRESULT __stdcall SetFocus() final override;
HRESULT __stdcall get_FragmentRoot(
_COM_Outptr_opt_result_maybenull_ ::IRawElementProviderFragmentRoot** fragmentRoot) final override;
private:
// Property setters.
void Parent(winrt::weak_ref<AutomationBase> const& parent) { std::unique_lock lock{ m_mutex }; m_parent = parent; }
void PreviousSibling(winrt::weak_ref<AutomationBase> const& previousSibling) { std::unique_lock lock{ m_mutex }; m_previousSibling = previousSibling; }
void NextSibling(winrt::weak_ref<AutomationBase> const& nextSibling) { std::unique_lock lock{ m_mutex }; m_nextSibling = nextSibling; }
// Property getters.
winrt::com_ptr<AutomationFragment> Parent() const { std::unique_lock lock{ m_mutex }; return LockWeak<AutomationFragment>(m_parent); }
winrt::com_ptr<AutomationFragment> PreviousSibling() const { std::unique_lock lock{ m_mutex }; return LockWeak<AutomationFragment>(m_previousSibling); }
winrt::com_ptr<AutomationFragment> NextSibling() const { std::unique_lock lock{ m_mutex }; return LockWeak<AutomationFragment>(m_nextSibling); }
int* RuntimeId() { std::unique_lock lock{ m_mutex }; return reinterpret_cast<int*>(&(m_runtimeId[0])); }
int RuntimeIdSize() const { std::unique_lock lock{ m_mutex }; return static_cast<int>(m_runtimeId.size()); }
// Automatically generate unique runtime IDs per fragment.
inline static unsigned __int32 s_nextAvailableInternalRuntimeId{ 0 };
std::array<unsigned __int32, 2> m_runtimeId{ UiaAppendRuntimeId, ++s_nextAvailableInternalRuntimeId };
winrt::weak_ref<AutomationBase> m_parent{ nullptr };
winrt::weak_ref<AutomationBase> m_previousSibling{ nullptr };
winrt::weak_ref<AutomationBase> m_nextSibling{ nullptr };
std::vector<winrt::com_ptr<AutomationFragment>> m_children{};
std::vector<winrt::com_ptr<AutomationFragment>> m_embeddedFragments{};
};
}

Просмотреть файл

@ -0,0 +1,56 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
#include "AutomationFragmentRoot.h"
namespace AutomationHelpers
{
std::unique_ptr<AutomationCallbackRevoker> AutomationFragmentRoot::SetFragmentRootCallbackHandler(
IAutomationFragmentRootCallbackHandler* const handler)
{
AddHandler(AutomationCallbackHandlerType::FragmentRoot, handler);
return AutomationCallbackRevoker::Create(GetWeak(), handler);
}
HRESULT __stdcall AutomationFragmentRoot::ElementProviderFromPoint(
_In_ double x,
_In_ double y,
_COM_Outptr_opt_result_maybenull_ ::IRawElementProviderFragment** fragment)
{
try
{
std::unique_lock lock{ m_mutex };
if (nullptr != fragment)
{
*fragment = nullptr;
if (auto handler = GetHandler<IAutomationFragmentRootCallbackHandler>(AutomationCallbackHandlerType::FragmentRoot))
{
handler->GetFragmentFromPointForAutomation(x, y, GetIUnknown<AutomationFragmentRoot>()).copy_to(fragment);
}
}
}
catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; }
return S_OK;
}
HRESULT __stdcall AutomationFragmentRoot::GetFocus(
_COM_Outptr_opt_result_maybenull_ ::IRawElementProviderFragment** fragmentInFocus)
{
try
{
std::unique_lock lock{ m_mutex };
if (nullptr != fragmentInFocus)
{
*fragmentInFocus = nullptr;
if (auto handler = GetHandler<IAutomationFragmentRootCallbackHandler>(AutomationCallbackHandlerType::FragmentRoot))
{
handler->GetFragmentInFocusForAutomation(GetIUnknown<AutomationFragmentRoot>()).copy_to(fragmentInFocus);
}
}
}
catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; }
return S_OK;
}
}

Просмотреть файл

@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#include "AutomationFragment.h"
namespace AutomationHelpers
{
struct AutomationFragmentRoot : winrt::implements<AutomationFragmentRoot, AutomationFragment, ::IRawElementProviderFragmentRoot>
{
// Automation callback handler.
[[nodiscard]] std::unique_ptr<AutomationCallbackRevoker> SetFragmentRootCallbackHandler(
IAutomationFragmentRootCallbackHandler* const handler);
// IRawElementProviderFragmentRoot implementation.
HRESULT __stdcall ElementProviderFromPoint(
_In_ double x,
_In_ double y,
_COM_Outptr_opt_result_maybenull_ ::IRawElementProviderFragment** fragment) final override;
HRESULT __stdcall GetFocus(
_COM_Outptr_opt_result_maybenull_ ::IRawElementProviderFragment** fragmentInFocus) final override;
};
}

Просмотреть файл

@ -15,7 +15,9 @@ namespace winrt::CommunityToolkit::WinAppSDK::LottieIsland::implementation
{
m_rootVisual = m_compositor.CreateContainerVisual();
m_island = winrt::ContentIsland::Create(m_rootVisual);
m_island.AppData(get_strong().as<winrt::Windows::Foundation::IInspectable>());
m_island.AutomationProviderRequested({ get_weak(), &LottieContentIsland::OnIslandAutomationProviderRequested });
m_island.StateChanged({ get_weak(), &LottieContentIsland::OnIslandStateChanged });
// Once it's not experimental, we should use InputPointerSource::GetForVisual on our root visual.
@ -165,6 +167,48 @@ namespace winrt::CommunityToolkit::WinAppSDK::LottieIsland::implementation
StopAnimation();
}
winrt::Windows::Graphics::RectInt32 LottieContentIsland::GetBoundingRectangleInScreenSpaceForAutomation(
::IUnknown const* const /*sender*/) const
{
// Convert our local bounds to screen space and return it to UI Automation.
auto coordinateConverter = m_island.CoordinateConverter();
auto actualSize = m_island.ActualSize();
winrt::Windows::Foundation::Rect islandLocalBounds{ 0, 0, actualSize.x, actualSize.y };
auto islandScreenBounds = coordinateConverter.ConvertLocalToScreen(islandLocalBounds);
return islandScreenBounds;
}
void LottieContentIsland::HandleSetFocusForAutomation(
::IUnknown const* const /*sender*/)
{
// No-op.
}
winrt::com_ptr<::IRawElementProviderFragment> LottieContentIsland::GetFragmentFromPointForAutomation(
double /*x*/,
double /*y*/,
::IUnknown const* const /*sender*/) const
{
// No child automation fragments.
return nullptr;
}
winrt::com_ptr<::IRawElementProviderFragment> LottieContentIsland::GetFragmentInFocusForAutomation(
::IUnknown const* const /*sender*/) const
{
// No child automation fragments.
return nullptr;
}
void LottieContentIsland::HandleInvokeForAutomation(
::IUnknown const* const /*sender*/)
{
if (nullptr != m_animatedVisual)
{
IsPlaying() ? StopAnimation() : StartAnimation(0.0f, 1.0f, false);
}
}
void LottieContentIsland::StartAnimation(float fromProgress, float toProgress, bool loop)
{
if (m_animatedVisual == nullptr)
@ -217,6 +261,30 @@ namespace winrt::CommunityToolkit::WinAppSDK::LottieIsland::implementation
m_progressPropertySet = nullptr;
}
void LottieContentIsland::OnIslandAutomationProviderRequested(
const winrt::ContentIsland& island,
const winrt::ContentIslandAutomationProviderRequestedEventArgs& args)
{
if (nullptr == m_automationProvider)
{
// We need to create the automation provider.
m_automationProvider = winrt::make_self<LottieIslandInternal::LottieIslandAutomationProvider>();
m_automationProvider->Name(L"Lottie");
// Register ourselves as the callback for our automation provider.
m_fragmentCallbackRevoker = m_automationProvider->SetFragmentCallbackHandler(this);
m_fragmentRootCallbackRevoker = m_automationProvider->SetFragmentRootCallbackHandler(this);
m_invokeCallbackRevoker = m_automationProvider->SetInvokeCallbackHandler(this);
// Set up the host provider.
auto hostProviderAsIInspectable = island.GetAutomationHostProvider();
m_automationProvider->HostProvider(hostProviderAsIInspectable.try_as<::IRawElementProviderSimple>());
}
args.AutomationProvider(m_automationProvider.as<IInspectable>());
args.Handled(true);
}
void LottieContentIsland::OnIslandStateChanged(const winrt::ContentIsland& /*island*/, const winrt::ContentIslandStateChangedEventArgs& args)
{
if (args.DidActualSizeChange() && IsAnimationLoaded())

Просмотреть файл

@ -2,6 +2,7 @@
#include "LottieContentIsland.g.h"
#include "winrt/CommunityToolkit.WinAppSDK.LottieIsland.h"
#include "LottieIslandAutomationProvider.h"
namespace winrt
{
@ -10,7 +11,10 @@ namespace winrt
namespace winrt::CommunityToolkit::WinAppSDK::LottieIsland::implementation
{
struct LottieContentIsland : LottieContentIslandT<LottieContentIsland>
struct LottieContentIsland : LottieContentIslandT<LottieContentIsland>,
AutomationHelpers::IAutomationFragmentCallbackHandler,
AutomationHelpers::IAutomationFragmentRootCallbackHandler,
AutomationHelpers::IAutomationInvokeCallbackHandler
{
using PointerEventHandler = Windows::Foundation::TypedEventHandler<winrt::LottieContentIsland, winrt::PointerEventArgs>;
@ -59,10 +63,29 @@ namespace winrt::CommunityToolkit::WinAppSDK::LottieIsland::implementation
void Stop();
// UI Automation callback implementation.
winrt::Windows::Graphics::RectInt32 GetBoundingRectangleInScreenSpaceForAutomation(
::IUnknown const* const sender) const final override;
void HandleSetFocusForAutomation(
::IUnknown const* const sender) final override;
winrt::com_ptr<::IRawElementProviderFragment> GetFragmentFromPointForAutomation(
double x,
double y,
::IUnknown const* const sender) const final override;
winrt::com_ptr<::IRawElementProviderFragment> GetFragmentInFocusForAutomation(
::IUnknown const* const sender) const final override;
void HandleInvokeForAutomation(
::IUnknown const* const sender) final override;
private:
void StartAnimation(float fromProgress, float toProgress, bool loop);
void StopAnimation();
void OnIslandAutomationProviderRequested(const winrt::ContentIsland& island, const winrt::ContentIslandAutomationProviderRequestedEventArgs& args);
void OnIslandStateChanged(const winrt::ContentIsland& island, const winrt::ContentIslandStateChangedEventArgs& args);
void Resize(const float2& size);
@ -75,6 +98,12 @@ namespace winrt::CommunityToolkit::WinAppSDK::LottieIsland::implementation
winrt::event<PointerEventHandler> m_pointerPressedEvent;
winrt::event<PointerEventHandler> m_pointerReleasedEvent;
// UI Automation.
winrt::com_ptr<LottieIslandInternal::LottieIslandAutomationProvider> m_automationProvider{ nullptr };
std::unique_ptr<AutomationHelpers::AutomationCallbackRevoker> m_fragmentCallbackRevoker{ nullptr };
std::unique_ptr<AutomationHelpers::AutomationCallbackRevoker> m_fragmentRootCallbackRevoker{ nullptr };
std::unique_ptr<AutomationHelpers::AutomationCallbackRevoker> m_invokeCallbackRevoker{ nullptr };
winrt::Compositor m_compositor{ nullptr };
winrt::ContainerVisual m_rootVisual{ nullptr };
winrt::ContentIsland m_island{ nullptr };

Просмотреть файл

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Microsoft.WindowsAppSDK.1.5.240428000\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\packages\Microsoft.WindowsAppSDK.1.5.240428000\build\native\Microsoft.WindowsAppSDK.props')" />
<Import Project="..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.props" Condition="Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.props')" />
<Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.props')" />
<Import Project="..\packages\Microsoft.WindowsAppSDK.1.5.240227000\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\packages\Microsoft.WindowsAppSDK.1.5.240227000\build\native\Microsoft.WindowsAppSDK.props')" />
<Import Project="..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.props" Condition="Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.props')" />
<PropertyGroup Label="Globals">
<CppWinRTOptimized>true</CppWinRTOptimized>
<CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>
@ -115,12 +115,24 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="AutomationBase.h" />
<ClInclude Include="AutomationCallbackHandler.h" />
<ClInclude Include="AutomationCallbackRevoker.h" />
<ClInclude Include="AutomationElement.h" />
<ClInclude Include="AutomationFragment.h" />
<ClInclude Include="AutomationFragmentRoot.h" />
<ClInclude Include="LottieIslandAutomationProvider.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="LottieContentIsland.h">
<DependentUpon>CommunityToolkit.WinAppSDK.LottieIsland.idl</DependentUpon>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="AutomationBase.cpp" />
<ClCompile Include="AutomationElement.cpp" />
<ClCompile Include="AutomationFragment.cpp" />
<ClCompile Include="AutomationFragmentRoot.cpp" />
<ClCompile Include="LottieIslandAutomationProvider.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
@ -145,20 +157,22 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.targets')" />
<Import Project="..\packages\Microsoft.WindowsAppSDK.1.5.240227000\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\packages\Microsoft.WindowsAppSDK.1.5.240227000\build\native\Microsoft.WindowsAppSDK.targets')" />
<Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.targets')" />
<Import Project="..\packages\Microsoft.WindowsAppSDK.1.5.240428000\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\packages\Microsoft.WindowsAppSDK.1.5.240428000\build\native\Microsoft.WindowsAppSDK.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.props'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.WindowsAppSDK.1.5.240227000\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.WindowsAppSDK.1.5.240227000\build\native\Microsoft.WindowsAppSDK.props'))" />
<Error Condition="!Exists('..\packages\Microsoft.WindowsAppSDK.1.5.240227000\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.WindowsAppSDK.1.5.240227000\build\native\Microsoft.WindowsAppSDK.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.props'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.WindowsAppSDK.1.5.240428000\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.WindowsAppSDK.1.5.240428000\build\native\Microsoft.WindowsAppSDK.props'))" />
<Error Condition="!Exists('..\packages\Microsoft.WindowsAppSDK.1.5.240428000\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.WindowsAppSDK.1.5.240428000\build\native\Microsoft.WindowsAppSDK.targets'))" />
</Target>
<Target Name="Pack">
<!-- Dummy target to mute warnings about attempts to create a NuPkg -->

Просмотреть файл

@ -11,20 +11,56 @@
<Filter Include="Assets">
<UniqueIdentifier>{8de2e0c6-cc70-4b56-a68f-dd3ec76ce5fc}</UniqueIdentifier>
</Filter>
<Filter Include="Automation">
<UniqueIdentifier>{f244735f-9786-4673-9823-f1b890d98b19}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp" />
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="AutomationBase.cpp">
<Filter>Automation</Filter>
</ClCompile>
<ClCompile Include="AutomationElement.cpp">
<Filter>Automation</Filter>
</ClCompile>
<ClCompile Include="AutomationFragment.cpp">
<Filter>Automation</Filter>
</ClCompile>
<ClCompile Include="AutomationFragmentRoot.cpp">
<Filter>Automation</Filter>
</ClCompile>
<ClCompile Include="LottieIslandAutomationProvider.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="AutomationBase.h">
<Filter>Automation</Filter>
</ClInclude>
<ClInclude Include="AutomationCallbackHandler.h">
<Filter>Automation</Filter>
</ClInclude>
<ClInclude Include="AutomationCallbackRevoker.h">
<Filter>Automation</Filter>
</ClInclude>
<ClInclude Include="AutomationElement.h">
<Filter>Automation</Filter>
</ClInclude>
<ClInclude Include="AutomationFragment.h">
<Filter>Automation</Filter>
</ClInclude>
<ClInclude Include="AutomationFragmentRoot.h">
<Filter>Automation</Filter>
</ClInclude>
<ClInclude Include="LottieIslandAutomationProvider.h" />
</ItemGroup>
<ItemGroup>
<Midl Include="CommunityToolkit.WinAppSDK.LottieIsland.idl" />
</ItemGroup>
<ItemGroup>
<None Include="LottieIsland.def" />
<None Include="packages.config" />
<None Include="CommunityToolkit.WinAppSDK.LottieIsland.def" />
<None Include="Directory.Build.props" />
</ItemGroup>
<ItemGroup>
<None Include="PropertySheet.props" />
@ -32,4 +68,7 @@
<ItemGroup>
<Text Include="readme.txt" />
</ItemGroup>
<ItemGroup>
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,33 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
#include "LottieIslandAutomationProvider.h"
namespace LottieIslandInternal
{
std::unique_ptr<AutomationHelpers::AutomationCallbackRevoker> LottieIslandAutomationProvider::SetInvokeCallbackHandler(
AutomationHelpers::IAutomationInvokeCallbackHandler* const handler)
{
AddHandler(AutomationHelpers::AutomationCallbackHandlerType::Invoke, handler);
return AutomationHelpers::AutomationCallbackRevoker::Create(GetWeak(), handler);
}
HRESULT __stdcall LottieIslandAutomationProvider::Invoke()
{
try
{
std::unique_lock lock{ m_mutex };
if (auto handler = GetHandler<AutomationHelpers::IAutomationInvokeCallbackHandler>(
AutomationHelpers::AutomationCallbackHandlerType::Invoke))
{
handler->HandleInvokeForAutomation(GetIUnknown<LottieIslandAutomationProvider>());
}
}
catch (...) { return UIA_E_ELEMENTNOTAVAILABLE; }
return S_OK;
}
}

Просмотреть файл

@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#include "AutomationFragmentRoot.h"
namespace LottieIslandInternal
{
struct LottieIslandAutomationProvider : winrt::implements<LottieIslandAutomationProvider, AutomationHelpers::AutomationFragmentRoot, ::IInvokeProvider>
{
// Automation callback handler.
[[nodiscard]] std::unique_ptr<AutomationHelpers::AutomationCallbackRevoker> SetInvokeCallbackHandler(
AutomationHelpers::IAutomationInvokeCallbackHandler* const handler);
// IInvokeProvider implementation.
HRESULT __stdcall Invoke() final override;
};
}

Просмотреть файл

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.240405.15" targetFramework="native" />
<package id="Microsoft.Windows.SDK.BuildTools" version="10.0.22621.756" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.5.240227000" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.240122.1" targetFramework="native" />
<package id="Microsoft.Windows.SDK.BuildTools" version="10.0.22621.3233" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.5.240428000" targetFramework="native" />
</packages>

Просмотреть файл

@ -21,11 +21,11 @@
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\LottieIsland\LottieIsland.vcxproj"/>
<ProjectReference Include="..\LottieIsland\LottieIsland.vcxproj" />
<!-- <CSWinRTInputs Include="$(PkgMicrosoft_WinUI)\lib\uap10.0\*.winmd" /> -->
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.0.7" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240404000" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240428000" />
</ItemGroup>
</Project>

Просмотреть файл

@ -19,13 +19,13 @@
<ItemGroup>
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.0.7" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240404000" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.756" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240428000" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.3233" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Lottie-Windows\Lottie-Windows-WinUI3\Lottie-Windows-WinUI3.csproj" PrivateAssets="All" />
<ProjectReference Include="..\LottieIslandProjection\LottieIslandProjection.csproj" PrivateAssets="All"/>
<ProjectReference Include="..\LottieIslandProjection\LottieIslandProjection.csproj" PrivateAssets="All" />
</ItemGroup>
<PropertyGroup>
@ -33,7 +33,7 @@
</PropertyGroup>
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences">
<ItemGroup>
<BuildOutputInPackage Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference'))" />
<BuildOutputInPackage Include="@(ReferenceCopyLocalPaths-&gt;WithMetadataValue('ReferenceSourceTarget', 'ProjectReference'))" />
</ItemGroup>
</Target>

Просмотреть файл

@ -36,7 +36,7 @@ struct WindowInfo
winrt::DesktopChildSiteBridge Bridge{ nullptr };
winrt::event_token TakeFocusRequestedToken{};
HWND LastFocusedWindow{ NULL };
winrt::LottieContentIsland LottieIsland{ nullptr };
winrt::ContentIsland Island{ nullptr };
bool isPaused = false;
};
@ -197,30 +197,38 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
windowInfo->Compositor,
winrt::GetWindowIdFromWindow(hWnd));
// Create the LottieIsland, which is a WinRT wrapper for hosting a Lottie animation in a ContentIsland
windowInfo->LottieIsland = winrt::LottieContentIsland::Create(windowInfo->Compositor);
// Create the LottieIsland, which is a WinRT wrapper for hosting
// a Lottie animation in a ContentIsland
auto lottieIsland = winrt::LottieContentIsland::Create(windowInfo->Compositor);
windowInfo->Island = lottieIsland.Island();
// Connect the ContentIsland to the DesktopChildSiteBridge
windowInfo->Bridge.Connect(windowInfo->LottieIsland.Island());
windowInfo->Bridge.Connect(windowInfo->Island);
windowInfo->Bridge.Show();
winrt::LottieVisualSourceWinRT lottieVisualSource = winrt::LottieVisualSourceWinRT::CreateFromString(L"ms-appx:///LottieLogo1.json");
lottieVisualSource.AnimatedVisualInvalidated([hWnd, windowInfo, lottieVisualSource](const winrt::IInspectable&, auto&&)
winrt::LottieVisualSourceWinRT lottieVisualSource =
winrt::LottieVisualSourceWinRT::CreateFromString(L"ms-appx:///LottieLogo1.json");
lottieVisualSource.AnimatedVisualInvalidated(
[hWnd, lottieIsland, lottieVisualSource, windowInfo](auto&&, auto&&)
{
windowInfo->Compositor.DispatcherQueue().TryEnqueue([hWnd, windowInfo, lottieVisualSource]()
windowInfo->Compositor.DispatcherQueue().TryEnqueue(
[hWnd, lottieIsland, lottieVisualSource, windowInfo]()
{
winrt::Windows::Foundation::IInspectable diagnostics;
winrt::IAnimatedVisualFrameworkless animatedVisual = lottieVisualSource.TryCreateAnimatedVisual(windowInfo->Compositor, diagnostics);
windowInfo->LottieIsland.AnimatedVisual(animatedVisual.as<winrt::IAnimatedVisualFrameworkless>());
winrt::IAnimatedVisualFrameworkless animatedVisual =
lottieVisualSource.TryCreateAnimatedVisual(windowInfo->Compositor, diagnostics);
lottieIsland.AnimatedVisual(
animatedVisual.as<winrt::IAnimatedVisualFrameworkless>());
// Resize bridge
RECT rect;
GetClientRect(hWnd, &rect);
LayoutBridge(windowInfo, rect.right - rect.left, rect.bottom-rect.top);
LayoutBridge(windowInfo, rect.right - rect.left, rect.bottom - rect.top);
});
});
windowInfo->LottieIsland.PointerPressed([=](auto&...) {
lottieIsland.PointerPressed([=](auto&...) {
// Clicking on the Lottie animation acts like clicking "Pause/Resume"
OnButtonClicked(ButtonType::PauseButton, windowInfo, hWnd);
});
@ -303,6 +311,11 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
}
break;
case WM_DESTROY:
if (nullptr != windowInfo && nullptr != windowInfo->Island)
{
// Must close the ContentIsland so that it will release the reference to its AppData.
windowInfo->Island.Close();
}
PostQuitMessage(0);
break;
case WM_NCDESTROY:
@ -394,10 +407,14 @@ void CreateWin32Button(ButtonType type, const std::wstring_view& text, HWND pare
void OnButtonClicked(ButtonType type, WindowInfo* windowInfo, HWND topLevelWindow)
{
winrt::Windows::Foundation::IAsyncAction asyncAction{ nullptr };
// We can retrieve the Lottie-specific functionality from the LottieContentIsland via its AppData.
winrt::LottieContentIsland lottieIsland{ windowInfo->Island.AppData().as<winrt::LottieContentIsland>() };
switch (type)
{
case ButtonType::PlayButton:
asyncAction = windowInfo->LottieIsland.PlayAsync(0.0, 1.0, true);
case ButtonType::PlayButton:
asyncAction = lottieIsland.PlayAsync(0.0, 1.0, true);
asyncAction.Completed([](auto&&, auto&& asyncStatus)
{
// Check if the async operation was successfully completed
@ -417,26 +434,26 @@ void OnButtonClicked(ButtonType type, WindowInfo* windowInfo, HWND topLevelWindo
case ButtonType::PauseButton:
if (windowInfo->isPaused)
{
windowInfo->LottieIsland.Resume();
lottieIsland.Resume();
}
else
{
windowInfo->LottieIsland.Pause();
lottieIsland.Pause();
}
SetPauseState(windowInfo, !windowInfo->isPaused, topLevelWindow);
break;
case ButtonType::StopButton:
windowInfo->LottieIsland.Stop();
lottieIsland.Stop();
SetPauseState(windowInfo, false, topLevelWindow);
break;
case ButtonType::ReverseButton:
if (windowInfo->LottieIsland.PlaybackRate() == 1.0)
if (lottieIsland.PlaybackRate() == 1.0)
{
windowInfo->LottieIsland.PlaybackRate(-1.0);
lottieIsland.PlaybackRate(-1.0);
}
else
{
windowInfo->LottieIsland.PlaybackRate(1.0);
lottieIsland.PlaybackRate(1.0);
}
break;
default:

Просмотреть файл

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.props" Condition="Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.props')" />
<Import Project="..\packages\Microsoft.WindowsAppSDK.1.5.240227000\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\packages\Microsoft.WindowsAppSDK.1.5.240227000\build\native\Microsoft.WindowsAppSDK.props')" />
<Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.230706.1\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.230706.1\build\native\Microsoft.Windows.CppWinRT.props')" />
<Import Project="..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.props" Condition="Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.props')" />
<Import Project="..\packages\Microsoft.WindowsAppSDK.1.5.240428000\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\packages\Microsoft.WindowsAppSDK.1.5.240428000\build\native\Microsoft.WindowsAppSDK.props')" />
<Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
@ -192,10 +192,10 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.230706.1\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.230706.1\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="..\packages\Microsoft.WindowsAppSDK.1.5.240227000\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\packages\Microsoft.WindowsAppSDK.1.5.240227000\build\native\Microsoft.WindowsAppSDK.targets')" />
<Import Project="..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.targets')" />
<Import Project="..\packages\Microsoft.Graphics.Win2D.1.2.0\build\native\Microsoft.Graphics.Win2D.targets" Condition="Exists('..\packages\Microsoft.Graphics.Win2D.1.2.0\build\native\Microsoft.Graphics.Win2D.targets')" />
<Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="..\packages\Microsoft.WindowsAppSDK.1.5.240428000\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\packages\Microsoft.WindowsAppSDK.1.5.240428000\build\native\Microsoft.WindowsAppSDK.targets')" />
<Import Project="..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.targets')" />
</ImportGroup>
<Target Name="Pack">
<!-- Dummy target to mute warnings about attempts to create a NuPkg -->
@ -204,12 +204,12 @@
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.230706.1\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.230706.1\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.230706.1\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.230706.1\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.WindowsAppSDK.1.5.240227000\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.WindowsAppSDK.1.5.240227000\build\native\Microsoft.WindowsAppSDK.props'))" />
<Error Condition="!Exists('..\packages\Microsoft.WindowsAppSDK.1.5.240227000\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.WindowsAppSDK.1.5.240227000\build\native\Microsoft.WindowsAppSDK.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.props'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.756\build\Microsoft.Windows.SDK.BuildTools.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.Graphics.Win2D.1.2.0\build\native\Microsoft.Graphics.Win2D.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Graphics.Win2D.1.2.0\build\native\Microsoft.Graphics.Win2D.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.240405.15\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.WindowsAppSDK.1.5.240428000\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.WindowsAppSDK.1.5.240428000\build\native\Microsoft.WindowsAppSDK.props'))" />
<Error Condition="!Exists('..\packages\Microsoft.WindowsAppSDK.1.5.240428000\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.WindowsAppSDK.1.5.240428000\build\native\Microsoft.WindowsAppSDK.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.props'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Graphics.Win2D" version="1.2.0" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.230706.1" targetFramework="native" />
<package id="Microsoft.Windows.SDK.BuildTools" version="10.0.22621.756" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.5.240227000" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.240405.15" targetFramework="native" />
<package id="Microsoft.Windows.SDK.BuildTools" version="10.0.22621.3233" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.5.240428000" targetFramework="native" />
</packages>