Skip to content

WIP: Initial parts of Steam Input API support#1695

Draft
RobertCochran wants to merge 7 commits intoredeclipse:masterfrom
RobertCochran:siapi
Draft

WIP: Initial parts of Steam Input API support#1695
RobertCochran wants to merge 7 commits intoredeclipse:masterfrom
RobertCochran:siapi

Conversation

@RobertCochran
Copy link

WIP for Steam Input support, as requested on Discord.

There are several things that don't work, aren't implemented the way I'm supposed to, etc.

Perhaps the most important thing to note is that I broke the build for the Red Eclipse server. That needs addressing but it's not short-term important.

@RobertCochran RobertCochran requested a review from a team as a code owner January 28, 2026 06:36
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Steam Input action definitions file. Steam reads this to know what actions are available and what kind of actions they are. This is still WIP.

ISteamUserStats *stats = NULL;
ISteamClient *client = NULL, *sclient = NULL;
ISteamGameServer *serv = NULL;
ISteamInput *input = NULL;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a lot of places where the whitespace is inconsistent. Sorry. I'll be sure it's fixed when I am ready to actually get this PR reviewed.

if(d)
{
float scale = (focus == player1 && inzoom() && zoomsensitivity > 0 ? (1.f-((zoomlevel+1)/float(zoomlevels+2)))*zoomsensitivity : 1.f)*sensitivity;
float scale = zoomsens()*sensitivity;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The zoom scaling code got factored out into a helper function so that it could be used inside the controller code.

f += (bf-f)*amt;
}

#define mousesens(a,b,c) ((float(a)/float(b))*c)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This macro moved here to the header so that it could be used inside the controller code.

@qreeves qreeves marked this pull request as draft January 28, 2026 08:18
@qreeves qreeves requested review from qreeves and removed request for a team January 28, 2026 08:18
@qreeves qreeves added this to the 2.1.0 milestone Jan 28, 2026
@Jigoku
Copy link
Member

Jigoku commented Jan 28, 2026

Perhaps the most important thing to note is that I broke the build for the Red Eclipse server. That needs addressing but it's not short-term important.

For this, Looks like you need to add game/controller.o to CLIENT_OBJS in the Makefile so that the compiler can link it 👍

@RobertCochran
Copy link
Author

There's been some more stuff since I posted

Copy link
Author

@RobertCochran RobertCochran Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Settings menu item for glyph prompts. 'Automatic' is probably what most people want (dynamically changes glyphs based on last input), but - as is considered good practice - there are options to explicitly lock glyphs if needed. Because Steam Input handles different hardware types for us, the only glyph distinction we need make is KB/M vs controller. This is technically an interface thing, but I feel like it makes more sense to have it together with the controls options.

KNOWN ISSUE 1: The box for this is weirdly not as wide as the other boxes in the menu. I probably copied a setting I didn't intend.
KNOWN ISSUE 2: This box needs to be hidden for non-Steam builds since it will be connected to a variable that will do nothing without SIAPI support.

It may not be worth fiddling with this much because I still need to add a button to open up the controller configurator interface provided by Steam.

Comment on lines +19 to +39
// Steam Input API controller actions
keymap -20 SIAPI_PRIMARY
keymap -21 SIAPI_SECONDARY
keymap -22 SIAPI_RELOAD
keymap -23 SIAPI_USE
keymap -24 SIAPI_JUMP
keymap -25 SIAPI_WALK
keymap -26 SIAPI_CROUCH
keymap -27 SIAPI_SPECIAL
keymap -28 SIAPI_DROP
keymap -29 SIAPI_AFFINITY
keymap -30 SIAPI_DASH
keymap -31 SIAPI_NEXT_WEAPON
keymap -32 SIAPI_PREVIOUS_WEAPON
keymap -33 SIAPI_PRIMARY_WEAPON
keymap -34 SIAPI_SECONDARY_WEAPON
keymap -35 SIAPI_WHEEL_SELECT
keymap -36 SIAPI_CHANGE_LOADOUT
keymap -37 SIAPI_SCOREBOARD
keymap -38 SIAPI_SUICIDE
keymap -39 SIAPI_MENU
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the SIAPI actions to the keymap, as requested. Because only the SIAPI support code should hit these 'keys' in the keymap and there is an enum to map the codes to nice names in the code, this keymap range can be moved theoretically at any time without risk of breaking anything.

Comment on lines +134 to +159
// Steam Input controller binds; these actions _should not be rebound_ - do it
// through the Steam Input configuration interface
bind SIAPI_PRIMARY [ primary ]
specbind SIAPI_PRIMARY [ spectate 0 ]
bind SIAPI_SECONDARY [ secondary ]
specbind SIAPI_SECONDARY [ spectate 0 ]
bind SIAPI_WHEEL_SELECT [ game_hud_piemenu_open_weapsel_key ] // Currently broken
bind SIAPI_NEXT_WEAPON [ universaldelta 1 ]
bind SIAPI_PREVIOUS_WEAPON [ universaldelta -1 ]
bind SIAPI_PRIMARY_WEAPON [ weapon (weapload 0) 1 ]
bind SIAPI_SECONDARY_WEAPON [ weapon (weapload 1) 1 ]
bind SIAPI_MENU [ uitoggle ]
bind SIAPI_JUMP [ jump ]
specbind SIAPI_JUMP [ specmodeswitch ]
bind SIAPI_SPECIAL [ special ]
bind SIAPI_CROUCH [ crouch ]
bind SIAPI_USE [ use ]
specbind SIAPI_USE [ spectate 0 ]
bind SIAPI_RELOAD [ reload ]
specbind SIAPI_RELOAD [ specmodeswitch ]
bind SIAPI_DROP [ drop ]
bind SIAPI_AFFINITY [ affinity ]
bind SIAPI_SCOREBOARD [ showscores ]
bind SIAPI_CHANGE_LOADOUT [ gameui_player_show_loadout ]
bind SIAPI_SUICIDE [ suicide ]

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bind the SIAPI actions. You are not supposed to rebind these actions in-engine; you are intended to use the Steam Input configurator tool and change things there.

Comment on lines -745 to -756
struct textkey
{
char *name, *file;
Texture *tex;
textkey() : name(NULL), file(NULL), tex(NULL) {}
textkey(char *n, char *f, Texture *t) : name(newstring(n)), file(newstring(f)), tex(t) {}
~textkey()
{
DELETEA(name);
DELETEA(file);
}
};
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This moved to rendertext.h because I needed the struct to be available elsewhere.

Comment on lines +47 to +61
bool shouldkeepkey(const char *str)
{
bool is_siapi_textkey = controller::is_siapi_textkey(str);
switch (textkeyimagepreference) {
case tkip_automatic:
return controller::lastinputwassiapi ? is_siapi_textkey : !is_siapi_textkey;
case tkip_kbm:
return !is_siapi_textkey;
case tkip_controller:
return is_siapi_textkey;
case tkip_both:
return true;
};
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pursuant to above variable, there is now support in the textkey system to filter out glyphs

das->tk->file = NULL; // we don't use this here
das->tk->name = newstring(str);
}
// We have to check if the origin has changed, and if so, reload the texture
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://partner.steamgames.com/doc/features/steam_controller/getting_started_for_devs says that

Please note that the user can change their configuration at any time. To help with this, we've ensured the ISteamInput::GetDigitalActionOrigins and ISteamInput::GetAnalogActionOrigins functions are extremely cheap to call.

When you display an onscreen prompt, don't cache the origins and keep displaying the first results. Instead, we recommend you re-gather the origins each frame, and display the matching prompts. That way, if a user decides to change their configuration as a result of seeing the prompt, when they return from the configuration screen the prompts will automatically update to match the new origins.

In order to honor this best practice, textkeys related to SIAPI actions are handled differently and not cached in the same way that regular KB/M ones are.

public:
InputDigitalActionHandle_t handle = -1;
int keymap_id = -1;
// Should be more than one origin eventually!
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SIAPI actions can have up to 8 origins (which is SIAPIese for 'the button this action is bound to'), but this implementation doesn't yet support actually using them all. It's going to require a non-trivial refactoring of the textkey rendering system to support this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants