reckfellENGINE

OpenXR action map: configure input

Sets, actions, controller profiles, an executed C# resource example and binding diagnostics.

On this page

An action map connects input meaning to XR-controller components. Game code checks an action such as select; the map specifies which control triggers it on each device profile. This is separate from ordinary InputMap: adding a Project Settings → Input Map action does not create an OpenXR binding.

Map structure

ResourcePurposeExample
OpenXRActionMapRoot map resourceopenxr_action_map.rdata
OpenXRActionSetActions for one game modegameplay, menu
OpenXRActionNamed action and value typeselect, Bool
OpenXRInteractionProfileBindings for a controller profile/interaction_profiles/khr/simple_controller
OpenXRIPBindingOne action and one complete input path/user/hand/right/input/select/click

ResourceName stores the internal name; LocalizedName is the human-readable label. Prefer short, stable lowercase internal names such as select or move_player. Do not use translated labels as game-code keys. Action names and labels must be unique within their set; the XR runtime checks them when creating actions. OpenXR name and subaction-path requirements.

ToplevelPaths identifies devices for the action, such as left and right hands. BindingPath identifies a specific component on such a device. Two hands require two bindings to the same action, not a comma-separated pair of paths in one string.

Start with one action

A minimal selection map:

  1. Create set gameplay, label Gameplay, Priority=0.
  2. Add action select, label Select, type Bool.
  3. Set ToplevelPaths to /user/hand/left and /user/hand/right.
  4. Add profile /interaction_profiles/khr/simple_controller.
  5. Add two bindings to select: /user/hand/left/input/select/click and /user/hand/right/input/select/click.
  6. Save to asset://openxr_action_map.rdata.

Simple Controller describes a minimal input subset. It provides neither sticks nor every controller-specific feature or guaranteed support on every headset. For more input, add the relevant profiles and paths allowed for those profiles. Application bindings are suggestions to the runtime, not direct access to raw buttons. OpenXR suggested-binding rules.

Create the same map in C#

This helper builds and saves a resource. It is not an attachable Entity script or XR-session startup code.

C#
using Reckfell;

public static class SelectionActionMap
{
    // Caller owns the map. This builds resources; it does not start an XR session.
    public static OpenXRActionMap Create()
    {
        var map = new OpenXRActionMap();
        using var set = new OpenXRActionSet
        {
            ResourceName = "gameplay", LocalizedName = "Gameplay", Priority = 0
        };
        using var select = new OpenXRAction
        {
            ResourceName = "select", LocalizedName = "Select",
            ActionType = OpenXRAction.ActionTypeEnum.Bool,
            ToplevelPaths = ["/user/hand/left", "/user/hand/right"]
        };
        set.AddAction(select);
        map.AddActionSet(set);

        using var profile = new OpenXRInteractionProfile
        {
            InteractionProfilePath = "/interaction_profiles/khr/simple_controller"
        };
        using var left = new OpenXRIPBinding
        {
            Action = select, BindingPath = "/user/hand/left/input/select/click"
        };
        using var right = new OpenXRIPBinding
        {
            Action = select, BindingPath = "/user/hand/right/input/select/click"
        };
        using var bindings = new Reckfell.Collections.Array { left, right };
        profile.Bindings = bindings;
        map.AddInteractionProfile(profile);
        return map;
    }

    public static Error Save(string path = "asset://openxr_action_map.rdata")
    {
        using var map = Create();
        return ResourceSaver.Save(map, path);
    }
}

From a separate resource-preparation tool, call SelectionActionMap.Save() and check for Error.Ok. By default it writes asset://openxr_action_map.rdata in the project executing the call. Prepare the file before starting the XR project. Saving a new map in _Ready() of an already running XR session does not reconnect its current actions.

The editor exposes the same structure in its OpenXR Action Map dock. Enable xr/openxr/enabled and restart the editor when requested. xr/openxr/default_action_map must point to the intended file; its default is asset://openxr_action_map.rdata. This setting matters more than matching the example filename.

If no map can be loaded, native code creates a default map. A tools-enabled build also attempts to save it. Do not rely on this to create your intended game actions in an exported project: keep your own map in the project and check its export inclusion.

Read an action

Select the relevant XRController3D hand tracker: left_hand or right_hand. After the XR session starts successfully and has focus, query actions by internal name:

Action typeXRController3D C# APIMeaning
BoolIsButtonPressed("select")Current pressed state, not a one-frame event
FloatGetFloat("trigger")Analog value of the configured action
Vector2GetVector2("move")Two axes of the configured action
PosePose property on the XR objectSelects a named tracked pose, not a button

First define and bind trigger, move and the required pose; the minimal map above contains only select. It does not replace XROrigin3D, camera or XR startup configuration.

The map editor offers a Haptic type. However, current installed C# OpenXRAction.ActionTypeEnum has no named Haptic member: do not use a nonexistent member or substitute a numeric cast. Configure that action in the map editor. It must target a supported output, such as /user/hand/right/output/haptic, before calling TriggerHapticPulse. That call uses seconds for duration; OpenXRHapticVibration.Duration for modifiers uses nanoseconds. A binding alone does not establish working vibration on a device.

Sets and map changes

Start with one set. Later separate gameplay and menu when one controller component should serve different purposes. OpenXRInterface.SetActionSetActive toggles an existing set by name. Priority resolves conflicts between active sets; avoid leaving conflicting sets active unnecessarily. Adding an OpenXRAction to a second OpenXRActionSet moves it out of the first: independent actions require separate resources.

Editing resource data does not rebuild an attached XR session. OpenXR forbids adding actions and changing suggested bindings after sets are attached to that session. Prepare the map and restart the session. Toggling an existing set’s activity is a separate operation. xrAttachSessionActionSets restrictions.

The current GetActionSets() returns a shared Array. Calling Clear() changes the map without Changed. For ordinary editing, use AddActionSet/RemoveActionSet and the corresponding resource methods; do not clear the returned container as though it were an independent copy.

Add modifiers after checking basic input. xr/openxr/binding_modifiers/analog_threshold and xr/openxr/binding_modifiers/dpad_binding request the corresponding extensions; runtime support is required. Separate analog on/off thresholds to avoid chatter around a boundary. D-pad modifiers require suitable two-dimensional input rather than an arbitrary path. Test each modifier on the target runtime: saving a resource does not establish device-side application.

Diagnose missing input

SymptomCheck
Code always reads falseXR session is running and focused; correct tracker; action set active
Only one hand worksBoth ToplevelPaths and a separate BindingPath for each hand
Saved map has no effectCorrect xr/openxr/default_action_map; session restarted after saving
Fails on another controllerAppropriate interaction profile; valid paths for it; runtime accepted bindings
Action creation failsNo empty/duplicate names or labels; action type matches the component
Vibration does not workHaptic output action and correct output path; correct action/tracker; duration units

The exact C# example, structure, two bindings referencing one action, .rdata saving and independent reload were checked in the installed engine without a headset. Action transfer between sets and shared Array behavior were also checked. Physical input, session focus, pose tracking, haptics, modifiers and editor interaction were not tested in this run.

Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.