I want my context action to fire when either Keycode.One is pressed or Keycode.DPadUp is pressed. I have achieved this using this code in a LocalScript.
local CAS = game:GetService("ContextActionService")
CAS:BindAction("HelloWorld", function(EventName, InputState, InputObject)
print("EventName: "..EventName.." | InputState: "..tostring(InputState).." | InputObject: "..tostring(InputObject))
end, false, Enum.KeyCode.One, Enum.KeyCode.DPadUp)
Although I get my desired behavior with this code, I have created a bug. If I press Esc and then click on the Settings menu, my context action fires somehow.
Output from intended behavior (1 press of the One key):
EventName: HelloWorld | InputState: Enum.UserInputState.Begin | InputObject: InputObject
Output from unintended behavior (Pressing Esc and clicking on Settings once):
EventName: HelloWorld | InputState: Enum.UserInputState.Cancel | InputObject: InputObject
Interestingly, this behavior stops if I remove Enum.Keycode.DPadUp from the parameters of my “HelloWorld” BindAction. Should I be handling gamepad input differently to avoid this behavior?
The unintended behavior causes an UserInputState called Cancel. I’m not entirely sure what that means as well, if someone could explain that it would be nice.
local player = game.Players.LocalPlayer
local UIS = game:GetService("UserInputService")
UIS.InputBegan:Connect(function(Keycode)
if Keycode.KeyCode == Enum.KeyCode.One then
print("One was pressed")
else
print("not touched")
end
end)
UIS.InputEnd:Connect(function(Keycode)
if Keycode.KeyCode == Enum.KeyCode.One then
print("One was pressed")
else
print("not touched")
end
end)
UIS.InputBegan:Connect(function(Keycode)
if Keycode.KeyCode == Enum.KeyCode.DPadUp then
print("One was pressed")
else
print("not touched")
end
end)
UIS.InputEnd:Connect(function(Keycode)
if Keycode.KeyCode == Enum.KeyCode.DPadUp then
print("One was pressed")
else
print("not touched")
end
end)
Your code would still fire because you don’t filter out input if it’s listened to internally.
That is not the purpose of MessagingService. Please do not suggest things without knowing what they do.
ContextActionService, if I recall correctly, does not have a way to void input that is listened to internally. That’s why UserInputService works better if you need that check explicitly.
local UserInputService = game:GetService("UserInputService")
UserInputService.InputBegan:Connect(function (InputObject, GameProcessedEvent)
if not GameProcessedEvent then
print(InputObject.KeyCode)
end
end)
This will prevent yor input from firing when a keybind is listening to an internal keybind.
I noticed that the UserInputState for the unintended behavior is “Cancel”. If I add an if statement to my handler function that accepts only “Begin” or “End”, then I’ll be able to achieve my intended behavior still, right?
I really want to use ContextActionService over UserInputService because it seems a lot more convenient and beginner friendly. Is that advisable?
You have to compare the UserInputState passed into the function to make sure you’re not listening to the Cancel user input state.
This would make the action only listen to UserInputState.Begin
local CAS = game:GetService("ContextActionService")
CAS:BindAction("HelloWorld", function(EventName, InputState, InputObject)
if InputState == Enum.UserInputState.Begin then
print("EventName: "..EventName.." | InputState: "..tostring(InputState).." | InputObject: "..tostring(InputObject))
end
end, false, Enum.KeyCode.One, Enum.KeyCode.DPadUp)
If you want to shorten the comparison, you can also use the Enum’s name:
if InputState.Name == "Begin" then --...
It looks like Cancel is fired whenever a Roblox gui is meant to process input. You can probably use this as a way to close other gui’s if they protrude.