Commit 3d4ee7ac authored by Alex Cooper's avatar Alex Cooper Committed by Commit Bot

Rename Windows Mixed Reality Controllers for WebVR

This change switches the gamepad id of WMR controllers in chrome to
match the value reported in Edge, which is of the format:
Spatial Controller (Spatial Interaction Source) <vendor id>-<product id>

This ensures the greatest compatibility with existing libraries and
prevents fragmentation for developers.

In order to expose this, the vendor id/product id are queried from the
controller if available, and plumbed up through XRGamepad's VRPose
by way of creating a device::Gamepad attached to a dummy
XRInputSourceState.

WMRController is created as a separate class (rather than simply adding
Vendor/ProductId as properties on WMRInputSource), as that is also where
methods for controller haptics live, and it would need to be split out
at that time.

Bug: 957281
Change-Id: Ib17ebf0e274719c3d974800eb0c0deb96af321e5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1636562
Commit-Queue: Alexander Cooper <alcooper@chromium.org>
Reviewed-by: default avatarBill Orr <billorr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#664908}
parent 0aa87c0b
......@@ -229,15 +229,21 @@ void IsolatedGamepadDataFetcher::GetGamepadData(bool devices_changed_hint) {
L"Oculus Remote");
}
} else if (this->source() == GAMEPAD_SOURCE_WIN_MR) {
if (dest.hand == GamepadHand::kLeft) {
swprintf(base::as_writable_wcstr(dest.id), Gamepad::kIdLengthCap,
L"Windows Mixed Reality (Left)");
} else if (dest.hand == GamepadHand::kRight) {
// For compatibility with Edge and existing libraries, Win MR may plumb
// an input_state and corresponding gamepad up via the Pose for the
// purposes of exposing the Gamepad ID that should be used.
// If it is present, use that, otherwise, just use the same prefix as
// Edge uses.
if (source->pose && source->pose->input_state &&
source->pose->input_state.value().size() > 0 &&
source->pose->input_state.value()[0]->gamepad) {
Gamepad id_gamepad =
source->pose->input_state.value()[0]->gamepad.value();
swprintf(base::as_writable_wcstr(dest.id), Gamepad::kIdLengthCap,
L"Windows Mixed Reality (Right)");
id_gamepad.id);
} else {
swprintf(base::as_writable_wcstr(dest.id), Gamepad::kIdLengthCap,
L"Windows Mixed Reality");
L"Spatial Controller (Spatial Interaction Source) 0000-0000");
}
}
......
......@@ -13,6 +13,7 @@
#include <unordered_map>
#include <vector>
#include "base/strings/safe_sprintf.h"
#include "device/gamepad/public/cpp/gamepads.h"
#include "device/vr/public/mojom/isolated_xr_service.mojom.h"
#include "device/vr/util/gamepad_builder.h"
......@@ -179,17 +180,47 @@ mojom::XRGamepadPtr GetWebVRGamepad(ParsedInputState input_state) {
AddButton(gamepad, nullptr); // Nothing seems to trigger this button in Edge.
AddButtonWithAxes(gamepad, input_state.button_data[ButtonName::kTouchpad]);
auto handedness = input_state.source_state->description->handedness;
gamepad->timestamp = base::TimeTicks::Now();
gamepad->hand = input_state.source_state->description->handedness;
gamepad->hand = handedness;
gamepad->controller_id = input_state.source_state->source_id;
// We need to ensure that we have a VRPose so that we can attach input_states
// and therefore a gamepad to plumb up the Gamepad Id with VendorId/ProductId.
if (input_state.gamepad_pose.not_null) {
gamepad->pose = ConvertToVRPose(input_state.gamepad_pose);
gamepad->can_provide_position = input_state.gamepad_pose.position.not_null;
gamepad->can_provide_orientation =
input_state.gamepad_pose.orientation.not_null;
} else {
gamepad->can_provide_orientation = false;
gamepad->can_provide_position = false;
gamepad->pose = mojom::VRPose::New();
}
// Build the gamepad id, this prefix is used for all controller types and
// VendorId-ProductId is appended after it, padded with leading 0's.
char gamepad_id[Gamepad::kIdLengthCap];
base::strings::SafeSPrintf(
gamepad_id, "Spatial Controller (Spatial Interaction Source) %04X-%04X",
input_state.vendor_id, input_state.product_id);
// We have to use the GamepadBuilder because the mojom serialization complains
// if some of the values are missing/invalid.
GamepadBuilder builder(gamepad_id, GamepadBuilder::GamepadMapping::kNone,
handedness);
auto input_source_state = mojom::XRInputSourceState::New();
input_source_state->gamepad = builder.GetGamepad();
// Typical chromium style would be to use the initializer list, but that
// doesn't seem to be compatible with the explicitly deleted move/copy
// constructors for the vector.
std::vector<mojom::XRInputSourceStatePtr> input_source_vector;
input_source_vector.push_back(std::move(input_source_state));
gamepad->pose->input_state = std::move(input_source_vector);
return gamepad;
}
......@@ -495,6 +526,12 @@ ParsedInputState MixedRealityInputHelper::LockedParseWindowsSourceState(
input_state.gamepad_pose = gamepad_pose;
}
std::unique_ptr<WMRController> controller = source->Controller();
if (controller) {
input_state.product_id = controller->ProductId();
input_state.vendor_id = controller->VendorId();
}
}
base::Optional<gfx::Transform> grip_from_pointer =
......
......@@ -32,6 +32,8 @@ struct ParsedInputState {
mojom::XRInputSourceStatePtr source_state;
std::unordered_map<ButtonName, GamepadBuilder::ButtonData> button_data;
GamepadPose gamepad_pose;
uint16_t vendor_id = 0;
uint16_t product_id = 0;
ParsedInputState();
~ParsedInputState();
ParsedInputState(ParsedInputState&& other);
......
......@@ -6,6 +6,14 @@
namespace device {
uint16_t MockWMRController::ProductId() {
return 0;
}
uint16_t MockWMRController::VendorId() {
return 0;
}
MockWMRInputSource::MockWMRInputSource(ControllerFrameData data,
unsigned int id)
: data_(data), id_(id) {}
......@@ -26,6 +34,10 @@ bool MockWMRInputSource::IsPointingSupported() const {
return true;
}
std::unique_ptr<WMRController> MockWMRInputSource::Controller() const {
return std::make_unique<MockWMRController>();
}
ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceHandedness
MockWMRInputSource::Handedness() const {
switch (data_.role) {
......
......@@ -8,6 +8,14 @@
#include "device/vr/windows_mixed_reality/wrappers/wmr_input_source.h"
namespace device {
class MockWMRController : public WMRController {
public:
MockWMRController() = default;
~MockWMRController() override = default;
uint16_t ProductId() override;
uint16_t VendorId() override;
};
class MockWMRInputSource : public WMRInputSource {
public:
......@@ -18,6 +26,7 @@ class MockWMRInputSource : public WMRInputSource {
ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceKind Kind()
const override;
bool IsPointingSupported() const override;
std::unique_ptr<WMRController> Controller() const override;
ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceHandedness
Handedness() const override;
......
......@@ -17,11 +17,34 @@ using SourceHandedness =
using SourceKind =
ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceKind;
using ABI::Windows::UI::Input::Spatial::ISpatialInteractionController;
using ABI::Windows::UI::Input::Spatial::ISpatialInteractionSource;
using Microsoft::WRL::ComPtr;
namespace device {
WMRControllerImpl::WMRControllerImpl(
ComPtr<ISpatialInteractionController> controller)
: controller_(controller) {
DCHECK(controller_);
}
WMRControllerImpl::~WMRControllerImpl() = default;
uint16_t WMRControllerImpl::ProductId() {
uint16_t id = 0;
HRESULT hr = controller_->get_ProductId(&id);
DCHECK(SUCCEEDED(hr));
return id;
}
uint16_t WMRControllerImpl::VendorId() {
uint16_t id = 0;
HRESULT hr = controller_->get_VendorId(&id);
DCHECK(SUCCEEDED(hr));
return id;
}
ABI::Windows::UI::Input::Spatial::ISpatialInteractionSource*
WMRInputSource::GetRawPtr() const {
// This should only ever be used by the real implementation, so by default
......@@ -65,6 +88,17 @@ bool WMRInputSourceImpl::IsPointingSupported() const {
return val;
}
std::unique_ptr<WMRController> WMRInputSourceImpl::Controller() const {
if (!source2_)
return nullptr;
ComPtr<ISpatialInteractionController> controller;
HRESULT hr = source2_->get_Controller(&controller);
if (SUCCEEDED(hr))
return std::make_unique<WMRControllerImpl>(controller);
return nullptr;
}
SourceHandedness WMRInputSourceImpl::Handedness() const {
if (!source3_)
return SourceHandedness::SpatialInteractionSourceHandedness_Unspecified;
......
......@@ -8,8 +8,34 @@
#include <wrl.h>
#include <cstdint>
#include <memory>
namespace device {
class WMRController {
public:
virtual ~WMRController() = default;
virtual uint16_t ProductId() = 0;
virtual uint16_t VendorId() = 0;
};
class WMRControllerImpl : public WMRController {
public:
explicit WMRControllerImpl(
Microsoft::WRL::ComPtr<
ABI::Windows::UI::Input::Spatial::ISpatialInteractionController>
controller);
~WMRControllerImpl() override;
uint16_t ProductId() override;
uint16_t VendorId() override;
private:
Microsoft::WRL::ComPtr<
ABI::Windows::UI::Input::Spatial::ISpatialInteractionController>
controller_;
};
class WMRInputSource {
public:
virtual ~WMRInputSource() = default;
......@@ -21,6 +47,7 @@ class WMRInputSource {
// Uses ISpatialInteractionSource2.
virtual bool IsPointingSupported() const = 0;
virtual std::unique_ptr<WMRController> Controller() const = 0;
// Uses ISpatialInteractionSource3.
virtual ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceHandedness
......@@ -45,6 +72,7 @@ class WMRInputSourceImpl : public WMRInputSource {
// Uses ISpatialInteractionSource2.
bool IsPointingSupported() const override;
std::unique_ptr<WMRController> Controller() const override;
// Uses ISpatialInteractionSource3.
ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceHandedness
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment