Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  XRInputSource.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "mozilla/dom/XRInputSource.h"
#include "mozilla/dom/XRInputSourceEvent.h"
#include "XRNativeOriginViewer.h"
#include "XRNativeOriginTracker.h"
#include "XRInputSpace.h"
#include "VRDisplayClient.h"

#include "mozilla/dom/Gamepad.h"
#include "mozilla/dom/GamepadManager.h"

namespace mozilla::dom {

NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(XRInputSource, mParent, mTargetRaySpace,
                                      mGripSpace, mGamepad)

// Follow the controller profile ids from
// https://github.com/immersive-web/webxr-input-profiles.
nsTArray<nsString> GetInputSourceProfile(gfx::VRControllerType aType) {
  nsTArray<nsString> profile;
  nsString id;

  switch (aType) {
    case gfx::VRControllerType::HTCVive:
      id.AssignLiteral("htc-vive");
      profile.AppendElement(id);
      id.AssignLiteral("generic-trigger-squeeze-touchpad");
      profile.AppendElement(id);
      break;
    case gfx::VRControllerType::HTCViveCosmos:
      id.AssignLiteral("htc-vive-cosmos");
      profile.AppendElement(id);
      id.AssignLiteral("generic-trigger-squeeze-thumbstick");
      profile.AppendElement(id);
      break;
    case gfx::VRControllerType::HTCViveFocus:
      id.AssignLiteral("htc-vive-focus");
      profile.AppendElement(id);
      id.AssignLiteral("generic-trigger-touchpad");
      profile.AppendElement(id);
      break;
    case gfx::VRControllerType::HTCViveFocusPlus:
      id.AssignLiteral("htc-vive-focus-plus");
      profile.AppendElement(id);
      id.AssignLiteral("generic-trigger-squeeze-touchpad");
      profile.AppendElement(id);
      break;
    case gfx::VRControllerType::MSMR:
      id.AssignLiteral("microsoft-mixed-reality");
      profile.AppendElement(id);
      id.AssignLiteral("generic-trigger-squeeze-touchpad-thumbstick");
      profile.AppendElement(id);
      break;
    case gfx::VRControllerType::ValveIndex:
      id.AssignLiteral("valve-index");
      profile.AppendElement(id);
      id.AssignLiteral("generic-trigger-squeeze-touchpad-thumbstick");
      profile.AppendElement(id);
      break;
    case gfx::VRControllerType::OculusGo:
      id.AssignLiteral("oculus-go");
      profile.AppendElement(id);
      id.AssignLiteral("generic-trigger-touchpad");
      profile.AppendElement(id);
      break;
    case gfx::VRControllerType::OculusTouch:
      id.AssignLiteral("oculus-touch");
      profile.AppendElement(id);
      id.AssignLiteral("generic-trigger-squeeze-thumbstick");
      profile.AppendElement(id);
      break;
    case gfx::VRControllerType::OculusTouch2:
      id.AssignLiteral("oculus-touch-v2");
      profile.AppendElement(id);
      id.AssignLiteral("oculus-touch");
      profile.AppendElement(id);
      id.AssignLiteral("generic-trigger-squeeze-thumbstick");
      profile.AppendElement(id);
      break;
    case gfx::VRControllerType::OculusTouch3:
      id.AssignLiteral("oculus-touch-v3");
      profile.AppendElement(id);
      id.AssignLiteral("oculus-touch-v2");
      profile.AppendElement(id);
      id.AssignLiteral("oculus-touch");
      profile.AppendElement(id);
      id.AssignLiteral("generic-trigger-squeeze-thumbstick");
      profile.AppendElement(id);
      break;
    case gfx::VRControllerType::PicoGaze:
      id.AssignLiteral("pico-gaze");
      profile.AppendElement(id);
      id.AssignLiteral("generic-button");
      profile.AppendElement(id);
      break;
    case gfx::VRControllerType::PicoG2:
      id.AssignLiteral("pico-g2");
      profile.AppendElement(id);
      id.AssignLiteral("generic-trigger-touchpad");
      profile.AppendElement(id);
      break;
    case gfx::VRControllerType::PicoNeo2:
      id.AssignLiteral("pico-neo2");
      profile.AppendElement(id);
      id.AssignLiteral("generic-trigger-squeeze-thumbstick");
      profile.AppendElement(id);
      break;
    default:
      NS_WARNING("Unsupported XR input source profile.\n");
      break;
  }
  return profile;
}

XRInputSource::XRInputSource(nsISupports* aParent)
    : mParent(aParent),
      mGamepad(nullptr),
      mIndex(-1),
      mSelectAction(ActionState::ActionState_Released),
      mSqueezeAction(ActionState::ActionState_Released) {}

XRInputSource::~XRInputSource() {
  mTargetRaySpace = nullptr;
  mGripSpace = nullptr;
  mGamepad = nullptr;
}

JSObject* XRInputSource::WrapObject(JSContext* aCx,
                                    JS::Handle<JSObject*> aGivenProto) {
  return XRInputSource_Binding::Wrap(aCx, this, aGivenProto);
}

XRHandedness XRInputSource::Handedness() { return mHandedness; }

XRTargetRayMode XRInputSource::TargetRayMode() { return mTargetRayMode; }

XRSpace* XRInputSource::TargetRaySpace() { return mTargetRaySpace; }

XRSpace* XRInputSource::GetGripSpace() { return mGripSpace; }

void XRInputSource::GetProfiles(nsTArray<nsString>& aResult) {
  aResult = mProfiles.Clone();
}

Gamepad* XRInputSource::GetGamepad() { return mGamepad; }

void XRInputSource::Setup(XRSession* aSession, uint32_t aIndex) {
  MOZ_ASSERT(aSession);
  gfx::VRDisplayClient* displayClient = aSession->GetDisplayClient();
  if (!displayClient) {
    MOZ_ASSERT(displayClient);
    return;
  }
  const gfx::VRDisplayInfo& displayInfo = displayClient->GetDisplayInfo();
  const gfx::VRControllerState& controllerState =
      displayInfo.mControllerState[aIndex];
  MOZ_ASSERT(controllerState.controllerName[0] != '\0');

  mProfiles = GetInputSourceProfile(controllerState.type);
  mHandedness = XRHandedness::None;
  switch (controllerState.hand) {
    case GamepadHand::_empty:
      mHandedness = XRHandedness::None;
      break;
    case GamepadHand::Left:
      mHandedness = XRHandedness::Left;
      break;
    case GamepadHand::Right:
      mHandedness = XRHandedness::Right;
      break;
    default:
      MOZ_ASSERT(false && "Unknown GamepadHand type.");
      break;
  }

  RefPtr<XRNativeOrigin> nativeOriginTargetRay = nullptr;
  mTargetRayMode = XRTargetRayMode::Tracked_pointer;
  switch (controllerState.targetRayMode) {
    case gfx::TargetRayMode::Gaze:
      mTargetRayMode = XRTargetRayMode::Gaze;
      nativeOriginTargetRay = new XRNativeOriginViewer(displayClient);
      break;
    case gfx::TargetRayMode::TrackedPointer:
      mTargetRayMode = XRTargetRayMode::Tracked_pointer;
      // We use weak pointers of poses in XRNativeOriginTracker to sync their
      // data internally.
      nativeOriginTargetRay =
          new XRNativeOriginTracker(&controllerState.targetRayPose);
      break;
    case gfx::TargetRayMode::Screen:
      mTargetRayMode = XRTargetRayMode::Screen;
      break;
    default:
      MOZ_ASSERT(false && "Undefined TargetRayMode type.");
      break;
  }

  mTargetRaySpace = new XRInputSpace(aSession->GetParentObject(), aSession,
                                     nativeOriginTargetRay, aIndex);

  const uint32_t gamepadHandleValue =
      displayInfo.mDisplayID * gfx::kVRControllerMaxCount + aIndex;

  const GamepadHandle gamepadHandle{gamepadHandleValue, GamepadHandleKind::VR};

  mGamepad =
      new Gamepad(mParent, NS_ConvertASCIItoUTF16(""), -1, gamepadHandle,
                  GamepadMappingType::Xr_standard, controllerState.hand,
                  displayInfo.mDisplayID, controllerState.numButtons,
                  controllerState.numAxes, controllerState.numHaptics, 0, 0);
  mIndex = aIndex;

  if (!mGripSpace) {
    CreateGripSpace(aSession, controllerState);
  }
}

void XRInputSource::SetGamepadIsConnected(bool aConnected,
                                          XRSession* aSession) {
  mGamepad->SetConnected(aConnected);
  MOZ_ASSERT(aSession);

  if (!aConnected) {
    if (mSelectAction != ActionState::ActionState_Released) {
      DispatchEvent(u"selectend"_ns, aSession);
      mSelectAction = ActionState::ActionState_Released;
    }
    if (mSqueezeAction != ActionState::ActionState_Released) {
      DispatchEvent(u"squeezeend"_ns, aSession);
      mSqueezeAction = ActionState::ActionState_Released;
    }
  }
}

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');

  // OculusVR and OpenVR controllers need to wait until
  // update functions to assign GamepadCapabilityFlags::Cap_GripSpacePosition
  // flag.
  if (!mGripSpace) {
    CreateGripSpace(aSession, controllerState);
  }

  // Update button values.
  nsTArray<RefPtr<GamepadButton>> buttons;
  mGamepad->GetButtons(buttons);
  for (uint32_t i = 0; i < buttons.Length(); ++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 < axes.Length(); ++i) {
    if (axes[i] != controllerState.axisValue[i]) {
      mGamepad->SetAxis(i, controllerState.axisValue[i]);
    }
  }

  // We define 0.85f and 0.15f based on our current finding
  // for better experience, we can adjust these values if we need.
  const float completeThreshold = 0.90f;
  const float startThreshold = 0.85f;
  const float endThreshold = 0.15f;
  const uint32_t selectIndex = 0;
  const uint32_t squeezeIndex = 1;

  // Checking selectstart, select, selectend
  if (buttons.Length() > selectIndex) {
    if (controllerState.selectActionStartFrameId >
        controllerState.selectActionStopFrameId) {
      if (mSelectAction == ActionState::ActionState_Released &&
          controllerState.triggerValue[selectIndex] > endThreshold) {
        DispatchEvent(u"selectstart"_ns, aSession);
        mSelectAction = ActionState::ActionState_Pressing;
      } else if (mSelectAction == ActionState::ActionState_Pressing &&
                 controllerState.triggerValue[selectIndex] >
                     completeThreshold) {
        mSelectAction = ActionState::ActionState_Pressed;
      } else if (mSelectAction == ActionState::ActionState_Pressed &&
                 controllerState.triggerValue[selectIndex] < startThreshold) {
        DispatchEvent(u"select"_ns, aSession);
        mSelectAction = ActionState::ActionState_Releasing;
      } else if (mSelectAction <= ActionState::ActionState_Releasing &&
                 controllerState.triggerValue[selectIndex] < endThreshold) {
        // For a select btn which only has pressed and unpressed status.
        if (mSelectAction == ActionState::ActionState_Pressed) {
          DispatchEvent(u"select"_ns, aSession);
        }
        DispatchEvent(u"selectend"_ns, aSession);
        mSelectAction = ActionState::ActionState_Released;
      }
    } else if (mSelectAction <= ActionState::ActionState_Releasing) {
      // For a select btn which only has pressed and unpressed status.
      if (mSelectAction == ActionState::ActionState_Pressed) {
        DispatchEvent(u"select"_ns, aSession);
      }
      DispatchEvent(u"selectend"_ns, aSession);
      mSelectAction = ActionState::ActionState_Released;
    }
  }

  // Checking squeezestart, squeeze, squeezeend
  if (buttons.Length() > squeezeIndex) {
    if (controllerState.squeezeActionStartFrameId >
        controllerState.squeezeActionStopFrameId) {
      if (mSqueezeAction == ActionState::ActionState_Released &&
          controllerState.triggerValue[squeezeIndex] > endThreshold) {
        DispatchEvent(u"squeezestart"_ns, aSession);
        mSqueezeAction = ActionState::ActionState_Pressing;
      } else if (mSqueezeAction == ActionState::ActionState_Pressing &&
                 controllerState.triggerValue[squeezeIndex] >
                     completeThreshold) {
        mSqueezeAction = ActionState::ActionState_Pressed;
      } else if (mSqueezeAction == ActionState::ActionState_Pressed &&
                 controllerState.triggerValue[squeezeIndex] < startThreshold) {
        DispatchEvent(u"squeeze"_ns, aSession);
        mSqueezeAction = ActionState::ActionState_Releasing;
      } else if (mSqueezeAction <= ActionState::ActionState_Releasing &&
                 controllerState.triggerValue[squeezeIndex] < endThreshold) {
        // For a squeeze btn which only has pressed and unpressed status.
        if (mSqueezeAction == ActionState::ActionState_Pressed) {
          DispatchEvent(u"squeeze"_ns, aSession);
        }
        DispatchEvent(u"squeezeend"_ns, aSession);
        mSqueezeAction = ActionState::ActionState_Released;
      }
    } else if (mSqueezeAction <= ActionState::ActionState_Releasing) {
      // For a squeeze btn which only has pressed and unpressed status.
      if (mSqueezeAction == ActionState::ActionState_Pressed) {
        DispatchEvent(u"squeeze"_ns, aSession);
      }
      DispatchEvent(u"squeezeend"_ns, aSession);
      mSqueezeAction = ActionState::ActionState_Released;
    }
  }
}

int32_t XRInputSource::GetIndex() { return mIndex; }

void XRInputSource::DispatchEvent(const nsAString& aEvent,
                                  XRSession* aSession) {
  if (!GetParentObject() || !aSession) {
    return;
  }
  // Create a XRFrame for its callbacks
  RefPtr<XRFrame> frame = new XRFrame(GetParentObject(), aSession);
  frame->StartInputSourceEvent();

  XRInputSourceEventInit init;
  init.mBubbles = false;
  init.mCancelable = false;
  init.mFrame = frame;
  init.mInputSource = this;

  RefPtr<XRInputSourceEvent> event =
      XRInputSourceEvent::Constructor(aSession, aEvent, init);

  event->SetTrusted(true);
  aSession->DispatchEvent(*event);
  frame->EndInputSourceEvent();
}

void XRInputSource::CreateGripSpace(
    XRSession* aSession, const gfx::VRControllerState& controllerState) {
  MOZ_ASSERT(!mGripSpace);
  MOZ_ASSERT(aSession && mIndex >= 0 && mGamepad);
  if (mTargetRayMode == XRTargetRayMode::Tracked_pointer &&
      controllerState.flags & GamepadCapabilityFlags::Cap_GripSpacePosition) {
    RefPtr<XRNativeOrigin> nativeOriginGrip = nullptr;
    nativeOriginGrip = new XRNativeOriginTracker(&controllerState.pose);
    mGripSpace = new XRInputSpace(aSession->GetParentObject(), aSession,
                                  nativeOriginGrip, mIndex);
  } else {
    mGripSpace = nullptr;
  }
}

}  // namespace mozilla::dom

98%


¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge