Appearance
Steam Input
Controller and gamepad support via Steam Input API.
Overview
Steam Input provides a unified API for all controller types:
- Xbox controllers
- PlayStation controllers (DualShock 4, DualSense)
- Nintendo Switch Pro Controller
- Steam Controller
- Generic gamepads
The API is action-based, meaning you define actions (like "Jump", "Move") in Steam and query their state, rather than checking individual buttons.
Setup
1. Configure Actions in Steamworks
Before using Steam Input, configure your game's actions in the Steamworks Partner Portal:
- Go to App Admin > Steam Input
- Create an Action Set (e.g., "GameControls")
- Define Digital Actions (buttons) like "jump", "fire", "pause"
- Define Analog Actions (sticks/triggers) like "move", "look"
- Set up default bindings for each controller type
2. Initialize Steam Input
javascript
// Initialize Steam Input (call once at game start)
const success = await steam.initInput(false);
if (success) {
console.log('Steam Input ready');
}Methods
initInput(explicitlyCallRunFrame)
Initialize the Steam Input system.
javascript
await steam.initInput(false);Parameters:
explicitlyCallRunFrame(boolean): Iftrue, you must callinputRunFrame()manually. Iffalse, Steam handles it automatically.
Returns: Promise<boolean> - true if successful
shutdownInput()
Shutdown Steam Input. Call when your game exits.
javascript
await steam.shutdownInput();inputRunFrame(reserved)
Process input events. Only needed if initInput(true) was called.
javascript
// In your game loop
await steam.inputRunFrame(false);getConnectedControllers()
Get all connected controller handles.
javascript
const controllers = await steam.getConnectedControllers();
// Returns array of controller handle strings: ["12345", "67890"]Returns: Promise<string[]> - Array of controller handles
getActionSetHandle(name)
Get handle for an action set defined in Steamworks.
javascript
const actionSet = await steam.getActionSetHandle('GameControls');Returns: Promise<string> - Action set handle
activateActionSet(controllerHandle, actionSetHandle)
Activate an action set for a controller.
javascript
const controllers = await steam.getConnectedControllers();
const actionSet = await steam.getActionSetHandle('GameControls');
for (const controller of controllers) {
await steam.activateActionSet(controller, actionSet);
}getDigitalActionHandle(name)
Get handle for a digital action (button).
javascript
const jumpAction = await steam.getDigitalActionHandle('jump');getAnalogActionHandle(name)
Get handle for an analog action (stick/trigger).
javascript
const moveAction = await steam.getAnalogActionHandle('move');getDigitalActionData(controllerHandle, actionHandle)
Get current state of a digital action.
javascript
const data = await steam.getDigitalActionData(controller, jumpAction);
// { state: true/false, active: true/false }
if (data.active && data.state) {
player.jump();
}Returns:
typescript
{
state: boolean, // true = pressed
active: boolean // true = action is bound and available
}getAnalogActionData(controllerHandle, actionHandle)
Get current state of an analog action.
javascript
const data = await steam.getAnalogActionData(controller, moveAction);
// { mode: 1, x: 0.5, y: -0.3, active: true }
if (data.active) {
player.velocity.x = data.x * speed;
player.velocity.y = data.y * speed;
}Returns:
typescript
{
mode: number, // Input source mode
x: number, // X axis (-1.0 to 1.0)
y: number, // Y axis (-1.0 to 1.0)
active: boolean // true = action is bound and available
}getInputTypeForHandle(controllerHandle)
Get the type of controller.
javascript
const type = await steam.getInputTypeForHandle(controller);Returns: Promise<number> - Controller type enum:
| Value | Type |
|---|---|
| 0 | Unknown |
| 1 | Steam Controller |
| 2 | Xbox 360 |
| 3 | Xbox One |
| 4 | Generic XInput |
| 5 | PS4 |
| 6 | Apple MFi |
| 7 | Android |
| 8 | Switch Pro |
| 9 | Steam Deck |
| 10 | PS3 |
| 11 | PS5 |
Complete Example
javascript
// Initialize
let controllers = [];
let actionSet, jumpAction, moveAction;
async function initControls() {
if (!await steam.initInput(false)) {
console.log('Steam Input not available');
return;
}
// Get action handles (defined in Steamworks)
actionSet = await steam.getActionSetHandle('GameControls');
jumpAction = await steam.getDigitalActionHandle('jump');
moveAction = await steam.getAnalogActionHandle('move');
// Activate for all controllers
controllers = await steam.getConnectedControllers();
for (const c of controllers) {
await steam.activateActionSet(c, actionSet);
}
console.log(`${controllers.length} controller(s) connected`);
}
// Game loop
async function update() {
// Refresh controller list periodically
controllers = await steam.getConnectedControllers();
for (const controller of controllers) {
// Check jump button
const jump = await steam.getDigitalActionData(controller, jumpAction);
if (jump.active && jump.state) {
player.jump();
}
// Read movement stick
const move = await steam.getAnalogActionData(controller, moveAction);
if (move.active) {
player.velocity.x = move.x * player.speed;
player.velocity.y = move.y * player.speed;
}
}
}
// Cleanup
async function cleanup() {
await steam.shutdownInput();
}Notes
- Steam Input requires action configuration in the Steamworks Partner Portal
- Without configured actions,
getDigitalActionDataandgetAnalogActionDatawill returnactive: false - For simple gamepad support without Steam, consider using the browser's Gamepad API (
navigator.getGamepads()) - Steam Input works on Windows, macOS, and Linux
- The Steam Deck automatically uses Steam Input for all games
Browser Gamepad API Alternative
If you don't need Steam-specific features, the browser's Gamepad API works without configuration:
javascript
function pollGamepad() {
const gamepads = navigator.getGamepads();
for (const gp of gamepads) {
if (!gp) continue;
// Buttons
if (gp.buttons[0].pressed) player.jump(); // A button
// Sticks
player.velocity.x = gp.axes[0] * speed; // Left stick X
player.velocity.y = gp.axes[1] * speed; // Left stick Y
}
}The browser API works in all GemShell builds, even without Steam.
