PC/Pawn/Widget input priorities ?

Hey Everyone !

I didn’t get any answer on the answerhub with this one, so trying my luck here :slight_smile:

My left mouse button can be catched by 3 different assets:

1/ an pawn (APawn) through a NotifyActorOnClicked() callback
2/ the player controller (APlayerController) through its input component
3/ a 3D UMG widget (MyDefaultPawn->UWidgetComponent->UUserWidget) through an interaction widget (MyDefaultPawn->UWidgetInteractionComponent)

I need those three to occur in a specific order and sometimes block the input but don’t know how to do that.

(2) is faily simple, there is an input component so i can set InputComponent->Priority and InputComponent->bBlockInput but it doesn’t seem to have the least effect.

(1) is odd, the pawn has an inputcomponent of its own but it’s not defined and yet NotifyActorOnClicked() is called. I even tried to put an “if (InputCompoent)” in NotifyActorOnClicked() but i never satisfy the condition. So it seems that the pawn respond to the left mouse click without an input component.

(3) is also very mysterious to me, i have no idea how UMG widget interact with inputs (even more mysterious now that the Interaction widget is around). It seems to be depending on the PC’s inputcomponent since i trigger the Interaction Widget using a function bound to the inputcomponent action:



InputComponent->BindAction("LeftMouseButton", IE_Pressed, this, &AYagPlayerController::OnLeftMouseButtonPressed);

-------------

void AYagPlayerController::OnLeftMouseButtonPressed()
{
	// click on the UI
	ThisPawn->WidgetInteractionComponent->PressPointerKey(EKeys::LeftMouseButton);

	// do what PC is supposed to do: draw a selection rectangle (RTS style)
	SelectStartRectangle();
}

But this setup doesn’t allow the widget to block the PC.

Anyone around to point me in the right direction to manage my inputs priorities and blockings ?

Thanks !

Cedric

Hey mister Cedric (that’s also my name :x),

I may not be able to answer all your questions, but I know that PC and Pawn should work like this:

You have the hardware input, so your keyboard. That forwards the key press to the PlayerInputMapping
and that will then go over to the InputComponents. This is done by the “PlayerInput” UObject, that can be found in the PlayerController
on all clients. It has the two structs for ActionKey and AxisKey Mappings.

The system has checks to determine which InputComponent will be processed first. Here is the list of how it (should) work/s:

  1. Input-Enabled Actor (most recent first)
  2. PlayerController
  3. LevelBlueprint
  4. Pawn

(1.) Is the important one here. Any actor, that recently had “Enable Input”, or better “Accepts Input” enabled,
will be process first here. They are ordered by priority, means the Actor that had this enabled most recently, will
be processed first. Then it will process everyone else based on the same idea, until all are finished. Then (2.) will
be processed. To keep an Actor as the first one to be processed, you just have to make sure to reenabled the Input
to move it up to the top of the stack.

Now, who does get the Input now? Answer, everyone. If you have something bound to SPACE and you bind it to an Actor,
to the PlayerController and to the Pawn, all 3 will be processed, based on the top list.

But how can we make sure that only one of them gets it? We set them up to consume the input.
If the PlayerController is set to consume the input, the Actor will still have the Spacebar working, but the Pawn won’t receive
the key press, as the PlayerController consumes it.

At least that’s how I understood it.

What I can’t answer you is how the Widget comes into play. You are binding it to an Input Event in the PlayerController,
so I would guess this counts as a PlayerController event and the information above applies.

Hello Cedric^^

I’m still a baby Cedric, while you’re a Mythic one !!

Thanks for your answer :slight_smile:

Do you make a difference between “enable” and “accept” input ? The unreal doc about input also mentions some “accepts input” property but i couldn’t find it, and i remember having tried using the familiar AActor::EnableInput with no success.

So maybe “accepts input” is the new beast i need, but i don’t know where to find it.

Anyway, i will remake some more carefully crafted tests after work using EnableInput (my game is networked and while the pawn is created server-side, i didn’t try yet to tune the replication-related properties), which, at least on the paper, really looks like a winner here.

For the widget, if no better suggestion comes, i was thinking using some hovering event to drive a boolean flag to be used in my LeftMousePressed function.

Of course, i’ll update here when i come up with a satisfying enough solution/workaround.

Cheers !

Cedric

Unfortunately still no luck after a few more tests.

I tried to use EnableInput on the PC (to put it on top of its own input stack, i even put a EnableInput(this) in its tick function to be sure^^), lower the actor priority (InputPriority = -10), increase the PC priority (InputComponent->Priority = 10), but still, NotifyActorOnClicked() fires before everything else.

It looks like no matter what i do, actors will always catch the event before the PC, while i’d want the PC on top of the “global stack” (whatever that may be^^)

Going on with my tests, will update if i find anything :slight_smile:

Cheers

Cedric

Hey,

Anyone knows how to use DiscardPlayerInput ?

I am calling it in my NotifyActorOnClicked():


ThisController->PlayerInput->DiscardPlayerInput();

But the PC::OnLeftMouseButtonPressed is still called right after this.

Hi again !

Now i’m lost :slight_smile:

For the sake of testing, i did try to disable the PC’s input in the pawn’s NotifyActorOnclicked (using PC->DisableInput(PC))

I was expecting that the PC’s would entirely stop to respond to keyboard/mouse and that i would have to figure out where to reenable it (PC->EnableInput(PC)).

But to my surprise, the DisableInput seems to be effective only during the current frame, and input is completely usable in the next frames.

So all in all, it works exactly as i want to (i can disable PC’s input when the actor is clicked only for the current frame) and i would be very happy if i understood why :slight_smile:

I thought calling DisableInput would disable it for eternity !

So i realise i don’t understand what in my code is called for life and what is called only for one frame (game thread vs rendering thread, is that the correct vocabulary ?).

I tried to read the doc:
https://docs.unrealengine.com/latest/INT/Programming/Rendering/Overview/
but i couldn’t figure out a rule of thumb that could tell me “This part of the code will last forever and this part will only last one frame”.

Surely there is a difference, otherwise the tick function would serve no purpose.

Or maybe there is something specific with the “NotifyActorOnClicked()” funtion ? I already mentionned that it seemed to work without any InputComponent involved, which puzzles me.

I’m completely lost here. If anyone with an advanced understanding of what’s happening cared to put a few words, that would be very nice^^

Of course and as always since i posted here, if i manage to understand something by testing/reading i’ll keep this thread updated with my findings !

Cheers

Cedric