Bug 1304044 - implement auxclick r=smaug draft
authorKevin Wern <kevin.m.wern@gmail.com>
Wed, 30 Nov 2016 19:48:02 -0500
changeset 448734 558261dd0d0b9241efa84ca168c50455850af03a
parent 448733 aba6c73511a2cec62891f79e1ecd09f1b85dd175
child 539358 7189fbb11503e9a247e91860af049ed781cb1389
push id38415
push userbmo:kevin.m.wern@gmail.com
push dateMon, 12 Dec 2016 18:48:54 +0000
reviewerssmaug
bugs1304044
milestone53.0a1
Bug 1304044 - implement auxclick r=smaug After click events with button 2 or 3 are fired, fire auxclick, a new event intended to represent a non-primary mouse click. Because this event, based on the design examples and blink's implementation, is intended to be used with content listeners, always dispatch on content listeners--not just those that force all events to be dispatched (i.e. document/window). This diverges from the behavior of our click events from non-primary buttons. Eventually, we hope this will replace click events for non-primary buttons. For now, leave those events for compatibility reasons. Additionally, add handling of this new event, where necessary. MozReview-Commit-ID: 8osozM4h6Ya
dom/base/nsGkAtomList.h
dom/events/EventNameList.h
dom/events/EventStateManager.cpp
dom/events/EventStateManager.h
dom/events/WheelHandlingHelper.cpp
dom/events/test/mochitest.ini
dom/events/test/test_bug1304044.html
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/webidl/EventHandler.webidl
dom/xul/nsXULElement.cpp
gfx/layers/apz/src/APZCTreeManager.cpp
widget/BasicEvents.h
widget/EventMessageList.h
widget/WidgetEventImpl.cpp
widget/nsBaseWidget.cpp
widget/windows/WinUtils.cpp
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -698,16 +698,17 @@ GK_ATOM(onanimationiteration, "onanimati
 GK_ATOM(onanimationstart, "onanimationstart")
 GK_ATOM(onantennaavailablechange, "onantennaavailablechange")
 GK_ATOM(onAppCommand, "onAppCommand")
 GK_ATOM(onappinstalled, "onappinstalled")
 GK_ATOM(onattributechanged, "onattributechanged")
 GK_ATOM(onattributereadreq, "onattributereadreq")
 GK_ATOM(onattributewritereq, "onattributewritereq")
 GK_ATOM(onaudioprocess, "onaudioprocess")
+GK_ATOM(onauxclick, "onauxclick")
 GK_ATOM(onbeforecopy, "onbeforecopy")
 GK_ATOM(onbeforecut, "onbeforecut")
 GK_ATOM(onbeforepaste, "onbeforepaste")
 GK_ATOM(onbeforeevicted, "onbeforeevicted")
 GK_ATOM(onbeforeprint, "onbeforeprint")
 GK_ATOM(onbeforescriptexecute, "onbeforescriptexecute")
 GK_ATOM(onbeforeunload, "onbeforeunload")
 GK_ATOM(onblocked, "onblocked")
--- a/dom/events/EventNameList.h
+++ b/dom/events/EventNameList.h
@@ -159,16 +159,20 @@ EVENT(canplay,
 EVENT(canplaythrough,
       eCanPlayThrough,
       EventNameType_HTML,
       eBasicEventClass)
 EVENT(change,
       eFormChange,
       EventNameType_HTMLXUL,
       eBasicEventClass)
+EVENT(auxclick,
+      eMouseAuxClick,
+      EventNameType_All,
+      eMouseEventClass)
 EVENT(click,
       eMouseClick,
       EventNameType_All,
       eMouseEventClass)
 EVENT(contextmenu,
       eContextMenu,
       EventNameType_HTMLXUL,
       eMouseEventClass)
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -484,16 +484,17 @@ EventStateManager::TryToFlushPendingNoti
 }
 
 static bool
 IsMessageMouseUserActivity(EventMessage aMessage)
 {
   return aMessage == eMouseMove ||
          aMessage == eMouseUp ||
          aMessage == eMouseDown ||
+         aMessage == eMouseAuxClick ||
          aMessage == eMouseDoubleClick ||
          aMessage == eMouseClick ||
          aMessage == eMouseActivate ||
          aMessage == eMouseLongTap;
 }
 
 static bool
 IsMessageGamepadUserActivity(EventMessage aMessage)
@@ -4613,16 +4614,42 @@ EventStateManager::SetClickCount(WidgetM
     }
     break;
   }
 
   return NS_OK;
 }
 
 nsresult
+EventStateManager::InitAndDispatchClickEvent(WidgetMouseEvent* aEvent,
+                                             nsEventStatus* aStatus,
+                                             EventMessage aMessage,
+                                             nsIPresShell* aPresShell,
+                                             nsIContent* aMouseTarget,
+                                             nsWeakFrame aCurrentTarget,
+                                             bool aNoContentDispatch)
+{
+  WidgetMouseEvent event(aEvent->IsTrusted(), aMessage,
+                         aEvent->mWidget, WidgetMouseEvent::eReal);
+
+  event.mRefPoint = aEvent->mRefPoint;
+  event.mClickCount = aEvent->mClickCount;
+  event.mModifiers = aEvent->mModifiers;
+  event.buttons = aEvent->buttons;
+  event.mTime = aEvent->mTime;
+  event.mTimeStamp = aEvent->mTimeStamp;
+  event.mFlags.mNoContentDispatch = aNoContentDispatch;
+  event.button = aEvent->button;
+  event.inputSource = aEvent->inputSource;
+
+  return aPresShell->HandleEventWithTarget(&event, aCurrentTarget,
+                                           aMouseTarget, aStatus);
+}
+
+nsresult
 EventStateManager::CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
                                             nsEventStatus* aStatus)
 {
   nsresult ret = NS_OK;
 
   //If mouse is still over same element, clickcount will be > 1.
   //If it has moved it will be zero, so no click.
   if (aEvent->mClickCount) {
@@ -4631,27 +4658,17 @@ EventStateManager::CheckForAndDispatchCl
     if (aEvent->mWidget && !aEvent->mWidget->IsEnabled()) {
       return ret;
     }
     //fire click
     bool notDispatchToContents =
      (aEvent->button == WidgetMouseEvent::eMiddleButton ||
       aEvent->button == WidgetMouseEvent::eRightButton);
 
-    WidgetMouseEvent event(aEvent->IsTrusted(), eMouseClick,
-                           aEvent->mWidget, WidgetMouseEvent::eReal);
-    event.mRefPoint = aEvent->mRefPoint;
-    event.mClickCount = aEvent->mClickCount;
-    event.mModifiers = aEvent->mModifiers;
-    event.buttons = aEvent->buttons;
-    event.mTime = aEvent->mTime;
-    event.mTimeStamp = aEvent->mTimeStamp;
-    event.mFlags.mNoContentDispatch = notDispatchToContents;
-    event.button = aEvent->button;
-    event.inputSource = aEvent->inputSource;
+    bool fireAuxClick = notDispatchToContents;
 
     nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
     if (presShell) {
       nsCOMPtr<nsIContent> mouseContent = GetEventTargetContent(aEvent);
       // Click events apply to *elements* not nodes. At this point the target
       // content may have been reset to some non-element content, and so we need
       // to walk up the closest ancestor element, just like we do in
       // nsPresShell::HandlePositionedEvent.
@@ -4660,35 +4677,32 @@ EventStateManager::CheckForAndDispatchCl
       }
 
       if (!mouseContent && !mCurrentTarget) {
         return NS_OK;
       }
 
       // HandleEvent clears out mCurrentTarget which we might need again
       nsWeakFrame currentTarget = mCurrentTarget;
-      ret = presShell->HandleEventWithTarget(&event, currentTarget,
-                                             mouseContent, aStatus);
+      ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseClick,
+                                      presShell, mouseContent, currentTarget,
+                                      notDispatchToContents);
+
       if (NS_SUCCEEDED(ret) && aEvent->mClickCount == 2 &&
           mouseContent && mouseContent->IsInComposedDoc()) {
         //fire double click
-        WidgetMouseEvent event2(aEvent->IsTrusted(), eMouseDoubleClick,
-                                aEvent->mWidget, WidgetMouseEvent::eReal);
-        event2.mRefPoint = aEvent->mRefPoint;
-        event2.mClickCount = aEvent->mClickCount;
-        event2.mModifiers = aEvent->mModifiers;
-        event2.buttons = aEvent->buttons;
-        event2.mTime = aEvent->mTime;
-        event2.mTimeStamp = aEvent->mTimeStamp;
-        event2.mFlags.mNoContentDispatch = notDispatchToContents;
-        event2.button = aEvent->button;
-        event2.inputSource = aEvent->inputSource;
-
-        ret = presShell->HandleEventWithTarget(&event2, currentTarget,
-                                               mouseContent, aStatus);
+        ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseDoubleClick,
+                                        presShell, mouseContent, currentTarget,
+                                        notDispatchToContents);
+      }
+      if (NS_SUCCEEDED(ret) && mouseContent && fireAuxClick &&
+          mouseContent->IsInComposedDoc()) {
+        ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseAuxClick,
+                                        presShell, mouseContent, currentTarget,
+                                        false);
       }
     }
   }
   return ret;
 }
 
 nsIFrame*
 EventStateManager::GetEventTarget()
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -410,16 +410,23 @@ protected:
                            nsIContent* aTargetContent,
                            nsWeakFrame& aTargetFrame);
   /**
    * Update the initial drag session data transfer with any changes that occur
    * on cloned data transfer objects used for events.
    */
   void UpdateDragDataTransfer(WidgetDragEvent* dragEvent);
 
+  static nsresult InitAndDispatchClickEvent(WidgetMouseEvent* aEvent,
+                                            nsEventStatus* aStatus,
+                                            EventMessage aMessage,
+                                            nsIPresShell* aPresShell,
+                                            nsIContent* aMouseTarget,
+                                            nsWeakFrame aCurrentTarget,
+                                            bool aNoContentDispatch);
   nsresult SetClickCount(WidgetMouseEvent* aEvent, nsEventStatus* aStatus);
   nsresult CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
                                     nsEventStatus* aStatus);
   void EnsureDocument(nsPresContext* aPresContext);
   void FlushPendingEvents(nsPresContext* aPresContext);
 
   /**
    * The phases of HandleAccessKey processing. See below.
@@ -1039,11 +1046,12 @@ private:
 
 } // namespace mozilla
 
 // Click and double-click events need to be handled even for content that
 // has no frame. This is required for Web compatibility.
 #define NS_EVENT_NEEDS_FRAME(event) \
     (!(event)->HasPluginActivationEventMessage() && \
      (event)->mMessage != eMouseClick && \
-     (event)->mMessage != eMouseDoubleClick)
+     (event)->mMessage != eMouseDoubleClick && \
+     (event)->mMessage != eMouseAuxClick)
 
 #endif // mozilla_EventStateManager_h_
--- a/dom/events/WheelHandlingHelper.cpp
+++ b/dom/events/WheelHandlingHelper.cpp
@@ -252,16 +252,17 @@ WheelTransaction::OnEvent(WidgetEvent* a
       return;
     }
     case eKeyPress:
     case eKeyUp:
     case eKeyDown:
     case eMouseUp:
     case eMouseDown:
     case eMouseDoubleClick:
+    case eMouseAuxClick:
     case eMouseClick:
     case eContextMenu:
     case eDrop:
       EndTransaction();
       return;
     default:
       break;
   }
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -179,8 +179,9 @@ skip-if = toolkit == 'android' #CRASH_DU
 [test_offsetxy.html]
 [test_onerror_handler_args.html]
 [test_passive_listeners.html]
 [test_paste_image.html]
 [test_wheel_default_action.html]
 [test_bug687787.html]
 [test_bug1305458.html]
 [test_bug1298970.html]
+[test_bug1304044.html]
new file mode 100644
--- /dev/null
+++ b/dom/events/test/test_bug1304044.html
@@ -0,0 +1,133 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1304044
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1304044</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+    var eventsFired = [];
+    var target;
+    var eventsExpected;
+
+    function GetNodeString(node) {
+      if (node == window)
+        return "window";
+      if (node == document)
+        return "document";
+      if (node.id)
+        return node.id;
+      if (node.nodeName)
+        return node.nodeName;
+      return node;
+    }
+
+    function TargetAndListener(listener, target) {
+      this.listener = listener;
+      this.target = target;
+    }
+
+    TargetAndListener.prototype.toString = function() {
+      var targetName = GetNodeString(this.target);
+      var listenerName = GetNodeString(this.listener);
+      return "(listener: " + listenerName + ", target: " + targetName + ")";
+    }
+
+    var tests = [
+      TestAuxClickBubblesForEventListener,
+      TestAuxClickBubblesForOnAuxClick,
+    ];
+
+    function CompareEvents(evt, expected) {
+      return evt && expected && evt.listener == expected.listener &&
+          evt.target == expected.target;
+    }
+
+    function ResetEventsFired() {
+      eventsFired = [];
+    }
+
+    function ClearEventListeners() {
+      for (i in arguments) {
+        arguments[i].removeEventListener("auxclick", log_event);
+      }
+    }
+
+    function ClickTarget(tgt) {
+      synthesizeMouseAtCenter(tgt, {type : "mousedown", button: 2}, window);
+      synthesizeMouseAtCenter(tgt, {type : "mouseup", button: 2}, window);
+    }
+
+    function log_event(e) {
+      eventsFired[eventsFired.length] = new TargetAndListener(this, e.target);
+    }
+
+    function CompareEventsToExpected(expected, actual) {
+      for (var i = 0; i < expected.length || i < actual.length; i++) {
+        ok(CompareEvents(actual[i], expected[i]),
+           "Auxclick receiver's don't match: TargetAndListener " +
+           i + ": Expected: " + expected[i] + ", Actual: " + actual[i]);
+      }
+    }
+
+    function TestAuxClickBubblesForEventListener() {
+      target.addEventListener("auxclick", log_event);
+      document.addEventListener("auxclick", log_event);
+      window.addEventListener("auxclick", log_event);
+
+      ClickTarget(target)
+      CompareEventsToExpected(eventsExpected, eventsFired);
+      ResetEventsFired();
+      ClearEventListeners(target, document, window);
+    }
+
+    function TestAuxClickBubblesForOnAuxClick() {
+      target.onauxclick = log_event;
+      document.onauxclick = log_event;
+      window.onauxclick = log_event;
+
+      ClickTarget(target);
+      CompareEventsToExpected(eventsExpected, eventsFired);
+      ResetEventsFired();
+    }
+
+    function RunTests(){
+      for (var i = 0; i < tests.length; i++) {
+        tests[i]();
+      }
+    }
+
+    function Begin() {
+      target = document.getElementById("target");
+      eventsExpected =  [
+        new TargetAndListener(target, target),
+        new TargetAndListener(document, target),
+        new TargetAndListener(window, target),
+      ];
+      RunTests();
+      target.remove();
+      SimpleTest.finish();
+    }
+
+    window.onload = function() {
+      SimpleTest.waitForExplicitFinish();
+      SimpleTest.executeSoon(Begin);
+    }
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1304044">Mozilla Bug 1304044</a>
+<p id="display">
+  <div id="target">Target</div>
+</p>
+<div id="content" style:"display:none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -2527,16 +2527,17 @@ nsEventStatus nsPluginInstanceOwner::Pro
     if (pPluginEvent) {
       // Make event coordinates relative to our enclosing widget,
       // not the widget they were received on.
       // See use of NPEvent in widget/windows/nsWindow.cpp
       // for why this assert should be safe
       NS_ASSERTION(anEvent.mMessage == eMouseDown ||
                    anEvent.mMessage == eMouseUp ||
                    anEvent.mMessage == eMouseDoubleClick ||
+                   anEvent.mMessage == eMouseAuxClick ||
                    anEvent.mMessage == eMouseOver ||
                    anEvent.mMessage == eMouseOut ||
                    anEvent.mMessage == eMouseMove ||
                    anEvent.mMessage == eWheel,
                    "Incorrect event type for coordinate translation");
       nsPoint pt =
         nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mPluginFrame) -
         mPluginFrame->GetContentRectRelativeToSelf().TopLeft();
@@ -2589,16 +2590,17 @@ nsEventStatus nsPluginInstanceOwner::Pro
   pluginEvent.type = 0;
 
   switch(anEvent.mClass) {
     case eMouseEventClass:
       {
         switch (anEvent.mMessage) {
           case eMouseClick:
           case eMouseDoubleClick:
+          case eMouseAuxClick:
             // Button up/down events sent instead.
             return rv;
           default:
             break;
           }
 
         // Get reference point relative to plugin origin.
         const nsPresContext* presContext = mPluginFrame->PresContext();
@@ -2792,16 +2794,17 @@ nsEventStatus nsPluginInstanceOwner::Pro
     }
   }
   switch(anEvent.mClass) {
     case eMouseEventClass:
       {
         switch (anEvent.mMessage) {
           case eMouseClick:
           case eMouseDoubleClick:
+          case eMouseAuxClick:
             // Button up/down events sent instead.
             return rv;
           default:
             break;
           }
 
         // Get reference point relative to plugin origin.
         const nsPresContext* presContext = mPluginFrame->PresContext();
--- a/dom/webidl/EventHandler.webidl
+++ b/dom/webidl/EventHandler.webidl
@@ -28,16 +28,17 @@ typedef OnErrorEventHandlerNonNull? OnEr
 interface GlobalEventHandlers {
            attribute EventHandler onabort;
            attribute EventHandler onblur;
 // We think the spec is wrong here. See OnErrorEventHandlerForNodes/Window
 // below.
 //         attribute OnErrorEventHandler onerror;
            attribute EventHandler onfocus;
            //(Not implemented)attribute EventHandler oncancel;
+           attribute EventHandler onauxclick;
            attribute EventHandler oncanplay;
            attribute EventHandler oncanplaythrough;
            attribute EventHandler onchange;
            attribute EventHandler onclick;
            //(Not implemented)attribute EventHandler onclose;
            attribute EventHandler oncontextmenu;
            //(Not implemented)attribute EventHandler oncuechange;
            attribute EventHandler ondblclick;
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -1272,17 +1272,17 @@ nsXULElement::List(FILE* out, int32_t aI
 
 bool
 nsXULElement::IsEventStoppedFromAnonymousScrollbar(EventMessage aMessage)
 {
     return (IsRootOfNativeAnonymousSubtree() &&
             IsAnyOfXULElements(nsGkAtoms::scrollbar, nsGkAtoms::scrollcorner) &&
             (aMessage == eMouseClick || aMessage == eMouseDoubleClick ||
              aMessage == eXULCommand || aMessage == eContextMenu ||
-             aMessage == eDragStart));
+             aMessage == eDragStart  || aMessage == eMouseAuxClick));
 }
 
 nsresult
 nsXULElement::DispatchXULCommand(const EventChainVisitor& aVisitor,
                                  nsAutoString& aCommand)
 {
     // XXX sXBL/XBL2 issue! Owner or current document?
     nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(GetUncomposedDoc()));
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -1140,16 +1140,17 @@ APZCTreeManager::UpdateWheelTransaction(
     return;
    }
    case eKeyPress:
    case eKeyUp:
    case eKeyDown:
    case eMouseUp:
    case eMouseDown:
    case eMouseDoubleClick:
+   case eMouseAuxClick:
    case eMouseClick:
    case eContextMenu:
    case eDrop:
      txn->EndTransaction();
      return;
    default:
      break;
   }
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -590,16 +590,17 @@ public:
         break;
       case eKeyboardEventClass:
         mFlags.mComposed = mMessage == eKeyDown || mMessage == eKeyUp ||
                            mMessage == eKeyPress;
         break;
       case eMouseEventClass:
         mFlags.mComposed = mMessage == eMouseClick ||
                            mMessage == eMouseDoubleClick ||
+                           mMessage == eMouseAuxClick ||
                            mMessage == eMouseDown || mMessage == eMouseUp ||
                            mMessage == eMouseEnter || mMessage == eMouseLeave ||
                            mMessage == eMouseOver || mMessage == eMouseOut ||
                            mMessage == eMouseMove || mMessage == eContextMenu;
         break;
       case ePointerEventClass:
         // All pointer events are composed
         mFlags.mComposed = mMessage == ePointerDown ||
--- a/widget/EventMessageList.h
+++ b/widget/EventMessageList.h
@@ -79,16 +79,17 @@ NS_EVENT_MESSAGE(eLanguageChange)
 
 NS_EVENT_MESSAGE(eMouseMove)
 NS_EVENT_MESSAGE(eMouseUp)
 NS_EVENT_MESSAGE(eMouseDown)
 NS_EVENT_MESSAGE(eMouseEnterIntoWidget)
 NS_EVENT_MESSAGE(eMouseExitFromWidget)
 NS_EVENT_MESSAGE(eMouseDoubleClick)
 NS_EVENT_MESSAGE(eMouseClick)
+NS_EVENT_MESSAGE(eMouseAuxClick)
 // eMouseActivate is fired when the widget is activated by a click.
 NS_EVENT_MESSAGE(eMouseActivate)
 NS_EVENT_MESSAGE(eMouseOver)
 NS_EVENT_MESSAGE(eMouseOut)
 NS_EVENT_MESSAGE(eMouseHitTest)
 NS_EVENT_MESSAGE(eMouseEnter)
 NS_EVENT_MESSAGE(eMouseLeave)
 NS_EVENT_MESSAGE(eMouseLongTap)
--- a/widget/WidgetEventImpl.cpp
+++ b/widget/WidgetEventImpl.cpp
@@ -231,16 +231,17 @@ WidgetEvent::IsNativeEventDelivererForPl
 bool
 WidgetEvent::HasMouseEventMessage() const
 {
   switch (mMessage) {
     case eMouseDown:
     case eMouseUp:
     case eMouseClick:
     case eMouseDoubleClick:
+    case eMouseAuxClick:
     case eMouseEnterIntoWidget:
     case eMouseExitFromWidget:
     case eMouseActivate:
     case eMouseOver:
     case eMouseOut:
     case eMouseHitTest:
     case eMouseMove:
       return true;
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -3081,16 +3081,17 @@ case _value: eventName.AssignLiteral(_na
     _ASSIGN_eventName(eKeyDown,"eKeyDown");
     _ASSIGN_eventName(eKeyPress,"eKeyPress");
     _ASSIGN_eventName(eKeyUp,"eKeyUp");
     _ASSIGN_eventName(eMouseEnterIntoWidget,"eMouseEnterIntoWidget");
     _ASSIGN_eventName(eMouseExitFromWidget,"eMouseExitFromWidget");
     _ASSIGN_eventName(eMouseDown,"eMouseDown");
     _ASSIGN_eventName(eMouseUp,"eMouseUp");
     _ASSIGN_eventName(eMouseClick,"eMouseClick");
+    _ASSIGN_eventName(eMouseAuxClick,"eMouseAuxClick");
     _ASSIGN_eventName(eMouseDoubleClick,"eMouseDoubleClick");
     _ASSIGN_eventName(eMouseMove,"eMouseMove");
     _ASSIGN_eventName(eLoad,"eLoad");
     _ASSIGN_eventName(ePopState,"ePopState");
     _ASSIGN_eventName(eBeforeScriptExecute,"eBeforeScriptExecute");
     _ASSIGN_eventName(eAfterScriptExecute,"eAfterScriptExecute");
     _ASSIGN_eventName(eUnload,"eUnload");
     _ASSIGN_eventName(eHashChange,"eHashChange");
--- a/widget/windows/WinUtils.cpp
+++ b/widget/windows/WinUtils.cpp
@@ -1138,17 +1138,18 @@ WinUtils::GetMousePointerID()
 
 /* static */
 bool
 WinUtils::GetIsMouseFromTouch(EventMessage aEventMessage)
 {
   const uint32_t MOZ_T_I_SIGNATURE = TABLET_INK_TOUCH | TABLET_INK_SIGNATURE;
   const uint32_t MOZ_T_I_CHECK_TCH = TABLET_INK_TOUCH | TABLET_INK_CHECK;
   return ((aEventMessage == eMouseMove || aEventMessage == eMouseDown ||
-           aEventMessage == eMouseUp || aEventMessage == eMouseDoubleClick) &&
+           aEventMessage == eMouseUp || aEventMessage == eMouseAuxClick ||
+           aEventMessage == eMouseDoubleClick) &&
          (GetMessageExtraInfo() & MOZ_T_I_SIGNATURE) == MOZ_T_I_CHECK_TCH);
 }
 
 /* static */
 MSG
 WinUtils::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam, HWND aWnd)
 {
   MSG msg;