author Masayuki Nakano <masayuki@d-toybox.com>
Sat, 09 Apr 2016 15:45:06 +0900
changeset 332507 8ced614c9a1ff986eb1be374b75f96d545c5a8a1
parent 332041 31b3a03707447d000981a6c1aa2dc81697458fc8
child 332513 1bf2088320755b225f40a7b90ba0381460550421
permissions -rw-r--r--
Bug 1257759 part.3 ModifierKeyState should be available in plugin module r=jimm Before posting native key message from PluginInstanceChild, we need to check if the key combination could be a shortcut key, i.e., we need to check if Ctrl or Alt key is pressed. ModifierKeyState is a good class for checking it but it should be defined in an independent header file. This patch separates the definition of ModifierKeyState to mozilla/widget/WinModifierKeyState.h and implement MaybeMatchShortcutKey() for PluginInstanceChild. MozReview-Commit-ID: ZjLnJx02Ou

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef KeyboardLayout_h__
#define KeyboardLayout_h__

#include "mozilla/RefPtr.h"
#include "nscore.h"
#include "nsString.h"
#include "nsWindowBase.h"
#include "nsWindowDefs.h"
#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
#include "mozilla/TextEventDispatcher.h"
#include "mozilla/widget/WinModifierKeyState.h"
#include <windows.h>

#define NS_NUM_OF_KEYS          70

#define VK_OEM_1                0xBA   // ';:' for US
#define VK_OEM_PLUS             0xBB   // '+' any country
#define VK_OEM_COMMA            0xBC
#define VK_OEM_MINUS            0xBD   // '-' any country
#define VK_OEM_PERIOD           0xBE
#define VK_OEM_2                0xBF
#define VK_OEM_3                0xC0
// '/?' for Brazilian (ABNT)
#define VK_ABNT_C1              0xC1
// Separator in Numpad for Brazilian (ABNT) or JIS keyboard for Mac.
#define VK_ABNT_C2              0xC2
#define VK_OEM_4                0xDB
#define VK_OEM_5                0xDC
#define VK_OEM_6                0xDD
#define VK_OEM_7                0xDE
#define VK_OEM_8                0xDF
#define VK_OEM_102              0xE2
#define VK_OEM_CLEAR            0xFE

class nsIIdleServiceInternal;

namespace mozilla {
namespace widget {

static const uint32_t sModifierKeyMap[][3] = {
  { nsIWidget::CAPS_LOCK, VK_CAPITAL, 0 },
  { nsIWidget::NUM_LOCK,  VK_NUMLOCK, 0 },
  { nsIWidget::SHIFT_L,   VK_SHIFT,   VK_LSHIFT },
  { nsIWidget::SHIFT_R,   VK_SHIFT,   VK_RSHIFT },
  { nsIWidget::CTRL_L,    VK_CONTROL, VK_LCONTROL },
  { nsIWidget::CTRL_R,    VK_CONTROL, VK_RCONTROL },
  { nsIWidget::ALT_L,     VK_MENU,    VK_LMENU },
  { nsIWidget::ALT_R,     VK_MENU,    VK_RMENU }

class KeyboardLayout;

struct UniCharsAndModifiers
  // Dead-key + up to 4 characters
  char16_t mChars[5];
  Modifiers mModifiers[5];
  uint32_t  mLength;

  UniCharsAndModifiers() : mLength(0) {}
  UniCharsAndModifiers operator+(const UniCharsAndModifiers& aOther) const;
  UniCharsAndModifiers& operator+=(const UniCharsAndModifiers& aOther);

   * Append a pair of unicode character and the final modifier.
  void Append(char16_t aUniChar, Modifiers aModifiers);
  void Clear() { mLength = 0; }
  bool IsEmpty() const { return !mLength; }

  void FillModifiers(Modifiers aModifiers);

  bool UniCharsEqual(const UniCharsAndModifiers& aOther) const;
  bool UniCharsCaseInsensitiveEqual(const UniCharsAndModifiers& aOther) const;

  nsString ToString() const { return nsString(mChars, mLength); }

struct DeadKeyEntry;
class DeadKeyTable;

class VirtualKey
  //  0 - Normal
  //  1 - Shift
  //  2 - Control
  //  3 - Control + Shift
  //  4 - Alt
  //  5 - Alt + Shift
  //  6 - Alt + Control (AltGr)
  //  7 - Alt + Control + Shift (AltGr + Shift)
  //  8 - CapsLock
  //  9 - CapsLock + Shift
  // 10 - CapsLock + Control
  // 11 - CapsLock + Control + Shift
  // 12 - CapsLock + Alt
  // 13 - CapsLock + Alt + Shift
  // 14 - CapsLock + Alt + Control (CapsLock + AltGr)
  // 15 - CapsLock + Alt + Control + Shift (CapsLock + AltGr + Shift)

  enum ShiftStateFlag
    STATE_SHIFT    = 0x01,
    STATE_CONTROL  = 0x02,
    STATE_ALT      = 0x04,

  typedef uint8_t ShiftState;

  static ShiftState ModifiersToShiftState(Modifiers aModifiers);
  static Modifiers ShiftStateToModifiers(ShiftState aShiftState);

  union KeyShiftState
      char16_t Chars[4];
    } Normal;
      const DeadKeyTable* Table;
      char16_t DeadChar;
    } DeadKey;

  KeyShiftState mShiftStates[16];
  uint16_t mIsDeadKey;

  void SetDeadKey(ShiftState aShiftState, bool aIsDeadKey)
    if (aIsDeadKey) {
      mIsDeadKey |= 1 << aShiftState;
    } else {
      mIsDeadKey &= ~(1 << aShiftState);

  static void FillKbdState(PBYTE aKbdState, const ShiftState aShiftState);

  bool IsDeadKey(ShiftState aShiftState) const
    return (mIsDeadKey & (1 << aShiftState)) != 0;

  void AttachDeadKeyTable(ShiftState aShiftState,
                          const DeadKeyTable* aDeadKeyTable)
    mShiftStates[aShiftState].DeadKey.Table = aDeadKeyTable;

  void SetNormalChars(ShiftState aShiftState, const char16_t* aChars,
                      uint32_t aNumOfChars);
  void SetDeadChar(ShiftState aShiftState, char16_t aDeadChar);
  const DeadKeyTable* MatchingDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
                                           uint32_t aEntries) const;
  inline char16_t GetCompositeChar(ShiftState aShiftState,
                                    char16_t aBaseChar) const;
  UniCharsAndModifiers GetNativeUniChars(ShiftState aShiftState) const;
  UniCharsAndModifiers GetUniChars(ShiftState aShiftState) const;

class MOZ_STACK_CLASS NativeKey
  friend class KeyboardLayout;

  struct FakeCharMsg
    UINT mCharCode;
    UINT mScanCode;
    bool mIsDeadKey;
    bool mConsumed;

    FakeCharMsg() :
      mCharCode(0), mScanCode(0), mIsDeadKey(false), mConsumed(false)

    MSG GetCharMsg(HWND aWnd) const
      MSG msg;
      msg.hwnd = aWnd;
      msg.message = mIsDeadKey ? WM_DEADCHAR : WM_CHAR;
      msg.wParam = static_cast<WPARAM>(mCharCode);
      msg.lParam = static_cast<LPARAM>(mScanCode << 16);
      msg.time = 0;
      msg.pt.x = msg.pt.y = 0;
      return msg;

  NativeKey(nsWindowBase* aWidget,
            const MSG& aMessage,
            const ModifierKeyState& aModKeyState,
            nsTArray<FakeCharMsg>* aFakeCharMsgs = nullptr);

   * Handle WM_KEYDOWN message or WM_SYSKEYDOWN message.  The instance must be
   * initialized with WM_KEYDOWN or WM_SYSKEYDOWN.
   * Returns true if dispatched keydown event or keypress event is consumed.
   * Otherwise, false.
  bool HandleKeyDownMessage(bool* aEventDispatched = nullptr) const;

   * Handles WM_CHAR message or WM_SYSCHAR message.  The instance must be
   * initialized with WM_KEYDOWN, WM_SYSKEYDOWN or them.
   * Returns true if dispatched keypress event is consumed.  Otherwise, false.
  bool HandleCharMessage(const MSG& aCharMsg,
                         bool* aEventDispatched = nullptr) const;

   * Handles keyup message.  Returns true if the event is consumed.
   * Otherwise, false.
  bool HandleKeyUpMessage(bool* aEventDispatched = nullptr) const;

   * Handles WM_APPCOMMAND message.  Returns true if the event is consumed.
   * Otherwise, false.
  bool HandleAppCommandMessage() const;

   * Callback of TextEventDispatcherListener::WillDispatchKeyboardEvent().
   * This method sets alternative char codes of aKeyboardEvent.
  void WillDispatchKeyboardEvent(WidgetKeyboardEvent& aKeyboardEvent,
                                 uint32_t aIndex);

  RefPtr<nsWindowBase> mWidget;
  RefPtr<TextEventDispatcher> mDispatcher;
  HKL mKeyboardLayout;
  MSG mMsg;

  uint32_t mDOMKeyCode;
  KeyNameIndex mKeyNameIndex;
  CodeNameIndex mCodeNameIndex;

  ModifierKeyState mModKeyState;

  // mVirtualKeyCode distinguishes left key or right key of modifier key.
  uint8_t mVirtualKeyCode;
  // mOriginalVirtualKeyCode doesn't distinguish left key or right key of
  // modifier key.  However, if the given keycode is VK_PROCESS, it's resolved
  // to a keycode before it's handled by IME.
  uint8_t mOriginalVirtualKeyCode;

  // mCommittedChars indicates the inputted characters which is committed by
  // the key.  If dead key fail to composite a character, mCommittedChars
  // indicates both the dead characters and the base characters.
  UniCharsAndModifiers mCommittedCharsAndModifiers;

  // Following strings are computed by
  // ComputeInputtingStringWithKeyboardLayout() which is typically called
  // before dispatching keydown event.
  // mInputtingStringAndModifiers's string is the string to be
  // inputted into the focused editor and its modifier state is proper
  // modifier state for inputting the string into the editor.
  UniCharsAndModifiers mInputtingStringAndModifiers;
  // mShiftedString is the string to be inputted into the editor with
  // current modifier state with active shift state.
  UniCharsAndModifiers mShiftedString;
  // mUnshiftedString is the string to be inputted into the editor with
  // current modifier state without shift state.
  UniCharsAndModifiers mUnshiftedString;
  // Following integers are computed by
  // ComputeInputtingStringWithKeyboardLayout() which is typically called
  // before dispatching keydown event.  The meaning of these values is same
  // as charCode.
  uint32_t mShiftedLatinChar;
  uint32_t mUnshiftedLatinChar;

  WORD    mScanCode;
  bool    mIsExtended;
  bool    mIsDeadKey;
  // mIsPrintableKey is true if the key may be a printable key without
  // any modifier keys.  Otherwise, false.
  // Please note that the event may not cause any text input even if this
  // is true.  E.g., it might be dead key state or Ctrl key may be pressed.
  bool    mIsPrintableKey;

  nsTArray<FakeCharMsg>* mFakeCharMsgs;

  // When a keydown event is dispatched at handling WM_APPCOMMAND, the computed
  // virtual keycode is set to this.  Even if we consume WM_APPCOMMAND message,
  // Windows may send WM_KEYDOWN and WM_KEYUP message for them.
  // At that time, we should not dispatch key events for them.
  static uint8_t sDispatchedKeyOfAppCommand;

    MOZ_CRASH("The default constructor of NativeKey isn't available");

  void InitWithAppCommand();

   * Returns true if the key event is caused by auto repeat.
  bool IsRepeat() const
    switch (mMsg.message) {
      case WM_KEYDOWN:
      case WM_SYSKEYDOWN:
      case WM_CHAR:
      case WM_SYSCHAR:
      case WM_DEADCHAR:
      case WM_SYSDEADCHAR:
        return ((mMsg.lParam & (1 << 30)) != 0);
      case WM_APPCOMMAND:
        if (mVirtualKeyCode) {
          // If we can map the WM_APPCOMMAND to a virtual keycode, we can trust
          // the result of GetKeyboardState().
          BYTE kbdState[256];
          memset(kbdState, 0, sizeof(kbdState));
          return !!kbdState[mVirtualKeyCode];
        // If there is no virtual keycode for the command, we dispatch both
        // keydown and keyup events from WM_APPCOMMAND handler.  Therefore,
        // even if WM_APPCOMMAND is caused by auto key repeat, web apps receive
        // a pair of DOM keydown and keyup events.  I.e., KeyboardEvent.repeat
        // should be never true of such keys.
        return false;
        return false;

  UINT GetScanCodeWithExtendedFlag() const;

  // The result is one of nsIDOMKeyEvent::DOM_KEY_LOCATION_*.
  uint32_t GetKeyLocation() const;

   * "Kakutei-Undo" of ATOK or WXG (both of them are Japanese IME) causes
   * strange WM_KEYDOWN/WM_KEYUP/WM_CHAR message pattern.  So, when this
   * returns true, the caller needs to be careful for processing the messages.
  bool IsIMEDoingKakuteiUndo() const;

  bool IsKeyDownMessage() const
    return (mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN);
  bool IsKeyUpMessage() const
    return (mMsg.message == WM_KEYUP || mMsg.message == WM_SYSKEYUP);
  bool IsPrintableCharMessage(const MSG& aMSG) const
    return IsPrintableCharMessage(aMSG.message);
  bool IsPrintableCharMessage(UINT aMessage) const
    return (aMessage == WM_CHAR || aMessage == WM_SYSCHAR);
  bool IsCharMessage(const MSG& aMSG) const
    return IsCharMessage(aMSG.message);
  bool IsCharMessage(UINT aMessage) const
    return (IsPrintableCharMessage(aMessage) || IsDeadCharMessage(aMessage));
  bool IsDeadCharMessage(const MSG& aMSG) const
    return IsDeadCharMessage(aMSG.message);
  bool IsDeadCharMessage(UINT aMessage) const
    return (aMessage == WM_DEADCHAR || aMessage == WM_SYSDEADCHAR);
  bool IsSysCharMessage(const MSG& aMSG) const
    return IsSysCharMessage(aMSG.message);
  bool IsSysCharMessage(UINT aMessage) const
    return (aMessage == WM_SYSCHAR || aMessage == WM_SYSDEADCHAR);
  bool MayBeSameCharMessage(const MSG& aCharMsg1, const MSG& aCharMsg2) const;
  bool IsFollowedByDeadCharMessage() const;

   * GetFollowingCharMessage() returns following char message of handling
   * keydown event.  If the message is found, this method returns true.
   * Otherwise, returns false.
   * WARNING: Even if this returns true, aCharMsg may be WM_NULL or its
   *          hwnd may be different window.
  bool GetFollowingCharMessage(MSG& aCharMsg) const;

   * Whether the key event can compute virtual keycode from the scancode value.
  bool CanComputeVirtualKeyCodeFromScanCode() const;

   * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK.
  uint8_t ComputeVirtualKeyCodeFromScanCode() const;

   * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK_EX.
  uint8_t ComputeVirtualKeyCodeFromScanCodeEx() const;

   * Wraps MapVirtualKeyEx() with MAPVK_VK_TO_VSC_EX or MAPVK_VK_TO_VSC.
  uint16_t ComputeScanCodeExFromVirtualKeyCode(UINT aVirtualKeyCode) const;

   * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK and MAPVK_VK_TO_CHAR.
  char16_t ComputeUnicharFromScanCode() const;

   * Initializes the aKeyEvent with the information stored in the instance.
  nsEventStatus InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
                             const ModifierKeyState& aModKeyState,
                             const MSG* aMsgSentToPlugin = nullptr) const;
  nsEventStatus InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
                             const MSG* aMsgSentToPlugin = nullptr) const;

   * Dispatches a command event for aEventCommand.
   * Returns true if the event is consumed.  Otherwise, false.
  bool DispatchCommandEvent(uint32_t aEventCommand) const;

   * DispatchKeyPressEventsWithoutCharMessage() dispatches keypress event(s)
   * without char messages.  So, this should be used only when there are no
   * following char messages.
  bool DispatchKeyPressEventsWithoutCharMessage() const;

   * Remove all following WM_CHAR, WM_SYSCHAR and WM_DEADCHAR messages for the
   * WM_KEYDOWN or WM_SYSKEYDOWN message.  Additionally, dispatches plugin
   * events if it's necessary.
   * Returns true if the widget is destroyed.  Otherwise, false.
  bool DispatchPluginEventsAndDiscardsCharMessages() const;

   * DispatchKeyPressEventForFollowingCharMessage() dispatches keypress event
   * for following WM_*CHAR message which is removed and set to aCharMsg.
   * Returns true if the event is consumed.  Otherwise, false.
  bool DispatchKeyPressEventForFollowingCharMessage(const MSG& aCharMsg) const;

   * Checkes whether the key event down message is handled without following
   * WM_CHAR messages.  For example, if following WM_CHAR message indicates
   * control character input, the WM_CHAR message is unclear whether it's
   * caused by a printable key with Ctrl or just a function key such as Enter
   * or Backspace.
  bool NeedsToHandleWithoutFollowingCharMessages() const;

   * ComputeInputtingStringWithKeyboardLayout() computes string to be inputted
   * with the key and the modifier state, without shift state and with shift
   * state.
  void ComputeInputtingStringWithKeyboardLayout();

class KeyboardLayout
  friend class NativeKey;


  static KeyboardLayout* sInstance;
  static nsIIdleServiceInternal* sIdleService;

  struct DeadKeyTableListEntry
    DeadKeyTableListEntry* next;
    uint8_t data[1];

  HKL mKeyboardLayout;

  VirtualKey mVirtualKeys[NS_NUM_OF_KEYS];
  DeadKeyTableListEntry* mDeadKeyTableListHead;
  int32_t mActiveDeadKey;                 // -1 = no active dead-key
  VirtualKey::ShiftState mDeadKeyShiftState;

  bool mIsOverridden : 1;
  bool mIsPendingToRestoreKeyboardLayout : 1;

  static inline int32_t GetKeyIndex(uint8_t aVirtualKey);
  static int CompareDeadKeyEntries(const void* aArg1, const void* aArg2,
                                   void* aData);
  static bool AddDeadKeyEntry(char16_t aBaseChar, char16_t aCompositeChar,
                                DeadKeyEntry* aDeadKeyArray, uint32_t aEntries);
  bool EnsureDeadKeyActive(bool aIsActive, uint8_t aDeadKey,
                             const PBYTE aDeadKeyKbdState);
  uint32_t GetDeadKeyCombinations(uint8_t aDeadKey,
                                  const PBYTE aDeadKeyKbdState,
                                  uint16_t aShiftStatesWithBaseChars,
                                  DeadKeyEntry* aDeadKeyArray,
                                  uint32_t aMaxEntries);
  void DeactivateDeadKeyState();
  const DeadKeyTable* AddDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
                                      uint32_t aEntries);
  void ReleaseDeadKeyTables();

   * Loads the specified keyboard layout. This method always clear the dead key
   * state.
  void LoadLayout(HKL aLayout);

   * InitNativeKey() must be called when actually widget receives WM_KEYDOWN or
   * WM_KEYUP.  This method is stateful.  This saves current dead key state at
   * WM_KEYDOWN.  Additionally, computes current inputted character(s) and set
   * them to the aNativeKey.
  void InitNativeKey(NativeKey& aNativeKey,
                     const ModifierKeyState& aModKeyState);

  static KeyboardLayout* GetInstance();
  static void Shutdown();
  static void NotifyIdleServiceOfUserActivity();

  static bool IsPrintableCharKey(uint8_t aVirtualKey);

   * IsDeadKey() returns true if aVirtualKey is a dead key with aModKeyState.
   * This method isn't stateful.
  bool IsDeadKey(uint8_t aVirtualKey,
                 const ModifierKeyState& aModKeyState) const;

   * GetUniCharsAndModifiers() returns characters which is inputted by the
   * aVirtualKey with aModKeyState.  This method isn't stateful.
  UniCharsAndModifiers GetUniCharsAndModifiers(
                         uint8_t aVirtualKey,
                         const ModifierKeyState& aModKeyState) const;

   * OnLayoutChange() must be called before the first keydown message is
   * received.  LoadLayout() changes the keyboard state, that causes breaking
   * dead key state.  Therefore, we need to load the layout before the first
   * keydown message.
  void OnLayoutChange(HKL aKeyboardLayout)

   * OverrideLayout() loads the specified keyboard layout.
  void OverrideLayout(HKL aLayout)
    mIsOverridden = true;

   * RestoreLayout() loads the current keyboard layout of the thread.
  void RestoreLayout()
    mIsOverridden = false;
    mIsPendingToRestoreKeyboardLayout = true;

  uint32_t ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const;

   * ConvertNativeKeyCodeToKeyNameIndex() returns KeyNameIndex value for
   * non-printable keys (except some special keys like space key).
  KeyNameIndex ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const;

   * ConvertScanCodeToCodeNameIndex() returns CodeNameIndex value for
   * the given scan code.  aScanCode can be over 0xE000 since this method
   * doesn't use Windows API.
  static CodeNameIndex ConvertScanCodeToCodeNameIndex(UINT aScanCode);

  HKL GetLayout() const
    return mIsPendingToRestoreKeyboardLayout ? ::GetKeyboardLayout(0) :

   * This wraps MapVirtualKeyEx() API with MAPVK_VK_TO_VSC.
  WORD ComputeScanCodeForVirtualKeyCode(uint8_t aVirtualKeyCode) const;

   * Implementation of nsIWidget::SynthesizeNativeKeyEvent().
  nsresult SynthesizeNativeKeyEvent(nsWindowBase* aWidget,
                                    int32_t aNativeKeyboardLayout,
                                    int32_t aNativeKeyCode,
                                    uint32_t aModifierFlags,
                                    const nsAString& aCharacters,
                                    const nsAString& aUnmodifiedCharacters);

class RedirectedKeyDownMessageManager
   * If a window receives WM_KEYDOWN message or WM_SYSKEYDOWM message which is
   * a redirected message, NativeKey::DispatchKeyDownAndKeyPressEvent()
   * prevents to dispatch eKeyDown event because it has been dispatched
   * before the message was redirected.  However, in some cases, WM_*KEYDOWN
   * message handler may not handle actually.  Then, the message handler needs
   * to forget the redirected message and remove WM_CHAR message or WM_SYSCHAR
   * message for the redirected keydown message.  AutoFlusher class is a helper
   * class for doing it.  This must be created in the stack.
  class MOZ_STACK_CLASS AutoFlusher final
    AutoFlusher(nsWindowBase* aWidget, const MSG &aMsg) :
      mWidget(aWidget), mMsg(aMsg)

      if (mCancel) {
      // Prevent unnecessary keypress event
      if (!mWidget->Destroyed()) {
      // Foreget the redirected message

    void Cancel() { mCancel = true; }

    bool mCancel;
    RefPtr<nsWindowBase> mWidget;
    const MSG &mMsg;

  static void WillRedirect(const MSG& aMsg, bool aDefualtPrevented)
    sRedirectedKeyDownMsg = aMsg;
    sDefaultPreventedOfRedirectedMsg = aDefualtPrevented;

  static void Forget()
    sRedirectedKeyDownMsg.message = WM_NULL;

  static void PreventDefault() { sDefaultPreventedOfRedirectedMsg = true; }
  static bool DefaultPrevented() { return sDefaultPreventedOfRedirectedMsg; }

  static bool IsRedirectedMessage(const MSG& aMsg);

   * RemoveNextCharMessage() should be called by WM_KEYDOWN or WM_SYSKEYDOWM
   * message handler.  If there is no WM_(SYS)CHAR message for it, this
   * method does nothing.
   * NOTE: WM_(SYS)CHAR message is posted by TranslateMessage() API which is
   * called in message loop.  So, WM_(SYS)KEYDOWN message should have
   * WM_(SYS)CHAR message in the queue if the keydown event causes character
   * input.
  static void RemoveNextCharMessage(HWND aWnd);

  // sRedirectedKeyDownMsg is WM_KEYDOWN message or WM_SYSKEYDOWN message which
  // is reirected with SendInput() API by
  // widget::NativeKey::DispatchKeyDownAndKeyPressEvent()
  static MSG sRedirectedKeyDownMsg;
  static bool sDefaultPreventedOfRedirectedMsg;

} // namespace widget
} // namespace mozilla