---
title: "Micro gamepad input"
url: /docs/en-us/input/micro-gamepad
last_updated: 2026-10-02T21:48:44Z
description: "Explains how to accept input from micro gamepads, such as TV remotes, which provide directional navigation and a small set of buttons."
---

# Micro gamepad input

Roblox experiences can receive input from **micro gamepads**, navigation-focused controllers that typically provide a directional pad and can include additional buttons. TV remotes are one type of micro gamepad; they commonly provide a directional pad, center button, and back button. Micro gamepads use the `Enum.UserInputType|Gamepad1`–`Enum.UserInputType|Gamepad8` input slots and are represented as `Enum.PreferredInput|MicroGamepad` when they are the player's preferred input.

TV remotes expose TV remote-specific keycodes, but their button events currently map to legacy gamepad keycodes before reaching experience code. Use the [Input Action System](/docs/en-us/input/input-action-system.md) or `Class.ContextActionService` to bind actions to those legacy events.

## Input type detection

`Enum.PreferredInput|MicroGamepad` is a future API for identifying TV remotes and other navigation-focused controllers. It is not currently set for these devices, so until runtime support is complete, check the supported keycodes for `Enum.UserInputType|Gamepad1`:

```lua
local UserInputService = game:GetService("UserInputService")

local function isMicroGamepadPreferred()
	local gamepad = Enum.UserInputType.Gamepad1
	if not UserInputService:GetGamepadConnected(gamepad) then
		return false
	end

	local supportsThumbstick1 = UserInputService:GamepadSupports(
		gamepad,
		Enum.KeyCode.Thumbstick1
	)
	local supportsThumbstick2 = UserInputService:GamepadSupports(
		gamepad,
		Enum.KeyCode.Thumbstick2
	)

	return not supportsThumbstick1 and not supportsThumbstick2
end
```

`Enum.UserInputType|Gamepad1` is always the most preferred connected gamepad. If a player has only a TV remote, it occupies `Enum.UserInputType|Gamepad1`. If another gamepad is connected, that gamepad occupies `Enum.UserInputType|Gamepad1` instead. Therefore, checking that `Enum.UserInputType|Gamepad1` supports neither `Enum.KeyCode|Thumbstick1` nor `Enum.KeyCode|Thumbstick2` indicates that the currently preferred gamepad is a micro gamepad.

If you need to identify a TV remote specifically, check whether the preferred gamepad supports `Enum.KeyCode|ButtonCenter` in addition to checking its micro gamepad capabilities:

```lua
local UserInputService = game:GetService("UserInputService")

local function isTVRemotePreferred()
	return isMicroGamepadPreferred()
		and UserInputService:GamepadSupports(
			Enum.UserInputType.Gamepad1,
			Enum.KeyCode.ButtonCenter
		)
end
```

Reuse `isMicroGamepadPreferred()` in your action handlers instead of implementing device detection separately for each action system. Use `isTVRemotePreferred()` only when behavior must be specific to a TV remote rather than to micro gamepads generally.

## Micro gamepad keycodes

Micro gamepads can expose these navigation-oriented keycodes. TV remotes commonly support this set:

| Keycode | Meaning |
| --- | --- |
| `Enum.KeyCode\|ButtonUp` | Move focus or selection up. |
| `Enum.KeyCode\|ButtonDown` | Move focus or selection down. |
| `Enum.KeyCode\|ButtonLeft` | Move focus or selection left. |
| `Enum.KeyCode\|ButtonRight` | Move focus or selection right. |
| `Enum.KeyCode\|ButtonCenter` | Confirm, select, or activate the focused item. |
| `Enum.KeyCode\|ButtonBack` | Cancel, close, or return to the previous screen. |

These are example TV remote capabilities; experiences might encounter additional supported keycodes. See [Legacy gamepad control schema](#legacy-gamepad-control-schema) for how these keycodes currently map to gamepad events.

## Legacy gamepad control schema

Until raw TV remote events are available, bind actions to the legacy keycodes generated by TV remote input. The mapping depends on the input context:

| TV remote keycode | Context | Current gamepad event | Common use |
| --- | --- | --- | --- |
| `Enum.KeyCode\|ButtonCenter` | All contexts | `Enum.KeyCode\|ButtonA` | Select or jump. |
| `Enum.KeyCode\|ButtonBack` | All contexts | `Enum.KeyCode\|ButtonB` | Go back, dismiss a dialog, or open the selector menu. |
| `Enum.KeyCode\|ButtonUp`, `Enum.KeyCode\|ButtonDown`, `Enum.KeyCode\|ButtonLeft`, `Enum.KeyCode\|ButtonRight` | Menu, selection mode, or virtual cursor | `Enum.KeyCode\|DPadUp`, `Enum.KeyCode\|DPadDown`, `Enum.KeyCode\|DPadLeft`, `Enum.KeyCode\|DPadRight` | Navigate focus or selection. |
| `Enum.KeyCode\|ButtonUp`, `Enum.KeyCode\|ButtonDown` | Studio or experience with Classic Camera | `Enum.KeyCode\|Thumbstick1` | Move the character. |
| `Enum.KeyCode\|ButtonLeft`, `Enum.KeyCode\|ButtonRight` | Studio or experience with Classic Camera | `Enum.KeyCode\|Thumbstick2` | Rotate the camera. |
| `Enum.KeyCode\|ButtonUp`, `Enum.KeyCode\|ButtonDown`, `Enum.KeyCode\|ButtonLeft`, `Enum.KeyCode\|ButtonRight` | Studio or experience with Follow Camera | `Enum.KeyCode\|Thumbstick1` | Move the character with an auto-rotated camera. |

> **Warning:** Do not use legacy keycodes alone to identify a TV remote. The same keycodes can also come from a full gamepad.
## Binding actions

Choose the approach that matches your experience:

- Use the [Input Action System](/docs/en-us/input/input-action-system.md) (IAS) for new input architecture or a structured migration. IAS uses `Class.InputContext`, `Class.InputAction`, and `Class.InputBinding` instances and action events such as `Pressed` and `Released`.
- Use `Class.ContextActionService` (CAS) if your experience already relies on `Class.ContextActionService` bindings.

Both examples below reuse the `isMicroGamepadPreferred()` helper from the [input type detection](#input-type-detection) section.

### Option 1: Input Action System

For example, create `ConfirmOrJump` and `BackOrCancel` actions with legacy `Enum.KeyCode|ButtonA` and `Enum.KeyCode|ButtonB` bindings:

```lua
local ReplicatedStorage = game:GetService("ReplicatedStorage")

-- Create these InputAction instances and bindings in Studio:
-- ReplicatedStorage.Inputs.NavigationContext.ConfirmOrJump -> ButtonA
-- ReplicatedStorage.Inputs.NavigationContext.BackOrCancel -> ButtonB
local navigationContext = ReplicatedStorage:WaitForChild("Inputs"):WaitForChild("NavigationContext")
local confirmOrJump = navigationContext:WaitForChild("ConfirmOrJump")
local backOrCancel = navigationContext:WaitForChild("BackOrCancel")

confirmOrJump.Pressed:Connect(function()
	if isMicroGamepadPreferred() then
		ActivateFocusedItem()
	else
		Jump()
	end
end)

backOrCancel.Pressed:Connect(function()
	if isMicroGamepadPreferred() then
		NavigateBack()
	else
		CancelGameplayAction()
	end
end)
```

For example, directional navigation actions can use `Enum.KeyCode|DPadUp`, `Enum.KeyCode|DPadDown`, `Enum.KeyCode|DPadLeft`, and `Enum.KeyCode|DPadRight` bindings and call focus-navigation functions only when `isMicroGamepadPreferred()` returns `true`. Use separate input contexts for navigation and gameplay so the same legacy button does not trigger both actions simultaneously.

### Option 2: ContextActionService

If your experience already uses CAS, keep the existing bindings and reuse the same capability check:

```lua
local ContextActionService = game:GetService("ContextActionService")

local function confirmOrJump(actionName, inputState)
	if inputState ~= Enum.UserInputState.Begin then
		return Enum.ContextActionResult.Pass
	end

	if isMicroGamepadPreferred() then
		ActivateFocusedItem()
	else
		Jump()
	end

	return Enum.ContextActionResult.Sink
end

ContextActionService:BindAction(
	"ConfirmOrJump",
	confirmOrJump,
	false,
	Enum.KeyCode.ButtonA
)
```

Use the same pattern for `Enum.KeyCode|ButtonB` and the D-pad bindings. Return `Enum.ContextActionResult|Pass` for input states you don't handle so other bound actions can still process them, and return `Enum.ContextActionResult|Sink` once you handle the input.

In the future, raw TV remote events will allow IAS or CAS actions to bind directly to `Enum.KeyCode|ButtonUp`, `Enum.KeyCode|ButtonDown`, `Enum.KeyCode|ButtonLeft`, `Enum.KeyCode|ButtonRight`, `Enum.KeyCode|ButtonCenter`, and `Enum.KeyCode|ButtonBack`, without legacy-keycode branching.

## Designing UI for TV remote input

- Provide a visible focus state for the selected item.
- Make every interactive item reachable with the four directional buttons.
- Use the center button for the primary action.
- Use the back button consistently to close, cancel, or return.
- Preserve focus when opening and closing menus.
- Use large controls and clear spacing for a 10-foot viewing experience.

## Controller emulation

Test on the target TV platform with a physical remote whenever possible. You can also emulate Android TV in Studio with the **Device Emulator** and [Controller Emulator](/docs/en-us/input/gamepad.md#controller-emulation).

Selecting Android TV makes Studio render a TV-sized 1920×1080 viewport and enables a virtual TV Remote on `Enum.UserInputType|Gamepad1`. The remote is driven from the keyboard or mouse and follows the same input path as a connected TV remote.

To test TV remote input:

1. Open Studio's **Test** menu, enable **Device Emulator**, and select the Android TV device in the Device Emulator.
2. Open the **Controller Emulator** and select **TV Remote** from the controller picker. The **TV Remote** controller is available only when Android TV is selected in the Device Emulator.
3. Use the displayed keyboard controls to send D-pad, center, and back input.
4. Verify the resulting `Class.UserInputService.InputBegan|InputBegan`, `Class.UserInputService.InputChanged|InputChanged`, and action events in your experience.

![View of the TV Remote controller in the Controller Emulator.](../assets/studio/general/Controller-Emulator-TVRemote.png)

You can control the virtual remote with the keyboard or mouse using the displayed mappings. To view or change those mappings, use **Edit mappings** in the Controller Emulator; see [Controller emulation](/docs/en-us/input/gamepad.md#controller-emulation) for more details.