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 296996 1b02f9d6c0586c7d7db405b3fc1ad4347503a180
parent 296995 ece69108baefc705cf2f7fd2802119fe883f80d0
child 296997 dddeac9ffc39e1a42b3ce866b6edd0b419be5c32
push id30251
push usercbook@mozilla.com
push dateThu, 12 May 2016 09:54:48 +0000
treeherdermozilla-central@c3f5e6079284 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmasayuki
bugs1101975
milestone49.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 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)