Bug 1257759 part.9 Implement nsWindow::OnKeyEventInPluginProcess() on Windows r=jimm draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 15 Apr 2016 17:02:36 +0900
changeset 355643 387ce72dcea23a92bd8c774fc54a8bff8da6c844
parent 355642 361be61bc6ff0213e3386427878d2f81321ca0df
child 355644 b99f8057d5e93035a769af2506292ff7d2cb8f4a
push id16345
push usermasayuki@d-toybox.com
push dateSat, 23 Apr 2016 09:42:11 +0000
reviewersjimm
bugs1257759
milestone48.0a1
Bug 1257759 part.9 Implement nsWindow::OnKeyEventInPluginProcess() on Windows r=jimm Implementing nsWindow::OnWindowedPluginKeyEvent() on Windows. This patch makes NativeKey class dispatches eKeyDownOnPlugin and eKeyUpOnPlugin when the method is called. MozReview-Commit-ID: L8yRZvDaQKR
widget/windows/KeyboardLayout.cpp
widget/windows/KeyboardLayout.h
widget/windows/WinMessages.h
widget/windows/nsWindow.cpp
--- a/widget/windows/KeyboardLayout.cpp
+++ b/widget/windows/KeyboardLayout.cpp
@@ -674,16 +674,17 @@ VirtualKey::FillKbdState(PBYTE aKbdState
  * mozilla::widget::NativeKey
  *****************************************************************************/
 
 uint8_t NativeKey::sDispatchedKeyOfAppCommand = 0;
 
 NativeKey::NativeKey(nsWindowBase* aWidget,
                      const MSG& aMessage,
                      const ModifierKeyState& aModKeyState,
+                     HKL aOverrideKeyboardLayout,
                      nsTArray<FakeCharMsg>* aFakeCharMsgs)
   : mWidget(aWidget)
   , mDispatcher(aWidget->GetTextEventDispatcher())
   , mMsg(aMessage)
   , mDOMKeyCode(0)
   , mKeyNameIndex(KEY_NAME_INDEX_Unidentified)
   , mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN)
   , mModKeyState(aModKeyState)
@@ -696,35 +697,48 @@ NativeKey::NativeKey(nsWindowBase* aWidg
   , mIsDeadKey(false)
   , mFakeCharMsgs(aFakeCharMsgs && aFakeCharMsgs->Length() ?
                     aFakeCharMsgs : nullptr)
 {
   MOZ_ASSERT(aWidget);
   MOZ_ASSERT(mDispatcher);
   KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
   mKeyboardLayout = keyboardLayout->GetLayout();
+  if (aOverrideKeyboardLayout && mKeyboardLayout != aOverrideKeyboardLayout) {
+    keyboardLayout->OverrideLayout(aOverrideKeyboardLayout);
+    mKeyboardLayout = keyboardLayout->GetLayout();
+    MOZ_ASSERT(mKeyboardLayout == aOverrideKeyboardLayout);
+    mIsOverridingKeyboardLayout = true;
+  } else {
+    mIsOverridingKeyboardLayout = false;
+  }
 
   if (mMsg.message == WM_APPCOMMAND) {
     InitWithAppCommand();
     return;
   }
 
   mScanCode = WinUtils::GetScanCode(mMsg.lParam);
   mIsExtended = WinUtils::IsExtendedScanCode(mMsg.lParam);
   switch (mMsg.message) {
     case WM_KEYDOWN:
     case WM_SYSKEYDOWN:
+    case MOZ_WM_KEYDOWN:
     case WM_KEYUP:
-    case WM_SYSKEYUP: {
+    case WM_SYSKEYUP:
+    case MOZ_WM_KEYUP: {
       // If the key message is sent from other application like a11y tools, the
       // scancode value might not be set proper value.  Then, probably the value
       // is 0.
       // NOTE: If the virtual keycode can be caused by both non-extended key
       //       and extended key, the API returns the non-extended key's
       //       scancode.  E.g., VK_LEFT causes "4" key on numpad.
+      // NOTE: Cannot compute scancode from keycode if the key message comes
+      //       from plugin process since active keyboard layout may be
+      //       different.
       if (!mScanCode) {
         uint16_t scanCodeEx = ComputeScanCodeExFromVirtualKeyCode(mMsg.wParam);
         if (scanCodeEx) {
           mScanCode = static_cast<uint8_t>(scanCodeEx & 0xFF);
           uint8_t extended = static_cast<uint8_t>((scanCodeEx & 0xFF00) >> 8);
           mIsExtended = (extended == 0xE0) || (extended == 0xE1);
         }
       }
@@ -884,16 +898,24 @@ NativeKey::NativeKey(nsWindowBase* aWidg
   // modifier state if this key event won't cause text input actually.
   // They will be used for setting alternativeCharCodes in the callback
   // method which will be called by TextEventDispatcher.
   if (IsKeyDownMessage() && NeedsToHandleWithoutFollowingCharMessages()) {
     ComputeInputtingStringWithKeyboardLayout();
   }
 }
 
+NativeKey::~NativeKey()
+{
+  if (mIsOverridingKeyboardLayout) {
+    KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
+    keyboardLayout->RestoreLayout();
+  }
+}
+
 void
 NativeKey::InitWithAppCommand()
 {
   if (GET_DEVICE_LPARAM(mMsg.lParam) != FAPPCOMMAND_KEY) {
     return;
   }
 
   uint32_t appCommand = GET_APPCOMMAND_LPARAM(mMsg.lParam);
@@ -986,16 +1008,18 @@ NativeKey::InitWithAppCommand()
 }
 
 bool
 NativeKey::IsFollowedByDeadCharMessage() const
 {
   MSG nextMsg;
   if (mFakeCharMsgs) {
     nextMsg = mFakeCharMsgs->ElementAt(0).GetCharMsg(mMsg.hwnd);
+  } else if (IsKeyMessageOnPlugin()) {
+    return false;
   } else {
     if (!WinUtils::PeekMessage(&nextMsg, mMsg.hwnd, WM_KEYFIRST, WM_KEYLAST,
                                PM_NOREMOVE | PM_NOYIELD)) {
       return false;
     }
   }
   return IsDeadCharMessage(nextMsg);
 }
@@ -1178,22 +1202,24 @@ NativeKey::InitKeyEvent(WidgetKeyboardEv
     MOZ_CRASH("NativeKey tries to dispatch a key event on destroyed widget");
   }
 
   LayoutDeviceIntPoint point(0, 0);
   mWidget->InitEvent(aKeyEvent, &point);
 
   switch (aKeyEvent.mMessage) {
     case eKeyDown:
+    case eKeyDownOnPlugin:
       aKeyEvent.keyCode = mDOMKeyCode;
       // Unique id for this keydown event and its associated keypress.
       sUniqueKeyEventId++;
       aKeyEvent.mUniqueId = sUniqueKeyEventId;
       break;
     case eKeyUp:
+    case eKeyUpOnPlugin:
       aKeyEvent.keyCode = mDOMKeyCode;
       // Set defaultPrevented of the key event if the VK_MENU is not a system
       // key release, so that the menu bar does not trigger.  This helps avoid
       // triggering the menu bar for ALT key accelerators used in assistive
       // technologies such as Window-Eyes and ZoomText or for switching open
       // state of IME.
       if (mOriginalVirtualKeyCode == VK_MENU && mMsg.message != WM_SYSKEYUP) {
         aKeyEvent.PreventDefaultBeforeDispatch();
@@ -1457,60 +1483,68 @@ NativeKey::HandleKeyDownMessage(bool* aE
       sDispatchedKeyOfAppCommand == mOriginalVirtualKeyCode) {
     // The multimedia key event has already been dispatch from
     // HandleAppCommandMessage().
     sDispatchedKeyOfAppCommand = 0;
     return true;
   }
 
   bool defaultPrevented = false;
-  if (mFakeCharMsgs ||
+  if (mFakeCharMsgs || IsKeyMessageOnPlugin() ||
       !RedirectedKeyDownMessageManager::IsRedirectedMessage(mMsg)) {
     // Ignore [shift+]alt+space so the OS can handle it.
     if (mModKeyState.IsAlt() && !mModKeyState.IsControl() &&
         mVirtualKeyCode == VK_SPACE) {
       return false;
     }
 
     nsresult rv = mDispatcher->BeginNativeInputTransaction();
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return true;
     }
 
     bool isIMEEnabled = WinUtils::IsIMEEnabled(mWidget->GetInputContext());
-    WidgetKeyboardEvent keydownEvent(true, eKeyDown, mWidget);
+    EventMessage keyDownMessage =
+      IsKeyMessageOnPlugin() ? eKeyDownOnPlugin : eKeyDown;
+    WidgetKeyboardEvent keydownEvent(true, keyDownMessage, mWidget);
     nsEventStatus status = InitKeyEvent(keydownEvent, mModKeyState, &mMsg);
     bool dispatched =
       mDispatcher->DispatchKeyboardEvent(eKeyDown, keydownEvent, status,
                                          const_cast<NativeKey*>(this));
     if (aEventDispatched) {
       *aEventDispatched = dispatched;
     }
     if (!dispatched) {
       // If the keydown event wasn't fired, there must be composition.
       // we don't need to do anything anymore.
       return false;
     }
     defaultPrevented = status == nsEventStatus_eConsumeNoDefault;
 
+    // We don't need to handle key messages on plugin for eKeyPress since
+    // eKeyDownOnPlugin is handled as both eKeyDown and eKeyPress.
+    if (IsKeyMessageOnPlugin()) {
+      return defaultPrevented;
+    }
+
     if (mWidget->Destroyed()) {
       return true;
     }
 
     // If IMC wasn't associated to the window but is associated it now (i.e.,
     // focus is moved from a non-editable editor to an editor by keydown
     // event handler), WM_CHAR and WM_SYSCHAR shouldn't cause first character
     // inputting if IME is opened.  But then, we should redirect the native
     // keydown message to IME.
     // However, note that if focus has been already moved to another
     // application, we shouldn't redirect the message to it because the keydown
     // message is processed by us, so, nobody shouldn't process it.
     HWND focusedWnd = ::GetFocus();
-    if (!defaultPrevented && !mFakeCharMsgs && focusedWnd &&
-        !mWidget->PluginHasFocus() && !isIMEEnabled &&
+    if (!defaultPrevented && !mFakeCharMsgs && !IsKeyMessageOnPlugin() &&
+        focusedWnd && !mWidget->PluginHasFocus() && !isIMEEnabled &&
         WinUtils::IsIMEEnabled(mWidget->GetInputContext())) {
       RedirectedKeyDownMessageManager::RemoveNextCharMessage(focusedWnd);
 
       INPUT keyinput;
       keyinput.type = INPUT_KEYBOARD;
       keyinput.ki.wVk = mOriginalVirtualKeyCode;
       keyinput.ki.wScan = mScanCode;
       keyinput.ki.dwFlags = KEYEVENTF_SCANCODE;
@@ -1728,30 +1762,38 @@ NativeKey::HandleKeyUpMessage(bool* aEve
 
   nsresult rv = mDispatcher->BeginNativeInputTransaction();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return true;
   }
 
   WidgetKeyboardEvent keyupEvent(true, eKeyUp, mWidget);
   nsEventStatus status = InitKeyEvent(keyupEvent, mModKeyState, &mMsg);
+  EventMessage keyUpMessage = IsKeyMessageOnPlugin() ? eKeyUpOnPlugin : eKeyUp;
   bool dispatched =
     mDispatcher->DispatchKeyboardEvent(eKeyUp, keyupEvent, status,
                                        const_cast<NativeKey*>(this));
   if (aEventDispatched) {
     *aEventDispatched = dispatched;
   }
   return status == nsEventStatus_eConsumeNoDefault;
 }
 
 bool
 NativeKey::NeedsToHandleWithoutFollowingCharMessages() const
 {
   MOZ_ASSERT(IsKeyDownMessage());
 
+  // We cannot know following char messages of key messages in a plugin
+  // process.  So, let's compute the character to be inputted with every
+  // printable key should be computed with the keyboard layout.
+  if (IsKeyMessageOnPlugin()) {
+    return true;
+  }
+
   // Enter and backspace are always handled here to avoid for example the
   // confusion between ctrl-enter and ctrl-J.
   if (mDOMKeyCode == NS_VK_RETURN || mDOMKeyCode == NS_VK_BACK) {
     return true;
   }
 
   // If inputting two or more characters, should be dispatched after removing
   // whole following char messages.
@@ -1845,16 +1887,17 @@ NativeKey::MayBeSameCharMessage(const MS
     aCharMsg1.wParam == aCharMsg2.wParam &&
     (aCharMsg1.lParam & ~kScanCodeMask) == (aCharMsg2.lParam & ~kScanCodeMask);
 }
 
 bool
 NativeKey::GetFollowingCharMessage(MSG& aCharMsg) const
 {
   MOZ_ASSERT(IsKeyDownMessage());
+  MOZ_ASSERT(!IsKeyMessageOnPlugin());
 
   aCharMsg.message = WM_NULL;
 
   if (mFakeCharMsgs) {
     for (size_t i = 0; i < mFakeCharMsgs->Length(); i++) {
       FakeCharMsg& fakeCharMsg = mFakeCharMsgs->ElementAt(i);
       if (fakeCharMsg.mConsumed) {
         continue;
@@ -2055,16 +2098,17 @@ NativeKey::GetFollowingCharMessage(MSG& 
   MOZ_CRASH("We lost the following char message");
   return false;
 }
 
 bool
 NativeKey::DispatchPluginEventsAndDiscardsCharMessages() const
 {
   MOZ_ASSERT(IsKeyDownMessage());
+  MOZ_ASSERT(!IsKeyMessageOnPlugin());
 
   // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
   // They can be more than one because of:
   //  * Dead-keys not pairing with base character
   //  * Some keyboard layouts may map up to 4 characters to the single key
   bool anyCharMessagesRemoved = false;
   MSG msg;
   while (GetFollowingCharMessage(msg)) {
@@ -3315,16 +3359,18 @@ KeyboardLayout::SynthesizeNativeKeyEvent
 
   AutoTArray<KeyPair,10> keySequence;
   WinUtils::SetupKeyModifiersSequence(&keySequence, aModifierFlags);
   NS_ASSERTION(aNativeKeyCode >= 0 && aNativeKeyCode < 256,
                "Native VK key code out of range");
   keySequence.AppendElement(KeyPair(aNativeKeyCode, argumentKeySpecific));
 
   // Simulate the pressing of each modifier key and then the real key
+  // FYI: Each NativeKey instance here doesn't need to override keyboard layout
+  //      since this method overrides and restores the keyboard layout.
   for (uint32_t i = 0; i < keySequence.Length(); ++i) {
     uint8_t key = keySequence[i].mGeneral;
     uint8_t keySpecific = keySequence[i].mSpecific;
     kbdState[key] = 0x81; // key is down and toggled on if appropriate
     if (keySpecific) {
       kbdState[keySpecific] = 0x81;
     }
     ::SetKeyboardState(kbdState);
@@ -3356,17 +3402,17 @@ KeyboardLayout::SynthesizeNativeKeyEvent
       } else {
         AutoTArray<NativeKey::FakeCharMsg, 10> fakeCharMsgs;
         for (uint32_t j = 0; j < chars.Length(); j++) {
           NativeKey::FakeCharMsg* fakeCharMsg = fakeCharMsgs.AppendElement();
           fakeCharMsg->mCharCode = chars.CharAt(j);
           fakeCharMsg->mScanCode = scanCode;
           fakeCharMsg->mIsDeadKey = makeDeadCharMsg;
         }
-        NativeKey nativeKey(aWidget, keyDownMsg, modKeyState, &fakeCharMsgs);
+        NativeKey nativeKey(aWidget, keyDownMsg, modKeyState, 0, &fakeCharMsgs);
         bool dispatched;
         nativeKey.HandleKeyDownMessage(&dispatched);
         // If some char messages are not consumed, let's emulate the widget
         // receiving the message directly.
         for (uint32_t j = 1; j < fakeCharMsgs.Length(); j++) {
           if (fakeCharMsgs[j].mConsumed) {
             continue;
           }
--- a/widget/windows/KeyboardLayout.h
+++ b/widget/windows/KeyboardLayout.h
@@ -9,16 +9,17 @@
 #include "mozilla/RefPtr.h"
 #include "nscore.h"
 #include "nsString.h"
 #include "nsWindowBase.h"
 #include "nsWindowDefs.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/TextEventDispatcher.h"
+#include "mozilla/widget/WinMessages.h"
 #include "mozilla/widget/WinModifierKeyState.h"
 #include <windows.h>
 
 #define NS_NUM_OF_KEYS          70
 
 #define VK_OEM_1                0xBA   // ';:' for US
 #define VK_OEM_PLUS             0xBB   // '+' any country
 #define VK_OEM_COMMA            0xBC
@@ -165,17 +166,17 @@ public:
   const DeadKeyTable* MatchingDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
                                            uint32_t aEntries) const;
   inline char16_t GetCompositeChar(ShiftState aShiftState,
                                     char16_t aBaseChar) const;
   UniCharsAndModifiers GetNativeUniChars(ShiftState aShiftState) const;
   UniCharsAndModifiers GetUniChars(ShiftState aShiftState) const;
 };
 
-class MOZ_STACK_CLASS NativeKey
+class MOZ_STACK_CLASS NativeKey final
 {
   friend class KeyboardLayout;
 
 public:
   struct FakeCharMsg
   {
     UINT mCharCode;
     UINT mScanCode;
@@ -198,18 +199,21 @@ public:
       msg.pt.x = msg.pt.y = 0;
       return msg;
     }
   };
 
   NativeKey(nsWindowBase* aWidget,
             const MSG& aMessage,
             const ModifierKeyState& aModKeyState,
+            HKL aOverrideKeyboardLayout = 0,
             nsTArray<FakeCharMsg>* aFakeCharMsgs = nullptr);
 
+  ~NativeKey();
+
   /**
    * Handle WM_KEYDOWN message or WM_SYSKEYDOWN message.  The instance must be
    * initialized with WM_KEYDOWN or WM_SYSKEYDOWN.
    * Returns true if dispatched keydown event or keypress event is consumed.
    * Otherwise, false.
    */
   bool HandleKeyDownMessage(bool* aEventDispatched = nullptr) const;
 
@@ -287,16 +291,19 @@ private:
   WORD    mScanCode;
   bool    mIsExtended;
   bool    mIsDeadKey;
   // mIsPrintableKey is true if the key may be a printable key without
   // any modifier keys.  Otherwise, false.
   // Please note that the event may not cause any text input even if this
   // is true.  E.g., it might be dead key state or Ctrl key may be pressed.
   bool    mIsPrintableKey;
+  // mIsOverridingKeyboardLayout is true if the instance temporarily overriding
+  // keyboard layout with specified by the constructor.
+  bool    mIsOverridingKeyboardLayout;
 
   nsTArray<FakeCharMsg>* mFakeCharMsgs;
 
   // When a keydown event is dispatched at handling WM_APPCOMMAND, the computed
   // virtual keycode is set to this.  Even if we consume WM_APPCOMMAND message,
   // Windows may send WM_KEYDOWN and WM_KEYUP message for them.
   // At that time, we should not dispatch key events for them.
   static uint8_t sDispatchedKeyOfAppCommand;
@@ -315,16 +322,17 @@ private:
   {
     switch (mMsg.message) {
       case WM_KEYDOWN:
       case WM_SYSKEYDOWN:
       case WM_CHAR:
       case WM_SYSCHAR:
       case WM_DEADCHAR:
       case WM_SYSDEADCHAR:
+      case MOZ_WM_KEYDOWN:
         return ((mMsg.lParam & (1 << 30)) != 0);
       case WM_APPCOMMAND:
         if (mVirtualKeyCode) {
           // If we can map the WM_APPCOMMAND to a virtual keycode, we can trust
           // the result of GetKeyboardState().
           BYTE kbdState[256];
           memset(kbdState, 0, sizeof(kbdState));
           ::GetKeyboardState(kbdState);
@@ -350,21 +358,25 @@ private:
    * "Kakutei-Undo" of ATOK or WXG (both of them are Japanese IME) causes
    * strange WM_KEYDOWN/WM_KEYUP/WM_CHAR message pattern.  So, when this
    * returns true, the caller needs to be careful for processing the messages.
    */
   bool IsIMEDoingKakuteiUndo() const;
 
   bool IsKeyDownMessage() const
   {
-    return (mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN);
+    return (mMsg.message == WM_KEYDOWN ||
+            mMsg.message == WM_SYSKEYDOWN ||
+            mMsg.message == MOZ_WM_KEYDOWN);
   }
   bool IsKeyUpMessage() const
   {
-    return (mMsg.message == WM_KEYUP || mMsg.message == WM_SYSKEYUP);
+    return (mMsg.message == WM_KEYUP ||
+            mMsg.message == WM_SYSKEYUP ||
+            mMsg.message == MOZ_WM_KEYUP);
   }
   bool IsPrintableCharMessage(const MSG& aMSG) const
   {
     return IsPrintableCharMessage(aMSG.message);
   }
   bool IsPrintableCharMessage(UINT aMessage) const
   {
     return (aMessage == WM_CHAR || aMessage == WM_SYSCHAR);
@@ -390,16 +402,21 @@ private:
     return IsSysCharMessage(aMSG.message);
   }
   bool IsSysCharMessage(UINT aMessage) const
   {
     return (aMessage == WM_SYSCHAR || aMessage == WM_SYSDEADCHAR);
   }
   bool MayBeSameCharMessage(const MSG& aCharMsg1, const MSG& aCharMsg2) const;
   bool IsFollowedByDeadCharMessage() const;
+  bool IsKeyMessageOnPlugin() const
+  {
+    return (mMsg.message == MOZ_WM_KEYDOWN ||
+            mMsg.message == MOZ_WM_KEYUP);
+  }
 
   /**
    * GetFollowingCharMessage() returns following char message of handling
    * keydown event.  If the message is found, this method returns true.
    * Otherwise, returns false.
    *
    * WARNING: Even if this returns true, aCharMsg may be WM_NULL or its
    *          hwnd may be different window.
--- a/widget/windows/WinMessages.h
+++ b/widget/windows/WinMessages.h
@@ -29,18 +29,18 @@
 // If TSFTextStore needs to notify TSF/TIP of layout change later, this
 // message is posted.
 #define MOZ_WM_NOTIY_TSF_OF_LAYOUT_CHANGE (WM_APP+0x0315)
 // Internal message used in correcting backwards clock skew
 #define MOZ_WM_SKEWFIX                    (WM_APP+0x0316)
 // Internal message used for hiding the on-screen keyboard
 #define MOZ_WM_DISMISS_ONSCREEN_KEYBOARD  (WM_APP+0x0317)
 
-// Following MOZ_WM_*KEY* messages are used by PluginInstanceChild internally.
-// (never posted to the queue)
+// Following MOZ_WM_*KEY* messages are used by PluginInstanceChild and
+// NativeKey internally. (never posted to the queue)
 #define MOZ_WM_KEYDOWN                    (WM_APP+0x0318)
 #define MOZ_WM_KEYUP                      (WM_APP+0x0319)
 #define MOZ_WM_SYSKEYDOWN                 (WM_APP+0x031A)
 #define MOZ_WM_SYSKEYUP                   (WM_APP+0x031B)
 #define MOZ_WM_CHAR                       (WM_APP+0x031C)
 #define MOZ_WM_SYSCHAR                    (WM_APP+0x031D)
 #define MOZ_WM_DEADCHAR                   (WM_APP+0x031E)
 #define MOZ_WM_SYSDEADCHAR                (WM_APP+0x031F)
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -129,16 +129,17 @@
 #include "nsIWidgetListener.h"
 #include "mozilla/dom/Touch.h"
 #include "mozilla/gfx/2D.h"
 #include "nsToolkitCompsCID.h"
 #include "nsIAppStartup.h"
 #include "mozilla/WindowsVersion.h"
 #include "mozilla/TextEvents.h" // For WidgetKeyboardEvent
 #include "mozilla/TextEventDispatcherListener.h"
+#include "mozilla/widget/WinNativeEventData.h"
 #include "nsThemeConstants.h"
 #include "nsBidiKeyboard.h"
 
 #include "nsIGfxInfo.h"
 #include "nsUXThemeConstants.h"
 #include "KeyboardLayout.h"
 #include "nsNativeDragTarget.h"
 #include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN
@@ -7861,18 +7862,49 @@ nsWindow::DefaultProcOfPluginEvent(const
   CallWindowProcW(GetPrevWindowProc(), mWnd, pPluginEvent->event,
                   pPluginEvent->wParam, pPluginEvent->lParam);
 }
 
 nsresult
 nsWindow::OnWindowedPluginKeyEvent(const NativeEventData& aKeyEventData,
                                    nsIKeyEventInPluginCallback* aCallback)
 {
-  // TODO: Implement in the following patch.
-  return NS_ERROR_NOT_IMPLEMENTED;
+  if (NS_WARN_IF(!mWnd)) {
+    return NS_OK;
+  }
+  const WinNativeKeyEventData* eventData =
+    static_cast<const WinNativeKeyEventData*>(aKeyEventData);
+  switch (eventData->mMessage) {
+    case WM_KEYDOWN:
+    case WM_SYSKEYDOWN: {
+      MSG mozMsg =
+        WinUtils::InitMSG(MOZ_WM_KEYDOWN, eventData->mWParam,
+                          eventData->mLParam, mWnd);
+      ModifierKeyState modifierKeyState(eventData->mModifiers);
+      NativeKey nativeKey(this, mozMsg, modifierKeyState,
+                          eventData->GetKeyboardLayout());
+      return nativeKey.HandleKeyDownMessage() ? NS_SUCCESS_EVENT_CONSUMED :
+                                                NS_OK;
+    }
+    case WM_KEYUP:
+    case WM_SYSKEYUP: {
+      MSG mozMsg =
+        WinUtils::InitMSG(MOZ_WM_KEYUP, eventData->mWParam,
+                          eventData->mLParam, mWnd);
+      ModifierKeyState modifierKeyState(eventData->mModifiers);
+      NativeKey nativeKey(this, mozMsg, modifierKeyState,
+                          eventData->GetKeyboardLayout());
+      return nativeKey.HandleKeyUpMessage() ? NS_SUCCESS_EVENT_CONSUMED : NS_OK;
+    }
+    default:
+      // We shouldn't consume WM_*CHAR messages here even if the preceding
+      // keydown or keyup event on the plugin is consumed.  It should be
+      // managed in each plugin window rather than top level window.
+      return NS_OK;
+  }
 }
 
 /**************************************************************
  **************************************************************
  **
  ** BLOCK: ChildWindow impl.
  **
  ** Child window overrides.