UserInputService in-depth.

Learn how to make a debounced, tool compatible UserInputService script!

by Gojinhan

Author Avatar

UserInputService is the service that tracks ALL userinputs. To even work with it, we of course must obtain it:

local uis = game:GetService("UserInputService")

There are an extremely large amounts of applications for this service. The most common usage is tracking key presses, but it's useful for adding Gamepad support, and mobile support to your games as well.

e.g:

if uis.TouchEnabled then
   print("Mobile user")
end

That may not be perfect however. As people who use things like HP Pavillion desktops will be flagged as a mobile user just because they have a touch screen as an available input.

Let's get into some common applications for this & some explaining. :D

(Tracking Keypresses)

let's start by each line, then combine at the end. This is just to help explain better.

uis.InputBegan:connect() 


end

These lines are an event, when somebody triggers ANY input, any form of interaction with the user's connected peripherals this will fire. So what we can do is establish a connection:

uis.InputBegan:connect(function(input,  gp) -- Very necessary arguments!

end)

Let's explain the arguments we just used. 'input' the very first argument in InputBegan, is the input object, this variable tracks whatever input we just did to Fire that event. gp, short for GameProcessed is a way of tracking if the input was fired while the player was chatting or in the pause menu.

gp is a bool value, so if we were chatting or something, it would return true. Otherwise, it will always be false.

You might have already figured it by now, but we can setup a reliable keypress tracker with this.

uis.InputBegan:connect(function(input,  gp)
    if gp then
        return -- if yes, end the function.
    else
        -- do stuff.
    end
    end
end)

Now let's utilizize this input object.


uis.InputBegan:connect(function(input, gp)
    if gp then
        return
    else
        if input.KeyCode == Enum.KeyCode.Q then
            -- do stuff
        end
    end
end)

If our 'keycode' input from our keyboard was equal to the Q key (change that key to anything you like.), the if statement would execute. Just like how we can get a keycode from a keyboard, we can indeed get input from our mouse. So instead of using player:GetMouse() or all that, we can use our fresh and modern inputservice.


uis.InputBegan:connect(function(input, gp)
    if gp then
        return
    else
        if input.UserInputType == Enum.UserInputType.MouseButton1 then
            -- do stuff
        end
    end
end)

If our input 'type' was our button1 on our mouse, (aka left click) then we execute that if statement.

let's get into making this compatible with tool equipping, unequipping, debouncing, and input ended.

Let's start with InputEnded. It's short and can be explained easily. I don't mean to be lazy, but it's literally the exact same thing as InputBegan except it fires when any input is not used anymore. So we can do something like this:

local attacking = false

uis.InputBegan:connect(function(input, gp)
    if gp then
        return
    else
        if input.UserInputType == Enum.UserInputType.MouseButton1 then
            attacking = true
            print("charging attack")
        end
    end
end)




uis.InputEnded:connect(function(input, gp)
    if gp then
        return
    else
        if input.UserInputType == Enum.UserInputType.MouseButton1 then
            attacking = false
            print(" attack charge done: ")
        end
    end
end)

This is especially useful for attack charging. Have it charge when InputBegan, then fire it off when that input ends.

Let's make it compatible with tools, then make it debounced. Otherwise this may get confusing.

(Let's assume this whole entire script is in a local script that is parented to a tool.)

local tool = script.Parent
local equipped = false

tool.Equipped:connect(function()
    equipped = true
end)

tool.Unequipped:connect(function()
    equipped = false
end)

uis.InputBegan:connect(function(input, gp)
    if gp then
        return
    else
        if input.UserInputType == Enum.UserInputType.MouseButton1 and equipped then
            -- do stuff
        end
    end
end)

So if our tool was equipped, and we did our input we'd execute the function. Simple, do not forget to check your 'RequiresHandle' property of your tool. I've made this mistake plenty of times developing some magic tools that don't have a handle then spending many wasted minutes wondering why .Equipped and Unequipped never fired. If you don't have a handle in your tool, untick that property. If you do have a handle, don't worry about it and do nothing.

Now let's debounce!

local tool = script.Parent
local equipped = false
local debounce = false

tool.Equipped:connect(function()
    equipped = true
end)

tool.Unequipped:connect(function()
    equipped = false
end)

uis.InputBegan:connect(function(input, gp)
    if gp then
        return
    else
        if input.UserInputType == Enum.UserInputType.MouseButton1 and equipped and not db then
            debounce = true
            -- do stuff

            wait(5)
            debounce = false
        end
    end
end)

That's all there is to that application :D If debounce was false, we'd make it true so the function cannot run anymore (as indicated in our extension to the if statement) Then after a cooldown, we'd make it false again so it can run. :D

There are many, many many more things you can do with UserInputService, but I'll leave it at here. Thank you for reading :)

View in-game to comment, award, and more!