Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

Why does ContextActionService fire UserInputState.Begin twice on keypad input?

Asked by 8 years ago
Edited 8 years ago

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:

1local ContextActionService = game:GetService("ContextActionService")
2 
3ContextActionService:BindAction("keypad", print, false, Enum.KeyCode.KeypadFive)
4ContextActionService: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

2 answers

Log in to vote
1
Answered by 8 years ago
Edited 8 years ago

(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:

01do
02    local args
03    local lastTime = -1
04    function printOnce(arg)
05        if lastTime ~= workspace.DistributedGameTime then
06            args = {}
07            lastTime = workspace.DistributedGameTime
08        end
09        if args[arg] then return end --already printed this
10        args[arg] = true
11        print(arg)
12    end
13end
14printOnce(1) --Prints 1
15printOnce(2) --Prints 2
16printOnce(1) --Duplicate, so doesn't print anything
17wait()
18printOnce(1) --Time has passed, so prints 1

To prevent having to write this code repeatedly, you might use a wrapper function like these:

01function CallFuncOncePerTime(func) --pass in the function
02    local lastTime = -1 --this local variable is created for each function you pass in
03    return function(...) --this is the function to return; it accepts any number of arguments
04        if lastTime == workspace.DistributedGameTime then return end --we want the function to do nothing in this condition
05        lastTime = workspace.DistributedGameTime --update lastTime
06        func(...) --call the original function with any arguments passed in
07    end
08end
09function CallFuncOncePerTimeArg(func) --func will run only if its first argument is unique for this time frame
10    local lastTime = -1
11    local args
12    return function(...)
13        if lastTime ~= workspace.DistributedGameTime then --reset args
14            args = {}
15            lastTime = workspace.DistributedGameTime
View all 43 lines...

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").

0
I held the keypad key for like 1-2 seconds when it printed another Enum.UserInputState.Begin. Thanks for your debounce suggestion, I'll look into it but don't think I'll make it use time (because there might be some time between the state firing a second time) but just use kind of bools like if table[key] ~= inputstate then table[key] = inputstate code() end! Happywalker 185 — 8y
0
That was important information you didn't mention. Anyway, you're correct that using a table like that will work. I'd use: dict[key] = true/false (recording whether the button is currently pressed down or not), and only fire the 'OnDown' function if it's not already pressed down. chess123mate 5873 — 8y
Ad
Log in to vote
0
Answered by
Dorx86 0
8 years ago

I recomend ContextActionService, its a eaiser version of UserInputServer

01local createMobileButton = true -- if u want mobile buttons
02local actionName = "CallFuncOncePerTimeArg"
03 
04local function onMouseDown(actionName,state,info)
05    if state == Enum.UserInputState.Begin then
06            function CallFuncOncePerTime()
07    local lastTime = -1
08    return function(...)
09        if lastTime == workspace.DistributedGameTime then return end
10        lastTime = workspace.DistributedGameTime
11        func(...)
12    end
13end
14    elseif state == Enum.UserInputState.End then
15        print("Stopped Using Func")
16    end
17end
18 
19contextAction:BindAction(actionName,onMouseDown,createMobileButton,Enum.UserInputType.MouseButton1)

Answer this question