Bug 1617023 - Part 1: Integrating Gamepad with XRInputSource. r=kip

Differential Revision: https://phabricator.services.mozilla.com/D67431

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Daosheng Mu 2020-04-07 22:55:41 +00:00
Родитель e2003e251b
Коммит 91ad9bdf58
7 изменённых файлов: 110 добавлений и 32 удалений

Просмотреть файл

@ -50,6 +50,27 @@ const uint32_t VR_GAMEPAD_IDX_OFFSET = 0x01 << 16;
NS_IMPL_ISUPPORTS(GamepadManager, nsIObserver)
/*static*/
uint32_t GamepadManager::GetGamepadIndexWithServiceType(
uint32_t aIndex, GamepadServiceType aServiceType) {
uint32_t newIndex = 0;
switch (aServiceType) {
case GamepadServiceType::Standard:
MOZ_ASSERT(aIndex <= VR_GAMEPAD_IDX_OFFSET);
newIndex = aIndex;
break;
case GamepadServiceType::VR:
newIndex = aIndex + VR_GAMEPAD_IDX_OFFSET;
break;
default:
MOZ_ASSERT(false);
break;
}
return newIndex;
}
GamepadManager::GamepadManager()
: mEnabled(false),
mNonstandardEventsEnabled(false),
@ -195,26 +216,6 @@ already_AddRefed<Gamepad> GamepadManager::GetGamepad(
return GetGamepad(GetGamepadIndexWithServiceType(aGamepadId, aServiceType));
}
uint32_t GamepadManager::GetGamepadIndexWithServiceType(
uint32_t aIndex, GamepadServiceType aServiceType) const {
uint32_t newIndex = 0;
switch (aServiceType) {
case GamepadServiceType::Standard:
MOZ_ASSERT(aIndex <= VR_GAMEPAD_IDX_OFFSET);
newIndex = aIndex;
break;
case GamepadServiceType::VR:
newIndex = aIndex + VR_GAMEPAD_IDX_OFFSET;
break;
default:
MOZ_ASSERT(false);
break;
}
return newIndex;
}
void GamepadManager::AddGamepad(uint32_t aIndex, const nsAString& aId,
GamepadMappingType aMapping, GamepadHand aHand,
GamepadServiceType aServiceType,

Просмотреть файл

@ -35,6 +35,11 @@ class GamepadManager final : public nsIObserver {
// Get the singleton service
static already_AddRefed<GamepadManager> GetService();
// Our gamepad index has VR_GAMEPAD_IDX_OFFSET while GamepadChannelType
// is from VRManager.
static uint32_t GetGamepadIndexWithServiceType(
uint32_t aIndex, GamepadServiceType aServiceType);
void BeginShutdown();
void StopMonitoring();
@ -139,10 +144,6 @@ class GamepadManager final : public nsIObserver {
// Indicate that a window has received data from a gamepad.
void SetWindowHasSeenGamepad(nsGlobalWindowInner* aWindow, uint32_t aIndex,
bool aHasSeen = true);
// Our gamepad index has VR_GAMEPAD_IDX_OFFSET while GamepadChannelType
// is from VRManager.
uint32_t GetGamepadIndexWithServiceType(
uint32_t aIndex, GamepadServiceType aServiceType) const;
// Gamepads connected to the system. Copies of these are handed out
// to each window.

Просмотреть файл

@ -8,6 +8,9 @@
#include "XRNativeOriginViewer.h"
#include "XRNativeOriginTracker.h"
#include "mozilla/dom/Gamepad.h"
#include "mozilla/dom/GamepadManager.h"
namespace mozilla {
namespace dom {
@ -102,7 +105,17 @@ nsTArray<nsString> GetInputSourceProfile(VRControllerType aType) {
return profile;
}
XRInputSource::XRInputSource(nsISupports* aParent) : mParent(aParent) {}
XRInputSource::XRInputSource(nsISupports* aParent)
: mParent(aParent),
mGamepad(nullptr),
mIndex(-1) {}
XRInputSource::~XRInputSource() {
mTargetRaySpace = nullptr;
mGripSpace = nullptr;
mGamepad = nullptr;
mozilla::DropJSObjects(this);
}
JSObject* XRInputSource::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
@ -130,8 +143,7 @@ void XRInputSource::GetProfiles(nsTArray<nsString>& aResult) {
}
Gamepad* XRInputSource::GetGamepad() {
// TODO (Bug 1617023): Implement Gamepad for XRInputSource.
return nullptr;
return mGamepad;
}
void XRInputSource::Setup(XRSession* aSession, uint32_t aIndex) {
@ -186,13 +198,51 @@ void XRInputSource::Setup(XRSession* aSession, uint32_t aIndex) {
}
mTargetRaySpace = new XRSpace(aSession->GetParentObject(), aSession, nativeOriginTargetRay);
mGripSpace = new XRSpace(aSession->GetParentObject(), aSession, nativeOriginGrip);
const uint32_t gamepadId = displayInfo.mDisplayID * kVRControllerMaxCount + aIndex;
const uint32_t hashKey = GamepadManager::GetGamepadIndexWithServiceType(gamepadId, GamepadServiceType::VR);
mGamepad = new Gamepad(mParent, NS_ConvertASCIItoUTF16(""), -1, hashKey, GamepadMappingType::Xr_standard,
controllerState.hand, displayInfo.mDisplayID, controllerState.numButtons, controllerState.numAxes,
controllerState.numHaptics, 0, 0);
mIndex = aIndex;
}
void XRInputSource::SetGamepadIsConnected(bool aConnected) {
mGamepad->SetConnected(aConnected);
}
void XRInputSource::Update(XRSession* aSession) {
MOZ_ASSERT(aSession && mIndex >= 0 && mGamepad);
gfx::VRDisplayClient* displayClient = aSession->GetDisplayClient();
if (!displayClient) {
MOZ_ASSERT(displayClient);
return;
}
const gfx::VRDisplayInfo& displayInfo = displayClient->GetDisplayInfo();
const gfx::VRControllerState& controllerState = displayInfo.mControllerState[mIndex];
MOZ_ASSERT(controllerState.controllerName[0] != '\0');
// Update button values.
nsTArray<RefPtr<GamepadButton>> buttons;
mGamepad->GetButtons(buttons);
for (uint32_t i = 0; i < controllerState.numButtons; ++i) {
const bool pressed = controllerState.buttonPressed & (1ULL << i);
const bool touched = controllerState.buttonTouched & (1ULL << i);
if (buttons[i]->Pressed() != pressed || buttons[i]->Touched() != touched ||
buttons[i]->Value() != controllerState.triggerValue[i]) {
mGamepad->SetButton(i, pressed, touched, controllerState.triggerValue[i]);
}
}
// Update axis values.
nsTArray<double> axes;
mGamepad->GetAxes(axes);
for (uint32_t i = 0; i < controllerState.numAxes; ++i) {
if (axes[i] != controllerState.axisValue[i]) {
mGamepad->SetAxis(i, controllerState.axisValue[i]);
}
}
}
}
int32_t XRInputSource::GetIndex() {

Просмотреть файл

@ -49,7 +49,7 @@ class XRInputSource final : public nsWrapperCache {
int32_t GetIndex();
protected:
virtual ~XRInputSource() = default;
virtual ~XRInputSource();
nsCOMPtr<nsISupports> mParent;
@ -60,6 +60,7 @@ class XRInputSource final : public nsWrapperCache {
RefPtr<XRSpace> mTargetRaySpace;
RefPtr<XRSpace> mGripSpace;
RefPtr<Gamepad> mGamepad;
int32_t mIndex;
};

Просмотреть файл

@ -50,16 +50,26 @@ void XRInputSourceArray::Update(XRSession* aSession) {
}
}
// Checking if it is added before.
if (!found) {
if (!found &&
(controllerState.numButtons > 0 || controllerState.numAxes > 0)) {
inputSource = new XRInputSource(mParent);
inputSource->Setup(aSession, i);
mInputSources.AppendElement(inputSource);
}
// If added, updating the current controller states.
inputSource->Update(aSession);
if (inputSource) {
inputSource->Update(aSession);
}
}
}
void XRInputSourceArray::Clear() {
for (auto& input: mInputSources) {
input->SetGamepadIsConnected(false);
}
mInputSources.Clear();
}
uint32_t XRInputSourceArray::Length() { return mInputSources.Length(); }
XRInputSource* XRInputSourceArray::IndexedGetter(uint32_t aIndex,

Просмотреть файл

@ -396,6 +396,9 @@ void XRSession::Shutdown() {
}
void XRSession::ExitPresentInternal() {
if (mInputSources) {
mInputSources->Clear();
}
if (mDisplayClient) {
mDisplayClient->SessionEnded(this);
}

Просмотреть файл

@ -15,6 +15,7 @@
#include "mozilla/dom/GamepadManager.h"
#include "mozilla/dom/Gamepad.h"
#include "mozilla/dom/XRSession.h"
#include "mozilla/dom/XRInputSourceArray.h"
#include "mozilla/Preferences.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/WebXRBinding.h"
@ -140,8 +141,19 @@ void VRDisplayClient::FireEvents() {
StartFrame();
}
// We only call FireGamepadEvents() in WebVR instead of WebXR
FireGamepadEvents();
// In WebXR spec, Gamepad instances returned by an XRInputSource's gamepad attribute
// MUST NOT be included in the array returned by navigator.getGamepads().
if (!StaticPrefs::dom_vr_webxr_enabled()) { // Checking mWebVR?
FireGamepadEvents();
} else {
// Update controller states into XRInputSourceArray.
for (auto& session : mSessions) {
dom::XRInputSourceArray* inputs = session->InputSources();
if (inputs) {
inputs->Update(session);
}
}
}
}
void VRDisplayClient::GamepadMappingForWebVR(