Bug 1101975, handle access keys in content process before menus, r=masayuki
authorNeil Deakin <neil@mozilla.com>
Wed, 11 May 2016 08:56:42 -0400
changeset 296997 1b02f9d6c0586c7d7db405b3fc1ad4347503a180
parent 296996 ece69108baefc705cf2f7fd2802119fe883f80d0
child 296998 dddeac9ffc39e1a42b3ce866b6edd0b419be5c32
push id19195
push usercbook@mozilla.com
push dateThu, 12 May 2016 09:58:44 +0000
treeherderfx-team@6e3f70253ead [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmasayuki
bugs1101975
milestone49.0a1
Bug 1101975, handle access keys in content process before menus, r=masayuki
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/base/nsFocusManager.cpp
dom/base/nsGkAtomList.h
dom/events/EventNameList.h
dom/events/EventStateManager.cpp
dom/events/EventStateManager.h
dom/events/KeyboardEvent.cpp
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
layout/base/nsPresContext.cpp
layout/xul/nsMenuBarFrame.cpp
layout/xul/nsMenuBarListener.cpp
widget/EventMessageList.h
widget/TextEvents.h
widget/WidgetEventImpl.cpp
widget/nsGUIEventIPC.h
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7129,48 +7129,54 @@ nsContentUtils::GetHostOrIPv6WithBracket
   nsresult rv = GetHostOrIPv6WithBrackets(aURI, hostname);
   if (NS_FAILED(rv)) {
     return rv;
   }
   CopyUTF8toUTF16(hostname, aHost);
   return NS_OK;
 }
 
-void
+bool
 nsContentUtils::CallOnAllRemoteChildren(nsIMessageBroadcaster* aManager,
                                         CallOnRemoteChildFunction aCallback,
                                         void* aArg)
 {
   uint32_t tabChildCount = 0;
   aManager->GetChildCount(&tabChildCount);
   for (uint32_t j = 0; j < tabChildCount; ++j) {
     nsCOMPtr<nsIMessageListenerManager> childMM;
     aManager->GetChildAt(j, getter_AddRefs(childMM));
     if (!childMM) {
       continue;
     }
 
     nsCOMPtr<nsIMessageBroadcaster> nonLeafMM = do_QueryInterface(childMM);
     if (nonLeafMM) {
-      CallOnAllRemoteChildren(nonLeafMM, aCallback, aArg);
+      if (CallOnAllRemoteChildren(nonLeafMM, aCallback, aArg)) {
+        return true;
+      }
       continue;
     }
 
     nsCOMPtr<nsIMessageSender> tabMM = do_QueryInterface(childMM);
 
     mozilla::dom::ipc::MessageManagerCallback* cb =
      static_cast<nsFrameMessageManager*>(tabMM.get())->GetCallback();
     if (cb) {
       nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb);
       TabParent* remote = TabParent::GetFrom(fl);
       if (remote && aCallback) {
-        aCallback(remote, aArg);
+        if (aCallback(remote, aArg)) {
+          return true;
+        }
       }
     }
   }
+
+  return false;
 }
 
 void
 nsContentUtils::CallOnAllRemoteChildren(nsPIDOMWindowOuter* aWindow,
                                         CallOnRemoteChildFunction aCallback,
                                         void* aArg)
 {
   nsCOMPtr<nsIDOMChromeWindow> chromeWindow(do_QueryInterface(aWindow));
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -166,17 +166,17 @@ struct EventNameMapping
   // This holds pointers to nsGkAtoms members, and is therefore safe as a
   // non-owning reference.
   nsIAtom* MOZ_NON_OWNING_REF mAtom;
   int32_t  mType;
   mozilla::EventMessage mMessage;
   mozilla::EventClassID mEventClassID;
 };
 
-typedef void (*CallOnRemoteChildFunction) (mozilla::dom::TabParent* aTabParent,
+typedef bool (*CallOnRemoteChildFunction) (mozilla::dom::TabParent* aTabParent,
                                            void* aArg);
 
 class nsContentUtils
 {
   friend class nsAutoScriptBlockerSuppressNodeRemoved;
   typedef mozilla::dom::Element Element;
   typedef mozilla::TimeDuration TimeDuration;
 
@@ -2374,17 +2374,17 @@ public:
    * If the hostname for aURI is an IPv6 it encloses it in brackets,
    * otherwise it just outputs the hostname in aHost.
    */
   static nsresult GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost);
   static nsresult GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost);
 
   /*
    * Call the given callback on all remote children of the given top-level
-   * window.
+   * window. Return true from the callback to stop calling further children.
    */
   static void CallOnAllRemoteChildren(nsPIDOMWindowOuter* aWindow,
                                       CallOnRemoteChildFunction aCallback,
                                       void* aArg);
 
   /**
    * Given an nsIFile, attempts to read it into aString.
    *
@@ -2593,17 +2593,17 @@ private:
   static void DestroyClassNameArray(void* aData);
   static void* AllocClassMatchingInfo(nsINode* aRootNode,
                                       const nsString* aClasses);
 
   // Fills in aInfo with the tokens from the supplied autocomplete attribute.
   static AutocompleteAttrState InternalSerializeAutocompleteAttribute(const nsAttrValue* aAttrVal,
                                                                       mozilla::dom::AutocompleteInfo& aInfo);
 
-  static void CallOnAllRemoteChildren(nsIMessageBroadcaster* aManager,
+  static bool CallOnAllRemoteChildren(nsIMessageBroadcaster* aManager,
                                       CallOnRemoteChildFunction aCallback,
                                       void* aArg);
 
   /*
    * Checks if storage for a given principal is permitted by the user's
    * preferences. If aWindow is non-null, its principal must be passed as
    * aPrincipal, and the third-party iframe and sandboxing status of the window
    * are also checked.
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1105,21 +1105,22 @@ nsFocusManager::EnsureCurrentWidgetFocus
         vm->GetRootWidget(getter_AddRefs(widget));
         if (widget)
           widget->SetFocus(false);
       }
     }
   }
 }
 
-void
+bool
 ActivateOrDeactivateChild(TabParent* aParent, void* aArg)
 {
   bool active = static_cast<bool>(aArg);
   Unused << aParent->SendParentActivated(active);
+  return false;
 }
 
 void
 nsFocusManager::ActivateOrDeactivate(nsPIDOMWindowOuter* aWindow, bool aActive)
 {
   if (!aWindow) {
     return;
   }
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -677,16 +677,17 @@ GK_ATOM(objectType, "object-type")
 GK_ATOM(observer, "observer")
 GK_ATOM(observes, "observes")
 GK_ATOM(odd, "odd")
 GK_ATOM(OFF, "OFF")
 GK_ATOM(ol, "ol")
 GK_ATOM(omitXmlDeclaration, "omit-xml-declaration")
 GK_ATOM(ona2dpstatuschanged, "ona2dpstatuschanged")
 GK_ATOM(onabort, "onabort")
+GK_ATOM(onmozaccesskeynotfound, "onmozaccesskeynotfound")
 GK_ATOM(onactivate, "onactivate")
 GK_ATOM(onadapteradded, "onadapteradded")
 GK_ATOM(onadapterremoved, "onadapterremoved")
 GK_ATOM(onafterprint, "onafterprint")
 GK_ATOM(onafterscriptexecute, "onafterscriptexecute")
 GK_ATOM(onalerting, "onalerting")
 GK_ATOM(onanimationend, "onanimationend")
 GK_ATOM(onanimationiteration, "onanimationiteration")
--- a/dom/events/EventNameList.h
+++ b/dom/events/EventNameList.h
@@ -265,16 +265,20 @@ NON_IDL_EVENT(mozbrowserafterkeydown,
 NON_IDL_EVENT(mozbrowserbeforekeyup,
               eBeforeKeyUp,
               EventNameType_None,
               eBeforeAfterKeyboardEventClass)
 NON_IDL_EVENT(mozbrowserafterkeyup,
               eAfterKeyUp,
               EventNameType_None,
               eBeforeAfterKeyboardEventClass)
+NON_IDL_EVENT(mozaccesskeynotfound,
+              eAccessKeyNotFound,
+              EventNameType_None,
+              eKeyboardEventClass)
 EVENT(loadeddata,
       eLoadedData,
       EventNameType_HTML,
       eBasicEventClass)
 EVENT(loadedmetadata,
       eLoadedMetaData,
       EventNameType_HTML,
       eBasicEventClass)
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -727,25 +727,28 @@ EventStateManager::PreHandleEvent(nsPres
       if (keyEvent->IsAlt())
         modifierMask |= NS_MODIFIER_ALT;
       if (keyEvent->IsMeta())
         modifierMask |= NS_MODIFIER_META;
       if (keyEvent->IsOS())
         modifierMask |= NS_MODIFIER_OS;
 
       // Prevent keyboard scrolling while an accesskey modifier is in use.
-      if (modifierMask &&
-          (modifierMask == Prefs::ChromeAccessModifierMask() ||
-           modifierMask == Prefs::ContentAccessModifierMask())) {
-        AutoTArray<uint32_t, 10> accessCharCodes;
-        keyEvent->GetAccessKeyCandidates(accessCharCodes);
-
-        if (HandleAccessKey(aPresContext, accessCharCodes,
-                            keyEvent->IsTrusted(), modifierMask)) {
-          *aStatus = nsEventStatus_eConsumeNoDefault;
+      if (modifierMask) {
+        bool matchesContentAccessKey = (modifierMask == Prefs::ContentAccessModifierMask());
+        
+        if (modifierMask == Prefs::ChromeAccessModifierMask() ||
+            matchesContentAccessKey) {
+          AutoTArray<uint32_t, 10> accessCharCodes;
+          keyEvent->GetAccessKeyCandidates(accessCharCodes);
+
+          if (HandleAccessKey(keyEvent, aPresContext, accessCharCodes,
+                              modifierMask, matchesContentAccessKey)) {
+            *aStatus = nsEventStatus_eConsumeNoDefault;
+          }
         }
       }
     }
     // then fall through...
     MOZ_FALLTHROUGH;
   case eBeforeKeyDown:
   case eKeyDown:
   case eAfterKeyDown:
@@ -1031,63 +1034,69 @@ EventStateManager::GetAccessKeyLabelPref
     aPrefix.Append(modifierText + separator);
   }
   if (modifierMask & NS_MODIFIER_SHIFT) {
     nsContentUtils::GetShiftText(modifierText);
     aPrefix.Append(modifierText + separator);
   }
 }
 
-struct AccessKeyInfo
+struct MOZ_STACK_CLASS AccessKeyInfo
 {
+  WidgetKeyboardEvent* event;
   nsTArray<uint32_t>& charCodes;
-  bool isTrusted;
   int32_t modifierMask;
 
-  AccessKeyInfo(nsTArray<uint32_t>& aCharCodes, bool aIsTrusted, int32_t aModifierMask)
-    : charCodes(aCharCodes)
-    , isTrusted(aIsTrusted)
+  AccessKeyInfo(WidgetKeyboardEvent* aEvent, nsTArray<uint32_t>& aCharCodes, int32_t aModifierMask)
+    : event(aEvent)
+    , charCodes(aCharCodes)
     , modifierMask(aModifierMask)
   {
   }
 };
 
-static void
+static bool
 HandleAccessKeyInRemoteChild(TabParent* aTabParent, void* aArg)
 {
   AccessKeyInfo* accessKeyInfo = static_cast<AccessKeyInfo*>(aArg);
 
   // Only forward accesskeys for the active tab.
   bool active;
   aTabParent->GetDocShellIsActive(&active);
   if (active) {
-    aTabParent->HandleAccessKey(accessKeyInfo->charCodes, accessKeyInfo->isTrusted,
+    accessKeyInfo->event->mAccessKeyForwardedToChild = true;
+    aTabParent->HandleAccessKey(*accessKeyInfo->event,
+                                accessKeyInfo->charCodes,
                                 accessKeyInfo->modifierMask);
-  }
+    return true;
+  }
+
+  return false;
 }
 
 bool
-EventStateManager::HandleAccessKey(nsPresContext* aPresContext,
+EventStateManager::HandleAccessKey(WidgetKeyboardEvent* aEvent,
+                                   nsPresContext* aPresContext,
                                    nsTArray<uint32_t>& aAccessCharCodes,
-                                   bool aIsTrusted,
+                                   bool aMatchesContentAccessKey,
                                    nsIDocShellTreeItem* aBubbledFrom,
                                    ProcessingAccessKeyState aAccessKeyState,
                                    int32_t aModifierMask)
 {
   EnsureDocument(mPresContext);
   nsCOMPtr<nsIDocShell> docShell = aPresContext->GetDocShell();
   if (NS_WARN_IF(!docShell) || NS_WARN_IF(!mDocument)) {
     return false;
   }
 
   // Alt or other accesskey modifier is down, we may need to do an accesskey.
   if (mAccessKeys.Count() > 0 &&
       aModifierMask == GetAccessModifierMaskFor(docShell)) {
     // Someone registered an accesskey.  Find and activate it.
-    if (ExecuteAccessKey(aAccessCharCodes, aIsTrusted)) {
+    if (ExecuteAccessKey(aAccessCharCodes, aEvent->IsTrusted())) {
       return true;
     }
   }
 
   int32_t childCount;
   docShell->GetChildCount(&childCount);
   for (int32_t counter = 0; counter < childCount; counter++) {
     // Not processing the child which bubbles up the handling
@@ -1110,17 +1119,18 @@ EventStateManager::HandleAccessKey(nsPre
       }
 
       nsPresContext *subPC = subPS->GetPresContext();
 
       EventStateManager* esm =
         static_cast<EventStateManager*>(subPC->EventStateManager());
 
       if (esm &&
-          esm->HandleAccessKey(subPC, aAccessCharCodes, aIsTrusted, nullptr,
+          esm->HandleAccessKey(aEvent, subPC, aAccessCharCodes,
+                               aMatchesContentAccessKey, nullptr,
                                eAccessKeyProcessingDown, aModifierMask)) {
         return true;
       }
     }
   }// if end . checking all sub docshell ends here.
 
   // bubble up the process to the parent docshell if necessary
   if (eAccessKeyProcessingDown != aAccessKeyState) {
@@ -1132,32 +1142,37 @@ EventStateManager::HandleAccessKey(nsPre
       NS_ASSERTION(parentPS, "Our PresShell exists but the parent's does not?");
 
       nsPresContext *parentPC = parentPS->GetPresContext();
       NS_ASSERTION(parentPC, "PresShell without PresContext");
 
       EventStateManager* esm =
         static_cast<EventStateManager*>(parentPC->EventStateManager());
       if (esm &&
-          esm->HandleAccessKey(parentPC, aAccessCharCodes, aIsTrusted, docShell,
-                               eAccessKeyProcessingUp, aModifierMask)) {
+          esm->HandleAccessKey(aEvent, parentPC, aAccessCharCodes,
+                               aMatchesContentAccessKey, docShell,
+                               eAccessKeyProcessingDown, aModifierMask)) {
         return true;
       }
     }
   }// if end. bubble up process
 
-  // Now try remote children
-  if (mDocument && mDocument->GetWindow()) {
+  // If the content access key modifier is pressed, try remote children
+  if (aMatchesContentAccessKey && mDocument && mDocument->GetWindow()) {
     // If the focus is currently on a node with a TabParent, the key event will
     // get forwarded to the child process and HandleAccessKey called from there.
     // If focus is somewhere else, then we need to check the remote children.
     nsFocusManager* fm = nsFocusManager::GetFocusManager();
     nsIContent* focusedContent = fm ? fm->GetFocusedContent() : nullptr;
-    if (!TabParent::GetFrom(focusedContent)) {
-      AccessKeyInfo accessKeyInfo(aAccessCharCodes, aIsTrusted, aModifierMask);
+    if (TabParent::GetFrom(focusedContent)) {
+      // A remote child process is focused. The key event should get sent to
+      // the child process.
+      aEvent->mAccessKeyForwardedToChild = true;
+    } else {
+      AccessKeyInfo accessKeyInfo(aEvent, aAccessCharCodes, aModifierMask);
       nsContentUtils::CallOnAllRemoteChildren(mDocument->GetWindow(),
                                               HandleAccessKeyInRemoteChild, &accessKeyInfo);
     }
   }
 
   return false;
 }// end of HandleAccessKey
 
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -178,23 +178,25 @@ public:
    *
    * @param  aContent  the given element (must not be null)
    * @return           registered accesskey
    */
   uint32_t GetRegisteredAccessKey(nsIContent* aContent);
 
   static void GetAccessKeyLabelPrefix(dom::Element* aElement, nsAString& aPrefix);
 
-  bool HandleAccessKey(nsPresContext* aPresContext,
+  bool HandleAccessKey(WidgetKeyboardEvent* aEvent,
+                       nsPresContext* aPresContext,
                        nsTArray<uint32_t>& aAccessCharCodes,
-                       bool aIsTrusted,
-                       int32_t aModifierMask)
+                       int32_t aModifierMask,
+                       bool aMatchesContentAccessKey)
   {
-    return HandleAccessKey(aPresContext, aAccessCharCodes, aIsTrusted,
-                           nullptr, eAccessKeyProcessingNormal, aModifierMask);
+    return HandleAccessKey(aEvent, aPresContext, aAccessCharCodes,
+                           aMatchesContentAccessKey, nullptr,
+                           eAccessKeyProcessingNormal, aModifierMask);
   }
 
   nsresult SetCursor(int32_t aCursor, imgIContainer* aContainer,
                      bool aHaveHotspot, float aHotspotX, float aHotspotY,
                      nsIWidget* aWidget, bool aLockCursor); 
 
   static void StartHandlingUserInput()
   {
@@ -430,37 +432,39 @@ protected:
 
   /**
    * Access key handling.  If there is registered content for the accesskey
    * given by the key event and modifier mask then call
    * content.PerformAccesskey(), otherwise call HandleAccessKey() recursively,
    * on descendant docshells first, then on the ancestor (with |aBubbledFrom|
    * set to the docshell associated with |this|), until something matches.
    *
+   * @param aEvent the keyboard event triggering the acccess key
    * @param aPresContext the presentation context
    * @param aAccessCharCodes list of charcode candidates
-   * @param aIsTrusted true if triggered by a trusted key event
+   * @param aMatchesContentAccessKey true if the content accesskey modifier is pressed
    * @param aBubbledFrom is used by an ancestor to avoid calling HandleAccessKey()
    *        on the child the call originally came from, i.e. this is the child
    *        that recursively called us in its Up phase. The initial caller
    *        passes |nullptr| here. This is to avoid an infinite loop.
    * @param aAccessKeyState Normal, Down or Up processing phase (see enums
    *        above). The initial event receiver uses 'normal', then 'down' when
    *        processing children and Up when recursively calling its ancestor.
    * @param aModifierMask modifier mask for the key event
    */
-  bool HandleAccessKey(nsPresContext* aPresContext,
-                     nsTArray<uint32_t>& aAccessCharCodes,
-                     bool aIsTrusted,
-                     nsIDocShellTreeItem* aBubbledFrom,
-                     ProcessingAccessKeyState aAccessKeyState,
-                     int32_t aModifierMask);
+  bool HandleAccessKey(WidgetKeyboardEvent* aEvent,
+                       nsPresContext* aPresContext,
+                       nsTArray<uint32_t>& aAccessCharCodes,
+                       bool aMatchesContentAccessKey,
+                       nsIDocShellTreeItem* aBubbledFrom,
+                       ProcessingAccessKeyState aAccessKeyState,
+                       int32_t aModifierMask);
 
   bool ExecuteAccessKey(nsTArray<uint32_t>& aAccessCharCodes,
-                          bool aIsTrustedEvent);
+                        bool aIsTrustedEvent);
 
   //---------------------------------------------
   // DocShell Focus Traversal Methods
   //---------------------------------------------
 
   nsIContent* GetFocusedContent();
   bool IsShellVisible(nsIDocShell* aShell);
 
--- a/dom/events/KeyboardEvent.cpp
+++ b/dom/events/KeyboardEvent.cpp
@@ -193,16 +193,17 @@ KeyboardEvent::CharCode()
   case eKeyDownOnPlugin:
   case eAfterKeyDown:
   case eBeforeKeyUp:
   case eKeyUp:
   case eKeyUpOnPlugin:
   case eAfterKeyUp:
     return 0;
   case eKeyPress:
+  case eAccessKeyNotFound:
     return mEvent->AsKeyboardEvent()->charCode;
   default:
     break;
   }
   return 0;
 }
 
 NS_IMETHODIMP
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -501,16 +501,18 @@ parent:
     /**
      * Returns the number of tabs in the window via the out parameter.
      * If the number of tabs can't be determined, returns 0.
      *
      * @param aValue where to store the tab count
      */
     sync GetTabCount() returns (uint32_t value);
 
+    async AccessKeyNotHandled(WidgetKeyboardEvent event);
+
 child:
     async NativeSynthesisResponse(uint64_t aObserverId, nsCString aResponse);
 
 
 parent:
 
     /**
      * Child informs the parent that the graphics objects are ready for
@@ -741,21 +743,22 @@ child:
      * with another.
      */
     async SwappedWithOtherRemoteLoader(IPCTabContext context);
 
     /**
      * A potential accesskey was just pressed. Look for accesskey targets
      * using the list of provided charCodes.
      *
-     * @param charCode array of potential character codes
+     * @param event keyboard event
      * @param isTrusted true if triggered by a trusted key event
      * @param modifierMask indicates which accesskey modifiers are pressed
      */
-    async HandleAccessKey(uint32_t[] charCodes, bool isTrusted, int32_t modifierMask);
+    async HandleAccessKey(WidgetKeyboardEvent event,
+                          uint32_t[] charCodes, int32_t modifierMask);
 
     /**
      * Propagate a refresh to the child process
      */
     async AudioChannelChangeNotification(uint32_t aAudioChannel,
                                          float aVolume,
                                          bool aMuted);
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2119,20 +2119,27 @@ TabChild::RecvRealKeyEvent(const WidgetK
   WidgetKeyboardEvent localEvent(event);
   localEvent.mWidget = mPuppetWidget;
   nsEventStatus status = APZCCallbackHelper::DispatchWidgetEvent(localEvent);
 
   if (event.mMessage == eKeyDown) {
     mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault;
   }
 
+  // If a response is desired from the content process, resend the key event.
+  // If mAccessKeyForwardedToChild is set, then don't resend the key event yet
+  // as RecvHandleAccessKey will do this.
   if (localEvent.mFlags.mWantReplyFromContentProcess) {
     SendReplyKeyEvent(localEvent);
   }
 
+  if (localEvent.mAccessKeyForwardedToChild) {
+    SendAccessKeyNotHandled(localEvent);
+  }
+
   if (PresShell::BeforeAfterKeyboardEventEnabled()) {
     SendDispatchAfterKeyboardEvent(localEvent);
   }
 
   return true;
 }
 
 bool
@@ -2385,26 +2392,35 @@ TabChild::RecvSwappedWithOtherRemoteLoad
   nsContentUtils::FirePageShowEvent(ourDocShell, ourEventTarget, true);
 
   docShell->SetInFrameSwap(false);
 
   return true;
 }
 
 bool
-TabChild::RecvHandleAccessKey(nsTArray<uint32_t>&& aCharCodes,
-                              const bool& aIsTrusted,
+TabChild::RecvHandleAccessKey(const WidgetKeyboardEvent& aEvent,
+                              nsTArray<uint32_t>&& aCharCodes,
                               const int32_t& aModifierMask)
 {
   nsCOMPtr<nsIDocument> document(GetDocument());
   nsCOMPtr<nsIPresShell> presShell = document->GetShell();
   if (presShell) {
     nsPresContext* pc = presShell->GetPresContext();
     if (pc) {
-      pc->EventStateManager()->HandleAccessKey(pc, aCharCodes, aIsTrusted, aModifierMask);
+      if (!pc->EventStateManager()->
+                 HandleAccessKey(&(const_cast<WidgetKeyboardEvent&>(aEvent)),
+                                 pc, aCharCodes,
+                                 aModifierMask, true)) {
+        // If no accesskey was found, inform the parent so that accesskeys on
+        // menus can be handled.
+        WidgetKeyboardEvent localEvent(aEvent);
+        localEvent.mWidget = mPuppetWidget;
+        SendAccessKeyNotHandled(localEvent);
+      }
     }
   }
 
   return true;
 }
 
 bool
 TabChild::RecvAudioChannelChangeNotification(const uint32_t& aAudioChannel,
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -561,18 +561,18 @@ public:
   }
 
   virtual bool RecvUIResolutionChanged(const float& aDpi,
                                        const double& aScale) override;
 
   virtual bool
   RecvThemeChanged(nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache) override;
 
-  virtual bool RecvHandleAccessKey(nsTArray<uint32_t>&& aCharCodes,
-                                   const bool& aIsTrusted,
+  virtual bool RecvHandleAccessKey(const WidgetKeyboardEvent& aEvent,
+                                   nsTArray<uint32_t>&& aCharCodes,
                                    const int32_t& aModifierMask) override;
 
   virtual bool RecvAudioChannelChangeNotification(const uint32_t& aAudioChannel,
                                                   const float& aVolume,
                                                   const bool& aMuted) override;
 
   virtual bool RecvSetUseGlobalHistory(const bool& aUse) override;
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -983,22 +983,22 @@ TabParent::ThemeChanged()
     // LookAndFeel should have the up-to-date values, which we now
     // send down to the child. We do this for every remote tab for now,
     // but bug 1156934 has been filed to do it once per content process.
     Unused << SendThemeChanged(LookAndFeel::GetIntCache());
   }
 }
 
 void
-TabParent::HandleAccessKey(nsTArray<uint32_t>& aCharCodes,
-                           const bool& aIsTrusted,
+TabParent::HandleAccessKey(const WidgetKeyboardEvent& aEvent,
+                           nsTArray<uint32_t>& aCharCodes,
                            const int32_t& aModifierMask)
 {
   if (!mIsDestroyed) {
-    Unused << SendHandleAccessKey(aCharCodes, aIsTrusted, aModifierMask);
+    Unused << SendHandleAccessKey(aEvent, aCharCodes, aModifierMask);
   }
 }
 
 void
 TabParent::Activate()
 {
   if (!mIsDestroyed) {
     Unused << SendActivate();
@@ -2126,16 +2126,41 @@ TabParent::RecvDispatchAfterKeyboardEven
     presShell->DispatchAfterKeyboardEvent(mFrameElement, localEvent,
                                           aEvent.DefaultPrevented());
   }
 
   return true;
 }
 
 bool
+TabParent::RecvAccessKeyNotHandled(const WidgetKeyboardEvent& aEvent)
+{
+  NS_ENSURE_TRUE(mFrameElement, true);
+
+  WidgetKeyboardEvent localEvent(aEvent);
+  localEvent.mMessage = eAccessKeyNotFound;
+  localEvent.mAccessKeyForwardedToChild = false;
+
+  // Here we convert the WidgetEvent that we received to an nsIDOMEvent
+  // to be able to dispatch it to the <browser> element as the target element.
+  nsIDocument* doc = mFrameElement->OwnerDoc();
+  nsIPresShell* presShell = doc->GetShell();
+  NS_ENSURE_TRUE(presShell, true);
+
+  if (presShell->CanDispatchEvent()) {
+    nsPresContext* presContext = presShell->GetPresContext();
+    NS_ENSURE_TRUE(presContext, true);
+
+    EventDispatcher::Dispatch(mFrameElement, presContext, &localEvent);
+  }
+
+  return true;
+}
+
+bool
 TabParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return true;
   }
   if (NS_WARN_IF(!mContentCache.HandleQueryContentEvent(aEvent, widget)) ||
       NS_WARN_IF(!aEvent.mSucceeded)) {
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -169,16 +169,19 @@ public:
 
   virtual bool RecvEvent(const RemoteDOMEvent& aEvent) override;
 
   virtual bool RecvReplyKeyEvent(const WidgetKeyboardEvent& aEvent) override;
 
   virtual bool
   RecvDispatchAfterKeyboardEvent(const WidgetKeyboardEvent& aEvent) override;
 
+  virtual bool
+  RecvAccessKeyNotHandled(const WidgetKeyboardEvent& aEvent) override;
+
   virtual bool RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
                                           PRenderFrameParent* aRenderFrame,
                                           const nsString& aURL,
                                           const nsString& aName,
                                           const nsString& aFeatures,
                                           bool* aOutWindowOpened,
                                           TextureFactoryIdentifier* aTextureFactoryIdentifier,
                                           uint64_t* aLayersId) override;
@@ -359,18 +362,18 @@ public:
   void UpdateDimensions(const nsIntRect& aRect, const ScreenIntSize& aSize);
 
   void SizeModeChanged(const nsSizeMode& aSizeMode);
 
   void UIResolutionChanged();
 
   void ThemeChanged();
 
-  void HandleAccessKey(nsTArray<uint32_t>& aCharCodes,
-                       const bool& aIsTrusted,
+  void HandleAccessKey(const WidgetKeyboardEvent& aEvent,
+                       nsTArray<uint32_t>& aCharCodes,
                        const int32_t& aModifierMask);
 
   void Activate();
 
   void Deactivate();
 
   bool MapEventCoordinatesForChildProcess(mozilla::WidgetEvent* aEvent);
 
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -1591,20 +1591,21 @@ nsPresContext::ThemeChanged()
     nsCOMPtr<nsIRunnable> ev =
       NewRunnableMethod(this, &nsPresContext::ThemeChangedInternal);
     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
       mPendingThemeChanged = true;
     }
   }
 }
 
-static void
+static bool
 NotifyThemeChanged(TabParent* aTabParent, void* aArg)
 {
   aTabParent->ThemeChanged();
+  return false;
 }
 
 void
 nsPresContext::ThemeChangedInternal()
 {
   mPendingThemeChanged = false;
 
   // Tell the theme that it changed, so it can flush any handles to stale theme
@@ -1943,21 +1944,22 @@ nsPresContext::HandleMediaFeatureValuesC
 {
   // Null-check mShell in case the shell has been destroyed (and the
   // event is the only thing holding the pres context alive).
   if (mPendingMediaFeatureValuesChanged && mShell) {
     MediaFeatureValuesChanged(nsRestyleHint(0));
   }
 }
 
-static void
+static bool
 NotifyTabSizeModeChanged(TabParent* aTab, void* aArg)
 {
   nsSizeMode* sizeMode = static_cast<nsSizeMode*>(aArg);
   aTab->SizeModeChanged(*sizeMode);
+  return false;
 }
 
 void
 nsPresContext::SizeModeChanged(nsSizeMode aSizeMode)
 {
   if (HasCachedStyleData()) {
     nsContentUtils::CallOnAllRemoteChildren(mDocument->GetWindow(),
                                             NotifyTabSizeModeChanged,
--- a/layout/xul/nsMenuBarFrame.cpp
+++ b/layout/xul/nsMenuBarFrame.cpp
@@ -74,16 +74,17 @@ nsMenuBarFrame::Init(nsIContent*       a
   mTarget = aContent->GetComposedDoc();
 
   // Also hook up the listener to the window listening for focus events. This is so we can keep proper
   // state as the user alt-tabs through processes.
 
   mTarget->AddSystemEventListener(NS_LITERAL_STRING("keypress"), mMenuBarListener, false);
   mTarget->AddSystemEventListener(NS_LITERAL_STRING("keydown"), mMenuBarListener, false);
   mTarget->AddSystemEventListener(NS_LITERAL_STRING("keyup"), mMenuBarListener, false);
+  mTarget->AddSystemEventListener(NS_LITERAL_STRING("mozaccesskeynotfound"), mMenuBarListener, false);
 
   // mousedown event should be handled in all phase
   mTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, true);
   mTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, false);
   mTarget->AddEventListener(NS_LITERAL_STRING("blur"), mMenuBarListener, true);
 }
 
 NS_IMETHODIMP
@@ -411,16 +412,17 @@ nsMenuBarFrame::DestroyFrom(nsIFrame* aD
 {
   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
   if (pm)
     pm->SetActiveMenuBar(this, false);
 
   mTarget->RemoveSystemEventListener(NS_LITERAL_STRING("keypress"), mMenuBarListener, false);
   mTarget->RemoveSystemEventListener(NS_LITERAL_STRING("keydown"), mMenuBarListener, false);
   mTarget->RemoveSystemEventListener(NS_LITERAL_STRING("keyup"), mMenuBarListener, false);
+  mTarget->RemoveSystemEventListener(NS_LITERAL_STRING("mozaccesskeynotfound"), mMenuBarListener, false);
 
   mTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, true);
   mTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, false);
   mTarget->RemoveEventListener(NS_LITERAL_STRING("blur"), mMenuBarListener, true);
 
   mMenuBarListener->OnDestroyMenuBarFrame();
   mMenuBarListener = nullptr;
 
--- a/layout/xul/nsMenuBarListener.cpp
+++ b/layout/xul/nsMenuBarListener.cpp
@@ -194,93 +194,92 @@ nsMenuBarListener::KeyPress(nsIDOMEvent*
   }
 
   //handlers shouldn't be triggered by non-trusted events.
   bool trustedEvent = false;
   if (aKeyEvent) {
     aKeyEvent->GetIsTrusted(&trustedEvent);
   }
 
-  if (!trustedEvent)
+  if (!trustedEvent) {
     return NS_OK;
+  }
 
-  nsresult retVal = NS_OK;  // default is to not consume event
-  
   InitAccessKey();
 
   if (mAccessKey)
   {
-    bool preventDefault;
-    aKeyEvent->GetDefaultPrevented(&preventDefault);
-    if (!preventDefault) {
-      nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
-      uint32_t keyCode, charCode;
-      keyEvent->GetKeyCode(&keyCode);
-      keyEvent->GetCharCode(&charCode);
+    // If accesskey handling was forwarded to a child process, wait for
+    // the mozaccesskeynotfound event before handling accesskeys.
+    WidgetKeyboardEvent* nativeKeyEvent =
+      aKeyEvent->WidgetEventPtr()->AsKeyboardEvent();
+    if (nativeKeyEvent->mAccessKeyForwardedToChild) {
+      return NS_OK;
+    }
+
+    nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
+    uint32_t keyCode, charCode;
+    keyEvent->GetKeyCode(&keyCode);
+    keyEvent->GetCharCode(&charCode);
+
+    bool hasAccessKeyCandidates = charCode != 0;
+    if (!hasAccessKeyCandidates) {
+      if (nativeKeyEvent) {
+        AutoTArray<uint32_t, 10> keys;
+        nativeKeyEvent->GetAccessKeyCandidates(keys);
+        hasAccessKeyCandidates = !keys.IsEmpty();
+      }
+    }
+
+    // Cancel the access key flag unless we are pressing the access key.
+    if (keyCode != (uint32_t)mAccessKey) {
+      mAccessKeyDownCanceled = true;
+    }
 
-      bool hasAccessKeyCandidates = charCode != 0;
-      if (!hasAccessKeyCandidates) {
-        WidgetKeyboardEvent* nativeKeyEvent =
-          aKeyEvent->WidgetEventPtr()->AsKeyboardEvent();
-        if (nativeKeyEvent) {
-          AutoTArray<uint32_t, 10> keys;
-          nativeKeyEvent->GetAccessKeyCandidates(keys);
-          hasAccessKeyCandidates = !keys.IsEmpty();
+    if (IsAccessKeyPressed(keyEvent) && hasAccessKeyCandidates) {
+      // Do shortcut navigation.
+      // A letter was pressed. We want to see if a shortcut gets matched. If
+      // so, we'll know the menu got activated.
+      nsMenuFrame* result = mMenuBarFrame->FindMenuWithShortcut(keyEvent);
+      if (result) {
+        mMenuBarFrame->SetActiveByKeyboard();
+        mMenuBarFrame->SetActive(true);
+        result->OpenMenu(true);
+
+        // The opened menu will listen next keyup event.
+        // Therefore, we should clear the keydown flags here.
+        mAccessKeyDown = mAccessKeyDownCanceled = false;
+
+        aKeyEvent->StopPropagation();
+        aKeyEvent->PreventDefault();
+      }
+    }    
+#ifndef XP_MACOSX
+    // Also need to handle F10 specially on Non-Mac platform.
+    else if (nativeKeyEvent->mMessage == eKeyPress && keyCode == NS_VK_F10) {
+      if ((GetModifiersForAccessKey(keyEvent) & ~MODIFIER_CONTROL) == 0) {
+        // The F10 key just went down by itself or with ctrl pressed.
+        // In Windows, both of these activate the menu bar.
+        mMenuBarFrame->SetActiveByKeyboard();
+        ToggleMenuActiveState();
+
+        if (mMenuBarFrame->IsActive()) {
+#ifdef MOZ_WIDGET_GTK
+          // In GTK, this also opens the first menu.
+          mMenuBarFrame->GetCurrentMenuItem()->OpenMenu(true);
+#endif
+          aKeyEvent->StopPropagation();
+          aKeyEvent->PreventDefault();
         }
       }
-
-      // Cancel the access key flag unless we are pressing the access key.
-      if (keyCode != (uint32_t)mAccessKey) {
-        mAccessKeyDownCanceled = true;
-      }
-
-      if (IsAccessKeyPressed(keyEvent) && hasAccessKeyCandidates) {
-        // Do shortcut navigation.
-        // A letter was pressed. We want to see if a shortcut gets matched. If
-        // so, we'll know the menu got activated.
-        nsMenuFrame* result = mMenuBarFrame->FindMenuWithShortcut(keyEvent);
-        if (result) {
-          mMenuBarFrame->SetActiveByKeyboard();
-          mMenuBarFrame->SetActive(true);
-          result->OpenMenu(true);
-
-          // The opened menu will listen next keyup event.
-          // Therefore, we should clear the keydown flags here.
-          mAccessKeyDown = mAccessKeyDownCanceled = false;
-
-          aKeyEvent->StopPropagation();
-          aKeyEvent->PreventDefault();
-          retVal = NS_OK;       // I am consuming event
-        }
-      }    
-#ifndef XP_MACOSX
-      // Also need to handle F10 specially on Non-Mac platform.
-      else if (keyCode == NS_VK_F10) {
-        if ((GetModifiersForAccessKey(keyEvent) & ~MODIFIER_CONTROL) == 0) {
-          // The F10 key just went down by itself or with ctrl pressed.
-          // In Windows, both of these activate the menu bar.
-          mMenuBarFrame->SetActiveByKeyboard();
-          ToggleMenuActiveState();
-
-          if (mMenuBarFrame->IsActive()) {
-#ifdef MOZ_WIDGET_GTK
-            // In GTK, this also opens the first menu.
-            mMenuBarFrame->GetCurrentMenuItem()->OpenMenu(true);
-#endif
-            aKeyEvent->StopPropagation();
-            aKeyEvent->PreventDefault();
-            return NS_OK; // consume the event
-          }
-        }
-      }
+    }
 #endif // !XP_MACOSX
-    } 
   }
 
-  return retVal;
+  return NS_OK;
 }
 
 bool
 nsMenuBarListener::IsAccessKeyPressed(nsIDOMKeyEvent* aKeyEvent)
 {
   InitAccessKey();
   // No other modifiers are allowed to be down except for Shift.
   uint32_t modifiers = GetModifiersForAccessKey(aKeyEvent);
@@ -420,16 +419,19 @@ nsMenuBarListener::HandleEvent(nsIDOMEve
     return KeyUp(aEvent);
   }
   if (eventType.EqualsLiteral("keydown")) {
     return KeyDown(aEvent);
   }
   if (eventType.EqualsLiteral("keypress")) {
     return KeyPress(aEvent);
   }
+  if (eventType.EqualsLiteral("mozaccesskeynotfound")) {
+    return KeyPress(aEvent);
+  }
   if (eventType.EqualsLiteral("blur")) {
     return Blur(aEvent);
   }
   if (eventType.EqualsLiteral("mousedown")) {
     return MouseDown(aEvent);
   }
 
   NS_ABORT();
--- a/widget/EventMessageList.h
+++ b/widget/EventMessageList.h
@@ -47,16 +47,22 @@ NS_EVENT_MESSAGE(eKeyDown)
 NS_EVENT_MESSAGE(eKeyDownOnPlugin)
 NS_EVENT_MESSAGE(eKeyUpOnPlugin)
 
 NS_EVENT_MESSAGE(eBeforeKeyDown)
 NS_EVENT_MESSAGE(eAfterKeyDown)
 NS_EVENT_MESSAGE(eBeforeKeyUp)
 NS_EVENT_MESSAGE(eAfterKeyUp)
 
+// This message is sent after a content process handles a key event or accesskey
+// to indicate that an potential accesskey was not found. The parent process may
+// then respond by, for example, opening menus and processing other shortcuts.
+// It inherits its properties from a keypress event.
+NS_EVENT_MESSAGE(eAccessKeyNotFound)
+
 NS_EVENT_MESSAGE(eResize)
 NS_EVENT_MESSAGE(eScroll)
 
 // A plugin was clicked or otherwise focused. ePluginActivate should be
 // used when the window is not active. ePluginFocus should be used when
 // the window is active. In the latter case, the dispatcher of the event
 // is expected to ensure that the plugin's widget is focused beforehand.
 NS_EVENT_MESSAGE(ePluginActivate)
--- a/widget/TextEvents.h
+++ b/widget/TextEvents.h
@@ -105,16 +105,17 @@ protected:
     : keyCode(0)
     , charCode(0)
     , mPseudoCharCode(0)
     , location(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD)
     , isChar(false)
     , mIsRepeat(false)
     , mIsComposing(false)
     , mIsReserved(false)
+    , mAccessKeyForwardedToChild(false)
     , mKeyNameIndex(mozilla::KEY_NAME_INDEX_Unidentified)
     , mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN)
     , mNativeKeyEvent(nullptr)
     , mUniqueId(0)
 #ifdef XP_MACOSX
     , mNativeKeyCode(0)
     , mNativeModifierFlags(0)
 #endif
@@ -133,16 +134,17 @@ public:
     , keyCode(0)
     , charCode(0)
     , mPseudoCharCode(0)
     , location(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD)
     , isChar(false)
     , mIsRepeat(false)
     , mIsComposing(false)
     , mIsReserved(false)
+    , mAccessKeyForwardedToChild(false)
     , mKeyNameIndex(mozilla::KEY_NAME_INDEX_Unidentified)
     , mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN)
     , mNativeKeyEvent(nullptr)
     , mUniqueId(0)
 #ifdef XP_MACOSX
     , mNativeKeyCode(0)
     , mNativeModifierFlags(0)
 #endif
@@ -215,16 +217,21 @@ public:
   bool mIsRepeat;
   // Indicates whether the event is generated during IME (or deadkey)
   // composition.  This is initialized by EventStateManager.  So, key event
   // dispatchers don't need to initialize this.
   bool mIsComposing;
   // Indicates if the key combination is reserved by chrome.  This is set by
   // nsXBLWindowKeyHandler at capturing phase of the default event group.
   bool mIsReserved;
+  // True if accesskey handling was forwarded to the child via
+  // TabParent::HandleAccessKey. In this case, parent process menu access key
+  // handling should be delayed until it is determined that there exists no
+  // overriding access key in the content process.
+  bool mAccessKeyForwardedToChild;
   // DOM KeyboardEvent.key
   KeyNameIndex mKeyNameIndex;
   // DOM KeyboardEvent.code
   CodeNameIndex mCodeNameIndex;
   // DOM KeyboardEvent.key only when mKeyNameIndex is KEY_NAME_INDEX_USE_STRING.
   nsString mKeyValue;
   // DOM KeyboardEvent.code only when mCodeNameIndex is
   // CODE_NAME_INDEX_USE_STRING.
@@ -369,16 +376,17 @@ public:
     charCode = aEvent.charCode;
     mPseudoCharCode = aEvent.mPseudoCharCode;
     location = aEvent.location;
     alternativeCharCodes = aEvent.alternativeCharCodes;
     isChar = aEvent.isChar;
     mIsRepeat = aEvent.mIsRepeat;
     mIsComposing = aEvent.mIsComposing;
     mIsReserved = aEvent.mIsReserved;
+    mAccessKeyForwardedToChild = aEvent.mAccessKeyForwardedToChild;
     mKeyNameIndex = aEvent.mKeyNameIndex;
     mCodeNameIndex = aEvent.mCodeNameIndex;
     mKeyValue = aEvent.mKeyValue;
     mCodeValue = aEvent.mCodeValue;
     // Don't copy mNativeKeyEvent because it may be referred after its instance
     // is destroyed.
     mNativeKeyEvent = nullptr;
     mUniqueId = aEvent.mUniqueId;
--- a/widget/WidgetEventImpl.cpp
+++ b/widget/WidgetEventImpl.cpp
@@ -166,16 +166,17 @@ WidgetEvent::HasKeyEventMessage() const
     case eKeyPress:
     case eKeyUp:
     case eKeyDownOnPlugin:
     case eKeyUpOnPlugin:
     case eBeforeKeyDown:
     case eBeforeKeyUp:
     case eAfterKeyDown:
     case eAfterKeyUp:
+    case eAccessKeyNotFound:
       return true;
     default:
       return false;
   }
 }
 
 bool
 WidgetEvent::HasIMEEventMessage() const
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -394,16 +394,17 @@ struct ParamTraits<mozilla::WidgetKeyboa
     WriteParam(aMsg, aParam.mCodeValue);
     WriteParam(aMsg, aParam.keyCode);
     WriteParam(aMsg, aParam.charCode);
     WriteParam(aMsg, aParam.mPseudoCharCode);
     WriteParam(aMsg, aParam.alternativeCharCodes);
     WriteParam(aMsg, aParam.isChar);
     WriteParam(aMsg, aParam.mIsRepeat);
     WriteParam(aMsg, aParam.mIsReserved);
+    WriteParam(aMsg, aParam.mAccessKeyForwardedToChild);
     WriteParam(aMsg, aParam.location);
     WriteParam(aMsg, aParam.mUniqueId);
     WriteParam(aMsg, aParam.mIsSynthesizedByTIP);
     WriteParam(aMsg,
                static_cast<mozilla::WidgetKeyboardEvent::InputMethodAppStateType>
                  (aParam.mInputMethodAppState));
 #ifdef XP_MACOSX
     WriteParam(aMsg, aParam.mNativeKeyCode);
@@ -429,16 +430,17 @@ struct ParamTraits<mozilla::WidgetKeyboa
         ReadParam(aMsg, aIter, &aResult->mCodeValue) &&
         ReadParam(aMsg, aIter, &aResult->keyCode) &&
         ReadParam(aMsg, aIter, &aResult->charCode) &&
         ReadParam(aMsg, aIter, &aResult->mPseudoCharCode) &&
         ReadParam(aMsg, aIter, &aResult->alternativeCharCodes) &&
         ReadParam(aMsg, aIter, &aResult->isChar) &&
         ReadParam(aMsg, aIter, &aResult->mIsRepeat) &&
         ReadParam(aMsg, aIter, &aResult->mIsReserved) &&
+        ReadParam(aMsg, aIter, &aResult->mAccessKeyForwardedToChild) &&
         ReadParam(aMsg, aIter, &aResult->location) &&
         ReadParam(aMsg, aIter, &aResult->mUniqueId) &&
         ReadParam(aMsg, aIter, &aResult->mIsSynthesizedByTIP) &&
         ReadParam(aMsg, aIter, &inputMethodAppState)
 #ifdef XP_MACOSX
         && ReadParam(aMsg, aIter, &aResult->mNativeKeyCode)
         && ReadParam(aMsg, aIter, &aResult->mNativeModifierFlags)
         && ReadParam(aMsg, aIter, &aResult->mNativeCharacters)