widget/windows/KeyboardLayout.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/widget/windows/KeyboardLayout.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2881 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "mozilla/ArrayUtils.h"
    1.10 +#include "mozilla/DebugOnly.h"
    1.11 +#include "mozilla/MouseEvents.h"
    1.12 +#include "mozilla/TextEvents.h"
    1.13 +#include "mozilla/WindowsVersion.h"
    1.14 +
    1.15 +#include "KeyboardLayout.h"
    1.16 +#include "nsIMM32Handler.h"
    1.17 +
    1.18 +#include "nsMemory.h"
    1.19 +#include "nsToolkit.h"
    1.20 +#include "nsQuickSort.h"
    1.21 +#include "nsAlgorithm.h"
    1.22 +#include "nsUnicharUtils.h"
    1.23 +#include "WidgetUtils.h"
    1.24 +#include "WinUtils.h"
    1.25 +#include "nsWindowDbg.h"
    1.26 +#include "nsServiceManagerUtils.h"
    1.27 +#include "nsPrintfCString.h"
    1.28 +
    1.29 +#include "nsIDOMKeyEvent.h"
    1.30 +#include "nsIIdleServiceInternal.h"
    1.31 +
    1.32 +#ifdef MOZ_CRASHREPORTER
    1.33 +#include "nsExceptionHandler.h"
    1.34 +#endif
    1.35 +
    1.36 +#include "npapi.h"
    1.37 +
    1.38 +#include <windows.h>
    1.39 +#include <winuser.h>
    1.40 +#include <algorithm>
    1.41 +
    1.42 +#ifndef WINABLEAPI
    1.43 +#include <winable.h>
    1.44 +#endif
    1.45 +
    1.46 +namespace mozilla {
    1.47 +namespace widget {
    1.48 +
    1.49 +// Unique id counter associated with a keydown / keypress events. Used in
    1.50 +// identifing keypress events for removal from async event dispatch queue
    1.51 +// in metrofx after preventDefault is called on keydown events.
    1.52 +static uint32_t sUniqueKeyEventId = 0;
    1.53 +
    1.54 +struct DeadKeyEntry
    1.55 +{
    1.56 +  char16_t BaseChar;
    1.57 +  char16_t CompositeChar;
    1.58 +};
    1.59 +
    1.60 +
    1.61 +class DeadKeyTable
    1.62 +{
    1.63 +  friend class KeyboardLayout;
    1.64 +
    1.65 +  uint16_t mEntries;
    1.66 +  // KeyboardLayout::AddDeadKeyTable() will allocate as many entries as
    1.67 +  // required.  It is the only way to create new DeadKeyTable instances.
    1.68 +  DeadKeyEntry mTable[1];
    1.69 +
    1.70 +  void Init(const DeadKeyEntry* aDeadKeyArray, uint32_t aEntries)
    1.71 +  {
    1.72 +    mEntries = aEntries;
    1.73 +    memcpy(mTable, aDeadKeyArray, aEntries * sizeof(DeadKeyEntry));
    1.74 +  }
    1.75 +
    1.76 +  static uint32_t SizeInBytes(uint32_t aEntries)
    1.77 +  {
    1.78 +    return offsetof(DeadKeyTable, mTable) + aEntries * sizeof(DeadKeyEntry);
    1.79 +  }
    1.80 +
    1.81 +public:
    1.82 +  uint32_t Entries() const
    1.83 +  {
    1.84 +    return mEntries;
    1.85 +  }
    1.86 +
    1.87 +  bool IsEqual(const DeadKeyEntry* aDeadKeyArray, uint32_t aEntries) const
    1.88 +  {
    1.89 +    return (mEntries == aEntries &&
    1.90 +            !memcmp(mTable, aDeadKeyArray,
    1.91 +                    aEntries * sizeof(DeadKeyEntry)));
    1.92 +  }
    1.93 +
    1.94 +  char16_t GetCompositeChar(char16_t aBaseChar) const;
    1.95 +};
    1.96 +
    1.97 +
    1.98 +/*****************************************************************************
    1.99 + * mozilla::widget::ModifierKeyState
   1.100 + *****************************************************************************/
   1.101 +
   1.102 +ModifierKeyState::ModifierKeyState()
   1.103 +{
   1.104 +  Update();
   1.105 +}
   1.106 +
   1.107 +ModifierKeyState::ModifierKeyState(bool aIsShiftDown,
   1.108 +                                   bool aIsControlDown,
   1.109 +                                   bool aIsAltDown)
   1.110 +{
   1.111 +  Update();
   1.112 +  Unset(MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT | MODIFIER_ALTGRAPH);
   1.113 +  Modifiers modifiers = 0;
   1.114 +  if (aIsShiftDown) {
   1.115 +    modifiers |= MODIFIER_SHIFT;
   1.116 +  }
   1.117 +  if (aIsControlDown) {
   1.118 +    modifiers |= MODIFIER_CONTROL;
   1.119 +  }
   1.120 +  if (aIsAltDown) {
   1.121 +    modifiers |= MODIFIER_ALT;
   1.122 +  }
   1.123 +  if (modifiers) {
   1.124 +    Set(modifiers);
   1.125 +  }
   1.126 +}
   1.127 +
   1.128 +ModifierKeyState::ModifierKeyState(Modifiers aModifiers) :
   1.129 +  mModifiers(aModifiers)
   1.130 +{
   1.131 +  EnsureAltGr();
   1.132 +}
   1.133 +
   1.134 +void
   1.135 +ModifierKeyState::Update()
   1.136 +{
   1.137 +  mModifiers = 0;
   1.138 +  if (IS_VK_DOWN(VK_SHIFT)) {
   1.139 +    mModifiers |= MODIFIER_SHIFT;
   1.140 +  }
   1.141 +  if (IS_VK_DOWN(VK_CONTROL)) {
   1.142 +    mModifiers |= MODIFIER_CONTROL;
   1.143 +  }
   1.144 +  if (IS_VK_DOWN(VK_MENU)) {
   1.145 +    mModifiers |= MODIFIER_ALT;
   1.146 +  }
   1.147 +  if (IS_VK_DOWN(VK_LWIN) || IS_VK_DOWN(VK_RWIN)) {
   1.148 +    mModifiers |= MODIFIER_OS;
   1.149 +  }
   1.150 +  if (::GetKeyState(VK_CAPITAL) & 1) {
   1.151 +    mModifiers |= MODIFIER_CAPSLOCK;
   1.152 +  }
   1.153 +  if (::GetKeyState(VK_NUMLOCK) & 1) {
   1.154 +    mModifiers |= MODIFIER_NUMLOCK;
   1.155 +  }
   1.156 +  if (::GetKeyState(VK_SCROLL) & 1) {
   1.157 +    mModifiers |= MODIFIER_SCROLLLOCK;
   1.158 +  }
   1.159 +
   1.160 +  EnsureAltGr();
   1.161 +}
   1.162 +
   1.163 +void
   1.164 +ModifierKeyState::Unset(Modifiers aRemovingModifiers)
   1.165 +{
   1.166 +  mModifiers &= ~aRemovingModifiers;
   1.167 +  // Note that we don't need to unset AltGr flag here automatically.
   1.168 +  // For nsEditor, we need to remove Alt and Control flags but AltGr isn't
   1.169 +  // checked in nsEditor, so, it can be kept.
   1.170 +}
   1.171 +
   1.172 +void
   1.173 +ModifierKeyState::Set(Modifiers aAddingModifiers)
   1.174 +{
   1.175 +  mModifiers |= aAddingModifiers;
   1.176 +  EnsureAltGr();
   1.177 +}
   1.178 +
   1.179 +void
   1.180 +ModifierKeyState::InitInputEvent(WidgetInputEvent& aInputEvent) const
   1.181 +{
   1.182 +  aInputEvent.modifiers = mModifiers;
   1.183 +
   1.184 +  switch(aInputEvent.eventStructType) {
   1.185 +    case NS_MOUSE_EVENT:
   1.186 +    case NS_MOUSE_SCROLL_EVENT:
   1.187 +    case NS_WHEEL_EVENT:
   1.188 +    case NS_DRAG_EVENT:
   1.189 +    case NS_SIMPLE_GESTURE_EVENT:
   1.190 +      InitMouseEvent(aInputEvent);
   1.191 +      break;
   1.192 +    default:
   1.193 +      break;
   1.194 +  }
   1.195 +}
   1.196 +
   1.197 +void
   1.198 +ModifierKeyState::InitMouseEvent(WidgetInputEvent& aMouseEvent) const
   1.199 +{
   1.200 +  NS_ASSERTION(aMouseEvent.eventStructType == NS_MOUSE_EVENT ||
   1.201 +               aMouseEvent.eventStructType == NS_WHEEL_EVENT ||
   1.202 +               aMouseEvent.eventStructType == NS_DRAG_EVENT ||
   1.203 +               aMouseEvent.eventStructType == NS_SIMPLE_GESTURE_EVENT,
   1.204 +               "called with non-mouse event");
   1.205 +
   1.206 +  if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) {
   1.207 +    // Buttons for immersive mode are handled in MetroInput.
   1.208 +    return;
   1.209 +  }
   1.210 +
   1.211 +  WidgetMouseEventBase& mouseEvent = *aMouseEvent.AsMouseEventBase();
   1.212 +  mouseEvent.buttons = 0;
   1.213 +  if (::GetKeyState(VK_LBUTTON) < 0) {
   1.214 +    mouseEvent.buttons |= WidgetMouseEvent::eLeftButtonFlag;
   1.215 +  }
   1.216 +  if (::GetKeyState(VK_RBUTTON) < 0) {
   1.217 +    mouseEvent.buttons |= WidgetMouseEvent::eRightButtonFlag;
   1.218 +  }
   1.219 +  if (::GetKeyState(VK_MBUTTON) < 0) {
   1.220 +    mouseEvent.buttons |= WidgetMouseEvent::eMiddleButtonFlag;
   1.221 +  }
   1.222 +  if (::GetKeyState(VK_XBUTTON1) < 0) {
   1.223 +    mouseEvent.buttons |= WidgetMouseEvent::e4thButtonFlag;
   1.224 +  }
   1.225 +  if (::GetKeyState(VK_XBUTTON2) < 0) {
   1.226 +    mouseEvent.buttons |= WidgetMouseEvent::e5thButtonFlag;
   1.227 +  }
   1.228 +}
   1.229 +
   1.230 +bool
   1.231 +ModifierKeyState::IsShift() const
   1.232 +{
   1.233 +  return (mModifiers & MODIFIER_SHIFT) != 0;
   1.234 +}
   1.235 +
   1.236 +bool
   1.237 +ModifierKeyState::IsControl() const
   1.238 +{
   1.239 +  return (mModifiers & MODIFIER_CONTROL) != 0;
   1.240 +}
   1.241 +
   1.242 +bool
   1.243 +ModifierKeyState::IsAlt() const
   1.244 +{
   1.245 +  return (mModifiers & MODIFIER_ALT) != 0;
   1.246 +}
   1.247 +
   1.248 +bool
   1.249 +ModifierKeyState::IsAltGr() const
   1.250 +{
   1.251 +  return IsControl() && IsAlt();
   1.252 +}
   1.253 +
   1.254 +bool
   1.255 +ModifierKeyState::IsWin() const
   1.256 +{
   1.257 +  return (mModifiers & MODIFIER_OS) != 0;
   1.258 +}
   1.259 +
   1.260 +bool
   1.261 +ModifierKeyState::IsCapsLocked() const
   1.262 +{
   1.263 +  return (mModifiers & MODIFIER_CAPSLOCK) != 0;
   1.264 +}
   1.265 +
   1.266 +bool
   1.267 +ModifierKeyState::IsNumLocked() const
   1.268 +{
   1.269 +  return (mModifiers & MODIFIER_NUMLOCK) != 0;
   1.270 +}
   1.271 +
   1.272 +bool
   1.273 +ModifierKeyState::IsScrollLocked() const
   1.274 +{
   1.275 +  return (mModifiers & MODIFIER_SCROLLLOCK) != 0;
   1.276 +}
   1.277 +
   1.278 +Modifiers
   1.279 +ModifierKeyState::GetModifiers() const
   1.280 +{
   1.281 +  return mModifiers;
   1.282 +}
   1.283 +
   1.284 +void
   1.285 +ModifierKeyState::EnsureAltGr()
   1.286 +{
   1.287 +  // If both Control key and Alt key are pressed, it means AltGr is pressed.
   1.288 +  // Ideally, we should check whether the current keyboard layout has AltGr
   1.289 +  // or not.  However, setting AltGr flags for keyboard which doesn't have
   1.290 +  // AltGr must not be serious bug.  So, it should be OK for now.
   1.291 +  if (IsAltGr()) {
   1.292 +    mModifiers |= MODIFIER_ALTGRAPH;
   1.293 +  }
   1.294 +}
   1.295 +
   1.296 +/*****************************************************************************
   1.297 + * mozilla::widget::UniCharsAndModifiers
   1.298 + *****************************************************************************/
   1.299 +
   1.300 +void
   1.301 +UniCharsAndModifiers::Append(char16_t aUniChar, Modifiers aModifiers)
   1.302 +{
   1.303 +  MOZ_ASSERT(mLength < 5);
   1.304 +  mChars[mLength] = aUniChar;
   1.305 +  mModifiers[mLength] = aModifiers;
   1.306 +  mLength++;
   1.307 +}
   1.308 +
   1.309 +void
   1.310 +UniCharsAndModifiers::FillModifiers(Modifiers aModifiers)
   1.311 +{
   1.312 +  for (uint32_t i = 0; i < mLength; i++) {
   1.313 +    mModifiers[i] = aModifiers;
   1.314 +  }
   1.315 +}
   1.316 +
   1.317 +bool
   1.318 +UniCharsAndModifiers::UniCharsEqual(const UniCharsAndModifiers& aOther) const
   1.319 +{
   1.320 +  if (mLength != aOther.mLength) {
   1.321 +    return false;
   1.322 +  }
   1.323 +  return !memcmp(mChars, aOther.mChars, mLength * sizeof(char16_t));
   1.324 +}
   1.325 +
   1.326 +bool
   1.327 +UniCharsAndModifiers::UniCharsCaseInsensitiveEqual(
   1.328 +                        const UniCharsAndModifiers& aOther) const
   1.329 +{
   1.330 +  if (mLength != aOther.mLength) {
   1.331 +    return false;
   1.332 +  }
   1.333 +
   1.334 +  nsCaseInsensitiveStringComparator comp;
   1.335 +  return !comp(mChars, aOther.mChars, mLength, aOther.mLength);
   1.336 +}
   1.337 +
   1.338 +UniCharsAndModifiers&
   1.339 +UniCharsAndModifiers::operator+=(const UniCharsAndModifiers& aOther)
   1.340 +{
   1.341 +  uint32_t copyCount = std::min(aOther.mLength, 5 - mLength);
   1.342 +  NS_ENSURE_TRUE(copyCount > 0, *this);
   1.343 +  memcpy(&mChars[mLength], aOther.mChars, copyCount * sizeof(char16_t));
   1.344 +  memcpy(&mModifiers[mLength], aOther.mModifiers,
   1.345 +         copyCount * sizeof(Modifiers));
   1.346 +  mLength += copyCount;
   1.347 +  return *this;
   1.348 +}
   1.349 +
   1.350 +UniCharsAndModifiers
   1.351 +UniCharsAndModifiers::operator+(const UniCharsAndModifiers& aOther) const
   1.352 +{
   1.353 +  UniCharsAndModifiers result(*this);
   1.354 +  result += aOther;
   1.355 +  return result;
   1.356 +}
   1.357 +
   1.358 +/*****************************************************************************
   1.359 + * mozilla::widget::VirtualKey
   1.360 + *****************************************************************************/
   1.361 +
   1.362 +// static
   1.363 +VirtualKey::ShiftState
   1.364 +VirtualKey::ModifiersToShiftState(Modifiers aModifiers)
   1.365 +{
   1.366 +  ShiftState state = 0;
   1.367 +  if (aModifiers & MODIFIER_SHIFT) {
   1.368 +    state |= STATE_SHIFT;
   1.369 +  }
   1.370 +  if (aModifiers & MODIFIER_CONTROL) {
   1.371 +    state |= STATE_CONTROL;
   1.372 +  }
   1.373 +  if (aModifiers & MODIFIER_ALT) {
   1.374 +    state |= STATE_ALT;
   1.375 +  }
   1.376 +  if (aModifiers & MODIFIER_CAPSLOCK) {
   1.377 +    state |= STATE_CAPSLOCK;
   1.378 +  }
   1.379 +  return state;
   1.380 +}
   1.381 +
   1.382 +// static
   1.383 +Modifiers
   1.384 +VirtualKey::ShiftStateToModifiers(ShiftState aShiftState)
   1.385 +{
   1.386 +  Modifiers modifiers = 0;
   1.387 +  if (aShiftState & STATE_SHIFT) {
   1.388 +    modifiers |= MODIFIER_SHIFT;
   1.389 +  }
   1.390 +  if (aShiftState & STATE_CONTROL) {
   1.391 +    modifiers |= MODIFIER_CONTROL;
   1.392 +  }
   1.393 +  if (aShiftState & STATE_ALT) {
   1.394 +    modifiers |= MODIFIER_ALT;
   1.395 +  }
   1.396 +  if (aShiftState & STATE_CAPSLOCK) {
   1.397 +    modifiers |= MODIFIER_CAPSLOCK;
   1.398 +  }
   1.399 +  if ((modifiers & (MODIFIER_ALT | MODIFIER_CONTROL)) ==
   1.400 +         (MODIFIER_ALT | MODIFIER_CONTROL)) {
   1.401 +    modifiers |= MODIFIER_ALTGRAPH;
   1.402 +  }
   1.403 +  return modifiers;
   1.404 +}
   1.405 +
   1.406 +inline char16_t
   1.407 +VirtualKey::GetCompositeChar(ShiftState aShiftState, char16_t aBaseChar) const
   1.408 +{
   1.409 +  return mShiftStates[aShiftState].DeadKey.Table->GetCompositeChar(aBaseChar);
   1.410 +}
   1.411 +
   1.412 +const DeadKeyTable*
   1.413 +VirtualKey::MatchingDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
   1.414 +                                 uint32_t aEntries) const
   1.415 +{
   1.416 +  if (!mIsDeadKey) {
   1.417 +    return nullptr;
   1.418 +  }
   1.419 +
   1.420 +  for (ShiftState shiftState = 0; shiftState < 16; shiftState++) {
   1.421 +    if (!IsDeadKey(shiftState)) {
   1.422 +      continue;
   1.423 +    }
   1.424 +    const DeadKeyTable* dkt = mShiftStates[shiftState].DeadKey.Table;
   1.425 +    if (dkt && dkt->IsEqual(aDeadKeyArray, aEntries)) {
   1.426 +      return dkt;
   1.427 +    }
   1.428 +  }
   1.429 +
   1.430 +  return nullptr;
   1.431 +}
   1.432 +
   1.433 +void
   1.434 +VirtualKey::SetNormalChars(ShiftState aShiftState,
   1.435 +                           const char16_t* aChars,
   1.436 +                           uint32_t aNumOfChars)
   1.437 +{
   1.438 +  NS_ASSERTION(aShiftState < ArrayLength(mShiftStates), "invalid index");
   1.439 +
   1.440 +  SetDeadKey(aShiftState, false);
   1.441 +
   1.442 +  for (uint32_t index = 0; index < aNumOfChars; index++) {
   1.443 +    // Ignore legacy non-printable control characters
   1.444 +    mShiftStates[aShiftState].Normal.Chars[index] =
   1.445 +      (aChars[index] >= 0x20) ? aChars[index] : 0;
   1.446 +  }
   1.447 +
   1.448 +  uint32_t len = ArrayLength(mShiftStates[aShiftState].Normal.Chars);
   1.449 +  for (uint32_t index = aNumOfChars; index < len; index++) {
   1.450 +    mShiftStates[aShiftState].Normal.Chars[index] = 0;
   1.451 +  }
   1.452 +}
   1.453 +
   1.454 +void
   1.455 +VirtualKey::SetDeadChar(ShiftState aShiftState, char16_t aDeadChar)
   1.456 +{
   1.457 +  NS_ASSERTION(aShiftState < ArrayLength(mShiftStates), "invalid index");
   1.458 +
   1.459 +  SetDeadKey(aShiftState, true);
   1.460 +
   1.461 +  mShiftStates[aShiftState].DeadKey.DeadChar = aDeadChar;
   1.462 +  mShiftStates[aShiftState].DeadKey.Table = nullptr;
   1.463 +}
   1.464 +
   1.465 +UniCharsAndModifiers
   1.466 +VirtualKey::GetUniChars(ShiftState aShiftState) const
   1.467 +{
   1.468 +  UniCharsAndModifiers result = GetNativeUniChars(aShiftState);
   1.469 +
   1.470 +  const ShiftState STATE_ALT_CONTROL = (STATE_ALT | STATE_CONTROL);
   1.471 +  if (!(aShiftState & STATE_ALT_CONTROL)) {
   1.472 +    return result;
   1.473 +  }
   1.474 +
   1.475 +  if (!result.mLength) {
   1.476 +    result = GetNativeUniChars(aShiftState & ~STATE_ALT_CONTROL);
   1.477 +    result.FillModifiers(ShiftStateToModifiers(aShiftState));
   1.478 +    return result;
   1.479 +  }
   1.480 +
   1.481 +  if ((aShiftState & STATE_ALT_CONTROL) == STATE_ALT_CONTROL) {
   1.482 +    // Even if the shifted chars and the unshifted chars are same, we
   1.483 +    // should consume the Alt key state and the Ctrl key state when
   1.484 +    // AltGr key is pressed. Because if we don't consume them, the input
   1.485 +    // events are ignored on nsEditor. (I.e., Users cannot input the
   1.486 +    // characters with this key combination.)
   1.487 +    Modifiers finalModifiers = ShiftStateToModifiers(aShiftState);
   1.488 +    finalModifiers &= ~(MODIFIER_ALT | MODIFIER_CONTROL);
   1.489 +    result.FillModifiers(finalModifiers);
   1.490 +    return result;
   1.491 +  }
   1.492 +
   1.493 +  UniCharsAndModifiers unmodifiedReslt =
   1.494 +    GetNativeUniChars(aShiftState & ~STATE_ALT_CONTROL);
   1.495 +  if (!result.UniCharsEqual(unmodifiedReslt)) {
   1.496 +    // Otherwise, we should consume the Alt key state and the Ctrl key state
   1.497 +    // only when the shifted chars and unshifted chars are different.
   1.498 +    Modifiers finalModifiers = ShiftStateToModifiers(aShiftState);
   1.499 +    finalModifiers &= ~(MODIFIER_ALT | MODIFIER_CONTROL);
   1.500 +    result.FillModifiers(finalModifiers);
   1.501 +  }
   1.502 +  return result;
   1.503 +}
   1.504 +
   1.505 +
   1.506 +UniCharsAndModifiers
   1.507 +VirtualKey::GetNativeUniChars(ShiftState aShiftState) const
   1.508 +{
   1.509 +#ifdef DEBUG
   1.510 +  if (aShiftState < 0 || aShiftState >= ArrayLength(mShiftStates)) {
   1.511 +    nsPrintfCString warning("Shift state is out of range: "
   1.512 +                            "aShiftState=%d, ArrayLength(mShiftState)=%d",
   1.513 +                            aShiftState, ArrayLength(mShiftStates));
   1.514 +    NS_WARNING(warning.get());
   1.515 +  }
   1.516 +#endif
   1.517 +
   1.518 +  UniCharsAndModifiers result;
   1.519 +  Modifiers modifiers = ShiftStateToModifiers(aShiftState);
   1.520 +  if (IsDeadKey(aShiftState)) {
   1.521 +    result.Append(mShiftStates[aShiftState].DeadKey.DeadChar, modifiers);
   1.522 +    return result;
   1.523 +  }
   1.524 +
   1.525 +  uint32_t index;
   1.526 +  uint32_t len = ArrayLength(mShiftStates[aShiftState].Normal.Chars);
   1.527 +  for (index = 0;
   1.528 +       index < len && mShiftStates[aShiftState].Normal.Chars[index]; index++) {
   1.529 +    result.Append(mShiftStates[aShiftState].Normal.Chars[index], modifiers);
   1.530 +  }
   1.531 +  return result;
   1.532 +}
   1.533 +
   1.534 +// static
   1.535 +void
   1.536 +VirtualKey::FillKbdState(PBYTE aKbdState,
   1.537 +                         const ShiftState aShiftState)
   1.538 +{
   1.539 +  NS_ASSERTION(aShiftState < 16, "aShiftState out of range");
   1.540 +
   1.541 +  if (aShiftState & STATE_SHIFT) {
   1.542 +    aKbdState[VK_SHIFT] |= 0x80;
   1.543 +  } else {
   1.544 +    aKbdState[VK_SHIFT]  &= ~0x80;
   1.545 +    aKbdState[VK_LSHIFT] &= ~0x80;
   1.546 +    aKbdState[VK_RSHIFT] &= ~0x80;
   1.547 +  }
   1.548 +
   1.549 +  if (aShiftState & STATE_CONTROL) {
   1.550 +    aKbdState[VK_CONTROL] |= 0x80;
   1.551 +  } else {
   1.552 +    aKbdState[VK_CONTROL]  &= ~0x80;
   1.553 +    aKbdState[VK_LCONTROL] &= ~0x80;
   1.554 +    aKbdState[VK_RCONTROL] &= ~0x80;
   1.555 +  }
   1.556 +
   1.557 +  if (aShiftState & STATE_ALT) {
   1.558 +    aKbdState[VK_MENU] |= 0x80;
   1.559 +  } else {
   1.560 +    aKbdState[VK_MENU]  &= ~0x80;
   1.561 +    aKbdState[VK_LMENU] &= ~0x80;
   1.562 +    aKbdState[VK_RMENU] &= ~0x80;
   1.563 +  }
   1.564 +
   1.565 +  if (aShiftState & STATE_CAPSLOCK) {
   1.566 +    aKbdState[VK_CAPITAL] |= 0x01;
   1.567 +  } else {
   1.568 +    aKbdState[VK_CAPITAL] &= ~0x01;
   1.569 +  }
   1.570 +}
   1.571 +
   1.572 +/*****************************************************************************
   1.573 + * mozilla::widget::NativeKey
   1.574 + *****************************************************************************/
   1.575 +
   1.576 +NativeKey::NativeKey(nsWindowBase* aWidget,
   1.577 +                     const MSG& aKeyOrCharMessage,
   1.578 +                     const ModifierKeyState& aModKeyState,
   1.579 +                     nsTArray<FakeCharMsg>* aFakeCharMsgs) :
   1.580 +  mWidget(aWidget), mMsg(aKeyOrCharMessage), mDOMKeyCode(0),
   1.581 +  mModKeyState(aModKeyState), mVirtualKeyCode(0), mOriginalVirtualKeyCode(0),
   1.582 +  mFakeCharMsgs(aFakeCharMsgs && aFakeCharMsgs->Length() ?
   1.583 +                  aFakeCharMsgs : nullptr)
   1.584 +{
   1.585 +  MOZ_ASSERT(aWidget);
   1.586 +  KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
   1.587 +  mKeyboardLayout = keyboardLayout->GetLayout();
   1.588 +  mScanCode = WinUtils::GetScanCode(mMsg.lParam);
   1.589 +  mIsExtended = WinUtils::IsExtendedScanCode(mMsg.lParam);
   1.590 +  // On WinXP and WinServer2003, we cannot compute the virtual keycode for
   1.591 +  // extended keys due to the API limitation.
   1.592 +  bool canComputeVirtualKeyCodeFromScanCode =
   1.593 +    (!mIsExtended || IsVistaOrLater());
   1.594 +  switch (mMsg.message) {
   1.595 +    case WM_KEYDOWN:
   1.596 +    case WM_SYSKEYDOWN:
   1.597 +    case WM_KEYUP:
   1.598 +    case WM_SYSKEYUP: {
   1.599 +      // First, resolve the IME converted virtual keycode to its original
   1.600 +      // keycode.
   1.601 +      if (mMsg.wParam == VK_PROCESSKEY) {
   1.602 +        mOriginalVirtualKeyCode =
   1.603 +          static_cast<uint8_t>(::ImmGetVirtualKey(mMsg.hwnd));
   1.604 +      } else {
   1.605 +        mOriginalVirtualKeyCode = static_cast<uint8_t>(mMsg.wParam);
   1.606 +      }
   1.607 +
   1.608 +      // Most keys are not distinguished as left or right keys.
   1.609 +      bool isLeftRightDistinguishedKey = false;
   1.610 +
   1.611 +      // mOriginalVirtualKeyCode must not distinguish left or right of
   1.612 +      // Shift, Control or Alt.
   1.613 +      switch (mOriginalVirtualKeyCode) {
   1.614 +        case VK_SHIFT:
   1.615 +        case VK_CONTROL:
   1.616 +        case VK_MENU:
   1.617 +          isLeftRightDistinguishedKey = true;
   1.618 +          break;
   1.619 +        case VK_LSHIFT:
   1.620 +        case VK_RSHIFT:
   1.621 +          mVirtualKeyCode = mOriginalVirtualKeyCode;
   1.622 +          mOriginalVirtualKeyCode = VK_SHIFT;
   1.623 +          isLeftRightDistinguishedKey = true;
   1.624 +          break;
   1.625 +        case VK_LCONTROL:
   1.626 +        case VK_RCONTROL:
   1.627 +          mVirtualKeyCode = mOriginalVirtualKeyCode;
   1.628 +          mOriginalVirtualKeyCode = VK_CONTROL;
   1.629 +          isLeftRightDistinguishedKey = true;
   1.630 +          break;
   1.631 +        case VK_LMENU:
   1.632 +        case VK_RMENU:
   1.633 +          mVirtualKeyCode = mOriginalVirtualKeyCode;
   1.634 +          mOriginalVirtualKeyCode = VK_MENU;
   1.635 +          isLeftRightDistinguishedKey = true;
   1.636 +          break;
   1.637 +      }
   1.638 +
   1.639 +      // If virtual keycode (left-right distinguished keycode) is already
   1.640 +      // computed, we don't need to do anymore.
   1.641 +      if (mVirtualKeyCode) {
   1.642 +        break;
   1.643 +      }
   1.644 +
   1.645 +      // If the keycode doesn't have LR distinguished keycode, we just set
   1.646 +      // mOriginalVirtualKeyCode to mVirtualKeyCode.  Note that don't compute
   1.647 +      // it from MapVirtualKeyEx() because the scan code might be wrong if
   1.648 +      // the message is sent/posted by other application.  Then, we will compute
   1.649 +      // unexpected keycode from the scan code.
   1.650 +      if (!isLeftRightDistinguishedKey) {
   1.651 +        break;
   1.652 +      }
   1.653 +
   1.654 +      if (!canComputeVirtualKeyCodeFromScanCode) {
   1.655 +        // The right control key and the right alt key are extended keys.
   1.656 +        // Therefore, we never get VK_RCONTRL and VK_RMENU for the result of
   1.657 +        // MapVirtualKeyEx() on WinXP or WinServer2003.
   1.658 +        //
   1.659 +        // If VK_CONTROL or VK_MENU key message is caused by an extended key,
   1.660 +        // we should assume that the right key of them is pressed.
   1.661 +        switch (mOriginalVirtualKeyCode) {
   1.662 +          case VK_CONTROL:
   1.663 +            mVirtualKeyCode = VK_RCONTROL;
   1.664 +            break;
   1.665 +          case VK_MENU:
   1.666 +            mVirtualKeyCode = VK_RMENU;
   1.667 +            break;
   1.668 +          case VK_SHIFT:
   1.669 +            // Neither left shift nor right shift is not an extended key,
   1.670 +            // let's use VK_LSHIFT for invalid scan code.
   1.671 +            mVirtualKeyCode = VK_LSHIFT;
   1.672 +            break;
   1.673 +          default:
   1.674 +            MOZ_CRASH("Unsupported mOriginalVirtualKeyCode");
   1.675 +        }
   1.676 +        break;
   1.677 +      }
   1.678 +
   1.679 +      NS_ASSERTION(!mVirtualKeyCode,
   1.680 +                   "mVirtualKeyCode has been computed already");
   1.681 +
   1.682 +      // Otherwise, compute the virtual keycode with MapVirtualKeyEx().
   1.683 +      mVirtualKeyCode = ComputeVirtualKeyCodeFromScanCodeEx();
   1.684 +
   1.685 +      // The result might be unexpected value due to the scan code is
   1.686 +      // wrong.  For example, any key messages can be generated by
   1.687 +      // SendMessage() or PostMessage() from applications.  So, it's possible
   1.688 +      // failure.  Then, let's respect the extended flag even if it might be
   1.689 +      // set intentionally.
   1.690 +      switch (mOriginalVirtualKeyCode) {
   1.691 +        case VK_CONTROL:
   1.692 +          if (mVirtualKeyCode != VK_LCONTROL &&
   1.693 +              mVirtualKeyCode != VK_RCONTROL) {
   1.694 +            mVirtualKeyCode = mIsExtended ? VK_RCONTROL : VK_LCONTROL;
   1.695 +          }
   1.696 +          break;
   1.697 +        case VK_MENU:
   1.698 +          if (mVirtualKeyCode != VK_LMENU && mVirtualKeyCode != VK_RMENU) {
   1.699 +            mVirtualKeyCode = mIsExtended ? VK_RMENU : VK_LMENU;
   1.700 +          }
   1.701 +          break;
   1.702 +        case VK_SHIFT:
   1.703 +          if (mVirtualKeyCode != VK_LSHIFT && mVirtualKeyCode != VK_RSHIFT) {
   1.704 +            // Neither left shift nor right shift is not an extended key,
   1.705 +            // let's use VK_LSHIFT for invalid scan code.
   1.706 +            mVirtualKeyCode = VK_LSHIFT;
   1.707 +          }
   1.708 +          break;
   1.709 +        default:
   1.710 +          MOZ_CRASH("Unsupported mOriginalVirtualKeyCode");
   1.711 +      }
   1.712 +      break;
   1.713 +    }
   1.714 +    case WM_CHAR:
   1.715 +    case WM_UNICHAR:
   1.716 +    case WM_SYSCHAR:
   1.717 +      // We cannot compute the virtual key code from WM_CHAR message on WinXP
   1.718 +      // if it's caused by an extended key.
   1.719 +      if (!canComputeVirtualKeyCodeFromScanCode) {
   1.720 +        break;
   1.721 +      }
   1.722 +      mVirtualKeyCode = mOriginalVirtualKeyCode =
   1.723 +        ComputeVirtualKeyCodeFromScanCodeEx();
   1.724 +      NS_ASSERTION(mVirtualKeyCode, "Failed to compute virtual keycode");
   1.725 +      break;
   1.726 +    default:
   1.727 +      MOZ_CRASH("Unsupported message");
   1.728 +  }
   1.729 +
   1.730 +  if (!mVirtualKeyCode) {
   1.731 +    mVirtualKeyCode = mOriginalVirtualKeyCode;
   1.732 +  }
   1.733 +
   1.734 +  mDOMKeyCode =
   1.735 +    keyboardLayout->ConvertNativeKeyCodeToDOMKeyCode(mOriginalVirtualKeyCode);
   1.736 +  mKeyNameIndex =
   1.737 +    keyboardLayout->ConvertNativeKeyCodeToKeyNameIndex(mOriginalVirtualKeyCode);
   1.738 +
   1.739 +  keyboardLayout->InitNativeKey(*this, mModKeyState);
   1.740 +
   1.741 +  mIsDeadKey =
   1.742 +    (IsFollowedByDeadCharMessage() ||
   1.743 +     keyboardLayout->IsDeadKey(mOriginalVirtualKeyCode, mModKeyState));
   1.744 +  mIsPrintableKey = KeyboardLayout::IsPrintableCharKey(mOriginalVirtualKeyCode);
   1.745 +}
   1.746 +
   1.747 +bool
   1.748 +NativeKey::IsFollowedByDeadCharMessage() const
   1.749 +{
   1.750 +  MSG nextMsg;
   1.751 +  if (mFakeCharMsgs) {
   1.752 +    nextMsg = mFakeCharMsgs->ElementAt(0).GetCharMsg(mMsg.hwnd);
   1.753 +  } else {
   1.754 +    if (!WinUtils::PeekMessage(&nextMsg, mMsg.hwnd, WM_KEYFIRST, WM_KEYLAST,
   1.755 +                               PM_NOREMOVE | PM_NOYIELD)) {
   1.756 +      return false;
   1.757 +    }
   1.758 +  }
   1.759 +  return IsDeadCharMessage(nextMsg);
   1.760 +}
   1.761 +
   1.762 +bool
   1.763 +NativeKey::IsIMEDoingKakuteiUndo() const
   1.764 +{
   1.765 +  // Following message pattern is caused by "Kakutei-Undo" of ATOK or WXG:
   1.766 +  // ---------------------------------------------------------------------------
   1.767 +  // WM_KEYDOWN              * n (wParam = VK_BACK, lParam = 0x1)
   1.768 +  // WM_KEYUP                * 1 (wParam = VK_BACK, lParam = 0xC0000001) # ATOK
   1.769 +  // WM_IME_STARTCOMPOSITION * 1 (wParam = 0x0, lParam = 0x0)
   1.770 +  // WM_IME_COMPOSITION      * 1 (wParam = 0x0, lParam = 0x1BF)
   1.771 +  // WM_CHAR                 * n (wParam = VK_BACK, lParam = 0x1)
   1.772 +  // WM_KEYUP                * 1 (wParam = VK_BACK, lParam = 0xC00E0001)
   1.773 +  // ---------------------------------------------------------------------------
   1.774 +  // This doesn't match usual key message pattern such as:
   1.775 +  //   WM_KEYDOWN -> WM_CHAR -> WM_KEYDOWN -> WM_CHAR -> ... -> WM_KEYUP
   1.776 +  // See following bugs for the detail.
   1.777 +  // https://bugzilla.mozilla.gr.jp/show_bug.cgi?id=2885 (written in Japanese)
   1.778 +  // https://bugzilla.mozilla.org/show_bug.cgi?id=194559 (written in English)
   1.779 +  MSG startCompositionMsg, compositionMsg, charMsg;
   1.780 +  return WinUtils::PeekMessage(&startCompositionMsg, mMsg.hwnd,
   1.781 +                               WM_IME_STARTCOMPOSITION, WM_IME_STARTCOMPOSITION,
   1.782 +                               PM_NOREMOVE | PM_NOYIELD) &&
   1.783 +         WinUtils::PeekMessage(&compositionMsg, mMsg.hwnd, WM_IME_COMPOSITION,
   1.784 +                               WM_IME_COMPOSITION, PM_NOREMOVE | PM_NOYIELD) &&
   1.785 +         WinUtils::PeekMessage(&charMsg, mMsg.hwnd, WM_CHAR, WM_CHAR,
   1.786 +                               PM_NOREMOVE | PM_NOYIELD) &&
   1.787 +         startCompositionMsg.wParam == 0x0 &&
   1.788 +         startCompositionMsg.lParam == 0x0 &&
   1.789 +         compositionMsg.wParam == 0x0 &&
   1.790 +         compositionMsg.lParam == 0x1BF &&
   1.791 +         charMsg.wParam == VK_BACK && charMsg.lParam == 0x1 &&
   1.792 +         startCompositionMsg.time <= compositionMsg.time &&
   1.793 +         compositionMsg.time <= charMsg.time;
   1.794 +}
   1.795 +
   1.796 +UINT
   1.797 +NativeKey::GetScanCodeWithExtendedFlag() const
   1.798 +{
   1.799 +  // MapVirtualKeyEx() has been improved for supporting extended keys since
   1.800 +  // Vista.  When we call it for mapping a scancode of an extended key and
   1.801 +  // a virtual keycode, we need to add 0xE000 to the scancode.
   1.802 +  // On Win XP and Win Server 2003, this doesn't support. On them, we have
   1.803 +  // no way to get virtual keycodes from scancode of extended keys.
   1.804 +  if (!mIsExtended || !IsVistaOrLater()) {
   1.805 +    return mScanCode;
   1.806 +  }
   1.807 +  return (0xE000 | mScanCode);
   1.808 +}
   1.809 +
   1.810 +uint32_t
   1.811 +NativeKey::GetKeyLocation() const
   1.812 +{
   1.813 +  switch (mVirtualKeyCode) {
   1.814 +    case VK_LSHIFT:
   1.815 +    case VK_LCONTROL:
   1.816 +    case VK_LMENU:
   1.817 +    case VK_LWIN:
   1.818 +      return nsIDOMKeyEvent::DOM_KEY_LOCATION_LEFT;
   1.819 +
   1.820 +    case VK_RSHIFT:
   1.821 +    case VK_RCONTROL:
   1.822 +    case VK_RMENU:
   1.823 +    case VK_RWIN:
   1.824 +      return nsIDOMKeyEvent::DOM_KEY_LOCATION_RIGHT;
   1.825 +
   1.826 +    case VK_RETURN:
   1.827 +      // XXX This code assumes that all keyboard drivers use same mapping.
   1.828 +      return !mIsExtended ? nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD :
   1.829 +                            nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD;
   1.830 +
   1.831 +    case VK_INSERT:
   1.832 +    case VK_DELETE:
   1.833 +    case VK_END:
   1.834 +    case VK_DOWN:
   1.835 +    case VK_NEXT:
   1.836 +    case VK_LEFT:
   1.837 +    case VK_CLEAR:
   1.838 +    case VK_RIGHT:
   1.839 +    case VK_HOME:
   1.840 +    case VK_UP:
   1.841 +    case VK_PRIOR:
   1.842 +      // XXX This code assumes that all keyboard drivers use same mapping.
   1.843 +      return mIsExtended ? nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD :
   1.844 +                           nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD;
   1.845 +
   1.846 +    // NumLock key isn't included due to IE9's behavior.
   1.847 +    case VK_NUMPAD0:
   1.848 +    case VK_NUMPAD1:
   1.849 +    case VK_NUMPAD2:
   1.850 +    case VK_NUMPAD3:
   1.851 +    case VK_NUMPAD4:
   1.852 +    case VK_NUMPAD5:
   1.853 +    case VK_NUMPAD6:
   1.854 +    case VK_NUMPAD7:
   1.855 +    case VK_NUMPAD8:
   1.856 +    case VK_NUMPAD9:
   1.857 +    case VK_DECIMAL:
   1.858 +    case VK_DIVIDE:
   1.859 +    case VK_MULTIPLY:
   1.860 +    case VK_SUBTRACT:
   1.861 +    case VK_ADD:
   1.862 +    // Separator key of Brazilian keyboard or JIS keyboard for Mac
   1.863 +    case VK_ABNT_C2:
   1.864 +      return nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD;
   1.865 +
   1.866 +    case VK_SHIFT:
   1.867 +    case VK_CONTROL:
   1.868 +    case VK_MENU:
   1.869 +      NS_WARNING("Failed to decide the key location?");
   1.870 +
   1.871 +    default:
   1.872 +      return nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD;
   1.873 +  }
   1.874 +}
   1.875 +
   1.876 +uint8_t
   1.877 +NativeKey::ComputeVirtualKeyCodeFromScanCode() const
   1.878 +{
   1.879 +  return static_cast<uint8_t>(
   1.880 +           ::MapVirtualKeyEx(mScanCode, MAPVK_VSC_TO_VK, mKeyboardLayout));
   1.881 +}
   1.882 +
   1.883 +uint8_t
   1.884 +NativeKey::ComputeVirtualKeyCodeFromScanCodeEx() const
   1.885 +{
   1.886 +  // NOTE: WinXP doesn't support mapping scan code to virtual keycode of
   1.887 +  //       extended keys.
   1.888 +  NS_ENSURE_TRUE(!mIsExtended || IsVistaOrLater(), 0);
   1.889 +  return static_cast<uint8_t>(
   1.890 +           ::MapVirtualKeyEx(GetScanCodeWithExtendedFlag(), MAPVK_VSC_TO_VK_EX,
   1.891 +                             mKeyboardLayout));
   1.892 +}
   1.893 +
   1.894 +char16_t
   1.895 +NativeKey::ComputeUnicharFromScanCode() const
   1.896 +{
   1.897 +  return static_cast<char16_t>(
   1.898 +           ::MapVirtualKeyEx(ComputeVirtualKeyCodeFromScanCode(),
   1.899 +                             MAPVK_VK_TO_CHAR, mKeyboardLayout));
   1.900 +}
   1.901 +
   1.902 +void
   1.903 +NativeKey::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent) const
   1.904 +{
   1.905 +  InitKeyEvent(aKeyEvent, mModKeyState);
   1.906 +}
   1.907 +
   1.908 +void
   1.909 +NativeKey::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
   1.910 +                        const ModifierKeyState& aModKeyState) const
   1.911 +{
   1.912 +  nsIntPoint point(0, 0);
   1.913 +  mWidget->InitEvent(aKeyEvent, &point);
   1.914 +
   1.915 +  switch (aKeyEvent.message) {
   1.916 +    case NS_KEY_DOWN:
   1.917 +      aKeyEvent.keyCode = mDOMKeyCode;
   1.918 +      // Unique id for this keydown event and its associated keypress.
   1.919 +      sUniqueKeyEventId++;
   1.920 +      aKeyEvent.mUniqueId = sUniqueKeyEventId;
   1.921 +      break;
   1.922 +    case NS_KEY_UP:
   1.923 +      aKeyEvent.keyCode = mDOMKeyCode;
   1.924 +      // Set defaultPrevented of the key event if the VK_MENU is not a system
   1.925 +      // key release, so that the menu bar does not trigger.  This helps avoid
   1.926 +      // triggering the menu bar for ALT key accelerators used in assistive
   1.927 +      // technologies such as Window-Eyes and ZoomText or for switching open
   1.928 +      // state of IME.
   1.929 +      aKeyEvent.mFlags.mDefaultPrevented =
   1.930 +        (mOriginalVirtualKeyCode == VK_MENU && mMsg.message != WM_SYSKEYUP);
   1.931 +      break;
   1.932 +    case NS_KEY_PRESS:
   1.933 +      aKeyEvent.mUniqueId = sUniqueKeyEventId;
   1.934 +      break;
   1.935 +    default:
   1.936 +      MOZ_CRASH("Invalid event message");
   1.937 +  }
   1.938 +
   1.939 +  aKeyEvent.mIsRepeat = IsRepeat();
   1.940 +  aKeyEvent.mKeyNameIndex = mKeyNameIndex;
   1.941 +  if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) {
   1.942 +    aKeyEvent.mKeyValue = mCommittedCharsAndModifiers.ToString();
   1.943 +  }
   1.944 +  aKeyEvent.location = GetKeyLocation();
   1.945 +  aModKeyState.InitInputEvent(aKeyEvent);
   1.946 +}
   1.947 +
   1.948 +bool
   1.949 +NativeKey::DispatchKeyEvent(WidgetKeyboardEvent& aKeyEvent,
   1.950 +                            const MSG* aMsgSentToPlugin) const
   1.951 +{
   1.952 +  if (mWidget->Destroyed()) {
   1.953 +    MOZ_CRASH("NativeKey tries to dispatch a key event on destroyed widget");
   1.954 +  }
   1.955 +
   1.956 +  KeyboardLayout::NotifyIdleServiceOfUserActivity();
   1.957 +
   1.958 +  NPEvent pluginEvent;
   1.959 +  if (aMsgSentToPlugin &&
   1.960 +      mWidget->GetInputContext().mIMEState.mEnabled == IMEState::PLUGIN) {
   1.961 +    pluginEvent.event = aMsgSentToPlugin->message;
   1.962 +    pluginEvent.wParam = aMsgSentToPlugin->wParam;
   1.963 +    pluginEvent.lParam = aMsgSentToPlugin->lParam;
   1.964 +    aKeyEvent.pluginEvent = static_cast<void*>(&pluginEvent);
   1.965 +  }
   1.966 +
   1.967 +  return (mWidget->DispatchKeyboardEvent(&aKeyEvent) || mWidget->Destroyed());
   1.968 +}
   1.969 +
   1.970 +bool
   1.971 +NativeKey::HandleKeyDownMessage(bool* aEventDispatched) const
   1.972 +{
   1.973 +  MOZ_ASSERT(IsKeyDownMessage());
   1.974 +
   1.975 +  if (aEventDispatched) {
   1.976 +    *aEventDispatched = false;
   1.977 +  }
   1.978 +
   1.979 +  bool defaultPrevented = false;
   1.980 +  if (mFakeCharMsgs ||
   1.981 +      !RedirectedKeyDownMessageManager::IsRedirectedMessage(mMsg)) {
   1.982 +    // Ignore [shift+]alt+space so the OS can handle it.
   1.983 +    if (mModKeyState.IsAlt() && !mModKeyState.IsControl() &&
   1.984 +        mVirtualKeyCode == VK_SPACE) {
   1.985 +      return false;
   1.986 +    }
   1.987 +
   1.988 +    bool isIMEEnabled = WinUtils::IsIMEEnabled(mWidget->GetInputContext());
   1.989 +    WidgetKeyboardEvent keydownEvent(true, NS_KEY_DOWN, mWidget);
   1.990 +    InitKeyEvent(keydownEvent, mModKeyState);
   1.991 +    if (aEventDispatched) {
   1.992 +      *aEventDispatched = true;
   1.993 +    }
   1.994 +    defaultPrevented = DispatchKeyEvent(keydownEvent, &mMsg);
   1.995 +
   1.996 +    if (mWidget->Destroyed()) {
   1.997 +      return true;
   1.998 +    }
   1.999 +
  1.1000 +    // If IMC wasn't associated to the window but is associated it now (i.e.,
  1.1001 +    // focus is moved from a non-editable editor to an editor by keydown
  1.1002 +    // event handler), WM_CHAR and WM_SYSCHAR shouldn't cause first character
  1.1003 +    // inputting if IME is opened.  But then, we should redirect the native
  1.1004 +    // keydown message to IME.
  1.1005 +    // However, note that if focus has been already moved to another
  1.1006 +    // application, we shouldn't redirect the message to it because the keydown
  1.1007 +    // message is processed by us, so, nobody shouldn't process it.
  1.1008 +    HWND focusedWnd = ::GetFocus();
  1.1009 +    if (!defaultPrevented && !mFakeCharMsgs && focusedWnd &&
  1.1010 +        !mWidget->PluginHasFocus() && !isIMEEnabled &&
  1.1011 +        WinUtils::IsIMEEnabled(mWidget->GetInputContext())) {
  1.1012 +      RedirectedKeyDownMessageManager::RemoveNextCharMessage(focusedWnd);
  1.1013 +
  1.1014 +      INPUT keyinput;
  1.1015 +      keyinput.type = INPUT_KEYBOARD;
  1.1016 +      keyinput.ki.wVk = mOriginalVirtualKeyCode;
  1.1017 +      keyinput.ki.wScan = mScanCode;
  1.1018 +      keyinput.ki.dwFlags = KEYEVENTF_SCANCODE;
  1.1019 +      if (mIsExtended) {
  1.1020 +        keyinput.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
  1.1021 +      }
  1.1022 +      keyinput.ki.time = 0;
  1.1023 +      keyinput.ki.dwExtraInfo = 0;
  1.1024 +
  1.1025 +      RedirectedKeyDownMessageManager::WillRedirect(mMsg, defaultPrevented);
  1.1026 +
  1.1027 +      ::SendInput(1, &keyinput, sizeof(keyinput));
  1.1028 +
  1.1029 +      // Return here.  We shouldn't dispatch keypress event for this WM_KEYDOWN.
  1.1030 +      // If it's needed, it will be dispatched after next (redirected)
  1.1031 +      // WM_KEYDOWN.
  1.1032 +      return true;
  1.1033 +    }
  1.1034 +  } else {
  1.1035 +    defaultPrevented = RedirectedKeyDownMessageManager::DefaultPrevented();
  1.1036 +    // If this is redirected keydown message, we have dispatched the keydown
  1.1037 +    // event already.
  1.1038 +    if (aEventDispatched) {
  1.1039 +      *aEventDispatched = true;
  1.1040 +    }
  1.1041 +  }
  1.1042 +
  1.1043 +  RedirectedKeyDownMessageManager::Forget();
  1.1044 +
  1.1045 +  // If the key was processed by IME, we shouldn't dispatch keypress event.
  1.1046 +  if (mOriginalVirtualKeyCode == VK_PROCESSKEY) {
  1.1047 +    return defaultPrevented;
  1.1048 +  }
  1.1049 +
  1.1050 +  // Don't dispatch keypress event for modifier keys.
  1.1051 +  switch (mDOMKeyCode) {
  1.1052 +    case NS_VK_SHIFT:
  1.1053 +    case NS_VK_CONTROL:
  1.1054 +    case NS_VK_ALT:
  1.1055 +    case NS_VK_CAPS_LOCK:
  1.1056 +    case NS_VK_NUM_LOCK:
  1.1057 +    case NS_VK_SCROLL_LOCK:
  1.1058 +    case NS_VK_WIN:
  1.1059 +      return defaultPrevented;
  1.1060 +  }
  1.1061 +
  1.1062 +  if (defaultPrevented) {
  1.1063 +    DispatchPluginEventsAndDiscardsCharMessages();
  1.1064 +    return true;
  1.1065 +  }
  1.1066 +
  1.1067 +  // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a
  1.1068 +  // keypress for almost all keys
  1.1069 +  if (NeedsToHandleWithoutFollowingCharMessages()) {
  1.1070 +    return (DispatchPluginEventsAndDiscardsCharMessages() ||
  1.1071 +            DispatchKeyPressEventsWithKeyboardLayout());
  1.1072 +  }
  1.1073 +
  1.1074 +  MSG followingCharMsg;
  1.1075 +  if (GetFollowingCharMessage(followingCharMsg)) {
  1.1076 +    // Even if there was char message, it might be redirected by different
  1.1077 +    // window (perhaps, focus move?).  Then, we shouldn't continue to handle
  1.1078 +    // the message since no input should occur on the window.
  1.1079 +    if (followingCharMsg.message == WM_NULL ||
  1.1080 +        followingCharMsg.hwnd != mMsg.hwnd) {
  1.1081 +      return false;
  1.1082 +    }
  1.1083 +    return DispatchKeyPressEventForFollowingCharMessage(followingCharMsg);
  1.1084 +  }
  1.1085 +
  1.1086 +  if (!mModKeyState.IsControl() && !mModKeyState.IsAlt() &&
  1.1087 +      !mModKeyState.IsWin() && mIsPrintableKey) {
  1.1088 +    // If this is simple KeyDown event but next message is not WM_CHAR,
  1.1089 +    // this event may not input text, so we should ignore this event.
  1.1090 +    // See bug 314130.
  1.1091 +    return false;
  1.1092 +  }
  1.1093 +
  1.1094 +  if (mIsDeadKey) {
  1.1095 +    return false;
  1.1096 +  }
  1.1097 +
  1.1098 +  return DispatchKeyPressEventsWithKeyboardLayout();
  1.1099 +}
  1.1100 +
  1.1101 +bool
  1.1102 +NativeKey::HandleCharMessage(const MSG& aCharMsg,
  1.1103 +                             bool* aEventDispatched) const
  1.1104 +{
  1.1105 +  MOZ_ASSERT(IsKeyDownMessage() || IsPrintableCharMessage(mMsg));
  1.1106 +  MOZ_ASSERT(IsPrintableCharMessage(aCharMsg.message));
  1.1107 +
  1.1108 +  if (aEventDispatched) {
  1.1109 +    *aEventDispatched = false;
  1.1110 +  }
  1.1111 +
  1.1112 +  // Alt+Space key is handled by OS, we shouldn't touch it.
  1.1113 +  if (mModKeyState.IsAlt() && !mModKeyState.IsControl() &&
  1.1114 +      mVirtualKeyCode == VK_SPACE) {
  1.1115 +    return false;
  1.1116 +  }
  1.1117 +
  1.1118 +  // Bug 818235: Ignore Ctrl+Enter.
  1.1119 +  if (!mModKeyState.IsAlt() && mModKeyState.IsControl() &&
  1.1120 +      mVirtualKeyCode == VK_RETURN) {
  1.1121 +    return false;
  1.1122 +  }
  1.1123 +
  1.1124 +  // XXXmnakao I think that if aNativeKeyDown is null, such lonely WM_CHAR
  1.1125 +  //           should cause composition events because they are not caused
  1.1126 +  //           by actual keyboard operation.
  1.1127 +
  1.1128 +  static const char16_t U_SPACE = 0x20;
  1.1129 +  static const char16_t U_EQUAL = 0x3D;
  1.1130 +
  1.1131 +  // First, handle normal text input or non-printable key case here.
  1.1132 +  if ((!mModKeyState.IsAlt() && !mModKeyState.IsControl()) ||
  1.1133 +      mModKeyState.IsAltGr() ||
  1.1134 +      (mOriginalVirtualKeyCode &&
  1.1135 +       !KeyboardLayout::IsPrintableCharKey(mOriginalVirtualKeyCode))) {
  1.1136 +    WidgetKeyboardEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
  1.1137 +    if (aCharMsg.wParam >= U_SPACE) {
  1.1138 +      keypressEvent.charCode = static_cast<uint32_t>(aCharMsg.wParam);
  1.1139 +    } else {
  1.1140 +      keypressEvent.keyCode = mDOMKeyCode;
  1.1141 +    }
  1.1142 +    // When AltGr (Alt+Ctrl) is pressed, that causes normal text input.
  1.1143 +    // At this time, if either alt or ctrl flag is set, nsEditor ignores the
  1.1144 +    // keypress event.  For avoiding this issue, we should remove ctrl and alt
  1.1145 +    // flags.
  1.1146 +    ModifierKeyState modKeyState(mModKeyState);
  1.1147 +    modKeyState.Unset(MODIFIER_ALT | MODIFIER_CONTROL);
  1.1148 +    InitKeyEvent(keypressEvent, modKeyState);
  1.1149 +    if (aEventDispatched) {
  1.1150 +      *aEventDispatched = true;
  1.1151 +    }
  1.1152 +    return DispatchKeyEvent(keypressEvent, &aCharMsg);
  1.1153 +  }
  1.1154 +
  1.1155 +  // XXX It seems that following code was implemented for shortcut key
  1.1156 +  //     handling.  However, it's now handled in WM_KEYDOWN message handler.
  1.1157 +  //     So, this actually runs only when WM_CHAR is sent/posted without
  1.1158 +  //     WM_KEYDOWN.  I think that we don't need to keypress event in such
  1.1159 +  //     case especially for shortcut keys.
  1.1160 +
  1.1161 +  char16_t uniChar;
  1.1162 +  // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
  1.1163 +  if (mModKeyState.IsControl() && aCharMsg.wParam <= 0x1A) {
  1.1164 +    // Bug 16486: Need to account for shift here.
  1.1165 +    uniChar = aCharMsg.wParam - 1 + (mModKeyState.IsShift() ? 'A' : 'a');
  1.1166 +  } else if (mModKeyState.IsControl() && aCharMsg.wParam <= 0x1F) {
  1.1167 +    // Bug 50255: <ctrl><[> and <ctrl><]> are not being processed.
  1.1168 +    // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
  1.1169 +    // for some reason the keypress handler need to have the uniChar code set
  1.1170 +    // with the addition of a upper case A not the lower case.
  1.1171 +    uniChar = aCharMsg.wParam - 1 + 'A';
  1.1172 +  } else if (aCharMsg.wParam < U_SPACE ||
  1.1173 +             (aCharMsg.wParam == U_EQUAL && mModKeyState.IsControl())) {
  1.1174 +    uniChar = 0;
  1.1175 +  } else {
  1.1176 +    uniChar = aCharMsg.wParam;
  1.1177 +  }
  1.1178 +
  1.1179 +  // Bug 50255 and Bug 351310: Keep the characters unshifted for shortcuts and
  1.1180 +  // accesskeys and make sure that numbers are always passed as such.
  1.1181 +  if (uniChar && (mModKeyState.IsControl() || mModKeyState.IsAlt())) {
  1.1182 +    KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
  1.1183 +    char16_t unshiftedCharCode =
  1.1184 +      (mVirtualKeyCode >= '0' && mVirtualKeyCode <= '9') ?
  1.1185 +        mVirtualKeyCode :  mModKeyState.IsShift() ?
  1.1186 +                             ComputeUnicharFromScanCode() : 0;
  1.1187 +    // Ignore diacritics (top bit set) and key mapping errors (char code 0)
  1.1188 +    if (static_cast<int32_t>(unshiftedCharCode) > 0) {
  1.1189 +      uniChar = unshiftedCharCode;
  1.1190 +    }
  1.1191 +  }
  1.1192 +
  1.1193 +  // Bug 285161 and Bug 295095: They were caused by the initial fix for
  1.1194 +  // bug 178110.  When pressing (alt|ctrl)+char, the char must be lowercase
  1.1195 +  // unless shift is pressed too.
  1.1196 +  if (!mModKeyState.IsShift() &&
  1.1197 +      (mModKeyState.IsAlt() || mModKeyState.IsControl())) {
  1.1198 +    uniChar = towlower(uniChar);
  1.1199 +  }
  1.1200 +
  1.1201 +  WidgetKeyboardEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
  1.1202 +  keypressEvent.charCode = uniChar;
  1.1203 +  if (!keypressEvent.charCode) {
  1.1204 +    keypressEvent.keyCode = mDOMKeyCode;
  1.1205 +  }
  1.1206 +  InitKeyEvent(keypressEvent, mModKeyState);
  1.1207 +  if (aEventDispatched) {
  1.1208 +    *aEventDispatched = true;
  1.1209 +  }
  1.1210 +  return DispatchKeyEvent(keypressEvent, &aCharMsg);
  1.1211 +}
  1.1212 +
  1.1213 +bool
  1.1214 +NativeKey::HandleKeyUpMessage(bool* aEventDispatched) const
  1.1215 +{
  1.1216 +  MOZ_ASSERT(IsKeyUpMessage());
  1.1217 +
  1.1218 +  if (aEventDispatched) {
  1.1219 +    *aEventDispatched = false;
  1.1220 +  }
  1.1221 +
  1.1222 +  // Ignore [shift+]alt+space so the OS can handle it.
  1.1223 +  if (mModKeyState.IsAlt() && !mModKeyState.IsControl() &&
  1.1224 +      mVirtualKeyCode == VK_SPACE) {
  1.1225 +    return false;
  1.1226 +  }
  1.1227 +
  1.1228 +  WidgetKeyboardEvent keyupEvent(true, NS_KEY_UP, mWidget);
  1.1229 +  InitKeyEvent(keyupEvent, mModKeyState);
  1.1230 +  if (aEventDispatched) {
  1.1231 +    *aEventDispatched = true;
  1.1232 +  }
  1.1233 +  return DispatchKeyEvent(keyupEvent, &mMsg);
  1.1234 +}
  1.1235 +
  1.1236 +bool
  1.1237 +NativeKey::NeedsToHandleWithoutFollowingCharMessages() const
  1.1238 +{
  1.1239 +  MOZ_ASSERT(IsKeyDownMessage());
  1.1240 +
  1.1241 +  // Enter and backspace are always handled here to avoid for example the
  1.1242 +  // confusion between ctrl-enter and ctrl-J.
  1.1243 +  if (mDOMKeyCode == NS_VK_RETURN || mDOMKeyCode == NS_VK_BACK) {
  1.1244 +    return true;
  1.1245 +  }
  1.1246 +
  1.1247 +  // If any modifier keys which may cause printable keys becoming non-printable
  1.1248 +  // are not pressed, we don't need special handling for the key.
  1.1249 +  if (!mModKeyState.IsControl() && !mModKeyState.IsAlt() &&
  1.1250 +      !mModKeyState.IsWin()) {
  1.1251 +    return false;
  1.1252 +  }
  1.1253 +
  1.1254 +  // If the key event causes dead key event, we don't need to dispatch keypress
  1.1255 +  // event.
  1.1256 +  if (mIsDeadKey && mCommittedCharsAndModifiers.IsEmpty()) {
  1.1257 +    return false;
  1.1258 +  }
  1.1259 +
  1.1260 +  // Even if the key is a printable key, it might cause non-printable character
  1.1261 +  // input with modifier key(s).
  1.1262 +  return mIsPrintableKey;
  1.1263 +}
  1.1264 +
  1.1265 +#ifdef MOZ_CRASHREPORTER
  1.1266 +
  1.1267 +static nsCString
  1.1268 +GetResultOfInSendMessageEx()
  1.1269 +{
  1.1270 +  DWORD ret = ::InSendMessageEx(nullptr);
  1.1271 +  if (!ret) {
  1.1272 +    return NS_LITERAL_CSTRING("ISMEX_NOSEND");
  1.1273 +  }
  1.1274 +  nsAutoCString result;
  1.1275 +  if (ret & ISMEX_CALLBACK) {
  1.1276 +    result = "ISMEX_CALLBACK";
  1.1277 +  }
  1.1278 +  if (ret & ISMEX_NOTIFY) {
  1.1279 +    if (!result.IsEmpty()) {
  1.1280 +      result += " | ";
  1.1281 +    }
  1.1282 +    result += "ISMEX_NOTIFY";
  1.1283 +  }
  1.1284 +  if (ret & ISMEX_REPLIED) {
  1.1285 +    if (!result.IsEmpty()) {
  1.1286 +      result += " | ";
  1.1287 +    }
  1.1288 +    result += "ISMEX_REPLIED";
  1.1289 +  }
  1.1290 +  if (ret & ISMEX_SEND) {
  1.1291 +    if (!result.IsEmpty()) {
  1.1292 +      result += " | ";
  1.1293 +    }
  1.1294 +    result += "ISMEX_SEND";
  1.1295 +  }
  1.1296 +  return result;
  1.1297 +}
  1.1298 +
  1.1299 +static const char*
  1.1300 +GetMessageName(UINT aMessage)
  1.1301 +{
  1.1302 +  switch (aMessage) {
  1.1303 +    case WM_KEYDOWN:     return "WM_KEYDOWN";
  1.1304 +    case WM_SYSKEYDOWN:  return "WM_SYSKEYDOWN";
  1.1305 +    case WM_KEYUP:       return "WM_KEYUP";
  1.1306 +    case WM_SYSKEYUP:    return "WM_SYSKEYUP";
  1.1307 +    case WM_CHAR:        return "WM_CHAR";
  1.1308 +    case WM_DEADCHAR:    return "WM_DEADCHAR";
  1.1309 +    case WM_SYSCHAR:     return "WM_SYSCHAR";
  1.1310 +    case WM_SYSDEADCHAR: return "WM_SYSDEADCHAR";
  1.1311 +    case WM_UNICHAR:     return "WM_UNICHAR";
  1.1312 +    case WM_QUIT:        return "WM_QUIT";
  1.1313 +    case WM_NULL:        return "WM_NULL";
  1.1314 +    default:             return "Unknown";
  1.1315 +  }
  1.1316 +}
  1.1317 +
  1.1318 +#endif // #ifdef MOZ_CRASHREPORTER
  1.1319 +
  1.1320 +bool
  1.1321 +NativeKey::MayBeSameCharMessage(const MSG& aCharMsg1,
  1.1322 +                                const MSG& aCharMsg2) const
  1.1323 +{
  1.1324 +  // NOTE: Although, we don't know when this case occurs, the scan code value
  1.1325 +  //       in lParam may be changed from 0 to something.  The changed value
  1.1326 +  //       is different from the scan code of handling keydown message.
  1.1327 +  static const LPARAM kScanCodeMask = 0x00FF0000;
  1.1328 +  return
  1.1329 +    aCharMsg1.message == aCharMsg2.message &&
  1.1330 +    aCharMsg1.wParam == aCharMsg2.wParam &&
  1.1331 +    (aCharMsg1.lParam & ~kScanCodeMask) == (aCharMsg2.lParam & ~kScanCodeMask);
  1.1332 +}
  1.1333 +
  1.1334 +bool
  1.1335 +NativeKey::GetFollowingCharMessage(MSG& aCharMsg) const
  1.1336 +{
  1.1337 +  MOZ_ASSERT(IsKeyDownMessage());
  1.1338 +
  1.1339 +  aCharMsg.message = WM_NULL;
  1.1340 +
  1.1341 +  if (mFakeCharMsgs) {
  1.1342 +    FakeCharMsg& fakeCharMsg = mFakeCharMsgs->ElementAt(0);
  1.1343 +    if (fakeCharMsg.mConsumed) {
  1.1344 +      return false;
  1.1345 +    }
  1.1346 +    MSG charMsg = fakeCharMsg.GetCharMsg(mMsg.hwnd);
  1.1347 +    fakeCharMsg.mConsumed = true;
  1.1348 +    if (!IsCharMessage(charMsg)) {
  1.1349 +      return false;
  1.1350 +    }
  1.1351 +    aCharMsg = charMsg;
  1.1352 +    return true;
  1.1353 +  }
  1.1354 +
  1.1355 +  // If next key message is not char message, we should give up to find a
  1.1356 +  // related char message for the handling keydown event for now.
  1.1357 +  // Note that it's possible other applications may send other key message
  1.1358 +  // after we call TranslateMessage(). That may cause PeekMessage() failing
  1.1359 +  // to get char message for the handling keydown message.
  1.1360 +  MSG nextKeyMsg;
  1.1361 +  if (!WinUtils::PeekMessage(&nextKeyMsg, mMsg.hwnd, WM_KEYFIRST, WM_KEYLAST,
  1.1362 +                             PM_NOREMOVE | PM_NOYIELD) ||
  1.1363 +      !IsCharMessage(nextKeyMsg)) {
  1.1364 +    return false;
  1.1365 +  }
  1.1366 +
  1.1367 +  // On Metrofox, PeekMessage() sometimes returns WM_NULL even if we specify
  1.1368 +  // the message range.  So, if it returns WM_NULL, we should retry to get
  1.1369 +  // the following char message it was found above.
  1.1370 +  for (uint32_t i = 0; i < 5; i++) {
  1.1371 +    MSG removedMsg, nextKeyMsgInAllWindows;
  1.1372 +    bool doCrash = false;
  1.1373 +    if (!WinUtils::PeekMessage(&removedMsg, mMsg.hwnd,
  1.1374 +                               nextKeyMsg.message, nextKeyMsg.message,
  1.1375 +                               PM_REMOVE | PM_NOYIELD)) {
  1.1376 +      // We meets unexpected case.  We should collect the message queue state
  1.1377 +      // and crash for reporting the bug.
  1.1378 +      doCrash = true;
  1.1379 +      // The char message is redirected to different thread's window by focus
  1.1380 +      // move or something or just cancelled by external application.
  1.1381 +      if (!WinUtils::PeekMessage(&nextKeyMsgInAllWindows, 0,
  1.1382 +                                 WM_KEYFIRST, WM_KEYLAST,
  1.1383 +                                 PM_NOREMOVE | PM_NOYIELD)) {
  1.1384 +        return true;
  1.1385 +      }
  1.1386 +      if (MayBeSameCharMessage(nextKeyMsgInAllWindows, nextKeyMsg)) {
  1.1387 +        // The char message is redirected to different window created by our
  1.1388 +        // thread.
  1.1389 +        if (nextKeyMsgInAllWindows.hwnd != mMsg.hwnd) {
  1.1390 +          aCharMsg = nextKeyMsgInAllWindows;
  1.1391 +          return true;
  1.1392 +        }
  1.1393 +        // The found char message still in the queue, but PeekMessage() failed
  1.1394 +        // to remove it only with PM_REMOVE.  Although, we don't know why this
  1.1395 +        // occurs.  However, this occurs acctually.
  1.1396 +        // Try to remove the char message with GetMessage() again.
  1.1397 +        if (WinUtils::GetMessage(&removedMsg, mMsg.hwnd,
  1.1398 +                                 nextKeyMsg.message, nextKeyMsg.message)) {
  1.1399 +          // Cancel to crash, but we need to check the removed message value.
  1.1400 +          doCrash = false;
  1.1401 +        }
  1.1402 +      }
  1.1403 +    }
  1.1404 +
  1.1405 +    if (doCrash) {
  1.1406 +#ifdef MOZ_CRASHREPORTER
  1.1407 +      nsPrintfCString info("\nPeekMessage() failed to remove char message! "
  1.1408 +                           "\nHandling message: %s (0x%08X), wParam: 0x%08X, "
  1.1409 +                           "lParam: 0x%08X, hwnd=0x%p, InSendMessageEx()=%s, \n"
  1.1410 +                           "Found message: %s (0x%08X), wParam: 0x%08X, "
  1.1411 +                           "lParam: 0x%08X, hwnd=0x%p, "
  1.1412 +                           "\nWM_NULL has been removed: %d, "
  1.1413 +                           "\nNext key message in all windows: %s (0x%08X), "
  1.1414 +                           "wParam: 0x%08X, lParam: 0x%08X, hwnd=0x%p, "
  1.1415 +                           "time=%d, ",
  1.1416 +                           GetMessageName(mMsg.message),
  1.1417 +                           mMsg.message, mMsg.wParam, mMsg.lParam,
  1.1418 +                           nextKeyMsg.hwnd,
  1.1419 +                           GetResultOfInSendMessageEx().get(),
  1.1420 +                           GetMessageName(nextKeyMsg.message),
  1.1421 +                           nextKeyMsg.message, nextKeyMsg.wParam,
  1.1422 +                           nextKeyMsg.lParam, nextKeyMsg.hwnd, i,
  1.1423 +                           GetMessageName(nextKeyMsgInAllWindows.message),
  1.1424 +                           nextKeyMsgInAllWindows.message,
  1.1425 +                           nextKeyMsgInAllWindows.wParam,
  1.1426 +                           nextKeyMsgInAllWindows.lParam,
  1.1427 +                           nextKeyMsgInAllWindows.hwnd,
  1.1428 +                           nextKeyMsgInAllWindows.time);
  1.1429 +      CrashReporter::AppendAppNotesToCrashReport(info);
  1.1430 +      MSG nextMsg;
  1.1431 +      if (WinUtils::PeekMessage(&nextMsg, 0, 0, 0,
  1.1432 +                                PM_NOREMOVE | PM_NOYIELD)) {
  1.1433 +        nsPrintfCString info("\nNext message in all windows: %s (0x%08X), "
  1.1434 +                             "wParam: 0x%08X, lParam: 0x%08X, hwnd=0x%p, "
  1.1435 +                             "time=%d",
  1.1436 +                             GetMessageName(nextMsg.message),
  1.1437 +                             nextMsg.message, nextMsg.wParam, nextMsg.lParam,
  1.1438 +                             nextMsg.hwnd, nextMsg.time);
  1.1439 +        CrashReporter::AppendAppNotesToCrashReport(info);
  1.1440 +      } else {
  1.1441 +        CrashReporter::AppendAppNotesToCrashReport(
  1.1442 +          NS_LITERAL_CSTRING("\nThere is no message in any window"));
  1.1443 +      }
  1.1444 +#endif // #ifdef MOZ_CRASHREPORTER
  1.1445 +      MOZ_CRASH("We lost the following char message");
  1.1446 +    }
  1.1447 +
  1.1448 +    // Retry for the strange case.
  1.1449 +    if (removedMsg.message == WM_NULL) {
  1.1450 +      continue;
  1.1451 +    }
  1.1452 +
  1.1453 +    // Typically, this case occurs with WM_DEADCHAR.  If the removed message's
  1.1454 +    // wParam becomes 0, that means that the key event shouldn't cause text
  1.1455 +    // input.  So, let's ignore the strange char message.
  1.1456 +    if (removedMsg.message == nextKeyMsg.message && !removedMsg.wParam) {
  1.1457 +      return false;
  1.1458 +    }
  1.1459 +
  1.1460 +    // NOTE: Although, we don't know when this case occurs, the scan code value
  1.1461 +    //       in lParam may be changed from 0 to something.  The changed value
  1.1462 +    //       is different from the scan code of handling keydown message.
  1.1463 +    if (!MayBeSameCharMessage(removedMsg, nextKeyMsg)) {
  1.1464 +#ifdef MOZ_CRASHREPORTER
  1.1465 +      nsPrintfCString info("\nPeekMessage() removed unexpcted char message! "
  1.1466 +                           "\nHandling message: %s (0x%08X), wParam: 0x%08X, "
  1.1467 +                           "lParam: 0x%08X, hwnd=0x%p, InSendMessageEx()=%s, "
  1.1468 +                           "\nFound message: %s (0x%08X), wParam: 0x%08X, "
  1.1469 +                           "lParam: 0x%08X, hwnd=0x%p, "
  1.1470 +                           "\nRemoved message: %s (0x%08X), wParam: 0x%08X, "
  1.1471 +                           "lParam: 0x%08X, hwnd=0x%p, ",
  1.1472 +                           GetMessageName(mMsg.message),
  1.1473 +                           mMsg.message, mMsg.wParam, mMsg.lParam, mMsg.hwnd,
  1.1474 +                           GetResultOfInSendMessageEx().get(),
  1.1475 +                           GetMessageName(nextKeyMsg.message),
  1.1476 +                           nextKeyMsg.message, nextKeyMsg.wParam,
  1.1477 +                           nextKeyMsg.lParam, nextKeyMsg.hwnd,
  1.1478 +                           GetMessageName(removedMsg.message),
  1.1479 +                           removedMsg.message, removedMsg.wParam,
  1.1480 +                           removedMsg.lParam, removedMsg.hwnd);
  1.1481 +      CrashReporter::AppendAppNotesToCrashReport(info);
  1.1482 +      // What's the next key message?
  1.1483 +      MSG nextKeyMsgAfter;
  1.1484 +      if (WinUtils::PeekMessage(&nextKeyMsgAfter, mMsg.hwnd,
  1.1485 +                                WM_KEYFIRST, WM_KEYLAST,
  1.1486 +                                PM_NOREMOVE | PM_NOYIELD)) {
  1.1487 +        nsPrintfCString info("\nNext key message after unexpected char message "
  1.1488 +                             "removed: %s (0x%08X), wParam: 0x%08X, "
  1.1489 +                             "lParam: 0x%08X, hwnd=0x%p, ",
  1.1490 +                             GetMessageName(nextKeyMsgAfter.message),
  1.1491 +                             nextKeyMsgAfter.message, nextKeyMsgAfter.wParam,
  1.1492 +                             nextKeyMsgAfter.lParam, nextKeyMsgAfter.hwnd);
  1.1493 +        CrashReporter::AppendAppNotesToCrashReport(info);
  1.1494 +      } else {
  1.1495 +        CrashReporter::AppendAppNotesToCrashReport(
  1.1496 +          NS_LITERAL_CSTRING("\nThere is no key message after unexpected char "
  1.1497 +                             "message removed, "));
  1.1498 +      }
  1.1499 +      // Another window has a key message?
  1.1500 +      MSG nextKeyMsgInAllWindows;
  1.1501 +      if (WinUtils::PeekMessage(&nextKeyMsgInAllWindows, 0,
  1.1502 +                                WM_KEYFIRST, WM_KEYLAST,
  1.1503 +                                PM_NOREMOVE | PM_NOYIELD)) {
  1.1504 +        nsPrintfCString info("\nNext key message in all windows: %s (0x%08X), "
  1.1505 +                             "wParam: 0x%08X, lParam: 0x%08X, hwnd=0x%p.",
  1.1506 +                             GetMessageName(nextKeyMsgInAllWindows.message),
  1.1507 +                             nextKeyMsgInAllWindows.message,
  1.1508 +                             nextKeyMsgInAllWindows.wParam,
  1.1509 +                             nextKeyMsgInAllWindows.lParam,
  1.1510 +                             nextKeyMsgInAllWindows.hwnd);
  1.1511 +        CrashReporter::AppendAppNotesToCrashReport(info);
  1.1512 +      } else {
  1.1513 +        CrashReporter::AppendAppNotesToCrashReport(
  1.1514 +          NS_LITERAL_CSTRING("\nThere is no key message in any windows."));
  1.1515 +      }
  1.1516 +#endif // #ifdef MOZ_CRASHREPORTER
  1.1517 +      MOZ_CRASH("PeekMessage() removed unexpected message");
  1.1518 +    }
  1.1519 +
  1.1520 +    aCharMsg = removedMsg;
  1.1521 +    return true;
  1.1522 +  }
  1.1523 +#ifdef MOZ_CRASHREPORTER
  1.1524 +  nsPrintfCString info("\nWe lost following char message! "
  1.1525 +                       "\nHandling message: %s (0x%08X), wParam: 0x%08X, "
  1.1526 +                       "lParam: 0x%08X, InSendMessageEx()=%s, \n"
  1.1527 +                       "Found message: %s (0x%08X), wParam: 0x%08X, "
  1.1528 +                       "lParam: 0x%08X, removed a lot of WM_NULL",
  1.1529 +                       GetMessageName(mMsg.message),
  1.1530 +                       mMsg.message, mMsg.wParam, mMsg.lParam,
  1.1531 +                       GetResultOfInSendMessageEx().get(),
  1.1532 +                       GetMessageName(nextKeyMsg.message),
  1.1533 +                       nextKeyMsg.message, nextKeyMsg.wParam,
  1.1534 +                       nextKeyMsg.lParam);
  1.1535 +  CrashReporter::AppendAppNotesToCrashReport(info);
  1.1536 +#endif // #ifdef MOZ_CRASHREPORTER
  1.1537 +  MOZ_CRASH("We lost the following char message");
  1.1538 +  return false;
  1.1539 +}
  1.1540 +
  1.1541 +bool
  1.1542 +NativeKey::DispatchPluginEventsAndDiscardsCharMessages() const
  1.1543 +{
  1.1544 +  MOZ_ASSERT(IsKeyDownMessage());
  1.1545 +
  1.1546 +  // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
  1.1547 +  // They can be more than one because of:
  1.1548 +  //  * Dead-keys not pairing with base character
  1.1549 +  //  * Some keyboard layouts may map up to 4 characters to the single key
  1.1550 +  bool anyCharMessagesRemoved = false;
  1.1551 +  MSG msg;
  1.1552 +  while (GetFollowingCharMessage(msg)) {
  1.1553 +    if (msg.message == WM_NULL) {
  1.1554 +      continue;
  1.1555 +    }
  1.1556 +    anyCharMessagesRemoved = true;
  1.1557 +    // If the window handle is changed, focused window must be changed.
  1.1558 +    // So, plugin shouldn't handle it anymore.
  1.1559 +    if (msg.hwnd != mMsg.hwnd) {
  1.1560 +      break;
  1.1561 +    }
  1.1562 +    MOZ_RELEASE_ASSERT(!mWidget->Destroyed(),
  1.1563 +      "NativeKey tries to dispatch a plugin event on destroyed widget");
  1.1564 +    mWidget->DispatchPluginEvent(msg);
  1.1565 +    if (mWidget->Destroyed()) {
  1.1566 +      return true;
  1.1567 +    }
  1.1568 +  }
  1.1569 +
  1.1570 +  if (!mFakeCharMsgs && !anyCharMessagesRemoved &&
  1.1571 +      mDOMKeyCode == NS_VK_BACK && IsIMEDoingKakuteiUndo()) {
  1.1572 +    // This is for a hack for ATOK and WXG.  So, PeekMessage() must scceed!
  1.1573 +    while (WinUtils::PeekMessage(&msg, mMsg.hwnd, WM_CHAR, WM_CHAR,
  1.1574 +                                 PM_REMOVE | PM_NOYIELD)) {
  1.1575 +      if (msg.message != WM_CHAR) {
  1.1576 +        MOZ_RELEASE_ASSERT(msg.message == WM_NULL,
  1.1577 +                           "Unexpected message was removed");
  1.1578 +        continue;
  1.1579 +      }
  1.1580 +      MOZ_RELEASE_ASSERT(!mWidget->Destroyed(),
  1.1581 +        "NativeKey tries to dispatch a plugin event on destroyed widget");
  1.1582 +      mWidget->DispatchPluginEvent(msg);
  1.1583 +      return mWidget->Destroyed();
  1.1584 +    }
  1.1585 +    MOZ_CRASH("NativeKey failed to get WM_CHAR for ATOK or WXG");
  1.1586 +  }
  1.1587 +
  1.1588 +  return false;
  1.1589 +}
  1.1590 +
  1.1591 +bool
  1.1592 +NativeKey::DispatchKeyPressEventsWithKeyboardLayout() const
  1.1593 +{
  1.1594 +  MOZ_ASSERT(IsKeyDownMessage());
  1.1595 +  MOZ_ASSERT(!mIsDeadKey);
  1.1596 +
  1.1597 +  KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
  1.1598 +
  1.1599 +  UniCharsAndModifiers inputtingChars(mCommittedCharsAndModifiers);
  1.1600 +  UniCharsAndModifiers shiftedChars;
  1.1601 +  UniCharsAndModifiers unshiftedChars;
  1.1602 +  uint32_t shiftedLatinChar = 0;
  1.1603 +  uint32_t unshiftedLatinChar = 0;
  1.1604 +
  1.1605 +  if (!KeyboardLayout::IsPrintableCharKey(mVirtualKeyCode)) {
  1.1606 +    inputtingChars.Clear();
  1.1607 +  }
  1.1608 +
  1.1609 +  if (mModKeyState.IsControl() ^ mModKeyState.IsAlt()) {
  1.1610 +    ModifierKeyState capsLockState(
  1.1611 +                       mModKeyState.GetModifiers() & MODIFIER_CAPSLOCK);
  1.1612 +
  1.1613 +    unshiftedChars =
  1.1614 +      keyboardLayout->GetUniCharsAndModifiers(mVirtualKeyCode, capsLockState);
  1.1615 +    capsLockState.Set(MODIFIER_SHIFT);
  1.1616 +    shiftedChars =
  1.1617 +      keyboardLayout->GetUniCharsAndModifiers(mVirtualKeyCode, capsLockState);
  1.1618 +
  1.1619 +    // The current keyboard cannot input alphabets or numerics,
  1.1620 +    // we should append them for Shortcut/Access keys.
  1.1621 +    // E.g., for Cyrillic keyboard layout.
  1.1622 +    capsLockState.Unset(MODIFIER_SHIFT);
  1.1623 +    WidgetUtils::GetLatinCharCodeForKeyCode(mDOMKeyCode,
  1.1624 +                                            capsLockState.GetModifiers(),
  1.1625 +                                            &unshiftedLatinChar,
  1.1626 +                                            &shiftedLatinChar);
  1.1627 +
  1.1628 +    // If the shiftedLatinChar isn't 0, the key code is NS_VK_[A-Z].
  1.1629 +    if (shiftedLatinChar) {
  1.1630 +      // If the produced characters of the key on current keyboard layout
  1.1631 +      // are same as computed Latin characters, we shouldn't append the
  1.1632 +      // Latin characters to alternativeCharCode.
  1.1633 +      if (unshiftedLatinChar == unshiftedChars.mChars[0] &&
  1.1634 +          shiftedLatinChar == shiftedChars.mChars[0]) {
  1.1635 +        shiftedLatinChar = unshiftedLatinChar = 0;
  1.1636 +      }
  1.1637 +    } else if (unshiftedLatinChar) {
  1.1638 +      // If the shiftedLatinChar is 0, the keyCode doesn't produce
  1.1639 +      // alphabet character.  At that time, the character may be produced
  1.1640 +      // with Shift key.  E.g., on French keyboard layout, NS_VK_PERCENT
  1.1641 +      // key produces LATIN SMALL LETTER U WITH GRAVE (U+00F9) without
  1.1642 +      // Shift key but with Shift key, it produces '%'.
  1.1643 +      // If the unshiftedLatinChar is produced by the key on current
  1.1644 +      // keyboard layout, we shouldn't append it to alternativeCharCode.
  1.1645 +      if (unshiftedLatinChar == unshiftedChars.mChars[0] ||
  1.1646 +          unshiftedLatinChar == shiftedChars.mChars[0]) {
  1.1647 +        unshiftedLatinChar = 0;
  1.1648 +      }
  1.1649 +    }
  1.1650 +
  1.1651 +    // If the charCode is not ASCII character, we should replace the
  1.1652 +    // charCode with ASCII character only when Ctrl is pressed.
  1.1653 +    // But don't replace the charCode when the charCode is not same as
  1.1654 +    // unmodified characters. In such case, Ctrl is sometimes used for a
  1.1655 +    // part of character inputting key combination like Shift.
  1.1656 +    if (mModKeyState.IsControl()) {
  1.1657 +      uint32_t ch =
  1.1658 +        mModKeyState.IsShift() ? shiftedLatinChar : unshiftedLatinChar;
  1.1659 +      if (ch &&
  1.1660 +          (!inputtingChars.mLength ||
  1.1661 +           inputtingChars.UniCharsCaseInsensitiveEqual(
  1.1662 +             mModKeyState.IsShift() ? shiftedChars : unshiftedChars))) {
  1.1663 +        inputtingChars.Clear();
  1.1664 +        inputtingChars.Append(ch, mModKeyState.GetModifiers());
  1.1665 +      }
  1.1666 +    }
  1.1667 +  }
  1.1668 +
  1.1669 +  if (inputtingChars.IsEmpty() &&
  1.1670 +      shiftedChars.IsEmpty() && unshiftedChars.IsEmpty()) {
  1.1671 +    WidgetKeyboardEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
  1.1672 +    keypressEvent.keyCode = mDOMKeyCode;
  1.1673 +    InitKeyEvent(keypressEvent, mModKeyState);
  1.1674 +    return DispatchKeyEvent(keypressEvent);
  1.1675 +  }
  1.1676 +
  1.1677 +  uint32_t longestLength =
  1.1678 +    std::max(inputtingChars.mLength,
  1.1679 +             std::max(shiftedChars.mLength, unshiftedChars.mLength));
  1.1680 +  uint32_t skipUniChars = longestLength - inputtingChars.mLength;
  1.1681 +  uint32_t skipShiftedChars = longestLength - shiftedChars.mLength;
  1.1682 +  uint32_t skipUnshiftedChars = longestLength - unshiftedChars.mLength;
  1.1683 +  UINT keyCode = !inputtingChars.mLength ? mDOMKeyCode : 0;
  1.1684 +  bool defaultPrevented = false;
  1.1685 +  for (uint32_t cnt = 0; cnt < longestLength; cnt++) {
  1.1686 +    uint16_t uniChar, shiftedChar, unshiftedChar;
  1.1687 +    uniChar = shiftedChar = unshiftedChar = 0;
  1.1688 +    ModifierKeyState modKeyState(mModKeyState);
  1.1689 +    if (skipUniChars <= cnt) {
  1.1690 +      if (cnt - skipUniChars  < inputtingChars.mLength) {
  1.1691 +        // If key in combination with Alt and/or Ctrl produces a different
  1.1692 +        // character than without them then do not report these flags
  1.1693 +        // because it is separate keyboard layout shift state. If dead-key
  1.1694 +        // and base character does not produce a valid composite character
  1.1695 +        // then both produced dead-key character and following base
  1.1696 +        // character may have different modifier flags, too.
  1.1697 +        modKeyState.Unset(MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT |
  1.1698 +                          MODIFIER_ALTGRAPH | MODIFIER_CAPSLOCK);
  1.1699 +        modKeyState.Set(inputtingChars.mModifiers[cnt - skipUniChars]);
  1.1700 +      }
  1.1701 +      uniChar = inputtingChars.mChars[cnt - skipUniChars];
  1.1702 +    }
  1.1703 +    if (skipShiftedChars <= cnt)
  1.1704 +      shiftedChar = shiftedChars.mChars[cnt - skipShiftedChars];
  1.1705 +    if (skipUnshiftedChars <= cnt)
  1.1706 +      unshiftedChar = unshiftedChars.mChars[cnt - skipUnshiftedChars];
  1.1707 +    nsAutoTArray<AlternativeCharCode, 5> altArray;
  1.1708 +
  1.1709 +    if (shiftedChar || unshiftedChar) {
  1.1710 +      AlternativeCharCode chars(unshiftedChar, shiftedChar);
  1.1711 +      altArray.AppendElement(chars);
  1.1712 +    }
  1.1713 +    if (cnt == longestLength - 1) {
  1.1714 +      if (unshiftedLatinChar || shiftedLatinChar) {
  1.1715 +        AlternativeCharCode chars(unshiftedLatinChar, shiftedLatinChar);
  1.1716 +        altArray.AppendElement(chars);
  1.1717 +      }
  1.1718 +
  1.1719 +      // Typically, following virtual keycodes are used for a key which can
  1.1720 +      // input the character.  However, these keycodes are also used for
  1.1721 +      // other keys on some keyboard layout.  E.g., in spite of Shift+'1'
  1.1722 +      // inputs '+' on Thai keyboard layout, a key which is at '=/+'
  1.1723 +      // key on ANSI keyboard layout is VK_OEM_PLUS.  Native applications
  1.1724 +      // handle it as '+' key if Ctrl key is pressed.
  1.1725 +      char16_t charForOEMKeyCode = 0;
  1.1726 +      switch (mVirtualKeyCode) {
  1.1727 +        case VK_OEM_PLUS:   charForOEMKeyCode = '+'; break;
  1.1728 +        case VK_OEM_COMMA:  charForOEMKeyCode = ','; break;
  1.1729 +        case VK_OEM_MINUS:  charForOEMKeyCode = '-'; break;
  1.1730 +        case VK_OEM_PERIOD: charForOEMKeyCode = '.'; break;
  1.1731 +      }
  1.1732 +      if (charForOEMKeyCode &&
  1.1733 +          charForOEMKeyCode != unshiftedChars.mChars[0] &&
  1.1734 +          charForOEMKeyCode != shiftedChars.mChars[0] &&
  1.1735 +          charForOEMKeyCode != unshiftedLatinChar &&
  1.1736 +          charForOEMKeyCode != shiftedLatinChar) {
  1.1737 +        AlternativeCharCode OEMChars(charForOEMKeyCode, charForOEMKeyCode);
  1.1738 +        altArray.AppendElement(OEMChars);
  1.1739 +      }
  1.1740 +    }
  1.1741 +
  1.1742 +    WidgetKeyboardEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
  1.1743 +    keypressEvent.charCode = uniChar;
  1.1744 +    keypressEvent.alternativeCharCodes.AppendElements(altArray);
  1.1745 +    InitKeyEvent(keypressEvent, modKeyState);
  1.1746 +    defaultPrevented = (DispatchKeyEvent(keypressEvent) || defaultPrevented);
  1.1747 +    if (mWidget->Destroyed()) {
  1.1748 +      return true;
  1.1749 +    }
  1.1750 +  }
  1.1751 +
  1.1752 +  return defaultPrevented;
  1.1753 +}
  1.1754 +
  1.1755 +bool
  1.1756 +NativeKey::DispatchKeyPressEventForFollowingCharMessage(
  1.1757 +             const MSG& aCharMsg) const
  1.1758 +{
  1.1759 +  MOZ_ASSERT(IsKeyDownMessage());
  1.1760 +
  1.1761 +  if (mFakeCharMsgs) {
  1.1762 +    if (IsDeadCharMessage(aCharMsg)) {
  1.1763 +      return false;
  1.1764 +    }
  1.1765 +#ifdef DEBUG
  1.1766 +    if (mIsPrintableKey) {
  1.1767 +      nsPrintfCString log(
  1.1768 +        "mOriginalVirtualKeyCode=0x%02X, mCommittedCharsAndModifiers={ "
  1.1769 +        "mChars=[ 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X ], mLength=%d }, "
  1.1770 +        "wParam=0x%04X",
  1.1771 +        mOriginalVirtualKeyCode, mCommittedCharsAndModifiers.mChars[0],
  1.1772 +        mCommittedCharsAndModifiers.mChars[1],
  1.1773 +        mCommittedCharsAndModifiers.mChars[2],
  1.1774 +        mCommittedCharsAndModifiers.mChars[3],
  1.1775 +        mCommittedCharsAndModifiers.mChars[4],
  1.1776 +        mCommittedCharsAndModifiers.mLength, aCharMsg.wParam);
  1.1777 +      if (mCommittedCharsAndModifiers.IsEmpty()) {
  1.1778 +        log.Insert("length is zero: ", 0);
  1.1779 +        NS_ERROR(log.get());
  1.1780 +        NS_ABORT();
  1.1781 +      } else if (mCommittedCharsAndModifiers.mChars[0] != aCharMsg.wParam) {
  1.1782 +        log.Insert("character mismatch: ", 0);
  1.1783 +        NS_ERROR(log.get());
  1.1784 +        NS_ABORT();
  1.1785 +      }
  1.1786 +    }
  1.1787 +#endif // #ifdef DEBUG
  1.1788 +    return HandleCharMessage(aCharMsg);
  1.1789 +  }
  1.1790 +
  1.1791 +  if (IsDeadCharMessage(aCharMsg)) {
  1.1792 +    if (!mWidget->PluginHasFocus()) {
  1.1793 +      return false;
  1.1794 +    }
  1.1795 +    return (mWidget->DispatchPluginEvent(aCharMsg) || mWidget->Destroyed());
  1.1796 +  }
  1.1797 +
  1.1798 +  bool defaultPrevented = HandleCharMessage(aCharMsg);
  1.1799 +  // If a syschar keypress wasn't processed, Windows may want to
  1.1800 +  // handle it to activate a native menu.
  1.1801 +  if (!defaultPrevented && IsSysCharMessage(aCharMsg)) {
  1.1802 +    ::DefWindowProcW(aCharMsg.hwnd, aCharMsg.message,
  1.1803 +                     aCharMsg.wParam, aCharMsg.lParam);
  1.1804 +  }
  1.1805 +  return defaultPrevented;
  1.1806 +}
  1.1807 +
  1.1808 +/*****************************************************************************
  1.1809 + * mozilla::widget::KeyboardLayout
  1.1810 + *****************************************************************************/
  1.1811 +
  1.1812 +KeyboardLayout* KeyboardLayout::sInstance = nullptr;
  1.1813 +nsIIdleServiceInternal* KeyboardLayout::sIdleService = nullptr;
  1.1814 +
  1.1815 +// static
  1.1816 +KeyboardLayout*
  1.1817 +KeyboardLayout::GetInstance()
  1.1818 +{
  1.1819 +  if (!sInstance) {
  1.1820 +    sInstance = new KeyboardLayout();
  1.1821 +    nsCOMPtr<nsIIdleServiceInternal> idleService =
  1.1822 +      do_GetService("@mozilla.org/widget/idleservice;1");
  1.1823 +    // The refcount will be decreased at shut down.
  1.1824 +    sIdleService = idleService.forget().take();
  1.1825 +  }
  1.1826 +  return sInstance;
  1.1827 +}
  1.1828 +
  1.1829 +// static
  1.1830 +void
  1.1831 +KeyboardLayout::Shutdown()
  1.1832 +{
  1.1833 +  delete sInstance;
  1.1834 +  sInstance = nullptr;
  1.1835 +  NS_IF_RELEASE(sIdleService);
  1.1836 +}
  1.1837 +
  1.1838 +// static
  1.1839 +void
  1.1840 +KeyboardLayout::NotifyIdleServiceOfUserActivity()
  1.1841 +{
  1.1842 +  sIdleService->ResetIdleTimeOut(0);
  1.1843 +}
  1.1844 +
  1.1845 +KeyboardLayout::KeyboardLayout() :
  1.1846 +  mKeyboardLayout(0), mIsOverridden(false),
  1.1847 +  mIsPendingToRestoreKeyboardLayout(false)
  1.1848 +{
  1.1849 +  mDeadKeyTableListHead = nullptr;
  1.1850 +
  1.1851 +  // NOTE: LoadLayout() should be called via OnLayoutChange().
  1.1852 +}
  1.1853 +
  1.1854 +KeyboardLayout::~KeyboardLayout()
  1.1855 +{
  1.1856 +  ReleaseDeadKeyTables();
  1.1857 +}
  1.1858 +
  1.1859 +bool
  1.1860 +KeyboardLayout::IsPrintableCharKey(uint8_t aVirtualKey)
  1.1861 +{
  1.1862 +  return GetKeyIndex(aVirtualKey) >= 0;
  1.1863 +}
  1.1864 +
  1.1865 +WORD
  1.1866 +KeyboardLayout::ComputeScanCodeForVirtualKeyCode(uint8_t aVirtualKeyCode) const
  1.1867 +{
  1.1868 +  return static_cast<WORD>(
  1.1869 +           ::MapVirtualKeyEx(aVirtualKeyCode, MAPVK_VK_TO_VSC, GetLayout()));
  1.1870 +}
  1.1871 +
  1.1872 +bool
  1.1873 +KeyboardLayout::IsDeadKey(uint8_t aVirtualKey,
  1.1874 +                          const ModifierKeyState& aModKeyState) const
  1.1875 +{
  1.1876 +  int32_t virtualKeyIndex = GetKeyIndex(aVirtualKey);
  1.1877 +  if (virtualKeyIndex < 0) {
  1.1878 +    return false;
  1.1879 +  }
  1.1880 +
  1.1881 +  return mVirtualKeys[virtualKeyIndex].IsDeadKey(
  1.1882 +           VirtualKey::ModifiersToShiftState(aModKeyState.GetModifiers()));
  1.1883 +}
  1.1884 +
  1.1885 +void
  1.1886 +KeyboardLayout::InitNativeKey(NativeKey& aNativeKey,
  1.1887 +                              const ModifierKeyState& aModKeyState)
  1.1888 +{
  1.1889 +  if (mIsPendingToRestoreKeyboardLayout) {
  1.1890 +    LoadLayout(::GetKeyboardLayout(0));
  1.1891 +  }
  1.1892 +
  1.1893 +  uint8_t virtualKey = aNativeKey.mOriginalVirtualKeyCode;
  1.1894 +  int32_t virtualKeyIndex = GetKeyIndex(virtualKey);
  1.1895 +
  1.1896 +  if (virtualKeyIndex < 0) {
  1.1897 +    // Does not produce any printable characters, but still preserves the
  1.1898 +    // dead-key state.
  1.1899 +    return;
  1.1900 +  }
  1.1901 +
  1.1902 +  MOZ_ASSERT(aNativeKey.mKeyNameIndex == KEY_NAME_INDEX_USE_STRING,
  1.1903 +    "Printable key's key name index must be KEY_NAME_INDEX_USE_STRING");
  1.1904 +
  1.1905 +  bool isKeyDown = aNativeKey.IsKeyDownMessage();
  1.1906 +  uint8_t shiftState =
  1.1907 +    VirtualKey::ModifiersToShiftState(aModKeyState.GetModifiers());
  1.1908 +
  1.1909 +  if (mVirtualKeys[virtualKeyIndex].IsDeadKey(shiftState)) {
  1.1910 +    if ((isKeyDown && mActiveDeadKey < 0) ||
  1.1911 +        (!isKeyDown && mActiveDeadKey == virtualKey)) {
  1.1912 +      //  First dead key event doesn't generate characters.
  1.1913 +      if (isKeyDown) {
  1.1914 +        // Dead-key state activated at keydown.
  1.1915 +        mActiveDeadKey = virtualKey;
  1.1916 +        mDeadKeyShiftState = shiftState;
  1.1917 +      }
  1.1918 +      UniCharsAndModifiers deadChars =
  1.1919 +        mVirtualKeys[virtualKeyIndex].GetNativeUniChars(shiftState);
  1.1920 +      NS_ASSERTION(deadChars.mLength == 1,
  1.1921 +                   "dead key must generate only one character");
  1.1922 +      aNativeKey.mKeyNameIndex =
  1.1923 +        WidgetUtils::GetDeadKeyNameIndex(deadChars.mChars[0]);
  1.1924 +      return;
  1.1925 +    }
  1.1926 +
  1.1927 +    // Dead key followed by another dead key causes inputting both character.
  1.1928 +    // However, at keydown message handling, we need to forget the first
  1.1929 +    // dead key because there is no guarantee coming WM_KEYUP for the second
  1.1930 +    // dead key before next WM_KEYDOWN.  E.g., due to auto key repeat or
  1.1931 +    // pressing another dead key before releasing current key.  Therefore,
  1.1932 +    // we can set only a character for current key for keyup event.
  1.1933 +    if (mActiveDeadKey < 0) {
  1.1934 +      aNativeKey.mCommittedCharsAndModifiers =
  1.1935 +        mVirtualKeys[virtualKeyIndex].GetUniChars(shiftState);
  1.1936 +      return;
  1.1937 +    }
  1.1938 +
  1.1939 +    int32_t activeDeadKeyIndex = GetKeyIndex(mActiveDeadKey);
  1.1940 +    if (activeDeadKeyIndex < 0 || activeDeadKeyIndex >= NS_NUM_OF_KEYS) {
  1.1941 +#if defined(DEBUG) || defined(MOZ_CRASHREPORTER)
  1.1942 +      nsPrintfCString warning("The virtual key index (%d) of mActiveDeadKey "
  1.1943 +                              "(0x%02X) is not a printable key (virtualKey="
  1.1944 +                              "0x%02X)",
  1.1945 +                              activeDeadKeyIndex, mActiveDeadKey, virtualKey);
  1.1946 +      NS_WARNING(warning.get());
  1.1947 +#ifdef MOZ_CRASHREPORTER
  1.1948 +      CrashReporter::AppendAppNotesToCrashReport(
  1.1949 +                       NS_LITERAL_CSTRING("\n") + warning);
  1.1950 +#endif // #ifdef MOZ_CRASHREPORTER
  1.1951 +#endif // #if defined(DEBUG) || defined(MOZ_CRASHREPORTER)
  1.1952 +      MOZ_CRASH("Trying to reference out of range of mVirtualKeys");
  1.1953 +    }
  1.1954 +    UniCharsAndModifiers prevDeadChars =
  1.1955 +      mVirtualKeys[activeDeadKeyIndex].GetUniChars(mDeadKeyShiftState);
  1.1956 +    UniCharsAndModifiers newChars =
  1.1957 +      mVirtualKeys[virtualKeyIndex].GetUniChars(shiftState);
  1.1958 +    // But keypress events should be fired for each committed character.
  1.1959 +    aNativeKey.mCommittedCharsAndModifiers = prevDeadChars + newChars;
  1.1960 +    if (isKeyDown) {
  1.1961 +      DeactivateDeadKeyState();
  1.1962 +    }
  1.1963 +    return;
  1.1964 +  }
  1.1965 +
  1.1966 +  UniCharsAndModifiers baseChars =
  1.1967 +    mVirtualKeys[virtualKeyIndex].GetUniChars(shiftState);
  1.1968 +  if (mActiveDeadKey < 0) {
  1.1969 +    // No dead-keys are active. Just return the produced characters.
  1.1970 +    aNativeKey.mCommittedCharsAndModifiers = baseChars;
  1.1971 +    return;
  1.1972 +  }
  1.1973 +
  1.1974 +  // Dead-key was active. See if pressed base character does produce
  1.1975 +  // valid composite character.
  1.1976 +  int32_t activeDeadKeyIndex = GetKeyIndex(mActiveDeadKey);
  1.1977 +  char16_t compositeChar = (baseChars.mLength == 1 && baseChars.mChars[0]) ?
  1.1978 +    mVirtualKeys[activeDeadKeyIndex].GetCompositeChar(mDeadKeyShiftState,
  1.1979 +                                                      baseChars.mChars[0]) : 0;
  1.1980 +  if (compositeChar) {
  1.1981 +    // Active dead-key and base character does produce exactly one
  1.1982 +    // composite character.
  1.1983 +    aNativeKey.mCommittedCharsAndModifiers.Append(compositeChar,
  1.1984 +                                                  baseChars.mModifiers[0]);
  1.1985 +    if (isKeyDown) {
  1.1986 +      DeactivateDeadKeyState();
  1.1987 +    }
  1.1988 +    return;
  1.1989 +  }
  1.1990 +
  1.1991 +  // There is no valid dead-key and base character combination.
  1.1992 +  // Return dead-key character followed by base character.
  1.1993 +  UniCharsAndModifiers deadChars =
  1.1994 +    mVirtualKeys[activeDeadKeyIndex].GetUniChars(mDeadKeyShiftState);
  1.1995 +  // But keypress events should be fired for each committed character.
  1.1996 +  aNativeKey.mCommittedCharsAndModifiers = deadChars + baseChars;
  1.1997 +  if (isKeyDown) {
  1.1998 +    DeactivateDeadKeyState();
  1.1999 +  }
  1.2000 +
  1.2001 +  return;
  1.2002 +}
  1.2003 +
  1.2004 +UniCharsAndModifiers
  1.2005 +KeyboardLayout::GetUniCharsAndModifiers(
  1.2006 +                  uint8_t aVirtualKey,
  1.2007 +                  const ModifierKeyState& aModKeyState) const
  1.2008 +{
  1.2009 +  UniCharsAndModifiers result;
  1.2010 +  int32_t key = GetKeyIndex(aVirtualKey);
  1.2011 +  if (key < 0) {
  1.2012 +    return result;
  1.2013 +  }
  1.2014 +  return mVirtualKeys[key].
  1.2015 +    GetUniChars(VirtualKey::ModifiersToShiftState(aModKeyState.GetModifiers()));
  1.2016 +}
  1.2017 +
  1.2018 +void
  1.2019 +KeyboardLayout::LoadLayout(HKL aLayout)
  1.2020 +{
  1.2021 +  mIsPendingToRestoreKeyboardLayout = false;
  1.2022 +
  1.2023 +  if (mKeyboardLayout == aLayout) {
  1.2024 +    return;
  1.2025 +  }
  1.2026 +
  1.2027 +  mKeyboardLayout = aLayout;
  1.2028 +
  1.2029 +  BYTE kbdState[256];
  1.2030 +  memset(kbdState, 0, sizeof(kbdState));
  1.2031 +
  1.2032 +  BYTE originalKbdState[256];
  1.2033 +  // Bitfield with all shift states that have at least one dead-key.
  1.2034 +  uint16_t shiftStatesWithDeadKeys = 0;
  1.2035 +  // Bitfield with all shift states that produce any possible dead-key base
  1.2036 +  // characters.
  1.2037 +  uint16_t shiftStatesWithBaseChars = 0;
  1.2038 +
  1.2039 +  mActiveDeadKey = -1;
  1.2040 +
  1.2041 +  ReleaseDeadKeyTables();
  1.2042 +
  1.2043 +  ::GetKeyboardState(originalKbdState);
  1.2044 +
  1.2045 +  // For each shift state gather all printable characters that are produced
  1.2046 +  // for normal case when no any dead-key is active.
  1.2047 +
  1.2048 +  for (VirtualKey::ShiftState shiftState = 0; shiftState < 16; shiftState++) {
  1.2049 +    VirtualKey::FillKbdState(kbdState, shiftState);
  1.2050 +    for (uint32_t virtualKey = 0; virtualKey < 256; virtualKey++) {
  1.2051 +      int32_t vki = GetKeyIndex(virtualKey);
  1.2052 +      if (vki < 0) {
  1.2053 +        continue;
  1.2054 +      }
  1.2055 +      NS_ASSERTION(uint32_t(vki) < ArrayLength(mVirtualKeys), "invalid index");
  1.2056 +      char16_t uniChars[5];
  1.2057 +      int32_t ret =
  1.2058 +        ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)uniChars,
  1.2059 +                      ArrayLength(uniChars), 0, mKeyboardLayout);
  1.2060 +      // dead-key
  1.2061 +      if (ret < 0) {
  1.2062 +        shiftStatesWithDeadKeys |= (1 << shiftState);
  1.2063 +        // Repeat dead-key to deactivate it and get its character
  1.2064 +        // representation.
  1.2065 +        char16_t deadChar[2];
  1.2066 +        ret = ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)deadChar,
  1.2067 +                            ArrayLength(deadChar), 0, mKeyboardLayout);
  1.2068 +        NS_ASSERTION(ret == 2, "Expecting twice repeated dead-key character");
  1.2069 +        mVirtualKeys[vki].SetDeadChar(shiftState, deadChar[0]);
  1.2070 +      } else {
  1.2071 +        if (ret == 1) {
  1.2072 +          // dead-key can pair only with exactly one base character.
  1.2073 +          shiftStatesWithBaseChars |= (1 << shiftState);
  1.2074 +        }
  1.2075 +        mVirtualKeys[vki].SetNormalChars(shiftState, uniChars, ret);
  1.2076 +      }
  1.2077 +    }
  1.2078 +  }
  1.2079 +
  1.2080 +  // Now process each dead-key to find all its base characters and resulting
  1.2081 +  // composite characters.
  1.2082 +  for (VirtualKey::ShiftState shiftState = 0; shiftState < 16; shiftState++) {
  1.2083 +    if (!(shiftStatesWithDeadKeys & (1 << shiftState))) {
  1.2084 +      continue;
  1.2085 +    }
  1.2086 +
  1.2087 +    VirtualKey::FillKbdState(kbdState, shiftState);
  1.2088 +
  1.2089 +    for (uint32_t virtualKey = 0; virtualKey < 256; virtualKey++) {
  1.2090 +      int32_t vki = GetKeyIndex(virtualKey);
  1.2091 +      if (vki >= 0 && mVirtualKeys[vki].IsDeadKey(shiftState)) {
  1.2092 +        DeadKeyEntry deadKeyArray[256];
  1.2093 +        int32_t n = GetDeadKeyCombinations(virtualKey, kbdState,
  1.2094 +                                           shiftStatesWithBaseChars,
  1.2095 +                                           deadKeyArray,
  1.2096 +                                           ArrayLength(deadKeyArray));
  1.2097 +        const DeadKeyTable* dkt =
  1.2098 +          mVirtualKeys[vki].MatchingDeadKeyTable(deadKeyArray, n);
  1.2099 +        if (!dkt) {
  1.2100 +          dkt = AddDeadKeyTable(deadKeyArray, n);
  1.2101 +        }
  1.2102 +        mVirtualKeys[vki].AttachDeadKeyTable(shiftState, dkt);
  1.2103 +      }
  1.2104 +    }
  1.2105 +  }
  1.2106 +
  1.2107 +  ::SetKeyboardState(originalKbdState);
  1.2108 +}
  1.2109 +
  1.2110 +inline int32_t
  1.2111 +KeyboardLayout::GetKeyIndex(uint8_t aVirtualKey)
  1.2112 +{
  1.2113 +// Currently these 68 (NS_NUM_OF_KEYS) virtual keys are assumed
  1.2114 +// to produce visible representation:
  1.2115 +// 0x20 - VK_SPACE          ' '
  1.2116 +// 0x30..0x39               '0'..'9'
  1.2117 +// 0x41..0x5A               'A'..'Z'
  1.2118 +// 0x60..0x69               '0'..'9' on numpad
  1.2119 +// 0x6A - VK_MULTIPLY       '*' on numpad
  1.2120 +// 0x6B - VK_ADD            '+' on numpad
  1.2121 +// 0x6D - VK_SUBTRACT       '-' on numpad
  1.2122 +// 0x6E - VK_DECIMAL        '.' on numpad
  1.2123 +// 0x6F - VK_DIVIDE         '/' on numpad
  1.2124 +// 0x6E - VK_DECIMAL        '.'
  1.2125 +// 0xBA - VK_OEM_1          ';:' for US
  1.2126 +// 0xBB - VK_OEM_PLUS       '+' any country
  1.2127 +// 0xBC - VK_OEM_COMMA      ',' any country
  1.2128 +// 0xBD - VK_OEM_MINUS      '-' any country
  1.2129 +// 0xBE - VK_OEM_PERIOD     '.' any country
  1.2130 +// 0xBF - VK_OEM_2          '/?' for US
  1.2131 +// 0xC0 - VK_OEM_3          '`~' for US
  1.2132 +// 0xC1 - VK_ABNT_C1        '/?' for Brazilian
  1.2133 +// 0xC2 - VK_ABNT_C2        separator key on numpad (Brazilian or JIS for Mac)
  1.2134 +// 0xDB - VK_OEM_4          '[{' for US
  1.2135 +// 0xDC - VK_OEM_5          '\|' for US
  1.2136 +// 0xDD - VK_OEM_6          ']}' for US
  1.2137 +// 0xDE - VK_OEM_7          ''"' for US
  1.2138 +// 0xDF - VK_OEM_8
  1.2139 +// 0xE1 - no name
  1.2140 +// 0xE2 - VK_OEM_102        '\_' for JIS
  1.2141 +// 0xE3 - no name
  1.2142 +// 0xE4 - no name
  1.2143 +
  1.2144 +  static const int8_t xlat[256] =
  1.2145 +  {
  1.2146 +  // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
  1.2147 +  //-----------------------------------------------------------------------
  1.2148 +    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // 00
  1.2149 +    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // 10
  1.2150 +     0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // 20
  1.2151 +     1,  2,  3,  4,  5,  6,  7,  8,  9, 10, -1, -1, -1, -1, -1, -1,   // 30
  1.2152 +    -1, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,   // 40
  1.2153 +    26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, -1, -1, -1,   // 50
  1.2154 +    37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, -1, 49, 50, 51,   // 60
  1.2155 +    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // 70
  1.2156 +    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // 80
  1.2157 +    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // 90
  1.2158 +    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // A0
  1.2159 +    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 52, 53, 54, 55, 56, 57,   // B0
  1.2160 +    58, 59, 60, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // C0
  1.2161 +    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 61, 62, 63, 64, 65,   // D0
  1.2162 +    -1, 66, 67, 68, 69, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // E0
  1.2163 +    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1    // F0
  1.2164 +  };
  1.2165 +
  1.2166 +  return xlat[aVirtualKey];
  1.2167 +}
  1.2168 +
  1.2169 +int
  1.2170 +KeyboardLayout::CompareDeadKeyEntries(const void* aArg1,
  1.2171 +                                      const void* aArg2,
  1.2172 +                                      void*)
  1.2173 +{
  1.2174 +  const DeadKeyEntry* arg1 = static_cast<const DeadKeyEntry*>(aArg1);
  1.2175 +  const DeadKeyEntry* arg2 = static_cast<const DeadKeyEntry*>(aArg2);
  1.2176 +
  1.2177 +  return arg1->BaseChar - arg2->BaseChar;
  1.2178 +}
  1.2179 +
  1.2180 +const DeadKeyTable*
  1.2181 +KeyboardLayout::AddDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
  1.2182 +                                uint32_t aEntries)
  1.2183 +{
  1.2184 +  DeadKeyTableListEntry* next = mDeadKeyTableListHead;
  1.2185 +
  1.2186 +  const size_t bytes = offsetof(DeadKeyTableListEntry, data) +
  1.2187 +    DeadKeyTable::SizeInBytes(aEntries);
  1.2188 +  uint8_t* p = new uint8_t[bytes];
  1.2189 +
  1.2190 +  mDeadKeyTableListHead = reinterpret_cast<DeadKeyTableListEntry*>(p);
  1.2191 +  mDeadKeyTableListHead->next = next;
  1.2192 +
  1.2193 +  DeadKeyTable* dkt =
  1.2194 +    reinterpret_cast<DeadKeyTable*>(mDeadKeyTableListHead->data);
  1.2195 +
  1.2196 +  dkt->Init(aDeadKeyArray, aEntries);
  1.2197 +
  1.2198 +  return dkt;
  1.2199 +}
  1.2200 +
  1.2201 +void
  1.2202 +KeyboardLayout::ReleaseDeadKeyTables()
  1.2203 +{
  1.2204 +  while (mDeadKeyTableListHead) {
  1.2205 +    uint8_t* p = reinterpret_cast<uint8_t*>(mDeadKeyTableListHead);
  1.2206 +    mDeadKeyTableListHead = mDeadKeyTableListHead->next;
  1.2207 +
  1.2208 +    delete [] p;
  1.2209 +  }
  1.2210 +}
  1.2211 +
  1.2212 +bool
  1.2213 +KeyboardLayout::EnsureDeadKeyActive(bool aIsActive,
  1.2214 +                                    uint8_t aDeadKey,
  1.2215 +                                    const PBYTE aDeadKeyKbdState)
  1.2216 +{
  1.2217 +  int32_t ret;
  1.2218 +  do {
  1.2219 +    char16_t dummyChars[5];
  1.2220 +    ret = ::ToUnicodeEx(aDeadKey, 0, (PBYTE)aDeadKeyKbdState,
  1.2221 +                        (LPWSTR)dummyChars, ArrayLength(dummyChars), 0,
  1.2222 +                        mKeyboardLayout);
  1.2223 +    // returned values:
  1.2224 +    // <0 - Dead key state is active. The keyboard driver will wait for next
  1.2225 +    //      character.
  1.2226 +    //  1 - Previous pressed key was a valid base character that produced
  1.2227 +    //      exactly one composite character.
  1.2228 +    // >1 - Previous pressed key does not produce any composite characters.
  1.2229 +    //      Return dead-key character followed by base character(s).
  1.2230 +  } while ((ret < 0) != aIsActive);
  1.2231 +
  1.2232 +  return (ret < 0);
  1.2233 +}
  1.2234 +
  1.2235 +void
  1.2236 +KeyboardLayout::DeactivateDeadKeyState()
  1.2237 +{
  1.2238 +  if (mActiveDeadKey < 0) {
  1.2239 +    return;
  1.2240 +  }
  1.2241 +
  1.2242 +  BYTE kbdState[256];
  1.2243 +  memset(kbdState, 0, sizeof(kbdState));
  1.2244 +
  1.2245 +  VirtualKey::FillKbdState(kbdState, mDeadKeyShiftState);
  1.2246 +
  1.2247 +  EnsureDeadKeyActive(false, mActiveDeadKey, kbdState);
  1.2248 +  mActiveDeadKey = -1;
  1.2249 +}
  1.2250 +
  1.2251 +bool
  1.2252 +KeyboardLayout::AddDeadKeyEntry(char16_t aBaseChar,
  1.2253 +                                char16_t aCompositeChar,
  1.2254 +                                DeadKeyEntry* aDeadKeyArray,
  1.2255 +                                uint32_t aEntries)
  1.2256 +{
  1.2257 +  for (uint32_t index = 0; index < aEntries; index++) {
  1.2258 +    if (aDeadKeyArray[index].BaseChar == aBaseChar) {
  1.2259 +      return false;
  1.2260 +    }
  1.2261 +  }
  1.2262 +
  1.2263 +  aDeadKeyArray[aEntries].BaseChar = aBaseChar;
  1.2264 +  aDeadKeyArray[aEntries].CompositeChar = aCompositeChar;
  1.2265 +
  1.2266 +  return true;
  1.2267 +}
  1.2268 +
  1.2269 +uint32_t
  1.2270 +KeyboardLayout::GetDeadKeyCombinations(uint8_t aDeadKey,
  1.2271 +                                       const PBYTE aDeadKeyKbdState,
  1.2272 +                                       uint16_t aShiftStatesWithBaseChars,
  1.2273 +                                       DeadKeyEntry* aDeadKeyArray,
  1.2274 +                                       uint32_t aMaxEntries)
  1.2275 +{
  1.2276 +  bool deadKeyActive = false;
  1.2277 +  uint32_t entries = 0;
  1.2278 +  BYTE kbdState[256];
  1.2279 +  memset(kbdState, 0, sizeof(kbdState));
  1.2280 +
  1.2281 +  for (uint32_t shiftState = 0; shiftState < 16; shiftState++) {
  1.2282 +    if (!(aShiftStatesWithBaseChars & (1 << shiftState))) {
  1.2283 +      continue;
  1.2284 +    }
  1.2285 +
  1.2286 +    VirtualKey::FillKbdState(kbdState, shiftState);
  1.2287 +
  1.2288 +    for (uint32_t virtualKey = 0; virtualKey < 256; virtualKey++) {
  1.2289 +      int32_t vki = GetKeyIndex(virtualKey);
  1.2290 +      // Dead-key can pair only with such key that produces exactly one base
  1.2291 +      // character.
  1.2292 +      if (vki >= 0 &&
  1.2293 +          mVirtualKeys[vki].GetNativeUniChars(shiftState).mLength == 1) {
  1.2294 +        // Ensure dead-key is in active state, when it swallows entered
  1.2295 +        // character and waits for the next pressed key.
  1.2296 +        if (!deadKeyActive) {
  1.2297 +          deadKeyActive = EnsureDeadKeyActive(true, aDeadKey,
  1.2298 +                                              aDeadKeyKbdState);
  1.2299 +        }
  1.2300 +
  1.2301 +        // Depending on the character the followed the dead-key, the keyboard
  1.2302 +        // driver can produce one composite character, or a dead-key character
  1.2303 +        // followed by a second character.
  1.2304 +        char16_t compositeChars[5];
  1.2305 +        int32_t ret =
  1.2306 +          ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)compositeChars,
  1.2307 +                        ArrayLength(compositeChars), 0, mKeyboardLayout);
  1.2308 +        switch (ret) {
  1.2309 +          case 0:
  1.2310 +            // This key combination does not produce any characters. The
  1.2311 +            // dead-key is still in active state.
  1.2312 +            break;
  1.2313 +          case 1: {
  1.2314 +            // Exactly one composite character produced. Now, when dead-key
  1.2315 +            // is not active, repeat the last character one more time to
  1.2316 +            // determine the base character.
  1.2317 +            char16_t baseChars[5];
  1.2318 +            ret = ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)baseChars,
  1.2319 +                                ArrayLength(baseChars), 0, mKeyboardLayout);
  1.2320 +            NS_ASSERTION(ret == 1, "One base character expected");
  1.2321 +            if (ret == 1 && entries < aMaxEntries &&
  1.2322 +                AddDeadKeyEntry(baseChars[0], compositeChars[0],
  1.2323 +                                aDeadKeyArray, entries)) {
  1.2324 +              entries++;
  1.2325 +            }
  1.2326 +            deadKeyActive = false;
  1.2327 +            break;
  1.2328 +          }
  1.2329 +          default:
  1.2330 +            // 1. Unexpected dead-key. Dead-key chaining is not supported.
  1.2331 +            // 2. More than one character generated. This is not a valid
  1.2332 +            //    dead-key and base character combination.
  1.2333 +            deadKeyActive = false;
  1.2334 +            break;
  1.2335 +        }
  1.2336 +      }
  1.2337 +    }
  1.2338 +  }
  1.2339 +
  1.2340 +  if (deadKeyActive) {
  1.2341 +    deadKeyActive = EnsureDeadKeyActive(false, aDeadKey, aDeadKeyKbdState);
  1.2342 +  }
  1.2343 +
  1.2344 +  NS_QuickSort(aDeadKeyArray, entries, sizeof(DeadKeyEntry),
  1.2345 +               CompareDeadKeyEntries, nullptr);
  1.2346 +  return entries;
  1.2347 +}
  1.2348 +
  1.2349 +uint32_t
  1.2350 +KeyboardLayout::ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const
  1.2351 +{
  1.2352 +  // Alphabet or Numeric or Numpad or Function keys
  1.2353 +  if ((aNativeKeyCode >= 0x30 && aNativeKeyCode <= 0x39) ||
  1.2354 +      (aNativeKeyCode >= 0x41 && aNativeKeyCode <= 0x5A) ||
  1.2355 +      (aNativeKeyCode >= 0x60 && aNativeKeyCode <= 0x87)) {
  1.2356 +    return static_cast<uint32_t>(aNativeKeyCode);
  1.2357 +  }
  1.2358 +  switch (aNativeKeyCode) {
  1.2359 +    // Following keycodes are same as our DOM keycodes
  1.2360 +    case VK_CANCEL:
  1.2361 +    case VK_BACK:
  1.2362 +    case VK_TAB:
  1.2363 +    case VK_CLEAR:
  1.2364 +    case VK_RETURN:
  1.2365 +    case VK_SHIFT:
  1.2366 +    case VK_CONTROL:
  1.2367 +    case VK_MENU: // Alt
  1.2368 +    case VK_PAUSE:
  1.2369 +    case VK_CAPITAL: // CAPS LOCK
  1.2370 +    case VK_KANA: // same as VK_HANGUL
  1.2371 +    case VK_JUNJA:
  1.2372 +    case VK_FINAL:
  1.2373 +    case VK_HANJA: // same as VK_KANJI
  1.2374 +    case VK_ESCAPE:
  1.2375 +    case VK_CONVERT:
  1.2376 +    case VK_NONCONVERT:
  1.2377 +    case VK_ACCEPT:
  1.2378 +    case VK_MODECHANGE:
  1.2379 +    case VK_SPACE:
  1.2380 +    case VK_PRIOR: // PAGE UP
  1.2381 +    case VK_NEXT: // PAGE DOWN
  1.2382 +    case VK_END:
  1.2383 +    case VK_HOME:
  1.2384 +    case VK_LEFT:
  1.2385 +    case VK_UP:
  1.2386 +    case VK_RIGHT:
  1.2387 +    case VK_DOWN:
  1.2388 +    case VK_SELECT:
  1.2389 +    case VK_PRINT:
  1.2390 +    case VK_EXECUTE:
  1.2391 +    case VK_SNAPSHOT:
  1.2392 +    case VK_INSERT:
  1.2393 +    case VK_DELETE:
  1.2394 +    case VK_APPS: // Context Menu
  1.2395 +    case VK_SLEEP:
  1.2396 +    case VK_NUMLOCK:
  1.2397 +    case VK_SCROLL: // SCROLL LOCK
  1.2398 +    case VK_ATTN: // Attension key of IBM midrange computers, e.g., AS/400
  1.2399 +    case VK_CRSEL: // Cursor Selection
  1.2400 +    case VK_EXSEL: // Extend Selection
  1.2401 +    case VK_EREOF: // Erase EOF key of IBM 3270 keyboard layout
  1.2402 +    case VK_PLAY:
  1.2403 +    case VK_ZOOM:
  1.2404 +    case VK_PA1: // PA1 key of IBM 3270 keyboard layout
  1.2405 +      return uint32_t(aNativeKeyCode);
  1.2406 +
  1.2407 +    case VK_HELP:
  1.2408 +      return NS_VK_HELP;
  1.2409 +
  1.2410 +    // Windows key should be mapped to a Win keycode
  1.2411 +    // They should be able to be distinguished by DOM3 KeyboardEvent.location
  1.2412 +    case VK_LWIN:
  1.2413 +    case VK_RWIN:
  1.2414 +      return NS_VK_WIN;
  1.2415 +
  1.2416 +    case VK_VOLUME_MUTE:
  1.2417 +      return NS_VK_VOLUME_MUTE;
  1.2418 +    case VK_VOLUME_DOWN:
  1.2419 +      return NS_VK_VOLUME_DOWN;
  1.2420 +    case VK_VOLUME_UP:
  1.2421 +      return NS_VK_VOLUME_UP;
  1.2422 +
  1.2423 +    // Following keycodes are not defined in our DOM keycodes.
  1.2424 +    case VK_BROWSER_BACK:
  1.2425 +    case VK_BROWSER_FORWARD:
  1.2426 +    case VK_BROWSER_REFRESH:
  1.2427 +    case VK_BROWSER_STOP:
  1.2428 +    case VK_BROWSER_SEARCH:
  1.2429 +    case VK_BROWSER_FAVORITES:
  1.2430 +    case VK_BROWSER_HOME:
  1.2431 +    case VK_MEDIA_NEXT_TRACK:
  1.2432 +    case VK_MEDIA_STOP:
  1.2433 +    case VK_MEDIA_PLAY_PAUSE:
  1.2434 +    case VK_LAUNCH_MAIL:
  1.2435 +    case VK_LAUNCH_MEDIA_SELECT:
  1.2436 +    case VK_LAUNCH_APP1:
  1.2437 +    case VK_LAUNCH_APP2:
  1.2438 +      return 0;
  1.2439 +
  1.2440 +    // Following OEM specific virtual keycodes should pass through DOM keyCode
  1.2441 +    // for compatibility with the other browsers on Windows.
  1.2442 +
  1.2443 +    // Following OEM specific virtual keycodes are defined for Fujitsu/OASYS.
  1.2444 +    case VK_OEM_FJ_JISHO:
  1.2445 +    case VK_OEM_FJ_MASSHOU:
  1.2446 +    case VK_OEM_FJ_TOUROKU:
  1.2447 +    case VK_OEM_FJ_LOYA:
  1.2448 +    case VK_OEM_FJ_ROYA:
  1.2449 +    // Not sure what means "ICO".
  1.2450 +    case VK_ICO_HELP:
  1.2451 +    case VK_ICO_00:
  1.2452 +    case VK_ICO_CLEAR:
  1.2453 +    // Following OEM specific virtual keycodes are defined for Nokia/Ericsson.
  1.2454 +    case VK_OEM_RESET:
  1.2455 +    case VK_OEM_JUMP:
  1.2456 +    case VK_OEM_PA1:
  1.2457 +    case VK_OEM_PA2:
  1.2458 +    case VK_OEM_PA3:
  1.2459 +    case VK_OEM_WSCTRL:
  1.2460 +    case VK_OEM_CUSEL:
  1.2461 +    case VK_OEM_ATTN:
  1.2462 +    case VK_OEM_FINISH:
  1.2463 +    case VK_OEM_COPY:
  1.2464 +    case VK_OEM_AUTO:
  1.2465 +    case VK_OEM_ENLW:
  1.2466 +    case VK_OEM_BACKTAB:
  1.2467 +    // VK_OEM_CLEAR is defined as not OEM specific, but let's pass though
  1.2468 +    // DOM keyCode like other OEM specific virtual keycodes.
  1.2469 +    case VK_OEM_CLEAR:
  1.2470 +      return uint32_t(aNativeKeyCode);
  1.2471 +
  1.2472 +    // 0xE1 is an OEM specific virtual keycode. However, the value is already
  1.2473 +    // used in our DOM keyCode for AltGr on Linux. So, this virtual keycode
  1.2474 +    // cannot pass through DOM keyCode.
  1.2475 +    case 0xE1:
  1.2476 +      return 0;
  1.2477 +
  1.2478 +    // Following keycodes are OEM keys which are keycodes for non-alphabet and
  1.2479 +    // non-numeric keys, we should compute each keycode of them from unshifted
  1.2480 +    // character which is inputted by each key.  But if the unshifted character
  1.2481 +    // is not an ASCII character but shifted character is an ASCII character,
  1.2482 +    // we should refer it.
  1.2483 +    case VK_OEM_1:
  1.2484 +    case VK_OEM_PLUS:
  1.2485 +    case VK_OEM_COMMA:
  1.2486 +    case VK_OEM_MINUS:
  1.2487 +    case VK_OEM_PERIOD:
  1.2488 +    case VK_OEM_2:
  1.2489 +    case VK_OEM_3:
  1.2490 +    case VK_OEM_4:
  1.2491 +    case VK_OEM_5:
  1.2492 +    case VK_OEM_6:
  1.2493 +    case VK_OEM_7:
  1.2494 +    case VK_OEM_8:
  1.2495 +    case VK_OEM_102:
  1.2496 +    case VK_ABNT_C1:
  1.2497 +    {
  1.2498 +      NS_ASSERTION(IsPrintableCharKey(aNativeKeyCode),
  1.2499 +                   "The key must be printable");
  1.2500 +      ModifierKeyState modKeyState(0);
  1.2501 +      UniCharsAndModifiers uniChars =
  1.2502 +        GetUniCharsAndModifiers(aNativeKeyCode, modKeyState);
  1.2503 +      if (uniChars.mLength != 1 ||
  1.2504 +          uniChars.mChars[0] < ' ' || uniChars.mChars[0] > 0x7F) {
  1.2505 +        modKeyState.Set(MODIFIER_SHIFT);
  1.2506 +        uniChars = GetUniCharsAndModifiers(aNativeKeyCode, modKeyState);
  1.2507 +        if (uniChars.mLength != 1 ||
  1.2508 +            uniChars.mChars[0] < ' ' || uniChars.mChars[0] > 0x7F) {
  1.2509 +          return 0;
  1.2510 +        }
  1.2511 +      }
  1.2512 +      return WidgetUtils::ComputeKeyCodeFromChar(uniChars.mChars[0]);
  1.2513 +    }
  1.2514 +
  1.2515 +    // IE sets 0xC2 to the DOM keyCode for VK_ABNT_C2.  However, we're already
  1.2516 +    // using NS_VK_SEPARATOR for the separator key on Mac and Linux.  Therefore,
  1.2517 +    // We should keep consistency between Gecko on all platforms rather than
  1.2518 +    // with other browsers since a lot of keyCode values are already different
  1.2519 +    // between browsers.
  1.2520 +    case VK_ABNT_C2:
  1.2521 +      return NS_VK_SEPARATOR;
  1.2522 +
  1.2523 +    // VK_PROCESSKEY means IME already consumed the key event.
  1.2524 +    case VK_PROCESSKEY:
  1.2525 +      return 0;
  1.2526 +    // VK_PACKET is generated by SendInput() API, we don't need to
  1.2527 +    // care this message as key event.
  1.2528 +    case VK_PACKET:
  1.2529 +      return 0;
  1.2530 +    // If a key is not mapped to a virtual keycode, 0xFF is used.
  1.2531 +    case 0xFF:
  1.2532 +      NS_WARNING("The key is failed to be converted to a virtual keycode");
  1.2533 +      return 0;
  1.2534 +  }
  1.2535 +#ifdef DEBUG
  1.2536 +  nsPrintfCString warning("Unknown virtual keycode (0x%08X), please check the "
  1.2537 +                          "latest MSDN document, there may be some new "
  1.2538 +                          "keycodes we've never known.",
  1.2539 +                          aNativeKeyCode);
  1.2540 +  NS_WARNING(warning.get());
  1.2541 +#endif
  1.2542 +  return 0;
  1.2543 +}
  1.2544 +
  1.2545 +KeyNameIndex
  1.2546 +KeyboardLayout::ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const
  1.2547 +{
  1.2548 +  if (IsPrintableCharKey(aVirtualKey)) {
  1.2549 +    return KEY_NAME_INDEX_USE_STRING;
  1.2550 +  }
  1.2551 +
  1.2552 +#define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
  1.2553 +#define NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
  1.2554 +#define NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
  1.2555 +#define NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
  1.2556 +
  1.2557 +  switch (aVirtualKey) {
  1.2558 +
  1.2559 +#undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  1.2560 +#define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \
  1.2561 +    case aNativeKey: return aKeyNameIndex;
  1.2562 +
  1.2563 +#include "NativeKeyToDOMKeyName.h"
  1.2564 +
  1.2565 +#undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  1.2566 +#define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
  1.2567 +
  1.2568 +    default:
  1.2569 +      break;
  1.2570 +  }
  1.2571 +
  1.2572 +  HKL layout = GetLayout();
  1.2573 +  WORD langID = LOWORD(static_cast<HKL>(layout));
  1.2574 +  WORD primaryLangID = PRIMARYLANGID(langID);
  1.2575 +
  1.2576 +  if (primaryLangID == LANG_JAPANESE) {
  1.2577 +    switch (aVirtualKey) {
  1.2578 +
  1.2579 +#undef NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  1.2580 +#define NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)\
  1.2581 +      case aNativeKey: return aKeyNameIndex;
  1.2582 +
  1.2583 +#include "NativeKeyToDOMKeyName.h"
  1.2584 +
  1.2585 +#undef NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  1.2586 +#define NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
  1.2587 +
  1.2588 +      default:
  1.2589 +        break;
  1.2590 +    }
  1.2591 +  } else if (primaryLangID == LANG_KOREAN) {
  1.2592 +    switch (aVirtualKey) {
  1.2593 +
  1.2594 +#undef NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  1.2595 +#define NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)\
  1.2596 +      case aNativeKey: return aKeyNameIndex;
  1.2597 +
  1.2598 +#include "NativeKeyToDOMKeyName.h"
  1.2599 +
  1.2600 +#undef NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  1.2601 +#define NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
  1.2602 +
  1.2603 +      default:
  1.2604 +        return KEY_NAME_INDEX_Unidentified;
  1.2605 +    }
  1.2606 +  }
  1.2607 +
  1.2608 +  switch (aVirtualKey) {
  1.2609 +
  1.2610 +#undef NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  1.2611 +#define NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)\
  1.2612 +    case aNativeKey: return aKeyNameIndex;
  1.2613 +
  1.2614 +#include "NativeKeyToDOMKeyName.h"
  1.2615 +
  1.2616 +#undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  1.2617 +#undef NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  1.2618 +#undef NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  1.2619 +#undef NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
  1.2620 +
  1.2621 +    default:
  1.2622 +      return KEY_NAME_INDEX_Unidentified;
  1.2623 +  }
  1.2624 +}
  1.2625 +
  1.2626 +nsresult
  1.2627 +KeyboardLayout::SynthesizeNativeKeyEvent(nsWindowBase* aWidget,
  1.2628 +                                         int32_t aNativeKeyboardLayout,
  1.2629 +                                         int32_t aNativeKeyCode,
  1.2630 +                                         uint32_t aModifierFlags,
  1.2631 +                                         const nsAString& aCharacters,
  1.2632 +                                         const nsAString& aUnmodifiedCharacters)
  1.2633 +{
  1.2634 +  UINT keyboardLayoutListCount = ::GetKeyboardLayoutList(0, nullptr);
  1.2635 +  NS_ASSERTION(keyboardLayoutListCount > 0,
  1.2636 +               "One keyboard layout must be installed at least");
  1.2637 +  HKL keyboardLayoutListBuff[50];
  1.2638 +  HKL* keyboardLayoutList =
  1.2639 +    keyboardLayoutListCount < 50 ? keyboardLayoutListBuff :
  1.2640 +                                   new HKL[keyboardLayoutListCount];
  1.2641 +  keyboardLayoutListCount =
  1.2642 +    ::GetKeyboardLayoutList(keyboardLayoutListCount, keyboardLayoutList);
  1.2643 +  NS_ASSERTION(keyboardLayoutListCount > 0,
  1.2644 +               "Failed to get all keyboard layouts installed on the system");
  1.2645 +
  1.2646 +  nsPrintfCString layoutName("%08x", aNativeKeyboardLayout);
  1.2647 +  HKL loadedLayout = LoadKeyboardLayoutA(layoutName.get(), KLF_NOTELLSHELL);
  1.2648 +  if (loadedLayout == nullptr) {
  1.2649 +    if (keyboardLayoutListBuff != keyboardLayoutList) {
  1.2650 +      delete [] keyboardLayoutList;
  1.2651 +    }
  1.2652 +    return NS_ERROR_NOT_AVAILABLE;
  1.2653 +  }
  1.2654 +
  1.2655 +  // Setup clean key state and load desired layout
  1.2656 +  BYTE originalKbdState[256];
  1.2657 +  ::GetKeyboardState(originalKbdState);
  1.2658 +  BYTE kbdState[256];
  1.2659 +  memset(kbdState, 0, sizeof(kbdState));
  1.2660 +  // This changes the state of the keyboard for the current thread only,
  1.2661 +  // and we'll restore it soon, so this should be OK.
  1.2662 +  ::SetKeyboardState(kbdState);
  1.2663 +
  1.2664 +  OverrideLayout(loadedLayout);
  1.2665 +
  1.2666 +  uint8_t argumentKeySpecific = 0;
  1.2667 +  switch (aNativeKeyCode) {
  1.2668 +    case VK_SHIFT:
  1.2669 +      aModifierFlags &= ~(nsIWidget::SHIFT_L | nsIWidget::SHIFT_R);
  1.2670 +      argumentKeySpecific = VK_LSHIFT;
  1.2671 +      break;
  1.2672 +    case VK_LSHIFT:
  1.2673 +      aModifierFlags &= ~nsIWidget::SHIFT_L;
  1.2674 +      argumentKeySpecific = aNativeKeyCode;
  1.2675 +      aNativeKeyCode = VK_SHIFT;
  1.2676 +      break;
  1.2677 +    case VK_RSHIFT:
  1.2678 +      aModifierFlags &= ~nsIWidget::SHIFT_R;
  1.2679 +      argumentKeySpecific = aNativeKeyCode;
  1.2680 +      aNativeKeyCode = VK_SHIFT;
  1.2681 +      break;
  1.2682 +    case VK_CONTROL:
  1.2683 +      aModifierFlags &= ~(nsIWidget::CTRL_L | nsIWidget::CTRL_R);
  1.2684 +      argumentKeySpecific = VK_LCONTROL;
  1.2685 +      break;
  1.2686 +    case VK_LCONTROL:
  1.2687 +      aModifierFlags &= ~nsIWidget::CTRL_L;
  1.2688 +      argumentKeySpecific = aNativeKeyCode;
  1.2689 +      aNativeKeyCode = VK_CONTROL;
  1.2690 +      break;
  1.2691 +    case VK_RCONTROL:
  1.2692 +      aModifierFlags &= ~nsIWidget::CTRL_R;
  1.2693 +      argumentKeySpecific = aNativeKeyCode;
  1.2694 +      aNativeKeyCode = VK_CONTROL;
  1.2695 +      break;
  1.2696 +    case VK_MENU:
  1.2697 +      aModifierFlags &= ~(nsIWidget::ALT_L | nsIWidget::ALT_R);
  1.2698 +      argumentKeySpecific = VK_LMENU;
  1.2699 +      break;
  1.2700 +    case VK_LMENU:
  1.2701 +      aModifierFlags &= ~nsIWidget::ALT_L;
  1.2702 +      argumentKeySpecific = aNativeKeyCode;
  1.2703 +      aNativeKeyCode = VK_MENU;
  1.2704 +      break;
  1.2705 +    case VK_RMENU:
  1.2706 +      aModifierFlags &= ~nsIWidget::ALT_R;
  1.2707 +      argumentKeySpecific = aNativeKeyCode;
  1.2708 +      aNativeKeyCode = VK_MENU;
  1.2709 +      break;
  1.2710 +    case VK_CAPITAL:
  1.2711 +      aModifierFlags &= ~nsIWidget::CAPS_LOCK;
  1.2712 +      argumentKeySpecific = VK_CAPITAL;
  1.2713 +      break;
  1.2714 +    case VK_NUMLOCK:
  1.2715 +      aModifierFlags &= ~nsIWidget::NUM_LOCK;
  1.2716 +      argumentKeySpecific = VK_NUMLOCK;
  1.2717 +      break;
  1.2718 +  }
  1.2719 +
  1.2720 +  nsAutoTArray<KeyPair,10> keySequence;
  1.2721 +  WinUtils::SetupKeyModifiersSequence(&keySequence, aModifierFlags);
  1.2722 +  NS_ASSERTION(aNativeKeyCode >= 0 && aNativeKeyCode < 256,
  1.2723 +               "Native VK key code out of range");
  1.2724 +  keySequence.AppendElement(KeyPair(aNativeKeyCode, argumentKeySpecific));
  1.2725 +
  1.2726 +  // Simulate the pressing of each modifier key and then the real key
  1.2727 +  for (uint32_t i = 0; i < keySequence.Length(); ++i) {
  1.2728 +    uint8_t key = keySequence[i].mGeneral;
  1.2729 +    uint8_t keySpecific = keySequence[i].mSpecific;
  1.2730 +    kbdState[key] = 0x81; // key is down and toggled on if appropriate
  1.2731 +    if (keySpecific) {
  1.2732 +      kbdState[keySpecific] = 0x81;
  1.2733 +    }
  1.2734 +    ::SetKeyboardState(kbdState);
  1.2735 +    ModifierKeyState modKeyState;
  1.2736 +    UINT scanCode =
  1.2737 +      ComputeScanCodeForVirtualKeyCode(keySpecific ? keySpecific : key);
  1.2738 +    LPARAM lParam = static_cast<LPARAM>(scanCode << 16);
  1.2739 +    // Add extended key flag to the lParam for right control key and right alt
  1.2740 +    // key.
  1.2741 +    if (keySpecific == VK_RCONTROL || keySpecific == VK_RMENU) {
  1.2742 +      lParam |= 0x1000000;
  1.2743 +    }
  1.2744 +    MSG keyDownMsg = WinUtils::InitMSG(WM_KEYDOWN, key, lParam,
  1.2745 +                                       aWidget->GetWindowHandle());
  1.2746 +    if (i == keySequence.Length() - 1) {
  1.2747 +      bool makeDeadCharMsg =
  1.2748 +        (IsDeadKey(key, modKeyState) && aCharacters.IsEmpty());
  1.2749 +      nsAutoString chars(aCharacters);
  1.2750 +      if (makeDeadCharMsg) {
  1.2751 +        UniCharsAndModifiers deadChars =
  1.2752 +          GetUniCharsAndModifiers(key, modKeyState);
  1.2753 +        chars = deadChars.ToString();
  1.2754 +        NS_ASSERTION(chars.Length() == 1,
  1.2755 +                     "Dead char must be only one character");
  1.2756 +      }
  1.2757 +      if (chars.IsEmpty()) {
  1.2758 +        NativeKey nativeKey(aWidget, keyDownMsg, modKeyState);
  1.2759 +        nativeKey.HandleKeyDownMessage();
  1.2760 +      } else {
  1.2761 +        nsAutoTArray<NativeKey::FakeCharMsg, 10> fakeCharMsgs;
  1.2762 +        for (uint32_t j = 0; j < chars.Length(); j++) {
  1.2763 +          NativeKey::FakeCharMsg* fakeCharMsg = fakeCharMsgs.AppendElement();
  1.2764 +          fakeCharMsg->mCharCode = chars.CharAt(j);
  1.2765 +          fakeCharMsg->mScanCode = scanCode;
  1.2766 +          fakeCharMsg->mIsDeadKey = makeDeadCharMsg;
  1.2767 +        }
  1.2768 +        NativeKey nativeKey(aWidget, keyDownMsg, modKeyState, &fakeCharMsgs);
  1.2769 +        bool dispatched;
  1.2770 +        nativeKey.HandleKeyDownMessage(&dispatched);
  1.2771 +        // If some char messages are not consumed, let's emulate the widget
  1.2772 +        // receiving the message directly.
  1.2773 +        for (uint32_t j = 1; j < fakeCharMsgs.Length(); j++) {
  1.2774 +          if (fakeCharMsgs[j].mConsumed) {
  1.2775 +            continue;
  1.2776 +          }
  1.2777 +          MSG charMsg = fakeCharMsgs[j].GetCharMsg(aWidget->GetWindowHandle());
  1.2778 +          NativeKey nativeKey(aWidget, charMsg, modKeyState);
  1.2779 +          nativeKey.HandleCharMessage(charMsg);
  1.2780 +        }
  1.2781 +      }
  1.2782 +    } else {
  1.2783 +      NativeKey nativeKey(aWidget, keyDownMsg, modKeyState);
  1.2784 +      nativeKey.HandleKeyDownMessage();
  1.2785 +    }
  1.2786 +  }
  1.2787 +  for (uint32_t i = keySequence.Length(); i > 0; --i) {
  1.2788 +    uint8_t key = keySequence[i - 1].mGeneral;
  1.2789 +    uint8_t keySpecific = keySequence[i - 1].mSpecific;
  1.2790 +    kbdState[key] = 0; // key is up and toggled off if appropriate
  1.2791 +    if (keySpecific) {
  1.2792 +      kbdState[keySpecific] = 0;
  1.2793 +    }
  1.2794 +    ::SetKeyboardState(kbdState);
  1.2795 +    ModifierKeyState modKeyState;
  1.2796 +    UINT scanCode =
  1.2797 +      ComputeScanCodeForVirtualKeyCode(keySpecific ? keySpecific : key);
  1.2798 +    LPARAM lParam = static_cast<LPARAM>(scanCode << 16);
  1.2799 +    // Add extended key flag to the lParam for right control key and right alt
  1.2800 +    // key.
  1.2801 +    if (keySpecific == VK_RCONTROL || keySpecific == VK_RMENU) {
  1.2802 +      lParam |= 0x1000000;
  1.2803 +    }
  1.2804 +    MSG keyUpMsg = WinUtils::InitMSG(WM_KEYUP, key, lParam,
  1.2805 +                                     aWidget->GetWindowHandle());
  1.2806 +    NativeKey nativeKey(aWidget, keyUpMsg, modKeyState);
  1.2807 +    nativeKey.HandleKeyUpMessage();
  1.2808 +  }
  1.2809 +
  1.2810 +  // Restore old key state and layout
  1.2811 +  ::SetKeyboardState(originalKbdState);
  1.2812 +  RestoreLayout();
  1.2813 +
  1.2814 +  // Don't unload the layout if it's installed actually.
  1.2815 +  for (uint32_t i = 0; i < keyboardLayoutListCount; i++) {
  1.2816 +    if (keyboardLayoutList[i] == loadedLayout) {
  1.2817 +      loadedLayout = 0;
  1.2818 +      break;
  1.2819 +    }
  1.2820 +  }
  1.2821 +  if (keyboardLayoutListBuff != keyboardLayoutList) {
  1.2822 +    delete [] keyboardLayoutList;
  1.2823 +  }
  1.2824 +  if (loadedLayout) {
  1.2825 +    ::UnloadKeyboardLayout(loadedLayout);
  1.2826 +  }
  1.2827 +  return NS_OK;
  1.2828 +}
  1.2829 +
  1.2830 +/*****************************************************************************
  1.2831 + * mozilla::widget::DeadKeyTable
  1.2832 + *****************************************************************************/
  1.2833 +
  1.2834 +char16_t
  1.2835 +DeadKeyTable::GetCompositeChar(char16_t aBaseChar) const
  1.2836 +{
  1.2837 +  // Dead-key table is sorted by BaseChar in ascending order.
  1.2838 +  // Usually they are too small to use binary search.
  1.2839 +
  1.2840 +  for (uint32_t index = 0; index < mEntries; index++) {
  1.2841 +    if (mTable[index].BaseChar == aBaseChar) {
  1.2842 +      return mTable[index].CompositeChar;
  1.2843 +    }
  1.2844 +    if (mTable[index].BaseChar > aBaseChar) {
  1.2845 +      break;
  1.2846 +    }
  1.2847 +  }
  1.2848 +
  1.2849 +  return 0;
  1.2850 +}
  1.2851 +
  1.2852 +/*****************************************************************************
  1.2853 + * mozilla::widget::RedirectedKeyDownMessage
  1.2854 + *****************************************************************************/
  1.2855 +
  1.2856 +MSG RedirectedKeyDownMessageManager::sRedirectedKeyDownMsg;
  1.2857 +bool RedirectedKeyDownMessageManager::sDefaultPreventedOfRedirectedMsg = false;
  1.2858 +
  1.2859 +// static
  1.2860 +bool
  1.2861 +RedirectedKeyDownMessageManager::IsRedirectedMessage(const MSG& aMsg)
  1.2862 +{
  1.2863 +  return (aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN) &&
  1.2864 +         (sRedirectedKeyDownMsg.message == aMsg.message &&
  1.2865 +          WinUtils::GetScanCode(sRedirectedKeyDownMsg.lParam) ==
  1.2866 +            WinUtils::GetScanCode(aMsg.lParam));
  1.2867 +}
  1.2868 +
  1.2869 +// static
  1.2870 +void
  1.2871 +RedirectedKeyDownMessageManager::RemoveNextCharMessage(HWND aWnd)
  1.2872 +{
  1.2873 +  MSG msg;
  1.2874 +  if (WinUtils::PeekMessage(&msg, aWnd, WM_KEYFIRST, WM_KEYLAST,
  1.2875 +                            PM_NOREMOVE | PM_NOYIELD) &&
  1.2876 +      (msg.message == WM_CHAR || msg.message == WM_SYSCHAR)) {
  1.2877 +    WinUtils::PeekMessage(&msg, aWnd, msg.message, msg.message,
  1.2878 +                          PM_REMOVE | PM_NOYIELD);
  1.2879 +  }
  1.2880 +}
  1.2881 +
  1.2882 +} // namespace widget
  1.2883 +} // namespace mozilla
  1.2884 +

mercurial