Bug 1304044 - implement auxclick r=smaug
authorKevin Wern <kevin.m.wern@gmail.com>
Wed, 30 Nov 2016 19:48:02 -0500
changeset 372989 ea7338a0b3deb91d7e10008e3560ca8e8e3605b0
parent 372941 da29c78960ebcfce36b84784522ecd000f5b2c00
child 372990 533ad81299f74d62e679afbf42bb52bea56ce7ac
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1304044
milestone53.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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;