// Copyright Epic Games, Inc. All Rights Reserved. #include "DriverElement.h" #include "IDriverElement.h" #include "IDriverSequence.h" #include "IElementLocator.h" #include "IApplicationElement.h" #include "AutomationDriver.h" #include "Async/Async.h" #include "Async/AsyncResult.h" #include "InputCoreTypes.h" #include "GenericPlatform/GenericApplicationMessageHandler.h" class FDriverElementExtensions { private: static TSharedPtr LocateSingleElement(const TSharedRef& ElementLocator) { check(IsInGameThread()); TArray> Elements; ElementLocator->Locate(Elements); if (Elements.Num() > 1) { return nullptr; } else if (Elements.Num() == 0) { return nullptr; } return Elements[0]; } public: static bool CanFocus(const TSharedRef& ElementLocator) { const TSharedPtr Element = LocateSingleElement(ElementLocator); if (!Element.IsValid()) { return false; } return Element->CanFocus(); } static bool IsFocused(const TSharedRef& ElementLocator) { const TSharedPtr Element = LocateSingleElement(ElementLocator); if (!Element.IsValid()) { return false; } return Element->IsFocused(); } static bool IsFocused(const TSharedRef& ElementLocator, uint32 UserIndex) { const TSharedPtr Element = LocateSingleElement(ElementLocator); if (!Element.IsValid()) { return false; } return Element->IsFocused(UserIndex); } static bool HasFocusedDescendants(const TSharedRef& ElementLocator) { const TSharedPtr Element = LocateSingleElement(ElementLocator); if (!Element.IsValid()) { return false; } return Element->HasFocusedDescendants(); } static bool HasFocusedDescendants(const TSharedRef& ElementLocator, uint32 UserIndex) { const TSharedPtr Element = LocateSingleElement(ElementLocator); if (!Element.IsValid()) { return false; } return Element->HasFocusedDescendants(UserIndex); } static bool Exists(const TSharedRef& ElementLocator) { return LocateSingleElement(ElementLocator).IsValid(); } static bool IsChecked(const TSharedRef& ElementLocator) { const TSharedPtr Element = LocateSingleElement(ElementLocator); if (!Element.IsValid()) { return false; } return Element->IsChecked(); } static bool IsInteractable(const TSharedRef& ElementLocator) { const TSharedPtr Element = LocateSingleElement(ElementLocator); if (!Element.IsValid()) { return false; } return Element->IsInteractable(); } static bool IsHovered(const TSharedRef& ElementLocator) { const TSharedPtr Element = LocateSingleElement(ElementLocator); if (!Element.IsValid()) { return false; } return Element->IsHovered(); } static bool IsVisible(const TSharedRef& ElementLocator) { const TSharedPtr Element = LocateSingleElement(ElementLocator); if (!Element.IsValid()) { return false; } return Element->IsVisible(); } static bool IsScrollable(const TSharedRef& ElementLocator) { const TSharedPtr Element = LocateSingleElement(ElementLocator); if (!Element.IsValid()) { return false; } return Element->IsScrollable(); } static bool IsScrolledToBeginning(const TSharedRef& ElementLocator) { const TSharedPtr Element = LocateSingleElement(ElementLocator); if (!Element.IsValid()) { return false; } return Element->IsScrolledToBeginning(); } static bool IsScrolledToEnd(const TSharedRef& ElementLocator) { const TSharedPtr Element = LocateSingleElement(ElementLocator); if (!Element.IsValid()) { return false; } return Element->IsScrolledToEnd(); } static FVector2D GetAbsolutePosition(const TSharedRef& ElementLocator) { const TSharedPtr Element = LocateSingleElement(ElementLocator); if (!Element.IsValid()) { return FVector2D::ZeroVector; } return Element->GetAbsolutePosition(); } static FVector2D GetSize(const TSharedRef& ElementLocator) { const TSharedPtr Element = LocateSingleElement(ElementLocator); if (!Element.IsValid()) { return FVector2D::ZeroVector; } return Element->GetSize(); } static FText GetText(const TSharedRef& ElementLocator) { const TSharedPtr Element = LocateSingleElement(ElementLocator); if (!Element.IsValid()) { return FText::GetEmpty(); } return Element->GetText(); } }; class FAsyncDriverElementCollection : public IAsyncDriverElementCollection , public TSharedFromThis { public: virtual ~FAsyncDriverElementCollection() { } virtual TAsyncResult>> GetElements() override { const TSharedRef>>, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise>>()); const TSharedRef Locator = ElementLocator; const TSharedRef Driver = AsyncDriver; AsyncTask( ENamedThreads::GameThread, [Driver, Locator, Promise]() { TArray> AppElements; Locator->Locate(AppElements); TArray> DriverElements; for (int32 Index = 0; Index < AppElements.Num(); ++Index) { DriverElements.Add(FAsyncDriverElementFactory::Create( Driver, AppElements[Index]->CreateLocator())); } Promise->SetValue(DriverElements); } ); return TAsyncResult>>(Promise->GetFuture(), nullptr, nullptr); } private: FAsyncDriverElementCollection( const TSharedRef& InAsyncDriver, const TSharedRef& InElementLocator) : AsyncDriver(InAsyncDriver) , ElementLocator(InElementLocator) { } private: const TSharedRef AsyncDriver; const TSharedRef ElementLocator; friend FAsyncDriverElementCollectionFactory; }; TSharedRef FAsyncDriverElementCollectionFactory::Create( const TSharedRef& AsyncDriver, const TSharedRef& ElementLocator) { return MakeShareable(new FAsyncDriverElementCollection( AsyncDriver, ElementLocator)); } class FAsyncDriverElement : public IAsyncDriverElement , public TSharedFromThis { public: virtual ~FAsyncDriverElement() { } virtual TAsyncResult Hover() override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().MoveToElement(SharedThis(this)); return Sequence->Perform(); } virtual TAsyncResult Click(EMouseButtons::Type MouseButton) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().Click(SharedThis(this), MouseButton); return Sequence->Perform(); } virtual TAsyncResult Click() override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().Click(SharedThis(this), EMouseButtons::Left); return Sequence->Perform(); } virtual TAsyncResult DoubleClick(EMouseButtons::Type MouseButton) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().DoubleClick(SharedThis(this), MouseButton); return Sequence->Perform(); } virtual TAsyncResult DoubleClick() override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().DoubleClick(SharedThis(this), EMouseButtons::Left); return Sequence->Perform(); } virtual TAsyncResult ScrollBy(float Delta) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().ScrollBy(SharedThis(this), Delta); return Sequence->Perform(); } virtual TAsyncResult ScrollToBeginning() override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().ScrollToBeginning(SharedThis(this)); return Sequence->Perform(); } virtual TAsyncResult ScrollToBeginning(float Amount) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().ScrollToBeginning(SharedThis(this), Amount); return Sequence->Perform(); } virtual TAsyncResult ScrollToBeginningUntil(const TSharedRef& DesiredElementLocator) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().ScrollToBeginningUntil(SharedThis(this), DesiredElementLocator); return Sequence->Perform(); } virtual TAsyncResult ScrollToEnd() override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().ScrollToEnd(SharedThis(this)); return Sequence->Perform(); } virtual TAsyncResult ScrollToEnd(float Amount) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().ScrollToEnd(SharedThis(this), Amount); return Sequence->Perform(); } virtual TAsyncResult ScrollToEndUntil(const TSharedRef& DesiredElementLocator) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().ScrollToEndUntil(SharedThis(this), DesiredElementLocator); return Sequence->Perform(); } virtual TAsyncResult Type(const TCHAR* Text) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().Type(SharedThis(this), FString(Text)); return Sequence->Perform(); } virtual TAsyncResult Type(FString Text) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().Type(SharedThis(this), MoveTemp(Text)); return Sequence->Perform(); } virtual TAsyncResult Type(FKey Key) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().Type(SharedThis(this), Key); return Sequence->Perform(); } virtual TAsyncResult Type(TCHAR Character) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().Type(SharedThis(this), Character); return Sequence->Perform(); } virtual TAsyncResult Type(const TArray& Keys) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().Type(SharedThis(this), Keys); return Sequence->Perform(); } virtual TAsyncResult TypeChord(FKey Key1, FKey Key2) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().TypeChord(SharedThis(this), Key1, Key2); return Sequence->Perform(); } virtual TAsyncResult TypeChord(FKey Key1, TCHAR Character) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().TypeChord(SharedThis(this), Key1, Character); return Sequence->Perform(); } virtual TAsyncResult TypeChord(FKey Key1, FKey Key2, FKey Key3) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().TypeChord(SharedThis(this), Key1, Key2, Key3); return Sequence->Perform(); } virtual TAsyncResult TypeChord(FKey Key1, FKey Key2, TCHAR Character) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().TypeChord(SharedThis(this), Key1, Key2, Character); return Sequence->Perform(); } virtual TAsyncResult Press(TCHAR Character) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().Press(SharedThis(this), Character); return Sequence->Perform(); } virtual TAsyncResult Press(FKey Key) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().Press(SharedThis(this), Key); return Sequence->Perform(); } virtual TAsyncResult Press(EMouseButtons::Type MouseButton) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().Press(SharedThis(this), MouseButton); return Sequence->Perform(); } virtual TAsyncResult PressChord(FKey Key1, FKey Key2) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().PressChord(SharedThis(this), Key1, Key2); return Sequence->Perform(); } virtual TAsyncResult PressChord(FKey Key1, TCHAR Character) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().PressChord(SharedThis(this), Key1, Character); return Sequence->Perform(); } virtual TAsyncResult PressChord(FKey Key1, FKey Key2, FKey Key3) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().PressChord(SharedThis(this), Key1, Key2, Key3); return Sequence->Perform(); } virtual TAsyncResult PressChord(FKey Key1, FKey Key2, TCHAR Character) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().PressChord(SharedThis(this), Key1, Key2, Character); return Sequence->Perform(); } virtual TAsyncResult Release(TCHAR Character) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().Release(SharedThis(this), Character); return Sequence->Perform(); } virtual TAsyncResult Release(FKey Key) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().Release(SharedThis(this), Key); return Sequence->Perform(); } virtual TAsyncResult Release(EMouseButtons::Type MouseButton) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().Release(SharedThis(this), MouseButton); return Sequence->Perform(); } virtual TAsyncResult ReleaseChord(FKey Key1, FKey Key2) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().ReleaseChord(SharedThis(this), Key1, Key2); return Sequence->Perform(); } virtual TAsyncResult ReleaseChord(FKey Key1, TCHAR Character) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().ReleaseChord(SharedThis(this), Key1, Character); return Sequence->Perform(); } virtual TAsyncResult ReleaseChord(FKey Key1, FKey Key2, FKey Key3) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().ReleaseChord(SharedThis(this), Key1, Key2, Key3); return Sequence->Perform(); } virtual TAsyncResult ReleaseChord(FKey Key1, FKey Key2, TCHAR Character) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().ReleaseChord(SharedThis(this), Key1, Key2, Character); return Sequence->Perform(); } virtual TAsyncResult Focus() override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().Focus(SharedThis(this)); return Sequence->Perform(); } virtual TAsyncResult Focus(uint32 UserFocus) override { TSharedRef Sequence = AsyncDriver->CreateSequence(); Sequence->Actions().Focus(SharedThis(this), UserFocus); return Sequence->Perform(); } virtual TAsyncResult CanFocus() const override { const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::CanFocus(Locator)); } ); return TAsyncResult(Promise->GetFuture(), nullptr, nullptr); } virtual TAsyncResult IsFocused() const override { const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::IsFocused(Locator)); } ); return TAsyncResult(Promise->GetFuture(), nullptr, nullptr); } virtual TAsyncResult IsFocused(uint32 UserIndex) const override { const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, UserIndex, Promise]() { Promise->SetValue(FDriverElementExtensions::IsFocused(Locator, UserIndex)); } ); return TAsyncResult(Promise->GetFuture(), nullptr, nullptr); } virtual TAsyncResult HasFocusedDescendants() const override { const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::HasFocusedDescendants(Locator)); } ); return TAsyncResult(Promise->GetFuture(), nullptr, nullptr); } virtual TAsyncResult HasFocusedDescendants(uint32 UserIndex) const override { const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, UserIndex, Promise]() { Promise->SetValue(FDriverElementExtensions::HasFocusedDescendants(Locator, UserIndex)); } ); return TAsyncResult(Promise->GetFuture(), nullptr, nullptr); } virtual TAsyncResult Exists() const override { const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::Exists(Locator)); } ); return TAsyncResult(Promise->GetFuture(), nullptr, nullptr); } virtual TAsyncResult IsVisible() const override { const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::IsVisible(Locator)); } ); return TAsyncResult(Promise->GetFuture(), nullptr, nullptr); } virtual TAsyncResult IsChecked() const override { const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::IsChecked(Locator)); } ); return TAsyncResult(Promise->GetFuture(), nullptr, nullptr); } virtual TAsyncResult IsInteractable() const override { const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::IsInteractable(Locator)); } ); return TAsyncResult(Promise->GetFuture(), nullptr, nullptr); } virtual TAsyncResult IsScrollable() const override { const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::IsScrollable(Locator)); } ); return TAsyncResult(Promise->GetFuture(), nullptr, nullptr); } virtual TAsyncResult IsScrolledToBeginning() const override { const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::IsScrolledToBeginning(Locator)); } ); return TAsyncResult(Promise->GetFuture(), nullptr, nullptr); } virtual TAsyncResult IsScrolledToEnd() const override { const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::IsScrolledToEnd(Locator)); } ); return TAsyncResult(Promise->GetFuture(), nullptr, nullptr); } virtual TAsyncResult IsHovered() const override { const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::IsHovered(Locator)); } ); return TAsyncResult(Promise->GetFuture(), nullptr, nullptr); } virtual TAsyncResult GetAbsolutePosition() const override { const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::GetAbsolutePosition(Locator)); } ); return TAsyncResult(Promise->GetFuture(), nullptr, nullptr); } virtual TAsyncResult GetSize() const override { const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::GetSize(Locator)); } ); return TAsyncResult(Promise->GetFuture(), nullptr, nullptr); } virtual TAsyncResult GetText() const override { const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::GetText(Locator)); } ); return TAsyncResult(Promise->GetFuture(), nullptr, nullptr); } virtual void Locate(TArray>& OutElements) const override { ElementLocator->Locate(OutElements); } virtual FString ToDebugString() const override { return ElementLocator->ToDebugString(); } private: FAsyncDriverElement( const TSharedRef& InAsyncDriver, const TSharedRef& InElementLocator) : AsyncDriver(InAsyncDriver) , ElementLocator(InElementLocator) { } private: const TSharedRef AsyncDriver; const TSharedRef ElementLocator; friend FAsyncDriverElementFactory; }; TSharedRef FAsyncDriverElementFactory::Create( const TSharedRef& AsyncDriver, const TSharedRef& ElementLocator) { return MakeShareable(new FAsyncDriverElement( AsyncDriver, ElementLocator)); } class FEmptyAsyncDriverElement : public IAsyncDriverElement , public TSharedFromThis { public: virtual ~FEmptyAsyncDriverElement() { } virtual TAsyncResult Hover() override { return TAsyncResult(false); } virtual TAsyncResult Click(EMouseButtons::Type MouseButton) override { return TAsyncResult(false); } virtual TAsyncResult Click() override { return TAsyncResult(false); } virtual TAsyncResult DoubleClick(EMouseButtons::Type MouseButton) override { return TAsyncResult(false); } virtual TAsyncResult DoubleClick() override { return TAsyncResult(false); } virtual TAsyncResult ScrollBy(float Delta) override { return TAsyncResult(false); } virtual TAsyncResult ScrollToBeginning() override { return TAsyncResult(false); } virtual TAsyncResult ScrollToBeginning(float Amount) override { return TAsyncResult(false); } virtual TAsyncResult ScrollToBeginningUntil(const TSharedRef& DesiredElementLocator) override { return TAsyncResult(false); } virtual TAsyncResult ScrollToEnd() override { return TAsyncResult(false); } virtual TAsyncResult ScrollToEnd(float Amount) override { return TAsyncResult(false); } virtual TAsyncResult ScrollToEndUntil(const TSharedRef& DesiredElementLocator) override { return TAsyncResult(false); } virtual TAsyncResult Type(const TCHAR* Text) override { return TAsyncResult(false); } virtual TAsyncResult Type(FString Text) override { return TAsyncResult(false); } virtual TAsyncResult Type(FKey Key) override { return TAsyncResult(false); } virtual TAsyncResult Type(TCHAR Character) override { return TAsyncResult(false); } virtual TAsyncResult Type(const TArray& Keys) override { return TAsyncResult(false); } virtual TAsyncResult TypeChord(FKey Key1, FKey Key2) override { return TAsyncResult(false); } virtual TAsyncResult TypeChord(FKey Key1, TCHAR Character) override { return TAsyncResult(false); } virtual TAsyncResult TypeChord(FKey Key1, FKey Key2, FKey Key3) override { return TAsyncResult(false); } virtual TAsyncResult TypeChord(FKey Key1, FKey Key2, TCHAR Character) override { return TAsyncResult(false); } virtual TAsyncResult Press(TCHAR Character) override { return TAsyncResult(false); } virtual TAsyncResult Press(FKey Key) override { return TAsyncResult(false); } virtual TAsyncResult Press(EMouseButtons::Type MouseButton) override { return TAsyncResult(false); } virtual TAsyncResult PressChord(FKey Key1, FKey Key2) override { return TAsyncResult(false); } virtual TAsyncResult PressChord(FKey Key1, TCHAR Character) override { return TAsyncResult(false); } virtual TAsyncResult PressChord(FKey Key1, FKey Key2, FKey Key3) override { return TAsyncResult(false); } virtual TAsyncResult PressChord(FKey Key1, FKey Key2, TCHAR Character) override { return TAsyncResult(false); } virtual TAsyncResult Release(TCHAR Character) override { return TAsyncResult(false); } virtual TAsyncResult Release(FKey Key) override { return TAsyncResult(false); } virtual TAsyncResult Release(EMouseButtons::Type MouseButton) override { return TAsyncResult(false); } virtual TAsyncResult ReleaseChord(FKey Key1, FKey Key2) override { return TAsyncResult(false); } virtual TAsyncResult ReleaseChord(FKey Key1, TCHAR Character) override { return TAsyncResult(false); } virtual TAsyncResult ReleaseChord(FKey Key1, FKey Key2, FKey Key3) override { return TAsyncResult(false); } virtual TAsyncResult ReleaseChord(FKey Key1, FKey Key2, TCHAR Character) override { return TAsyncResult(false); } virtual TAsyncResult Focus() override { return TAsyncResult(false); } virtual TAsyncResult Focus(uint32 UserFocus) override { return TAsyncResult(false); } virtual TAsyncResult CanFocus() const override { return TAsyncResult(false); } virtual TAsyncResult IsFocused() const override { return TAsyncResult(false); } virtual TAsyncResult IsFocused(uint32 UserIndex) const override { return TAsyncResult(false); } virtual TAsyncResult HasFocusedDescendants() const override { return TAsyncResult(false); } virtual TAsyncResult HasFocusedDescendants(uint32 UserIndex) const override { return TAsyncResult(false); } virtual TAsyncResult Exists() const override { return TAsyncResult(false); } virtual TAsyncResult IsVisible() const override { return TAsyncResult(false); } virtual TAsyncResult IsChecked() const override { return TAsyncResult(false); } virtual TAsyncResult IsInteractable() const override { return TAsyncResult(false); } virtual TAsyncResult IsScrollable() const override { return TAsyncResult(false); } virtual TAsyncResult IsScrolledToBeginning() const override { return TAsyncResult(false); } virtual TAsyncResult IsScrolledToEnd() const override { return TAsyncResult(false); } virtual TAsyncResult IsHovered() const override { return TAsyncResult(false); } virtual TAsyncResult GetAbsolutePosition() const override { return TAsyncResult(FVector2D(0, 0)); } virtual TAsyncResult GetSize() const override { return TAsyncResult(FVector2D(0, 0)); } virtual TAsyncResult GetText() const override { return TAsyncResult(FText::GetEmpty()); } virtual void Locate(TArray>& OutElements) const override { } virtual FString ToDebugString() const override { return TEXT("Empty Driver Element"); } private: FEmptyAsyncDriverElement() { } private: friend FEmptyAsyncDriverElementFactory; }; TSharedRef FEmptyAsyncDriverElementFactory::Create() { return MakeShareable(new FEmptyAsyncDriverElement()); } class FDriverElementCollection : public IDriverElementCollection , public TSharedFromThis { public: virtual ~FDriverElementCollection() { } virtual TArray> GetElements() override { if (IsInGameThread()) { return InternalGetElement(); } const TSharedRef LocalThis = SharedThis(this); const TSharedRef>>, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise>>()); AsyncTask( ENamedThreads::GameThread, [LocalThis, Promise]() { Promise->SetValue(LocalThis->InternalGetElement()); } ); return Promise->GetFuture().Get(); } private: TArray> InternalGetElement() { check(IsInGameThread()); TArray> AppElements; ElementLocator->Locate(AppElements); TArray> DriverElements; for (int32 Index = 0; Index < AppElements.Num(); ++Index) { DriverElements.Add(FDriverElementFactory::Create( Driver, AppElements[Index]->CreateLocator())); } return DriverElements; } private: FDriverElementCollection( const TSharedRef& InDriver, const TSharedRef& InElementLocator) : Driver(InDriver) , ElementLocator(InElementLocator) { } private: const TSharedRef Driver; const TSharedRef ElementLocator; friend FDriverElementCollectionFactory; }; TSharedRef FDriverElementCollectionFactory::Create( const TSharedRef& Driver, const TSharedRef& ElementLocator) { return MakeShareable(new FDriverElementCollection( Driver, ElementLocator)); } class FDriverElement : public IDriverElement , public TSharedFromThis { public: virtual ~FDriverElement() { } virtual bool Hover() override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().MoveToElement(SharedThis(this)); return Sequence->Perform(); } virtual bool Click(EMouseButtons::Type MouseButton) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().Click(SharedThis(this), MouseButton); return Sequence->Perform(); } virtual bool Click() override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().Click(SharedThis(this), EMouseButtons::Left); return Sequence->Perform(); } virtual bool DoubleClick() override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().DoubleClick(SharedThis(this), EMouseButtons::Left); return Sequence->Perform(); } virtual bool DoubleClick(EMouseButtons::Type MouseButton) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().DoubleClick(SharedThis(this), MouseButton); return Sequence->Perform(); } virtual bool ScrollBy(float Delta) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().ScrollBy(SharedThis(this), Delta); return Sequence->Perform(); } virtual bool ScrollToBeginning() override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().ScrollToBeginning(SharedThis(this)); return Sequence->Perform(); } virtual bool ScrollToBeginning(float Amount) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().ScrollToBeginning(SharedThis(this), Amount); return Sequence->Perform(); } virtual bool ScrollToBeginningUntil(const TSharedRef& DesiredElementLocator) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().ScrollToBeginningUntil(SharedThis(this), DesiredElementLocator); return Sequence->Perform(); } virtual bool ScrollToEnd() override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().ScrollToEnd(SharedThis(this)); return Sequence->Perform(); } virtual bool ScrollToEnd(float Amount) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().ScrollToEnd(SharedThis(this), Amount); return Sequence->Perform(); } virtual bool ScrollToEndUntil(const TSharedRef& DesiredElementLocator) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().ScrollToEndUntil(SharedThis(this), DesiredElementLocator); return Sequence->Perform(); } virtual bool Type(const TCHAR* Text) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().Type(SharedThis(this), FString(Text)); return Sequence->Perform(); } virtual bool Type(FString Text) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().Type(SharedThis(this), MoveTemp(Text)); return Sequence->Perform(); } virtual bool Type(FKey Key) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().Type(SharedThis(this), Key); return Sequence->Perform(); } virtual bool Type(TCHAR Character) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().Type(SharedThis(this), Character); return Sequence->Perform(); } virtual bool Type(const TArray& Keys) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().Type(SharedThis(this), Keys); return Sequence->Perform(); } virtual bool TypeChord(FKey Key1, FKey Key2) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().TypeChord(SharedThis(this), Key1, Key2); return Sequence->Perform(); } virtual bool TypeChord(FKey Key1, TCHAR Character) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().TypeChord(SharedThis(this), Key1, Character); return Sequence->Perform(); } virtual bool TypeChord(FKey Key1, FKey Key2, FKey Key3) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().TypeChord(SharedThis(this), Key1, Key2, Key3); return Sequence->Perform(); } virtual bool TypeChord(FKey Key1, FKey Key2, TCHAR Character) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().TypeChord(SharedThis(this), Key1, Key2, Character); return Sequence->Perform(); } virtual bool Press(TCHAR Character) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().Press(SharedThis(this), Character); return Sequence->Perform(); } virtual bool Press(FKey Key) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().Press(SharedThis(this), Key); return Sequence->Perform(); } virtual bool Press(EMouseButtons::Type MouseButton) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().Press(SharedThis(this), MouseButton); return Sequence->Perform(); } virtual bool PressChord(FKey Key1, FKey Key2) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().PressChord(SharedThis(this), Key1, Key2); return Sequence->Perform(); } virtual bool PressChord(FKey Key1, TCHAR Character) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().PressChord(SharedThis(this), Key1, Character); return Sequence->Perform(); } virtual bool PressChord(FKey Key1, FKey Key2, FKey Key3) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().PressChord(SharedThis(this), Key1, Key2, Key3); return Sequence->Perform(); } virtual bool PressChord(FKey Key1, FKey Key2, TCHAR Character) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().PressChord(SharedThis(this), Key1, Key2, Character); return Sequence->Perform(); } virtual bool Release(TCHAR Character) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().Release(SharedThis(this), Character); return Sequence->Perform(); } virtual bool Release(FKey Key) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().Release(SharedThis(this), Key); return Sequence->Perform(); } virtual bool Release(EMouseButtons::Type MouseButton) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().Release(SharedThis(this), MouseButton); return Sequence->Perform(); } virtual bool ReleaseChord(FKey Key1, FKey Key2) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().ReleaseChord(SharedThis(this), Key1, Key2); return Sequence->Perform(); } virtual bool ReleaseChord(FKey Key1, TCHAR Character) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().ReleaseChord(SharedThis(this), Key1, Character); return Sequence->Perform(); } virtual bool ReleaseChord(FKey Key1, FKey Key2, FKey Key3) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().ReleaseChord(SharedThis(this), Key1, Key2, Key3); return Sequence->Perform(); } virtual bool ReleaseChord(FKey Key1, FKey Key2, TCHAR Character) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().ReleaseChord(SharedThis(this), Key1, Key2, Character); return Sequence->Perform(); } virtual bool Focus() override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().Focus(SharedThis(this)); return Sequence->Perform(); } virtual bool Focus(uint32 UserIndex) override { TSharedRef Sequence = Driver->CreateSequence(); Sequence->Actions().Focus(SharedThis(this), UserIndex); return Sequence->Perform(); } virtual bool CanFocus() const override { if (IsInGameThread()) { return FDriverElementExtensions::CanFocus(ElementLocator); } const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::CanFocus(Locator)); } ); return Promise->GetFuture().Get(); } virtual bool IsFocused() const override { if (IsInGameThread()) { return FDriverElementExtensions::IsFocused(ElementLocator); } const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::IsFocused(Locator)); } ); return Promise->GetFuture().Get(); } virtual bool IsFocused(uint32 UserIndex) const override { if (IsInGameThread()) { return FDriverElementExtensions::IsFocused(ElementLocator, UserIndex); } const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, UserIndex, Promise]() { Promise->SetValue(FDriverElementExtensions::IsFocused(Locator, UserIndex)); } ); return Promise->GetFuture().Get(); } virtual bool HasFocusedDescendants() const override { if (IsInGameThread()) { return FDriverElementExtensions::HasFocusedDescendants(ElementLocator); } const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::HasFocusedDescendants(Locator)); } ); return Promise->GetFuture().Get(); } virtual bool HasFocusedDescendants(uint32 UserIndex) const override { if (IsInGameThread()) { return FDriverElementExtensions::HasFocusedDescendants(ElementLocator, UserIndex); } const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, UserIndex, Promise]() { Promise->SetValue(FDriverElementExtensions::HasFocusedDescendants(Locator, UserIndex)); } ); return Promise->GetFuture().Get(); } virtual bool Exists() const override { if (IsInGameThread()) { return FDriverElementExtensions::Exists(ElementLocator); } const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::Exists(Locator)); } ); return Promise->GetFuture().Get(); } virtual bool IsVisible() const override { if (IsInGameThread()) { return FDriverElementExtensions::IsVisible(ElementLocator); } const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::IsVisible(Locator)); } ); return Promise->GetFuture().Get(); } virtual bool IsChecked() const override { if (IsInGameThread()) { return FDriverElementExtensions::IsChecked(ElementLocator); } const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::IsChecked(Locator)); } ); return Promise->GetFuture().Get(); } virtual bool IsInteractable() const override { if (IsInGameThread()) { return FDriverElementExtensions::IsInteractable(ElementLocator); } const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::IsInteractable(Locator)); } ); return Promise->GetFuture().Get(); } virtual bool IsScrollable() const override { if (IsInGameThread()) { return FDriverElementExtensions::IsScrollable(ElementLocator); } const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::IsScrollable(Locator)); } ); return Promise->GetFuture().Get(); } virtual bool IsScrolledToBeginning() const override { if (IsInGameThread()) { return FDriverElementExtensions::IsScrolledToBeginning(ElementLocator); } const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::IsScrolledToBeginning(Locator)); } ); return Promise->GetFuture().Get(); } virtual bool IsScrolledToEnd() const override { if (IsInGameThread()) { return FDriverElementExtensions::IsScrolledToEnd(ElementLocator); } const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::IsScrolledToEnd(Locator)); } ); return Promise->GetFuture().Get(); } virtual bool IsHovered() const override { if (IsInGameThread()) { return FDriverElementExtensions::IsHovered(ElementLocator); } const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::IsHovered(Locator)); } ); return Promise->GetFuture().Get(); } virtual FVector2D GetAbsolutePosition() const override { if (IsInGameThread()) { return FDriverElementExtensions::GetAbsolutePosition(ElementLocator); } const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::GetAbsolutePosition(Locator)); } ); return Promise->GetFuture().Get(); } virtual FVector2D GetSize() const override { if (IsInGameThread()) { return FDriverElementExtensions::GetSize(ElementLocator); } const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::GetSize(Locator)); } ); return Promise->GetFuture().Get(); } virtual FText GetText() const override { if (IsInGameThread()) { return FDriverElementExtensions::GetText(ElementLocator); } const TSharedRef, ESPMode::ThreadSafe> Promise = MakeShareable(new TPromise()); const TSharedRef Locator = ElementLocator; AsyncTask( ENamedThreads::GameThread, [Locator, Promise]() { Promise->SetValue(FDriverElementExtensions::GetText(Locator)); } ); return Promise->GetFuture().Get(); } virtual void Locate(TArray>& OutElements) const override { ElementLocator->Locate(OutElements); } virtual FString ToDebugString() const override { return ElementLocator->ToDebugString(); } private: FDriverElement( const TSharedRef& InDriver, const TSharedRef& InElementLocator) : Driver(InDriver) , ElementLocator(InElementLocator) { } private: const TSharedRef Driver; const TSharedRef ElementLocator; friend FDriverElementFactory; }; TSharedRef FDriverElementFactory::Create( const TSharedRef& Driver, const TSharedRef& ElementLocator) { return MakeShareable(new FDriverElement( Driver, ElementLocator)); } class FEmptyDriverElement : public IDriverElement , public TSharedFromThis { public: virtual ~FEmptyDriverElement() { } virtual bool Hover() override { return false; } virtual bool Click(EMouseButtons::Type MouseButton) override { return false; } virtual bool Click() override { return false; } virtual bool DoubleClick() override { return false; } virtual bool DoubleClick(EMouseButtons::Type MouseButton) override { return false; } virtual bool ScrollBy(float Delta) override { return false; } virtual bool ScrollToBeginning() override { return false; } virtual bool ScrollToBeginning(float Amount) override { return false; } virtual bool ScrollToBeginningUntil(const TSharedRef& DesiredElementLocator) override { return false; } virtual bool ScrollToEnd() override { return false; } virtual bool ScrollToEnd(float Amount) override { return false; } virtual bool ScrollToEndUntil(const TSharedRef& DesiredElementLocator) override { return false; } virtual bool Type(const TCHAR* Text) override { return false; } virtual bool Type(FString Text) override { return false; } virtual bool Type(FKey Key) override { return false; } virtual bool Type(TCHAR Character) override { return false; } virtual bool Type(const TArray& Keys) override { return false; } virtual bool TypeChord(FKey Key1, FKey Key2) override { return false; } virtual bool TypeChord(FKey Key1, TCHAR Character) override { return false; } virtual bool TypeChord(FKey Key1, FKey Key2, FKey Key3) override { return false; } virtual bool TypeChord(FKey Key1, FKey Key2, TCHAR Character) override { return false; } virtual bool Press(TCHAR Character) override { return false; } virtual bool Press(FKey Key) override { return false; } virtual bool Press(EMouseButtons::Type MouseButton) override { return false; } virtual bool PressChord(FKey Key1, FKey Key2) override { return false; } virtual bool PressChord(FKey Key1, TCHAR Character) override { return false; } virtual bool PressChord(FKey Key1, FKey Key2, FKey Key3) override { return false; } virtual bool PressChord(FKey Key1, FKey Key2, TCHAR Character) override { return false; } virtual bool Release(TCHAR Character) override { return false; } virtual bool Release(FKey Key) override { return false; } virtual bool Release(EMouseButtons::Type MouseButton) override { return false; } virtual bool ReleaseChord(FKey Key1, FKey Key2) override { return false; } virtual bool ReleaseChord(FKey Key1, TCHAR Character) override { return false; } virtual bool ReleaseChord(FKey Key1, FKey Key2, FKey Key3) override { return false; } virtual bool ReleaseChord(FKey Key1, FKey Key2, TCHAR Character) override { return false; } virtual bool Focus() override { return false; } virtual bool Focus(uint32 UserIndex) override { return false; } virtual bool CanFocus() const override { return false; } virtual bool IsFocused() const override { return false; } virtual bool IsFocused(uint32 UserIndex) const override { return false; } virtual bool HasFocusedDescendants() const override { return false; } virtual bool HasFocusedDescendants(uint32 UserIndex) const override { return false; } virtual bool Exists() const override { return false; } virtual bool IsVisible() const override { return false; } virtual bool IsChecked() const override { return false; } virtual bool IsInteractable() const override { return false; } virtual bool IsScrollable() const override { return false; } virtual bool IsScrolledToBeginning() const override { return false; } virtual bool IsScrolledToEnd() const override { return false; } virtual bool IsHovered() const override { return false; } virtual FVector2D GetAbsolutePosition() const override { return FVector2D(0, 0); } virtual FVector2D GetSize() const override { return FVector2D(0, 0); } virtual FText GetText() const override { return FText::GetEmpty(); } virtual void Locate(TArray>& OutElements) const override { } virtual FString ToDebugString() const override { return TEXT("Empty Driver Element"); } private: FEmptyDriverElement() { } private: friend FEmptyDriverElementFactory; }; TSharedRef FEmptyDriverElementFactory::Create() { return MakeShareable(new FEmptyDriverElement()); }