Haptic binding not avaliable for HP Reverb G2

I’ve got haptics functioning nicely for VIVE Pro controllers using Unity 2022.1.16 and the new Input system (1.4.2), but when I perform the same configuration steps to add haptic support for HP Reverb G2 controllers, there’s no binding available for them. (They certainly do have the physical capability as they pulse for various reasons outside of unity.)

Theoretically, it should be ‘{RightHand}/haptic’ but that’s not available via the dropdown, and doesn’t resolve when manually entered.

The official MSFT doc on the matter just point to the Unity docs for the short-lived 2018 ‘UnityEngine.XR.InputDevices’ implementation.

//What I use to trigger a basic haptic pulse

//Populaed when UnityEngine.InputSystem.InputSystem.onDeviceChange is dispatched.
UnityEngine.InputSystem.InputDevice device;

//Populaed when UnityEngine.InputSystem.InputSystem.onDeviceChange is dispatched.
UnityEngine.InputSystem.InputAction hapticAction;

//Called to test a pulse
public void PulseHaptic(float amplitude) {
    if(hapticAction == null) {
        Debug.LogWarning("The controller '" + this + "' does not have a bound haptic action!");
        return;
    }

    amplitude = Mathf.Clamp01(amplitude);
   
    //Works for VIVE Pro, not HP Reverb G2 (frequency tested at 10, 50, 100, 500)
    UnityEngine.InputSystem.XR.OpenXRInput.SendHapticImpulse(hapticAction,
        amplitude,
        10f,
        1.0f,
        device);
   
    //Alternate, Works for VIVE Pro, not HP Reverb G2 (frequency tested at 10, 50, 100, 500)
    UnityEngine.InputSystem.XR.OpenXRInput.SendHapticImpulse(hapticAction,
        amplitude,
        10f,
        1.0f,
        UnityEngine.InputSystem.XR.XRController.rightHand);
}

The Input Actions Schema & Maps

{
    "name": "InputActions",
    "maps": [
        {
            "name": "RightController",
            "id": "1b6300a3-2abc-40ce-8a40-56d5f65965fe",
            "actions": [
                {
                    "name": "Position",
                    "type": "Value",
                    "id": "eee129a9-49d8-469b-83e4-8bb77849eb8c",
                    "expectedControlType": "Vector3",
                    "processors": "",
                    "interactions": "",
                    "initialStateCheck": true
                },
                {
                    "name": "Rotation",
                    "type": "PassThrough",
                    "id": "a0c5a7ae-c6d7-4623-9f03-8cdb35443195",
                    "expectedControlType": "Quaternion",
                    "processors": "",
                    "interactions": "",
                    "initialStateCheck": false
                },
                {
                    "name": "Trigger",
                    "type": "Value",
                    "id": "b8d6264f-7ca3-4c99-90a5-67b246030b8e",
                    "expectedControlType": "",
                    "processors": "",
                    "interactions": "",
                    "initialStateCheck": true
                },
                {
                    "name": "TriggerBtn",
                    "type": "Button",
                    "id": "533a5202-01ad-47ff-9134-6588782d46c6",
                    "expectedControlType": "Button",
                    "processors": "",
                    "interactions": "Press(behavior=1)",
                    "initialStateCheck": false
                },
                {
                    "name": "TriggerBtnHeld",
                    "type": "Button",
                    "id": "674c4a9e-df1c-4dca-b8fe-a1365e1ad9f2",
                    "expectedControlType": "Button",
                    "processors": "",
                    "interactions": "Hold",
                    "initialStateCheck": false
                },
                {
                    "name": "PrimaryBtn",
                    "type": "Button",
                    "id": "d8a081ac-f1e7-458d-baf3-32481ceb7a7c",
                    "expectedControlType": "Button",
                    "processors": "",
                    "interactions": "Press(behavior=1)",
                    "initialStateCheck": false
                },
                {
                    "name": "PrimaryBtnHeld",
                    "type": "Button",
                    "id": "72ce8707-bef5-4b0d-b08e-9255964c4b0f",
                    "expectedControlType": "Button",
                    "processors": "",
                    "interactions": "Hold",
                    "initialStateCheck": false
                },
                {
                    "name": "SecondaryBtn",
                    "type": "Button",
                    "id": "ebc2fff2-12d6-4e9d-9626-9c3ecaa427be",
                    "expectedControlType": "Button",
                    "processors": "",
                    "interactions": "Press(behavior=1)",
                    "initialStateCheck": false
                },
                {
                    "name": "SecondaryBtnHeld",
                    "type": "Button",
                    "id": "e5f81192-3974-4c7e-9f72-442033c1c971",
                    "expectedControlType": "Button",
                    "processors": "",
                    "interactions": "Hold",
                    "initialStateCheck": false
                },
                {
                    "name": "GripTrigger",
                    "type": "Value",
                    "id": "a4fe10d3-bab7-4208-84d9-1fa050f86d2a",
                    "expectedControlType": "Axis",
                    "processors": "",
                    "interactions": "",
                    "initialStateCheck": true
                },
                {
                    "name": "GripBtn",
                    "type": "Button",
                    "id": "b98d1ac7-a28d-4b01-b234-5090cc036542",
                    "expectedControlType": "Button",
                    "processors": "",
                    "interactions": "Press(behavior=1)",
                    "initialStateCheck": false
                },
                {
                    "name": "GripBtnHeld",
                    "type": "Button",
                    "id": "f6950bea-e54d-4e21-a7b1-e440c8aa67bd",
                    "expectedControlType": "Button",
                    "processors": "",
                    "interactions": "Hold",
                    "initialStateCheck": false
                },
                {
                    "name": "MenuBtn",
                    "type": "Button",
                    "id": "48784f00-33e5-4daa-be5e-549402866ffa",
                    "expectedControlType": "Button",
                    "processors": "",
                    "interactions": "Press(behavior=1)",
                    "initialStateCheck": false
                },
                {
                    "name": "MenuBtnHeld",
                    "type": "Button",
                    "id": "9e837c98-3ad0-4a3b-a2d6-f8b1b9861eb2",
                    "expectedControlType": "Button",
                    "processors": "",
                    "interactions": "Hold",
                    "initialStateCheck": false
                },
                {
                    "name": "TPadTouch",
                    "type": "Button",
                    "id": "e867f016-ca47-47bf-b736-e4fd5d789c49",
                    "expectedControlType": "Button",
                    "processors": "",
                    "interactions": "",
                    "initialStateCheck": false
                },
                {
                    "name": "TPad",
                    "type": "Button",
                    "id": "097bde5e-6145-4658-8695-40182d6f1c68",
                    "expectedControlType": "Button",
                    "processors": "",
                    "interactions": "",
                    "initialStateCheck": false
                },
                {
                    "name": "JoyStick",
                    "type": "Value",
                    "id": "b79fdc02-8a48-40bc-b5ba-d7b958fa78c8",
                    "expectedControlType": "Vector2",
                    "processors": "",
                    "interactions": "",
                    "initialStateCheck": true
                },
                {
                    "name": "JoyStickBtn",
                    "type": "Button",
                    "id": "314b3b32-752f-408c-9893-789c6a11f275",
                    "expectedControlType": "Button",
                    "processors": "",
                    "interactions": "Press(behavior=1)",
                    "initialStateCheck": false
                },
                {
                    "name": "JoyStickBtnHeld",
                    "type": "Button",
                    "id": "f67ea0a8-1937-4553-a951-3b5695038a91",
                    "expectedControlType": "Button",
                    "processors": "",
                    "interactions": "Hold",
                    "initialStateCheck": false
                },
                {
                    "name": "Haptic",
                    "type": "PassThrough",
                    "id": "1046b868-5318-4af0-9c93-9a2884b18b1f",
                    "expectedControlType": "Haptic",
                    "processors": "",
                    "interactions": "",
                    "initialStateCheck": true
                }
            ],
            "bindings": [
                {
                    "name": "",
                    "id": "8de5062c-4772-4f6f-b9cb-779dccb5da25",
                    "path": "<XRController>{RightHand}/devicePosition",
                    "interactions": "",
                    "processors": "",
                    "groups": "GenericXRController;VIVE Pro;HP Reverb G2 - XR",
                    "action": "Position",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "1d1f5fbb-7af3-4cda-a4a9-3818f8a43364",
                    "path": "<XRController>{RightHand}/deviceRotation",
                    "interactions": "",
                    "processors": "",
                    "groups": "GenericXRController;HP Reverb G2 - XR;VIVE Pro",
                    "action": "Rotation",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "86bdf087-dee9-4390-8fe2-0c510762f377",
                    "path": "<XRController>{RightHand}/trigger",
                    "interactions": "",
                    "processors": "",
                    "groups": "VIVE Pro;HP Reverb G2 - XR;GenericXRController",
                    "action": "Trigger",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "31d0b222-728b-4bf1-80a6-2f2d98853073",
                    "path": "<XRController>{RightHand}/triggerPressed",
                    "interactions": "",
                    "processors": "",
                    "groups": "HP Reverb G2 - XR;GenericXRController",
                    "action": "TriggerBtn",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "69a970e4-938e-4d45-8668-017ae964eb0e",
                    "path": "<ViveController>{RightHand}/trackpadClicked",
                    "interactions": "",
                    "processors": "",
                    "groups": "VIVE Pro",
                    "action": "SecondaryBtn",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "318d1ec4-a44b-4d1a-8549-b373cb0e603a",
                    "path": "<XRController>{RightHand}/secondaryButton",
                    "interactions": "",
                    "processors": "",
                    "groups": "GenericXRController;HP Reverb G2 - XR",
                    "action": "SecondaryBtn",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "061614ba-2477-44ba-a062-c7273fa41004",
                    "path": "<HPMixedRealityController>{RightHand}/thumbstick",
                    "interactions": "",
                    "processors": "",
                    "groups": "HP Reverb G2 - XR",
                    "action": "JoyStick",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "aefc4e5f-a15e-4215-8427-3e64cb0a46ec",
                    "path": "<HPMixedRealityController>{RightHand}/thumbstickClicked",
                    "interactions": "",
                    "processors": "",
                    "groups": "HP Reverb G2 - XR",
                    "action": "JoyStickBtn",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "0cf8d350-2dc6-441b-bb0c-c35f50fb00e3",
                    "path": "<XRController>{RightHand}/haptic",
                    "interactions": "",
                    "processors": "",
                    "groups": "HP Reverb G2 - XR;GenericXRController",
                    "action": "Haptic",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "2fc6e254-2a16-414c-afbf-db5a7cf538de",
                    "path": "<ViveController>{RightHand}/haptic",
                    "interactions": "",
                    "processors": "",
                    "groups": "VIVE Pro",
                    "action": "Haptic",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "8ffe9a4b-e0ba-4c3d-9ce4-69b207e9cb5e",
                    "path": "<HPMixedRealityController>{RightHand}/thumbstickClicked",
                    "interactions": "",
                    "processors": "",
                    "groups": "HP Reverb G2 - XR",
                    "action": "JoyStickBtnHeld",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "27d8210a-780f-4596-8638-d0a4ba653ed6",
                    "path": "<XRController>{RightHand}/triggerPressed",
                    "interactions": "",
                    "processors": "",
                    "groups": "HP Reverb G2 - XR;GenericXRController",
                    "action": "TriggerBtnHeld",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "b79ed51e-b9ed-41e7-9a15-dace18c14882",
                    "path": "<ViveController>{RightHand}/triggerPressed",
                    "interactions": "",
                    "processors": "",
                    "groups": "VIVE Pro",
                    "action": "PrimaryBtnHeld",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "0d9b8311-a30d-414b-8b0c-febcebb1ee6b",
                    "path": "<XRController>{RightHand}/primaryButton",
                    "interactions": "",
                    "processors": "",
                    "groups": "GenericXRController;HP Reverb G2 - XR",
                    "action": "PrimaryBtnHeld",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "5dc22179-89ba-4718-a891-16e2ed56f718",
                    "path": "<ViveController>{RightHand}/trackpadClicked",
                    "interactions": "",
                    "processors": "",
                    "groups": "VIVE Pro",
                    "action": "SecondaryBtnHeld",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "c8554669-cdab-4288-9ba3-733d56813a2c",
                    "path": "<XRController>{RightHand}/secondaryButton",
                    "interactions": "",
                    "processors": "",
                    "groups": "GenericXRController;HP Reverb G2 - XR",
                    "action": "SecondaryBtnHeld",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "a2c2cd5d-b27c-42a9-a247-b50224181073",
                    "path": "<ViveController>{RightHand}/trackpadTouched",
                    "interactions": "",
                    "processors": "",
                    "groups": "VIVE Pro",
                    "action": "TPadTouch",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "7bc92b46-08a6-4fce-936f-daad33c411a9",
                    "path": "<XRController>{RightHand}/gripPressed",
                    "interactions": "",
                    "processors": "",
                    "groups": "GenericXRController;VIVE Pro;HP Reverb G2 - XR",
                    "action": "GripBtnHeld",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "95c1329b-bd85-4917-9fbb-6cbf27077ce8",
                    "path": "<XRController>{RightHand}/menu",
                    "interactions": "",
                    "processors": "",
                    "groups": "GenericXRController;VIVE Pro;HP Reverb G2 - XR",
                    "action": "MenuBtnHeld",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "faebae6a-fc17-4d44-b10e-26995c33e2b7",
                    "path": "<XRController>{RightHand}/menu",
                    "interactions": "",
                    "processors": "",
                    "groups": "GenericXRController;VIVE Pro;HP Reverb G2 - XR",
                    "action": "MenuBtn",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "fa081314-1274-48da-96dc-c7e15bca3307",
                    "path": "<XRController>{RightHand}/gripPressed",
                    "interactions": "",
                    "processors": "",
                    "groups": "GenericXRController;VIVE Pro;HP Reverb G2 - XR",
                    "action": "GripBtn",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "10779db5-4c15-43ca-b52d-58d2a208162f",
                    "path": "<ViveController>{RightHand}/trackpad",
                    "interactions": "",
                    "processors": "",
                    "groups": "VIVE Pro",
                    "action": "TPad",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "74dae1eb-96c2-44ba-9066-d87ce7d990d6",
                    "path": "<HPMixedRealityController>{RightHand}/grip",
                    "interactions": "",
                    "processors": "",
                    "groups": "HP Reverb G2 - XR",
                    "action": "GripTrigger",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "7a082a37-0ce0-4e9f-bd55-6259b0530e71",
                    "path": "<ViveController>{RightHand}/triggerPressed",
                    "interactions": "",
                    "processors": "",
                    "groups": "VIVE Pro",
                    "action": "PrimaryBtn",
                    "isComposite": false,
                    "isPartOfComposite": false
                },
                {
                    "name": "",
                    "id": "e4f637a9-aba2-400d-bddc-0253cf9a580b",
                    "path": "<XRController>{RightHand}/primaryButton",
                    "interactions": "",
                    "processors": "",
                    "groups": "GenericXRController;HP Reverb G2 - XR",
                    "action": "PrimaryBtn",
                    "isComposite": false,
                    "isPartOfComposite": false
                }
            ]
        }
    ],
    "controlSchemes": [
        {
            "name": "HP Reverb G2 - XR",
            "bindingGroup": "HP Reverb G2 - XR",
            "devices": [
                {
                    "devicePath": "<XRController>",
                    "isOptional": false,
                    "isOR": false
                }
            ]
        },
        {
            "name": "VIVE Pro",
            "bindingGroup": "VIVE Pro",
            "devices": [
                {
                    "devicePath": "<ViveController>",
                    "isOptional": false,
                    "isOR": false
                }
            ]
        },
        {
            "name": "GenericXRController",
            "bindingGroup": "GenericXRController",
            "devices": [
                {
                    "devicePath": "<XRController>",
                    "isOptional": true,
                    "isOR": false
                }
            ]
        }
    ]
}

Upon further digging, it looks as though the HP Reverb G2 Controller Profile from MSFT’s Mixed Reality OpenXR Plugin (1.4.2) is misconfigured.

@yl-msft can you verify if what I’m seeing is correct?

Specifically, it looks as though the profile is missing the following declarations:

Before the ‘protected override void FinishSetup()’ method declaration ~Line 154

/// <summary>
/// A <see cref="HapticControl"/> that represents the <see cref="HTCViveControllerProfile.haptic"/> binding.
/// </summary>
[Preserve, InputControl(usage = "Haptic")]
public HapticControl haptic { get; private set; }

Within the ‘protected override void FinishSetup()’ method declaration ~Line 178

haptic = GetChildControl<HapticControl>("haptic");

At the end of the ActionMap declaration, usages isn’t set, and the name and localized name read vibrate.

// Haptics
new ActionConfig()
{
    name = "haptic",
    localizedName = "Haptic Output",
    type = ActionType.Vibrate,
    usages = new List<string>() { "Haptic" },
    bindings = new List<ActionBinding>()
    {
        new ActionBinding()
    {
    interactionPath = haptic,
    interactionProfileName = profile,
}

I created a custom profile based off Microsoft profile and added the changes which resulted in functional haptics.

Thank you so much for posting this - I had exactly the same problem with no Reverb G2 haptics (which I could get to work occasionally by adding/removing controller types in Unity, but it was never consistent). For anyone else seeing this the file I edited is:

com.microsoft.mixedreality.openxr-1.6.0\package\Runtime\FeaturePlugins\HPMixedRealityControllerProfile.cs

and I tested it with the 1.6.0 version of the package (obvs!) and used 7-zip for the unzip rezip.

No problem, glad to know it helped, If you encounter more oddities with WMR haptics, I have a GitHub ticket open on this topic that the Microsoft dev team are looking into, hopefully it’ll be patched in the coming months.

FYI, G2 haptics are stronger than the Vive’s weak pulsing, as such you may want to have ‘device specific’ strengths to make them feel similar. The added bonus is that running the G2 haptics at a weaker level will reduce battery consumption.