Make XR test input runtime-agnostic

Changes all the button and axis IDs used for sending controller input
during the XR browser tests to be runtime-agnostic instead of using the
OpenVR constants.

This fixes the issue of WMR having to duplicate the constants since it
can't rely directly on OpenVR, and also simplifies things by using the
notion of primary/secondary axes instead of having to conditionally
change which axis type we use based on runtime.

Bug: 965306
Change-Id: Ide659c0c25958c1a732a5f893ce01a9cd88499e5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1625933
Commit-Queue: Brian Sheedy <bsheedy@chromium.org>
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
Cr-Commit-Position: refs/heads/master@{#662458}
diff --git a/chrome/browser/vr/test/xr_browser_test.cc b/chrome/browser/vr/test/xr_browser_test.cc
index 8e95fd9..7f22461 100644
--- a/chrome/browser/vr/test/xr_browser_test.cc
+++ b/chrome/browser/vr/test/xr_browser_test.cc
@@ -158,6 +158,32 @@
   return XrBrowserTestBase::RuntimeType::RUNTIME_NONE;
 }
 
+device::XrAxisType XrBrowserTestBase::GetPrimaryAxisType() const {
+  auto runtime = GetRuntimeType();
+  switch (runtime) {
+    case XrBrowserTestBase::RuntimeType::RUNTIME_OPENVR:
+      return device::XrAxisType::kTrackpad;
+    case XrBrowserTestBase::RuntimeType::RUNTIME_WMR:
+      return device::XrAxisType::kJoystick;
+    case XrBrowserTestBase::RuntimeType::RUNTIME_NONE:
+      return device::XrAxisType::kNone;
+  }
+  NOTREACHED();
+}
+
+device::XrAxisType XrBrowserTestBase::GetSecondaryAxisType() const {
+  auto runtime = GetRuntimeType();
+  switch (runtime) {
+    case XrBrowserTestBase::RuntimeType::RUNTIME_OPENVR:
+      return device::XrAxisType::kJoystick;
+    case XrBrowserTestBase::RuntimeType::RUNTIME_WMR:
+      return device::XrAxisType::kTrackpad;
+    case XrBrowserTestBase::RuntimeType::RUNTIME_NONE:
+      return device::XrAxisType::kNone;
+  }
+  NOTREACHED();
+}
+
 GURL XrBrowserTestBase::GetFileUrlForHtmlTestFile(
     const std::string& test_name) {
   return ui_test_utils::GetTestUrl(
diff --git a/chrome/browser/vr/test/xr_browser_test.h b/chrome/browser/vr/test/xr_browser_test.h
index c2a6dca..0d3c9ae 100644
--- a/chrome/browser/vr/test/xr_browser_test.h
+++ b/chrome/browser/vr/test/xr_browser_test.h
@@ -19,6 +19,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
+#include "device/vr/test/test_hook.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "url/gurl.h"
 
@@ -75,6 +76,8 @@
   void TearDown() override;
 
   virtual RuntimeType GetRuntimeType() const;
+  device::XrAxisType GetPrimaryAxisType() const;
+  device::XrAxisType GetSecondaryAxisType() const;
 
   // Returns a GURL to the XR test HTML file of the given name, e.g.
   // GetHtmlTestFile("foo") returns a GURL for the foo.html file in the XR
diff --git a/chrome/browser/vr/test/xr_browser_tests.md b/chrome/browser/vr/test/xr_browser_tests.md
index fc7f3a9..e69404f 100644
--- a/chrome/browser/vr/test/xr_browser_tests.md
+++ b/chrome/browser/vr/test/xr_browser_tests.md
@@ -112,14 +112,6 @@
 There are currently several assumptions made that must be adhered to in order
 for input to work properly in both OpenVR and Windows Mixed Reality.
 
-#### Primary Axes
-
-OpenVR assumes that axis 0 is the primary axis (usually a touchpad). However,
-WMR assumes that axis 2 is the primary axis (must be a joystick). This will
-eventually be abstracted away, but in the meantime, if you care about the
-primary axis (i.e. which one shows up as axis 0 in WebXR), you'll need to
-conditionally change which axis you set based on runtime.
-
 #### WMR and Incomplete Gamepads
 
 OpenVR supports arbitrary controller mappings, but WMR only supports one actual
diff --git a/chrome/browser/vr/webxr_vr_input_browser_test.cc b/chrome/browser/vr/webxr_vr_input_browser_test.cc
index 1c6edae..a2df4b2 100644
--- a/chrome/browser/vr/webxr_vr_input_browser_test.cc
+++ b/chrome/browser/vr/webxr_vr_input_browser_test.cc
@@ -77,9 +77,9 @@
     UpdateControllerAndWait(index, controller_data);
   }
 
-  void ToggleTriggerButton(unsigned int index, vr::EVRButtonId button_id) {
+  void ToggleTriggerButton(unsigned int index, device::XrButtonId button_id) {
     auto controller_data = GetCurrentControllerData(index);
-    uint64_t button_mask = vr::ButtonMaskFromId(button_id);
+    uint64_t button_mask = device::XrButtonMaskFromId(button_id);
 
     controller_data.packet_number++;
     controller_data.buttons_pressed ^= button_mask;
@@ -87,19 +87,19 @@
 
     bool is_pressed = ((controller_data.buttons_pressed & button_mask) != 0);
 
-    unsigned int axis_offset = GetAxisOffset(button_id);
+    unsigned int axis_offset = device::XrAxisOffsetFromId(button_id);
     DCHECK(controller_data.axis_data[axis_offset].axis_type ==
-           vr::k_eControllerAxis_Trigger);
+           device::XrAxisType::kTrigger);
     controller_data.axis_data[axis_offset].x = is_pressed ? 1.0 : 0.0;
     UpdateControllerAndWait(index, controller_data);
   }
 
   void SetAxes(unsigned int index,
-               vr::EVRButtonId button_id,
+               device::XrButtonId button_id,
                float x,
                float y) {
     auto controller_data = GetCurrentControllerData(index);
-    unsigned int axis_offset = GetAxisOffset(button_id);
+    unsigned int axis_offset = device::XrAxisOffsetFromId(button_id);
     DCHECK(controller_data.axis_data[axis_offset].axis_type != 0);
 
     controller_data.packet_number++;
@@ -109,7 +109,7 @@
   }
 
   void TogglePrimaryTrigger(unsigned int index) {
-    ToggleTriggerButton(index, vr::k_EButton_SteamVR_Trigger);
+    ToggleTriggerButton(index, device::XrButtonId::kAxisTrigger);
   }
 
   void PressReleasePrimaryTrigger(unsigned int index) {
@@ -118,20 +118,16 @@
   }
 
   unsigned int CreateAndConnectMinimalGamepad(
-      vr::EVRButtonId primary_axis = vr::k_EButton_Axis0) {
+      device::XrAxisType primary_axis_type) {
     // Create a controller that only supports select and one TrackPad, i.e. it
     // has just enough data to be considered a gamepad.
     uint64_t supported_buttons =
-        vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Trigger) |
-        vr::ButtonMaskFromId(primary_axis);
+        device::XrButtonMaskFromId(device::XrButtonId::kAxisTrigger) |
+        device::XrButtonMaskFromId(device::XrButtonId::kAxisPrimary);
 
-    unsigned int primary_axis_type = primary_axis == vr::k_EButton_Axis0
-                                         ? vr::k_eControllerAxis_TrackPad
-                                         : vr::k_eControllerAxis_Joystick;
-
-    std::map<vr::EVRButtonId, unsigned int> axis_types = {
-        {primary_axis, primary_axis_type},
-        {vr::k_EButton_SteamVR_Trigger, vr::k_eControllerAxis_Trigger},
+    std::map<device::XrButtonId, unsigned int> axis_types = {
+        {device::XrButtonId::kAxisPrimary, primary_axis_type},
+        {device::XrButtonId::kAxisTrigger, device::XrAxisType::kTrigger},
     };
 
     return CreateAndConnectController(
@@ -141,12 +137,12 @@
 
   unsigned int CreateAndConnectController(
       device::ControllerRole role,
-      std::map<vr::EVRButtonId, unsigned int> axis_types = {},
+      std::map<device::XrButtonId, unsigned int> axis_types = {},
       uint64_t supported_buttons = UINT64_MAX) {
     auto controller = CreateValidController(role);
     controller.supported_buttons = supported_buttons;
     for (const auto& axis_type : axis_types) {
-      unsigned int axis_offset = GetAxisOffset(axis_type.first);
+      unsigned int axis_offset = device::XrAxisOffsetFromId(axis_type.first);
       controller.axis_data[axis_offset].axis_type = axis_type.second;
     }
 
@@ -155,14 +151,14 @@
 
   void UpdateControllerSupport(
       unsigned int controller_index,
-      const std::map<vr::EVRButtonId, unsigned int>& axis_types,
+      const std::map<device::XrButtonId, unsigned int>& axis_types,
       uint64_t supported_buttons) {
     auto controller_data = GetCurrentControllerData(controller_index);
 
     for (unsigned int i = 0; i < device::kMaxNumAxes; i++) {
       auto button_id = GetAxisId(i);
       auto it = axis_types.find(button_id);
-      unsigned int new_axis_type = k_eControllerAxis_None;
+      unsigned int new_axis_type = device::XrAxisType::kNone;
       if (it != axis_types.end())
         new_axis_type = it->second;
       controller_data.axis_data[i].axis_type = new_axis_type;
@@ -181,14 +177,9 @@
   }
 
  private:
-  vr::EVRButtonId GetAxisId(unsigned int offset) {
-    return static_cast<vr::EVRButtonId>(vr::k_EButton_Axis0 + offset);
-  }
-  unsigned int GetAxisOffset(vr::EVRButtonId button_id) {
-    DCHECK(vr::k_EButton_Axis0 <= button_id &&
-           button_id < (vr::k_EButton_Axis0 + device::kMaxNumAxes));
-    return static_cast<unsigned int>(button_id) -
-           static_cast<unsigned int>(vr::k_EButton_Axis0);
+  device::XrButtonId GetAxisId(unsigned int offset) {
+    return static_cast<device::XrButtonId>(device::XrButtonId::kAxisPrimary +
+                                           offset);
   }
 
   device::ControllerFrameData GetCurrentControllerData(unsigned int index) {
@@ -216,7 +207,8 @@
 // event is fired and a new input source is created.
 IN_PROC_BROWSER_TEST_F(WebXrVrBrowserTestStandard, TestInputHandednessChange) {
   WebXrControllerInputMock my_mock;
-  unsigned int controller_index = my_mock.CreateAndConnectMinimalGamepad();
+  unsigned int controller_index =
+      my_mock.CreateAndConnectMinimalGamepad(GetPrimaryAxisType());
 
   LoadUrlAndAwaitInitialization(
       GetFileUrlForHtmlTestFile("test_webxr_input_same_object"));
@@ -260,9 +252,9 @@
   // There's a potential for a race causing the input sources change event to
   // fire multiple times if we disconnect a controller that has a gamepad.
   uint64_t insufficient_buttons =
-      vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Trigger);
-  std::map<vr::EVRButtonId, unsigned int> insufficient_axis_types = {
-      {vr::k_EButton_SteamVR_Trigger, vr::k_eControllerAxis_Trigger},
+      device::XrButtonMaskFromId(device::XrButtonId::kAxisTrigger);
+  std::map<device::XrButtonId, unsigned int> insufficient_axis_types = {
+      {device::XrButtonId::kAxisTrigger, device::XrAxisType::kTrigger},
   };
   unsigned int controller_index = my_mock.CreateAndConnectController(
       device::ControllerRole::kControllerRoleRight, insufficient_axis_types,
@@ -297,7 +289,8 @@
   // it is both added and removed.
   // Since we're changing the controller state without disconnecting it, we can
   // (and should) use the minimal gamepad here.
-  controller_index = my_mock.CreateAndConnectMinimalGamepad();
+  controller_index =
+      my_mock.CreateAndConnectMinimalGamepad(t->GetPrimaryAxisType());
   t->PollJavaScriptBooleanOrFail("inputChangeEvents === 3",
                                  WebXrVrBrowserTestBase::kPollTimeoutShort);
   t->RunJavaScriptOrFail("updateCachedInputSource(0)");
@@ -342,19 +335,19 @@
   // Note that we need to set the trigger axis because of how OpenVR handles
   // selects.
   uint64_t insufficient_buttons =
-      vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Trigger);
-  std::map<vr::EVRButtonId, unsigned int> insufficient_axis_types = {
-      {vr::k_EButton_SteamVR_Trigger, vr::k_eControllerAxis_Trigger},
+      device::XrButtonMaskFromId(device::XrButtonId::kAxisTrigger);
+  std::map<device::XrButtonId, unsigned int> insufficient_axis_types = {
+      {device::XrButtonId::kAxisTrigger, device::XrAxisType::kTrigger},
   };
 
   // Create a set of buttons and axes that we expect to have enough data to be
   // made into an xr-standard gamepad (which we expect the runtimes to report).
   uint64_t sufficient_buttons =
-      vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Trigger) |
-      vr::ButtonMaskFromId(vr::k_EButton_Axis0);
-  std::map<vr::EVRButtonId, unsigned int> sufficient_axis_types = {
-      {vr::k_EButton_Axis0, vr::k_eControllerAxis_TrackPad},
-      {vr::k_EButton_SteamVR_Trigger, vr::k_eControllerAxis_Trigger},
+      device::XrButtonMaskFromId(device::XrButtonId::kAxisTrigger) |
+      device::XrButtonMaskFromId(device::XrButtonId::kAxisPrimary);
+  std::map<device::XrButtonId, unsigned int> sufficient_axis_types = {
+      {device::XrButtonId::kAxisPrimary, device::XrAxisType::kTrackpad},
+      {device::XrButtonId::kAxisTrigger, device::XrAxisType::kTrigger},
   };
 
   // Start off without a gamepad.
@@ -426,7 +419,7 @@
   // Create a controller that only supports select, i.e. it lacks enough data
   // to be considered a gamepad.
   uint64_t supported_buttons =
-      vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Trigger);
+      device::XrButtonMaskFromId(device::XrButtonId::kAxisTrigger);
   my_mock.CreateAndConnectController(
       device::ControllerRole::kControllerRoleRight, {}, supported_buttons);
 
@@ -440,16 +433,9 @@
 
 void TestGamepadMinimumDataImpl(WebXrVrBrowserTestBase* t) {
   WebXrControllerInputMock my_mock;
-  // The touchpad is the primary axis for OpenVR, while the Joystick is the
-  // primary axis for WMR.
-  vr::EVRButtonId primary_axis;
-  if (t->GetRuntimeType() == XrBrowserTestBase::RuntimeType::RUNTIME_OPENVR) {
-    primary_axis = vr::k_EButton_Axis0;
-  } else {
-    primary_axis = vr::k_EButton_Axis2;
-  }
+
   unsigned int controller_index =
-      my_mock.CreateAndConnectMinimalGamepad(primary_axis);
+      my_mock.CreateAndConnectMinimalGamepad(t->GetPrimaryAxisType());
 
   t->LoadUrlAndAwaitInitialization(
       t->GetFileUrlForHtmlTestFile("test_webxr_gamepad_support"));
@@ -458,8 +444,10 @@
   // Press the trigger and set the axis to a non-zero amount, so we can ensure
   // we aren't getting just default gamepad data.
   my_mock.TogglePrimaryTrigger(controller_index);
-  my_mock.SetAxes(controller_index, primary_axis, 0.5, -0.5);
-  my_mock.ToggleButtonTouches(controller_index, primary_axis);
+  my_mock.SetAxes(controller_index, device::XrButtonId::kAxisPrimary, 0.5,
+                  -0.5);
+  my_mock.ToggleButtonTouches(controller_index,
+                              device::XrButtonId::kAxisPrimary);
 
   // The trigger should be button 0, and the first set of axes should have it's
   // value set.
@@ -493,15 +481,15 @@
   // Create a controller that supports all reserved buttons.  Note that per
   // third_party/openvr/src/headers/openvr.h, SteamVR_Trigger is Axis1.
   uint64_t supported_buttons =
-      vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Trigger) |
-      vr::ButtonMaskFromId(vr::k_EButton_Axis0) |
-      vr::ButtonMaskFromId(vr::k_EButton_Axis2) |
-      vr::ButtonMaskFromId(vr::k_EButton_Grip);
+      device::XrButtonMaskFromId(device::XrButtonId::kAxisTrigger) |
+      device::XrButtonMaskFromId(device::XrButtonId::kAxisPrimary) |
+      device::XrButtonMaskFromId(device::XrButtonId::kAxisSecondary) |
+      device::XrButtonMaskFromId(device::XrButtonId::kGrip);
 
-  std::map<vr::EVRButtonId, unsigned int> axis_types = {
-      {vr::k_EButton_Axis0, vr::k_eControllerAxis_TrackPad},
-      {vr::k_EButton_SteamVR_Trigger, vr::k_eControllerAxis_Trigger},
-      {vr::k_EButton_Axis2, vr::k_eControllerAxis_Joystick},
+  std::map<device::XrButtonId, unsigned int> axis_types = {
+      {device::XrButtonId::kAxisPrimary, t->GetPrimaryAxisType()},
+      {device::XrButtonId::kAxisTrigger, device::XrAxisType::kTrigger},
+      {device::XrButtonId::kAxisSecondary, t->GetSecondaryAxisType()},
   };
 
   unsigned int controller_index = my_mock.CreateAndConnectController(
@@ -515,24 +503,17 @@
   // Setup some state on the optional buttons (as TestGamepadMinimumData should
   // ensure proper state on the required buttons).
   // Set a value on the secondary set of axes.
-  // Because the touchpad is primary for OpenVR but the Joystick is primary in
-  // WMR, we have to use different axes for each.
-  vr::EVRButtonId secondary_axis;
-  if (t->GetRuntimeType() == XrBrowserTestBase::RuntimeType::RUNTIME_OPENVR) {
-    secondary_axis = vr::k_EButton_Axis2;
-  } else {
-    secondary_axis = vr::k_EButton_Axis0;
-  }
-
-  my_mock.SetAxes(controller_index, secondary_axis, 0.25, -0.25);
+  my_mock.SetAxes(controller_index, device::XrButtonId::kAxisSecondary, 0.25,
+                  -0.25);
 
   // Set the secondary trackpad/joystick to be touched.
-  my_mock.ToggleButtonTouches(controller_index,
-                              vr::ButtonMaskFromId(secondary_axis));
+  my_mock.ToggleButtonTouches(
+      controller_index,
+      device::XrButtonMaskFromId(device::XrButtonId::kAxisSecondary));
 
   // Set the grip button to be pressed.
   my_mock.ToggleButtons(controller_index,
-                        vr::ButtonMaskFromId(vr::k_EButton_Grip));
+                        device::XrButtonMaskFromId(device::XrButtonId::kGrip));
 
   // Controller should meet the requirements for the 'xr-standard' mapping.
   t->PollJavaScriptBooleanOrFail("isMappingEqualTo('xr-standard')",
@@ -576,13 +557,13 @@
   // Create a controller that is missing reserved buttons, but supports an
   // extra button to guarantee that the reserved button is held.
   uint64_t supported_buttons =
-      vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Trigger) |
-      vr::ButtonMaskFromId(vr::k_EButton_Axis0) |
-      vr::ButtonMaskFromId(vr::k_EButton_A);
+      device::XrButtonMaskFromId(device::XrButtonId::kAxisTrigger) |
+      device::XrButtonMaskFromId(device::XrButtonId::kAxisPrimary) |
+      device::XrButtonMaskFromId(device::XrButtonId::kA);
 
-  std::map<vr::EVRButtonId, unsigned int> axis_types = {
-      {vr::k_EButton_Axis0, vr::k_eControllerAxis_Joystick},
-      {vr::k_EButton_SteamVR_Trigger, vr::k_eControllerAxis_Trigger},
+  std::map<device::XrButtonId, unsigned int> axis_types = {
+      {device::XrButtonId::kAxisPrimary, device::XrAxisType::kJoystick},
+      {device::XrButtonId::kAxisTrigger, device::XrAxisType::kTrigger},
   };
 
   unsigned int controller_index = my_mock.CreateAndConnectController(
@@ -620,7 +601,8 @@
 void TestControllerInputRegisteredImpl(WebXrVrBrowserTestBase* t) {
   WebXrControllerInputMock my_mock;
 
-  unsigned int controller_index = my_mock.CreateAndConnectMinimalGamepad();
+  unsigned int controller_index =
+      my_mock.CreateAndConnectMinimalGamepad(t->GetPrimaryAxisType());
 
   // Load the test page and enter presentation.
   t->LoadUrlAndAwaitInitialization(
@@ -672,7 +654,9 @@
   // here as that adds support for axis_data[0], which causes OpenVR on WebVR
   // to treat that button as the primary input (per the defacto webvr standard),
   // and we want it to only see the trigger.
-  controller_data.axis_data[1].axis_type = vr::k_eControllerAxis_Trigger;
+  controller_data
+      .axis_data[device::XrAxisOffsetFromId(device::XrButtonId::kAxisTrigger)]
+      .axis_type = device::XrAxisType::kTrigger;
   unsigned int controller_index = my_mock.ConnectController(controller_data);
 
   // Load the test page and enter presentation.
diff --git a/device/vr/openvr/test/test_helper.cc b/device/vr/openvr/test/test_helper.cc
index 5d3f3ca..480c7ea 100644
--- a/device/vr/openvr/test/test_helper.cc
+++ b/device/vr/openvr/test/test_helper.cc
@@ -3,6 +3,10 @@
 // found in the LICENSE file.
 
 #include "device/vr/openvr/test/test_helper.h"
+
+#include <map>
+#include <memory>
+
 #include "base/debug/debugger.h"
 #include "base/logging.h"
 #include "base/synchronization/lock.h"
@@ -14,7 +18,6 @@
 #include <D3D11_1.h>
 #include <DXGI1_4.h>
 #include <wrl.h>
-#include <memory>
 
 namespace vr {
 
@@ -115,6 +118,62 @@
   return ret;
 }
 
+static const std::map<device::XrButtonId, vr::EVRButtonId>
+    xr_to_openvr_button_map = {
+        {device::XrButtonId::kSystem, vr::EVRButtonId::k_EButton_System},
+        {device::XrButtonId::kMenu, vr::EVRButtonId::k_EButton_ApplicationMenu},
+        {device::XrButtonId::kGrip, vr::EVRButtonId::k_EButton_Grip},
+        {device::XrButtonId::kDpadLeft, vr::EVRButtonId::k_EButton_DPad_Left},
+        {device::XrButtonId::kDpadUp, vr::EVRButtonId::k_EButton_DPad_Up},
+        {device::XrButtonId::kDpadRight, vr::EVRButtonId::k_EButton_DPad_Right},
+        {device::XrButtonId::kDpadDown, vr::EVRButtonId::k_EButton_DPad_Down},
+        {device::XrButtonId::kA, vr::EVRButtonId::k_EButton_A},
+        {device::XrButtonId::kProximitySensor,
+         vr::EVRButtonId::k_EButton_ProximitySensor},
+        {device::XrButtonId::kAxisPrimary, vr::EVRButtonId::k_EButton_Axis0},
+        {device::XrButtonId::kAxisTrigger,
+         vr::EVRButtonId::k_EButton_SteamVR_Trigger},
+        {device::XrButtonId::kAxisSecondary, vr::EVRButtonId::k_EButton_Axis2},
+        {device::XrButtonId::kAxisTertiary, vr::EVRButtonId::k_EButton_Axis3},
+        {device::XrButtonId::kAxisQuaternary, vr::EVRButtonId::k_EButton_Axis4},
+};
+
+// Translates the platform-agnostic button masks to the OpenVR-specific button
+// masks. The platform-agnostic ones were based off OpenVR, so this actually
+// does little to nothing.
+uint64_t TranslateButtonMask(uint64_t xr_mask) {
+  uint64_t ret = 0;
+  for (const auto& pair : xr_to_openvr_button_map) {
+    // Bitwise-and the complete mask with the button-specific mask, shift it all
+    // the way to the right, then shift it to the left however much it needs to
+    // be in the correct location for OpenVR. Then, add that new button-specific
+    // mask to the complete mask that we'll be returning.
+    ret |= ((xr_mask & device::XrButtonMaskFromId(pair.first)) >> pair.first)
+           << pair.second;
+  }
+  return ret;
+}
+
+// Translates the platform-agnostic axis types to the OpenVR-specific axis
+// types. The platform-agnostic ones were based off OpenVR, so this actually
+// does little to nothing.
+vr::EVRControllerAxisType TranslateAxisType(device::XrAxisType type) {
+  switch (type) {
+    case device::XrAxisType::kNone:
+      return vr::EVRControllerAxisType::k_eControllerAxis_None;
+    case device::XrAxisType::kTrackpad:
+      return vr::EVRControllerAxisType::k_eControllerAxis_TrackPad;
+    case device::XrAxisType::kJoystick:
+      return vr::EVRControllerAxisType::k_eControllerAxis_Joystick;
+    case device::XrAxisType::kTrigger:
+      return vr::EVRControllerAxisType::k_eControllerAxis_Trigger;
+  }
+}
+
+vr::EVRControllerAxisType TranslateAxisType(unsigned int type) {
+  return TranslateAxisType(static_cast<device::XrAxisType>(type));
+}
+
 }  // namespace
 
 float TestHelper::GetInterpupillaryDistance() {
@@ -175,7 +234,7 @@
         ret = vr::TrackedProp_WrongDeviceClass;
         break;
       }
-      prop_value = static_cast<vr::EVRControllerAxisType>(
+      prop_value = TranslateAxisType(
           controller_data.axis_data[prop - vr::Prop_Axis0Type_Int32].axis_type);
       break;
     }
@@ -199,7 +258,7 @@
         ret = vr::TrackedProp_WrongDeviceClass;
         break;
       }
-      prop_value = controller_data.supported_buttons;
+      prop_value = TranslateButtonMask(controller_data.supported_buttons);
       break;
     }
     default:
@@ -261,8 +320,10 @@
   if (test_hook_) {
     auto controller_data = test_hook_->WaitGetControllerData(index);
     controller_state->unPacketNum = controller_data.packet_number;
-    controller_state->ulButtonPressed = controller_data.buttons_pressed;
-    controller_state->ulButtonTouched = controller_data.buttons_touched;
+    controller_state->ulButtonPressed =
+        TranslateButtonMask(controller_data.buttons_pressed);
+    controller_state->ulButtonTouched =
+        TranslateButtonMask(controller_data.buttons_touched);
     for (unsigned int i = 0; i < device::kMaxNumAxes; ++i) {
       controller_state->rAxis[i].x = controller_data.axis_data[i].x;
       controller_state->rAxis[i].y = controller_data.axis_data[i].y;
diff --git a/device/vr/test/test_hook.h b/device/vr/test/test_hook.h
index 08decb9c..ff078e5 100644
--- a/device/vr/test/test_hook.h
+++ b/device/vr/test/test_hook.h
@@ -5,15 +5,55 @@
 #ifndef DEVICE_VR_TEST_TEST_HOOK_H_
 #define DEVICE_VR_TEST_TEST_HOOK_H_
 
+#include "base/logging.h"
+
 #include <cstdint>
 
 namespace device {
 
 // Update this string whenever either interface changes.
-constexpr char kChromeOpenVRTestHookAPI[] = "ChromeTestHook_2";
+constexpr char kChromeOpenVRTestHookAPI[] = "ChromeTestHook_3";
 constexpr unsigned int kMaxTrackedDevices = 64;
 constexpr unsigned int kMaxNumAxes = 5;
 
+// These are largely the same as the OpenVR button/axis constants, but kept
+// separate so they're more runtime-agnostic.
+enum XrButtonId {
+  kSystem = 0,
+  kMenu = 1,
+  kGrip = 2,
+  kDpadLeft = 3,
+  kDpadUp = 4,
+  kDpadRight = 5,
+  kDpadDown = 6,
+  kA = 7,
+  kProximitySensor = 31,
+  kAxisPrimary = 32,
+  kAxisTrigger = 33,
+  kAxisSecondary = 34,
+  kAxisTertiary = 35,
+  kAxisQuaternary = 36,
+  kMax = 64
+};
+
+enum XrAxisType {
+  kNone = 0,
+  kTrackpad = 1,
+  kJoystick = 2,
+  kTrigger = 3,
+};
+
+inline uint64_t XrButtonMaskFromId(XrButtonId id) {
+  return 1ull << id;
+}
+
+inline unsigned int XrAxisOffsetFromId(XrButtonId id) {
+  DCHECK(XrButtonId::kAxisPrimary <= id &&
+         id < XrButtonId::kAxisPrimary + kMaxNumAxes);
+  return static_cast<unsigned int>(id) -
+         static_cast<unsigned int>(XrButtonId::kAxisPrimary);
+}
+
 struct Color {
   unsigned char r;
   unsigned char g;
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_manager.cc b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_manager.cc
index 0299adb..bca48e1 100644
--- a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_manager.cc
+++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_manager.cc
@@ -4,11 +4,40 @@
 
 #include "device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_manager.h"
 
+#include <map>
+
 #include "base/logging.h"
 #include "device/vr/test/test_hook.h"
 #include "device/vr/windows_mixed_reality/mixed_reality_statics.h"
 #include "device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_source_state.h"
 
+namespace {
+
+static const std::map<
+    uint64_t,
+    ABI::Windows::UI::Input::Spatial::SpatialInteractionPressKind>
+    mask_to_press_kind = {
+        // Select/trigger.
+        {device::XrButtonMaskFromId(device::XrButtonId::kAxisTrigger),
+         ABI::Windows::UI::Input::Spatial::SpatialInteractionPressKind_Select},
+        // Menu.
+        {device::XrButtonMaskFromId(device::XrButtonId::kMenu),
+         ABI::Windows::UI::Input::Spatial::SpatialInteractionPressKind_Menu},
+        // Grasp/grip.
+        {device::XrButtonMaskFromId(device::XrButtonId::kGrip),
+         ABI::Windows::UI::Input::Spatial::SpatialInteractionPressKind_Grasp},
+        // Touchpad.
+        {device::XrButtonMaskFromId(device::XrButtonId::kAxisSecondary),
+         ABI::Windows::UI::Input::Spatial::
+             SpatialInteractionPressKind_Touchpad},
+        // Joystick.
+        {device::XrButtonMaskFromId(device::XrButtonId::kAxisPrimary),
+         ABI::Windows::UI::Input::Spatial::
+             SpatialInteractionPressKind_Thumbstick},
+};
+
+}  // namespace
+
 namespace device {
 
 // MockWMRInputSourceEventArgs
@@ -83,35 +112,14 @@
 
   // Determine which buttons changed - if more than one changed, we'll have to
   // fire the callbacks multiple times.
-  // Select/trigger.
-  if (changed_buttons & kSelectButton) {
-    HandleCallback(
-        data, id, kSelectButton,
-        ABI::Windows::UI::Input::Spatial::SpatialInteractionPressKind_Select);
-  }
-  // Menu.
-  if (changed_buttons & kMenuButton) {
-    HandleCallback(
-        data, id, kMenuButton,
-        ABI::Windows::UI::Input::Spatial::SpatialInteractionPressKind_Menu);
-  }
-  // Grasp/grip.
-  if (changed_buttons & kGripButton) {
-    HandleCallback(
-        data, id, kGripButton,
-        ABI::Windows::UI::Input::Spatial::SpatialInteractionPressKind_Grasp);
-  }
-  // Touchpad.
-  if (changed_buttons & kTrackpadButton) {
-    HandleCallback(
-        data, id, kTrackpadButton,
-        ABI::Windows::UI::Input::Spatial::SpatialInteractionPressKind_Touchpad);
-  }
-  // Joystick.
-  if (changed_buttons & kJoystickButton) {
-    HandleCallback(data, id, kJoystickButton,
-                   ABI::Windows::UI::Input::Spatial::
-                       SpatialInteractionPressKind_Thumbstick);
+  for (const auto& pair : mask_to_press_kind) {
+    // pair.first is the button mask for the button type being checked and
+    // pair.second is the corresponding WMR SpatialInteractionPressKind. So, if
+    // the button being checked changed, handle the correct callback with the
+    // correct press kind.
+    if (changed_buttons & pair.first) {
+      HandleCallback(data, id, pair.first, pair.second);
+    }
   }
 }
 
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_source_state.cc b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_source_state.cc
index cfff5def..23a3eeb 100644
--- a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_source_state.cc
+++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_source_state.cc
@@ -27,15 +27,15 @@
 }
 
 bool MockWMRInputSourceState::IsGrasped() const {
-  return IsButtonPressed(kGripButton);
+  return IsButtonPressed(XrButtonId::kGrip);
 }
 
 bool MockWMRInputSourceState::IsSelectPressed() const {
-  return IsButtonPressed(kSelectButton);
+  return IsButtonPressed(XrButtonId::kAxisTrigger);
 }
 
 double MockWMRInputSourceState::SelectPressedValue() const {
-  double val = data_.axis_data[kSelectAxis].x;
+  double val = data_.axis_data[XrAxisOffsetFromId(XrButtonId::kAxisTrigger)].x;
   // Should only be in [0, 1] for triggers.
   DCHECK(val <= 1);
   DCHECK(val >= 0);
@@ -47,21 +47,21 @@
 }
 
 bool MockWMRInputSourceState::IsThumbstickPressed() const {
-  return IsButtonPressed(kJoystickButton);
+  return IsButtonPressed(XrButtonId::kAxisPrimary);
 }
 
 bool MockWMRInputSourceState::IsTouchpadPressed() const {
-  return IsButtonPressed(kTrackpadButton);
+  return IsButtonPressed(XrButtonId::kAxisSecondary);
 }
 
 bool MockWMRInputSourceState::IsTouchpadTouched() const {
-  auto touched =
-      data_.supported_buttons & data_.buttons_touched & kTrackpadButton;
+  auto touched = data_.supported_buttons & data_.buttons_touched &
+                 XrButtonMaskFromId(XrButtonId::kAxisSecondary);
   return touched != 0;
 }
 
 double MockWMRInputSourceState::ThumbstickX() const {
-  double val = data_.axis_data[kJoystickAxis].x;
+  double val = data_.axis_data[XrAxisOffsetFromId(XrButtonId::kAxisPrimary)].x;
   // Should be in [-1, 1] for joysticks.
   DCHECK(val <= 1);
   DCHECK(val >= -1);
@@ -69,7 +69,7 @@
 }
 
 double MockWMRInputSourceState::ThumbstickY() const {
-  double val = data_.axis_data[kJoystickAxis].y;
+  double val = data_.axis_data[XrAxisOffsetFromId(XrButtonId::kAxisPrimary)].y;
   // Should be in [-1, 1] for joysticks.
   DCHECK(val <= 1);
   DCHECK(val >= -1);
@@ -77,7 +77,8 @@
 }
 
 double MockWMRInputSourceState::TouchpadX() const {
-  double val = data_.axis_data[kTrackpadAxis].x;
+  double val =
+      data_.axis_data[XrAxisOffsetFromId(XrButtonId::kAxisSecondary)].x;
   // Should be in [-1, 1] for touchpads.
   DCHECK(val <= 1);
   DCHECK(val >= -1);
@@ -85,7 +86,8 @@
 }
 
 double MockWMRInputSourceState::TouchpadY() const {
-  double val = data_.axis_data[kTrackpadAxis].y;
+  double val =
+      data_.axis_data[XrAxisOffsetFromId(XrButtonId::kAxisSecondary)].y;
   // Should be in [-1, 1] for touchpads.
   DCHECK(val <= 1);
   DCHECK(val >= -1);
@@ -97,8 +99,9 @@
   return std::make_unique<MockWMRInputLocation>(data_);
 }
 
-bool MockWMRInputSourceState::IsButtonPressed(uint64_t button_mask) const {
-  auto pressed = data_.supported_buttons & data_.buttons_pressed & button_mask;
+bool MockWMRInputSourceState::IsButtonPressed(XrButtonId id) const {
+  auto mask = XrButtonMaskFromId(id);
+  auto pressed = data_.supported_buttons & data_.buttons_pressed & mask;
   return pressed != 0;
 }
 
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_source_state.h b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_source_state.h
index 1cad57a..7e60847a 100644
--- a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_source_state.h
+++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_source_state.h
@@ -9,23 +9,6 @@
 
 namespace device {
 
-// These are copies of various OpenVR mask constants that are used for
-// specifying controller input. However, since we won't necessarily have OpenVR
-// support compiled in, we can't use the constants directly.
-// k_EButton_ApplicationMenu.
-static constexpr uint64_t kMenuButton = 1ull << 1;
-// k_EButton_Grip.
-static constexpr uint64_t kGripButton = 1ull << 2;
-// k_EButton_SteamVR_Touchpad.
-static constexpr uint64_t kTrackpadButton = 1ull << 32;
-// k_EButton_SteamVR_Trigger.
-static constexpr uint64_t kSelectButton = 1ull << 33;
-// k_EButton_Axis2.
-static constexpr uint64_t kJoystickButton = 1ull << 34;
-static constexpr uint64_t kTrackpadAxis = 0;
-static constexpr uint64_t kSelectAxis = 1;
-static constexpr uint64_t kJoystickAxis = 2;
-
 class MockWMRInputSourceState : public WMRInputSourceState {
  public:
   MockWMRInputSourceState(ControllerFrameData data, unsigned int id);
@@ -53,7 +36,7 @@
       const WMRCoordinateSystem* origin) const override;
 
  private:
-  bool IsButtonPressed(uint64_t button_mask) const;
+  bool IsButtonPressed(XrButtonId id) const;
   ControllerFrameData data_;
   unsigned int id_;
 };