Steamworks Documentation
Steam Frame Input

Controllers


The Steam Frame Controllers have the same capabilities as your standard console gaming controllers plus touch states, grip buttons, capacitive finger tracking, and 6-DOF spatial tracking. This gives you many more options on how to let players interact with your titles. It also allows users to play non-VR content on the headset without a separate device.

steamframe-controllers_1.png

VR Compatibility

While you will always get a better user experience by tailoring your title to the Frame Controllers specifically, our controller compatibility modes have become quite robust. SteamVR will always use a Frame Controller binding by default but in the case one is not available it will first look for a OpenXR Generic Controller binding, then an Oculus Touch binding, and remap those to the Frame Controller layout.
  • The menu button on Oculus Touch will map to the View button at the top of the Steam Frame Controller.
  • The top button of the Oculus Touch controllers (B / Y) will map to all three top buttons of the Steam Frame Controllers (Dpad Left, Dpad Up, Dpad Right / X, Y, B).

Non-VR Compatibility

When playing Non-VR titles locally or via streaming the Frame Controllers take full advantage of Steam Input. Depending on the game and the configured bindings it will show up as a generic gamepad or keyboard/mouse.

OpenXR Interaction Profile

You'll find an OpenXR Interaction Profile included in each Game Engine plugin (or in the case of Godot in the engine itself). If you have your own custom engine you can add support via our extension detailed on the steamframe/engines/custom documentation page.

To enable the interaction profile you must request to use the extension:
XR_VALVE_frame_controller_interaction

Then you can suggest bindings for the interaction profile path:
/interaction_profiles/valve/frame_controller_valve

You can use the following paths:
"/user/hand/right/input/a/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/a/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/b/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/b/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/x/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/x/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/y/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/y/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/menu/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/menu/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/system/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/system/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/bumper/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/bumper/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/squeeze/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/squeeze/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/squeeze/value", XR_ACTION_TYPE_FLOAT_INPUT "/user/hand/right/input/trigger/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/trigger/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT "/user/hand/right/input/thumbstick/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/thumbstick/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/right/input/thumbstick/x", XR_ACTION_TYPE_FLOAT_INPUT "/user/hand/right/input/thumbstick/y", XR_ACTION_TYPE_FLOAT_INPUT "/user/hand/right/input/thumbstick", XR_ACTION_TYPE_VECTOR2F_INPUT "/user/hand/right/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT "/user/hand/right/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT "/user/hand/right/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT "/user/hand/left/input/dpad_up/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/dpad_up/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/dpad_left/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/dpad_left/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/dpad_down/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/dpad_down/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/dpad_right/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/dpad_right/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/view/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/view/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/system/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/system/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/bumper/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/bumper/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/squeeze/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/squeeze/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/squeeze/value", XR_ACTION_TYPE_FLOAT_INPUT "/user/hand/left/input/trigger/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/trigger/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT "/user/hand/left/input/thumbstick/touch", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/thumbstick/click", XR_ACTION_TYPE_BOOLEAN_INPUT "/user/hand/left/input/thumbstick/x", XR_ACTION_TYPE_FLOAT_INPUT "/user/hand/left/input/thumbstick/y", XR_ACTION_TYPE_FLOAT_INPUT "/user/hand/left/input/thumbstick", XR_ACTION_TYPE_VECTOR2F_INPUT "/user/hand/left/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT "/user/hand/left/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT "/user/hand/left/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT

OpenVR Bindings

You can bind to the Steam Frame Controllers like you would any other OpenVR controller type. Its controller_type is "frame_controller". They support finger tracking via the Skeletal Input API and all of the controls listed above. You can create bindings for it in the SteamVR Binding UI.

Left Controller "/user/hand/left/input/dpad_up": click, touch "/user/hand/left/input/dpad_down": click, touch "/user/hand/left/input/dpad_left": click, touch "/user/hand/left/input/dpad_right": click, touch "/user/hand/left/input/view": click, touch "/user/hand/left/input/bumper": click, touch "/user/hand/left/input/trigger": click, touch, value 1d "/user/hand/left/input/grip": click, touch, value 1d "/user/hand/left/input/thumbstick": click, touch, value 2d "/user/hand/left/input/system": click, touch Right Controller "/user/hand/right/input/a": click, touch "/user/hand/right/input/b": click, touch "/user/hand/right/input/x": click, touch "/user/hand/right/input/y": click, touch "/user/hand/right/input/menu": click, touch "/user/hand/right/input/bumper": click, touch "/user/hand/right/input/trigger": click, touch, value 1d "/user/hand/right/input/grip": click, touch, value 1d "/user/hand/right/input/thumbstick": click, touch, value 2d "/user/hand/right/input/system": click, touch

HMD


It is unlikely that you will have a reason to need the hmd name, but if you do, its controller_type is "frame_hmd". Be sure NOT to use this for determining the type of controllers the user currently has. Many users choose to mix and match hmds and controllers.

Eye Tracking

OpenXR

Our current support for eye tracking uses the XR_EXT_eye_gaze_interaction OpenXR extension. You can find details about that on the OpenXR spec site here.

OpenVR

OpenVR has two functions in IVRInput GetEyeTrackingDataRelativeToNow and GetEyeTrackingDataForNextFrame. To use those you will need to create a new action of type "eyetracking" to pass into the functions.