Long Title for such a small thing.
Why does ContextActionService
fire UserInputState.Begin
twice on keypad keys and once on normal keys?
It should only be firing once with Enum.UserInputState.Begin
and once with Enum.UserInputState.End
when you release a key.
< It does this when you connect a 'normal' key from your keyboard.
Here's my small experimental chunk of local code:
local ContextActionService = game:GetService("ContextActionService") ContextActionService:BindAction("keypad", print, false, Enum.KeyCode.KeypadFive) ContextActionService:BindAction("normal", print, false, Enum.KeyCode.H)
Some months ago when I was testing this, it didn't fire UserInputState.End
on keypad key release at all, now it fires twice Begin and one End ._.
thanks
(Strange... it only fires one Begin and one End for me. I've found the UserInputService to sometimes fire events twice in other scenarios, however.)
To fix when Roblox is sending out duplicate events, use 'debounce'. ex, here is a modified print that will only print its argument if it's not been printed in this time frame before:
do local args local lastTime = -1 function printOnce(arg) if lastTime ~= workspace.DistributedGameTime then args = {} lastTime = workspace.DistributedGameTime end if args[arg] then return end --already printed this args[arg] = true print(arg) end end printOnce(1) --Prints 1 printOnce(2) --Prints 2 printOnce(1) --Duplicate, so doesn't print anything wait() printOnce(1) --Time has passed, so prints 1
To prevent having to write this code repeatedly, you might use a wrapper function like these:
function CallFuncOncePerTime(func) --pass in the function local lastTime = -1 --this local variable is created for each function you pass in return function(...) --this is the function to return; it accepts any number of arguments if lastTime == workspace.DistributedGameTime then return end --we want the function to do nothing in this condition lastTime = workspace.DistributedGameTime --update lastTime func(...) --call the original function with any arguments passed in end end function CallFuncOncePerTimeArg(func) --func will run only if its first argument is unique for this time frame local lastTime = -1 local args return function(...) if lastTime ~= workspace.DistributedGameTime then --reset args args = {} lastTime = workspace.DistributedGameTime end local arg = {...} --get first arg arg = arg[1] if args[arg] then return end --this is a duplicate; return args[arg] = true func(...) end end --Usage example function test() print("Test") end test = CallFuncOncePerTime(test) --or test = CallFuncOncePerTime(function() print("Test") end --example 2: function test(arg) print("Test", arg) end test = CallFuncOncePerTimeArg(test) --or test = CallFuncOncePerTimeArg(function(arg) print("Test", arg) end)
You can thereby modify as many functions as you need so that they all exhibit this behaviour. The idea of a wrapper function is to "wrap" a function in another function. The Roblox article on debounce gives another example of this idea (under "Advanced Notation").
I recomend ContextActionService, its a eaiser version of UserInputServer
local createMobileButton = true -- if u want mobile buttons local actionName = "CallFuncOncePerTimeArg" local function onMouseDown(actionName,state,info) if state == Enum.UserInputState.Begin then function CallFuncOncePerTime() local lastTime = -1 return function(...) if lastTime == workspace.DistributedGameTime then return end lastTime = workspace.DistributedGameTime func(...) end end elseif state == Enum.UserInputState.End then print("Stopped Using Func") end end contextAction:BindAction(actionName,onMouseDown,createMobileButton,Enum.UserInputType.MouseButton1)