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) { ...@@ -229,15 +229,21 @@ void IsolatedGamepadDataFetcher::GetGamepadData(bool devices_changed_hint) {
L"Oculus Remote"); L"Oculus Remote");
} }
} else if (this->source() == GAMEPAD_SOURCE_WIN_MR) { } else if (this->source() == GAMEPAD_SOURCE_WIN_MR) {
if (dest.hand == GamepadHand::kLeft) { // For compatibility with Edge and existing libraries, Win MR may plumb
swprintf(base::as_writable_wcstr(dest.id), Gamepad::kIdLengthCap, // an input_state and corresponding gamepad up via the Pose for the
L"Windows Mixed Reality (Left)"); // purposes of exposing the Gamepad ID that should be used.
} else if (dest.hand == GamepadHand::kRight) { // 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, swprintf(base::as_writable_wcstr(dest.id), Gamepad::kIdLengthCap,
L"Windows Mixed Reality (Right)"); id_gamepad.id);
} else { } else {
swprintf(base::as_writable_wcstr(dest.id), Gamepad::kIdLengthCap, 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 @@ ...@@ -13,6 +13,7 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include "base/strings/safe_sprintf.h"
#include "device/gamepad/public/cpp/gamepads.h" #include "device/gamepad/public/cpp/gamepads.h"
#include "device/vr/public/mojom/isolated_xr_service.mojom.h" #include "device/vr/public/mojom/isolated_xr_service.mojom.h"
#include "device/vr/util/gamepad_builder.h" #include "device/vr/util/gamepad_builder.h"
...@@ -179,17 +180,47 @@ mojom::XRGamepadPtr GetWebVRGamepad(ParsedInputState input_state) { ...@@ -179,17 +180,47 @@ mojom::XRGamepadPtr GetWebVRGamepad(ParsedInputState input_state) {
AddButton(gamepad, nullptr); // Nothing seems to trigger this button in Edge. AddButton(gamepad, nullptr); // Nothing seems to trigger this button in Edge.
AddButtonWithAxes(gamepad, input_state.button_data[ButtonName::kTouchpad]); AddButtonWithAxes(gamepad, input_state.button_data[ButtonName::kTouchpad]);
auto handedness = input_state.source_state->description->handedness;
gamepad->timestamp = base::TimeTicks::Now(); 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; 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) { if (input_state.gamepad_pose.not_null) {
gamepad->pose = ConvertToVRPose(input_state.gamepad_pose); gamepad->pose = ConvertToVRPose(input_state.gamepad_pose);
gamepad->can_provide_position = input_state.gamepad_pose.position.not_null; gamepad->can_provide_position = input_state.gamepad_pose.position.not_null;
gamepad->can_provide_orientation = gamepad->can_provide_orientation =
input_state.gamepad_pose.orientation.not_null; 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; return gamepad;
} }
...@@ -495,6 +526,12 @@ ParsedInputState MixedRealityInputHelper::LockedParseWindowsSourceState( ...@@ -495,6 +526,12 @@ ParsedInputState MixedRealityInputHelper::LockedParseWindowsSourceState(
input_state.gamepad_pose = gamepad_pose; 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 = base::Optional<gfx::Transform> grip_from_pointer =
......
...@@ -32,6 +32,8 @@ struct ParsedInputState { ...@@ -32,6 +32,8 @@ struct ParsedInputState {
mojom::XRInputSourceStatePtr source_state; mojom::XRInputSourceStatePtr source_state;
std::unordered_map<ButtonName, GamepadBuilder::ButtonData> button_data; std::unordered_map<ButtonName, GamepadBuilder::ButtonData> button_data;
GamepadPose gamepad_pose; GamepadPose gamepad_pose;
uint16_t vendor_id = 0;
uint16_t product_id = 0;
ParsedInputState(); ParsedInputState();
~ParsedInputState(); ~ParsedInputState();
ParsedInputState(ParsedInputState&& other); ParsedInputState(ParsedInputState&& other);
......
...@@ -6,6 +6,14 @@ ...@@ -6,6 +6,14 @@
namespace device { namespace device {
uint16_t MockWMRController::ProductId() {
return 0;
}
uint16_t MockWMRController::VendorId() {
return 0;
}
MockWMRInputSource::MockWMRInputSource(ControllerFrameData data, MockWMRInputSource::MockWMRInputSource(ControllerFrameData data,
unsigned int id) unsigned int id)
: data_(data), id_(id) {} : data_(data), id_(id) {}
...@@ -26,6 +34,10 @@ bool MockWMRInputSource::IsPointingSupported() const { ...@@ -26,6 +34,10 @@ bool MockWMRInputSource::IsPointingSupported() const {
return true; return true;
} }
std::unique_ptr<WMRController> MockWMRInputSource::Controller() const {
return std::make_unique<MockWMRController>();
}
ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceHandedness ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceHandedness
MockWMRInputSource::Handedness() const { MockWMRInputSource::Handedness() const {
switch (data_.role) { switch (data_.role) {
......
...@@ -8,6 +8,14 @@ ...@@ -8,6 +8,14 @@
#include "device/vr/windows_mixed_reality/wrappers/wmr_input_source.h" #include "device/vr/windows_mixed_reality/wrappers/wmr_input_source.h"
namespace device { namespace device {
class MockWMRController : public WMRController {
public:
MockWMRController() = default;
~MockWMRController() override = default;
uint16_t ProductId() override;
uint16_t VendorId() override;
};
class MockWMRInputSource : public WMRInputSource { class MockWMRInputSource : public WMRInputSource {
public: public:
...@@ -18,6 +26,7 @@ class MockWMRInputSource : public WMRInputSource { ...@@ -18,6 +26,7 @@ class MockWMRInputSource : public WMRInputSource {
ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceKind Kind() ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceKind Kind()
const override; const override;
bool IsPointingSupported() const override; bool IsPointingSupported() const override;
std::unique_ptr<WMRController> Controller() const override;
ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceHandedness ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceHandedness
Handedness() const override; Handedness() const override;
......
...@@ -17,11 +17,34 @@ using SourceHandedness = ...@@ -17,11 +17,34 @@ using SourceHandedness =
using SourceKind = using SourceKind =
ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceKind; ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceKind;
using ABI::Windows::UI::Input::Spatial::ISpatialInteractionController;
using ABI::Windows::UI::Input::Spatial::ISpatialInteractionSource; using ABI::Windows::UI::Input::Spatial::ISpatialInteractionSource;
using Microsoft::WRL::ComPtr; using Microsoft::WRL::ComPtr;
namespace device { 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* ABI::Windows::UI::Input::Spatial::ISpatialInteractionSource*
WMRInputSource::GetRawPtr() const { WMRInputSource::GetRawPtr() const {
// This should only ever be used by the real implementation, so by default // This should only ever be used by the real implementation, so by default
...@@ -65,6 +88,17 @@ bool WMRInputSourceImpl::IsPointingSupported() const { ...@@ -65,6 +88,17 @@ bool WMRInputSourceImpl::IsPointingSupported() const {
return val; 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 { SourceHandedness WMRInputSourceImpl::Handedness() const {
if (!source3_) if (!source3_)
return SourceHandedness::SpatialInteractionSourceHandedness_Unspecified; return SourceHandedness::SpatialInteractionSourceHandedness_Unspecified;
......
...@@ -8,8 +8,34 @@ ...@@ -8,8 +8,34 @@
#include <wrl.h> #include <wrl.h>
#include <cstdint> #include <cstdint>
#include <memory>
namespace device { 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 { class WMRInputSource {
public: public:
virtual ~WMRInputSource() = default; virtual ~WMRInputSource() = default;
...@@ -21,6 +47,7 @@ class WMRInputSource { ...@@ -21,6 +47,7 @@ class WMRInputSource {
// Uses ISpatialInteractionSource2. // Uses ISpatialInteractionSource2.
virtual bool IsPointingSupported() const = 0; virtual bool IsPointingSupported() const = 0;
virtual std::unique_ptr<WMRController> Controller() const = 0;
// Uses ISpatialInteractionSource3. // Uses ISpatialInteractionSource3.
virtual ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceHandedness virtual ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceHandedness
...@@ -45,6 +72,7 @@ class WMRInputSourceImpl : public WMRInputSource { ...@@ -45,6 +72,7 @@ class WMRInputSourceImpl : public WMRInputSource {
// Uses ISpatialInteractionSource2. // Uses ISpatialInteractionSource2.
bool IsPointingSupported() const override; bool IsPointingSupported() const override;
std::unique_ptr<WMRController> Controller() const override;
// Uses ISpatialInteractionSource3. // Uses ISpatialInteractionSource3.
ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceHandedness 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