OpenXR Dpad "device" is overriding layout when feature is not turned on

I get an error after adding/configuring OpenXR 1.12.1 to a Unity 2022.3.43f1 project:
InvalidOperationException: Cannot instantiate device layout 'Dpad' as child of '/MyCustomController'; devices must be added at root

It sure looks like the normal layout for dpad has been overridden by OpenXR:

Notice the isControlLayout being FALSE and the isDeviceLayout being TRUE.

Dpad-binding is not enabled in the OpenXR settings, which I would expect means that the layout override is NOT injected into the InputSystem
image

The original Dpad layout is completely gone from the InputControlLayout collection cache

It would be nice if there was some mechanism that I could explicitly tell they system what Type to use.
Or the OpenXR plugin could make reasonable decisions about layout controls.

How do I disable the Dpad interaction override without uninstalling OpenXR???

Also the UnregisterDeviceLayout for DPadInteraction calls InputSystem.InputSystem.RemoveLayout(nameof(DPad)); which subsequently calls m_Layouts.baseLayoutTable.Remove(internedName);

Which nukes the base layout from the input system instead of cleanly removing the override.
Nice work.

Found the “fix”:

public class FixOpenXr : MonoBehaviour
{
    static FixOpenXr()
    {
        // remove bad dpad layout before it causes any problems
        InputSystem.RemoveLayout("DPad");
        // re-add the normal dpad layout
        InputSystem.RegisterLayout<UnityEngine.InputSystem.Controls.DpadControl>("DPad");
    }
}

I would put some kind of conditional to check if the OpenXR D-pad feature is toggled on, but I figure if the current package can’t be bothered having opt-in for weird decisions, it’ll be fine.

I just updated my project to Unity 6 and have been having this issue if I unplug and re-plug in a gamepad.

Could not create a device for 'Sony Computer Entertainment Wireless Controller (HID)' (exception: System.InvalidOperationException: Cannot instantiate device layout 'Dpad' as child of '/DualShock4GamepadHID'; devices must be added at root

For your workaround / “fix”, when do you actually call those InputSystem functions? I tried adding them to the Start method of a MonoBehaviour, but it didn’t fix it.

Edit: I was able to get it to work by delaying a couple frames after Start.

Having this same issue. If the proposed workaround is called too early it disables the controller completely. Any ideas on how to run the layout changes?

I tried waiting a few frames but without any luck.

If I manually call the function at some point during gameplay via a debug button press on the keyboard, this fix works great.

Found a working fix!
The issue was that when you replace the layouts, it removes devices that were using the previous layout.

To fix it you need to save a reference to all added input devices before you remove and register the new layout. After you register the new layout you need to add, register, and make current all the devices you saved before you replaced the layout.

You can check if the DPad layout has been overridden by using InputSystem.GetNameOfBaseLayout(“DPad”). If it is overridden this function will return “XRController” After you change the layouts this will return “Vector2”

I check for this in Update and run the fix if the base layout name is “XRController”
I do this in Update because the OpenXR plugin doesn’t immediately override the layout.
This is a simple way to make sure you are applying the fix after the override has happened.

void Update()
{
        if (InputSystem.GetNameOfBaseLayout("DPad") == "XRController")
        {
            FixOpenXRBidningOverride();
        }
}

void FixOpenXRBidningOverride()
{
        Debug.Log("Fixing OpenXR Binding Override");

        //Save a list of all added Devices
        List<InputDevice> addedDevices = new List<InputDevice>();

        foreach (InputDevice _device in InputSystem.devices)
        {
            if (_device.added == true)
            {
                addedDevices.Add(_device);
            }
        }

        InputSystem.RemoveLayout("DPad");
        InputSystem.RegisterLayout<UnityEngine.InputSystem.Controls.DpadControl>("DPad");

        //Re-add, reset, and make current all devices that were removed
        foreach (InputDevice _device in addedDevices)
        {
            if (_device.added == false)
            {
                InputSystem.AddDevice(_device);
                InputSystem.ResetDevice(_device);
                _device.MakeCurrent();
            }
        }
}