Steamworks Documentation
In-Game Actions File

Overview


Developers must supply an in-game actions (IGA) file that defines the actions, action sets, and basic structure of their game's input configuration. This article describes the overall structure of this file and provides several concrete examples from various games.

Example Files


Authoring an In-Game Actions File by hand

Start by downloading the starting one of the in-game actions (IGA) files linked in the examples above. Next, create a "controller_config" directory inside the Steam folder, usually C:/Program Files (x86)/Steam/controller_config, and place the file in the directory. The Steam folder will already have a very similarly named folder so make sure you've put it in the "controller_config" folder and not the "controller_base" folder. Rename the file to the following: "game_actions_X.vdf", where X is your game's Steam AppID. If you don't know what your game's Steam AppID is, it can be found by logging into your Steam partner site.

Now open up the file in your favorite text editor. The file is in a standard Valve format called KeyValues, which is a simple & easily read format. You might also find it useful to download one of our In-Game Actions File Templates or the Portal 2 IGA for a reference.

Generating an IGA file from an existing game that uses Steam Input API


If you save a configuration for any game on steam as a "local" configuration, you can then find a corresponding file in:
[SteamDirectory]\UserData\[youruserid]\241100\remote\controller_config\[appid]\[savename].vdf

Here's an example of where my local configurations for Defender's Quest are stored on a typical Windows 10 machine:

whereisvgf.png

Note that these files are not exact replicas of the master IGA file uploaded by the developer, but you can get an idea for the original structure by looking at the "actions" and "localization" blocks, which are drawn directly from the master file.

Here's a download link for the #library_controllersavedefaulttitle_0.vdf file shown in the above screenshot, you might find it useful to compare that to the master Defender's Quest IGA.

IGA Format


The IGA file takes the form of a VDF document, which is Valve's own data format for creating structured object data with key/value string pairs.

Skeleton


The basic structure of the file is a wrapper object with the name "In Game Actions", and two sub objects, named "actions", and "localization", respectively:

"In Game Actions" { "actions" { } "localization" { } }

Action Sets

Let's zoom into the "actions" object. This object will contain your action sets. The structure of an "actions" object looks like this:
"actions" { "ActionSetNameGoesHere" { "title" "#TitleGoesHere" "StickPadGyro" { } "AnalogTrigger" { } "Button" { } } }

The strings "ActionSetNameGoesHere" and "#TitleGoesHere" are the only strings in the above example the user should replace, the rest are reserved key words.

The value you replace "ActionSetNameGoesHere" with will be the name of the action set that you use in the Steam Input API. And the value you replace "#TitleGoesHere" with will be the localization token you use in the "localization" section later in the file. Note that the # sign is required here.

Each action set should have a unique string name, and you add more just by creating more objects within the scope of the "actions" container object. No commas or square brackets are necessary -- this is VDF, not JSON.

There are three possible sub-objects for each action set object. They are "StickPadGyro", "AnalogTrigger", and "Button". These are the only possible objects you can define, and they are the containers that will house your individual action definitions. You do not have to provide all three categories, however.

This structure is perfectly valid, for instance:
"actions" { "ActionSetName1" { "title" "#Title1" "AnalogTrigger" { } "Button" { } } "ActionSetName2" { "title" "#Title2" "StickPadGyro" { } } "ActionSetName3" { "title" "#Title3" "Button" { } } }

StickPadGyro

This action set block is for analog actions that will have up to two axes of motion, the sort of thing you might want to bind to a joystick, a trackpad, or a gyroscope. Also, anything you might want to control with a mouse or anything else like that should go in here.

AnalogTrigger

This action set block is for analog actions that will have only one axis of motion, the sort of thing you might want to bind to an analog trigger.

Button

This action set block is for purely digital actions, which only report an on/off state. Despite the name of this block being "button," digital actions can be bound to just about any physical inputs -- including ones originally designed to output analog data (such as joysticks, trackpads, etc).

Actions


An IGA file won't actually do anything until it's got some actions defined, so let's add some!

StickPadGyro Actions

Let's start by adding some StickPadGyro (2-axis analog) actions. How about something to move the character around -- we'll call it "Move", and something to control the camera -- we'll call it "Camera."

"actions" { "FPSControls" { "title" "#Set_FPSControls" "StickPadGyro" { "Move" { "title" "#Action_Move" "input_mode" "joystick_move" } "Camera" { "title" "#Action_Camera" "input_mode" "absolute_mouse" } } } }

As you can see the abstract structure for a StickPadGyro action is:
"ActionNameHere" { "title" "#ActionTitleHere" "input_mode" "<analog_mode>" }

The only user-editable values in this structure are the ones I've marked "ActionNameHere", "#ActionTitleHere", and "<analog_mode>". Respectively, they correspond to the action's string name for use in the Steam Input API, the localization key for use in this file's localization section and the Input Source Mode that governs how the analog data is processed and interpreted.

The "input_mode" property has two possible values for StickPadGyro actions:

  • "joystick_move"
  • "absolute_mouse"

You should use "joystick_move" for an action whose values are interpreted as a joystick (constant deflection from a central point), and you should use "absolute_mouse" for a more flexible general purpose analog action. When in doubt, use "absolute_mouse".

"joystick_move" vs. "absolute_mouse"

We can’t stress enough that when creating a camera input for your first/third person game or anything cursor driven, you should always use the "absolute_mouse" type and react to deltas as if it’s a mouse.

The API will automagically do the right thing here for stick based input, so you'll still get a tune-able stick input if your camera is applied to an analog stick (PS4/Xbox style) with full dead zones/response curves/etc. that you can specify in your default configuration. This same input will then work across joysticks, track pads, or motion control gyros (steam controller/ps4) as well as future support for mice.

You should not use the "joystick_move" based input method for your camera, as mapping the opposite direction to get useful 1:1 data for pad/gyro/mouse/motion controls isn't possible.

This also applies to cursor based input - "absolute_mouse" as a cursor will work just fine on stick based inputs, so you don't have to worry about creating your own stick based cursor, should you need one.

You can optionally send low-level mouse events along with your analog data. Your game will not be able to distinguish these mouse events from those generated by your operating system. You do this by adding the value "os_mouse" and assign it a value of 1.

Here's an example:
"StickPadGyro" { "Mouse" { "title" "#Action_Mouse" "input_mode" "absolute_mouse" "os_mouse" "1" } }


AnalogTrigger Actions
AnalogTrigger actions are 1-D analog actions which can be bound on triggers. If you are using a simple threshold of the trigger for something like firing a gun or initiating "Aim Down Sights" mode you may want to use a Button Action instead of an AnalogTrigger action so that users have more flexibility in rebinding.

The AnalogTrigger actions have a configurable deadzone in the rebinding UI and are rescaled from 0 - 1.0f between those values. Controllers with digital trigger buttons like the Nintendo Switch Pro controller will send either 0 or 1.0 so you may want to check that you don't have any gameplay code that depends on gradual trigger changes over time.

AnalogTrigger actions have a simple format, with the name of the action as the key and the localization token as the value. Like this:
"AnalogTrigger" { "AccelerationAxis" "#Action_Accelerate" "BreakingAxis" "#Action_Brake" }

Button Actions

Button actions also have a similar format, using action name and localization token:
"Button" { "digital_action_1_name_here" "#DigitalAction1TitleHere" "digital_action_2_name_here" "#DigitalAction2TitleHere" }

If necessary, you can define a native low-level input hardware event (like a native mouse click) that fires alongside the action. This is useful in some edge cases where your game relies on e.g. a finicky input stack seven layers deep that never quite treats simulated mouse events from your application layer the same as those directly generated by the operating system.

"Button" { "simple_click" "#simple_click" "fancy_click" "#fancy_click, mouse_button LEFT" }

This causes the game to emit a true, operating-system-level left mouse button event every time the "fancy_click" action is fired.

Warning!

You should never use this trick as a crutch for forcing specific fixed input bindings for your actions. That defeats the entire purpose of the "actions, not inputs" paradigm and giving the user full control over their configuration. If you find yourself using this feature for more than just fixing a few rare edge cases, you're probably overusing it.

Action Set Layers

In addition to Action Sets you can also overlay incremental changes to the active Action Set with an Action Set Layer. You can use this to handle specializations of a general mode like having a Sniper layer on top of your OnFoot controls or to handle cases when you have in-game UI that pops up over normal gameplay like voting screens. Layers are declared in their own section, ex:
"action_layers" { "IngameModalLayer" { "title" "#Layer_IngameModal" "legacy_set" "0" "set_layer" "1" "parent_set_name" "InGame" "AnalogTrigger" { } "Button" { "Modal_Accept" "#Action_Modal_Accept" "Modal_Decline" "#Action_Modal_Decline" } } }

Localization


The master IGA file should include a localization section alongside the action set definitions. The individual child objects of the localization object will be any one of the language strings that Steam supports. Make sure you include at least one block that contains English action titles.

"localization" { "english" { "move" "Move" "camera" "Camera" } }

Note that the names of the properties should correspond to the localization keys you specified in the earlier sections, except without the "#" character.

To add additional languages, simply add more language blocks with localized text for each entry:

"localization" { "english" { "move" "Move" "camera" "Camera" } "spanish" { "move" "Mover" "camera" "Cámara" } "norwegian" { "move" "Bevege" "camera" "Kamera" } }
The token for each language should match the "API language code" value, ex: "schinese" for Simplified Chinese. The full list of supported languages can be found here.

How Steam uses your IGA file


The master IGA file you create will only ever be during development (but it should still be saved, maintained, and stored in your version control, etc). When you create an official input configuration for your game during development, the steam client uses your master IGA file to generate a starting template.