Merge pull request #558 from CommunityToolkit/user/adpa-ms/lottie_island_uia
Add UIA support
This commit is contained in:
Коммит
0945863e88
|
@ -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->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>
|
Загрузка…
Ссылка в новой задаче