// Copyright Sam Bonifacio. All Rights Reserved. #pragma once #include "Blueprint/UserWidget.h" #include "Misc/AutoSettingsInputConfig.h" #include "BindCapturePrompt.generated.h" USTRUCT(BlueprintType) struct AUTOSETTINGSINPUT_API FCapturedInput { GENERATED_BODY() UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input") FInputChord Chord; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input") float AxisScale = 0.f; }; DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FChordCapturedEvent, FCapturedInput, CapturedInput); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FChordRejectedEvent, FCapturedInput, CapturedInput); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FCapturePromptClosedEvent, bool, bWasCancelled); UENUM() enum class EBindingCaptureMode : uint8 { // Capture keys when they are released (default) OnReleased, // Capture keys when they are pressed. This will prevent use of modifiers, since a modifier will be captured by itself when it is pressed. OnPressed, }; /** * Prompt that listens for an input chord and fires an event when it captures one */ UCLASS(abstract) class AUTOSETTINGSINPUT_API UBindCapturePrompt : public UUserWidget { GENERATED_BODY() public: UBindCapturePrompt(const FObjectInitializer& ObjectInitializer); // If true, then will tell viewport to ignore all game input (leaving only UI input) // while capturing, then restore if when closed. If the game supports multiple local players // binding at the same time then this may be undesirable. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Bind Capture Prompt") bool bIgnoreGameViewportInputWhileCapturing; // If true, only allow capturing keys in the passed in Key Group, otherwise the keys will be captured anyway UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Bind Capture Prompt") bool bRestrictKeyGroup; // Should keys and mouse clicks be captured when they are pressed, or when they are released? UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Bind Capture Prompt") EBindingCaptureMode CaptureMode; // If valid and bRestrictKeyGroup is true, then only keys allowed by this Key Group will be captured // If a key is rejected for not being in the Key Group, then OnChordRejected will be fired UPROPERTY() FGameplayTag KeyGroup; // Fired when an input chord is captured UPROPERTY(BlueprintAssignable, Category = "Bind Capture Prompt") FChordCapturedEvent OnChordCaptured; // Fired when an input chord is rejected UPROPERTY(BlueprintAssignable, Category = "Bind Capture Prompt") FChordRejectedEvent OnChordRejected; // Fired when the capture prompt is closed UPROPERTY(BlueprintAssignable, Category = "Bind Capture Prompt") FCapturePromptClosedEvent OnCapturePromptClosed; // Cancel listening and close the prompt UFUNCTION(BlueprintCallable, Category = "Bind Capture Prompt") void Cancel(); // Returns the key group used for this prompt UFUNCTION(BlueprintPure, Category = "Bind Capture Prompt") FGameplayTag GetKeyGroup() const { return KeyGroup; } protected: // Keys that are currently down, used to collect modifiers UPROPERTY() TArray KeysDown; // Value of viewport's "ignore input" before the prompt was opened UPROPERTY() bool PreviousIgnoreInput; virtual void NativeConstruct() override; virtual void NativeDestruct() override; // Start listening for capture input (called in Construct by default) virtual void StartListening(); // Stop listening for capture input (called automatically after a binding is captured) virtual void StopListening(); // Subclasses can override to disallow keys based on the prompt UFUNCTION(BlueprintNativeEvent) bool IsKeyAllowed(FKey PrimaryKey); void Capture(FKey PrimaryKey = EKeys::Invalid, float AxisScale = 1.f); virtual FReply NativeOnKeyDown(const FGeometry& InGeometry, const FKeyEvent& InKeyEvent) override; virtual FReply NativeOnKeyUp(const FGeometry& InGeometry, const FKeyEvent& InKeyEvent) override; virtual FReply NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override; virtual FReply NativeOnMouseButtonUp(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override; virtual FReply NativeOnMouseWheel(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override; virtual FReply NativeOnMouseMove(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override; private: // Total delta the mouse has moved UPROPERTY() FVector2D AccumulatedMouseDelta; bool ShouldIgnoreEvent(const FInputEvent& InputEvent) const; void ConfirmCapture(FCapturedInput CapturedInput); void RejectCapture(FCapturedInput CapturedInput); void ClosePrompt(bool bWasCancelled); };