Skip to content

Commit

Permalink
Set XRInputSource.profiles values
Browse files Browse the repository at this point in the history
Profiles array contents in order:

WMR
"samsung-odyssey" (only if detected by VID/PID)
"windows-mixed-reality"
"grip-touchpad-thumbstick-controller"

Oculus
"oculus-touch"
"grip-thumbstick-controller"

OpenVR
"<ManufacturerName>-<ModelName>" Whitespace is replace with "-" and
string is converted to lowercase to follow spec.
"<functionality>"

For example, OpenVR exposing HTC Vive would have profile array of:
"htc-vive-controller-mv"
"grip-touchpad-controller"

Bug: 989114
Change-Id: I0e1d5f7d0866355cbbd526892657c6bc41f0d88f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1741505
Commit-Queue: Jacob DeWitt <jacde@chromium.org>
Reviewed-by: Brandon Jones <bajones@chromium.org>
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
Cr-Commit-Position: refs/heads/master@{#685009}
  • Loading branch information
Jacob DeWitt authored and Commit Bot committed Aug 7, 2019
1 parent 46f21d4 commit d7a5a93
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 32 deletions.
8 changes: 8 additions & 0 deletions device/vr/oculus/oculus_render_loop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,14 @@ device::mojom::XRInputSourceStatePtr OculusRenderLoop::GetTouchData(
desc->pointer_offset->Translate3d(0, 0, -kGripOffsetZMeters);
desc->pointer_offset->RotateAboutXAxis(-kGripRotationXDelta);

// This function is only called when we're working with an Oculus touch.
desc->profiles.push_back("oculus-touch");

// The absence of "touchpad" in this string indicates that the slots in the
// button and axes arrays are placeholders required by the xr-standard mapping
// but not actually updated with any input.
desc->profiles.push_back("grip-thumbstick-controller");

state->description = std::move(desc);

state->gamepad = OculusGamepadHelper::CreateGamepad(session_, hand);
Expand Down
88 changes: 60 additions & 28 deletions device/vr/openvr/openvr_gamepad_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "device/gamepad/public/cpp/gamepads.h"
#include "device/vr/util/gamepad_builder.h"
Expand Down Expand Up @@ -127,6 +129,17 @@ constexpr std::array<vr::EVRButtonId, 5> kWebXRButtonOrder = {
vr::k_EButton_DPad_Right, vr::k_EButton_DPad_Down,
};

// To make sure this string fits the requirements of the WebXR spec, separate
// words/tokens are separated by "-" instead of whitespace and convert it to
// lowercase.
std::string FixupProfileString(const std::string& name) {
std::vector<std::string> tokens =
base::SplitString(name, base::kWhitespaceASCII, base::KEEP_WHITESPACE,
base::SPLIT_WANT_NONEMPTY);
std::string result = base::JoinString(tokens, "-");
return base::ToLowerASCII(result);
}

// Constants/functions only used by WebVR.
constexpr std::array<vr::EVRButtonId, 7> kWebVRButtonOrder = {
vr::k_EButton_A,
Expand Down Expand Up @@ -313,11 +326,46 @@ class OpenVRGamepadBuilder : public XRStandardGamepadBuilder {

// Finally, add any remaining axis buttons (triggers/josysticks/touchpads)
AddRemainingTriggersAndAxes();

// Find out the model and manufacturer names in case the caller wants this
// information for the input profiles array.
std::string model =
GetOpenVRString(vr_system, vr::Prop_ModelNumber_String, controller_id);
std::string manufacturer = GetOpenVRString(
vr_system, vr::Prop_ManufacturerName_String, controller_id);

UpdateProfiles(manufacturer, model);
}

~OpenVRGamepadBuilder() override = default;

std::vector<std::string> GetProfiles() const { return profiles_; }

private:
void UpdateProfiles(const std::string& manufacturer,
const std::string& model) {
// Per the WebXR spec, the first entry in the profiles array should be the
// most specific one.
std::string name =
FixupProfileString(manufacturer) + "-" + FixupProfileString(model);
profiles_.push_back(name);

// Also record information about what this controller actually does in a
// more general sense.
std::string capabilities = "";
if (HasSecondaryButton()) {
capabilities += "grip-";
}
if (HasTouchpad()) {
capabilities += "touchpad-";
}
if (HasThumbstick()) {
capabilities += "thumbstick-";
}
capabilities += "controller";
profiles_.push_back(capabilities);
}

base::Optional<GamepadBuilder::ButtonData> TryGetAxesOrTriggerButton(
vr::EVRButtonId button_id,
AxesRequirement requirement = AxesRequirement::kOptional) {
Expand Down Expand Up @@ -370,32 +418,6 @@ class OpenVRGamepadBuilder : public XRStandardGamepadBuilder {
}
}

static bool IsControllerHTCVive(vr::IVRSystem* vr_system,
uint32_t controller_id) {
std::string model =
GetOpenVRString(vr_system, vr::Prop_ModelNumber_String, controller_id);
std::string manufacturer = GetOpenVRString(
vr_system, vr::Prop_ManufacturerName_String, controller_id);

// OpenVR reports different model strings for developer vs released versions
// of Vive controllers. In the future, there could be additional iterations
// of the Vive controller that we also want to catch here. That's why we
// check if the model string contains "Vive" instead of doing an exact match
// against specific string(s).
return (manufacturer == "HTC") && (model.find("Vive") != std::string::npos);
}

// TODO(https://crbug.com/942201): Get correct ID string once WebXR spec issue
// #550 (https://github.com/immersive-web/webxr/issues/550) is resolved.
static std::string GetGamepadId(vr::IVRSystem* vr_system,
uint32_t controller_id) {
if (IsControllerHTCVive(vr_system, controller_id)) {
return "htc-vive";
}

return "openvr";
}

bool IsUsed(vr::EVRButtonId button_id) {
auto it = used_axes_.find(button_id);
return it != used_axes_.end();
Expand All @@ -410,18 +432,28 @@ class OpenVRGamepadBuilder : public XRStandardGamepadBuilder {
uint64_t supported_buttons_;
std::map<vr::EVRButtonId, GamepadBuilder::ButtonData> axes_data_;
std::unordered_set<vr::EVRButtonId> used_axes_;
std::vector<std::string> profiles_;

DISALLOW_COPY_AND_ASSIGN(OpenVRGamepadBuilder);
};

base::Optional<Gamepad> OpenVRGamepadHelper::GetXRGamepad(
OpenVRInputSourceData::OpenVRInputSourceData() = default;
OpenVRInputSourceData::~OpenVRInputSourceData() = default;
OpenVRInputSourceData::OpenVRInputSourceData(
const OpenVRInputSourceData& other) = default;

OpenVRInputSourceData OpenVRGamepadHelper::GetXRInputSourceData(
vr::IVRSystem* vr_system,
uint32_t controller_id,
vr::VRControllerState_t controller_state,
device::mojom::XRHandedness handedness) {
OpenVRGamepadBuilder builder(vr_system, controller_id, controller_state,
handedness);
return builder.GetGamepad();

OpenVRInputSourceData data;
data.gamepad = builder.GetGamepad();
data.profiles = builder.GetProfiles();
return data;
}

} // namespace device
14 changes: 13 additions & 1 deletion device/vr/openvr/openvr_gamepad_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,27 @@
#ifndef DEVICE_VR_OPENVR_OPENVR_GAMEPAD_HELPER_H_
#define DEVICE_VR_OPENVR_OPENVR_GAMEPAD_HELPER_H_

#include <string>
#include <utility>
#include <vector>

#include "device/vr/public/mojom/isolated_xr_service.mojom.h"
#include "third_party/openvr/src/headers/openvr.h"

namespace device {

struct OpenVRInputSourceData {
OpenVRInputSourceData();
~OpenVRInputSourceData();
OpenVRInputSourceData(const OpenVRInputSourceData& other);
base::Optional<Gamepad> gamepad;
std::vector<std::string> profiles;
};

class OpenVRGamepadHelper {
public:
static mojom::XRGamepadDataPtr GetGamepadData(vr::IVRSystem* system);
static base::Optional<Gamepad> GetXRGamepad(
static OpenVRInputSourceData GetXRInputSourceData(
vr::IVRSystem* system,
uint32_t controller_id,
vr::VRControllerState_t controller_state,
Expand Down
8 changes: 6 additions & 2 deletions device/vr/openvr/openvr_render_loop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,10 @@ std::vector<mojom::XRInputSourceStatePtr> OpenVRRenderLoop::GetInputState(
device::mojom::XRHandedness handedness =
ConvertToMojoHandedness(controller_role);

state->gamepad = OpenVRGamepadHelper::GetXRGamepad(
openvr_->GetSystem(), i, controller_state, handedness);
OpenVRInputSourceData input_source_data =
OpenVRGamepadHelper::GetXRInputSourceData(openvr_->GetSystem(), i,
controller_state, handedness);
state->gamepad = input_source_data.gamepad;

// If this is a newly active controller or if the handedness has changed
// since the last update, re-send the controller's description.
Expand All @@ -308,6 +310,8 @@ std::vector<mojom::XRInputSourceStatePtr> OpenVRRenderLoop::GetInputState(
desc->pointer_offset = gfx::Transform();
desc->pointer_offset->RotateAboutXAxis(kPointerErgoAngleDegrees);

desc->profiles = input_source_data.profiles;

state->description = std::move(desc);
}

Expand Down
4 changes: 4 additions & 0 deletions device/vr/util/xr_standard_gamepad_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ class XRStandardGamepadBuilder {

base::Optional<Gamepad> GetGamepad() const;

bool HasSecondaryButton() const { return !!secondary_button_; }
bool HasTouchpad() const { return !!touchpad_data_; }
bool HasThumbstick() const { return !!thumbstick_data_; }

private:
base::Optional<GamepadButton> primary_button_;
base::Optional<GamepadButton> secondary_button_;
Expand Down
17 changes: 16 additions & 1 deletion device/vr/windows_mixed_reality/mixed_reality_input_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,10 @@ uint32_t GetSourceId(const WMRInputSource* source) {

return id;
}

const unsigned short kSamsungVendorId = 1118;
const unsigned short kSamsungOdysseyProductId = 1629;

} // namespace

MixedRealityInputHelper::MixedRealityInputHelper(
Expand Down Expand Up @@ -556,8 +560,19 @@ ParsedInputState MixedRealityInputHelper::ParseWindowsSourceState(
description->target_ray_mode = device::mojom::XRTargetRayMode::POINTING;
description->handedness = WindowsToMojoHandedness(source->Handedness());

// If we know the particular headset/controller model, add this to the
// profiles array.
if (input_state.vendor_id == kSamsungVendorId &&
input_state.product_id == kSamsungOdysseyProductId) {
description->profiles.push_back("samsung-odyssey");
}

description->profiles.push_back("windows-mixed-reality");
description->profiles.push_back("touchpad-thumbstick-controller");

// This makes it clear that the controller actually has a grip button and
// touchpad and thumbstick input. Otherwise, it's ambiguous whether slots
// like the touchpad buttons + axes are hooked up vs just placeholders.
description->profiles.push_back("grip-touchpad-thumbstick-controller");

source_state->gamepad = GetWebXRGamepad(input_state);
} else {
Expand Down

0 comments on commit d7a5a93

Please sign in to comment.