roblox-input · diff
git:20261002.854861b to git:20261015.16e1a69
21 added, 39 removed. Audit A to A.
---
name: roblox-input
- description: "Use when handling Roblox keyboard, mouse, gamepad, touch, motion input, or cross-platform action binding."
- last_reviewed: 2026-10-02
+ description: "Use when handling Roblox touch, gamepad, keyboard, mouse or motion input, on-screen action buttons, or cross-platform action binding."
+ when_to_use: "Also when a button fires by accident, controls don't work on mobile or console, a controller gets stuck in a menu, or button prompts show the wrong key."
+ last_reviewed: 2026-10-14
sources:
- https://devforum.roblox.com/t/the-correct-way-to-design-mobile-buttons/2494558
- https://create.roblox.com/docs/reference/engine/classes/UserInputService
+ - https://create.roblox.com/docs/reference/engine/enums/PreferredInput
+ - https://create.roblox.com/docs/input/mobile
+ - https://create.roblox.com/docs/production/publishing/console-guidelines
+ - https://create.roblox.com/docs/reference/engine/classes/ContextActionService
+ - https://create.roblox.com/docs/reference/engine/classes/Tool
+ - https://create.roblox.com/docs/studio/controller-emulator
+ - original
- https://create.roblox.com/docs/projects/server-authority
- https://create.roblox.com/docs/ui/3D-drag-detectors
- https://create.roblox.com/docs/ui/ui-drag-detectors
---
# Roblox Input
## When to Load
- Load for keyboard, mouse, gamepad, touch, motion, or cross-platform action binding. Client-side only. For simulation-affecting input in a Server Authority project, use the Input Action System rather than traditional input events.
+ Touch, gamepad, keyboard, mouse or motion input, on-screen action buttons, cross-platform binding. Client-only; Server Authority simulation input uses the Input Action System.
## Quick Reference
- **Core events** (`UserInputService`): `InputBegan`, `InputChanged`, `InputEnded` fire as `(input: InputObject, gameProcessedEvent: boolean)`. `InputBegan` does NOT fire for mouse wheel. Events only fire while the client window is focused.
-
- **Prefer `ContextActionService` over `InputBegan`** for gameplay: free conflict resolution (chat won't steal H) and free mobile buttons:
-
- ```luau
- local CAS = game:GetService("ContextActionService")
-
- local function onAction(name, state, _input)
- if name == "Jump" and state == Enum.UserInputState.Begin then
- humanoid.Jump = true
- end
- end
-
- CAS:BindAction("Jump", onAction, true,
- Enum.KeyCode.Space, Enum.KeyCode.ButtonA)
- ```
-
- `BindAction(name, handler, createTouchButton, ...inputTypes)`. Handler returns `ContextActionResult.Sink` to consume, `.Pass` to fall through.
-
- **Server Authority:** use `InputAction`/`InputContext` for inputs that affect the core simulation, store the input state where the synchronized simulation can read it, and process it through `RunService:BindToSimulation()` (requires `Workspace.UseFixedSimulation` enabled in Studio). `ContextActionService` remains appropriate for UI-only or classic-project actions.
-
- **Gamepad UI focus:** separate gameplay bindings from menu selection. Set `GuiService.SelectedObject`, mark controls `Selectable`, and test nested/modal navigation.
-
- **Gamepad:** use `GetConnectedGamepads()` and listen to connection changes.
-
- **Touch:** use high-level gesture events or raw `TouchStarted`/`TouchMoved`/`TouchEnded` when tracking fingers.
-
- **Dragging:** `DragDetector` (3D parts/models, physics-capable) and `UIDragDetector` (UI) make objects draggable with zero code; events `DragStart`/`DragContinue`/`DragEnd`.
-
- **Pitfalls**:
- - `gameProcessedEvent=true` in InputBegan → UI consumed it. Filter for gameplay.
- - `BindAction` is stack-based: most-recent wins. Use `BindActionAtPriority`.
- - Client-only. Server scripts silently no-op.
- - `JumpRequest` fires multiple times per jump; debounce.
- - Mouse wheel only fires `InputChanged`.
+ - **Events:** `InputBegan/Changed/Ended` give `(input, gameProcessedEvent)`; filter it for gameplay. Wheel fires only `InputChanged`.
+ - **Bindings:** prefer `ContextActionService:BindAction(name, handler, touchButton, ...keys)`; gate on `state` (touch is `KeyCode.Unknown`); stack order, so `BindActionAtPriority`. Server Authority: `InputAction`/`InputContext` + `RunService:BindToSimulation()` (needs `Workspace.UseFixedSimulation`).
+ - **Mobile first, hybrid aware:** show controls from `UserInputService.PreferredInput` (`Enum.PreferredInput`), observed with `GetPropertyChangedSignal`, not from `TouchEnabled` cached once.
+ - **Touch action buttons:** fire only for touches that began on the button; camera drags across it never fire. Place from the measured jump button under `PlayerGui.TouchGui`; clear the thumbstick zone.
+ - **Gate gameplay:** block attacks while a game window is open, a `TextBox` is focused, `GuiService.MenuIsOpen`, or `GuiService.SelectedObject` is set.
+ - **Cancel is not release:** holds cancel on window open, `Cancel`, unequip, focus loss, input switch or pad disconnect.
+ - **Gamepad tools:** default controls bind `ButtonR2` through `BindActivate`; `Tool.ManualActivationOnly = true` disables it. Aim from the screen center on gamepad, not `GetMouseLocation()`.
+ - **Hints:** `GetStringForKeyCode(key, Enum.KeyCodeStringFormat.Abbreviated)`, `GetImageForKeyCode`, or `InputActionLabel`; never hardcode Xbox names.
+ - **Test:** Device Simulator + Controller Emulator; menu focus is in `roblox-gui`.
- Full event tables and polling methods: `references/full.md`.
+ > Details: [references/full.md](references/full.md)