Use event-queue heuristics to detect and ignore mouse events caused by touch events.
authorMichael Jumper <zhangmaike@users.sourceforge.net>
Mon, 30 Jul 2012 00:13:33 +0000 (17:13 -0700)
committerMichael Jumper <zhangmaike@users.sourceforge.net>
Mon, 30 Jul 2012 00:13:33 +0000 (17:13 -0700)
src/main/resources/mouse.js

index 96a18bb..bf2c6d5 100644 (file)
@@ -94,6 +94,39 @@ Guacamole.Mouse = function(element) {
      */
        this.onmousemove = null;
 
+    /**
+     * Zero-delay timeout set when mouse events are fired, and canceled when
+     * touch events are detected, in order to prevent touch events registering
+     * as mouse events (some browsers will do this).
+     */
+    var deferred_mouse_event = null;
+
+    /**
+     * Flag which, when set to true, will cause all mouse events to be
+     * ignored. Used to temporarily ignore events when generated by
+     * touch events, and not by a mouse.
+     */
+    var ignore_mouse = false;
+
+    /**
+     * Forces all mouse events to be ignored until the event queue is flushed.
+     */
+    function ignorePendingMouseEvents() {
+
+        // Cancel deferred event
+        if (deferred_mouse_event) {
+            window.clearTimeout(deferred_mouse_event);
+            deferred_mouse_event = null;
+        }
+
+        // Ignore all other events until end of event loop
+        ignore_mouse = true;
+        window.setTimeout(function() {
+            ignore_mouse = false;
+        }, 0);
+
+    }
+
     function cancelEvent(e) {
         e.stopPropagation();
         if (e.preventDefault) e.preventDefault();
@@ -122,7 +155,10 @@ Guacamole.Mouse = function(element) {
         guac_mouse.currentState.y -= parent.offsetTop  - documentScrollTop;
 
         if (guac_mouse.onmousemove)
-            guac_mouse.onmousemove(guac_mouse.currentState);
+            deferred_mouse_event = window.setTimeout(function() {
+                guac_mouse.onmousemove(guac_mouse.currentState);
+                deferred_mouse_event = null;
+            }, 0);
 
     }
 
@@ -136,6 +172,13 @@ Guacamole.Mouse = function(element) {
 
         cancelEvent(e);
 
+        // If artificial event detected, ignore currently pending events
+        if (deferred_mouse_event)
+            ignorePendingMouseEvents();
+
+        if (ignore_mouse)
+            return;
+
         moveMouse(e.clientX, e.clientY);
 
     }, false);
@@ -144,6 +187,13 @@ Guacamole.Mouse = function(element) {
 
         cancelEvent(e);
 
+        // If artificial event detected, ignore currently pending events
+        if (deferred_mouse_event)
+            ignorePendingMouseEvents();
+
+        if (ignore_mouse)
+            return;
+
         switch (e.button) {
             case 0:
                 guac_mouse.currentState.left = true;
@@ -157,7 +207,10 @@ Guacamole.Mouse = function(element) {
         }
 
         if (guac_mouse.onmousedown)
-            guac_mouse.onmousedown(guac_mouse.currentState);
+            deferred_mouse_event = window.setTimeout(function() {
+                guac_mouse.onmousedown(guac_mouse.currentState);
+                deferred_mouse_event = null;
+            }, 0);
 
     }, false);
 
@@ -165,6 +218,13 @@ Guacamole.Mouse = function(element) {
 
         cancelEvent(e);
 
+        // If artificial event detected, ignore currently pending events
+        if (deferred_mouse_event)
+            ignorePendingMouseEvents();
+
+        if (ignore_mouse)
+            return;
+
         switch (e.button) {
             case 0:
                 guac_mouse.currentState.left = false;
@@ -178,7 +238,10 @@ Guacamole.Mouse = function(element) {
         }
 
         if (guac_mouse.onmouseup)
-            guac_mouse.onmouseup(guac_mouse.currentState);
+            deferred_mouse_event = window.setTimeout(function() {
+                guac_mouse.onmouseup(guac_mouse.currentState);
+                deferred_mouse_event = null;
+            }, 0);
 
     }, false);
 
@@ -217,6 +280,12 @@ Guacamole.Mouse = function(element) {
         cancelEvent(e);
     }, false);
 
+
+    // Ignore all pending mouse events when touch events are the apparent source
+    element.addEventListener("touchmove",  ignorePendingMouseEvents, false);
+    element.addEventListener("touchstart", ignorePendingMouseEvents, false);
+    element.addEventListener("touchend",   ignorePendingMouseEvents, false);
+
     // Scroll wheel support
     function mousewheel_handler(e) {