From 776dc767c2b6b5be8f6889a808691b6cf75a3c5f Mon Sep 17 00:00:00 2001
From: Kevin Lee <kevin@infinite-lee.com>
Date: Wed, 18 Jul 2018 18:59:21 -0700
Subject: [PATCH] activatable component and sticky behavior Added activatable
 component, which allows a button to cause secondary activations to occur
 while an object is grabbed. Also made the pen "sticky" so it stays attached
 to your hand when you grab it. It can then only be dropped by using the
 "primary" grab button (e.g. grip buttons). The triggers now are
 "secondary_action" buttons, which work like normal except in the case that
 you are holding a sticky object, in which case they will not cause the object
 to be dropped.

---
 src/components/tools/pen.js       | 12 +++++-----
 src/hub.html                      | 12 +++++-----
 src/input-mappings.js             |  8 +++----
 src/utils/action-event-handler.js | 37 ++++++++++++++++++++++++-------
 yarn.lock                         |  4 ++--
 5 files changed, 49 insertions(+), 24 deletions(-)

diff --git a/src/components/tools/pen.js b/src/components/tools/pen.js
index 9bd18ac7e..8abd375a0 100644
--- a/src/components/tools/pen.js
+++ b/src/components/tools/pen.js
@@ -53,7 +53,7 @@ AFRAME.registerComponent("pen", {
   },
 
   play() {
-    if (this.data.useMouse) {
+    if (this.data.useMouse && false) {
       document.addEventListener("mousedown", this.onMouseDown);
       document.addEventListener("mouseup", this.onMouseUp);
     }
@@ -61,8 +61,10 @@ AFRAME.registerComponent("pen", {
     // this.el.parentNode.addEventListener("index_down", this.startDraw);
     // this.el.parentNode.addEventListener("index_up", this.endDraw);
 
-    this.el.parentNode.addEventListener("drag-start", this.startDraw);
-    this.el.parentNode.addEventListener("drag-end", this.endDraw);
+    if (!this.data.useMouse) {
+      this.el.parentNode.addEventListener("activate-start", this.startDraw);
+      this.el.parentNode.addEventListener("activate-end", this.endDraw);
+    }
   },
 
   pause() {
@@ -72,8 +74,8 @@ AFRAME.registerComponent("pen", {
     this.el.parentNode.removeEventListener("index_down", this.startDraw);
     this.el.parentNode.removeEventListener("index_up", this.endDraw);
 
-    this.el.parentNode.removeEventListener("drag-start", this.startDraw);
-    this.el.parentNode.removeEventListener("drag-end", this.endDraw);
+    this.el.parentNode.removeEventListener("activate-start", this.startDraw);
+    this.el.parentNode.removeEventListener("activate-end", this.endDraw);
   },
 
   tick(t, dt) {
diff --git a/src/hub.html b/src/hub.html
index af24a06ce..7830dce38 100644
--- a/src/hub.html
+++ b/src/hub.html
@@ -220,12 +220,12 @@
              <template id="pen-interactable">
                 <a-entity
                     gltf-model-plus="src: #interactable-pen; inflate: true;"
-                    class="interactable"
+                    class="interactable sticky"
                     super-networked-interactable="counter: #counter; mass: 1;"
                     body="type: dynamic; shape: none; mass: 1;"
-                    grabbable
+                    grabbable="maxGrabbers: 1; maxGrabBehavior: drop;"
                     hoverable
-                    draggable
+                    activatable="buttonStartEvent: secondary_action_grab; buttonEndEvent: secondary_action_release;"
                     scale="0.5 0.5 0.5"
                 >
                     <a-sphere 
@@ -271,7 +271,8 @@
                          colliderEndEvent: collisions; colliderEndEventProperty: clearedEls;
                          grabStartButtons: hand_grab; grabEndButtons: hand_release;
                          stretchStartButtons: hand_grab; stretchEndButtons: hand_release;
-                         dragDropStartButtons: index_down; dragDropEndButtons: index_up;"
+                         dragDropStartButtons: hand_grab; dragDropEndButtons: hand_release;
+                         activateStartButtons: secondary_action_grab; activateEndButtons: secondary_action_release;"
                      collision-filter="collisionForces: false"
                      physics-collider
             ></a-mixin>
@@ -301,7 +302,8 @@
                 colliderEndEvent: raycaster-intersection-cleared; colliderEndEventProperty: clearedEls;
                 grabStartButtons: cursor-grab; grabEndButtons: cursor-release;
                 stretchStartButtons: cursor-grab; stretchEndButtons: cursor-release;
-                dragDropStartButtons: cursor-grab; dragDropEndButtons: cursor-release;"
+                dragDropStartButtons: cursor-grab; dragDropEndButtons: cursor-release;
+                activateStartButtons: TODO; activateEndButtons: TODO;"
             segments-height="9"
             segments-width="9"
             event-repeater="events: raycaster-intersection, raycaster-intersection-cleared; eventSource: #cursor-controller"
diff --git a/src/input-mappings.js b/src/input-mappings.js
index d1784c8d1..3bf06cc84 100644
--- a/src/input-mappings.js
+++ b/src/input-mappings.js
@@ -61,8 +61,8 @@ const config = {
         gripup: ["action_release", "middle_ring_pinky_up"],
         trackpadtouchstart: "thumb_down",
         trackpadtouchend: "thumb_up",
-        triggerdown: ["index_down"],
-        triggerup: ["index_up"],
+        triggerdown: ["secondary_action_grab", "index_down"],
+        triggerup: ["secondary_action_release", "index_up"],
         scroll: { right: "move_duck" }
       },
       "oculus-touch-controls": {
@@ -86,8 +86,8 @@ const config = {
         surfacetouchend: "thumb_up",
         thumbsticktouchstart: "thumb_down",
         thumbsticktouchend: "thumb_up",
-        triggerdown: ["action_grab", "index_down"],
-        triggerup: ["action_release", "index_up"],
+        triggerdown: ["secondary_action_grab", "index_down"],
+        triggerup: ["secondary_action_release", "index_up"],
         "axismove.reverseY": { left: "move", right: "move_duck" },
         abuttondown: "action_primary_down",
         abuttonup: "action_primary_up"
diff --git a/src/utils/action-event-handler.js b/src/utils/action-event-handler.js
index 6288c34e0..fcb9aa736 100644
--- a/src/utils/action-event-handler.js
+++ b/src/utils/action-event-handler.js
@@ -7,6 +7,7 @@ export default class ActionEventHandler {
     this.isTeleporting = false;
     this.handThatAlsoDrivesCursor = null;
     this.hovered = false;
+    this.currentlyGrabbingSticky = {};
 
     this.onPrimaryDown = this.onPrimaryDown.bind(this);
     this.onPrimaryUp = this.onPrimaryUp.bind(this);
@@ -23,6 +24,8 @@ export default class ActionEventHandler {
     this.scene.addEventListener("action_primary_up", this.onPrimaryUp);
     this.scene.addEventListener("action_grab", this.onGrab);
     this.scene.addEventListener("action_release", this.onRelease);
+    this.scene.addEventListener("secondary_action_grab", this.onGrab);
+    this.scene.addEventListener("secondary_action_release", this.onRelease);
     this.scene.addEventListener("move_duck", this.onMoveDuck);
     this.scene.addEventListener("cardboardbuttondown", this.onCardboardButtonDown); // TODO: These should be actions
     this.scene.addEventListener("cardboardbuttonup", this.onCardboardButtonUp);
@@ -33,6 +36,8 @@ export default class ActionEventHandler {
     this.scene.removeEventListener("action_primary_up", this.onPrimaryUp);
     this.scene.removeEventListener("action_grab", this.onGrab);
     this.scene.removeEventListener("action_release", this.onRelease);
+    this.scene.removeEventListener("secondary_action_grab", this.onGrab);
+    this.scene.removeEventListener("secondary_action_release", this.onRelease);
     this.scene.removeEventListener("move_duck", this.onMoveDuck);
     this.scene.removeEventListener("cardboardbuttondown", this.onCardboardButtonDown);
     this.scene.removeEventListener("cardboardbuttonup", this.onCardboardButtonUp);
@@ -46,27 +51,43 @@ export default class ActionEventHandler {
     this.handThatAlsoDrivesCursor = handThatAlsoDrivesCursor;
   }
 
+  isSticky(el) {
+    return el && el.classList.contains("sticky");
+  }
+
   onGrab(e) {
-    if (this.handThatAlsoDrivesCursor && this.handThatAlsoDrivesCursor === e.target) {
-      if (this.isCursorInteracting) {
-        return;
-      } else if (e.target.components["super-hands"].state.has("hover-start")) {
+    const superHand = e.target.components["super-hands"];
+    const grabbed = superHand.state.get("grab-start");
+    if (this.currentlyGrabbingSticky[e.target.id] && !grabbed) {
+      this.currentlyGrabbingSticky[e.target.id] = false;
+    }
+    const validGrab = !this.isSticky(grabbed) || !this.currentlyGrabbingSticky[e.target.id] || e.type == "action_grab";
+    if (this.handThatAlsoDrivesCursor && this.handThatAlsoDrivesCursor === e.target && !this.isCursorInteracting) {
+      if (superHand.state.has("hover-start") && validGrab) {
         e.target.emit("hand_grab");
-        return;
       } else {
         this.isCursorInteracting = this.cursor.startInteraction();
         if (this.isCursorInteracting) {
           this.isCursorInteractingOnGrab = true;
         }
-        return;
       }
-    } else {
+    } else if (validGrab) {
       e.target.emit("hand_grab");
-      return;
     }
   }
 
   onRelease(e) {
+    const grabbed = e.target.components["super-hands"].state.get("grab-start");
+    if (
+      (!this.currentlyGrabbingSticky[e.target.id] && this.isSticky(grabbed)) ||
+      (this.currentlyGrabbingSticky[e.target.id] && e.type != "action_release")
+    ) {
+      this.currentlyGrabbingSticky[e.target.id] = true;
+      return;
+    } else {
+      this.currentlyGrabbingSticky[e.target.id] = false;
+    }
+
     if (
       this.isCursorInteracting &&
       this.isCursorInteractingOnGrab &&
diff --git a/yarn.lock b/yarn.lock
index 0dc13a86a..e94fc5e45 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7859,8 +7859,8 @@ subarg@^1.0.0:
     minimist "^1.1.0"
 
 "super-hands@https://github.com/mozillareality/aframe-super-hands-component#hubs/master":
-  version "2.1.0"
-  resolved "https://github.com/mozillareality/aframe-super-hands-component#579024a260f8b9821cf1cbabd403055116bc2eb9"
+  version "3.0.0"
+  resolved "https://github.com/mozillareality/aframe-super-hands-component#2fc7697793005e187f343e59f98a33a5ed45c698"
 
 supports-color@1.3.1:
   version "1.3.1"
-- 
GitLab