The Input Component offers us only one way of removing an action binding: by index.
Here’s the naive (and buggy) way to do this
[SPOILER]
I put it in a spoiler so people just trying to find the answer don’t copy and paste this without reading, because this does not work.
InputComponent->BindAction("MyAction", IE_Pressed, this, &AMyActor::MyFunction);
int32 bindingIndex = InputComponent->GetNumActionBindings() - 1;
Because we just added the binding, naturally, its index will be the last index in the bindings array, so we just get the length of the array and subtract 1 from it. So far so good.
Now to remove the binding, we would do:
InputComponent->RemoveActionBinding(bindingIndex);
This “works”. The problem is: if another binding gets removed before we remove our binding, our binding’s index will be shifted by -1, so we will actually end up removing the wrong binding.
PS: I also have previously tried to locate it by storing a pointer to the created FInputActionBinding, but this will lead to problems because the way dynamic arrays work, when an element is removed the others are shifted in memory so you might end up having an invalid pointer or pointing to a different element.
[/SPOILER]
The correct way to do it
So to circumvent this problem we do this:
FInputActionBinding myActionBinding; //This should be declared in your class!
myActionBinding = FInputActionBinding("MyAction", IE_Pressed);
myActionBinding.ActionDelegate.BindDelegate(this, &AMyActor::MyFunction);
&InputComponent->AddActionBinding(myActionBinding);
and to remove it, we loop through all bindings in our input component until we find a binding that has the same action name and same delegate as the one we’re looking for:
for (int i = 0; i < InputComponent->GetNumActionBindings(); i++)
{
FInputActionBinding binding = InputComponent->GetActionBinding(i);
if (CompareInputActionBindings(binding, myActionBinding))
{
playerController->InputComponent->RemoveActionBinding(i);
i--;
continue;
}
}
Here’s the function I used to compare two FInputActionBindings
bool CompareInputActionBindings(FInputActionBinding lhs, FInputActionBinding rhs)
{
return lhs.ActionDelegate.GetDelegateForManualSet().GetHandle() == rhs.ActionDelegate.GetDelegateForManualSet().GetHandle() &&
lhs.GetActionName() == rhs.GetActionName();
}
I hope to have helped someone