Touch IE_Repeat PIE When mouse input is set to use as touch

Hey,
I have set mouse input to be used as touch in the input settings of my project.
In my player controller I bind the IE_ Pressed, Repeat and Released methods… Pressed and Released methods get called fine but the Repeat method never gets called. Is this a bug or am I using it wrong?

PlayerController.h

UCLASS()
class ANGRYICECREAMMOB_API ATruckPlayerController : public APlayerController
{
	GENERATED_BODY()

public:
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
	int32 TouchCount;		// Number of inputs given

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
	FVector2D ScreenSpaceLocation;	// Screen space of cursor

private:
	// Process ScreenSpaceLocation
	void ProcessInput();

public:
	// Constructor
	ATruckPlayerController();
	
	// Controller interface
	virtual void PlayerTick(float DeltaTime) override;		// Called per frame
	virtual void SetupInputComponent() override;			// Initial action callbacks

	// Action callbacks
	void MyOnTouchDown(const ETouchIndex::Type FingerIndex, const FVector Location);
	void MyOnTouchHeld(const ETouchIndex::Type FingerIndex, const FVector Location);
	void MyOnTouchUp(const ETouchIndex::Type FingerIndex, const FVector Location);

	UFUNCTION()
	void SetForwardTarget(FVector TargetWorldPos);
};

PlayerController.cpp

ATruckPlayerController::ATruckPlayerController()
{
	bShowMouseCursor = true;	// We always want to show mouse cursor
	bEnableClickEvents = true;
	bEnableTouchEvents = true;
	
	// Defaults
	TouchCount = 0;
}

void ATruckPlayerController::PlayerTick(float DeltaTime)
{
	Super::PlayerTick(DeltaTime);

	
	if (TouchCount > 0)
	{
		ProcessInput();
	}
}

void ATruckPlayerController::ProcessInput()
{
	// Get our world space hit result from input
	FHitResult HitResult;
	GetHitResultAtScreenPosition(ScreenSpaceLocation, CurrentClickTraceChannel, true, HitResult);

	// Only do if we hit something in the world
	if (HitResult.bBlockingHit)
	{
		if(TouchCount == 1)
			SetForwardTarget(HitResult.ImpactPoint);
	}
}

void ATruckPlayerController::SetupInputComponent()
{
	Super::SetupInputComponent();

	if (InputComponent)
	{
		InputComponent->BindTouch(EInputEvent::IE_Pressed, this, &ATruckPlayerController::MyOnTouchDown);
		InputComponent->BindTouch(EInputEvent::IE_Repeat, this, &ATruckPlayerController::MyOnTouchHeld);
		InputComponent->BindTouch(EInputEvent::IE_Released, this, &ATruckPlayerController::MyOnTouchUp);
	}
	
}

void ATruckPlayerController::MyOnTouchDown(const ETouchIndex::Type FingerIndex, const FVector Location)
{
	print(FString::Printf(TEXT("Down = %d"), (int32)FingerIndex));

	TouchCount++;
	ScreenSpaceLocation = FVector2D(Location.X, Location.Y);
}

void ATruckPlayerController::MyOnTouchHeld(const ETouchIndex::Type FingerIndex, const FVector Location)
{
	print(FString::Printf(TEXT("Held = %d"), (int32)FingerIndex));

	ScreenSpaceLocation = FVector2D(Location.X, Location.Y);
}

void ATruckPlayerController::MyOnTouchUp(const ETouchIndex::Type FingerIndex, const FVector Location)
{
	print(FString::Printf(TEXT("Up = %d"), (int32)FingerIndex));

	TouchCount--;
}

void ATruckPlayerController::SetForwardTarget(FVector TargetWorldPos)
{
	if (ATruck* Truck = Cast<ATruck>(GetPawn()))
	{
		if (UTruckMovement* Movement = Truck->GetTruckMovementComponent())
		{
			Movement->SetTargetPosition(TargetWorldPos);
		}
	}
}

I’ve also tried querying the touch input per frame but it only seems to read input when it is pressed using “GetInputTouchState” function.

Thanks,
Nick

EDIT:: It works fine in stand alone build!

I have got weird behavior with this… If I hold the LMB down and move it out of the viewport and then release the mouse button (off screen) it then starts behaving correctly (IE_Repeat actions are fired off) when using the mouse as expected.
Is this a bug?

I have made a video to demonstrate the issue

Maybe you’ve already seen these threads, but between these and my own experience with this, it’s better to just create a bool that you set in press and release (i.e. bLeftMouseHeld), then setup the functionality you’re looking for in either the actor’s tick or possibly in a separate timer.

As far as I know, IE_Repeat is primarily for keyboard input, because keystroke input actually does repeat; if you hold down the “q” key, a line of q’s will output. Mouse clicks, to my knowledge, don’t function like that- they only have the two states. That said, I can’t imagine why it starts to behave that way when dragged off the screen. That does, indeed, sound like a bug.

Maybe you’ve already seen these threads,

Yes I’ve been giving this a bash for around 4 days now convinced I am doing something wrong and I’ve trapsed the forums, answerhub and google quite abit!

it’s better to just create a bool that you set in press and release (i.e. bLeftMouseHeld), then setup the functionality you’re looking for in either the actor’s tick or possibly in a separate timer.

This was my initial attempt, but could not find a way to read touch position per frame… The Touches array in PlayerInput (in the PlayerController class) only set their positions when they are first pressed but don’t update after that. And tried various other methods (mentioned in my original post). So quite stumped on how to read this information per frame for touches :confused:

What’s even more confusing is that this code works in a standalone build but not in editor!

That said, I can’t imagine why it starts to behave that way when dragged off the screen. That does, indeed, sound like a bug.

Recon it’s worth me posting this in the bug section?

Thanks for the reply,
Nick

As in it wasn’t responsive enough? Currently, I use something like this to record hold time for the sake of charged attacks:

	InputComponent->BindAction("MainAttack", IE_Pressed, this, &ADefaultCharacter::MainAttackPress);
	InputComponent->BindAction("MainAttack", IE_Released, this, &ADefaultCharacter::MainAttackRelease);

And the actual functions:

void ADefaultCharacter::MainAttackPress()
{
	//other stuff

	bIsMainAttackHeld = true;
	//reset hold time in anticipation of the next hold
	MainHoldTime = 0;

	GetWorldTimerManager().SetTimer(MainHeldTimerHandle, this, &ADefaultCharacter::RecordMainHeldTime, 0.01f, true);
}

void ADefaultCharacter::MainAttackRelease()
{
	bIsMainAttackHeld = false;
}

//track the amount of time that the main ability button is held
void ADefaultCharacter::RecordMainHeldTime()
{
	MainHoldTime = MainHoldTime + GetWorldTimerManager().GetTimerRate(MainHeldTimerHandle);

	if (!bIsMainAttackHeld)
	{
		GetWorldTimerManager().ClearTimer(MainHeldTimerHandle);
	}
}

I used a timer, but either should be fine. I like the timer, in this case, because I have better control over how often I make the check.

No, I need to know the position of the mouse (or touch input in this case) each frame whilst the screen is being touched by the user. The idea is that the car will follow the input so the user has to hold the screen and move his/her finger around the screen to direct the car.

I have posted this as a bug in the bug posts section of UE4 Answerhub as my code works perfectly fine in a standalone build (IE_Repeat events are being triggered) but it doesn’t work in the editor without doing something specific with the mouse (see the steps to reproduce in my bug post).
I have posted some video examples over there, you can see what kind of behavior I want/have in the working video

Working Video: - YouTube

Other than that, thanks for sharing code and taking the time to respond :slight_smile:

Thanks,
Nick

Ah, I think understand now. Well, in the meantime, a workaround using something similar, except you’d want it in the tick function, shouldn’t be too hard to setup.

And yeah, sure thing. I ask plenty of questions, so it’s only fair I try to answer some, too.

Yeah my initial thought after this didn’t work properly was to query the Input->Touches array (0 and 1 indices) in the Tick Method, however these only got updated when the touch was initially pressed (i.e the stored location of the touch when the button was first pressed never changed if you move the mouse whilst holding the button down).
I am totally stumped in a work around for this, I need it to work fine in editor because the whole game will be based around this driving mechanic! But after seeing it work perfect in standalone I am convinced this is an editor bug :confused:

When I am more familiar with Unreal (I have been itching to use it for some time!) I will return the favor on the answer hub :smiley:

Ah, there are two other alternatives you should consider: DeprojectMousePositionToWorld or GetHitResultUnderCursor. I gave an example on one of my other questions that I ended up having to answer myself.

I believe the deproject only gives the mouse’s screen position, if I remember right, so if you want to use the location to drive the direction the car travels in, you’d probably want to use the GetHitResult or do a similar trace from your mouse to game space. You would have to do some calculations to translate the screen space location into a usable direction, if you’d prefer that. In either case, just check that result in tick and adjust your car accordingly. Oh, also, I believe the top-down example does something similar to the kind of movement you’re looking for if you check that.

Cool, that’s the way to do it. The more people answering questions on here, the better. Also, be sure to accept this as an answer if it ends up working out so that other people can find it.

I can either promote that comment to an answer or you can just mark that first answer and people can just look down the line until they find what they need.

Brilliant! That worked!

Well, it worked for GetHitResultUnderCursor, I originally tried GetHitResultUnderTouch but it would only store its initial position when first pressed. I would assume this is still a bug! But other than that GetHitResultUnderCursor worked fine.

Thanks a lot for your help friend :slight_smile:

Thanks,
Nick

p.s How do I mark a comment as an answer?