From bc34007c0b73272b9fe01d4c2e906ec9d2fefb9f Mon Sep 17 00:00:00 2001
From: joni <johnfshaughnessy@gmail.com>
Date: Tue, 29 May 2018 14:26:12 -0700
Subject: [PATCH] Handle primary actions outside of cursor-controller.

---
 src/components/cursor-controller.js | 31 +++----------
 src/components/super-spawner.js     |  2 +-
 src/hub.html                        |  8 ++--
 src/hub.js                          | 67 +++++++++++++++++++--------
 src/utils/primary-action-handler.js | 72 +++++++++++++++++++++--------
 src/utils/touch-events-handler.js   |  2 +
 6 files changed, 115 insertions(+), 67 deletions(-)

diff --git a/src/components/cursor-controller.js b/src/components/cursor-controller.js
index 846c7a32d..d4a1cd9cc 100644
--- a/src/components/cursor-controller.js
+++ b/src/components/cursor-controller.js
@@ -15,11 +15,7 @@ AFRAME.registerComponent("cursor-controller", {
     maxDistance: { default: 3 },
     minDistance: { default: 0.5 },
     cursorColorHovered: { default: "#2F80ED" },
-    cursorColorUnhovered: { default: "#FFFFFF" },
-    primaryDown: { default: "action_primary_down" },
-    primaryUp: { default: "action_primary_up" },
-    grabEvent: { default: "action_grab" },
-    releaseEvent: { default: "action_release" }
+    cursorColorUnhovered: { default: "#FFFFFF" }
   },
 
   init: function() {
@@ -27,7 +23,6 @@ AFRAME.registerComponent("cursor-controller", {
     this.isMobile = AFRAME.utils.device.isMobile();
     this.hasPointingDevice = false;
     this.currentTargetType = TARGET_TYPE_NONE;
-    this.grabStarting = false;
     this.currentDistance = this.data.maxDistance;
     this.currentDistanceMod = 0;
     this.mousePos = new THREE.Vector2();
@@ -41,17 +36,11 @@ AFRAME.registerComponent("cursor-controller", {
 
     this.data.cursor.setAttribute("material", { color: this.data.cursorColorUnhovered });
 
-    window.APP.touchEventsHandler.registerPinchEmitter(this.el);
-    window.APP.touchEventsHandler.registerCursor(this);
-    window.APP.mouseEventsHandler.registerCursor(this);
-    window.APP.primaryActionHandler.registerCursor(this);
-
     this.startInteractionAndForceCursorUpdate = this.startInteractionAndForceCursorUpdate.bind(this);
     this.startInteraction = this.startInteraction.bind(this);
     this.moveCursor = this.moveCursor.bind(this);
     this.endInteraction = this.endInteraction.bind(this);
     this.handleMouseWheel = this.handleMouseWheel.bind(this);
-
     this._handleEnterVR = this._handleEnterVR.bind(this);
     this._handleExitVR = this._handleExitVR.bind(this);
     this._handleModelLoaded = this._handleModelLoaded.bind(this);
@@ -80,10 +69,6 @@ AFRAME.registerComponent("cursor-controller", {
     window.addEventListener("enter-vr", this._handleEnterVR);
     window.addEventListener("exit-vr", this._handleExitVR);
 
-    //    this.data.playerRig.addEventListener(this.data.primaryDown, this._handlePrimaryDown);
-    //    this.data.playerRig.addEventListener(this.data.primaryUp, this._handlePrimaryUp);
-    //this.data.playerRig.addEventListener(this.data.grabEvent, this._handlePrimaryDown);
-    //this.data.playerRig.addEventListener(this.data.releaseEvent, this._handlePrimaryUp);
     //this.data.playerRig.addEventListener("cardboardbuttondown", this._handlePrimaryDown);
     //this.data.playerRig.addEventListener("cardboardbuttonup", this._handlePrimaryUp);
     this.data.playerRig.addEventListener("model-loaded", this._handleModelLoaded);
@@ -96,12 +81,8 @@ AFRAME.registerComponent("cursor-controller", {
     window.removeEventListener("enter-vr", this._handleEnterVR);
     window.removeEventListener("exit-vr", this._handleExitVR);
 
-    //this.data.playerRig.removeEventListener(this.data.primaryDown, this._handlePrimaryDown);
-    //this.data.playerRig.removeEventListener(this.data.primaryUp, this._handlePrimaryUp);
-    //this.data.playerRig.removeEventListener(this.data.grabEvent, this._handlePrimaryDown);
-    //this.data.playerRig.removeEventListener(this.data.releaseEvent, this._handlePrimaryUp);
-    this.data.playerRig.removeEventListener("cardboardbuttondown", this._handlePrimaryDown);
-    this.data.playerRig.removeEventListener("cardboardbuttonup", this._handlePrimaryUp);
+    //this.data.playerRig.removeEventListener("cardboardbuttondown", this._handlePrimaryDown);
+    //this.data.playerRig.removeEventListener("cardboardbuttonup", this._handlePrimaryUp);
 
     this.data.playerRig.removeEventListener("model-loaded", this._handleModelLoaded);
 
@@ -119,7 +100,9 @@ AFRAME.registerComponent("cursor-controller", {
         this.currentTargetType = TARGET_TYPE_NONE;
       }
       this.wasPhysicalHandGrabbing = isPhysicalHandGrabbing;
-      if (isPhysicalHandGrabbing) return;
+      if (isPhysicalHandGrabbing) {
+        return;
+      }
     }
 
     //set raycaster origin/direction
@@ -223,7 +206,7 @@ AFRAME.registerComponent("cursor-controller", {
     raycasterComp.checkIntersections();
     const intersections = raycasterComp.intersections;
     if (intersections.length === 0 || intersections[0].distance >= this.data.maxDistance) {
-      return;
+      return false;
     }
     cursor.object3D.position.copy(intersections[0].point);
     // Cursor position must be synced to physics before constraint is created
diff --git a/src/components/super-spawner.js b/src/components/super-spawner.js
index 7bd554f5a..2d9ba8d78 100644
--- a/src/components/super-spawner.js
+++ b/src/components/super-spawner.js
@@ -5,7 +5,7 @@ AFRAME.registerComponent("super-spawner", {
     spawnPosition: { type: "vec3" },
     useCustomSpawnRotation: { default: false },
     spawnRotation: { type: "vec4" },
-    events: { default: ["cursor-grab", "action_grab"] },
+    events: { default: ["cursor-grab", "hand_grab"] },
     spawnCooldown: { default: 1 }
   },
 
diff --git a/src/hub.html b/src/hub.html
index 531b83871..b489c7945 100644
--- a/src/hub.html
+++ b/src/hub.html
@@ -184,9 +184,9 @@
                 super-hands="
                     colliderEvent: collisions; colliderEventProperty: els;
                     colliderEndEvent: collisions; colliderEndEventProperty: clearedEls;
-                    grabStartButtons: action_grab; grabEndButtons: action_release;
-                    stretchStartButtons: action_grab; stretchEndButtons: action_release;
-                    dragDropStartButtons: action_grab; dragDropEndButtons: action_release;"
+                    grabStartButtons: hand_grab; grabEndButtons: hand_release;
+                    stretchStartButtons: hand_grab; stretchEndButtons: hand_release;
+                    dragDropStartButtons: hand_grab; dragDropEndButtons: hand_release;"
                 collision-filter="collisionForces: false"
                 physics-collider
             ></a-mixin>
@@ -266,7 +266,7 @@
                     teleport-controls="
                     cameraRig: #player-rig;
                     teleportOrigin: #player-camera;
-                    button: cursor-teleport_;
+                    button: gaze-teleport_;
                     collisionEntities: [nav-mesh];
                     drawIncrementally: true;
                     incrementalDrawMs: 600;
diff --git a/src/hub.js b/src/hub.js
index d551d546d..23cfc97b1 100644
--- a/src/hub.js
+++ b/src/hub.js
@@ -126,8 +126,6 @@ import ConcurrentLoadDetector from "./utils/concurrent-load-detector.js";
 import TouchEventsHandler from "./utils/touch-events-handler.js";
 import { MouseEventsHandler, GearVRMouseEventsHandler } from "./utils/mouse-events-handler.js";
 import PrimaryActionHandler from "./utils/primary-action-handler.js";
-window.APP.touchEventsHandler = new TouchEventsHandler(); // TODO: Do not create TouchEventsHandler unless on mobile
-window.APP.mouseEventsHandler = new MouseEventsHandler();
 
 function qsTruthy(param) {
   const val = qs[param];
@@ -187,7 +185,6 @@ function mountUI(scene, props = {}) {
 
 const onReady = async () => {
   const scene = document.querySelector("a-scene");
-  window.APP.primaryActionHandler = new PrimaryActionHandler(scene);
   const hubChannel = new HubChannel(store);
 
   document.querySelector("canvas").classList.add("blurred");
@@ -240,25 +237,59 @@ const onReady = async () => {
 
     if (enterInVR) {
       scene.enterVR();
+      window.APP.primaryActionHandler = new PrimaryActionHandler(scene);
+
+      const cursorEl = document.querySelector("#cursor-controller");
+      if (cursorEl && cursorEl.components && cursorEl.components["cursor-controller"]) {
+        const cursor = cursorEl.components["cursor-controller"];
+        window.APP.primaryActionHandler.registerCursor(cursor);
+      } else {
+        const registerCursor = e => {
+          if (e.detail.name !== "cursor-controller") return;
+          const cursor = cursorEl.components["cursor-controller"];
+          window.APP.primaryActionHandler.registerCursor(cursor);
+        };
+        cursorEl.addEventListener("componentinitialized", registerCursor);
+      }
+    } else {
+      window.APP.touchEventsHandler = new TouchEventsHandler(); // TODO: Do not create TouchEventsHandler unless on mobile
+      window.APP.mouseEventsHandler = new MouseEventsHandler();
+
+      const camera = document.querySelector("#player-camera");
+      const registerCameraController = e => {
+        if (e.detail.name !== "camera-controller") return;
+        camera.removeEventListener("componentinitialized", registerCameraController);
+
+        window.APP.touchEventsHandler.registerCameraController(camera.components["camera-controller"]);
+        scene.components["look-on-mobile"].registerCameraController(camera.components["camera-controller"]);
+        scene.setAttribute("look-on-mobile", "enabled", true);
+
+        window.APP.mouseEventsHandler.registerCameraController(camera.components["camera-controller"]);
+        window.APP.mouseEventsHandler.setInverseMouseLook(qsTruthy("invertMouseLook"));
+      };
+      camera.addEventListener("componentinitialized", registerCameraController);
+      camera.setAttribute("camera-controller", "foo", "bar");
+
+      const cursorEl = document.querySelector("#cursor-controller");
+      if (cursorEl && cursorEl.components && cursorEl.components["cursor-controller"]) {
+        const cursor = cursorEl.components["cursor-controller"];
+        window.APP.touchEventsHandler.registerPinchEmitter(cursorEl);
+        window.APP.touchEventsHandler.registerCursor(cursor);
+        window.APP.mouseEventsHandler.registerCursor(cursor);
+      } else {
+        const registerCursor = e => {
+          if (e.detail.name !== "cursor-controller") return;
+          const cursor = cursorEl.components["cursor-controller"];
+          window.APP.touchEventsHandler.registerPinchEmitter(cursorEl);
+          window.APP.touchEventsHandler.registerCursor(cursor);
+          window.APP.mouseEventsHandler.registerCursor(cursor);
+        };
+        cursorEl.addEventListener("componentinitialized", registerCursor);
+      }
     }
 
     AFRAME.registerInputActions(inGameActions, "default");
 
-    const camera = document.querySelector("#player-camera");
-    const registerCameraController = e => {
-      if (e.detail.name !== "camera-controller") return;
-      camera.removeEventListener("componentinitialized", registerCameraController);
-
-      window.APP.touchEventsHandler.registerCameraController(camera.components["camera-controller"]);
-      scene.components["look-on-mobile"].registerCameraController(camera.components["camera-controller"]);
-      scene.setAttribute("look-on-mobile", "enabled", true);
-
-      window.APP.mouseEventsHandler.registerCameraController(camera.components["camera-controller"]);
-      window.APP.mouseEventsHandler.setInverseMouseLook(qsTruthy("invertMouseLook"));
-    };
-    camera.addEventListener("componentinitialized", registerCameraController);
-    camera.setAttribute("camera-controller", "foo", "bar");
-
     scene.setAttribute("networked-scene", {
       room: hubId,
       serverURL: process.env.JANUS_SERVER
diff --git a/src/utils/primary-action-handler.js b/src/utils/primary-action-handler.js
index 2c64d3117..aefb8a595 100644
--- a/src/utils/primary-action-handler.js
+++ b/src/utils/primary-action-handler.js
@@ -1,18 +1,16 @@
 export default class PrimaryActionHandler {
   constructor(scene) {
-    this.cursor = null;
-    this.handledByCursor = false;
-    this.handledByTeleport = false;
-
-    this.rightTeleporter = null;
-    this.leftTeleporter = null;
     this.scene = scene;
+    this.cursor = null;
+    this.isCursorInteracting = false;
 
     this.registerCursor = this.registerCursor.bind(this);
     this.isReady = this.isReady.bind(this);
     this.addEventListeners = this.addEventListeners.bind(this);
     this.onPrimaryDown = this.onPrimaryDown.bind(this);
     this.onPrimaryUp = this.onPrimaryUp.bind(this);
+    this.onGrab = this.onGrab.bind(this);
+    this.onRelease = this.onRelease.bind(this);
   }
 
   registerCursor(cursor) {
@@ -29,35 +27,69 @@ export default class PrimaryActionHandler {
   addEventListeners() {
     this.scene.addEventListener("action_primary_down", this.onPrimaryDown);
     this.scene.addEventListener("action_primary_up", this.onPrimaryUp);
+    this.scene.addEventListener("action_grab", this.onGrab);
+    this.scene.addEventListener("action_release", this.onRelease);
   }
 
-  onPrimaryDown(e) {
-    this.handledByCursor = this.cursor.startInteraction();
-    if (this.handledByCursor) return;
-    this.cursor.setCursorVisibility(false);
+  onGrab(e) {
+    if (e.target.id.match(this.cursor.data.handedness)) {
+      if (this.isCursorInteracting) {
+        return;
+      } else if (e.target.components["super-hands"].state.has("hover-start")) {
+        e.target.emit("hand_grab");
+        return;
+      } else {
+        this.isCursorInteracting = this.cursor.startInteraction();
+        return;
+      }
+    } else {
+      e.target.emit("hand_grab");
+      return;
+    }
+  }
 
-    // Do teleport things.
-    if (!e.target.components["teleport-controls"]) {
-      console.error("no teleport controls");
+  onRelease(e) {
+    if (e.target.id.match(this.cursor.data.handedness) && this.isCursorInteracting) {
+      this.isCursorInteracting = false;
+      this.cursor.endInteraction();
+    } else {
+      e.target.emit("hand_release");
     }
+  }
+
+  // "Primary" buttons interact with super hands, the cursor, and teleport controls
+  onPrimaryDown(e) {
+    if (e.target.id.match(this.cursor.data.handedness)) {
+      if (this.isCursorInteracting) {
+        return;
+      } else if (e.target.components["super-hands"].state.has("hover-start")) {
+        e.target.emit("hand_grab");
+        return;
+      } else {
+        this.isCursorInteracting = this.cursor.startInteraction();
+        if (this.isCursorInteracting) return;
+      }
+    }
+
+    this.cursor.setCursorVisibility(false);
     const button = e.target.components["teleport-controls"].data.button;
     e.target.emit(button + "down");
   }
 
   onPrimaryUp(e) {
-    if (this.handledByCursor) {
+    if (e.target.id.match(this.cursor.data.handedness) && this.isCursorInteracting) {
+      this.isCursorInteracting = false;
       this.cursor.endInteraction();
       return;
     }
 
-    // Do teleport things.
-    if (!e.target.components["teleport-controls"]) {
-      console.error("no teleport controls");
+    // TODO: Figure out if this event target is grabbing something, then decide whether to end the teleport or end the grab
+    if (e.target.components["super-hands"].state.has("grab-start")) {
+      e.target.emit("hand_release");
     }
-    const button = e.target.components["teleport-controls"].data.button;
-    e.target.emit(button + "up");
 
-    // Show cursor
     this.cursor.setCursorVisibility(true);
+    const button = e.target.components["teleport-controls"].data.button;
+    e.target.emit(button + "up");
   }
 }
diff --git a/src/utils/touch-events-handler.js b/src/utils/touch-events-handler.js
index 7f712ff51..24f58c5d8 100644
--- a/src/utils/touch-events-handler.js
+++ b/src/utils/touch-events-handler.js
@@ -64,6 +64,8 @@ export default class TouchEventsHandler {
   }
 
   handleTouchStart(e) {
+    console.log(e);
+    this.cursor.setCursorVisibility(false);
     Array.prototype.forEach.call(e.changedTouches, this.singleTouchStart);
   }
 
-- 
GitLab