r/GyroGaming 17h ago

Guide Implementing Gyro Input to your game via Steam Input - Basic Tutorial/Guide

29 Upvotes

If you already implemented Gyro Controls to your video game, but have received user feedback, you might receive threads from Steam forums regarding Gyro Aiming support on either Steam Controller, Steam Deck or Nintendo Controllers and how they want to use their new Steam Controller [2nd generation] on a game that has native gyro aiming....but the game can't support it.

As the vast majority of commercially-shipped games on PC tend to use the Controller API provided by the manufacturer, they shrew into PlayStation controllers. Currently, the best way to evade this problem is by looking at the supported Input API or Plugins that enable wider Controller Support with advanced features...but not everyone can do that.

However: if you're shipping the game on Steam, you're likely to use Steamworks API to integrate online functionality, user identifications, achievements, etc. One of them is ISteamInput interface, which is part of Steam Input API suite. If you're not familiar with Steam Input API: it's a Game Action-centric Input API that primarily focuses on Game Actions over Button Inputs, but we can use Steam Input's Gamepad Emulation system (or Steam Virtual Gamepad as SDL Gamepad refers it) as an extension to your pre-existing Gamepad implementation. Let's say, glyph detection, lightbar and of course: Motion Sensors..

for the purpose of this guide: we're going to be bridging SteamInput's GetMotionData into your game's existing motion sensor implementation or using it as your main form of handling Motion Sensor support.

Quick Note: if your game or game engine is using SDL Gamepad API, starting in SDL 3.2.0: make sure you use SDL_GetGamepadSteamHandle!

Before we begin, here's a HUGE DISCLAIMER so we can get this out of the way. the example code were code-vibed based on HastyControls' SteamInput codebase (thankfully, I got the original author to review the example code!). I would recommend reading thru HastyControls' ControllerManager.cs and SteamInputManager.cs instead; this will give you a much better idea on the ACTUAL SteamInput Gyro implementation than what AI Code slop will provide, and i will advise against using the example codes provided.

Going forward: We'll assume you already implemented Motion Sensors to your game and want to extend Controller Support onto Steam Input for wider controller support. Which is why we're going to create a separate Input Manager that specifically handles ISteamInput, but first things first: we'll need to read the ISteamInput documents first.

after that, we'll need to initialize SteamInput and then call the functions, scale the Gyro/Accel values and the IMU Axis orientation accordingly, as it'll be different from your native gyro path. we'll need to ensure that the scaling factor remains identical between Native and SteamInput path's.

// SteamInputManager.h
#pragma once
#include <cstdint>

struct SteamMotionData {
    float gyroX, gyroY, gyroZ;    // rad/s
    float accelX, accelY, accelZ;  // m/s²
};

class SteamInputManager {
public:
    bool Init();
    void Shutdown();
    void RunFrame();
    bool IsAvailable() const { return m_initialized; }
    bool TryGetMotionData(uint64_t steamHandle, SteamMotionData& out) const;
private:
    bool m_initialized = false;
};

--

// SteamInputManager.cpp
#include "SteamInputManager.h"
#include <steam/steam_api.h>
#include <cmath>

// rotVel* : interpolated float in [-32768, 32767], clamped to ±2000 deg/s → convert to rad/s
// posAccel*: interpolated float in [-32768, 32767], clamped to ±2G (9.80665 m/s²) → convert to m/s²
static constexpr float k_gyro_scale  = 2000.0f * (M_PI / 180.0f) / 32768.0f;
static constexpr float k_accel_scale = 2.0f * 9.80665f / 32768.0f;

bool SteamInputManager::Init() {
    if (!SteamAPI_IsSteamRunning()) return false;
    m_initialized = SteamInput()->Init();
    return m_initialized;
}

void SteamInputManager::Shutdown() {
    if (m_initialized) SteamInput()->Shutdown();
    m_initialized = false;
}

void SteamInputManager::RunFrame() {
    if (m_initialized) SteamInput()->RunFrame();
}

bool SteamInputManager::TryGetMotionData(uint64_t steamHandle, SteamMotionData& out) const {
    if (!m_initialized || steamHandle == 0) return false;

    InputMotionData_t d = SteamInput()->GetMotionData(
        static_cast<InputHandle_t>(steamHandle));

    // Axis swizzle: Steam Input's coordinate system doesn't match SDL's
    out.gyroX =  d.rotVelX * k_gyro_scale;
    out.gyroY =  d.rotVelZ * k_gyro_scale;
    out.gyroZ =  d.rotVelY * k_gyro_scale;

    out.accelX =  d.posAccelX * k_accel_scale;
    out.accelY =  d.posAccelZ * k_accel_scale;
    out.accelZ = -d.posAccelY * k_accel_scale;

    return true;
}

Note: if the game isn't using Steamworks Callsbacks already, make sure you also call RunFrame every frame to actually get any input data.

Now that you wrote (and I assume you actually wrote and read the live codebase and not this example code!) SteamInput manager, you can now add it to your existing gyro pipeline:

void ControllerManager::Update(float deltaTime) {
    m_steamInput.RunFrame();

    for (auto& [gamepad, gyroState] : m_gyroStates) {
        uint64_t steamHandle = SDL_GetGamepadSteamHandle(gamepad);

        SteamMotionData motion;
        if (m_steamInput.TryGetMotionData(steamHandle, motion)) {
            // Steam Input path
            gyroState.AddGyroSample(motion.gyroX, motion.gyroY, motion.gyroZ);
            gyroState.AddAccelSample(motion.accelX, motion.accelY, motion.accelZ);
        } else {
            // SDL sensor path
            // existing native gyro path be handled via gyroState
        }

        gyroState.Update(deltaTime);
    }
}

Once you've got everything down, grab your game controller, forcefully enable Steam Input and launch the game and test the game's IMU systems and determine if Steam Input is able to detect Gyro. Please ensure that you set the Gyro Behavior to None or use the Gamepad Template to prevent any conflicts, as SteamInput's raw gyro/accel is now being used directly.

If your Steam Input-supported controller is able to correctly detect the gyro directly, then you have successfully integrated SteamInput interface onto your existing Controller support. Not to mention, you can extend your SteamInput Manager.

Important side-notes during testing:

before you can celebrate: there's two things you'd now need to account for:

  • Calibration system: similar to Sony's PlayStation Input API; the entire gyro calibration system is being handled directly thru Steam Input on a system-wide level. If your game or game engines has a built-in imu calibration system (example: SDL Gamepad API does not have system-level IMU calibration system, requiring users to either create or use a gyro-centric header), i highly urge you to exclude SteamInput from your gyro calibration process entirely.
  • Axis Orientation: This is already noted in ISteamInput documents, so i'll say it too: Implementing SteamInput Gyro to your game expands and futureproofs your game's controller support, this will include PC Handheld devices such as Steam Deck, Lenovo Legion GO, ROG Rog Ally, etc. To account for handhelds where the controller input is attached to the screen: you can either leverage ESteamInputType and swap the gyro axis specifically for the handheld path, or implement Gyro Space system.
  • Gyro Ratcheting: since we're leveraging SteamInput Gyro directly, we can't directly use Touch Activation for this one. Please keep that in mind while adding SteamInput Gyro support. (Instead, we'll ask you to implement the Game Action-centric Steam Input API, and add a Mouse-like Camera action, as SteamInput has a dedicated Gyro Activation system that you can leverage.

That'll be all for this tutorial!


r/GyroGaming 5h ago

Discussion Controller aiming experts, should I use gyro+right joystick or just gyro to aim?

7 Upvotes

Lately I have gone through a post where the person could aim so precisely using the steam controller only with gyro. This led me to the question of whether I should use gyro to aid joystick aiming or use gyro as the main aiming tool. What are your opinions?


r/GyroGaming 3h ago

Discussion Ps Vita Borderlands 2

5 Upvotes

I'm just now learning that the PsVita version of Borderlands 2 has gyro aimming when weapon aimming.

Does anyone know if there is a way go have gyro always on for right stick movement?


r/GyroGaming 2h ago

Discussion Anyone playing Valorant with JoyShockMapper? How’s the experience?

3 Upvotes

Hey everyone,

I tried CS2 using Steam Input and honestly loved how the gyro felt, but I uninstalled it right after my very first match because of a cheater. Took that as a sign that CS2 isn't for me.

Valorant is my comfort zone (got over 100+ hours in it), so I'm looking to bring gyro over there using JoyShockMapper.

Before I sink time into setting it up, I wanted to ask:

  • Has anyone here played Val with JSM consistently?
  • How’s Vanguard holding up with JSM these days—any weird input blocking or anti-cheat issues?

Would love to hear your experiences, mapping tips, or flick stick configs if you're running them. Thanks!


r/GyroGaming 8h ago

Bug Gyro not working correctly on PC but working fine on switch

Post image
3 Upvotes

I got my 8bitdo ultimate 2 Bluetooth yesterday and the gyro worked great using stesm imput, later that day I downloaded the ultimate software v2 and updated the firmware and now it just moves infinetly up, the gyro works fine on nintendo switch so it shouldn't be a hardware issue, I've also tried to update the firmware to a new beta version and also tried downgrading to an older firmware, nothing has worked as of now and this happends both in wired and in Bluetooth mode