useGamepadEventHandler
Gamepad Overview
Kepler supports gamepad devices for both navigation and game controls in React Native for Kepler apps. Gamepads can trigger:
- Key events (For example, pressing A, B, or triggers)
- Axis events (For example., moving thumbsticks or the D-Pad)
Apps can consume these inputs by subscribing to either primary, secondary, or both types of events, which are exposed via Kepler's React Native hooks.
- Primary events are the raw, gamepad-specific inputs such as thumbstick movement or key presses.
- Secondary events are the high-level TV navigation events such as
select
,back
,up
,down
that are mapped to gamepad inputs where appropriate.
Input Events
Ideally, all gamepads can support multiple input events for a particular key or axis action. For instance, pressing the action button 'A' on the gamepad produces a primary event of action_btn_a
and a secondary event of select
, if the app is subscribed to it. This is useful when an app wants to perform navigation or item selection on the screen using a gamepad instead of a TV remote, as the secondary events provide those capabilities.
useGamepadEventHandler
and secondary events via useTVEventHandler
or TVEventHandler
, then a single key or axis action can trigger both primary and secondary events. Make sure the app logic handles this accordingly. For information about useTVEventHandler
and TVEventHandler
, see TVEventHandler
.Kepler provides a dedicated hook called useKeplerBackHandler
for handling custom back event logic, which doesn't handle events through useTVEventHandler
or TVEventHandler
. By default, useKeplerBackHandler
returns false
if the app hasn't subscribed to it, meaning that whenever a back button is pressed the system acknowledges it to navigate to previous window. If this behavior is not appropriate for the app or you need to handle the logic from the JavaScript layer, then a subscription must be added through useKeplerBackHandler
, and the handler should return true
along with any custom logic.
Gamepad Input Events Mapping
Gamepad Buttons | Primary Events | Secondary Events |
---|---|---|
A | action_btn_a |
select |
B | action_btn_b |
back |
X | action_btn_x |
none |
Y | action_btn_y |
none |
Left Stick [left/right] | axis -> left_stick_x |
left or right if Math.abs(axis value) > 0.5 |
Left Stick [up/down] | axis -> left_stick_y |
up or down if Math.abs(axis value) > 0.5 |
Right Stick [left/right] | axis -> right_stick_x |
none |
Right Stick [up/down] | axis -> right_stick_y |
none |
Left Stick Press | left_stick_btn_thumbl |
none |
Right Stick Press | right_stick_btn_thumbr |
none |
Back | none | back |
Start | right_menu_btn_start |
none |
Select | left_menu_btn_select |
none |
Left Trigger [L2] | left_lower_trigger_btn_tl2 |
none |
Left Shoulder [L1] | left_upper_trigger_btn_tl |
none |
Right Trigger [R2] | right_lower_trigger_btn_tr2 |
none |
Right Shoulder [R1] | right_upper_trigger_btn_tr |
none |
D-Pad [left/right] | axis -> dpad_x |
left or right |
D-Pad [up/down] | axis -> dpad_y |
up or down |
Usage Reference
Subscribing to Primary/Default Events
An app can add a subscription to primary events by registering through useGamepadEventHandler
. This hook takes a handler method as an argument and returns a GamepadEventSubscription
object. The GamepadEventSubscription.enabled
property returns a boolean indicating whether the current handler is internally enabled if true
and disabled if false
. An app can control the subscription to primary events using GamepadEventSubscription.setEnabled
. Pass true
to enable the hook or false
to disable it.
The useGamepadEventHandler
hook has the following declaration which is exposed to JS layer.
export const useGamepadEventHandler: (handleEvent: (event: GamepadEvent) => void) => GamepadEventSubscription;
The following are the type definitions and interfaces used in the hook's definition above and the app must conform to these types.
export type GamepadEventSubscription = {
/**
* enabled flag indicates whether the current subscription is active or not.
*/
enabled: boolean,
/**
* setEnabled is used to enable/disable the subscription from JS layer.
* @param enable - Pass `true` to enable the subscription or `false` to disable it.
*/
setEnabled: (enable: boolean) => void
}
/**
* GamepadEvent is the payload that we receive from the native layer where eventType
* gives the current key/axis action.
* For example, if it is a key action and a user presses action button A then eventType
* will be 'action_btn_a' and eventKeyAction value will be 0 when pressed, 1 when released.
* If it is an Axis action and a user pushes left stick to right end, then eventType
* will be 'axis' and the axis object will include 'left_stick_x': 1 along with any
* other present axis values.
*/
export type GamepadEvent = {
eventType:
'action_btn_a'
| 'action_btn_b'
| 'action_btn_x'
| 'action_btn_y'
| 'dpad_btn_up'
| 'dpad_btn_down'
| 'dpad_btn_left'
| 'dpad_btn_right'
| 'left_stick_btn_thumbl'
| 'right_stick_btn_thumbr'
| 'right_upper_trigger_btn_tr'
| 'left_upper_trigger_btn_tl'
| 'left_lower_trigger_btn_tl2'
| 'right_lower_trigger_btn_tr2'
| 'left_menu_btn_select'
| 'right_menu_btn_start'
| 'axis'
| string;
eventKeyAction?: -1 | 0 | 1 | number;
axis?: AxisValues;
deviceIdentifier?: DeviceIdentifier;
};
interface AxisValues {
/**
* Current axis entries with their corresponding values.
*/
left_stick_x?: number,
left_stick_y?: number,
right_stick_x?: number,
right_stick_y?: number,
left_lower_trigger?: number,
right_lower_trigger?: number,
left_upper_trigger?: number,
right_upper_trigger?: number,
dpad_x?: number,
dpad_y?: number
}
interface DeviceIdentifier {
uniqueId?: string;
busId?: number;
vendorId?: number;
productId?: number;
version?: number;
}
The following example shows how to import the useGamepadEventHandler
hook.
import { useGamepadEventHandler } from "@amzn/react-native-kepler";
The following example usage shows how to use the useGamepadEventHandler
hook in an app.
import React, { useCallback, useState } from 'react';
import { View, Text, StyleSheet, ScrollView } from '@amzn/react-native-kepler';
import { useGamepadEventHandler, GamepadEvent } from '@amzn/react-native-kepler';
const GamepadEventLogger = () => {
const [log, setLog] = useState<string[]>([]);
const handleGamepadEvent = useCallback((event: GamepadEvent) => {
const { eventType, eventKeyAction, axis } = event;
const axisEntries = axis
? Object.entries(axis)
.map(([key, val]) => `${key}: ${val?.toFixed(2)}`)
.join(', ')
: '';
const logEntry = `[${new Date().toLocaleTimeString()}] ${eventType}${
axisEntries ? ` | Axis: ${axisEntries}` : ''
}${eventKeyAction !== undefined ? ` | Action: ${eventKeyAction}` : ''}`;
setLog(prev => [logEntry, ...prev.slice(0, 29)]);
}, []);
const {enabled, setEnabled} = useGamepadEventHandler(handleGamepadEvent);
return (
<View style={styles.container}>
<Text style={styles.title}>Gamepad Event Log</Text>
<ScrollView style={styles.scroll}>
{log.map((entry, idx) => (
<Text key={idx} style={styles.logText}>{entry}</Text>
))}
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'black',
padding: 16,
},
title: {
color: 'white',
fontSize: 18,
fontWeight: 'bold',
marginBottom: 12,
},
scroll: {
flex: 1,
},
logText: {
color: 'white',
fontSize: 14,
marginBottom: 4,
},
});
export default GamepadEventLogger;
For information about subscribing to secondary events, see TVEventHandler
.
Related topics
TVEventHandler
: UseuseTVEventHandler
to subscribe to high-level navigation events such asup
,down
, andselect
etc.useKeplerBackHandler
: Handle back-button events with custom logic from the JavaScript layer.
Last updated: Sep 30, 2025