widget/windows/KeyboardLayout.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifndef KeyboardLayout_h__
     7 #define KeyboardLayout_h__
     9 #include "nscore.h"
    10 #include "nsAutoPtr.h"
    11 #include "nsString.h"
    12 #include "nsWindowBase.h"
    13 #include "nsWindowDefs.h"
    14 #include "mozilla/Attributes.h"
    15 #include "mozilla/EventForwards.h"
    16 #include <windows.h>
    18 #define NS_NUM_OF_KEYS          70
    20 #define VK_OEM_1                0xBA   // ';:' for US
    21 #define VK_OEM_PLUS             0xBB   // '+' any country
    22 #define VK_OEM_COMMA            0xBC
    23 #define VK_OEM_MINUS            0xBD   // '-' any country
    24 #define VK_OEM_PERIOD           0xBE
    25 #define VK_OEM_2                0xBF
    26 #define VK_OEM_3                0xC0
    27 // '/?' for Brazilian (ABNT)
    28 #define VK_ABNT_C1              0xC1
    29 // Separator in Numpad for Brazilian (ABNT) or JIS keyboard for Mac.
    30 #define VK_ABNT_C2              0xC2
    31 #define VK_OEM_4                0xDB
    32 #define VK_OEM_5                0xDC
    33 #define VK_OEM_6                0xDD
    34 #define VK_OEM_7                0xDE
    35 #define VK_OEM_8                0xDF
    36 #define VK_OEM_102              0xE2
    37 #define VK_OEM_CLEAR            0xFE
    39 class nsIIdleServiceInternal;
    40 struct nsModifierKeyState;
    42 namespace mozilla {
    43 namespace widget {
    45 static const uint32_t sModifierKeyMap[][3] = {
    46   { nsIWidget::CAPS_LOCK, VK_CAPITAL, 0 },
    47   { nsIWidget::NUM_LOCK,  VK_NUMLOCK, 0 },
    48   { nsIWidget::SHIFT_L,   VK_SHIFT,   VK_LSHIFT },
    49   { nsIWidget::SHIFT_R,   VK_SHIFT,   VK_RSHIFT },
    50   { nsIWidget::CTRL_L,    VK_CONTROL, VK_LCONTROL },
    51   { nsIWidget::CTRL_R,    VK_CONTROL, VK_RCONTROL },
    52   { nsIWidget::ALT_L,     VK_MENU,    VK_LMENU },
    53   { nsIWidget::ALT_R,     VK_MENU,    VK_RMENU }
    54 };
    56 class KeyboardLayout;
    58 class ModifierKeyState
    59 {
    60 public:
    61   ModifierKeyState();
    62   ModifierKeyState(bool aIsShiftDown, bool aIsControlDown, bool aIsAltDown);
    63   ModifierKeyState(Modifiers aModifiers);
    65   MOZ_ALWAYS_INLINE void Update();
    67   MOZ_ALWAYS_INLINE void Unset(Modifiers aRemovingModifiers);
    68   void Set(Modifiers aAddingModifiers);
    70   void InitInputEvent(WidgetInputEvent& aInputEvent) const;
    72   bool IsShift() const;
    73   bool IsControl() const;
    74   MOZ_ALWAYS_INLINE bool IsAlt() const;
    75   MOZ_ALWAYS_INLINE bool IsAltGr() const;
    76   MOZ_ALWAYS_INLINE bool IsWin() const;
    78   MOZ_ALWAYS_INLINE bool IsCapsLocked() const;
    79   MOZ_ALWAYS_INLINE bool IsNumLocked() const;
    80   MOZ_ALWAYS_INLINE bool IsScrollLocked() const;
    82   MOZ_ALWAYS_INLINE Modifiers GetModifiers() const;
    84 private:
    85   Modifiers mModifiers;
    87   MOZ_ALWAYS_INLINE void EnsureAltGr();
    89   void InitMouseEvent(WidgetInputEvent& aMouseEvent) const;
    90 };
    92 struct UniCharsAndModifiers
    93 {
    94   // Dead-key + up to 4 characters
    95   char16_t mChars[5];
    96   Modifiers mModifiers[5];
    97   uint32_t  mLength;
    99   UniCharsAndModifiers() : mLength(0) {}
   100   UniCharsAndModifiers operator+(const UniCharsAndModifiers& aOther) const;
   101   UniCharsAndModifiers& operator+=(const UniCharsAndModifiers& aOther);
   103   /**
   104    * Append a pair of unicode character and the final modifier.
   105    */
   106   void Append(char16_t aUniChar, Modifiers aModifiers);
   107   void Clear() { mLength = 0; }
   108   bool IsEmpty() const { return !mLength; }
   110   void FillModifiers(Modifiers aModifiers);
   112   bool UniCharsEqual(const UniCharsAndModifiers& aOther) const;
   113   bool UniCharsCaseInsensitiveEqual(const UniCharsAndModifiers& aOther) const;
   115   nsString ToString() const { return nsString(mChars, mLength); }
   116 };
   118 struct DeadKeyEntry;
   119 class DeadKeyTable;
   122 class VirtualKey
   123 {
   124 public:
   125   //  0 - Normal
   126   //  1 - Shift
   127   //  2 - Control
   128   //  3 - Control + Shift
   129   //  4 - Alt
   130   //  5 - Alt + Shift
   131   //  6 - Alt + Control (AltGr)
   132   //  7 - Alt + Control + Shift (AltGr + Shift)
   133   //  8 - CapsLock
   134   //  9 - CapsLock + Shift
   135   // 10 - CapsLock + Control
   136   // 11 - CapsLock + Control + Shift
   137   // 12 - CapsLock + Alt
   138   // 13 - CapsLock + Alt + Shift
   139   // 14 - CapsLock + Alt + Control (CapsLock + AltGr)
   140   // 15 - CapsLock + Alt + Control + Shift (CapsLock + AltGr + Shift)
   142   enum ShiftStateFlag
   143   {
   144     STATE_SHIFT    = 0x01,
   145     STATE_CONTROL  = 0x02,
   146     STATE_ALT      = 0x04,
   147     STATE_CAPSLOCK = 0x08
   148   };
   150   typedef uint8_t ShiftState;
   152   static ShiftState ModifiersToShiftState(Modifiers aModifiers);
   153   static Modifiers ShiftStateToModifiers(ShiftState aShiftState);
   155 private:
   156   union KeyShiftState
   157   {
   158     struct
   159     {
   160       char16_t Chars[4];
   161     } Normal;
   162     struct
   163     {
   164       const DeadKeyTable* Table;
   165       char16_t DeadChar;
   166     } DeadKey;
   167   };
   169   KeyShiftState mShiftStates[16];
   170   uint16_t mIsDeadKey;
   172   void SetDeadKey(ShiftState aShiftState, bool aIsDeadKey)
   173   {
   174     if (aIsDeadKey) {
   175       mIsDeadKey |= 1 << aShiftState;
   176     } else {
   177       mIsDeadKey &= ~(1 << aShiftState);
   178     }
   179   }
   181 public:
   182   static void FillKbdState(PBYTE aKbdState, const ShiftState aShiftState);
   184   bool IsDeadKey(ShiftState aShiftState) const
   185   {
   186     return (mIsDeadKey & (1 << aShiftState)) != 0;
   187   }
   189   void AttachDeadKeyTable(ShiftState aShiftState,
   190                           const DeadKeyTable* aDeadKeyTable)
   191   {
   192     mShiftStates[aShiftState].DeadKey.Table = aDeadKeyTable;
   193   }
   195   void SetNormalChars(ShiftState aShiftState, const char16_t* aChars,
   196                       uint32_t aNumOfChars);
   197   void SetDeadChar(ShiftState aShiftState, char16_t aDeadChar);
   198   const DeadKeyTable* MatchingDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
   199                                            uint32_t aEntries) const;
   200   inline char16_t GetCompositeChar(ShiftState aShiftState,
   201                                     char16_t aBaseChar) const;
   202   UniCharsAndModifiers GetNativeUniChars(ShiftState aShiftState) const;
   203   UniCharsAndModifiers GetUniChars(ShiftState aShiftState) const;
   204 };
   206 class MOZ_STACK_CLASS NativeKey
   207 {
   208   friend class KeyboardLayout;
   210 public:
   211   struct FakeCharMsg
   212   {
   213     UINT mCharCode;
   214     UINT mScanCode;
   215     bool mIsDeadKey;
   216     bool mConsumed;
   218     FakeCharMsg() :
   219       mCharCode(0), mScanCode(0), mIsDeadKey(false), mConsumed(false)
   220     {
   221     }
   223     MSG GetCharMsg(HWND aWnd) const
   224     {
   225       MSG msg;
   226       msg.hwnd = aWnd;
   227       msg.message = mIsDeadKey ? WM_DEADCHAR : WM_CHAR;
   228       msg.wParam = static_cast<WPARAM>(mCharCode);
   229       msg.lParam = static_cast<LPARAM>(mScanCode << 16);
   230       msg.time = 0;
   231       msg.pt.x = msg.pt.y = 0;
   232       return msg;
   233     }
   234   };
   236   NativeKey(nsWindowBase* aWidget,
   237             const MSG& aKeyOrCharMessage,
   238             const ModifierKeyState& aModKeyState,
   239             nsTArray<FakeCharMsg>* aFakeCharMsgs = nullptr);
   241   /**
   242    * Handle WM_KEYDOWN message or WM_SYSKEYDOWN message.  The instance must be
   243    * initialized with WM_KEYDOWN or WM_SYSKEYDOWN.
   244    * Returns true if dispatched keydown event or keypress event is consumed.
   245    * Otherwise, false.
   246    */
   247   bool HandleKeyDownMessage(bool* aEventDispatched = nullptr) const;
   249   /**
   250    * Handles WM_CHAR message or WM_SYSCHAR message.  The instance must be
   251    * initialized with WM_KEYDOWN, WM_SYSKEYDOWN or them.
   252    * Returns true if dispatched keypress event is consumed.  Otherwise, false.
   253    */
   254   bool HandleCharMessage(const MSG& aCharMsg,
   255                          bool* aEventDispatched = nullptr) const;
   257   /**
   258    * Handles keyup message.  Returns true if the event is consumed.
   259    * Otherwise, false.
   260    */
   261   bool HandleKeyUpMessage(bool* aEventDispatched = nullptr) const;
   263 private:
   264   nsRefPtr<nsWindowBase> mWidget;
   265   HKL mKeyboardLayout;
   266   MSG mMsg;
   268   uint32_t mDOMKeyCode;
   269   KeyNameIndex mKeyNameIndex;
   271   ModifierKeyState mModKeyState;
   273   // mVirtualKeyCode distinguishes left key or right key of modifier key.
   274   uint8_t mVirtualKeyCode;
   275   // mOriginalVirtualKeyCode doesn't distinguish left key or right key of
   276   // modifier key.  However, if the given keycode is VK_PROCESS, it's resolved
   277   // to a keycode before it's handled by IME.
   278   uint8_t mOriginalVirtualKeyCode;
   280   // mCommittedChars indicates the inputted characters which is committed by
   281   // the key.  If dead key fail to composite a character, mCommittedChars
   282   // indicates both the dead characters and the base characters.
   283   UniCharsAndModifiers mCommittedCharsAndModifiers;
   285   WORD    mScanCode;
   286   bool    mIsExtended;
   287   bool    mIsDeadKey;
   288   // mIsPrintableKey is true if the key may be a printable key without
   289   // any modifier keys.  Otherwise, false.
   290   // Please note that the event may not cause any text input even if this
   291   // is true.  E.g., it might be dead key state or Ctrl key may be pressed.
   292   bool    mIsPrintableKey;
   294   nsTArray<FakeCharMsg>* mFakeCharMsgs;
   296   NativeKey()
   297   {
   298     MOZ_CRASH("The default constructor of NativeKey isn't available");
   299   }
   301   /**
   302    * Returns true if the key event is caused by auto repeat.
   303    */
   304   bool IsRepeat() const
   305   {
   306     switch (mMsg.message) {
   307       case WM_KEYDOWN:
   308       case WM_SYSKEYDOWN:
   309       case WM_CHAR:
   310       case WM_SYSCHAR:
   311       case WM_DEADCHAR:
   312       case WM_SYSDEADCHAR:
   313         return ((mMsg.lParam & (1 << 30)) != 0);
   314       default:
   315         return false;
   316     }
   317   }
   319   UINT GetScanCodeWithExtendedFlag() const;
   321   // The result is one of nsIDOMKeyEvent::DOM_KEY_LOCATION_*.
   322   uint32_t GetKeyLocation() const;
   324   /**
   325    * "Kakutei-Undo" of ATOK or WXG (both of them are Japanese IME) causes
   326    * strange WM_KEYDOWN/WM_KEYUP/WM_CHAR message pattern.  So, when this
   327    * returns true, the caller needs to be careful for processing the messages.
   328    */
   329   bool IsIMEDoingKakuteiUndo() const;
   331   bool IsKeyDownMessage() const
   332   {
   333     return (mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN);
   334   }
   335   bool IsKeyUpMessage() const
   336   {
   337     return (mMsg.message == WM_KEYUP || mMsg.message == WM_SYSKEYUP);
   338   }
   339   bool IsPrintableCharMessage(const MSG& aMSG) const
   340   {
   341     return IsPrintableCharMessage(aMSG.message);
   342   }
   343   bool IsPrintableCharMessage(UINT aMessage) const
   344   {
   345     return (aMessage == WM_CHAR || aMessage == WM_SYSCHAR);
   346   }
   347   bool IsCharMessage(const MSG& aMSG) const
   348   {
   349     return IsCharMessage(aMSG.message);
   350   }
   351   bool IsCharMessage(UINT aMessage) const
   352   {
   353     return (IsPrintableCharMessage(aMessage) || IsDeadCharMessage(aMessage));
   354   }
   355   bool IsDeadCharMessage(const MSG& aMSG) const
   356   {
   357     return IsDeadCharMessage(aMSG.message);
   358   }
   359   bool IsDeadCharMessage(UINT aMessage) const
   360   {
   361     return (aMessage == WM_DEADCHAR || aMessage == WM_SYSDEADCHAR);
   362   }
   363   bool IsSysCharMessage(const MSG& aMSG) const
   364   {
   365     return IsSysCharMessage(aMSG.message);
   366   }
   367   bool IsSysCharMessage(UINT aMessage) const
   368   {
   369     return (aMessage == WM_SYSCHAR || aMessage == WM_SYSDEADCHAR);
   370   }
   371   bool MayBeSameCharMessage(const MSG& aCharMsg1, const MSG& aCharMsg2) const;
   372   bool IsFollowedByDeadCharMessage() const;
   374   /**
   375    * GetFollowingCharMessage() returns following char message of handling
   376    * keydown event.  If the message is found, this method returns true.
   377    * Otherwise, returns false.
   378    *
   379    * WARNING: Even if this returns true, aCharMsg may be WM_NULL or its
   380    *          hwnd may be different window.
   381    */
   382   bool GetFollowingCharMessage(MSG& aCharMsg) const;
   384   /**
   385    * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK.
   386    */
   387   uint8_t ComputeVirtualKeyCodeFromScanCode() const;
   389   /**
   390    * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK_EX.
   391    */
   392   uint8_t ComputeVirtualKeyCodeFromScanCodeEx() const;
   394   /**
   395    * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK and MAPVK_VK_TO_CHAR.
   396    */
   397   char16_t ComputeUnicharFromScanCode() const;
   399   /**
   400    * Initializes the aKeyEvent with the information stored in the instance.
   401    */
   402   void InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
   403                     const ModifierKeyState& aModKeyState) const;
   404   void InitKeyEvent(WidgetKeyboardEvent& aKeyEvent) const;
   406   /**
   407    * Dispatches the key event.  Returns true if the event is consumed.
   408    * Otherwise, false.
   409    */
   410   bool DispatchKeyEvent(WidgetKeyboardEvent& aKeyEvent,
   411                         const MSG* aMsgSentToPlugin = nullptr) const;
   413   /**
   414    * DispatchKeyPressEventsWithKeyboardLayout() dispatches keypress event(s)
   415    * with the information provided by KeyboardLayout class.
   416    */
   417   bool DispatchKeyPressEventsWithKeyboardLayout() const;
   419   /**
   420    * Remove all following WM_CHAR, WM_SYSCHAR and WM_DEADCHAR messages for the
   421    * WM_KEYDOWN or WM_SYSKEYDOWN message.  Additionally, dispatches plugin
   422    * events if it's necessary.
   423    * Returns true if the widget is destroyed.  Otherwise, false.
   424    */
   425   bool DispatchPluginEventsAndDiscardsCharMessages() const;
   427   /**
   428    * DispatchKeyPressEventForFollowingCharMessage() dispatches keypress event
   429    * for following WM_*CHAR message which is removed and set to aCharMsg.
   430    * Returns true if the event is consumed.  Otherwise, false.
   431    */
   432   bool DispatchKeyPressEventForFollowingCharMessage(const MSG& aCharMsg) const;
   434   /**
   435    * Checkes whether the key event down message is handled without following
   436    * WM_CHAR messages.  For example, if following WM_CHAR message indicates
   437    * control character input, the WM_CHAR message is unclear whether it's
   438    * caused by a printable key with Ctrl or just a function key such as Enter
   439    * or Backspace.
   440    */
   441   bool NeedsToHandleWithoutFollowingCharMessages() const;
   442 };
   444 class KeyboardLayout
   445 {
   446   friend class NativeKey;
   448 private:
   449   KeyboardLayout();
   450   ~KeyboardLayout();
   452   static KeyboardLayout* sInstance;
   453   static nsIIdleServiceInternal* sIdleService;
   455   struct DeadKeyTableListEntry
   456   {
   457     DeadKeyTableListEntry* next;
   458     uint8_t data[1];
   459   };
   461   HKL mKeyboardLayout;
   463   VirtualKey mVirtualKeys[NS_NUM_OF_KEYS];
   464   DeadKeyTableListEntry* mDeadKeyTableListHead;
   465   int32_t mActiveDeadKey;                 // -1 = no active dead-key
   466   VirtualKey::ShiftState mDeadKeyShiftState;
   468   bool mIsOverridden : 1;
   469   bool mIsPendingToRestoreKeyboardLayout : 1;
   471   static inline int32_t GetKeyIndex(uint8_t aVirtualKey);
   472   static int CompareDeadKeyEntries(const void* aArg1, const void* aArg2,
   473                                    void* aData);
   474   static bool AddDeadKeyEntry(char16_t aBaseChar, char16_t aCompositeChar,
   475                                 DeadKeyEntry* aDeadKeyArray, uint32_t aEntries);
   476   bool EnsureDeadKeyActive(bool aIsActive, uint8_t aDeadKey,
   477                              const PBYTE aDeadKeyKbdState);
   478   uint32_t GetDeadKeyCombinations(uint8_t aDeadKey,
   479                                   const PBYTE aDeadKeyKbdState,
   480                                   uint16_t aShiftStatesWithBaseChars,
   481                                   DeadKeyEntry* aDeadKeyArray,
   482                                   uint32_t aMaxEntries);
   483   void DeactivateDeadKeyState();
   484   const DeadKeyTable* AddDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
   485                                       uint32_t aEntries);
   486   void ReleaseDeadKeyTables();
   488   /**
   489    * Loads the specified keyboard layout. This method always clear the dead key
   490    * state.
   491    */
   492   void LoadLayout(HKL aLayout);
   494   /**
   495    * InitNativeKey() must be called when actually widget receives WM_KEYDOWN or
   496    * WM_KEYUP.  This method is stateful.  This saves current dead key state at
   497    * WM_KEYDOWN.  Additionally, computes current inputted character(s) and set
   498    * them to the aNativeKey.
   499    */
   500   void InitNativeKey(NativeKey& aNativeKey,
   501                      const ModifierKeyState& aModKeyState);
   503 public:
   504   static KeyboardLayout* GetInstance();
   505   static void Shutdown();
   506   static void NotifyIdleServiceOfUserActivity();
   508   static bool IsPrintableCharKey(uint8_t aVirtualKey);
   510   /**
   511    * IsDeadKey() returns true if aVirtualKey is a dead key with aModKeyState.
   512    * This method isn't stateful.
   513    */
   514   bool IsDeadKey(uint8_t aVirtualKey,
   515                  const ModifierKeyState& aModKeyState) const;
   517   /**
   518    * GetUniCharsAndModifiers() returns characters which is inputted by the
   519    * aVirtualKey with aModKeyState.  This method isn't stateful.
   520    */
   521   UniCharsAndModifiers GetUniCharsAndModifiers(
   522                          uint8_t aVirtualKey,
   523                          const ModifierKeyState& aModKeyState) const;
   525   /**
   526    * OnLayoutChange() must be called before the first keydown message is
   527    * received.  LoadLayout() changes the keyboard state, that causes breaking
   528    * dead key state.  Therefore, we need to load the layout before the first
   529    * keydown message.
   530    */
   531   void OnLayoutChange(HKL aKeyboardLayout)
   532   {
   533     MOZ_ASSERT(!mIsOverridden);
   534     LoadLayout(aKeyboardLayout);
   535   }
   537   /**
   538    * OverrideLayout() loads the specified keyboard layout.
   539    */
   540   void OverrideLayout(HKL aLayout)
   541   {
   542     mIsOverridden = true;
   543     LoadLayout(aLayout);
   544   }
   546   /**
   547    * RestoreLayout() loads the current keyboard layout of the thread.
   548    */
   549   void RestoreLayout()
   550   {
   551     mIsOverridden = false;
   552     mIsPendingToRestoreKeyboardLayout = true;
   553   }
   555   uint32_t ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const;
   557   /**
   558    * ConvertNativeKeyCodeToKeyNameIndex() returns KeyNameIndex value for
   559    * non-printable keys (except some special keys like space key).
   560    */
   561   KeyNameIndex ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const;
   563   HKL GetLayout() const
   564   {
   565     return mIsPendingToRestoreKeyboardLayout ? ::GetKeyboardLayout(0) :
   566                                                mKeyboardLayout;
   567   }
   569   /**
   570    * This wraps MapVirtualKeyEx() API with MAPVK_VK_TO_VSC.
   571    */
   572   WORD ComputeScanCodeForVirtualKeyCode(uint8_t aVirtualKeyCode) const;
   574   /**
   575    * Implementation of nsIWidget::SynthesizeNativeKeyEvent().
   576    */
   577   nsresult SynthesizeNativeKeyEvent(nsWindowBase* aWidget,
   578                                     int32_t aNativeKeyboardLayout,
   579                                     int32_t aNativeKeyCode,
   580                                     uint32_t aModifierFlags,
   581                                     const nsAString& aCharacters,
   582                                     const nsAString& aUnmodifiedCharacters);
   583 };
   585 class RedirectedKeyDownMessageManager
   586 {
   587 public:
   588   /*
   589    * If a window receives WM_KEYDOWN message or WM_SYSKEYDOWM message which is
   590    * a redirected message, NativeKey::DispatchKeyDownAndKeyPressEvent()
   591    * prevents to dispatch NS_KEY_DOWN event because it has been dispatched
   592    * before the message was redirected.  However, in some cases, WM_*KEYDOWN
   593    * message handler may not handle actually.  Then, the message handler needs
   594    * to forget the redirected message and remove WM_CHAR message or WM_SYSCHAR
   595    * message for the redirected keydown message.  AutoFlusher class is a helper
   596    * class for doing it.  This must be created in the stack.
   597    */
   598   class MOZ_STACK_CLASS AutoFlusher MOZ_FINAL
   599   {
   600   public:
   601     AutoFlusher(nsWindowBase* aWidget, const MSG &aMsg) :
   602       mCancel(!RedirectedKeyDownMessageManager::IsRedirectedMessage(aMsg)),
   603       mWidget(aWidget), mMsg(aMsg)
   604     {
   605     }
   607     ~AutoFlusher()
   608     {
   609       if (mCancel) {
   610         return;
   611       }
   612       // Prevent unnecessary keypress event
   613       if (!mWidget->Destroyed()) {
   614         RedirectedKeyDownMessageManager::RemoveNextCharMessage(mMsg.hwnd);
   615       }
   616       // Foreget the redirected message
   617       RedirectedKeyDownMessageManager::Forget();
   618     }
   620     void Cancel() { mCancel = true; }
   622   private:
   623     bool mCancel;
   624     nsRefPtr<nsWindowBase> mWidget;
   625     const MSG &mMsg;
   626   };
   628   static void WillRedirect(const MSG& aMsg, bool aDefualtPrevented)
   629   {
   630     sRedirectedKeyDownMsg = aMsg;
   631     sDefaultPreventedOfRedirectedMsg = aDefualtPrevented;
   632   }
   634   static void Forget()
   635   {
   636     sRedirectedKeyDownMsg.message = WM_NULL;
   637   }
   639   static void PreventDefault() { sDefaultPreventedOfRedirectedMsg = true; }
   640   static bool DefaultPrevented() { return sDefaultPreventedOfRedirectedMsg; }
   642   static bool IsRedirectedMessage(const MSG& aMsg);
   644   /**
   645    * RemoveNextCharMessage() should be called by WM_KEYDOWN or WM_SYSKEYDOWM
   646    * message handler.  If there is no WM_(SYS)CHAR message for it, this
   647    * method does nothing.
   648    * NOTE: WM_(SYS)CHAR message is posted by TranslateMessage() API which is
   649    * called in message loop.  So, WM_(SYS)KEYDOWN message should have
   650    * WM_(SYS)CHAR message in the queue if the keydown event causes character
   651    * input.
   652    */
   653   static void RemoveNextCharMessage(HWND aWnd);
   655 private:
   656   // sRedirectedKeyDownMsg is WM_KEYDOWN message or WM_SYSKEYDOWN message which
   657   // is reirected with SendInput() API by
   658   // widget::NativeKey::DispatchKeyDownAndKeyPressEvent()
   659   static MSG sRedirectedKeyDownMsg;
   660   static bool sDefaultPreventedOfRedirectedMsg;
   661 };
   663 } // namespace widget
   664 } // namespace mozilla
   666 #endif

mercurial