A lightweight ContextActionService wrapper for Roblox that unifies desktop keyboard/mouse, gamepad, and mobile touch input behind a single API.
- One API for all platforms — define input once, works on PC and mobile
- Two mobile modes — use your own GUI buttons or let CAS auto-create touch buttons
- Config-driven — declarative
InputConfigtables keep bindings readable
- Place
InputService.luauin a shared module folder (e.g.ReplicatedStorage/Input) - In any
ScriptorLocalScript:
local InputService = require(path.to.InputService)Binds a named action. Platform is auto-detected via UserInputService.TouchEnabled unless overridden.
| Param | Type | Description |
|---|---|---|
name |
string |
Unique action identifier |
config |
InputConfig |
Trigger, callbacks, and mobile options |
isMobile? |
boolean? |
Force mobile mode override |
Unbinds a single action and cleans up all connections.
Unbinds all tracked actions and calls CAS:UnbindAllActions().
Returns true if the action is currently bound (checks both custom button and CAS bindings).
Defined at the top of InputService.luau:
type InputConfig = {
Trigger: {Enum.UserInputType | Enum.KeyCode}
| (Enum.UserInputType | Enum.KeyCode),
OnInputBegan: ((InputObject) -> ())?,
OnInputEnded: ((InputObject) -> ())?,
MobileButton: (TextButton | ImageButton)?,
Sink: boolean?,
}| Field | Description |
|---|---|
Trigger |
A single key/input type or an array of them that activate this action |
OnInputBegan |
Fires when the input starts |
OnInputEnded |
Fires when the input ends |
MobileButton |
Optional. A TextButton or ImageButton reference for custom UI on any platform |
Sink |
If true, consumes the input so it doesn't propagate |
The module has two mobile paths — custom UI and auto-created — determined by whether MobileButton is set:
When you pass a MobileButton reference, the module connects directly to the button's InputBegan/InputEnded events. Works the same on PC and mobile.
local myButton = script.Parent.JumpButton -- GuiButton
InputService.Bind("Jump", {
Trigger = Enum.KeyCode.Space,
MobileButton = myButton,
OnInputBegan = function()
-- handle jump
end,
})When MobileButton is nil and the device is mobile, ContextActionService:BindAction() is called with createTouchButton = true, which spawns a built-in on-screen button automatically. No GUI work needed.
InputService.Bind("Reload", {
Trigger = Enum.KeyCode.R,
OnInputBegan = function()
-- handle reload
end,
})On desktop the same config binds to the R key instead.
InputService.Bind("Shoot", {
Trigger = { Enum.UserInputType.MouseButton1, Enum.KeyCode.ButtonR2 },
OnInputBegan = function()
weapon:StartFiring()
end,
OnInputEnded = function()
weapon:StopFiring()
end,
Sink = true,
})InputService.Bind("Interact", {
Trigger = Enum.KeyCode.E,
MobileButton = script.Parent.InteractButton,
OnInputBegan = function()
proximityPrompt:Trigger()
end,
})InputService.UnBind("Shoot")
InputService.UnBindAll()MIT © 2025 Mawin Chuangkud