mirror of
https://github.com/lubosz/overte.git
synced 2025-04-23 01:04:06 +02:00
hand controllers send touch events instead of mouse events to web entities
This gives a much better experience when scrolling web content.
This commit is contained in:
parent
ed7eaebea8
commit
6d768d8327
7 changed files with 150 additions and 14 deletions
|
@ -3553,6 +3553,47 @@ void Application::sendEntityMouseEvent(const QUuid& id, const QMouseEvent& mouse
|
|||
}
|
||||
}
|
||||
|
||||
void Application::sendEntityTouchUpdateEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint) {
|
||||
QTouchEvent::TouchPoint point;
|
||||
point.setId(fingerID);
|
||||
point.setState(Qt::TouchPointMoved);
|
||||
QList<QTouchEvent::TouchPoint> touchPoints;
|
||||
touchPoints.push_back(point);
|
||||
QTouchEvent touchEvent(QEvent::TouchUpdate, nullptr, Qt::NoModifier, Qt::TouchPointMoved, touchPoints);
|
||||
sendEntityTouchEvent(entityID, touchEvent, intersectionPoint);
|
||||
}
|
||||
|
||||
void Application::sendEntityTouchBeginEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint) {
|
||||
QTouchEvent::TouchPoint point;
|
||||
point.setId(fingerID);
|
||||
point.setState(Qt::TouchPointPressed);
|
||||
QList<QTouchEvent::TouchPoint> touchPoints;
|
||||
touchPoints.push_back(point);
|
||||
QTouchEvent touchEvent(QEvent::TouchBegin, nullptr, Qt::NoModifier, Qt::TouchPointPressed, touchPoints);
|
||||
sendEntityTouchEvent(entityID, touchEvent, intersectionPoint);
|
||||
}
|
||||
|
||||
void Application::sendEntityTouchEndEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint) {
|
||||
QTouchEvent::TouchPoint point;
|
||||
point.setId(fingerID);
|
||||
point.setState(Qt::TouchPointReleased);
|
||||
QList<QTouchEvent::TouchPoint> touchPoints;
|
||||
touchPoints.push_back(point);
|
||||
QTouchEvent touchEvent(QEvent::TouchEnd, nullptr, Qt::NoModifier, Qt::TouchPointReleased, touchPoints);
|
||||
sendEntityTouchEvent(entityID, touchEvent, intersectionPoint);
|
||||
}
|
||||
|
||||
void Application::sendEntityTouchEvent(const QUuid& id, const QTouchEvent& touchEvent, const glm::vec3& intersectionPoint) {
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
EntityItemID entityItemID(id);
|
||||
auto properties = entityScriptingInterface->getEntityProperties(entityItemID);
|
||||
if (EntityTypes::Web == properties.getType() && !properties.getLocked() && properties.getVisible()) {
|
||||
auto entity = entityScriptingInterface->getEntityTree()->findEntityByID(entityItemID);
|
||||
RenderableWebEntityItem* webEntity = dynamic_cast<RenderableWebEntityItem*>(entity.get());
|
||||
webEntity->handleTouchEvent(touchEvent, intersectionPoint);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::updateDialogs(float deltaTime) const {
|
||||
PerformanceTimer perfTimer("updateDialogs");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
|
|
|
@ -321,7 +321,12 @@ public slots:
|
|||
void sendEntityLeftMouseDownEvent(QUuid id, glm::vec3 intersectionPoint);
|
||||
void sendEntityLeftMouseUpEvent(QUuid id, glm::vec3 intersectionPoint);
|
||||
|
||||
void sendEntityTouchUpdateEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint);
|
||||
void sendEntityTouchBeginEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint);
|
||||
void sendEntityTouchEndEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint);
|
||||
|
||||
private:
|
||||
void sendEntityTouchEvent(const QUuid& id, const QTouchEvent& touchEvent, const glm::vec3& intersectionPoint);
|
||||
void sendEntityMouseEvent(const QUuid& id, const QMouseEvent& mouseEvent, const glm::vec3& intersectionPoint);
|
||||
|
||||
private slots:
|
||||
|
|
|
@ -473,3 +473,15 @@ void ReticleInterface::sendEntityLeftMouseDownEvent(QUuid id, glm::vec3 intersec
|
|||
void ReticleInterface::sendEntityLeftMouseUpEvent(QUuid id, glm::vec3 intersectionPoint) {
|
||||
QMetaObject::invokeMethod(qApp, "sendEntityLeftMouseUpEvent", Qt::QueuedConnection, Q_ARG(QUuid, id), Q_ARG(glm::vec3, intersectionPoint));
|
||||
}
|
||||
|
||||
void ReticleInterface::sendEntityTouchUpdateEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint) {
|
||||
QMetaObject::invokeMethod(qApp, "sendEntityTouchUpdateEvent", Qt::QueuedConnection, Q_ARG(QUuid, entityID), Q_ARG(int, fingerID), Q_ARG(glm::vec3, intersectionPoint));
|
||||
}
|
||||
|
||||
void ReticleInterface::sendEntityTouchBeginEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint) {
|
||||
QMetaObject::invokeMethod(qApp, "sendEntityTouchBeginEvent", Qt::QueuedConnection, Q_ARG(QUuid, entityID), Q_ARG(int, fingerID), Q_ARG(glm::vec3, intersectionPoint));
|
||||
}
|
||||
|
||||
void ReticleInterface::sendEntityTouchEndEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint) {
|
||||
QMetaObject::invokeMethod(qApp, "sendEntityTouchEndEvent", Qt::QueuedConnection, Q_ARG(QUuid, entityID), Q_ARG(int, fingerID), Q_ARG(glm::vec3, intersectionPoint));
|
||||
}
|
||||
|
|
|
@ -209,7 +209,10 @@ public:
|
|||
Q_INVOKABLE void sendEntityMouseMoveEvent(QUuid id, glm::vec3 intersectionPoint);
|
||||
Q_INVOKABLE void sendEntityLeftMouseDownEvent(QUuid id, glm::vec3 intersectionPoint);
|
||||
Q_INVOKABLE void sendEntityLeftMouseUpEvent(QUuid id, glm::vec3 intersectionPoint);
|
||||
// TODO: right mouse + double click
|
||||
|
||||
Q_INVOKABLE void sendEntityTouchUpdateEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint);
|
||||
Q_INVOKABLE void sendEntityTouchBeginEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint);
|
||||
Q_INVOKABLE void sendEntityTouchEndEvent(QUuid entityID, int fingerID, glm::vec3 intersectionPoint);
|
||||
|
||||
private:
|
||||
CompositorHelper* _compositor;
|
||||
|
|
|
@ -238,6 +238,38 @@ void RenderableWebEntityItem::handleMouseEvent(QMouseEvent event, glm::vec3 inte
|
|||
QCoreApplication::sendEvent(_webSurface->getWindow(), &mappedEvent);
|
||||
}
|
||||
|
||||
void RenderableWebEntityItem::handleTouchEvent(QTouchEvent event, glm::vec3 intersectionPoint) {
|
||||
// Ignore mouse interaction if we're locked
|
||||
if (getLocked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Map the intersection point to an actual offscreen pixel
|
||||
glm::vec3 point = intersectionPoint;
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
point -= getPosition();
|
||||
point = glm::inverse(getRotation()) * point;
|
||||
point /= dimensions;
|
||||
point += 0.5f;
|
||||
point.y = 1.0f - point.y;
|
||||
point *= dimensions * (METERS_TO_INCHES * DPI);
|
||||
|
||||
QList<QTouchEvent::TouchPoint> touchPoints = event.touchPoints();
|
||||
for (auto& touchPoint : touchPoints) {
|
||||
touchPoint.setPos(QPointF(point.x, point.y));
|
||||
touchPoint.setScreenPos(QPointF(point.x, point.y));
|
||||
}
|
||||
|
||||
// Forward the touch event.
|
||||
QTouchEvent mappedEvent(event.type(),
|
||||
event.device(),
|
||||
event.modifiers(),
|
||||
event.touchPointStates(),
|
||||
touchPoints);
|
||||
QCoreApplication::sendEvent(_webSurface->getWindow(), &mappedEvent);
|
||||
}
|
||||
|
||||
|
||||
void RenderableWebEntityItem::destroyWebSurface() {
|
||||
if (_webSurface) {
|
||||
--_currentWebCount;
|
||||
|
|
|
@ -34,6 +34,7 @@ public:
|
|||
QObject* getEventHandler();
|
||||
|
||||
void handleMouseEvent(QMouseEvent event, glm::vec3 intersectionPoint);
|
||||
void handleTouchEvent(QTouchEvent event, glm::vec3 intersectionPoint);
|
||||
|
||||
void update(const quint64& now) override;
|
||||
bool needsToCallUpdate() const override { return _webSurface != nullptr; }
|
||||
|
|
|
@ -192,6 +192,7 @@ CONTROLLER_STATE_MACHINE[STATE_OFF] = {
|
|||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_SEARCHING] = {
|
||||
name: "searching",
|
||||
enterMethod: "searchEnter",
|
||||
updateMethod: "search"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_DISTANCE_HOLDING] = {
|
||||
|
@ -220,6 +221,18 @@ CONTROLLER_STATE_MACHINE[STATE_FAR_TRIGGER] = {
|
|||
updateMethod: "farTrigger"
|
||||
};
|
||||
|
||||
function rayIntersectPlane(planePosition, planeNormal, rayStart, rayDirection) {
|
||||
var rayDirectionDotPlaneNormal = Vec3.dot(rayDirection, planeNormal);
|
||||
if (rayDirectionDotPlaneNormal > 0.00001 || rayDirectionDotPlaneNormal < -0.00001) {
|
||||
var rayStartDotPlaneNormal = Vec3.dot(Vec3.subtract(planePosition, rayStart), planeNormal);
|
||||
var distance = rayStartDotPlaneNormal / rayDirectionDotPlaneNormal;
|
||||
return {hit: true, distance: distance};
|
||||
} else {
|
||||
// ray is parallel to the plane
|
||||
return {hit: false, distance: 0};
|
||||
}
|
||||
}
|
||||
|
||||
function stateToName(state) {
|
||||
return CONTROLLER_STATE_MACHINE[state] ? CONTROLLER_STATE_MACHINE[state].name : "???";
|
||||
}
|
||||
|
@ -965,7 +978,7 @@ function MyController(hand) {
|
|||
} else if (potentialEquipHotspot && Vec3.distance(this.lastHapticPulseLocation, currentLocation) > HAPTIC_TEXTURE_DISTANCE) {
|
||||
Controller.triggerHapticPulse(HAPTIC_TEXTURE_STRENGTH, HAPTIC_TEXTURE_DURATION, this.hand);
|
||||
this.lastHapticPulseLocation = currentLocation;
|
||||
}
|
||||
}
|
||||
this.prevPotentialEquipHotspot = potentialEquipHotspot;
|
||||
};
|
||||
|
||||
|
@ -1243,6 +1256,10 @@ function MyController(hand) {
|
|||
}
|
||||
};
|
||||
|
||||
this.searchEnter = function() {
|
||||
this.capturedWebEntity = null;
|
||||
};
|
||||
|
||||
this.search = function(deltaTime, timestamp) {
|
||||
var _this = this;
|
||||
var name;
|
||||
|
@ -1266,26 +1283,51 @@ function MyController(hand) {
|
|||
entityPropertiesCache.addEntity(rayPickInfo.entityID);
|
||||
}
|
||||
|
||||
// if the line probe hits a non-grabbable web entity or a web entity that is grabbed by the other hand.
|
||||
// route simulated mouse events to that entity.
|
||||
if (rayPickInfo.entityID && entityPropertiesCache.getProps(rayPickInfo.entityID).type === "Web" &&
|
||||
(!this.entityIsGrabbable(rayPickInfo.entityID) || this.getOtherHandController().grabbedEntity == rayPickInfo.entityID)) {
|
||||
// route simulated touch events to a webEntity.
|
||||
if (this.capturedWebEntity ||
|
||||
(rayPickInfo.entityID && entityPropertiesCache.getProps(rayPickInfo.entityID).type === "Web" &&
|
||||
(!this.entityIsGrabbable(rayPickInfo.entityID) || this.getOtherHandController().grabbedEntity == rayPickInfo.entityID))) {
|
||||
|
||||
if (Reticle.keyboardFocusEntity != rayPickInfo.entityID) {
|
||||
Reticle.keyboardFocusEntity = rayPickInfo.entityID;
|
||||
var standardControllerValue = (hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||
var pose = Controller.getPoseValue(standardControllerValue);
|
||||
var worldHandPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position);
|
||||
var worldHandRotation = Quat.multiply(MyAvatar.orientation, pose.rotation);
|
||||
|
||||
var focusedEntity = this.capturedWebEntity || rayPickInfo.entityID;
|
||||
entityPropertiesCache.addEntity(focusedEntity);
|
||||
|
||||
var props = entityPropertiesCache.getProps(focusedEntity);
|
||||
var planePosition = props.position
|
||||
var planeNormal = Vec3.multiplyQbyV(props.rotation, {x: 0, y: 0, z: 1.0});
|
||||
var rayStart = worldHandPosition;
|
||||
var rayDirection = Quat.getUp(worldHandRotation);
|
||||
var intersectionInfo = rayIntersectPlane(planePosition, planeNormal, rayStart, rayDirection);
|
||||
|
||||
var intersectionPoint = planePosition;
|
||||
if (intersectionInfo.hit && intersectionInfo.distance > 0) {
|
||||
intersectionPoint = Vec3.sum(rayStart, Vec3.multiply(intersectionInfo.distance, rayDirection));
|
||||
} else {
|
||||
intersectionPoint = planePosition;
|
||||
}
|
||||
Reticle.sendEntityMouseMoveEvent(rayPickInfo.entityID, rayPickInfo.intersection);
|
||||
|
||||
if (Reticle.keyboardFocusEntity != focusedEntity) {
|
||||
Reticle.keyboardFocusEntity = focusedEntity;
|
||||
}
|
||||
|
||||
Reticle.sendEntityTouchUpdateEvent(focusedEntity, this.hand, intersectionPoint);
|
||||
|
||||
if (this.triggerSmoothedGrab() && !this.lastTriggerSmoothedGrab) {
|
||||
print("AJT: mouse down");
|
||||
Reticle.sendEntityLeftMouseDownEvent(rayPickInfo.entityID, rayPickInfo.intersection);
|
||||
Reticle.sendEntityTouchBeginEvent(focusedEntity, this.hand, intersectionPoint);
|
||||
this.capturedWebEntity = focusedEntity;
|
||||
}
|
||||
if (!this.triggerSmoothedGrab() && this.lastTriggerSmoothedGrab) {
|
||||
print("AJT: mouse up");
|
||||
Reticle.sendEntityLeftMouseUpEvent(rayPickInfo.entityID, rayPickInfo.intersection);
|
||||
Reticle.sendEntityTouchEndEvent(focusedEntity, this.hand, intersectionPoint);
|
||||
this.capturedWebEntity = null;
|
||||
}
|
||||
this.lastTriggerSmoothedGrab = this.triggerSmoothedGrab();
|
||||
|
||||
equipHotspotBuddy.updateHotspots([], timestamp);
|
||||
this.intersectionDistance = rayPickInfo.distance;
|
||||
this.intersectionDistance = intersectionInfo.distance;
|
||||
} else {
|
||||
|
||||
var candidateEntities = Entities.findEntities(handPosition, NEAR_GRAB_RADIUS);
|
||||
|
|
Loading…
Reference in a new issue