isLeftHand, isRightHand, isMouse

This commit is contained in:
SamGondelman 2017-11-06 12:29:21 -08:00
parent 55ac585cd9
commit 7d420f5242
23 changed files with 176 additions and 127 deletions

View file

@ -64,11 +64,12 @@ Item {
keyItem.state = "mouseOver";
var globalPosition = keyItem.mapToGlobal(mouseArea1.mouseX, mouseArea1.mouseY);
var deviceId = Web3DOverlay.deviceIdByTouchPoint(globalPosition.x, globalPosition.y);
var hand = deviceId - 1; // based on touchEventUtils.js, deviceId is 'hand + 1', so 'hand' is 'deviceId' - 1
var pointerID = Web3DOverlay.deviceIdByTouchPoint(globalPosition.x, globalPosition.y);
if (hand == leftHand || hand == rightHand) {
Controller.triggerHapticPulse(_HAPTIC_STRENGTH, _HAPTIC_DURATION, hand);
if (Pointers.isLeftHand(pointerID)) {
Controller.triggerHapticPulse(_HAPTIC_STRENGTH, _HAPTIC_DURATION, leftHand);
} else if (Pointers.isRightHand(pointerID)) {
Controller.triggerHapticPulse(_HAPTIC_STRENGTH, _HAPTIC_DURATION, rightHand);
}
}

View file

@ -20,6 +20,9 @@ public:
const PickRay getMathematicalPick() const override;
bool isLeftHand() const override { return (_jointName == "_CONTROLLER_LEFTHAND") || (_jointName == "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"); }
bool isRightHand() const override { return (_jointName == "_CONTROLLER_RIGHTHAND") || (_jointName == "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND"); }
private:
std::string _jointName;
glm::vec3 _posOffset;

View file

@ -20,7 +20,7 @@ class LaserPointerScriptingInterface : public QObject, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY
public slots:
public:
Q_INVOKABLE unsigned int createLaserPointer(const QVariant& properties) const;
Q_INVOKABLE void enableLaserPointer(unsigned int uid) const { DependencyManager::get<PointerManager>()->enablePointer(uid); }
Q_INVOKABLE void disableLaserPointer(unsigned int uid) const { DependencyManager::get<PointerManager>()->disablePointer(uid); }
@ -36,6 +36,10 @@ public slots:
Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isOverlay) const { DependencyManager::get<PointerManager>()->setLockEndUUID(uid, objectID, isOverlay); }
Q_INVOKABLE bool isLeftHand(unsigned int uid) { return DependencyManager::get<PointerManager>()->isLeftHand(uid); }
Q_INVOKABLE bool isRightHand(unsigned int uid) { return DependencyManager::get<PointerManager>()->isRightHand(uid); }
Q_INVOKABLE bool isMouse(unsigned int uid) { return DependencyManager::get<PointerManager>()->isMouse(uid); }
};
#endif // hifi_LaserPointerScriptingInterface_h

View file

@ -19,6 +19,8 @@ public:
MouseRayPick(const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false);
const PickRay getMathematicalPick() const override;
bool isMouse() const override { return true; }
};
#endif // hifi_MouseRayPick_h

View file

@ -109,6 +109,18 @@ void PickScriptingInterface::setIncludeItems(unsigned int uid, const QScriptValu
DependencyManager::get<PickManager>()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems));
}
bool PickScriptingInterface::isLeftHand(unsigned int uid) {
return DependencyManager::get<PickManager>()->isLeftHand(uid);
}
bool PickScriptingInterface::isRightHand(unsigned int uid) {
return DependencyManager::get<PickManager>()->isRightHand(uid);
}
bool PickScriptingInterface::isMouse(unsigned int uid) {
return DependencyManager::get<PickManager>()->isMouse(uid);
}
QScriptValue pickTypesToScriptValue(QScriptEngine* engine, const PickQuery::PickType& pickType) {
return pickType;
}

View file

@ -37,7 +37,6 @@ public:
void registerMetaTypes(QScriptEngine* engine);
public slots:
Q_INVOKABLE unsigned int createPick(const PickQuery::PickType type, const QVariant& properties);
Q_INVOKABLE void enablePick(unsigned int uid);
Q_INVOKABLE void disablePick(unsigned int uid);
@ -48,6 +47,11 @@ public slots:
Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreEntities);
Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeEntities);
Q_INVOKABLE bool isLeftHand(unsigned int uid);
Q_INVOKABLE bool isRightHand(unsigned int uid);
Q_INVOKABLE bool isMouse(unsigned int uid);
public slots:
static constexpr unsigned int PICK_NOTHING() { return 0; }
static constexpr unsigned int PICK_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ENTITIES); }
static constexpr unsigned int PICK_OVERLAYS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_OVERLAYS); }

View file

@ -21,7 +21,6 @@ class PointerScriptingInterface : public QObject, public Dependency {
public:
unsigned int createLaserPointer(const QVariant& properties) const;
public slots:
Q_INVOKABLE unsigned int createPointer(const PickQuery::PickType& type, const QVariant& properties) const;
Q_INVOKABLE void enablePointer(unsigned int uid) const { DependencyManager::get<PointerManager>()->enablePointer(uid); }
Q_INVOKABLE void disablePointer(unsigned int uid) const { DependencyManager::get<PointerManager>()->disablePointer(uid); }
@ -37,6 +36,10 @@ public slots:
Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isOverlay) const { DependencyManager::get<PointerManager>()->setLockEndUUID(uid, objectID, isOverlay); }
Q_INVOKABLE bool isLeftHand(unsigned int uid) { return DependencyManager::get<PointerManager>()->isLeftHand(uid); }
Q_INVOKABLE bool isRightHand(unsigned int uid) { return DependencyManager::get<PointerManager>()->isRightHand(uid); }
Q_INVOKABLE bool isMouse(unsigned int uid) { return DependencyManager::get<PointerManager>()->isMouse(uid); }
signals:
void triggerBegin(const QUuid& id, const PointerEvent& pointerEvent);
void triggerContinue(const QUuid& id, const PointerEvent& pointerEvent);

View file

@ -51,3 +51,15 @@ void RayPickScriptingInterface::setIgnoreItems(uint32_t uid, const QScriptValue&
void RayPickScriptingInterface::setIncludeItems(uint32_t uid, const QScriptValue& includeItems) {
DependencyManager::get<PickManager>()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems));
}
bool RayPickScriptingInterface::isLeftHand(unsigned int uid) {
return DependencyManager::get<PickManager>()->isLeftHand(uid);
}
bool RayPickScriptingInterface::isRightHand(unsigned int uid) {
return DependencyManager::get<PickManager>()->isRightHand(uid);
}
bool RayPickScriptingInterface::isMouse(unsigned int uid) {
return DependencyManager::get<PickManager>()->isMouse(uid);
}

View file

@ -36,7 +36,7 @@ class RayPickScriptingInterface : public QObject, public Dependency {
Q_PROPERTY(unsigned int INTERSECTED_HUD READ INTERSECTED_HUD CONSTANT)
SINGLETON_DEPENDENCY
public slots:
public:
Q_INVOKABLE unsigned int createRayPick(const QVariant& properties);
Q_INVOKABLE void enableRayPick(unsigned int uid);
Q_INVOKABLE void disableRayPick(unsigned int uid);
@ -47,6 +47,11 @@ public slots:
Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreEntities);
Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeEntities);
Q_INVOKABLE bool isLeftHand(unsigned int uid);
Q_INVOKABLE bool isRightHand(unsigned int uid);
Q_INVOKABLE bool isMouse(unsigned int uid);
public slots:
static unsigned int PICK_NOTHING() { return PickScriptingInterface::PICK_NOTHING(); }
static unsigned int PICK_ENTITIES() { return PickScriptingInterface::PICK_ENTITIES(); }
static unsigned int PICK_OVERLAYS() { return PickScriptingInterface::PICK_OVERLAYS(); }

View file

@ -19,6 +19,8 @@
#include <QtNetwork/QNetworkReply>
#include <commerce/Ledger.h>
#include <pointers/PointerManager.h>
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
@ -79,8 +81,6 @@ ContextOverlayInterface::ContextOverlayInterface() {
_challengeOwnershipTimeoutTimer.setSingleShot(true);
}
static const uint32_t MOUSE_HW_ID = 0;
static const uint32_t LEFT_HAND_HW_ID = 1;
static const xColor CONTEXT_OVERLAY_COLOR = { 255, 255, 255 };
static const float CONTEXT_OVERLAY_INSIDE_DISTANCE = 1.0f; // in meters
static const float CONTEXT_OVERLAY_SIZE = 0.09f; // in meters, same x and y dims
@ -100,7 +100,7 @@ void ContextOverlayInterface::setEnabled(bool enabled) {
bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event) {
if (_enabled && event.getButton() == PointerEvent::SecondaryButton) {
if (contextOverlayFilterPassed(entityItemID)) {
if (event.getID() == MOUSE_HW_ID) {
if (event.getID() == PointerManager::MOUSE_POINTER_ID || DependencyManager::get<PointerManager>()->isMouse(event.getID())) {
enableEntityHighlight(entityItemID);
}
@ -151,7 +151,7 @@ bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID&
glm::vec3 normal;
boundingBox.findRayIntersection(cameraPosition, direction, distance, face, normal);
float offsetAngle = -CONTEXT_OVERLAY_OFFSET_ANGLE;
if (event.getID() == LEFT_HAND_HW_ID) {
if (DependencyManager::get<PointerManager>()->isLeftHand(event.getID())) {
offsetAngle *= -1.0f;
}
contextOverlayPosition = cameraPosition +
@ -253,13 +253,15 @@ void ContextOverlayInterface::contextOverlays_hoverLeaveOverlay(const OverlayID&
}
void ContextOverlayInterface::contextOverlays_hoverEnterEntity(const EntityItemID& entityID, const PointerEvent& event) {
if (contextOverlayFilterPassed(entityID) && _enabled && event.getID() != MOUSE_HW_ID) {
bool isMouse = event.getID() == PointerManager::MOUSE_POINTER_ID || DependencyManager::get<PointerManager>()->isMouse(event.getID());
if (contextOverlayFilterPassed(entityID) && _enabled && !isMouse) {
enableEntityHighlight(entityID);
}
}
void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemID& entityID, const PointerEvent& event) {
if (_currentEntityWithContextOverlay != entityID && _enabled && event.getID() != MOUSE_HW_ID) {
bool isMouse = event.getID() == PointerManager::MOUSE_POINTER_ID || DependencyManager::get<PointerManager>()->isMouse(event.getID());
if (_currentEntityWithContextOverlay != entityID && _enabled && !isMouse) {
disableEntityHighlight(entityID);
}
}

View file

@ -784,8 +784,6 @@ float Overlays::height() {
return offscreenUi->getWindow()->size().height();
}
static const uint32_t MOUSE_POINTER_ID = 0;
static glm::vec2 projectOntoOverlayXYPlane(glm::vec3 position, glm::quat rotation, glm::vec2 dimensions, const PickRay& pickRay,
const RayToOverlayIntersectionResult& rayPickResult) {
@ -846,7 +844,7 @@ PointerEvent Overlays::calculateOverlayPointerEvent(OverlayID overlayID, PickRay
glm::vec2 pos2D = projectOntoOverlayXYPlane(position, rotation, dimensions, ray, rayPickResult);
PointerEvent pointerEvent(eventType, MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal,
PointerEvent pointerEvent(eventType, PointerManager::MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal,
ray.direction, toPointerButton(*event), toPointerButtons(*event), event->modifiers());
return pointerEvent;

View file

@ -56,6 +56,8 @@
#include "ui/Snapshot.h"
#include "SoundCache.h"
#include "raypick/PointerScriptingInterface.h"
static const float DPI = 30.47f;
static const float INCHES_TO_METERS = 1.0f / 39.3701f;
static const float METERS_TO_INCHES = 39.3701f;
@ -216,6 +218,7 @@ void Web3DOverlay::setupQmlSurface() {
_webSurface->getSurfaceContext()->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
_webSurface->getSurfaceContext()->setContextProperty("Render", AbstractViewStateInterface::instance()->getRenderEngine()->getConfiguration().get());
_webSurface->getSurfaceContext()->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("Pointers", DependencyManager::get<PointerScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("Web3DOverlay", this);
_webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../");
@ -245,18 +248,12 @@ void Web3DOverlay::onResizeWebSurface() {
_webSurface->resize(QSize(_resolution.x, _resolution.y));
}
const int INVALID_DEVICE_ID = -1;
Q_INVOKABLE int Web3DOverlay::deviceIdByTouchPoint(qreal x, qreal y) {
auto mapped = _webSurface->getRootItem()->mapFromGlobal(QPoint(x, y));
for (auto pair : _activeTouchPoints) {
if (mapped.x() == (int)pair.second.pos().x() && mapped.y() == (int)pair.second.pos().y()) {
return pair.first;
}
unsigned int Web3DOverlay::deviceIdByTouchPoint(qreal x, qreal y) {
if (_webSurface) {
return _webSurface->deviceIdByTouchPoint(x, y);
} else {
return PointerEvent::INVALID_POINTER_ID;
}
return INVALID_DEVICE_ID;
}
void Web3DOverlay::render(RenderArgs* args) {
@ -341,13 +338,15 @@ void Web3DOverlay::setProxyWindow(QWindow* proxyWindow) {
}
void Web3DOverlay::hoverLeaveOverlay(const PointerEvent& event) {
if ((_pressed || (!_activeTouchPoints.empty() && _touchBeginAccepted)) && event.sendReleaseOnHoverLeave()) {
if (_inputMode == Mouse) {
PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(),
event.getButton(), event.getButtons(), event.getKeyboardModifiers());
handlePointerEvent(endEvent);
// QML onReleased is only triggered if a click has happened first. We need to send this "fake" mouse move event to properly trigger an onExited.
PointerEvent endMoveEvent(PointerEvent::Move, event.getID());
handlePointerEvent(endMoveEvent);
} else if (_webSurface) {
_webSurface->hoverEndEvent(event, _touchDevice);
}
}
@ -366,93 +365,11 @@ void Web3DOverlay::handlePointerEvent(const PointerEvent& event) {
}
void Web3DOverlay::handlePointerEventAsTouch(const PointerEvent& event) {
if (!_webSurface) {
return;
if (_webSurface) {
PointerEvent webEvent = event;
webEvent.setPos2D(event.getPos2D() * (METERS_TO_INCHES * _dpi));
_webSurface->handlePointerEvent(webEvent, _touchDevice);
}
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _dpi);
QPointF windowPoint(windowPos.x, windowPos.y);
Qt::TouchPointState state = Qt::TouchPointStationary;
if (event.getType() == PointerEvent::Press && event.getButton() == PointerEvent::PrimaryButton) {
state = Qt::TouchPointPressed;
} else if (event.getType() == PointerEvent::Release) {
state = Qt::TouchPointReleased;
} else if (_activeTouchPoints.count(event.getID()) && windowPoint != _activeTouchPoints[event.getID()].pos()) {
state = Qt::TouchPointMoved;
}
QEvent::Type touchType = QEvent::TouchUpdate;
if (_activeTouchPoints.empty()) {
// If the first active touch point is being created, send a begin
touchType = QEvent::TouchBegin;
} if (state == Qt::TouchPointReleased && _activeTouchPoints.size() == 1 && _activeTouchPoints.count(event.getID())) {
// If the last active touch point is being released, send an end
touchType = QEvent::TouchEnd;
}
{
QTouchEvent::TouchPoint point;
point.setId(event.getID());
point.setState(state);
point.setPos(windowPoint);
point.setScreenPos(windowPoint);
_activeTouchPoints[event.getID()] = point;
}
QTouchEvent touchEvent(touchType, &_touchDevice, event.getKeyboardModifiers());
{
QList<QTouchEvent::TouchPoint> touchPoints;
Qt::TouchPointStates touchPointStates;
for (const auto& entry : _activeTouchPoints) {
touchPointStates |= entry.second.state();
touchPoints.push_back(entry.second);
}
touchEvent.setWindow(_webSurface->getWindow());
touchEvent.setDevice(&_touchDevice);
touchEvent.setTarget(_webSurface->getRootItem());
touchEvent.setTouchPoints(touchPoints);
touchEvent.setTouchPointStates(touchPointStates);
}
// Send mouse events to the Web surface so that HTML dialog elements work with mouse press and hover.
//
// In Qt 5.9 mouse events must be sent before touch events to make sure some QtQuick components will
// receive mouse events
Qt::MouseButton button = Qt::NoButton;
Qt::MouseButtons buttons = Qt::NoButton;
if (event.getButton() == PointerEvent::PrimaryButton) {
button = Qt::LeftButton;
}
if (event.getButtons() & PointerEvent::PrimaryButton) {
buttons |= Qt::LeftButton;
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
if (event.getType() == PointerEvent::Move) {
QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers());
QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent);
}
#endif
if (touchType == QEvent::TouchBegin) {
_touchBeginAccepted = QCoreApplication::sendEvent(_webSurface->getWindow(), &touchEvent);
} else if (_touchBeginAccepted) {
QCoreApplication::sendEvent(_webSurface->getWindow(), &touchEvent);
}
// If this was a release event, remove the point from the active touch points
if (state == Qt::TouchPointReleased) {
_activeTouchPoints.erase(event.getID());
}
#if QT_VERSION < QT_VERSION_CHECK(5, 9, 0)
if (event.getType() == PointerEvent::Move) {
QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers());
QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent);
}
#endif
}
void Web3DOverlay::handlePointerEventAsMouse(const PointerEvent& event) {

View file

@ -67,7 +67,7 @@ public:
void destroyWebSurface();
void onResizeWebSurface();
Q_INVOKABLE int deviceIdByTouchPoint(qreal x, qreal y);
Q_INVOKABLE unsigned int deviceIdByTouchPoint(qreal x, qreal y);
public slots:
void emitScriptEvent(const QVariant& scriptMessage);
@ -98,8 +98,6 @@ private:
bool _showKeyboardFocusHighlight{ true };
bool _pressed{ false };
bool _touchBeginAccepted { false };
std::map<uint32_t, QTouchEvent::TouchPoint> _activeTouchPoints;
QTouchDevice _touchDevice;
uint8_t _desiredMaxFPS { 10 };

View file

@ -571,8 +571,6 @@ static PointerEvent::Button toPointerButton(const QMouseEvent& event) {
}
}
static const uint32_t MOUSE_POINTER_ID = 0;
void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) {
// If we don't have a tree, or we're in the process of shutting down, then don't
// process these events.
@ -593,7 +591,7 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) {
}
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Press, MOUSE_POINTER_ID,
PointerEvent pointerEvent(PointerEvent::Press, PointerManager::MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event),
@ -625,7 +623,7 @@ void EntityTreeRenderer::mouseDoublePressEvent(QMouseEvent* event) {
RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID);
if (rayPickResult.intersects && rayPickResult.entity) {
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Press, MOUSE_POINTER_ID,
PointerEvent pointerEvent(PointerEvent::Press, PointerManager::MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event), Qt::NoModifier);
@ -657,7 +655,7 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
//qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID;
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Release, MOUSE_POINTER_ID,
PointerEvent pointerEvent(PointerEvent::Release, PointerManager::MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event),
@ -673,7 +671,7 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
// we're releasing the button, then this is considered a clickReleaseOn event
if (!_currentClickingOnEntityID.isInvalidID()) {
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Release, MOUSE_POINTER_ID,
PointerEvent pointerEvent(PointerEvent::Release, PointerManager::MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event),
@ -699,7 +697,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID);
if (rayPickResult.intersects && rayPickResult.entity) {
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID,
PointerEvent pointerEvent(PointerEvent::Move, PointerManager::MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event),
@ -713,7 +711,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
// then we need to send the hover leave.
if (!_currentHoverOverEntityID.isInvalidID() && rayPickResult.entityID != _currentHoverOverEntityID) {
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID,
PointerEvent pointerEvent(PointerEvent::Move, PointerManager::MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event),
@ -744,7 +742,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
// send the hover leave for our previous entity
if (!_currentHoverOverEntityID.isInvalidID()) {
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID,
PointerEvent pointerEvent(PointerEvent::Move, PointerManager::MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event),

View file

@ -182,6 +182,10 @@ public:
void setIgnoreItems(const QVector<QUuid>& items);
void setIncludeItems(const QVector<QUuid>& items);
virtual bool isLeftHand() const { return false; }
virtual bool isRightHand() const { return false; }
virtual bool isMouse() const { return false; }
private:
PickFilter _filter;
const float _maxDistance;

View file

@ -96,4 +96,28 @@ void PickManager::update() {
bool shouldPickHUD = _shouldPickHUDOperator();
_rayPickCacheOptimizer.update(cachedPicks[PickQuery::Ray], shouldPickHUD);
}
bool PickManager::isLeftHand(unsigned int uid) {
auto pick = findPick(uid);
if (pick) {
return pick->isLeftHand();
}
return false;
}
bool PickManager::isRightHand(unsigned int uid) {
auto pick = findPick(uid);
if (pick) {
return pick->isRightHand();
}
return false;
}
bool PickManager::isMouse(unsigned int uid) {
auto pick = findPick(uid);
if (pick) {
return pick->isMouse();
}
return false;
}

View file

@ -33,6 +33,10 @@ public:
void setIgnoreItems(unsigned int uid, const QVector<QUuid>& ignore) const;
void setIncludeItems(unsigned int uid, const QVector<QUuid>& include) const;
bool isLeftHand(unsigned int uid);
bool isRightHand(unsigned int uid);
bool isMouse(unsigned int uid);
void setShouldPickHUDOperator(std::function<bool()> shouldPickHUDOperator) { _shouldPickHUDOperator = shouldPickHUDOperator; }
void setCalculatePos2DFromHUDOperator(std::function<glm::vec2(const glm::vec3&)> calculatePos2DFromHUDOperator) { _calculatePos2DFromHUDOperator = calculatePos2DFromHUDOperator; }
glm::vec2 calculatePos2DFromHUD(const glm::vec3& intersection) { return _calculatePos2DFromHUDOperator(intersection); }

View file

@ -46,6 +46,18 @@ void Pointer::setIncludeItems(const QVector<QUuid>& includeItems) const {
DependencyManager::get<PickManager>()->setIncludeItems(_pickUID, includeItems);
}
bool Pointer::isLeftHand() const {
return DependencyManager::get<PickManager>()->isLeftHand(_pickUID);
}
bool Pointer::isRightHand() const {
return DependencyManager::get<PickManager>()->isRightHand(_pickUID);
}
bool Pointer::isMouse() const {
return DependencyManager::get<PickManager>()->isMouse(_pickUID);
}
void Pointer::update(unsigned int pointerID) {
// This only needs to be a read lock because update won't change any of the properties that can be modified from scripts
withReadLock([&] {

View file

@ -53,6 +53,10 @@ public:
virtual void setIgnoreItems(const QVector<QUuid>& ignoreItems) const;
virtual void setIncludeItems(const QVector<QUuid>& includeItems) const;
bool isLeftHand() const;
bool isRightHand() const;
bool isMouse() const;
// Pointers can choose to implement these
virtual void setLength(float length) {}
virtual void setLockEndUUID(const QUuid& objectID, bool isOverlay) {}

View file

@ -120,3 +120,27 @@ void PointerManager::setLockEndUUID(unsigned int uid, const QUuid& objectID, boo
pointer->setLockEndUUID(objectID, isOverlay);
}
}
bool PointerManager::isLeftHand(unsigned int uid) {
auto pointer = find(uid);
if (pointer) {
return pointer->isLeftHand();
}
return false;
}
bool PointerManager::isRightHand(unsigned int uid) {
auto pointer = find(uid);
if (pointer) {
return pointer->isRightHand();
}
return false;
}
bool PointerManager::isMouse(unsigned int uid) {
auto pointer = find(uid);
if (pointer) {
return pointer->isMouse();
}
return false;
}

View file

@ -40,6 +40,10 @@ public:
void update();
bool isLeftHand(unsigned int uid);
bool isRightHand(unsigned int uid);
bool isMouse(unsigned int uid);
static const unsigned int MOUSE_POINTER_ID { PointerEvent::INVALID_POINTER_ID + 1 };
private:

View file

@ -927,6 +927,18 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even
return false;
}
unsigned int OffscreenQmlSurface::deviceIdByTouchPoint(qreal x, qreal y) {
auto mapped = _rootItem->mapFromGlobal(QPoint(x, y));
for (auto pair : _activeTouchPoints) {
if (mapped.x() == (int)pair.second.pos().x() && mapped.y() == (int)pair.second.pos().y()) {
return pair.first;
}
}
return PointerEvent::INVALID_POINTER_ID;
}
PointerEvent::EventType OffscreenQmlSurface::choosePointerEventType(QEvent::Type type) {
switch (type) {
case QEvent::MouseButtonDblClick:

View file

@ -100,6 +100,8 @@ public:
PointerEvent::EventType choosePointerEventType(QEvent::Type type);
unsigned int deviceIdByTouchPoint(qreal x, qreal y);
signals:
void focusObjectChanged(QObject* newFocus);
void focusTextChanged(bool focusText);