Bug 855975 part.1 Make widget::KeyboardLayout a singleton class r=jimm
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 29 May 2013 15:34:47 +0900
changeset 133228 90a6e3a943b659c15337c7edd5f4ef2dd5771552
parent 133227 0d52ae944c001eadc3d5d3315b44fade8bce8e9c
child 133229 6919e1b2926e053f88ce168bd2f7613c1f47ea33
push id28671
push usermasayuki@d-toybox.com
push dateWed, 29 May 2013 06:35:17 +0000
treeherdermozilla-inbound@57461a161f93 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs855975
milestone24.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 855975 part.1 Make widget::KeyboardLayout a singleton class r=jimm
widget/windows/KeyboardLayout.cpp
widget/windows/KeyboardLayout.h
widget/windows/nsWidgetFactory.cpp
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
--- a/widget/windows/KeyboardLayout.cpp
+++ b/widget/windows/KeyboardLayout.cpp
@@ -376,22 +376,23 @@ VirtualKey::FillKbdState(PBYTE aKbdState
     aKbdState[VK_CAPITAL] &= ~0x01;
   }
 }
 
 /*****************************************************************************
  * mozilla::widget::NativeKey
  *****************************************************************************/
 
-NativeKey::NativeKey(const KeyboardLayout& aKeyboardLayout,
-                     nsWindow* aWindow,
-                     const MSG& aKeyOrCharMessage) :
+NativeKey::NativeKey(nsWindow* aWindow,
+                     const MSG& aKeyOrCharMessage,
+                     const ModifierKeyState& aModKeyState) :
   mDOMKeyCode(0), mMessage(aKeyOrCharMessage.message),
   mVirtualKeyCode(0), mOriginalVirtualKeyCode(0)
 {
+  KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
   mScanCode = WinUtils::GetScanCode(aKeyOrCharMessage.lParam);
   mIsExtended = WinUtils::IsExtendedScanCode(aKeyOrCharMessage.lParam);
   // On WinXP and WinServer2003, we cannot compute the virtual keycode for
   // extended keys due to the API limitation.
   bool canComputeVirtualKeyCodeFromScanCode =
     (!mIsExtended || WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION);
   switch (mMessage) {
     case WM_KEYDOWN:
@@ -481,17 +482,17 @@ NativeKey::NativeKey(const KeyboardLayou
       }
 
       NS_ASSERTION(!mVirtualKeyCode,
                    "mVirtualKeyCode has been computed already");
 
       // Otherwise, compute the virtual keycode with MapVirtualKeyEx().
       mVirtualKeyCode = static_cast<uint8_t>(
         ::MapVirtualKeyEx(GetScanCodeWithExtendedFlag(),
-                          MAPVK_VSC_TO_VK_EX, aKeyboardLayout.GetLayout()));
+                          MAPVK_VSC_TO_VK_EX, keyboardLayout->GetLayout()));
 
       // The result might be unexpected value due to the scan code is
       // wrong.  For example, any key messages can be generated by
       // SendMessage() or PostMessage() from applications.  So, it's possible
       // failure.  Then, let's respect the extended flag even if it might be
       // set intentionally.
       switch (mOriginalVirtualKeyCode) {
         case VK_CONTROL:
@@ -523,31 +524,33 @@ NativeKey::NativeKey(const KeyboardLayou
     case WM_SYSCHAR:
       // We cannot compute the virtual key code from WM_CHAR message on WinXP
       // if it's caused by an extended key.
       if (!canComputeVirtualKeyCodeFromScanCode) {
         break;
       }
       mVirtualKeyCode = mOriginalVirtualKeyCode = static_cast<uint8_t>(
         ::MapVirtualKeyEx(GetScanCodeWithExtendedFlag(),
-                          MAPVK_VSC_TO_VK_EX, aKeyboardLayout.GetLayout()));
+                          MAPVK_VSC_TO_VK_EX, keyboardLayout->GetLayout()));
       break;
     default:
       MOZ_NOT_REACHED("Unsupported message");
       break;
   }
 
   if (!mVirtualKeyCode) {
     mVirtualKeyCode = mOriginalVirtualKeyCode;
   }
 
   mDOMKeyCode =
-    aKeyboardLayout.ConvertNativeKeyCodeToDOMKeyCode(mOriginalVirtualKeyCode);
+    keyboardLayout->ConvertNativeKeyCodeToDOMKeyCode(mOriginalVirtualKeyCode);
   mKeyNameIndex =
-    aKeyboardLayout.ConvertNativeKeyCodeToKeyNameIndex(mOriginalVirtualKeyCode);
+    keyboardLayout->ConvertNativeKeyCodeToKeyNameIndex(mOriginalVirtualKeyCode);
+
+  keyboardLayout->InitNativeKey(*this, aModKeyState);
 }
 
 UINT
 NativeKey::GetScanCodeWithExtendedFlag() const
 {
   // MapVirtualKeyEx() has been improved for supporting extended keys since
   // Vista.  When we call it for mapping a scancode of an extended key and
   // a virtual keycode, we need to add 0xE000 to the scancode.
@@ -623,24 +626,43 @@ NativeKey::GetKeyLocation() const
       return nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD;
   }
 }
 
 /*****************************************************************************
  * mozilla::widget::KeyboardLayout
  *****************************************************************************/
 
+KeyboardLayout* KeyboardLayout::sInstance = nullptr;
+
+// static
+KeyboardLayout*
+KeyboardLayout::GetInstance()
+{
+  if (!sInstance) {
+    sInstance = new KeyboardLayout();
+  }
+  return sInstance;
+}
+
+// static
+void
+KeyboardLayout::Shutdown()
+{
+  delete sInstance;
+  sInstance = nullptr;
+}
+
 KeyboardLayout::KeyboardLayout() :
-  mKeyboardLayout(0), mPendingKeyboardLayout(0)
+  mKeyboardLayout(0), mIsOverridden(false),
+  mIsPendingToRestoreKeyboardLayout(false)
 {
   mDeadKeyTableListHead = nullptr;
 
-  // Note: Don't call LoadLayout from here. Because an instance of this class
-  // can be static. In that case, we cannot use any services in LoadLayout,
-  // e.g., pref service.
+  // NOTE: LoadLayout() should be called via OnLayoutChange().
 }
 
 KeyboardLayout::~KeyboardLayout()
 {
   ReleaseDeadKeyTables();
 }
 
 bool
@@ -661,18 +683,18 @@ KeyboardLayout::IsDeadKey(uint8_t aVirtu
   return mVirtualKeys[virtualKeyIndex].IsDeadKey(
            VirtualKey::ModifiersToShiftState(aModKeyState.GetModifiers()));
 }
 
 void
 KeyboardLayout::InitNativeKey(NativeKey& aNativeKey,
                               const ModifierKeyState& aModKeyState)
 {
-  if (mPendingKeyboardLayout) {
-    LoadLayout(mPendingKeyboardLayout);
+  if (mIsPendingToRestoreKeyboardLayout) {
+    LoadLayout(::GetKeyboardLayout(0));
   }
 
   uint8_t virtualKey = aNativeKey.GetOriginalVirtualKeyCode();
   int32_t virtualKeyIndex = GetKeyIndex(virtualKey);
 
   if (virtualKeyIndex < 0) {
     // Does not produce any printable characters, but still preserves the
     // dead-key state.
@@ -764,24 +786,19 @@ KeyboardLayout::GetUniCharsAndModifiers(
   if (key < 0) {
     return result;
   }
   return mVirtualKeys[key].
     GetUniChars(VirtualKey::ModifiersToShiftState(aModKeyState.GetModifiers()));
 }
 
 void
-KeyboardLayout::LoadLayout(HKL aLayout, bool aLoadLater)
+KeyboardLayout::LoadLayout(HKL aLayout)
 {
-  if (aLoadLater) {
-    mPendingKeyboardLayout = aLayout;
-    return;
-  }
-
-  mPendingKeyboardLayout = 0;
+  mIsPendingToRestoreKeyboardLayout = false;
 
   if (mKeyboardLayout == aLayout) {
     return;
   }
 
   mKeyboardLayout = aLayout;
 
   BYTE kbdState[256];
--- a/widget/windows/KeyboardLayout.h
+++ b/widget/windows/KeyboardLayout.h
@@ -267,28 +267,24 @@ public:
   const DeadKeyTable* MatchingDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
                                            uint32_t aEntries) const;
   inline PRUnichar GetCompositeChar(ShiftState aShiftState,
                                     PRUnichar aBaseChar) const;
   UniCharsAndModifiers GetNativeUniChars(ShiftState aShiftState) const;
   UniCharsAndModifiers GetUniChars(ShiftState aShiftState) const;
 };
 
-class NativeKey {
+class MOZ_STACK_CLASS NativeKey
+{
+  friend class KeyboardLayout;
+
 public:
-  NativeKey() :
-    mDOMKeyCode(0), mKeyNameIndex(KEY_NAME_INDEX_Unidentified),
-    mMessage(0), mVirtualKeyCode(0), mOriginalVirtualKeyCode(0),
-    mScanCode(0), mIsExtended(false)
-  {
-  }
-
-  NativeKey(const KeyboardLayout& aKeyboardLayout,
-            nsWindow* aWindow,
-            const MSG& aKeyOrCharMessage);
+  NativeKey(nsWindow* aWindow,
+            const MSG& aKeyOrCharMessage,
+            const ModifierKeyState& aModKeyState);
 
   uint32_t GetDOMKeyCode() const { return mDOMKeyCode; }
   KeyNameIndex GetKeyNameIndex() const { return mKeyNameIndex; }
   const UniCharsAndModifiers& GetCommittedCharsAndModifiers() const
   {
     return mCommittedCharsAndModifiers;
   }
 
@@ -320,37 +316,50 @@ private:
   // mCommittedChars indicates the inputted characters which is committed by
   // the key.  If dead key fail to composite a character, mCommittedChars
   // indicates both the dead characters and the base characters.
   UniCharsAndModifiers mCommittedCharsAndModifiers;
 
   WORD    mScanCode;
   bool    mIsExtended;
 
-  UINT GetScanCodeWithExtendedFlag() const;
+  NativeKey()
+  {
+    MOZ_NOT_REACHED("The default constructor of NativeKey isn't available");
+  }
 
-  friend class KeyboardLayout;
+  UINT GetScanCodeWithExtendedFlag() const;
 };
 
 class KeyboardLayout
 {
+  friend class NativeKey;
+
+private:
+  KeyboardLayout();
+  ~KeyboardLayout();
+
+  static KeyboardLayout* sInstance;
+
   struct DeadKeyTableListEntry
   {
     DeadKeyTableListEntry* next;
     uint8_t data[1];
   };
 
   HKL mKeyboardLayout;
-  HKL mPendingKeyboardLayout;
 
   VirtualKey mVirtualKeys[NS_NUM_OF_KEYS];
   DeadKeyTableListEntry* mDeadKeyTableListHead;
   int32_t mActiveDeadKey;                 // -1 = no active dead-key
   VirtualKey::ShiftState mDeadKeyShiftState;
 
+  bool mIsOverridden : 1;
+  bool mIsPendingToRestoreKeyboardLayout : 1;
+
   static inline int32_t GetKeyIndex(uint8_t aVirtualKey);
   static int CompareDeadKeyEntries(const void* aArg1, const void* aArg2,
                                    void* aData);
   static bool AddDeadKeyEntry(PRUnichar aBaseChar, PRUnichar aCompositeChar,
                                 DeadKeyEntry* aDeadKeyArray, uint32_t aEntries);
   bool EnsureDeadKeyActive(bool aIsActive, uint8_t aDeadKey,
                              const PBYTE aDeadKeyKbdState);
   uint32_t GetDeadKeyCombinations(uint8_t aDeadKey,
@@ -358,19 +367,34 @@ class KeyboardLayout
                                   uint16_t aShiftStatesWithBaseChars,
                                   DeadKeyEntry* aDeadKeyArray,
                                   uint32_t aMaxEntries);
   void DeactivateDeadKeyState();
   const DeadKeyTable* AddDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
                                       uint32_t aEntries);
   void ReleaseDeadKeyTables();
 
+  /**
+   * Loads the specified keyboard layout. This method always clear the dead key
+   * state.
+   */
+  void LoadLayout(HKL aLayout);
+
+  /**
+   * InitNativeKey() must be called when actually widget receives WM_KEYDOWN or
+   * WM_KEYUP.  This method is stateful.  This saves current dead key state at
+   * WM_KEYDOWN.  Additionally, computes current inputted character(s) and set
+   * them to the aNativeKey.
+   */
+  void InitNativeKey(NativeKey& aNativeKey,
+                     const ModifierKeyState& aModKeyState);
+
 public:
-  KeyboardLayout();
-  ~KeyboardLayout();
+  static KeyboardLayout* GetInstance();
+  static void Shutdown();
 
   static bool IsPrintableCharKey(uint8_t aVirtualKey);
 
   /**
    * IsDeadKey() returns true if aVirtualKey is a dead key with aModKeyState.
    * This method isn't stateful.
    */
   bool IsDeadKey(uint8_t aVirtualKey,
@@ -380,40 +404,56 @@ public:
    * GetUniCharsAndModifiers() returns characters which is inputted by the
    * aVirtualKey with aModKeyState.  This method isn't stateful.
    */
   UniCharsAndModifiers GetUniCharsAndModifiers(
                          uint8_t aVirtualKey,
                          const ModifierKeyState& aModKeyState) const;
 
   /**
-   * InitNativeKey() must be called when actually widget receives WM_KEYDOWN or
-   * WM_KEYUP.  This method is stateful.  This saves current dead key state at
-   * WM_KEYDOWN.  Additionally, computes current inputted character(s) and set
-   * them to the aNativeKey.
+   * OnLayoutChange() must be called before the first keydown message is
+   * received.  LoadLayout() changes the keyboard state, that causes breaking
+   * dead key state.  Therefore, we need to load the layout before the first
+   * keydown message.
    */
-  void InitNativeKey(NativeKey& aNativeKey,
-                     const ModifierKeyState& aModKeyState);
+  void OnLayoutChange(HKL aKeyboardLayout)
+  {
+    MOZ_ASSERT(!mIsOverridden);
+    LoadLayout(aKeyboardLayout);
+  }
 
   /**
-   * LoadLayout() loads the keyboard layout.  If aLoadLater is true,
-   * it will be done when OnKeyDown() is called.
+   * OverrideLayout() loads the specified keyboard layout.
    */
-  void LoadLayout(HKL aLayout, bool aLoadLater = false);
+  void OverrideLayout(HKL aLayout)
+  {
+    mIsOverridden = true;
+    LoadLayout(aLayout);
+  }
+
+  /**
+   * RestoreLayout() loads the current keyboard layout of the thread.
+   */
+  void RestoreLayout()
+  {
+    mIsOverridden = false;
+    mIsPendingToRestoreKeyboardLayout = true;
+  }
 
   uint32_t ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const;
 
   /**
    * ConvertNativeKeyCodeToKeyNameIndex() returns KeyNameIndex value for
    * non-printable keys (except some special keys like space key).
    */
   KeyNameIndex ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const;
 
   HKL GetLayout() const
   {
-    return mPendingKeyboardLayout ? mPendingKeyboardLayout : mKeyboardLayout;
+    return mIsPendingToRestoreKeyboardLayout ? ::GetKeyboardLayout(0) :
+                                               mKeyboardLayout;
   }
 };
 
 } // namespace widget
 } // namespace mozilla
 
 #endif
--- a/widget/windows/nsWidgetFactory.cpp
+++ b/widget/windows/nsWidgetFactory.cpp
@@ -12,16 +12,17 @@
 #include "nsAppShellSingleton.h"
 #include "mozilla/ModuleUtils.h"
 #include "nsIServiceManager.h"
 #include "nsIdleServiceWin.h"
 #include "nsLookAndFeel.h"
 #include "nsScreenManagerWin.h"
 #include "nsSound.h"
 #include "WinMouseScrollHandler.h"
+#include "KeyboardLayout.h"
 #include "GfxInfo.h"
 #include "nsToolkit.h"
 
 // Modules that switch out based on the environment
 #include "nsXULAppAPI.h"
 // Desktop
 #include "nsFilePicker.h" // needs to be included before other shobjidl.h includes
 #include "nsNativeThemeWin.h"
@@ -254,16 +255,17 @@ static const mozilla::Module::ContractID
   { "@mozilla.org/gfx/devicecontextspec;1", &kNS_DEVICE_CONTEXT_SPEC_CID },
 #endif
   { NULL }
 };
 
 static void
 nsWidgetWindowsModuleDtor()
 {
+  KeyboardLayout::Shutdown();
   MouseScrollHandler::Shutdown();
   nsLookAndFeel::Shutdown();
   nsToolkit::Shutdown();
   nsAppShellShutdown();
 }
 
 static const mozilla::Module kWidgetModule = {
   mozilla::Module::kVersion,
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -243,19 +243,16 @@ MSG             nsWindow::sRedirectedKey
  **************************************************************/
 
 static const char *sScreenManagerContractID       = "@mozilla.org/gfx/screenmanager;1";
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* gWindowsLog                      = nullptr;
 #endif
 
-// Kbd layout. Used throughout character processing.
-static KeyboardLayout gKbdLayout;
-
 // Global used in Show window enumerations.
 static bool     gWindowsVisible                   = false;
 
 // True if we have sent a notification that we are suspending/sleeping.
 static bool     gIsSleepMode                      = false;
 
 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
 
@@ -351,17 +348,17 @@ nsWindow::nsWindow() : nsWindowBase()
   mTaskbarPreview = nullptr;
   mHasTaskbarIconBeenCreated = false;
 
   // Global initialization
   if (!sInstanceCount) {
     // Global app registration id for Win7 and up. See
     // WinTaskbar.cpp for details.
     mozilla::widget::WinTaskbar::RegisterAppUserModelID();
-    gKbdLayout.LoadLayout(::GetKeyboardLayout(0));
+    KeyboardLayout::GetInstance()->OnLayoutChange(::GetKeyboardLayout(0));
     IMEHandler::Initialize();
     if (SUCCEEDED(::OleInitialize(NULL))) {
       sIsOleInitialized = TRUE;
     }
     NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n");
     MouseScrollHandler::Initialize();
     // Init titlebar button info for custom frames.
     nsUXThemeData::InitTitlebarInfo();
@@ -5105,17 +5102,17 @@ bool nsWindow::ProcessMessage(UINT msg, 
           // when minimizing a window, the deactivation and focus events will
           // be fired in the reverse order. Instead, just deactivate right away.
           if (HIWORD(wParam))
             DispatchFocusToTopLevelWindow(false);
           else
             sJustGotDeactivate = true;
 
           if (mIsTopWidgetWindow)
-            mLastKeyboardLayout = gKbdLayout.GetLayout();
+            mLastKeyboardLayout = KeyboardLayout::GetInstance()->GetLayout();
 
         } else {
           StopFlashing();
 
           sJustGotActivate = true;
           nsMouseEvent event(true, NS_MOUSE_ACTIVATE, this,
                              nsMouseEvent::eReal);
           InitEvent(event);
@@ -5190,17 +5187,19 @@ bool nsWindow::ProcessMessage(UINT msg, 
     break;
 
     case WM_INPUTLANGCHANGEREQUEST:
       *aRetValue = TRUE;
       result = false;
       break;
 
     case WM_INPUTLANGCHANGE:
-      result = OnInputLangChange((HKL)lParam);
+      KeyboardLayout::GetInstance()->
+        OnLayoutChange(reinterpret_cast<HKL>(lParam));
+      result = false; // always pass to child window
       break;
 
     case WM_DESTROYCLIPBOARD:
     {
       nsIClipboard* clipboard;
       nsresult rv = CallGetService(kCClipboardCID, &clipboard);
       if(NS_SUCCEEDED(rv)) {
         clipboard->EmptyClipboard(nsIClipboard::kGlobalClipboard);
@@ -5651,18 +5650,17 @@ LRESULT nsWindow::ProcessCharMessage(con
   PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
          ("%s charCode=%d scanCode=%d\n",
           aMsg.message == WM_SYSCHAR ? "WM_SYSCHAR" : "WM_CHAR",
           aMsg.wParam, HIWORD(aMsg.lParam) & 0xFF));
 
   // These must be checked here too as a lone WM_CHAR could be received
   // if a child window didn't handle it (for example Alt+Space in a content window)
   ModifierKeyState modKeyState;
-  NativeKey nativeKey(gKbdLayout, this, aMsg);
-  gKbdLayout.InitNativeKey(nativeKey, modKeyState);
+  NativeKey nativeKey(this, aMsg, modKeyState);
   return OnChar(aMsg, nativeKey, modKeyState, aEventDispatched);
 }
 
 LRESULT nsWindow::ProcessKeyUpMessage(const MSG &aMsg, bool *aEventDispatched)
 {
   NS_PRECONDITION(aMsg.message == WM_KEYUP || aMsg.message == WM_SYSKEYUP,
                   "message is not keydown event");
   PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
@@ -5785,18 +5783,19 @@ nsWindow::SynthesizeNativeKeyEvent(int32
   // Setup clean key state and load desired layout
   BYTE originalKbdState[256];
   ::GetKeyboardState(originalKbdState);
   BYTE kbdState[256];
   memset(kbdState, 0, sizeof(kbdState));
   // This changes the state of the keyboard for the current thread only,
   // and we'll restore it soon, so this should be OK.
   ::SetKeyboardState(kbdState);
-  HKL oldLayout = gKbdLayout.GetLayout();
-  gKbdLayout.LoadLayout(loadedLayout);
+
+  KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
+  keyboardLayout->OverrideLayout(loadedLayout);
 
   uint8_t argumentKeySpecific = 0;
   switch (aNativeKeyCode) {
     case VK_SHIFT:
       aModifierFlags &= ~(nsIWidget::SHIFT_L | nsIWidget::SHIFT_R);
       argumentKeySpecific = VK_LSHIFT;
       break;
     case VK_LSHIFT:
@@ -5860,45 +5859,46 @@ nsWindow::SynthesizeNativeKeyEvent(int32
     kbdState[key] = 0x81; // key is down and toggled on if appropriate
     if (keySpecific) {
       kbdState[keySpecific] = 0x81;
     }
     ::SetKeyboardState(kbdState);
     ModifierKeyState modKeyState;
     UINT scanCode = ::MapVirtualKeyEx(argumentKeySpecific ?
                                         argumentKeySpecific : aNativeKeyCode,
-                                      MAPVK_VK_TO_VSC, gKbdLayout.GetLayout());
+                                      MAPVK_VK_TO_VSC,
+                                      keyboardLayout->GetLayout());
     LPARAM lParam = static_cast<LPARAM>(scanCode << 16);
     // Add extended key flag to the lParam for right control key and right alt
     // key.
     if (keySpecific == VK_RCONTROL || keySpecific == VK_RMENU) {
       lParam |= 0x1000000;
     }
     MSG msg = WinUtils::InitMSG(WM_KEYDOWN, key, lParam);
     if (i == keySequence.Length() - 1) {
       bool makeDeadCharMessage =
-        gKbdLayout.IsDeadKey(key, modKeyState) && aCharacters.IsEmpty();
+        keyboardLayout->IsDeadKey(key, modKeyState) && aCharacters.IsEmpty();
       nsAutoString chars(aCharacters);
       if (makeDeadCharMessage) {
         UniCharsAndModifiers deadChars =
-          gKbdLayout.GetUniCharsAndModifiers(key, modKeyState);
+          keyboardLayout->GetUniCharsAndModifiers(key, modKeyState);
         chars = deadChars.ToString();
         NS_ASSERTION(chars.Length() == 1,
                      "Dead char must be only one character");
       }
       if (chars.IsEmpty()) {
         OnKeyDown(msg, modKeyState, nullptr, nullptr);
       } else {
         nsFakeCharMessage fakeMsg = { chars.CharAt(0), scanCode,
                                       makeDeadCharMessage };
         OnKeyDown(msg, modKeyState, nullptr, &fakeMsg);
         for (uint32_t j = 1; j < chars.Length(); j++) {
           nsFakeCharMessage fakeMsg = { chars.CharAt(j), scanCode, false };
           MSG msg = fakeMsg.GetCharMessage(mWnd);
-          NativeKey nativeKey(gKbdLayout, this, msg);
+          NativeKey nativeKey(this, msg, modKeyState);
           OnChar(msg, nativeKey, modKeyState, nullptr);
         }
       }
     } else {
       OnKeyDown(msg, modKeyState, nullptr, nullptr);
     }
   }
   for (uint32_t i = keySequence.Length(); i > 0; --i) {
@@ -5907,30 +5907,31 @@ nsWindow::SynthesizeNativeKeyEvent(int32
     kbdState[key] = 0; // key is up and toggled off if appropriate
     if (keySpecific) {
       kbdState[keySpecific] = 0;
     }
     ::SetKeyboardState(kbdState);
     ModifierKeyState modKeyState;
     UINT scanCode = ::MapVirtualKeyEx(argumentKeySpecific ?
                                         argumentKeySpecific : aNativeKeyCode,
-                                      MAPVK_VK_TO_VSC, gKbdLayout.GetLayout());
+                                      MAPVK_VK_TO_VSC,
+                                      keyboardLayout->GetLayout());
     LPARAM lParam = static_cast<LPARAM>(scanCode << 16);
     // Add extended key flag to the lParam for right control key and right alt
     // key.
     if (keySpecific == VK_RCONTROL || keySpecific == VK_RMENU) {
       lParam |= 0x1000000;
     }
     MSG msg = WinUtils::InitMSG(WM_KEYUP, key, lParam);
     OnKeyUp(msg, modKeyState, nullptr);
   }
 
   // Restore old key state and layout
   ::SetKeyboardState(originalKbdState);
-  gKbdLayout.LoadLayout(oldLayout, true);
+  keyboardLayout->RestoreLayout();
 
   // Don't unload the layout if it's installed actually.
   for (uint32_t i = 0; i < keyboardLayoutListCount; i++) {
     if (keyboardLayoutList[i] == loadedLayout) {
       loadedLayout = 0;
       break;
     }
   }
@@ -5980,25 +5981,16 @@ nsWindow::SynthesizeNativeMouseScrollEve
  *
  * SECTION: OnXXX message handlers
  *
  * For message handlers that need to be broken out or
  * implemented in specific platform code.
  *
  **************************************************************/
 
-BOOL nsWindow::OnInputLangChange(HKL aHKL)
-{
-#ifdef KE_DEBUG
-  PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("OnInputLanguageChange\n"));
-#endif
-  gKbdLayout.LoadLayout(aHKL);
-  return false;   // always pass to child window
-}
-
 void nsWindow::OnWindowPosChanged(WINDOWPOS *wp, bool& result)
 {
   if (wp == nullptr)
     return;
 
 #ifdef WINSTATE_DEBUG_OUTPUT
   if (mWnd == WinUtils::GetTopLevelHWND(mWnd)) {
     PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("*** OnWindowPosChanged: [  top] "));
@@ -6459,18 +6451,18 @@ bool nsWindow::IsRedirectedKeyDownMessag
  * that as if it was in the message queue, and refrain from actually
  * looking at or touching the message queue.
  */
 LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
                             const ModifierKeyState &aModKeyState,
                             bool *aEventDispatched,
                             nsFakeCharMessage* aFakeCharMessage)
 {
-  NativeKey nativeKey(gKbdLayout, this, aMsg);
-  gKbdLayout.InitNativeKey(nativeKey, aModKeyState);
+  KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
+  NativeKey nativeKey(this, aMsg, aModKeyState);
   UniCharsAndModifiers inputtingChars =
     nativeKey.GetCommittedCharsAndModifiers();
   uint32_t DOMKeyCode = nativeKey.GetDOMKeyCode();
 
 #ifdef DEBUG
   //PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("In OnKeyDown virt: %d\n", DOMKeyCode));
 #endif
 
@@ -6551,17 +6543,17 @@ LRESULT nsWindow::OnKeyDown(const MSG &a
     case NS_VK_CAPS_LOCK:
     case NS_VK_NUM_LOCK:
     case NS_VK_SCROLL_LOCK:
     case NS_VK_WIN:
       return noDefault;
   }
 
   UINT virtualKeyCode = nativeKey.GetOriginalVirtualKeyCode();
-  bool isDeadKey = gKbdLayout.IsDeadKey(virtualKeyCode, aModKeyState);
+  bool isDeadKey = keyboardLayout->IsDeadKey(virtualKeyCode, aModKeyState);
   EventFlags extraFlags;
   extraFlags.mDefaultPrevented = noDefault;
   MSG msg;
   BOOL gotMsg = aFakeCharMessage ||
     WinUtils::PeekMessage(&msg, mWnd, WM_KEYFIRST, WM_KEYLAST,
                           PM_NOREMOVE | PM_NOYIELD);
   // Enter and backspace are always handled here to avoid for example the
   // confusion between ctrl-enter and ctrl-J.
@@ -6676,20 +6668,20 @@ LRESULT nsWindow::OnKeyDown(const MSG &a
   if (!KeyboardLayout::IsPrintableCharKey(virtualKeyCode)) {
     inputtingChars.Clear();
   }
 
   if (aModKeyState.IsControl() ^ aModKeyState.IsAlt()) {
     widget::ModifierKeyState capsLockState(
       aModKeyState.GetModifiers() & MODIFIER_CAPSLOCK);
     unshiftedChars =
-      gKbdLayout.GetUniCharsAndModifiers(virtualKeyCode, capsLockState);
+      keyboardLayout->GetUniCharsAndModifiers(virtualKeyCode, capsLockState);
     capsLockState.Set(MODIFIER_SHIFT);
     shiftedChars =
-      gKbdLayout.GetUniCharsAndModifiers(virtualKeyCode, capsLockState);
+      keyboardLayout->GetUniCharsAndModifiers(virtualKeyCode, capsLockState);
 
     // The current keyboard cannot input alphabets or numerics,
     // we should append them for Shortcut/Access keys.
     // E.g., for Cyrillic keyboard layout.
     capsLockState.Unset(MODIFIER_SHIFT);
     WidgetUtils::GetLatinCharCodeForKeyCode(DOMKeyCode,
                                             capsLockState.GetModifiers(),
                                             &unshiftedLatinChar,
@@ -6826,18 +6818,17 @@ LRESULT nsWindow::OnKeyUp(const MSG &aMs
 {
   // NOTE: VK_PROCESSKEY never comes with WM_KEYUP
   PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
          ("nsWindow::OnKeyUp wParam(VK)=%d\n", aMsg.wParam));
 
   if (aEventDispatched)
     *aEventDispatched = true;
   nsKeyEvent keyupEvent(true, NS_KEY_UP, this);
-  NativeKey nativeKey(gKbdLayout, this, aMsg);
-  gKbdLayout.InitNativeKey(nativeKey, aModKeyState);
+  NativeKey nativeKey(this, aMsg, aModKeyState);
   keyupEvent.keyCode = nativeKey.GetDOMKeyCode();
   InitKeyEvent(keyupEvent, nativeKey, aModKeyState);
   // 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.
   keyupEvent.mFlags.mDefaultPrevented =
@@ -6895,24 +6886,25 @@ LRESULT nsWindow::OnChar(const MSG &aMsg
     } else {
       uniChar = charCode;
     }
   }
 
   // Keep the characters unshifted for shortcuts and accesskeys and make sure
   // that numbers are always passed as such (among others: bugs 50255 and 351310)
   if (uniChar && (modKeyState.IsControl() || modKeyState.IsAlt())) {
-    UINT virtualKeyCode = ::MapVirtualKeyEx(aNativeKey.GetScanCode(),
-                                            MAPVK_VSC_TO_VK,
-                                            gKbdLayout.GetLayout());
+    KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
+    UINT virtualKeyCode =
+      ::MapVirtualKeyEx(aNativeKey.GetScanCode(),
+                        MAPVK_VSC_TO_VK, keyboardLayout->GetLayout());
     UINT unshiftedCharCode =
       virtualKeyCode >= '0' && virtualKeyCode <= '9' ? virtualKeyCode :
-        modKeyState.IsShift() ? ::MapVirtualKeyEx(virtualKeyCode,
-                                                  MAPVK_VK_TO_CHAR,
-                                                  gKbdLayout.GetLayout()) : 0;
+        modKeyState.IsShift() ?
+          ::MapVirtualKeyEx(virtualKeyCode, MAPVK_VK_TO_CHAR,
+                            keyboardLayout->GetLayout()) : 0;
     // ignore diacritics (top bit set) and key mapping errors (char code 0)
     if ((INT)unshiftedCharCode > 0)
       uniChar = unshiftedCharCode;
   }
 
   // Fix for bug 285161 (and 295095) which was caused by the initial fix for bug 178110.
   // When pressing (alt|ctrl)+char, the char must be lowercase unless shift is
   // pressed too.
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -383,17 +383,16 @@ protected:
                                     bool *aEventDispatched,
                                     nsFakeCharMessage* aFakeCharMessage);
   LRESULT                 OnKeyUp(const MSG &aMsg,
                                   const mozilla::widget::ModifierKeyState &aModKeyState,
                                   bool *aEventDispatched);
   bool                    OnGesture(WPARAM wParam, LPARAM lParam);
   bool                    OnTouch(WPARAM wParam, LPARAM lParam);
   bool                    OnHotKey(WPARAM wParam, LPARAM lParam);
-  BOOL                    OnInputLangChange(HKL aHKL);
   bool                    OnPaint(HDC aDC, uint32_t aNestingLevel);
   void                    OnWindowPosChanged(WINDOWPOS *wp, bool& aResult);
   void                    OnWindowPosChanging(LPWINDOWPOS& info);
   void                    OnSysColorChanged();
 
   /**
    * Function that registers when the user has been active (used for detecting
    * when the user is idle).