Player input and cameras across keyboard/mouse, touch, gamepad, VR - Input Action System (InputContext, InputAction, InputBinding), UserInputService (PreferredInput, gameProcessedEvent, mouse lock), ContextActionService, reserved keys, custom cameras with BindToRenderStep. Use when adding controls, keybinds, abilities, vehicles, on-screen buttons, or custom cameras.
Installs into .claude/skills of the current project.
Are you the author of Roblox Input?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/el4cteo-roblox-input)
---
name: roblox-input
description: Player input and cameras across keyboard/mouse, touch, gamepad, VR - Input Action System (InputContext, InputAction, InputBinding), UserInputService (PreferredInput, gameProcessedEvent, mouse lock), ContextActionService, reserved keys, custom cameras with BindToRenderStep. Use when adding controls, keybinds, abilities, vehicles, on-screen buttons, or custom cameras.
---
# Roblox input and camera
## Choose an approach
| Approach | Use when |
| --- | --- |
| **Input Action System** (`InputContext` → `InputAction` → `InputBinding`) | New gameplay controls. Cross-device bindings configured as instances, contexts you enable/disable, built-in on-screen button binding, prompt display. Recommended. |
| `UserInputService` events | Raw input, text-free hotkeys, mouse position/delta, touch gestures, device detection. |
| `ContextActionService:BindAction` | Legacy/simple bind-with-mobile-button; existing code. |
All input handling is **client-side**. Send *intent* to the server via remotes; the server validates.
## Input Action System
Structure (typically in `ReplicatedStorage.Inputs`, or created from a client script):
```text
Inputs (Folder)
PlayContext (InputContext, Priority 1000) -- gameplay controls
Sprint (InputAction, Type = Bool)
Keyboard (InputBinding, KeyCode = LeftShift)
Gamepad (InputBinding, KeyCode = ButtonL3)
Touch (InputBinding, UIButton = <on-screen TextButton>)
MenuContext (InputContext, Priority 2000, Sink = true, Enabled = false)
```
- `InputAction.Type`: `Bool` (press/release), `Direction1D` (triggers, zoom), `Direction2D` (move, camera),
`Direction3D` (flying), `ViewportPosition` (pointer position).
- Events: `Pressed`, `Released` (Bool only), `StateChanged(value)` for every type. `action:GetState()` reads the current value.
- `InputBinding` fields: `KeyCode`; composite directions `Up/Down/Left/Right/Forward/Backward`; `Scale`
(e.g. `0.01` for `MouseDelta`/`TouchDelta`); `PressedThreshold`/`ReleasedThreshold` for analog triggers;
`PrimaryModifier`/`SecondaryModifier` for chords (Ctrl+S); `UIButton` to drive the action from a GUI button;
`DisplayName`/`DisplayImage` for prompts.
- `InputContext.Enabled` switches whole control schemes (gameplay ↔ menu ↔ vehicle); `Priority` + `Sink`
lets a higher context consume keys so lower contexts don't also fire.
- Set `Workspace.PlayerScriptsUseInputActionSystem = Enabled` to have Roblox's default player/camera
scripts use the system too (required for server authority).
```luau
--!strict
-- Client: build a Sprint action in code and react to it.
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local context = Instance.new("InputContext")
context.Name = "PlayContext"
context.Priority = 1000
local sprint = Instance.new("InputAction")
sprint.Name = "Sprint"
sprint.Type = Enum.InputActionType.Bool
sprint.Parent = context
local keyboard = Instance.new("InputBinding")
keyboard.KeyCode = Enum.KeyCode.LeftShift
keyboard.Parent = sprint
local gamepad = Instance.new("InputBinding")
gamepad.KeyCode = Enum.KeyCode.ButtonL3
gamepad.Parent = sprint
context.Parent = player:WaitForChild("PlayerScripts")
local function setSprinting(on: boolean)
local character = player.Character
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
if humanoid then
humanoid.WalkSpeed = if on then 24 else 16 -- server should validate/own real speed limits
end
end
sprint.Pressed:Connect(function()
setSprinting(true)
end)
sprint.Released:Connect(function()
setSprinting(false)
end)
```
Show the right key/button: an `InputActionLabel` (beta) auto-renders the binding for the current device,
or read `action.PreferredBinding` (+ its `DisplayName`/`KeyCode`) and `UserInputService:GetStringForKeyCode`
/ `GetImageForKeyCode`, updating on `GetPropertyChangedSignal("PreferredBinding")`.
## UserInputService essentials
```luau
--!strict
local UserInputService = game:GetService("UserInputService")
UserInputService.InputBegan:Connect(function(input: InputObject, gameProcessedEvent: boolean)
if gameProcessedEvent then
return -- typing in a TextBox, clicking UI, or a core-script action consumed it
end
if input.KeyCode == Enum.KeyCode.E then
print("interact")
elseif input.UserInputType == Enum.UserInputType.MouseButton1 then
print("click at", input.Position)
end
end)
local function onPreferredInputChanged()
local preferred = UserInputService.PreferredInput -- KeyboardAndMouse | Touch | Gamepad
print("show prompts for", preferred)
end
UserInputService:GetPropertyChangedSignal("PreferredInput"):Connect(onPreferredInputChanged)
onPreferredInputChanged()
```
- **Always honor `gameProcessedEvent`** or players trigger abilities while typing in chat.
- `PreferredInput` reflects what the player is actually using (phone + Bluetooth gamepad → `Gamepad`);
don't branch on `TouchEnabled`/`KeyboardEnabled` alone.
- Mouse: `UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter` for FPS (set every frame while
in first person if other scripts may reset it), `GetMouseLocation()` (includes top-bar inset),
`MouseDeltaSensitivity`, `MouseIconEnabled`.
- Gamepad: `GetConnectedGamepads`, `GamepadConnected/Disconnected`, thumbstick `input.Position` in
`InputChanged` (apply a dead zone ≈ 0.15). Haptics: `HapticService` / `HapticEffect`.
- Touch: `TouchTap`, `TouchLongPress`, `TouchPinch`, `TouchSwipe`; hide default controls only if you
replace them (`GuiService.TouchControlsEnabled`).
- Reserved keys you can't override: Esc/Start (menu), F9 (console), F11, F12, PrintScreen; chat `/`,
Tab (player list), backpack and tool-number keys unless you disable those core features.
## ContextActionService (legacy-compatible)
`ContextActionService:BindAction(name, handler, createTouchButton, ...inputs)` with handler
`(actionName, inputState, inputObject) -> Enum.ContextActionResult?`; return `Pass` to let other
bindings see the input. Use `BindActionAtPriority` for ordering and `UnbindAction` when the context
ends (e.g. tool unequipped). Prefer the Input Action System for new work.
## Custom cameras
```luau
--!strict
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local camera = workspace.CurrentCamera
local OFFSET = Vector3.new(0, 30, 20)
camera.CameraType = Enum.CameraType.Scriptable
RunService:BindToRenderStep("TopDownCamera", Enum.RenderPriority.Camera.Value + 1, function()
local character = Players.LocalPlayer.Character
local root = character and character:FindFirstChild("HumanoidRootPart") :: BasePart?
if root then
local target = root.Position
camera.CFrame = CFrame.lookAt(target + OFFSET, target)
end
end)
-- Restore: RunService:UnbindFromRenderStep("TopDownCamera"); camera.CameraType = Enum.CameraType.Custom
```
- Update cameras in `BindToRenderStep` (runs before render, ordered), not `Heartbeat`/`task.wait` loops.
- Smooth with `camera.CFrame:Lerp(goal, 1 - math.exp(-speed * deltaTime))` (frame-rate independent).
- First person: `player.CameraMode = Enum.CameraMode.LockFirstPerson`; zoom limits with
`player.CameraMinZoomDistance`/`CameraMaxZoomDistance`. Shake: offset the CFrame, don't move parts.
- Screen → world: `camera:ViewportPointToRay(x, y)` / `ScreenPointToRay` + `workspace:Raycast`.
## Cross-platform checklist
- Every action has keyboard, gamepad, **and** touch bindings (touch via `UIButton` or on-screen buttons).
- Prompts/hints update when `PreferredInput` changes. Console UI is navigable with D-pad and closes with B.
- No hover-only interactions (touch has no hover). Hold-to-confirm for destructive actions.
- Test in Studio's Device Emulator and Controller Emulator.
## Related skills
`roblox-ui` (buttons, gamepad selection), `roblox-characters-animation` (movement, abilities),
`roblox-networking` (sending intents), `roblox-physics` (vehicles).