widget/windows/KeyboardLayout.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "mozilla/ArrayUtils.h"
     7 #include "mozilla/DebugOnly.h"
     8 #include "mozilla/MouseEvents.h"
     9 #include "mozilla/TextEvents.h"
    10 #include "mozilla/WindowsVersion.h"
    12 #include "KeyboardLayout.h"
    13 #include "nsIMM32Handler.h"
    15 #include "nsMemory.h"
    16 #include "nsToolkit.h"
    17 #include "nsQuickSort.h"
    18 #include "nsAlgorithm.h"
    19 #include "nsUnicharUtils.h"
    20 #include "WidgetUtils.h"
    21 #include "WinUtils.h"
    22 #include "nsWindowDbg.h"
    23 #include "nsServiceManagerUtils.h"
    24 #include "nsPrintfCString.h"
    26 #include "nsIDOMKeyEvent.h"
    27 #include "nsIIdleServiceInternal.h"
    29 #ifdef MOZ_CRASHREPORTER
    30 #include "nsExceptionHandler.h"
    31 #endif
    33 #include "npapi.h"
    35 #include <windows.h>
    36 #include <winuser.h>
    37 #include <algorithm>
    39 #ifndef WINABLEAPI
    40 #include <winable.h>
    41 #endif
    43 namespace mozilla {
    44 namespace widget {
    46 // Unique id counter associated with a keydown / keypress events. Used in
    47 // identifing keypress events for removal from async event dispatch queue
    48 // in metrofx after preventDefault is called on keydown events.
    49 static uint32_t sUniqueKeyEventId = 0;
    51 struct DeadKeyEntry
    52 {
    53   char16_t BaseChar;
    54   char16_t CompositeChar;
    55 };
    58 class DeadKeyTable
    59 {
    60   friend class KeyboardLayout;
    62   uint16_t mEntries;
    63   // KeyboardLayout::AddDeadKeyTable() will allocate as many entries as
    64   // required.  It is the only way to create new DeadKeyTable instances.
    65   DeadKeyEntry mTable[1];
    67   void Init(const DeadKeyEntry* aDeadKeyArray, uint32_t aEntries)
    68   {
    69     mEntries = aEntries;
    70     memcpy(mTable, aDeadKeyArray, aEntries * sizeof(DeadKeyEntry));
    71   }
    73   static uint32_t SizeInBytes(uint32_t aEntries)
    74   {
    75     return offsetof(DeadKeyTable, mTable) + aEntries * sizeof(DeadKeyEntry);
    76   }
    78 public:
    79   uint32_t Entries() const
    80   {
    81     return mEntries;
    82   }
    84   bool IsEqual(const DeadKeyEntry* aDeadKeyArray, uint32_t aEntries) const
    85   {
    86     return (mEntries == aEntries &&
    87             !memcmp(mTable, aDeadKeyArray,
    88                     aEntries * sizeof(DeadKeyEntry)));
    89   }
    91   char16_t GetCompositeChar(char16_t aBaseChar) const;
    92 };
    95 /*****************************************************************************
    96  * mozilla::widget::ModifierKeyState
    97  *****************************************************************************/
    99 ModifierKeyState::ModifierKeyState()
   100 {
   101   Update();
   102 }
   104 ModifierKeyState::ModifierKeyState(bool aIsShiftDown,
   105                                    bool aIsControlDown,
   106                                    bool aIsAltDown)
   107 {
   108   Update();
   109   Unset(MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT | MODIFIER_ALTGRAPH);
   110   Modifiers modifiers = 0;
   111   if (aIsShiftDown) {
   112     modifiers |= MODIFIER_SHIFT;
   113   }
   114   if (aIsControlDown) {
   115     modifiers |= MODIFIER_CONTROL;
   116   }
   117   if (aIsAltDown) {
   118     modifiers |= MODIFIER_ALT;
   119   }
   120   if (modifiers) {
   121     Set(modifiers);
   122   }
   123 }
   125 ModifierKeyState::ModifierKeyState(Modifiers aModifiers) :
   126   mModifiers(aModifiers)
   127 {
   128   EnsureAltGr();
   129 }
   131 void
   132 ModifierKeyState::Update()
   133 {
   134   mModifiers = 0;
   135   if (IS_VK_DOWN(VK_SHIFT)) {
   136     mModifiers |= MODIFIER_SHIFT;
   137   }
   138   if (IS_VK_DOWN(VK_CONTROL)) {
   139     mModifiers |= MODIFIER_CONTROL;
   140   }
   141   if (IS_VK_DOWN(VK_MENU)) {
   142     mModifiers |= MODIFIER_ALT;
   143   }
   144   if (IS_VK_DOWN(VK_LWIN) || IS_VK_DOWN(VK_RWIN)) {
   145     mModifiers |= MODIFIER_OS;
   146   }
   147   if (::GetKeyState(VK_CAPITAL) & 1) {
   148     mModifiers |= MODIFIER_CAPSLOCK;
   149   }
   150   if (::GetKeyState(VK_NUMLOCK) & 1) {
   151     mModifiers |= MODIFIER_NUMLOCK;
   152   }
   153   if (::GetKeyState(VK_SCROLL) & 1) {
   154     mModifiers |= MODIFIER_SCROLLLOCK;
   155   }
   157   EnsureAltGr();
   158 }
   160 void
   161 ModifierKeyState::Unset(Modifiers aRemovingModifiers)
   162 {
   163   mModifiers &= ~aRemovingModifiers;
   164   // Note that we don't need to unset AltGr flag here automatically.
   165   // For nsEditor, we need to remove Alt and Control flags but AltGr isn't
   166   // checked in nsEditor, so, it can be kept.
   167 }
   169 void
   170 ModifierKeyState::Set(Modifiers aAddingModifiers)
   171 {
   172   mModifiers |= aAddingModifiers;
   173   EnsureAltGr();
   174 }
   176 void
   177 ModifierKeyState::InitInputEvent(WidgetInputEvent& aInputEvent) const
   178 {
   179   aInputEvent.modifiers = mModifiers;
   181   switch(aInputEvent.eventStructType) {
   182     case NS_MOUSE_EVENT:
   183     case NS_MOUSE_SCROLL_EVENT:
   184     case NS_WHEEL_EVENT:
   185     case NS_DRAG_EVENT:
   186     case NS_SIMPLE_GESTURE_EVENT:
   187       InitMouseEvent(aInputEvent);
   188       break;
   189     default:
   190       break;
   191   }
   192 }
   194 void
   195 ModifierKeyState::InitMouseEvent(WidgetInputEvent& aMouseEvent) const
   196 {
   197   NS_ASSERTION(aMouseEvent.eventStructType == NS_MOUSE_EVENT ||
   198                aMouseEvent.eventStructType == NS_WHEEL_EVENT ||
   199                aMouseEvent.eventStructType == NS_DRAG_EVENT ||
   200                aMouseEvent.eventStructType == NS_SIMPLE_GESTURE_EVENT,
   201                "called with non-mouse event");
   203   if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) {
   204     // Buttons for immersive mode are handled in MetroInput.
   205     return;
   206   }
   208   WidgetMouseEventBase& mouseEvent = *aMouseEvent.AsMouseEventBase();
   209   mouseEvent.buttons = 0;
   210   if (::GetKeyState(VK_LBUTTON) < 0) {
   211     mouseEvent.buttons |= WidgetMouseEvent::eLeftButtonFlag;
   212   }
   213   if (::GetKeyState(VK_RBUTTON) < 0) {
   214     mouseEvent.buttons |= WidgetMouseEvent::eRightButtonFlag;
   215   }
   216   if (::GetKeyState(VK_MBUTTON) < 0) {
   217     mouseEvent.buttons |= WidgetMouseEvent::eMiddleButtonFlag;
   218   }
   219   if (::GetKeyState(VK_XBUTTON1) < 0) {
   220     mouseEvent.buttons |= WidgetMouseEvent::e4thButtonFlag;
   221   }
   222   if (::GetKeyState(VK_XBUTTON2) < 0) {
   223     mouseEvent.buttons |= WidgetMouseEvent::e5thButtonFlag;
   224   }
   225 }
   227 bool
   228 ModifierKeyState::IsShift() const
   229 {
   230   return (mModifiers & MODIFIER_SHIFT) != 0;
   231 }
   233 bool
   234 ModifierKeyState::IsControl() const
   235 {
   236   return (mModifiers & MODIFIER_CONTROL) != 0;
   237 }
   239 bool
   240 ModifierKeyState::IsAlt() const
   241 {
   242   return (mModifiers & MODIFIER_ALT) != 0;
   243 }
   245 bool
   246 ModifierKeyState::IsAltGr() const
   247 {
   248   return IsControl() && IsAlt();
   249 }
   251 bool
   252 ModifierKeyState::IsWin() const
   253 {
   254   return (mModifiers & MODIFIER_OS) != 0;
   255 }
   257 bool
   258 ModifierKeyState::IsCapsLocked() const
   259 {
   260   return (mModifiers & MODIFIER_CAPSLOCK) != 0;
   261 }
   263 bool
   264 ModifierKeyState::IsNumLocked() const
   265 {
   266   return (mModifiers & MODIFIER_NUMLOCK) != 0;
   267 }
   269 bool
   270 ModifierKeyState::IsScrollLocked() const
   271 {
   272   return (mModifiers & MODIFIER_SCROLLLOCK) != 0;
   273 }
   275 Modifiers
   276 ModifierKeyState::GetModifiers() const
   277 {
   278   return mModifiers;
   279 }
   281 void
   282 ModifierKeyState::EnsureAltGr()
   283 {
   284   // If both Control key and Alt key are pressed, it means AltGr is pressed.
   285   // Ideally, we should check whether the current keyboard layout has AltGr
   286   // or not.  However, setting AltGr flags for keyboard which doesn't have
   287   // AltGr must not be serious bug.  So, it should be OK for now.
   288   if (IsAltGr()) {
   289     mModifiers |= MODIFIER_ALTGRAPH;
   290   }
   291 }
   293 /*****************************************************************************
   294  * mozilla::widget::UniCharsAndModifiers
   295  *****************************************************************************/
   297 void
   298 UniCharsAndModifiers::Append(char16_t aUniChar, Modifiers aModifiers)
   299 {
   300   MOZ_ASSERT(mLength < 5);
   301   mChars[mLength] = aUniChar;
   302   mModifiers[mLength] = aModifiers;
   303   mLength++;
   304 }
   306 void
   307 UniCharsAndModifiers::FillModifiers(Modifiers aModifiers)
   308 {
   309   for (uint32_t i = 0; i < mLength; i++) {
   310     mModifiers[i] = aModifiers;
   311   }
   312 }
   314 bool
   315 UniCharsAndModifiers::UniCharsEqual(const UniCharsAndModifiers& aOther) const
   316 {
   317   if (mLength != aOther.mLength) {
   318     return false;
   319   }
   320   return !memcmp(mChars, aOther.mChars, mLength * sizeof(char16_t));
   321 }
   323 bool
   324 UniCharsAndModifiers::UniCharsCaseInsensitiveEqual(
   325                         const UniCharsAndModifiers& aOther) const
   326 {
   327   if (mLength != aOther.mLength) {
   328     return false;
   329   }
   331   nsCaseInsensitiveStringComparator comp;
   332   return !comp(mChars, aOther.mChars, mLength, aOther.mLength);
   333 }
   335 UniCharsAndModifiers&
   336 UniCharsAndModifiers::operator+=(const UniCharsAndModifiers& aOther)
   337 {
   338   uint32_t copyCount = std::min(aOther.mLength, 5 - mLength);
   339   NS_ENSURE_TRUE(copyCount > 0, *this);
   340   memcpy(&mChars[mLength], aOther.mChars, copyCount * sizeof(char16_t));
   341   memcpy(&mModifiers[mLength], aOther.mModifiers,
   342          copyCount * sizeof(Modifiers));
   343   mLength += copyCount;
   344   return *this;
   345 }
   347 UniCharsAndModifiers
   348 UniCharsAndModifiers::operator+(const UniCharsAndModifiers& aOther) const
   349 {
   350   UniCharsAndModifiers result(*this);
   351   result += aOther;
   352   return result;
   353 }
   355 /*****************************************************************************
   356  * mozilla::widget::VirtualKey
   357  *****************************************************************************/
   359 // static
   360 VirtualKey::ShiftState
   361 VirtualKey::ModifiersToShiftState(Modifiers aModifiers)
   362 {
   363   ShiftState state = 0;
   364   if (aModifiers & MODIFIER_SHIFT) {
   365     state |= STATE_SHIFT;
   366   }
   367   if (aModifiers & MODIFIER_CONTROL) {
   368     state |= STATE_CONTROL;
   369   }
   370   if (aModifiers & MODIFIER_ALT) {
   371     state |= STATE_ALT;
   372   }
   373   if (aModifiers & MODIFIER_CAPSLOCK) {
   374     state |= STATE_CAPSLOCK;
   375   }
   376   return state;
   377 }
   379 // static
   380 Modifiers
   381 VirtualKey::ShiftStateToModifiers(ShiftState aShiftState)
   382 {
   383   Modifiers modifiers = 0;
   384   if (aShiftState & STATE_SHIFT) {
   385     modifiers |= MODIFIER_SHIFT;
   386   }
   387   if (aShiftState & STATE_CONTROL) {
   388     modifiers |= MODIFIER_CONTROL;
   389   }
   390   if (aShiftState & STATE_ALT) {
   391     modifiers |= MODIFIER_ALT;
   392   }
   393   if (aShiftState & STATE_CAPSLOCK) {
   394     modifiers |= MODIFIER_CAPSLOCK;
   395   }
   396   if ((modifiers & (MODIFIER_ALT | MODIFIER_CONTROL)) ==
   397          (MODIFIER_ALT | MODIFIER_CONTROL)) {
   398     modifiers |= MODIFIER_ALTGRAPH;
   399   }
   400   return modifiers;
   401 }
   403 inline char16_t
   404 VirtualKey::GetCompositeChar(ShiftState aShiftState, char16_t aBaseChar) const
   405 {
   406   return mShiftStates[aShiftState].DeadKey.Table->GetCompositeChar(aBaseChar);
   407 }
   409 const DeadKeyTable*
   410 VirtualKey::MatchingDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
   411                                  uint32_t aEntries) const
   412 {
   413   if (!mIsDeadKey) {
   414     return nullptr;
   415   }
   417   for (ShiftState shiftState = 0; shiftState < 16; shiftState++) {
   418     if (!IsDeadKey(shiftState)) {
   419       continue;
   420     }
   421     const DeadKeyTable* dkt = mShiftStates[shiftState].DeadKey.Table;
   422     if (dkt && dkt->IsEqual(aDeadKeyArray, aEntries)) {
   423       return dkt;
   424     }
   425   }
   427   return nullptr;
   428 }
   430 void
   431 VirtualKey::SetNormalChars(ShiftState aShiftState,
   432                            const char16_t* aChars,
   433                            uint32_t aNumOfChars)
   434 {
   435   NS_ASSERTION(aShiftState < ArrayLength(mShiftStates), "invalid index");
   437   SetDeadKey(aShiftState, false);
   439   for (uint32_t index = 0; index < aNumOfChars; index++) {
   440     // Ignore legacy non-printable control characters
   441     mShiftStates[aShiftState].Normal.Chars[index] =
   442       (aChars[index] >= 0x20) ? aChars[index] : 0;
   443   }
   445   uint32_t len = ArrayLength(mShiftStates[aShiftState].Normal.Chars);
   446   for (uint32_t index = aNumOfChars; index < len; index++) {
   447     mShiftStates[aShiftState].Normal.Chars[index] = 0;
   448   }
   449 }
   451 void
   452 VirtualKey::SetDeadChar(ShiftState aShiftState, char16_t aDeadChar)
   453 {
   454   NS_ASSERTION(aShiftState < ArrayLength(mShiftStates), "invalid index");
   456   SetDeadKey(aShiftState, true);
   458   mShiftStates[aShiftState].DeadKey.DeadChar = aDeadChar;
   459   mShiftStates[aShiftState].DeadKey.Table = nullptr;
   460 }
   462 UniCharsAndModifiers
   463 VirtualKey::GetUniChars(ShiftState aShiftState) const
   464 {
   465   UniCharsAndModifiers result = GetNativeUniChars(aShiftState);
   467   const ShiftState STATE_ALT_CONTROL = (STATE_ALT | STATE_CONTROL);
   468   if (!(aShiftState & STATE_ALT_CONTROL)) {
   469     return result;
   470   }
   472   if (!result.mLength) {
   473     result = GetNativeUniChars(aShiftState & ~STATE_ALT_CONTROL);
   474     result.FillModifiers(ShiftStateToModifiers(aShiftState));
   475     return result;
   476   }
   478   if ((aShiftState & STATE_ALT_CONTROL) == STATE_ALT_CONTROL) {
   479     // Even if the shifted chars and the unshifted chars are same, we
   480     // should consume the Alt key state and the Ctrl key state when
   481     // AltGr key is pressed. Because if we don't consume them, the input
   482     // events are ignored on nsEditor. (I.e., Users cannot input the
   483     // characters with this key combination.)
   484     Modifiers finalModifiers = ShiftStateToModifiers(aShiftState);
   485     finalModifiers &= ~(MODIFIER_ALT | MODIFIER_CONTROL);
   486     result.FillModifiers(finalModifiers);
   487     return result;
   488   }
   490   UniCharsAndModifiers unmodifiedReslt =
   491     GetNativeUniChars(aShiftState & ~STATE_ALT_CONTROL);
   492   if (!result.UniCharsEqual(unmodifiedReslt)) {
   493     // Otherwise, we should consume the Alt key state and the Ctrl key state
   494     // only when the shifted chars and unshifted chars are different.
   495     Modifiers finalModifiers = ShiftStateToModifiers(aShiftState);
   496     finalModifiers &= ~(MODIFIER_ALT | MODIFIER_CONTROL);
   497     result.FillModifiers(finalModifiers);
   498   }
   499   return result;
   500 }
   503 UniCharsAndModifiers
   504 VirtualKey::GetNativeUniChars(ShiftState aShiftState) const
   505 {
   506 #ifdef DEBUG
   507   if (aShiftState < 0 || aShiftState >= ArrayLength(mShiftStates)) {
   508     nsPrintfCString warning("Shift state is out of range: "
   509                             "aShiftState=%d, ArrayLength(mShiftState)=%d",
   510                             aShiftState, ArrayLength(mShiftStates));
   511     NS_WARNING(warning.get());
   512   }
   513 #endif
   515   UniCharsAndModifiers result;
   516   Modifiers modifiers = ShiftStateToModifiers(aShiftState);
   517   if (IsDeadKey(aShiftState)) {
   518     result.Append(mShiftStates[aShiftState].DeadKey.DeadChar, modifiers);
   519     return result;
   520   }
   522   uint32_t index;
   523   uint32_t len = ArrayLength(mShiftStates[aShiftState].Normal.Chars);
   524   for (index = 0;
   525        index < len && mShiftStates[aShiftState].Normal.Chars[index]; index++) {
   526     result.Append(mShiftStates[aShiftState].Normal.Chars[index], modifiers);
   527   }
   528   return result;
   529 }
   531 // static
   532 void
   533 VirtualKey::FillKbdState(PBYTE aKbdState,
   534                          const ShiftState aShiftState)
   535 {
   536   NS_ASSERTION(aShiftState < 16, "aShiftState out of range");
   538   if (aShiftState & STATE_SHIFT) {
   539     aKbdState[VK_SHIFT] |= 0x80;
   540   } else {
   541     aKbdState[VK_SHIFT]  &= ~0x80;
   542     aKbdState[VK_LSHIFT] &= ~0x80;
   543     aKbdState[VK_RSHIFT] &= ~0x80;
   544   }
   546   if (aShiftState & STATE_CONTROL) {
   547     aKbdState[VK_CONTROL] |= 0x80;
   548   } else {
   549     aKbdState[VK_CONTROL]  &= ~0x80;
   550     aKbdState[VK_LCONTROL] &= ~0x80;
   551     aKbdState[VK_RCONTROL] &= ~0x80;
   552   }
   554   if (aShiftState & STATE_ALT) {
   555     aKbdState[VK_MENU] |= 0x80;
   556   } else {
   557     aKbdState[VK_MENU]  &= ~0x80;
   558     aKbdState[VK_LMENU] &= ~0x80;
   559     aKbdState[VK_RMENU] &= ~0x80;
   560   }
   562   if (aShiftState & STATE_CAPSLOCK) {
   563     aKbdState[VK_CAPITAL] |= 0x01;
   564   } else {
   565     aKbdState[VK_CAPITAL] &= ~0x01;
   566   }
   567 }
   569 /*****************************************************************************
   570  * mozilla::widget::NativeKey
   571  *****************************************************************************/
   573 NativeKey::NativeKey(nsWindowBase* aWidget,
   574                      const MSG& aKeyOrCharMessage,
   575                      const ModifierKeyState& aModKeyState,
   576                      nsTArray<FakeCharMsg>* aFakeCharMsgs) :
   577   mWidget(aWidget), mMsg(aKeyOrCharMessage), mDOMKeyCode(0),
   578   mModKeyState(aModKeyState), mVirtualKeyCode(0), mOriginalVirtualKeyCode(0),
   579   mFakeCharMsgs(aFakeCharMsgs && aFakeCharMsgs->Length() ?
   580                   aFakeCharMsgs : nullptr)
   581 {
   582   MOZ_ASSERT(aWidget);
   583   KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
   584   mKeyboardLayout = keyboardLayout->GetLayout();
   585   mScanCode = WinUtils::GetScanCode(mMsg.lParam);
   586   mIsExtended = WinUtils::IsExtendedScanCode(mMsg.lParam);
   587   // On WinXP and WinServer2003, we cannot compute the virtual keycode for
   588   // extended keys due to the API limitation.
   589   bool canComputeVirtualKeyCodeFromScanCode =
   590     (!mIsExtended || IsVistaOrLater());
   591   switch (mMsg.message) {
   592     case WM_KEYDOWN:
   593     case WM_SYSKEYDOWN:
   594     case WM_KEYUP:
   595     case WM_SYSKEYUP: {
   596       // First, resolve the IME converted virtual keycode to its original
   597       // keycode.
   598       if (mMsg.wParam == VK_PROCESSKEY) {
   599         mOriginalVirtualKeyCode =
   600           static_cast<uint8_t>(::ImmGetVirtualKey(mMsg.hwnd));
   601       } else {
   602         mOriginalVirtualKeyCode = static_cast<uint8_t>(mMsg.wParam);
   603       }
   605       // Most keys are not distinguished as left or right keys.
   606       bool isLeftRightDistinguishedKey = false;
   608       // mOriginalVirtualKeyCode must not distinguish left or right of
   609       // Shift, Control or Alt.
   610       switch (mOriginalVirtualKeyCode) {
   611         case VK_SHIFT:
   612         case VK_CONTROL:
   613         case VK_MENU:
   614           isLeftRightDistinguishedKey = true;
   615           break;
   616         case VK_LSHIFT:
   617         case VK_RSHIFT:
   618           mVirtualKeyCode = mOriginalVirtualKeyCode;
   619           mOriginalVirtualKeyCode = VK_SHIFT;
   620           isLeftRightDistinguishedKey = true;
   621           break;
   622         case VK_LCONTROL:
   623         case VK_RCONTROL:
   624           mVirtualKeyCode = mOriginalVirtualKeyCode;
   625           mOriginalVirtualKeyCode = VK_CONTROL;
   626           isLeftRightDistinguishedKey = true;
   627           break;
   628         case VK_LMENU:
   629         case VK_RMENU:
   630           mVirtualKeyCode = mOriginalVirtualKeyCode;
   631           mOriginalVirtualKeyCode = VK_MENU;
   632           isLeftRightDistinguishedKey = true;
   633           break;
   634       }
   636       // If virtual keycode (left-right distinguished keycode) is already
   637       // computed, we don't need to do anymore.
   638       if (mVirtualKeyCode) {
   639         break;
   640       }
   642       // If the keycode doesn't have LR distinguished keycode, we just set
   643       // mOriginalVirtualKeyCode to mVirtualKeyCode.  Note that don't compute
   644       // it from MapVirtualKeyEx() because the scan code might be wrong if
   645       // the message is sent/posted by other application.  Then, we will compute
   646       // unexpected keycode from the scan code.
   647       if (!isLeftRightDistinguishedKey) {
   648         break;
   649       }
   651       if (!canComputeVirtualKeyCodeFromScanCode) {
   652         // The right control key and the right alt key are extended keys.
   653         // Therefore, we never get VK_RCONTRL and VK_RMENU for the result of
   654         // MapVirtualKeyEx() on WinXP or WinServer2003.
   655         //
   656         // If VK_CONTROL or VK_MENU key message is caused by an extended key,
   657         // we should assume that the right key of them is pressed.
   658         switch (mOriginalVirtualKeyCode) {
   659           case VK_CONTROL:
   660             mVirtualKeyCode = VK_RCONTROL;
   661             break;
   662           case VK_MENU:
   663             mVirtualKeyCode = VK_RMENU;
   664             break;
   665           case VK_SHIFT:
   666             // Neither left shift nor right shift is not an extended key,
   667             // let's use VK_LSHIFT for invalid scan code.
   668             mVirtualKeyCode = VK_LSHIFT;
   669             break;
   670           default:
   671             MOZ_CRASH("Unsupported mOriginalVirtualKeyCode");
   672         }
   673         break;
   674       }
   676       NS_ASSERTION(!mVirtualKeyCode,
   677                    "mVirtualKeyCode has been computed already");
   679       // Otherwise, compute the virtual keycode with MapVirtualKeyEx().
   680       mVirtualKeyCode = ComputeVirtualKeyCodeFromScanCodeEx();
   682       // The result might be unexpected value due to the scan code is
   683       // wrong.  For example, any key messages can be generated by
   684       // SendMessage() or PostMessage() from applications.  So, it's possible
   685       // failure.  Then, let's respect the extended flag even if it might be
   686       // set intentionally.
   687       switch (mOriginalVirtualKeyCode) {
   688         case VK_CONTROL:
   689           if (mVirtualKeyCode != VK_LCONTROL &&
   690               mVirtualKeyCode != VK_RCONTROL) {
   691             mVirtualKeyCode = mIsExtended ? VK_RCONTROL : VK_LCONTROL;
   692           }
   693           break;
   694         case VK_MENU:
   695           if (mVirtualKeyCode != VK_LMENU && mVirtualKeyCode != VK_RMENU) {
   696             mVirtualKeyCode = mIsExtended ? VK_RMENU : VK_LMENU;
   697           }
   698           break;
   699         case VK_SHIFT:
   700           if (mVirtualKeyCode != VK_LSHIFT && mVirtualKeyCode != VK_RSHIFT) {
   701             // Neither left shift nor right shift is not an extended key,
   702             // let's use VK_LSHIFT for invalid scan code.
   703             mVirtualKeyCode = VK_LSHIFT;
   704           }
   705           break;
   706         default:
   707           MOZ_CRASH("Unsupported mOriginalVirtualKeyCode");
   708       }
   709       break;
   710     }
   711     case WM_CHAR:
   712     case WM_UNICHAR:
   713     case WM_SYSCHAR:
   714       // We cannot compute the virtual key code from WM_CHAR message on WinXP
   715       // if it's caused by an extended key.
   716       if (!canComputeVirtualKeyCodeFromScanCode) {
   717         break;
   718       }
   719       mVirtualKeyCode = mOriginalVirtualKeyCode =
   720         ComputeVirtualKeyCodeFromScanCodeEx();
   721       NS_ASSERTION(mVirtualKeyCode, "Failed to compute virtual keycode");
   722       break;
   723     default:
   724       MOZ_CRASH("Unsupported message");
   725   }
   727   if (!mVirtualKeyCode) {
   728     mVirtualKeyCode = mOriginalVirtualKeyCode;
   729   }
   731   mDOMKeyCode =
   732     keyboardLayout->ConvertNativeKeyCodeToDOMKeyCode(mOriginalVirtualKeyCode);
   733   mKeyNameIndex =
   734     keyboardLayout->ConvertNativeKeyCodeToKeyNameIndex(mOriginalVirtualKeyCode);
   736   keyboardLayout->InitNativeKey(*this, mModKeyState);
   738   mIsDeadKey =
   739     (IsFollowedByDeadCharMessage() ||
   740      keyboardLayout->IsDeadKey(mOriginalVirtualKeyCode, mModKeyState));
   741   mIsPrintableKey = KeyboardLayout::IsPrintableCharKey(mOriginalVirtualKeyCode);
   742 }
   744 bool
   745 NativeKey::IsFollowedByDeadCharMessage() const
   746 {
   747   MSG nextMsg;
   748   if (mFakeCharMsgs) {
   749     nextMsg = mFakeCharMsgs->ElementAt(0).GetCharMsg(mMsg.hwnd);
   750   } else {
   751     if (!WinUtils::PeekMessage(&nextMsg, mMsg.hwnd, WM_KEYFIRST, WM_KEYLAST,
   752                                PM_NOREMOVE | PM_NOYIELD)) {
   753       return false;
   754     }
   755   }
   756   return IsDeadCharMessage(nextMsg);
   757 }
   759 bool
   760 NativeKey::IsIMEDoingKakuteiUndo() const
   761 {
   762   // Following message pattern is caused by "Kakutei-Undo" of ATOK or WXG:
   763   // ---------------------------------------------------------------------------
   764   // WM_KEYDOWN              * n (wParam = VK_BACK, lParam = 0x1)
   765   // WM_KEYUP                * 1 (wParam = VK_BACK, lParam = 0xC0000001) # ATOK
   766   // WM_IME_STARTCOMPOSITION * 1 (wParam = 0x0, lParam = 0x0)
   767   // WM_IME_COMPOSITION      * 1 (wParam = 0x0, lParam = 0x1BF)
   768   // WM_CHAR                 * n (wParam = VK_BACK, lParam = 0x1)
   769   // WM_KEYUP                * 1 (wParam = VK_BACK, lParam = 0xC00E0001)
   770   // ---------------------------------------------------------------------------
   771   // This doesn't match usual key message pattern such as:
   772   //   WM_KEYDOWN -> WM_CHAR -> WM_KEYDOWN -> WM_CHAR -> ... -> WM_KEYUP
   773   // See following bugs for the detail.
   774   // https://bugzilla.mozilla.gr.jp/show_bug.cgi?id=2885 (written in Japanese)
   775   // https://bugzilla.mozilla.org/show_bug.cgi?id=194559 (written in English)
   776   MSG startCompositionMsg, compositionMsg, charMsg;
   777   return WinUtils::PeekMessage(&startCompositionMsg, mMsg.hwnd,
   778                                WM_IME_STARTCOMPOSITION, WM_IME_STARTCOMPOSITION,
   779                                PM_NOREMOVE | PM_NOYIELD) &&
   780          WinUtils::PeekMessage(&compositionMsg, mMsg.hwnd, WM_IME_COMPOSITION,
   781                                WM_IME_COMPOSITION, PM_NOREMOVE | PM_NOYIELD) &&
   782          WinUtils::PeekMessage(&charMsg, mMsg.hwnd, WM_CHAR, WM_CHAR,
   783                                PM_NOREMOVE | PM_NOYIELD) &&
   784          startCompositionMsg.wParam == 0x0 &&
   785          startCompositionMsg.lParam == 0x0 &&
   786          compositionMsg.wParam == 0x0 &&
   787          compositionMsg.lParam == 0x1BF &&
   788          charMsg.wParam == VK_BACK && charMsg.lParam == 0x1 &&
   789          startCompositionMsg.time <= compositionMsg.time &&
   790          compositionMsg.time <= charMsg.time;
   791 }
   793 UINT
   794 NativeKey::GetScanCodeWithExtendedFlag() const
   795 {
   796   // MapVirtualKeyEx() has been improved for supporting extended keys since
   797   // Vista.  When we call it for mapping a scancode of an extended key and
   798   // a virtual keycode, we need to add 0xE000 to the scancode.
   799   // On Win XP and Win Server 2003, this doesn't support. On them, we have
   800   // no way to get virtual keycodes from scancode of extended keys.
   801   if (!mIsExtended || !IsVistaOrLater()) {
   802     return mScanCode;
   803   }
   804   return (0xE000 | mScanCode);
   805 }
   807 uint32_t
   808 NativeKey::GetKeyLocation() const
   809 {
   810   switch (mVirtualKeyCode) {
   811     case VK_LSHIFT:
   812     case VK_LCONTROL:
   813     case VK_LMENU:
   814     case VK_LWIN:
   815       return nsIDOMKeyEvent::DOM_KEY_LOCATION_LEFT;
   817     case VK_RSHIFT:
   818     case VK_RCONTROL:
   819     case VK_RMENU:
   820     case VK_RWIN:
   821       return nsIDOMKeyEvent::DOM_KEY_LOCATION_RIGHT;
   823     case VK_RETURN:
   824       // XXX This code assumes that all keyboard drivers use same mapping.
   825       return !mIsExtended ? nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD :
   826                             nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD;
   828     case VK_INSERT:
   829     case VK_DELETE:
   830     case VK_END:
   831     case VK_DOWN:
   832     case VK_NEXT:
   833     case VK_LEFT:
   834     case VK_CLEAR:
   835     case VK_RIGHT:
   836     case VK_HOME:
   837     case VK_UP:
   838     case VK_PRIOR:
   839       // XXX This code assumes that all keyboard drivers use same mapping.
   840       return mIsExtended ? nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD :
   841                            nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD;
   843     // NumLock key isn't included due to IE9's behavior.
   844     case VK_NUMPAD0:
   845     case VK_NUMPAD1:
   846     case VK_NUMPAD2:
   847     case VK_NUMPAD3:
   848     case VK_NUMPAD4:
   849     case VK_NUMPAD5:
   850     case VK_NUMPAD6:
   851     case VK_NUMPAD7:
   852     case VK_NUMPAD8:
   853     case VK_NUMPAD9:
   854     case VK_DECIMAL:
   855     case VK_DIVIDE:
   856     case VK_MULTIPLY:
   857     case VK_SUBTRACT:
   858     case VK_ADD:
   859     // Separator key of Brazilian keyboard or JIS keyboard for Mac
   860     case VK_ABNT_C2:
   861       return nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD;
   863     case VK_SHIFT:
   864     case VK_CONTROL:
   865     case VK_MENU:
   866       NS_WARNING("Failed to decide the key location?");
   868     default:
   869       return nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD;
   870   }
   871 }
   873 uint8_t
   874 NativeKey::ComputeVirtualKeyCodeFromScanCode() const
   875 {
   876   return static_cast<uint8_t>(
   877            ::MapVirtualKeyEx(mScanCode, MAPVK_VSC_TO_VK, mKeyboardLayout));
   878 }
   880 uint8_t
   881 NativeKey::ComputeVirtualKeyCodeFromScanCodeEx() const
   882 {
   883   // NOTE: WinXP doesn't support mapping scan code to virtual keycode of
   884   //       extended keys.
   885   NS_ENSURE_TRUE(!mIsExtended || IsVistaOrLater(), 0);
   886   return static_cast<uint8_t>(
   887            ::MapVirtualKeyEx(GetScanCodeWithExtendedFlag(), MAPVK_VSC_TO_VK_EX,
   888                              mKeyboardLayout));
   889 }
   891 char16_t
   892 NativeKey::ComputeUnicharFromScanCode() const
   893 {
   894   return static_cast<char16_t>(
   895            ::MapVirtualKeyEx(ComputeVirtualKeyCodeFromScanCode(),
   896                              MAPVK_VK_TO_CHAR, mKeyboardLayout));
   897 }
   899 void
   900 NativeKey::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent) const
   901 {
   902   InitKeyEvent(aKeyEvent, mModKeyState);
   903 }
   905 void
   906 NativeKey::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
   907                         const ModifierKeyState& aModKeyState) const
   908 {
   909   nsIntPoint point(0, 0);
   910   mWidget->InitEvent(aKeyEvent, &point);
   912   switch (aKeyEvent.message) {
   913     case NS_KEY_DOWN:
   914       aKeyEvent.keyCode = mDOMKeyCode;
   915       // Unique id for this keydown event and its associated keypress.
   916       sUniqueKeyEventId++;
   917       aKeyEvent.mUniqueId = sUniqueKeyEventId;
   918       break;
   919     case NS_KEY_UP:
   920       aKeyEvent.keyCode = mDOMKeyCode;
   921       // Set defaultPrevented of the key event if the VK_MENU is not a system
   922       // key release, so that the menu bar does not trigger.  This helps avoid
   923       // triggering the menu bar for ALT key accelerators used in assistive
   924       // technologies such as Window-Eyes and ZoomText or for switching open
   925       // state of IME.
   926       aKeyEvent.mFlags.mDefaultPrevented =
   927         (mOriginalVirtualKeyCode == VK_MENU && mMsg.message != WM_SYSKEYUP);
   928       break;
   929     case NS_KEY_PRESS:
   930       aKeyEvent.mUniqueId = sUniqueKeyEventId;
   931       break;
   932     default:
   933       MOZ_CRASH("Invalid event message");
   934   }
   936   aKeyEvent.mIsRepeat = IsRepeat();
   937   aKeyEvent.mKeyNameIndex = mKeyNameIndex;
   938   if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) {
   939     aKeyEvent.mKeyValue = mCommittedCharsAndModifiers.ToString();
   940   }
   941   aKeyEvent.location = GetKeyLocation();
   942   aModKeyState.InitInputEvent(aKeyEvent);
   943 }
   945 bool
   946 NativeKey::DispatchKeyEvent(WidgetKeyboardEvent& aKeyEvent,
   947                             const MSG* aMsgSentToPlugin) const
   948 {
   949   if (mWidget->Destroyed()) {
   950     MOZ_CRASH("NativeKey tries to dispatch a key event on destroyed widget");
   951   }
   953   KeyboardLayout::NotifyIdleServiceOfUserActivity();
   955   NPEvent pluginEvent;
   956   if (aMsgSentToPlugin &&
   957       mWidget->GetInputContext().mIMEState.mEnabled == IMEState::PLUGIN) {
   958     pluginEvent.event = aMsgSentToPlugin->message;
   959     pluginEvent.wParam = aMsgSentToPlugin->wParam;
   960     pluginEvent.lParam = aMsgSentToPlugin->lParam;
   961     aKeyEvent.pluginEvent = static_cast<void*>(&pluginEvent);
   962   }
   964   return (mWidget->DispatchKeyboardEvent(&aKeyEvent) || mWidget->Destroyed());
   965 }
   967 bool
   968 NativeKey::HandleKeyDownMessage(bool* aEventDispatched) const
   969 {
   970   MOZ_ASSERT(IsKeyDownMessage());
   972   if (aEventDispatched) {
   973     *aEventDispatched = false;
   974   }
   976   bool defaultPrevented = false;
   977   if (mFakeCharMsgs ||
   978       !RedirectedKeyDownMessageManager::IsRedirectedMessage(mMsg)) {
   979     // Ignore [shift+]alt+space so the OS can handle it.
   980     if (mModKeyState.IsAlt() && !mModKeyState.IsControl() &&
   981         mVirtualKeyCode == VK_SPACE) {
   982       return false;
   983     }
   985     bool isIMEEnabled = WinUtils::IsIMEEnabled(mWidget->GetInputContext());
   986     WidgetKeyboardEvent keydownEvent(true, NS_KEY_DOWN, mWidget);
   987     InitKeyEvent(keydownEvent, mModKeyState);
   988     if (aEventDispatched) {
   989       *aEventDispatched = true;
   990     }
   991     defaultPrevented = DispatchKeyEvent(keydownEvent, &mMsg);
   993     if (mWidget->Destroyed()) {
   994       return true;
   995     }
   997     // If IMC wasn't associated to the window but is associated it now (i.e.,
   998     // focus is moved from a non-editable editor to an editor by keydown
   999     // event handler), WM_CHAR and WM_SYSCHAR shouldn't cause first character
  1000     // inputting if IME is opened.  But then, we should redirect the native
  1001     // keydown message to IME.
  1002     // However, note that if focus has been already moved to another
  1003     // application, we shouldn't redirect the message to it because the keydown
  1004     // message is processed by us, so, nobody shouldn't process it.
  1005     HWND focusedWnd = ::GetFocus();
  1006     if (!defaultPrevented && !mFakeCharMsgs && focusedWnd &&
  1007         !mWidget->PluginHasFocus() && !isIMEEnabled &&
  1008         WinUtils::IsIMEEnabled(mWidget->GetInputContext())) {
  1009       RedirectedKeyDownMessageManager::RemoveNextCharMessage(focusedWnd);
  1011       INPUT keyinput;
  1012       keyinput.type = INPUT_KEYBOARD;
  1013       keyinput.ki.wVk = mOriginalVirtualKeyCode;
  1014       keyinput.ki.wScan = mScanCode;
  1015       keyinput.ki.dwFlags = KEYEVENTF_SCANCODE;
  1016       if (mIsExtended) {
  1017         keyinput.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
  1019       keyinput.ki.time = 0;
  1020       keyinput.ki.dwExtraInfo = 0;
  1022       RedirectedKeyDownMessageManager::WillRedirect(mMsg, defaultPrevented);
  1024       ::SendInput(1, &keyinput, sizeof(keyinput));
  1026       // Return here.  We shouldn't dispatch keypress event for this WM_KEYDOWN.
  1027       // If it's needed, it will be dispatched after next (redirected)
  1028       // WM_KEYDOWN.
  1029       return true;
  1031   } else {
  1032     defaultPrevented = RedirectedKeyDownMessageManager::DefaultPrevented();
  1033     // If this is redirected keydown message, we have dispatched the keydown
  1034     // event already.
  1035     if (aEventDispatched) {
  1036       *aEventDispatched = true;
  1040   RedirectedKeyDownMessageManager::Forget();
  1042   // If the key was processed by IME, we shouldn't dispatch keypress event.
  1043   if (mOriginalVirtualKeyCode == VK_PROCESSKEY) {
  1044     return defaultPrevented;
  1047   // Don't dispatch keypress event for modifier keys.
  1048   switch (mDOMKeyCode) {
  1049     case NS_VK_SHIFT:
  1050     case NS_VK_CONTROL:
  1051     case NS_VK_ALT:
  1052     case NS_VK_CAPS_LOCK:
  1053     case NS_VK_NUM_LOCK:
  1054     case NS_VK_SCROLL_LOCK:
  1055     case NS_VK_WIN:
  1056       return defaultPrevented;
  1059   if (defaultPrevented) {
  1060     DispatchPluginEventsAndDiscardsCharMessages();
  1061     return true;
  1064   // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a
  1065   // keypress for almost all keys
  1066   if (NeedsToHandleWithoutFollowingCharMessages()) {
  1067     return (DispatchPluginEventsAndDiscardsCharMessages() ||
  1068             DispatchKeyPressEventsWithKeyboardLayout());
  1071   MSG followingCharMsg;
  1072   if (GetFollowingCharMessage(followingCharMsg)) {
  1073     // Even if there was char message, it might be redirected by different
  1074     // window (perhaps, focus move?).  Then, we shouldn't continue to handle
  1075     // the message since no input should occur on the window.
  1076     if (followingCharMsg.message == WM_NULL ||
  1077         followingCharMsg.hwnd != mMsg.hwnd) {
  1078       return false;
  1080     return DispatchKeyPressEventForFollowingCharMessage(followingCharMsg);
  1083   if (!mModKeyState.IsControl() && !mModKeyState.IsAlt() &&
  1084       !mModKeyState.IsWin() && mIsPrintableKey) {
  1085     // If this is simple KeyDown event but next message is not WM_CHAR,
  1086     // this event may not input text, so we should ignore this event.
  1087     // See bug 314130.
  1088     return false;
  1091   if (mIsDeadKey) {
  1092     return false;
  1095   return DispatchKeyPressEventsWithKeyboardLayout();
  1098 bool
  1099 NativeKey::HandleCharMessage(const MSG& aCharMsg,
  1100                              bool* aEventDispatched) const
  1102   MOZ_ASSERT(IsKeyDownMessage() || IsPrintableCharMessage(mMsg));
  1103   MOZ_ASSERT(IsPrintableCharMessage(aCharMsg.message));
  1105   if (aEventDispatched) {
  1106     *aEventDispatched = false;
  1109   // Alt+Space key is handled by OS, we shouldn't touch it.
  1110   if (mModKeyState.IsAlt() && !mModKeyState.IsControl() &&
  1111       mVirtualKeyCode == VK_SPACE) {
  1112     return false;
  1115   // Bug 818235: Ignore Ctrl+Enter.
  1116   if (!mModKeyState.IsAlt() && mModKeyState.IsControl() &&
  1117       mVirtualKeyCode == VK_RETURN) {
  1118     return false;
  1121   // XXXmnakao I think that if aNativeKeyDown is null, such lonely WM_CHAR
  1122   //           should cause composition events because they are not caused
  1123   //           by actual keyboard operation.
  1125   static const char16_t U_SPACE = 0x20;
  1126   static const char16_t U_EQUAL = 0x3D;
  1128   // First, handle normal text input or non-printable key case here.
  1129   if ((!mModKeyState.IsAlt() && !mModKeyState.IsControl()) ||
  1130       mModKeyState.IsAltGr() ||
  1131       (mOriginalVirtualKeyCode &&
  1132        !KeyboardLayout::IsPrintableCharKey(mOriginalVirtualKeyCode))) {
  1133     WidgetKeyboardEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
  1134     if (aCharMsg.wParam >= U_SPACE) {
  1135       keypressEvent.charCode = static_cast<uint32_t>(aCharMsg.wParam);
  1136     } else {
  1137       keypressEvent.keyCode = mDOMKeyCode;
  1139     // When AltGr (Alt+Ctrl) is pressed, that causes normal text input.
  1140     // At this time, if either alt or ctrl flag is set, nsEditor ignores the
  1141     // keypress event.  For avoiding this issue, we should remove ctrl and alt
  1142     // flags.
  1143     ModifierKeyState modKeyState(mModKeyState);
  1144     modKeyState.Unset(MODIFIER_ALT | MODIFIER_CONTROL);
  1145     InitKeyEvent(keypressEvent, modKeyState);
  1146     if (aEventDispatched) {
  1147       *aEventDispatched = true;
  1149     return DispatchKeyEvent(keypressEvent, &aCharMsg);
  1152   // XXX It seems that following code was implemented for shortcut key
  1153   //     handling.  However, it's now handled in WM_KEYDOWN message handler.
  1154   //     So, this actually runs only when WM_CHAR is sent/posted without
  1155   //     WM_KEYDOWN.  I think that we don't need to keypress event in such
  1156   //     case especially for shortcut keys.
  1158   char16_t uniChar;
  1159   // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
  1160   if (mModKeyState.IsControl() && aCharMsg.wParam <= 0x1A) {
  1161     // Bug 16486: Need to account for shift here.
  1162     uniChar = aCharMsg.wParam - 1 + (mModKeyState.IsShift() ? 'A' : 'a');
  1163   } else if (mModKeyState.IsControl() && aCharMsg.wParam <= 0x1F) {
  1164     // Bug 50255: <ctrl><[> and <ctrl><]> are not being processed.
  1165     // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
  1166     // for some reason the keypress handler need to have the uniChar code set
  1167     // with the addition of a upper case A not the lower case.
  1168     uniChar = aCharMsg.wParam - 1 + 'A';
  1169   } else if (aCharMsg.wParam < U_SPACE ||
  1170              (aCharMsg.wParam == U_EQUAL && mModKeyState.IsControl())) {
  1171     uniChar = 0;
  1172   } else {
  1173     uniChar = aCharMsg.wParam;
  1176   // Bug 50255 and Bug 351310: Keep the characters unshifted for shortcuts and
  1177   // accesskeys and make sure that numbers are always passed as such.
  1178   if (uniChar && (mModKeyState.IsControl() || mModKeyState.IsAlt())) {
  1179     KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
  1180     char16_t unshiftedCharCode =
  1181       (mVirtualKeyCode >= '0' && mVirtualKeyCode <= '9') ?
  1182         mVirtualKeyCode :  mModKeyState.IsShift() ?
  1183                              ComputeUnicharFromScanCode() : 0;
  1184     // Ignore diacritics (top bit set) and key mapping errors (char code 0)
  1185     if (static_cast<int32_t>(unshiftedCharCode) > 0) {
  1186       uniChar = unshiftedCharCode;
  1190   // Bug 285161 and Bug 295095: They were caused by the initial fix for
  1191   // bug 178110.  When pressing (alt|ctrl)+char, the char must be lowercase
  1192   // unless shift is pressed too.
  1193   if (!mModKeyState.IsShift() &&
  1194       (mModKeyState.IsAlt() || mModKeyState.IsControl())) {
  1195     uniChar = towlower(uniChar);
  1198   WidgetKeyboardEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
  1199   keypressEvent.charCode = uniChar;
  1200   if (!keypressEvent.charCode) {
  1201     keypressEvent.keyCode = mDOMKeyCode;
  1203   InitKeyEvent(keypressEvent, mModKeyState);
  1204   if (aEventDispatched) {
  1205     *aEventDispatched = true;
  1207   return DispatchKeyEvent(keypressEvent, &aCharMsg);
  1210 bool
  1211 NativeKey::HandleKeyUpMessage(bool* aEventDispatched) const
  1213   MOZ_ASSERT(IsKeyUpMessage());
  1215   if (aEventDispatched) {
  1216     *aEventDispatched = false;
  1219   // Ignore [shift+]alt+space so the OS can handle it.
  1220   if (mModKeyState.IsAlt() && !mModKeyState.IsControl() &&
  1221       mVirtualKeyCode == VK_SPACE) {
  1222     return false;
  1225   WidgetKeyboardEvent keyupEvent(true, NS_KEY_UP, mWidget);
  1226   InitKeyEvent(keyupEvent, mModKeyState);
  1227   if (aEventDispatched) {
  1228     *aEventDispatched = true;
  1230   return DispatchKeyEvent(keyupEvent, &mMsg);
  1233 bool
  1234 NativeKey::NeedsToHandleWithoutFollowingCharMessages() const
  1236   MOZ_ASSERT(IsKeyDownMessage());
  1238   // Enter and backspace are always handled here to avoid for example the
  1239   // confusion between ctrl-enter and ctrl-J.
  1240   if (mDOMKeyCode == NS_VK_RETURN || mDOMKeyCode == NS_VK_BACK) {
  1241     return true;
  1244   // If any modifier keys which may cause printable keys becoming non-printable
  1245   // are not pressed, we don't need special handling for the key.
  1246   if (!mModKeyState.IsControl() && !mModKeyState.IsAlt() &&
  1247       !mModKeyState.IsWin()) {
  1248     return false;
  1251   // If the key event causes dead key event, we don't need to dispatch keypress
  1252   // event.
  1253   if (mIsDeadKey && mCommittedCharsAndModifiers.IsEmpty()) {
  1254     return false;
  1257   // Even if the key is a printable key, it might cause non-printable character
  1258   // input with modifier key(s).
  1259   return mIsPrintableKey;
  1262 #ifdef MOZ_CRASHREPORTER
  1264 static nsCString
  1265 GetResultOfInSendMessageEx()
  1267   DWORD ret = ::InSendMessageEx(nullptr);
  1268   if (!ret) {
  1269     return NS_LITERAL_CSTRING("ISMEX_NOSEND");
  1271   nsAutoCString result;
  1272   if (ret & ISMEX_CALLBACK) {
  1273     result = "ISMEX_CALLBACK";
  1275   if (ret & ISMEX_NOTIFY) {
  1276     if (!result.IsEmpty()) {
  1277       result += " | ";
  1279     result += "ISMEX_NOTIFY";
  1281   if (ret & ISMEX_REPLIED) {
  1282     if (!result.IsEmpty()) {
  1283       result += " | ";
  1285     result += "ISMEX_REPLIED";
  1287   if (ret & ISMEX_SEND) {
  1288     if (!result.IsEmpty()) {
  1289       result += " | ";
  1291     result += "ISMEX_SEND";
  1293   return result;
  1296 static const char*
  1297 GetMessageName(UINT aMessage)
  1299   switch (aMessage) {
  1300     case WM_KEYDOWN:     return "WM_KEYDOWN";
  1301     case WM_SYSKEYDOWN:  return "WM_SYSKEYDOWN";
  1302     case WM_KEYUP:       return "WM_KEYUP";
  1303     case WM_SYSKEYUP:    return "WM_SYSKEYUP";
  1304     case WM_CHAR:        return "WM_CHAR";
  1305     case WM_DEADCHAR:    return "WM_DEADCHAR";
  1306     case WM_SYSCHAR:     return "WM_SYSCHAR";
  1307     case WM_SYSDEADCHAR: return "WM_SYSDEADCHAR";
  1308     case WM_UNICHAR:     return "WM_UNICHAR";
  1309     case WM_QUIT:        return "WM_QUIT";
  1310     case WM_NULL:        return "WM_NULL";
  1311     default:             return "Unknown";
  1315 #endif // #ifdef MOZ_CRASHREPORTER
  1317 bool
  1318 NativeKey::MayBeSameCharMessage(const MSG& aCharMsg1,
  1319                                 const MSG& aCharMsg2) const
  1321   // NOTE: Although, we don't know when this case occurs, the scan code value
  1322   //       in lParam may be changed from 0 to something.  The changed value
  1323   //       is different from the scan code of handling keydown message.
  1324   static const LPARAM kScanCodeMask = 0x00FF0000;
  1325   return
  1326     aCharMsg1.message == aCharMsg2.message &&
  1327     aCharMsg1.wParam == aCharMsg2.wParam &&
  1328     (aCharMsg1.lParam & ~kScanCodeMask) == (aCharMsg2.lParam & ~kScanCodeMask);
  1331 bool
  1332 NativeKey::GetFollowingCharMessage(MSG& aCharMsg) const
  1334   MOZ_ASSERT(IsKeyDownMessage());
  1336   aCharMsg.message = WM_NULL;
  1338   if (mFakeCharMsgs) {
  1339     FakeCharMsg& fakeCharMsg = mFakeCharMsgs->ElementAt(0);
  1340     if (fakeCharMsg.mConsumed) {
  1341       return false;
  1343     MSG charMsg = fakeCharMsg.GetCharMsg(mMsg.hwnd);
  1344     fakeCharMsg.mConsumed = true;
  1345     if (!IsCharMessage(charMsg)) {
  1346       return false;
  1348     aCharMsg = charMsg;
  1349     return true;
  1352   // If next key message is not char message, we should give up to find a
  1353   // related char message for the handling keydown event for now.
  1354   // Note that it's possible other applications may send other key message
  1355   // after we call TranslateMessage(). That may cause PeekMessage() failing
  1356   // to get char message for the handling keydown message.
  1357   MSG nextKeyMsg;
  1358   if (!WinUtils::PeekMessage(&nextKeyMsg, mMsg.hwnd, WM_KEYFIRST, WM_KEYLAST,
  1359                              PM_NOREMOVE | PM_NOYIELD) ||
  1360       !IsCharMessage(nextKeyMsg)) {
  1361     return false;
  1364   // On Metrofox, PeekMessage() sometimes returns WM_NULL even if we specify
  1365   // the message range.  So, if it returns WM_NULL, we should retry to get
  1366   // the following char message it was found above.
  1367   for (uint32_t i = 0; i < 5; i++) {
  1368     MSG removedMsg, nextKeyMsgInAllWindows;
  1369     bool doCrash = false;
  1370     if (!WinUtils::PeekMessage(&removedMsg, mMsg.hwnd,
  1371                                nextKeyMsg.message, nextKeyMsg.message,
  1372                                PM_REMOVE | PM_NOYIELD)) {
  1373       // We meets unexpected case.  We should collect the message queue state
  1374       // and crash for reporting the bug.
  1375       doCrash = true;
  1376       // The char message is redirected to different thread's window by focus
  1377       // move or something or just cancelled by external application.
  1378       if (!WinUtils::PeekMessage(&nextKeyMsgInAllWindows, 0,
  1379                                  WM_KEYFIRST, WM_KEYLAST,
  1380                                  PM_NOREMOVE | PM_NOYIELD)) {
  1381         return true;
  1383       if (MayBeSameCharMessage(nextKeyMsgInAllWindows, nextKeyMsg)) {
  1384         // The char message is redirected to different window created by our
  1385         // thread.
  1386         if (nextKeyMsgInAllWindows.hwnd != mMsg.hwnd) {
  1387           aCharMsg = nextKeyMsgInAllWindows;
  1388           return true;
  1390         // The found char message still in the queue, but PeekMessage() failed
  1391         // to remove it only with PM_REMOVE.  Although, we don't know why this
  1392         // occurs.  However, this occurs acctually.
  1393         // Try to remove the char message with GetMessage() again.
  1394         if (WinUtils::GetMessage(&removedMsg, mMsg.hwnd,
  1395                                  nextKeyMsg.message, nextKeyMsg.message)) {
  1396           // Cancel to crash, but we need to check the removed message value.
  1397           doCrash = false;
  1402     if (doCrash) {
  1403 #ifdef MOZ_CRASHREPORTER
  1404       nsPrintfCString info("\nPeekMessage() failed to remove char message! "
  1405                            "\nHandling message: %s (0x%08X), wParam: 0x%08X, "
  1406                            "lParam: 0x%08X, hwnd=0x%p, InSendMessageEx()=%s, \n"
  1407                            "Found message: %s (0x%08X), wParam: 0x%08X, "
  1408                            "lParam: 0x%08X, hwnd=0x%p, "
  1409                            "\nWM_NULL has been removed: %d, "
  1410                            "\nNext key message in all windows: %s (0x%08X), "
  1411                            "wParam: 0x%08X, lParam: 0x%08X, hwnd=0x%p, "
  1412                            "time=%d, ",
  1413                            GetMessageName(mMsg.message),
  1414                            mMsg.message, mMsg.wParam, mMsg.lParam,
  1415                            nextKeyMsg.hwnd,
  1416                            GetResultOfInSendMessageEx().get(),
  1417                            GetMessageName(nextKeyMsg.message),
  1418                            nextKeyMsg.message, nextKeyMsg.wParam,
  1419                            nextKeyMsg.lParam, nextKeyMsg.hwnd, i,
  1420                            GetMessageName(nextKeyMsgInAllWindows.message),
  1421                            nextKeyMsgInAllWindows.message,
  1422                            nextKeyMsgInAllWindows.wParam,
  1423                            nextKeyMsgInAllWindows.lParam,
  1424                            nextKeyMsgInAllWindows.hwnd,
  1425                            nextKeyMsgInAllWindows.time);
  1426       CrashReporter::AppendAppNotesToCrashReport(info);
  1427       MSG nextMsg;
  1428       if (WinUtils::PeekMessage(&nextMsg, 0, 0, 0,
  1429                                 PM_NOREMOVE | PM_NOYIELD)) {
  1430         nsPrintfCString info("\nNext message in all windows: %s (0x%08X), "
  1431                              "wParam: 0x%08X, lParam: 0x%08X, hwnd=0x%p, "
  1432                              "time=%d",
  1433                              GetMessageName(nextMsg.message),
  1434                              nextMsg.message, nextMsg.wParam, nextMsg.lParam,
  1435                              nextMsg.hwnd, nextMsg.time);
  1436         CrashReporter::AppendAppNotesToCrashReport(info);
  1437       } else {
  1438         CrashReporter::AppendAppNotesToCrashReport(
  1439           NS_LITERAL_CSTRING("\nThere is no message in any window"));
  1441 #endif // #ifdef MOZ_CRASHREPORTER
  1442       MOZ_CRASH("We lost the following char message");
  1445     // Retry for the strange case.
  1446     if (removedMsg.message == WM_NULL) {
  1447       continue;
  1450     // Typically, this case occurs with WM_DEADCHAR.  If the removed message's
  1451     // wParam becomes 0, that means that the key event shouldn't cause text
  1452     // input.  So, let's ignore the strange char message.
  1453     if (removedMsg.message == nextKeyMsg.message && !removedMsg.wParam) {
  1454       return false;
  1457     // NOTE: Although, we don't know when this case occurs, the scan code value
  1458     //       in lParam may be changed from 0 to something.  The changed value
  1459     //       is different from the scan code of handling keydown message.
  1460     if (!MayBeSameCharMessage(removedMsg, nextKeyMsg)) {
  1461 #ifdef MOZ_CRASHREPORTER
  1462       nsPrintfCString info("\nPeekMessage() removed unexpcted char message! "
  1463                            "\nHandling message: %s (0x%08X), wParam: 0x%08X, "
  1464                            "lParam: 0x%08X, hwnd=0x%p, InSendMessageEx()=%s, "
  1465                            "\nFound message: %s (0x%08X), wParam: 0x%08X, "
  1466                            "lParam: 0x%08X, hwnd=0x%p, "
  1467                            "\nRemoved message: %s (0x%08X), wParam: 0x%08X, "
  1468                            "lParam: 0x%08X, hwnd=0x%p, ",
  1469                            GetMessageName(mMsg.message),
  1470                            mMsg.message, mMsg.wParam, mMsg.lParam, mMsg.hwnd,
  1471                            GetResultOfInSendMessageEx().get(),
  1472                            GetMessageName(nextKeyMsg.message),
  1473                            nextKeyMsg.message, nextKeyMsg.wParam,
  1474                            nextKeyMsg.lParam, nextKeyMsg.hwnd,
  1475                            GetMessageName(removedMsg.message),
  1476                            removedMsg.message, removedMsg.wParam,
  1477                            removedMsg.lParam, removedMsg.hwnd);
  1478       CrashReporter::AppendAppNotesToCrashReport(info);
  1479       // What's the next key message?
  1480       MSG nextKeyMsgAfter;
  1481       if (WinUtils::PeekMessage(&nextKeyMsgAfter, mMsg.hwnd,
  1482                                 WM_KEYFIRST, WM_KEYLAST,
  1483                                 PM_NOREMOVE | PM_NOYIELD)) {
  1484         nsPrintfCString info("\nNext key message after unexpected char message "
  1485                              "removed: %s (0x%08X), wParam: 0x%08X, "
  1486                              "lParam: 0x%08X, hwnd=0x%p, ",
  1487                              GetMessageName(nextKeyMsgAfter.message),
  1488                              nextKeyMsgAfter.message, nextKeyMsgAfter.wParam,
  1489                              nextKeyMsgAfter.lParam, nextKeyMsgAfter.hwnd);
  1490         CrashReporter::AppendAppNotesToCrashReport(info);
  1491       } else {
  1492         CrashReporter::AppendAppNotesToCrashReport(
  1493           NS_LITERAL_CSTRING("\nThere is no key message after unexpected char "
  1494                              "message removed, "));
  1496       // Another window has a key message?
  1497       MSG nextKeyMsgInAllWindows;
  1498       if (WinUtils::PeekMessage(&nextKeyMsgInAllWindows, 0,
  1499                                 WM_KEYFIRST, WM_KEYLAST,
  1500                                 PM_NOREMOVE | PM_NOYIELD)) {
  1501         nsPrintfCString info("\nNext key message in all windows: %s (0x%08X), "
  1502                              "wParam: 0x%08X, lParam: 0x%08X, hwnd=0x%p.",
  1503                              GetMessageName(nextKeyMsgInAllWindows.message),
  1504                              nextKeyMsgInAllWindows.message,
  1505                              nextKeyMsgInAllWindows.wParam,
  1506                              nextKeyMsgInAllWindows.lParam,
  1507                              nextKeyMsgInAllWindows.hwnd);
  1508         CrashReporter::AppendAppNotesToCrashReport(info);
  1509       } else {
  1510         CrashReporter::AppendAppNotesToCrashReport(
  1511           NS_LITERAL_CSTRING("\nThere is no key message in any windows."));
  1513 #endif // #ifdef MOZ_CRASHREPORTER
  1514       MOZ_CRASH("PeekMessage() removed unexpected message");
  1517     aCharMsg = removedMsg;
  1518     return true;
  1520 #ifdef MOZ_CRASHREPORTER
  1521   nsPrintfCString info("\nWe lost following char message! "
  1522                        "\nHandling message: %s (0x%08X), wParam: 0x%08X, "
  1523                        "lParam: 0x%08X, InSendMessageEx()=%s, \n"
  1524                        "Found message: %s (0x%08X), wParam: 0x%08X, "
  1525                        "lParam: 0x%08X, removed a lot of WM_NULL",
  1526                        GetMessageName(mMsg.message),
  1527                        mMsg.message, mMsg.wParam, mMsg.lParam,
  1528                        GetResultOfInSendMessageEx().get(),
  1529                        GetMessageName(nextKeyMsg.message),
  1530                        nextKeyMsg.message, nextKeyMsg.wParam,
  1531                        nextKeyMsg.lParam);
  1532   CrashReporter::AppendAppNotesToCrashReport(info);
  1533 #endif // #ifdef MOZ_CRASHREPORTER
  1534   MOZ_CRASH("We lost the following char message");
  1535   return false;
  1538 bool
  1539 NativeKey::DispatchPluginEventsAndDiscardsCharMessages() const
  1541   MOZ_ASSERT(IsKeyDownMessage());
  1543   // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
  1544   // They can be more than one because of:
  1545   //  * Dead-keys not pairing with base character
  1546   //  * Some keyboard layouts may map up to 4 characters to the single key
  1547   bool anyCharMessagesRemoved = false;
  1548   MSG msg;
  1549   while (GetFollowingCharMessage(msg)) {
  1550     if (msg.message == WM_NULL) {
  1551       continue;
  1553     anyCharMessagesRemoved = true;
  1554     // If the window handle is changed, focused window must be changed.
  1555     // So, plugin shouldn't handle it anymore.
  1556     if (msg.hwnd != mMsg.hwnd) {
  1557       break;
  1559     MOZ_RELEASE_ASSERT(!mWidget->Destroyed(),
  1560       "NativeKey tries to dispatch a plugin event on destroyed widget");
  1561     mWidget->DispatchPluginEvent(msg);
  1562     if (mWidget->Destroyed()) {
  1563       return true;
  1567   if (!mFakeCharMsgs && !anyCharMessagesRemoved &&
  1568       mDOMKeyCode == NS_VK_BACK && IsIMEDoingKakuteiUndo()) {
  1569     // This is for a hack for ATOK and WXG.  So, PeekMessage() must scceed!
  1570     while (WinUtils::PeekMessage(&msg, mMsg.hwnd, WM_CHAR, WM_CHAR,
  1571                                  PM_REMOVE | PM_NOYIELD)) {
  1572       if (msg.message != WM_CHAR) {
  1573         MOZ_RELEASE_ASSERT(msg.message == WM_NULL,
  1574                            "Unexpected message was removed");
  1575         continue;
  1577       MOZ_RELEASE_ASSERT(!mWidget->Destroyed(),
  1578         "NativeKey tries to dispatch a plugin event on destroyed widget");
  1579       mWidget->DispatchPluginEvent(msg);
  1580       return mWidget->Destroyed();
  1582     MOZ_CRASH("NativeKey failed to get WM_CHAR for ATOK or WXG");
  1585   return false;
  1588 bool
  1589 NativeKey::DispatchKeyPressEventsWithKeyboardLayout() const
  1591   MOZ_ASSERT(IsKeyDownMessage());
  1592   MOZ_ASSERT(!mIsDeadKey);
  1594   KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
  1596   UniCharsAndModifiers inputtingChars(mCommittedCharsAndModifiers);
  1597   UniCharsAndModifiers shiftedChars;
  1598   UniCharsAndModifiers unshiftedChars;
  1599   uint32_t shiftedLatinChar = 0;
  1600   uint32_t unshiftedLatinChar = 0;
  1602   if (!KeyboardLayout::IsPrintableCharKey(mVirtualKeyCode)) {
  1603     inputtingChars.Clear();
  1606   if (mModKeyState.IsControl() ^ mModKeyState.IsAlt()) {
  1607     ModifierKeyState capsLockState(
  1608                        mModKeyState.GetModifiers() & MODIFIER_CAPSLOCK);
  1610     unshiftedChars =
  1611       keyboardLayout->GetUniCharsAndModifiers(mVirtualKeyCode, capsLockState);
  1612     capsLockState.Set(MODIFIER_SHIFT);
  1613     shiftedChars =
  1614       keyboardLayout->GetUniCharsAndModifiers(mVirtualKeyCode, capsLockState);
  1616     // The current keyboard cannot input alphabets or numerics,
  1617     // we should append them for Shortcut/Access keys.
  1618     // E.g., for Cyrillic keyboard layout.
  1619     capsLockState.Unset(MODIFIER_SHIFT);
  1620     WidgetUtils::GetLatinCharCodeForKeyCode(mDOMKeyCode,
  1621                                             capsLockState.GetModifiers(),
  1622                                             &unshiftedLatinChar,
  1623                                             &shiftedLatinChar);
  1625     // If the shiftedLatinChar isn't 0, the key code is NS_VK_[A-Z].
  1626     if (shiftedLatinChar) {
  1627       // If the produced characters of the key on current keyboard layout
  1628       // are same as computed Latin characters, we shouldn't append the
  1629       // Latin characters to alternativeCharCode.
  1630       if (unshiftedLatinChar == unshiftedChars.mChars[0] &&
  1631           shiftedLatinChar == shiftedChars.mChars[0]) {
  1632         shiftedLatinChar = unshiftedLatinChar = 0;
  1634     } else if (unshiftedLatinChar) {
  1635       // If the shiftedLatinChar is 0, the keyCode doesn't produce
  1636       // alphabet character.  At that time, the character may be produced
  1637       // with Shift key.  E.g., on French keyboard layout, NS_VK_PERCENT
  1638       // key produces LATIN SMALL LETTER U WITH GRAVE (U+00F9) without
  1639       // Shift key but with Shift key, it produces '%'.
  1640       // If the unshiftedLatinChar is produced by the key on current
  1641       // keyboard layout, we shouldn't append it to alternativeCharCode.
  1642       if (unshiftedLatinChar == unshiftedChars.mChars[0] ||
  1643           unshiftedLatinChar == shiftedChars.mChars[0]) {
  1644         unshiftedLatinChar = 0;
  1648     // If the charCode is not ASCII character, we should replace the
  1649     // charCode with ASCII character only when Ctrl is pressed.
  1650     // But don't replace the charCode when the charCode is not same as
  1651     // unmodified characters. In such case, Ctrl is sometimes used for a
  1652     // part of character inputting key combination like Shift.
  1653     if (mModKeyState.IsControl()) {
  1654       uint32_t ch =
  1655         mModKeyState.IsShift() ? shiftedLatinChar : unshiftedLatinChar;
  1656       if (ch &&
  1657           (!inputtingChars.mLength ||
  1658            inputtingChars.UniCharsCaseInsensitiveEqual(
  1659              mModKeyState.IsShift() ? shiftedChars : unshiftedChars))) {
  1660         inputtingChars.Clear();
  1661         inputtingChars.Append(ch, mModKeyState.GetModifiers());
  1666   if (inputtingChars.IsEmpty() &&
  1667       shiftedChars.IsEmpty() && unshiftedChars.IsEmpty()) {
  1668     WidgetKeyboardEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
  1669     keypressEvent.keyCode = mDOMKeyCode;
  1670     InitKeyEvent(keypressEvent, mModKeyState);
  1671     return DispatchKeyEvent(keypressEvent);
  1674   uint32_t longestLength =
  1675     std::max(inputtingChars.mLength,
  1676              std::max(shiftedChars.mLength, unshiftedChars.mLength));
  1677   uint32_t skipUniChars = longestLength - inputtingChars.mLength;
  1678   uint32_t skipShiftedChars = longestLength - shiftedChars.mLength;
  1679   uint32_t skipUnshiftedChars = longestLength - unshiftedChars.mLength;
  1680   UINT keyCode = !inputtingChars.mLength ? mDOMKeyCode : 0;
  1681   bool defaultPrevented = false;
  1682   for (uint32_t cnt = 0; cnt < longestLength; cnt++) {
  1683     uint16_t uniChar, shiftedChar, unshiftedChar;
  1684     uniChar = shiftedChar = unshiftedChar = 0;
  1685     ModifierKeyState modKeyState(mModKeyState);
  1686     if (skipUniChars <= cnt) {
  1687       if (cnt - skipUniChars  < inputtingChars.mLength) {
  1688         // If key in combination with Alt and/or Ctrl produces a different
  1689         // character than without them then do not report these flags
  1690         // because it is separate keyboard layout shift state. If dead-key
  1691         // and base character does not produce a valid composite character
  1692         // then both produced dead-key character and following base
  1693         // character may have different modifier flags, too.
  1694         modKeyState.Unset(MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT |
  1695                           MODIFIER_ALTGRAPH | MODIFIER_CAPSLOCK);
  1696         modKeyState.Set(inputtingChars.mModifiers[cnt - skipUniChars]);
  1698       uniChar = inputtingChars.mChars[cnt - skipUniChars];
  1700     if (skipShiftedChars <= cnt)
  1701       shiftedChar = shiftedChars.mChars[cnt - skipShiftedChars];
  1702     if (skipUnshiftedChars <= cnt)
  1703       unshiftedChar = unshiftedChars.mChars[cnt - skipUnshiftedChars];
  1704     nsAutoTArray<AlternativeCharCode, 5> altArray;
  1706     if (shiftedChar || unshiftedChar) {
  1707       AlternativeCharCode chars(unshiftedChar, shiftedChar);
  1708       altArray.AppendElement(chars);
  1710     if (cnt == longestLength - 1) {
  1711       if (unshiftedLatinChar || shiftedLatinChar) {
  1712         AlternativeCharCode chars(unshiftedLatinChar, shiftedLatinChar);
  1713         altArray.AppendElement(chars);
  1716       // Typically, following virtual keycodes are used for a key which can
  1717       // input the character.  However, these keycodes are also used for
  1718       // other keys on some keyboard layout.  E.g., in spite of Shift+'1'
  1719       // inputs '+' on Thai keyboard layout, a key which is at '=/+'
  1720       // key on ANSI keyboard layout is VK_OEM_PLUS.  Native applications
  1721       // handle it as '+' key if Ctrl key is pressed.
  1722       char16_t charForOEMKeyCode = 0;
  1723       switch (mVirtualKeyCode) {
  1724         case VK_OEM_PLUS:   charForOEMKeyCode = '+'; break;
  1725         case VK_OEM_COMMA:  charForOEMKeyCode = ','; break;
  1726         case VK_OEM_MINUS:  charForOEMKeyCode = '-'; break;
  1727         case VK_OEM_PERIOD: charForOEMKeyCode = '.'; break;
  1729       if (charForOEMKeyCode &&
  1730           charForOEMKeyCode != unshiftedChars.mChars[0] &&
  1731           charForOEMKeyCode != shiftedChars.mChars[0] &&
  1732           charForOEMKeyCode != unshiftedLatinChar &&
  1733           charForOEMKeyCode != shiftedLatinChar) {
  1734         AlternativeCharCode OEMChars(charForOEMKeyCode, charForOEMKeyCode);
  1735         altArray.AppendElement(OEMChars);
  1739     WidgetKeyboardEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
  1740     keypressEvent.charCode = uniChar;
  1741     keypressEvent.alternativeCharCodes.AppendElements(altArray);
  1742     InitKeyEvent(keypressEvent, modKeyState);
  1743     defaultPrevented = (DispatchKeyEvent(keypressEvent) || defaultPrevented);
  1744     if (mWidget->Destroyed()) {
  1745       return true;
  1749   return defaultPrevented;
  1752 bool
  1753 NativeKey::DispatchKeyPressEventForFollowingCharMessage(
  1754              const MSG& aCharMsg) const
  1756   MOZ_ASSERT(IsKeyDownMessage());
  1758   if (mFakeCharMsgs) {
  1759     if (IsDeadCharMessage(aCharMsg)) {
  1760       return false;
  1762 #ifdef DEBUG
  1763     if (mIsPrintableKey) {
  1764       nsPrintfCString log(
  1765         "mOriginalVirtualKeyCode=0x%02X, mCommittedCharsAndModifiers={ "
  1766         "mChars=[ 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X ], mLength=%d }, "
  1767         "wParam=0x%04X",
  1768         mOriginalVirtualKeyCode, mCommittedCharsAndModifiers.mChars[0],
  1769         mCommittedCharsAndModifiers.mChars[1],
  1770         mCommittedCharsAndModifiers.mChars[2],
  1771         mCommittedCharsAndModifiers.mChars[3],
  1772         mCommittedCharsAndModifiers.mChars[4],
  1773         mCommittedCharsAndModifiers.mLength, aCharMsg.wParam);
  1774       if (mCommittedCharsAndModifiers.IsEmpty()) {
  1775         log.Insert("length is zero: ", 0);
  1776         NS_ERROR(log.get());
  1777         NS_ABORT();
  1778       } else if (mCommittedCharsAndModifiers.mChars[0] != aCharMsg.wParam) {
  1779         log.Insert("character mismatch: ", 0);
  1780         NS_ERROR(log.get());
  1781         NS_ABORT();
  1784 #endif // #ifdef DEBUG
  1785     return HandleCharMessage(aCharMsg);
  1788   if (IsDeadCharMessage(aCharMsg)) {
  1789     if (!mWidget->PluginHasFocus()) {
  1790       return false;
  1792     return (mWidget->DispatchPluginEvent(aCharMsg) || mWidget->Destroyed());
  1795   bool defaultPrevented = HandleCharMessage(aCharMsg);
  1796   // If a syschar keypress wasn't processed, Windows may want to
  1797   // handle it to activate a native menu.
  1798   if (!defaultPrevented && IsSysCharMessage(aCharMsg)) {
  1799     ::DefWindowProcW(aCharMsg.hwnd, aCharMsg.message,
  1800                      aCharMsg.wParam, aCharMsg.lParam);
  1802   return defaultPrevented;
  1805 /*****************************************************************************
  1806  * mozilla::widget::KeyboardLayout
  1807  *****************************************************************************/
  1809 KeyboardLayout* KeyboardLayout::sInstance = nullptr;
  1810 nsIIdleServiceInternal* KeyboardLayout::sIdleService = nullptr;
  1812 // static
  1813 KeyboardLayout*
  1814 KeyboardLayout::GetInstance()
  1816   if (!sInstance) {
  1817     sInstance = new KeyboardLayout();
  1818     nsCOMPtr<nsIIdleServiceInternal> idleService =
  1819       do_GetService("@mozilla.org/widget/idleservice;1");
  1820     // The refcount will be decreased at shut down.
  1821     sIdleService = idleService.forget().take();
  1823   return sInstance;
  1826 // static
  1827 void
  1828 KeyboardLayout::Shutdown()
  1830   delete sInstance;
  1831   sInstance = nullptr;
  1832   NS_IF_RELEASE(sIdleService);
  1835 // static
  1836 void
  1837 KeyboardLayout::NotifyIdleServiceOfUserActivity()
  1839   sIdleService->ResetIdleTimeOut(0);
  1842 KeyboardLayout::KeyboardLayout() :
  1843   mKeyboardLayout(0), mIsOverridden(false),
  1844   mIsPendingToRestoreKeyboardLayout(false)
  1846   mDeadKeyTableListHead = nullptr;
  1848   // NOTE: LoadLayout() should be called via OnLayoutChange().
  1851 KeyboardLayout::~KeyboardLayout()
  1853   ReleaseDeadKeyTables();
  1856 bool
  1857 KeyboardLayout::IsPrintableCharKey(uint8_t aVirtualKey)
  1859   return GetKeyIndex(aVirtualKey) >= 0;
  1862 WORD
  1863 KeyboardLayout::ComputeScanCodeForVirtualKeyCode(uint8_t aVirtualKeyCode) const
  1865   return static_cast<WORD>(
  1866            ::MapVirtualKeyEx(aVirtualKeyCode, MAPVK_VK_TO_VSC, GetLayout()));
  1869 bool
  1870 KeyboardLayout::IsDeadKey(uint8_t aVirtualKey,
  1871                           const ModifierKeyState& aModKeyState) const
  1873   int32_t virtualKeyIndex = GetKeyIndex(aVirtualKey);
  1874   if (virtualKeyIndex < 0) {
  1875     return false;
  1878   return mVirtualKeys[virtualKeyIndex].IsDeadKey(
  1879            VirtualKey::ModifiersToShiftState(aModKeyState.GetModifiers()));
  1882 void
  1883 KeyboardLayout::InitNativeKey(NativeKey& aNativeKey,
  1884                               const ModifierKeyState& aModKeyState)
  1886   if (mIsPendingToRestoreKeyboardLayout) {
  1887     LoadLayout(::GetKeyboardLayout(0));
  1890   uint8_t virtualKey = aNativeKey.mOriginalVirtualKeyCode;
  1891   int32_t virtualKeyIndex = GetKeyIndex(virtualKey);
  1893   if (virtualKeyIndex < 0) {
  1894     // Does not produce any printable characters, but still preserves the
  1895     // dead-key state.
  1896     return;
  1899   MOZ_ASSERT(aNativeKey.mKeyNameIndex == KEY_NAME_INDEX_USE_STRING,
  1900     "Printable key's key name index must be KEY_NAME_INDEX_USE_STRING");
  1902   bool isKeyDown = aNativeKey.IsKeyDownMessage();
  1903   uint8_t shiftState =
  1904     VirtualKey::ModifiersToShiftState(aModKeyState.GetModifiers());
  1906   if (mVirtualKeys[virtualKeyIndex].IsDeadKey(shiftState)) {
  1907     if ((isKeyDown && mActiveDeadKey < 0) ||
  1908         (!isKeyDown && mActiveDeadKey == virtualKey)) {
  1909       //  First dead key event doesn't generate characters.
  1910       if (isKeyDown) {
  1911         // Dead-key state activated at keydown.
  1912         mActiveDeadKey = virtualKey;
  1913         mDeadKeyShiftState = shiftState;
  1915       UniCharsAndModifiers deadChars =
  1916         mVirtualKeys[virtualKeyIndex].GetNativeUniChars(shiftState);
  1917       NS_ASSERTION(deadChars.mLength == 1,
  1918                    "dead key must generate only one character");
  1919       aNativeKey.mKeyNameIndex =
  1920         WidgetUtils::GetDeadKeyNameIndex(deadChars.mChars[0]);
  1921       return;
  1924     // Dead key followed by another dead key causes inputting both character.
  1925     // However, at keydown message handling, we need to forget the first
  1926     // dead key because there is no guarantee coming WM_KEYUP for the second
  1927     // dead key before next WM_KEYDOWN.  E.g., due to auto key repeat or
  1928     // pressing another dead key before releasing current key.  Therefore,
  1929     // we can set only a character for current key for keyup event.
  1930     if (mActiveDeadKey < 0) {
  1931       aNativeKey.mCommittedCharsAndModifiers =
  1932         mVirtualKeys[virtualKeyIndex].GetUniChars(shiftState);
  1933       return;
  1936     int32_t activeDeadKeyIndex = GetKeyIndex(mActiveDeadKey);
  1937     if (activeDeadKeyIndex < 0 || activeDeadKeyIndex >= NS_NUM_OF_KEYS) {
  1938 #if defined(DEBUG) || defined(MOZ_CRASHREPORTER)
  1939       nsPrintfCString warning("The virtual key index (%d) of mActiveDeadKey "
  1940                               "(0x%02X) is not a printable key (virtualKey="
  1941                               "0x%02X)",
  1942                               activeDeadKeyIndex, mActiveDeadKey, virtualKey);
  1943       NS_WARNING(warning.get());
  1944 #ifdef MOZ_CRASHREPORTER
  1945       CrashReporter::AppendAppNotesToCrashReport(
  1946                        NS_LITERAL_CSTRING("\n") + warning);
  1947 #endif // #ifdef MOZ_CRASHREPORTER
  1948 #endif // #if defined(DEBUG) || defined(MOZ_CRASHREPORTER)
  1949       MOZ_CRASH("Trying to reference out of range of mVirtualKeys");
  1951     UniCharsAndModifiers prevDeadChars =
  1952       mVirtualKeys[activeDeadKeyIndex].GetUniChars(mDeadKeyShiftState);
  1953     UniCharsAndModifiers newChars =
  1954       mVirtualKeys[virtualKeyIndex].GetUniChars(shiftState);
  1955     // But keypress events should be fired for each committed character.
  1956     aNativeKey.mCommittedCharsAndModifiers = prevDeadChars + newChars;
  1957     if (isKeyDown) {
  1958       DeactivateDeadKeyState();
  1960     return;
  1963   UniCharsAndModifiers baseChars =
  1964     mVirtualKeys[virtualKeyIndex].GetUniChars(shiftState);
  1965   if (mActiveDeadKey < 0) {
  1966     // No dead-keys are active. Just return the produced characters.
  1967     aNativeKey.mCommittedCharsAndModifiers = baseChars;
  1968     return;
  1971   // Dead-key was active. See if pressed base character does produce
  1972   // valid composite character.
  1973   int32_t activeDeadKeyIndex = GetKeyIndex(mActiveDeadKey);
  1974   char16_t compositeChar = (baseChars.mLength == 1 && baseChars.mChars[0]) ?
  1975     mVirtualKeys[activeDeadKeyIndex].GetCompositeChar(mDeadKeyShiftState,
  1976                                                       baseChars.mChars[0]) : 0;
  1977   if (compositeChar) {
  1978     // Active dead-key and base character does produce exactly one
  1979     // composite character.
  1980     aNativeKey.mCommittedCharsAndModifiers.Append(compositeChar,
  1981                                                   baseChars.mModifiers[0]);
  1982     if (isKeyDown) {
  1983       DeactivateDeadKeyState();
  1985     return;
  1988   // There is no valid dead-key and base character combination.
  1989   // Return dead-key character followed by base character.
  1990   UniCharsAndModifiers deadChars =
  1991     mVirtualKeys[activeDeadKeyIndex].GetUniChars(mDeadKeyShiftState);
  1992   // But keypress events should be fired for each committed character.
  1993   aNativeKey.mCommittedCharsAndModifiers = deadChars + baseChars;
  1994   if (isKeyDown) {
  1995     DeactivateDeadKeyState();
  1998   return;
  2001 UniCharsAndModifiers
  2002 KeyboardLayout::GetUniCharsAndModifiers(
  2003                   uint8_t aVirtualKey,
  2004                   const ModifierKeyState& aModKeyState) const
  2006   UniCharsAndModifiers result;
  2007   int32_t key = GetKeyIndex(aVirtualKey);
  2008   if (key < 0) {
  2009     return result;
  2011   return mVirtualKeys[key].
  2012     GetUniChars(VirtualKey::ModifiersToShiftState(aModKeyState.GetModifiers()));
  2015 void
  2016 KeyboardLayout::LoadLayout(HKL aLayout)
  2018   mIsPendingToRestoreKeyboardLayout = false;
  2020   if (mKeyboardLayout == aLayout) {
  2021     return;
  2024   mKeyboardLayout = aLayout;
  2026   BYTE kbdState[256];
  2027   memset(kbdState, 0, sizeof(kbdState));
  2029   BYTE originalKbdState[256];
  2030   // Bitfield with all shift states that have at least one dead-key.
  2031   uint16_t shiftStatesWithDeadKeys = 0;
  2032   // Bitfield with all shift states that produce any possible dead-key base
  2033   // characters.
  2034   uint16_t shiftStatesWithBaseChars = 0;
  2036   mActiveDeadKey = -1;
  2038   ReleaseDeadKeyTables();
  2040   ::GetKeyboardState(originalKbdState);
  2042   // For each shift state gather all printable characters that are produced
  2043   // for normal case when no any dead-key is active.
  2045   for (VirtualKey::ShiftState shiftState = 0; shiftState < 16; shiftState++) {
  2046     VirtualKey::FillKbdState(kbdState, shiftState);
  2047     for (uint32_t virtualKey = 0; virtualKey < 256; virtualKey++) {
  2048       int32_t vki = GetKeyIndex(virtualKey);
  2049       if (vki < 0) {
  2050         continue;
  2052       NS_ASSERTION(uint32_t(vki) < ArrayLength(mVirtualKeys), "invalid index");
  2053       char16_t uniChars[5];
  2054       int32_t ret =
  2055         ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)uniChars,
  2056                       ArrayLength(uniChars), 0, mKeyboardLayout);
  2057       // dead-key
  2058       if (ret < 0) {
  2059         shiftStatesWithDeadKeys |= (1 << shiftState);
  2060         // Repeat dead-key to deactivate it and get its character
  2061         // representation.
  2062         char16_t deadChar[2];
  2063         ret = ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)deadChar,
  2064                             ArrayLength(deadChar), 0, mKeyboardLayout);
  2065         NS_ASSERTION(ret == 2, "Expecting twice repeated dead-key character");
  2066         mVirtualKeys[vki].SetDeadChar(shiftState, deadChar[0]);
  2067       } else {
  2068         if (ret == 1) {
  2069           // dead-key can pair only with exactly one base character.
  2070           shiftStatesWithBaseChars |= (1 << shiftState);
  2072         mVirtualKeys[vki].SetNormalChars(shiftState, uniChars, ret);
  2077   // Now process each dead-key to find all its base characters and resulting
  2078   // composite characters.
  2079   for (VirtualKey::ShiftState shiftState = 0; shiftState < 16; shiftState++) {
  2080     if (!(shiftStatesWithDeadKeys & (1 << shiftState))) {
  2081       continue;
  2084     VirtualKey::FillKbdState(kbdState, shiftState);
  2086     for (uint32_t virtualKey = 0; virtualKey < 256; virtualKey++) {
  2087       int32_t vki = GetKeyIndex(virtualKey);
  2088       if (vki >= 0 && mVirtualKeys[vki].IsDeadKey(shiftState)) {
  2089         DeadKeyEntry deadKeyArray[256];
  2090         int32_t n = GetDeadKeyCombinations(virtualKey, kbdState,
  2091                                            shiftStatesWithBaseChars,
  2092                                            deadKeyArray,
  2093                                            ArrayLength(deadKeyArray));
  2094         const DeadKeyTable* dkt =
  2095           mVirtualKeys[vki].MatchingDeadKeyTable(deadKeyArray, n);
  2096         if (!dkt) {
  2097           dkt = AddDeadKeyTable(deadKeyArray, n);
  2099         mVirtualKeys[vki].AttachDeadKeyTable(shiftState, dkt);
  2104   ::SetKeyboardState(originalKbdState);
  2107 inline int32_t
  2108 KeyboardLayout::GetKeyIndex(uint8_t aVirtualKey)
  2110 // Currently these 68 (NS_NUM_OF_KEYS) virtual keys are assumed
  2111 // to produce visible representation:
  2112 // 0x20 - VK_SPACE          ' '
  2113 // 0x30..0x39               '0'..'9'
  2114 // 0x41..0x5A               'A'..'Z'
  2115 // 0x60..0x69               '0'..'9' on numpad
  2116 // 0x6A - VK_MULTIPLY       '*' on numpad
  2117 // 0x6B - VK_ADD            '+' on numpad
  2118 // 0x6D - VK_SUBTRACT       '-' on numpad
  2119 // 0x6E - VK_DECIMAL        '.' on numpad
  2120 // 0x6F - VK_DIVIDE         '/' on numpad
  2121 // 0x6E - VK_DECIMAL        '.'
  2122 // 0xBA - VK_OEM_1          ';:' for US
  2123 // 0xBB - VK_OEM_PLUS       '+' any country
  2124 // 0xBC - VK_OEM_COMMA      ',' any country
  2125 // 0xBD - VK_OEM_MINUS      '-' any country
  2126 // 0xBE - VK_OEM_PERIOD     '.' any country
  2127 // 0xBF - VK_OEM_2          '/?' for US
  2128 // 0xC0 - VK_OEM_3          '`~' for US
  2129 // 0xC1 - VK_ABNT_C1        '/?' for Brazilian
  2130 // 0xC2 - VK_ABNT_C2        separator key on numpad (Brazilian or JIS for Mac)
  2131 // 0xDB - VK_OEM_4          '[{' for US
  2132 // 0xDC - VK_OEM_5          '\|' for US
  2133 // 0xDD - VK_OEM_6          ']}' for US
  2134 // 0xDE - VK_OEM_7          ''"' for US
  2135 // 0xDF - VK_OEM_8
  2136 // 0xE1 - no name
  2137 // 0xE2 - VK_OEM_102        '\_' for JIS
  2138 // 0xE3 - no name
  2139 // 0xE4 - no name
  2141   static const int8_t xlat[256] =
  2143   // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
  2144   //-----------------------------------------------------------------------
  2145     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // 00
  2146     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // 10
  2147      0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // 20
  2148      1,  2,  3,  4,  5,  6,  7,  8,  9, 10, -1, -1, -1, -1, -1, -1,   // 30
  2149     -1, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,   // 40
  2150     26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, -1, -1, -1,   // 50
  2151     37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, -1, 49, 50, 51,   // 60
  2152     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // 70
  2153     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // 80
  2154     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // 90
  2155     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // A0
  2156     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 52, 53, 54, 55, 56, 57,   // B0
  2157     58, 59, 60, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // C0
  2158     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 61, 62, 63, 64, 65,   // D0
  2159     -1, 66, 67, 68, 69, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // E0
  2160     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1    // F0
  2161   };
  2163   return xlat[aVirtualKey];
  2166 int
  2167 KeyboardLayout::CompareDeadKeyEntries(const void* aArg1,
  2168                                       const void* aArg2,
  2169                                       void*)
  2171   const DeadKeyEntry* arg1 = static_cast<const DeadKeyEntry*>(aArg1);
  2172   const DeadKeyEntry* arg2 = static_cast<const DeadKeyEntry*>(aArg2);
  2174   return arg1->BaseChar - arg2->BaseChar;
  2177 const DeadKeyTable*
  2178 KeyboardLayout::AddDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
  2179                                 uint32_t aEntries)
  2181   DeadKeyTableListEntry* next = mDeadKeyTableListHead;
  2183   const size_t bytes = offsetof(DeadKeyTableListEntry, data) +
  2184     DeadKeyTable::SizeInBytes(aEntries);
  2185   uint8_t* p = new uint8_t[bytes];
  2187   mDeadKeyTableListHead = reinterpret_cast<DeadKeyTableListEntry*>(p);
  2188   mDeadKeyTableListHead->next = next;
  2190   DeadKeyTable* dkt =
  2191     reinterpret_cast<DeadKeyTable*>(mDeadKeyTableListHead->data);
  2193   dkt->Init(aDeadKeyArray, aEntries);
  2195   return dkt;
  2198 void
  2199 KeyboardLayout::ReleaseDeadKeyTables()
  2201   while (mDeadKeyTableListHead) {
  2202     uint8_t* p = reinterpret_cast<uint8_t*>(mDeadKeyTableListHead);
  2203     mDeadKeyTableListHead = mDeadKeyTableListHead->next;
  2205     delete [] p;
  2209 bool
  2210 KeyboardLayout::EnsureDeadKeyActive(bool aIsActive,
  2211                                     uint8_t aDeadKey,
  2212                                     const PBYTE aDeadKeyKbdState)
  2214   int32_t ret;
  2215   do {
  2216     char16_t dummyChars[5];
  2217     ret = ::ToUnicodeEx(aDeadKey, 0, (PBYTE)aDeadKeyKbdState,
  2218                         (LPWSTR)dummyChars, ArrayLength(dummyChars), 0,
  2219                         mKeyboardLayout);
  2220     // returned values:
  2221     // <0 - Dead key state is active. The keyboard driver will wait for next
  2222     //      character.
  2223     //  1 - Previous pressed key was a valid base character that produced
  2224     //      exactly one composite character.
  2225     // >1 - Previous pressed key does not produce any composite characters.
  2226     //      Return dead-key character followed by base character(s).
  2227   } while ((ret < 0) != aIsActive);
  2229   return (ret < 0);
  2232 void
  2233 KeyboardLayout::DeactivateDeadKeyState()
  2235   if (mActiveDeadKey < 0) {
  2236     return;
  2239   BYTE kbdState[256];
  2240   memset(kbdState, 0, sizeof(kbdState));
  2242   VirtualKey::FillKbdState(kbdState, mDeadKeyShiftState);
  2244   EnsureDeadKeyActive(false, mActiveDeadKey, kbdState);
  2245   mActiveDeadKey = -1;
  2248 bool
  2249 KeyboardLayout::AddDeadKeyEntry(char16_t aBaseChar,
  2250                                 char16_t aCompositeChar,
  2251                                 DeadKeyEntry* aDeadKeyArray,
  2252                                 uint32_t aEntries)
  2254   for (uint32_t index = 0; index < aEntries; index++) {
  2255     if (aDeadKeyArray[index].BaseChar == aBaseChar) {
  2256       return false;
  2260   aDeadKeyArray[aEntries].BaseChar = aBaseChar;
  2261   aDeadKeyArray[aEntries].CompositeChar = aCompositeChar;
  2263   return true;
  2266 uint32_t
  2267 KeyboardLayout::GetDeadKeyCombinations(uint8_t aDeadKey,
  2268                                        const PBYTE aDeadKeyKbdState,
  2269                                        uint16_t aShiftStatesWithBaseChars,
  2270                                        DeadKeyEntry* aDeadKeyArray,
  2271                                        uint32_t aMaxEntries)
  2273   bool deadKeyActive = false;
  2274   uint32_t entries = 0;
  2275   BYTE kbdState[256];
  2276   memset(kbdState, 0, sizeof(kbdState));
  2278   for (uint32_t shiftState = 0; shiftState < 16; shiftState++) {
  2279     if (!(aShiftStatesWithBaseChars & (1 << shiftState))) {
  2280       continue;
  2283     VirtualKey::FillKbdState(kbdState, shiftState);
  2285     for (uint32_t virtualKey = 0; virtualKey < 256; virtualKey++) {
  2286       int32_t vki = GetKeyIndex(virtualKey);
  2287       // Dead-key can pair only with such key that produces exactly one base
  2288       // character.
  2289       if (vki >= 0 &&
  2290           mVirtualKeys[vki].GetNativeUniChars(shiftState).mLength == 1) {
  2291         // Ensure dead-key is in active state, when it swallows entered
  2292         // character and waits for the next pressed key.
  2293         if (!deadKeyActive) {
  2294           deadKeyActive = EnsureDeadKeyActive(true, aDeadKey,
  2295                                               aDeadKeyKbdState);
  2298         // Depending on the character the followed the dead-key, the keyboard
  2299         // driver can produce one composite character, or a dead-key character
  2300         // followed by a second character.
  2301         char16_t compositeChars[5];
  2302         int32_t ret =
  2303           ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)compositeChars,
  2304                         ArrayLength(compositeChars), 0, mKeyboardLayout);
  2305         switch (ret) {
  2306           case 0:
  2307             // This key combination does not produce any characters. The
  2308             // dead-key is still in active state.
  2309             break;
  2310           case 1: {
  2311             // Exactly one composite character produced. Now, when dead-key
  2312             // is not active, repeat the last character one more time to
  2313             // determine the base character.
  2314             char16_t baseChars[5];
  2315             ret = ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)baseChars,
  2316                                 ArrayLength(baseChars), 0, mKeyboardLayout);
  2317             NS_ASSERTION(ret == 1, "One base character expected");
  2318             if (ret == 1 && entries < aMaxEntries &&
  2319                 AddDeadKeyEntry(baseChars[0], compositeChars[0],
  2320                                 aDeadKeyArray, entries)) {
  2321               entries++;
  2323             deadKeyActive = false;
  2324             break;
  2326           default:
  2327             // 1. Unexpected dead-key. Dead-key chaining is not supported.
  2328             // 2. More than one character generated. This is not a valid
  2329             //    dead-key and base character combination.
  2330             deadKeyActive = false;
  2331             break;
  2337   if (deadKeyActive) {
  2338     deadKeyActive = EnsureDeadKeyActive(false, aDeadKey, aDeadKeyKbdState);
  2341   NS_QuickSort(aDeadKeyArray, entries, sizeof(DeadKeyEntry),
  2342                CompareDeadKeyEntries, nullptr);
  2343   return entries;
  2346 uint32_t
  2347 KeyboardLayout::ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const
  2349   // Alphabet or Numeric or Numpad or Function keys
  2350   if ((aNativeKeyCode >= 0x30 && aNativeKeyCode <= 0x39) ||
  2351       (aNativeKeyCode >= 0x41 && aNativeKeyCode <= 0x5A) ||
  2352       (aNativeKeyCode >= 0x60 && aNativeKeyCode <= 0x87)) {
  2353     return static_cast<uint32_t>(aNativeKeyCode);
  2355   switch (aNativeKeyCode) {
  2356     // Following keycodes are same as our DOM keycodes
  2357     case VK_CANCEL:
  2358     case VK_BACK:
  2359     case VK_TAB:
  2360     case VK_CLEAR:
  2361     case VK_RETURN:
  2362     case VK_SHIFT:
  2363     case VK_CONTROL:
  2364     case VK_MENU: // Alt
  2365     case VK_PAUSE:
  2366     case VK_CAPITAL: // CAPS LOCK
  2367     case VK_KANA: // same as VK_HANGUL
  2368     case VK_JUNJA:
  2369     case VK_FINAL:
  2370     case VK_HANJA: // same as VK_KANJI
  2371     case VK_ESCAPE:
  2372     case VK_CONVERT:
  2373     case VK_NONCONVERT:
  2374     case VK_ACCEPT:
  2375     case VK_MODECHANGE:
  2376     case VK_SPACE:
  2377     case VK_PRIOR: // PAGE UP
  2378     case VK_NEXT: // PAGE DOWN
  2379     case VK_END:
  2380     case VK_HOME:
  2381     case VK_LEFT:
  2382     case VK_UP:
  2383     case VK_RIGHT:
  2384     case VK_DOWN:
  2385     case VK_SELECT:
  2386     case VK_PRINT:
  2387     case VK_EXECUTE:
  2388     case VK_SNAPSHOT:
  2389     case VK_INSERT:
  2390     case VK_DELETE:
  2391     case VK_APPS: // Context Menu
  2392     case VK_SLEEP:
  2393     case VK_NUMLOCK:
  2394     case VK_SCROLL: // SCROLL LOCK
  2395     case VK_ATTN: // Attension key of IBM midrange computers, e.g., AS/400
  2396     case VK_CRSEL: // Cursor Selection
  2397     case VK_EXSEL: // Extend Selection
  2398     case VK_EREOF: // Erase EOF key of IBM 3270 keyboard layout
  2399     case VK_PLAY:
  2400     case VK_ZOOM:
  2401     case VK_PA1: // PA1 key of IBM 3270 keyboard layout
  2402       return uint32_t(aNativeKeyCode);
  2404     case VK_HELP:
  2405       return NS_VK_HELP;
  2407     // Windows key should be mapped to a Win keycode
  2408     // They should be able to be distinguished by DOM3 KeyboardEvent.location
  2409     case VK_LWIN:
  2410     case VK_RWIN:
  2411       return NS_VK_WIN;
  2413     case VK_VOLUME_MUTE:
  2414       return NS_VK_VOLUME_MUTE;
  2415     case VK_VOLUME_DOWN:
  2416       return NS_VK_VOLUME_DOWN;
  2417     case VK_VOLUME_UP:
  2418       return NS_VK_VOLUME_UP;
  2420     // Following keycodes are not defined in our DOM keycodes.
  2421     case VK_BROWSER_BACK:
  2422     case VK_BROWSER_FORWARD:
  2423     case VK_BROWSER_REFRESH:
  2424     case VK_BROWSER_STOP:
  2425     case VK_BROWSER_SEARCH:
  2426     case VK_BROWSER_FAVORITES:
  2427     case VK_BROWSER_HOME:
  2428     case VK_MEDIA_NEXT_TRACK:
  2429     case VK_MEDIA_STOP:
  2430     case VK_MEDIA_PLAY_PAUSE:
  2431     case VK_LAUNCH_MAIL:
  2432     case VK_LAUNCH_MEDIA_SELECT:
  2433     case VK_LAUNCH_APP1:
  2434     case VK_LAUNCH_APP2:
  2435       return 0;
  2437     // Following OEM specific virtual keycodes should pass through DOM keyCode
  2438     // for compatibility with the other browsers on Windows.
  2440     // Following OEM specific virtual keycodes are defined for Fujitsu/OASYS.
  2441     case VK_OEM_FJ_JISHO:
  2442     case VK_OEM_FJ_MASSHOU:
  2443     case VK_OEM_FJ_TOUROKU:
  2444     case VK_OEM_FJ_LOYA:
  2445     case VK_OEM_FJ_ROYA:
  2446     // Not sure what means "ICO".
  2447     case VK_ICO_HELP:
  2448     case VK_ICO_00:
  2449     case VK_ICO_CLEAR:
  2450     // Following OEM specific virtual keycodes are defined for Nokia/Ericsson.
  2451     case VK_OEM_RESET:
  2452     case VK_OEM_JUMP:
  2453     case VK_OEM_PA1:
  2454     case VK_OEM_PA2:
  2455     case VK_OEM_PA3:
  2456     case VK_OEM_WSCTRL:
  2457     case VK_OEM_CUSEL:
  2458     case VK_OEM_ATTN:
  2459     case VK_OEM_FINISH:
  2460     case VK_OEM_COPY:
  2461     case VK_OEM_AUTO:
  2462     case VK_OEM_ENLW:
  2463     case VK_OEM_BACKTAB:
  2464     // VK_OEM_CLEAR is defined as not OEM specific, but let's pass though
  2465     // DOM keyCode like other OEM specific virtual keycodes.
  2466     case VK_OEM_CLEAR:
  2467       return uint32_t(aNativeKeyCode);
  2469     // 0xE1 is an OEM specific virtual keycode. However, the value is already
  2470     // used in our DOM keyCode for AltGr on Linux. So, this virtual keycode
  2471     // cannot pass through DOM keyCode.
  2472     case 0xE1:
  2473       return 0;
  2475     // Following keycodes are OEM keys which are keycodes for non-alphabet and
  2476     // non-numeric keys, we should compute each keycode of them from unshifted
  2477     // character which is inputted by each key.  But if the unshifted character
  2478     // is not an ASCII character but shifted character is an ASCII character,
  2479     // we should refer it.
  2480     case VK_OEM_1:
  2481     case VK_OEM_PLUS:
  2482     case VK_OEM_COMMA:
  2483     case VK_OEM_MINUS:
  2484     case VK_OEM_PERIOD:
  2485     case VK_OEM_2:
  2486     case VK_OEM_3:
  2487     case VK_OEM_4:
  2488     case VK_OEM_5:
  2489     case VK_OEM_6:
  2490     case VK_OEM_7:
  2491     case VK_OEM_8:
  2492     case VK_OEM_102:
  2493     case VK_ABNT_C1:
  2495       NS_ASSERTION(IsPrintableCharKey(aNativeKeyCode),
  2496                    "The key must be printable");
  2497       ModifierKeyState modKeyState(0);
  2498       UniCharsAndModifiers uniChars =
  2499         GetUniCharsAndModifiers(aNativeKeyCode, modKeyState);
  2500       if (uniChars.mLength != 1 ||
  2501           uniChars.mChars[0] < ' ' || uniChars.mChars[0] > 0x7F) {
  2502         modKeyState.Set(MODIFIER_SHIFT);
  2503         uniChars = GetUniCharsAndModifiers(aNativeKeyCode, modKeyState);
  2504         if (uniChars.mLength != 1 ||
  2505             uniChars.mChars[0] < ' ' || uniChars.mChars[0] > 0x7F) {
  2506           return 0;
  2509       return WidgetUtils::ComputeKeyCodeFromChar(uniChars.mChars[0]);
  2512     // IE sets 0xC2 to the DOM keyCode for VK_ABNT_C2.  However, we're already
  2513     // using NS_VK_SEPARATOR for the separator key on Mac and Linux.  Therefore,
  2514     // We should keep consistency between Gecko on all platforms rather than
  2515     // with other browsers since a lot of keyCode values are already different
  2516     // between browsers.
  2517     case VK_ABNT_C2:
  2518       return NS_VK_SEPARATOR;
  2520     // VK_PROCESSKEY means IME already consumed the key event.
  2521     case VK_PROCESSKEY:
  2522       return 0;
  2523     // VK_PACKET is generated by SendInput() API, we don't need to
  2524     // care this message as key event.
  2525     case VK_PACKET:
  2526       return 0;
  2527     // If a key is not mapped to a virtual keycode, 0xFF is used.
  2528     case 0xFF:
  2529       NS_WARNING("The key is failed to be converted to a virtual keycode");
  2530       return 0;
  2532 #ifdef DEBUG
  2533   nsPrintfCString warning("Unknown virtual keycode (0x%08X), please check the "
  2534                           "latest MSDN document, there may be some new "
  2535                           "keycodes we've never known.",
  2536                           aNativeKeyCode);
  2537   NS_WARNING(warning.get());
  2538 #endif
  2539   return 0;
  2542 KeyNameIndex
  2543 KeyboardLayout::ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const
  2545   if (IsPrintableCharKey(aVirtualKey)) {
  2546     return KEY_NAME_INDEX_USE_STRING;
  2549 #define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
  2550 #define NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
  2551 #define NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
  2552 #define NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
  2554   switch (aVirtualKey) {
  2556 #undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  2557 #define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \
  2558     case aNativeKey: return aKeyNameIndex;
  2560 #include "NativeKeyToDOMKeyName.h"
  2562 #undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  2563 #define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
  2565     default:
  2566       break;
  2569   HKL layout = GetLayout();
  2570   WORD langID = LOWORD(static_cast<HKL>(layout));
  2571   WORD primaryLangID = PRIMARYLANGID(langID);
  2573   if (primaryLangID == LANG_JAPANESE) {
  2574     switch (aVirtualKey) {
  2576 #undef NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  2577 #define NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)\
  2578       case aNativeKey: return aKeyNameIndex;
  2580 #include "NativeKeyToDOMKeyName.h"
  2582 #undef NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  2583 #define NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
  2585       default:
  2586         break;
  2588   } else if (primaryLangID == LANG_KOREAN) {
  2589     switch (aVirtualKey) {
  2591 #undef NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  2592 #define NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)\
  2593       case aNativeKey: return aKeyNameIndex;
  2595 #include "NativeKeyToDOMKeyName.h"
  2597 #undef NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  2598 #define NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
  2600       default:
  2601         return KEY_NAME_INDEX_Unidentified;
  2605   switch (aVirtualKey) {
  2607 #undef NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  2608 #define NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)\
  2609     case aNativeKey: return aKeyNameIndex;
  2611 #include "NativeKeyToDOMKeyName.h"
  2613 #undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  2614 #undef NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  2615 #undef NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  2616 #undef NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  2618     default:
  2619       return KEY_NAME_INDEX_Unidentified;
  2623 nsresult
  2624 KeyboardLayout::SynthesizeNativeKeyEvent(nsWindowBase* aWidget,
  2625                                          int32_t aNativeKeyboardLayout,
  2626                                          int32_t aNativeKeyCode,
  2627                                          uint32_t aModifierFlags,
  2628                                          const nsAString& aCharacters,
  2629                                          const nsAString& aUnmodifiedCharacters)
  2631   UINT keyboardLayoutListCount = ::GetKeyboardLayoutList(0, nullptr);
  2632   NS_ASSERTION(keyboardLayoutListCount > 0,
  2633                "One keyboard layout must be installed at least");
  2634   HKL keyboardLayoutListBuff[50];
  2635   HKL* keyboardLayoutList =
  2636     keyboardLayoutListCount < 50 ? keyboardLayoutListBuff :
  2637                                    new HKL[keyboardLayoutListCount];
  2638   keyboardLayoutListCount =
  2639     ::GetKeyboardLayoutList(keyboardLayoutListCount, keyboardLayoutList);
  2640   NS_ASSERTION(keyboardLayoutListCount > 0,
  2641                "Failed to get all keyboard layouts installed on the system");
  2643   nsPrintfCString layoutName("%08x", aNativeKeyboardLayout);
  2644   HKL loadedLayout = LoadKeyboardLayoutA(layoutName.get(), KLF_NOTELLSHELL);
  2645   if (loadedLayout == nullptr) {
  2646     if (keyboardLayoutListBuff != keyboardLayoutList) {
  2647       delete [] keyboardLayoutList;
  2649     return NS_ERROR_NOT_AVAILABLE;
  2652   // Setup clean key state and load desired layout
  2653   BYTE originalKbdState[256];
  2654   ::GetKeyboardState(originalKbdState);
  2655   BYTE kbdState[256];
  2656   memset(kbdState, 0, sizeof(kbdState));
  2657   // This changes the state of the keyboard for the current thread only,
  2658   // and we'll restore it soon, so this should be OK.
  2659   ::SetKeyboardState(kbdState);
  2661   OverrideLayout(loadedLayout);
  2663   uint8_t argumentKeySpecific = 0;
  2664   switch (aNativeKeyCode) {
  2665     case VK_SHIFT:
  2666       aModifierFlags &= ~(nsIWidget::SHIFT_L | nsIWidget::SHIFT_R);
  2667       argumentKeySpecific = VK_LSHIFT;
  2668       break;
  2669     case VK_LSHIFT:
  2670       aModifierFlags &= ~nsIWidget::SHIFT_L;
  2671       argumentKeySpecific = aNativeKeyCode;
  2672       aNativeKeyCode = VK_SHIFT;
  2673       break;
  2674     case VK_RSHIFT:
  2675       aModifierFlags &= ~nsIWidget::SHIFT_R;
  2676       argumentKeySpecific = aNativeKeyCode;
  2677       aNativeKeyCode = VK_SHIFT;
  2678       break;
  2679     case VK_CONTROL:
  2680       aModifierFlags &= ~(nsIWidget::CTRL_L | nsIWidget::CTRL_R);
  2681       argumentKeySpecific = VK_LCONTROL;
  2682       break;
  2683     case VK_LCONTROL:
  2684       aModifierFlags &= ~nsIWidget::CTRL_L;
  2685       argumentKeySpecific = aNativeKeyCode;
  2686       aNativeKeyCode = VK_CONTROL;
  2687       break;
  2688     case VK_RCONTROL:
  2689       aModifierFlags &= ~nsIWidget::CTRL_R;
  2690       argumentKeySpecific = aNativeKeyCode;
  2691       aNativeKeyCode = VK_CONTROL;
  2692       break;
  2693     case VK_MENU:
  2694       aModifierFlags &= ~(nsIWidget::ALT_L | nsIWidget::ALT_R);
  2695       argumentKeySpecific = VK_LMENU;
  2696       break;
  2697     case VK_LMENU:
  2698       aModifierFlags &= ~nsIWidget::ALT_L;
  2699       argumentKeySpecific = aNativeKeyCode;
  2700       aNativeKeyCode = VK_MENU;
  2701       break;
  2702     case VK_RMENU:
  2703       aModifierFlags &= ~nsIWidget::ALT_R;
  2704       argumentKeySpecific = aNativeKeyCode;
  2705       aNativeKeyCode = VK_MENU;
  2706       break;
  2707     case VK_CAPITAL:
  2708       aModifierFlags &= ~nsIWidget::CAPS_LOCK;
  2709       argumentKeySpecific = VK_CAPITAL;
  2710       break;
  2711     case VK_NUMLOCK:
  2712       aModifierFlags &= ~nsIWidget::NUM_LOCK;
  2713       argumentKeySpecific = VK_NUMLOCK;
  2714       break;
  2717   nsAutoTArray<KeyPair,10> keySequence;
  2718   WinUtils::SetupKeyModifiersSequence(&keySequence, aModifierFlags);
  2719   NS_ASSERTION(aNativeKeyCode >= 0 && aNativeKeyCode < 256,
  2720                "Native VK key code out of range");
  2721   keySequence.AppendElement(KeyPair(aNativeKeyCode, argumentKeySpecific));
  2723   // Simulate the pressing of each modifier key and then the real key
  2724   for (uint32_t i = 0; i < keySequence.Length(); ++i) {
  2725     uint8_t key = keySequence[i].mGeneral;
  2726     uint8_t keySpecific = keySequence[i].mSpecific;
  2727     kbdState[key] = 0x81; // key is down and toggled on if appropriate
  2728     if (keySpecific) {
  2729       kbdState[keySpecific] = 0x81;
  2731     ::SetKeyboardState(kbdState);
  2732     ModifierKeyState modKeyState;
  2733     UINT scanCode =
  2734       ComputeScanCodeForVirtualKeyCode(keySpecific ? keySpecific : key);
  2735     LPARAM lParam = static_cast<LPARAM>(scanCode << 16);
  2736     // Add extended key flag to the lParam for right control key and right alt
  2737     // key.
  2738     if (keySpecific == VK_RCONTROL || keySpecific == VK_RMENU) {
  2739       lParam |= 0x1000000;
  2741     MSG keyDownMsg = WinUtils::InitMSG(WM_KEYDOWN, key, lParam,
  2742                                        aWidget->GetWindowHandle());
  2743     if (i == keySequence.Length() - 1) {
  2744       bool makeDeadCharMsg =
  2745         (IsDeadKey(key, modKeyState) && aCharacters.IsEmpty());
  2746       nsAutoString chars(aCharacters);
  2747       if (makeDeadCharMsg) {
  2748         UniCharsAndModifiers deadChars =
  2749           GetUniCharsAndModifiers(key, modKeyState);
  2750         chars = deadChars.ToString();
  2751         NS_ASSERTION(chars.Length() == 1,
  2752                      "Dead char must be only one character");
  2754       if (chars.IsEmpty()) {
  2755         NativeKey nativeKey(aWidget, keyDownMsg, modKeyState);
  2756         nativeKey.HandleKeyDownMessage();
  2757       } else {
  2758         nsAutoTArray<NativeKey::FakeCharMsg, 10> fakeCharMsgs;
  2759         for (uint32_t j = 0; j < chars.Length(); j++) {
  2760           NativeKey::FakeCharMsg* fakeCharMsg = fakeCharMsgs.AppendElement();
  2761           fakeCharMsg->mCharCode = chars.CharAt(j);
  2762           fakeCharMsg->mScanCode = scanCode;
  2763           fakeCharMsg->mIsDeadKey = makeDeadCharMsg;
  2765         NativeKey nativeKey(aWidget, keyDownMsg, modKeyState, &fakeCharMsgs);
  2766         bool dispatched;
  2767         nativeKey.HandleKeyDownMessage(&dispatched);
  2768         // If some char messages are not consumed, let's emulate the widget
  2769         // receiving the message directly.
  2770         for (uint32_t j = 1; j < fakeCharMsgs.Length(); j++) {
  2771           if (fakeCharMsgs[j].mConsumed) {
  2772             continue;
  2774           MSG charMsg = fakeCharMsgs[j].GetCharMsg(aWidget->GetWindowHandle());
  2775           NativeKey nativeKey(aWidget, charMsg, modKeyState);
  2776           nativeKey.HandleCharMessage(charMsg);
  2779     } else {
  2780       NativeKey nativeKey(aWidget, keyDownMsg, modKeyState);
  2781       nativeKey.HandleKeyDownMessage();
  2784   for (uint32_t i = keySequence.Length(); i > 0; --i) {
  2785     uint8_t key = keySequence[i - 1].mGeneral;
  2786     uint8_t keySpecific = keySequence[i - 1].mSpecific;
  2787     kbdState[key] = 0; // key is up and toggled off if appropriate
  2788     if (keySpecific) {
  2789       kbdState[keySpecific] = 0;
  2791     ::SetKeyboardState(kbdState);
  2792     ModifierKeyState modKeyState;
  2793     UINT scanCode =
  2794       ComputeScanCodeForVirtualKeyCode(keySpecific ? keySpecific : key);
  2795     LPARAM lParam = static_cast<LPARAM>(scanCode << 16);
  2796     // Add extended key flag to the lParam for right control key and right alt
  2797     // key.
  2798     if (keySpecific == VK_RCONTROL || keySpecific == VK_RMENU) {
  2799       lParam |= 0x1000000;
  2801     MSG keyUpMsg = WinUtils::InitMSG(WM_KEYUP, key, lParam,
  2802                                      aWidget->GetWindowHandle());
  2803     NativeKey nativeKey(aWidget, keyUpMsg, modKeyState);
  2804     nativeKey.HandleKeyUpMessage();
  2807   // Restore old key state and layout
  2808   ::SetKeyboardState(originalKbdState);
  2809   RestoreLayout();
  2811   // Don't unload the layout if it's installed actually.
  2812   for (uint32_t i = 0; i < keyboardLayoutListCount; i++) {
  2813     if (keyboardLayoutList[i] == loadedLayout) {
  2814       loadedLayout = 0;
  2815       break;
  2818   if (keyboardLayoutListBuff != keyboardLayoutList) {
  2819     delete [] keyboardLayoutList;
  2821   if (loadedLayout) {
  2822     ::UnloadKeyboardLayout(loadedLayout);
  2824   return NS_OK;
  2827 /*****************************************************************************
  2828  * mozilla::widget::DeadKeyTable
  2829  *****************************************************************************/
  2831 char16_t
  2832 DeadKeyTable::GetCompositeChar(char16_t aBaseChar) const
  2834   // Dead-key table is sorted by BaseChar in ascending order.
  2835   // Usually they are too small to use binary search.
  2837   for (uint32_t index = 0; index < mEntries; index++) {
  2838     if (mTable[index].BaseChar == aBaseChar) {
  2839       return mTable[index].CompositeChar;
  2841     if (mTable[index].BaseChar > aBaseChar) {
  2842       break;
  2846   return 0;
  2849 /*****************************************************************************
  2850  * mozilla::widget::RedirectedKeyDownMessage
  2851  *****************************************************************************/
  2853 MSG RedirectedKeyDownMessageManager::sRedirectedKeyDownMsg;
  2854 bool RedirectedKeyDownMessageManager::sDefaultPreventedOfRedirectedMsg = false;
  2856 // static
  2857 bool
  2858 RedirectedKeyDownMessageManager::IsRedirectedMessage(const MSG& aMsg)
  2860   return (aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN) &&
  2861          (sRedirectedKeyDownMsg.message == aMsg.message &&
  2862           WinUtils::GetScanCode(sRedirectedKeyDownMsg.lParam) ==
  2863             WinUtils::GetScanCode(aMsg.lParam));
  2866 // static
  2867 void
  2868 RedirectedKeyDownMessageManager::RemoveNextCharMessage(HWND aWnd)
  2870   MSG msg;
  2871   if (WinUtils::PeekMessage(&msg, aWnd, WM_KEYFIRST, WM_KEYLAST,
  2872                             PM_NOREMOVE | PM_NOYIELD) &&
  2873       (msg.message == WM_CHAR || msg.message == WM_SYSCHAR)) {
  2874     WinUtils::PeekMessage(&msg, aWnd, msg.message, msg.message,
  2875                           PM_REMOVE | PM_NOYIELD);
  2879 } // namespace widget
  2880 } // namespace mozilla

mercurial