ContextActionService does not invoke callbacks with UserInputState.Cancel when PlayerActions overwritten with KeyCode

All behavior described in this report can be observed using this repro file: repro.rbxl (13.3 KB)

The Bug:

When multiple actions are bound to the same input with ContextActionService, the earlier binds’ functions are invoked with the state Enum.UserInputState.Cancel. However, when both inputs are the same key but bound to different enum items e.g. Enum.PlayerActions.CharacterJump and Enum.KeyCode.Space, UserInputState.Cancel is not sent.

Using StarterCharacterScripts>LocalScript in the repro file, the following repro steps can be used to observe the bug:

  1. Note that the bugEnabled switch is off, so both actions are bound to PlayerActions.CharacterJump
  2. Load the game in Play Solo
  3. The script prints to the output that the first bound was cancelled
  4. Pressing space does not trigger the first bound to be invoked
  5. Leave play solo
  6. Enable the bugEnabled switch, so the first action uses PlayerActions.CharacterJump and the second KeyCode.Space
  7. Load the game in Play Solo
  8. The script does not print to the output that the first bound was cancelled
  9. Even though the first bound was not cancelled, pressing space does not invoke it because the second action is being invoked instead

Expected Behavior:

Even though the enums are different, since the keys are the same the first action’s callback should be fed UserInputState.Cancel. The actions already behave this way (only the second is invoked even though the first isn’t technically cancelled) – it’s just that the callback isn’t notified.

Why This is a Problem:

This is most noticeable with the default character controls. Let’s imagine I have an ability that immobilizes the player and they press space to charge the ability when enabled until the charge meter is full. A player starts mashing space before using the ability, and while space is held down they use the ability which binds space to a new action. UserInputState.End is not passed to the control script’s callback since its callback is suspended, nor is it passed UserInputState.Cancel – it still thinks space is held. When the player regains control of their character, they’re stuck in a loop of jumping because the control script still thinks space is held.

3 Likes

@0xBAADF00D

Seems legit. I’ll fix it.

EDIT: How does this debug output look? I think it’s what you’re expecting, just making sure. Same thing with bugEnabled true or false with my fix.

14:57:32.376 - repro.rbxl was auto-saved
First invoked Cancel
Second invoked Begin
Second invoked End
1 Like

Sorry, I didn’t see the edit until now. Yes, this is what I was expecting. Thanks!

1 Like