From b2dff8aa77f28c130efddc474f330d940b790752 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 19 Aug 2016 15:25:46 -0700 Subject: [PATCH] Easier to click buttons on web entities with shaky hand controllers There is an angular and time dead spot on webEntity for scrolling vs clicking. Currently, it's 150 ms and 3 degrees. See POINTER_PRESS_TO_MOVE_DELAY and POINTER_PRESS_TO_MOVE_DEADSPOT_ANGLE * Fix for warnings when clicking on window.open() links in WebEntity --- interface/resources/qml/controls/WebView.qml | 4 +- .../src/RenderableWebEntityItem.cpp | 2 + .../system/controllers/handControllerGrab.js | 60 +++++++++++++------ .../controllers/handControllerPointer.js | 2 +- 4 files changed, 49 insertions(+), 19 deletions(-) diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml index bba91c64f6..7285db22d2 100644 --- a/interface/resources/qml/controls/WebView.qml +++ b/interface/resources/qml/controls/WebView.qml @@ -55,9 +55,11 @@ WebEngineView { } onNewViewRequested:{ + if (desktop) { var component = Qt.createComponent("../Browser.qml"); var newWindow = component.createObject(desktop); - request.openIn(newWindow.webView) + request.openIn(newWindow.webView); + } } // This breaks the webchannel used for passing messages. Fixed in Qt 5.6 diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index bb3f508d9b..9221fec140 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -68,6 +69,7 @@ bool RenderableWebEntityItem::buildWebSurface(EntityTreeRenderer* renderer) { _webSurface->load("WebView.qml"); _webSurface->resume(); _webSurface->getRootItem()->setProperty("url", _sourceUrl); + _webSurface->getRootContext()->setContextProperty("desktop", QVariant()); _connection = QObject::connect(_webSurface, &OffscreenQmlSurface::textureUpdated, [&](GLuint textureId) { _texture = textureId; }); diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index ab1fe76a91..ac1c844cc9 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -234,6 +234,10 @@ CONTROLLER_STATE_MACHINE[STATE_ENTITY_TOUCHING] = { updateMethod: "entityTouching" }; +function angleBetween(a, b) { + return Math.acos(Vec3.dot(Vec3.normalize(a), Vec3.normalize(b))); +} + function projectOntoEntityXYPlane(entityID, worldPos) { var props = entityPropertiesCache.getProps(entityID); var invRot = Quat.inverse(props.rotation); @@ -1975,7 +1979,8 @@ function MyController(hand) { var handPosition = this.getHandPosition(); // the center of the equipped object being far from the hand isn't enough to auto-unequip -- we also // need to fail the findEntities test. - var nearPickedCandidateEntities = Entities.findEntities(handPosition, NEAR_GRAB_RADIUS); + var TEAR_AWAY_DISTANCE = 0.04; + var nearPickedCandidateEntities = Entities.findEntities(handPosition, NEAR_GRAB_RADIUS + TEAR_AWAY_DISTANCE); if (nearPickedCandidateEntities.indexOf(this.grabbedEntity) == -1) { // for whatever reason, the held/equipped entity has been pulled away. ungrab or unequip. print("handControllerGrab -- autoreleasing held or equipped item because it is far from hand." + @@ -2128,6 +2133,11 @@ function MyController(hand) { Entities.sendMousePressOnEntity(this.grabbedEntity, pointerEvent); Entities.sendClickDownOnEntity(this.grabbedEntity, pointerEvent); + + this.touchingEnterTimer = 0; + this.touchingEnterPointerEvent = pointerEvent; + this.touchingEnterPointerEvent.button = "None"; + this.deadspotExpired = false; } }; @@ -2135,27 +2145,37 @@ function MyController(hand) { // test for intersection between controller laser and web entity plane. var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, this.hand); if (intersectInfo) { - var pointerEvent = { - type: "Release", - id: this.hand + 1, // 0 is reserved for hardware mouse - pos2D: projectOntoEntityXYPlane(this.grabbedEntity, intersectInfo.point), - pos3D: intersectInfo.point, - normal: intersectInfo.normal, - direction: intersectInfo.searchRay.direction, - button: "Primary", - isPrimaryButton: true, - isSecondaryButton: false, - isTertiaryButton: false - }; + var pointerEvent; + if (this.deadspotExpired) { + pointerEvent = { + type: "Release", + id: this.hand + 1, // 0 is reserved for hardware mouse + pos2D: projectOntoEntityXYPlane(this.grabbedEntity, intersectInfo.point), + pos3D: intersectInfo.point, + normal: intersectInfo.normal, + direction: intersectInfo.searchRay.direction, + button: "Primary", + isPrimaryButton: false, + isSecondaryButton: false, + isTertiaryButton: false + }; + } else { + pointerEvent = this.touchingEnterPointerEvent; + pointerEvent.button = "Primary"; + pointerEvent.isPrimaryButton = false; + } Entities.sendMouseReleaseOnEntity(this.grabbedEntity, pointerEvent); Entities.sendClickReleaseOnEntity(this.grabbedEntity, pointerEvent); Entities.sendHoverLeaveEntity(this.grabbedEntity, pointerEvent); - this.focusedEntity = null; } + this.focusedEntity = null; }; - this.entityTouching = function() { + this.entityTouching = function(dt) { + + this.touchingEnterTimer += dt; + entityPropertiesCache.addEntity(this.grabbedEntity); if (!this.triggerSmoothedGrab()) { @@ -2184,8 +2204,14 @@ function MyController(hand) { isTertiaryButton: false }; - Entities.sendMouseMoveOnEntity(this.grabbedEntity, pointerEvent); - Entities.sendHoldingClickOnEntity(this.grabbedEntity, pointerEvent); + var POINTER_PRESS_TO_MOVE_DELAY = 0.15; // seconds + var POINTER_PRESS_TO_MOVE_DEADSPOT_ANGLE = 0.05; // radians ~ 3 degrees + if (this.deadspotExpired || this.touchingEnterTimer > POINTER_PRESS_TO_MOVE_DELAY || + angleBetween(pointerEvent.direction, this.touchingEnterPointerEvent.direction) > POINTER_PRESS_TO_MOVE_DEADSPOT_ANGLE) { + Entities.sendMouseMoveOnEntity(this.grabbedEntity, pointerEvent); + Entities.sendHoldingClickOnEntity(this.grabbedEntity, pointerEvent); + this.deadspotExpired = true; + } this.intersectionDistance = intersectInfo.distance; this.searchIndicatorOn(intersectInfo.searchRay); diff --git a/scripts/system/controllers/handControllerPointer.js b/scripts/system/controllers/handControllerPointer.js index 4d6e9d7f60..5888b53a27 100644 --- a/scripts/system/controllers/handControllerPointer.js +++ b/scripts/system/controllers/handControllerPointer.js @@ -121,7 +121,7 @@ function ignoreMouseActivity() { return true; } var pos = Reticle.position; - if (pos.x == -1 && pos.y == -1) { + if (!pos || (pos.x == -1 && pos.y == -1)) { return true; } // Only we know if we moved it, which is why this script has to replace depthReticle.js