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/. */
5 
6 #ifndef KeyboardLayout_h__
7 #define KeyboardLayout_h__
8 
9 #include "mozilla/RefPtr.h"
10 #include "nscore.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 "mozilla/TextEventDispatcher.h"
17 #include "mozilla/widget/WinMessages.h"
18 #include "mozilla/widget/WinModifierKeyState.h"
19 #include <windows.h>
20 
21 #define NS_NUM_OF_KEYS 70
22 
23 #define VK_OEM_1 0xBA     // ';:' for US
24 #define VK_OEM_PLUS 0xBB  // '+' any country
25 #define VK_OEM_COMMA 0xBC
26 #define VK_OEM_MINUS 0xBD  // '-' any country
27 #define VK_OEM_PERIOD 0xBE
28 #define VK_OEM_2 0xBF
29 #define VK_OEM_3 0xC0
30 // '/?' for Brazilian (ABNT)
31 #define VK_ABNT_C1 0xC1
32 // Separator in Numpad for Brazilian (ABNT) or JIS keyboard for Mac.
33 #define VK_ABNT_C2 0xC2
34 #define VK_OEM_4 0xDB
35 #define VK_OEM_5 0xDC
36 #define VK_OEM_6 0xDD
37 #define VK_OEM_7 0xDE
38 #define VK_OEM_8 0xDF
39 #define VK_OEM_102 0xE2
40 #define VK_OEM_CLEAR 0xFE
41 
42 class nsIIdleServiceInternal;
43 
44 namespace mozilla {
45 namespace widget {
46 
47 static const uint32_t sModifierKeyMap[][3] = {
48     {nsIWidget::CAPS_LOCK, VK_CAPITAL, 0},
49     {nsIWidget::NUM_LOCK, VK_NUMLOCK, 0},
50     {nsIWidget::SHIFT_L, VK_SHIFT, VK_LSHIFT},
51     {nsIWidget::SHIFT_R, VK_SHIFT, VK_RSHIFT},
52     {nsIWidget::CTRL_L, VK_CONTROL, VK_LCONTROL},
53     {nsIWidget::CTRL_R, VK_CONTROL, VK_RCONTROL},
54     {nsIWidget::ALT_L, VK_MENU, VK_LMENU},
55     {nsIWidget::ALT_R, VK_MENU, VK_RMENU}};
56 
57 class KeyboardLayout;
58 
59 class MOZ_STACK_CLASS UniCharsAndModifiers final {
60  public:
UniCharsAndModifiers()61   UniCharsAndModifiers() {}
62   UniCharsAndModifiers operator+(const UniCharsAndModifiers& aOther) const;
63   UniCharsAndModifiers& operator+=(const UniCharsAndModifiers& aOther);
64 
65   /**
66    * Append a pair of unicode character and the final modifier.
67    */
68   void Append(char16_t aUniChar, Modifiers aModifiers);
Clear()69   void Clear() {
70     mChars.Truncate();
71     mModifiers.Clear();
72   }
IsEmpty()73   bool IsEmpty() const {
74     MOZ_ASSERT(mChars.Length() == mModifiers.Length());
75     return mChars.IsEmpty();
76   }
77 
CharAt(size_t aIndex)78   char16_t CharAt(size_t aIndex) const {
79     MOZ_ASSERT(aIndex < Length());
80     return mChars[aIndex];
81   }
ModifiersAt(size_t aIndex)82   Modifiers ModifiersAt(size_t aIndex) const {
83     MOZ_ASSERT(aIndex < Length());
84     return mModifiers[aIndex];
85   }
Length()86   size_t Length() const {
87     MOZ_ASSERT(mChars.Length() == mModifiers.Length());
88     return mChars.Length();
89   }
90 
91   void FillModifiers(Modifiers aModifiers);
92   /**
93    * OverwriteModifiersIfBeginsWith() assigns mModifiers with aOther between
94    * [0] and [aOther.mLength - 1] only when mChars begins with aOther.mChars.
95    */
96   void OverwriteModifiersIfBeginsWith(const UniCharsAndModifiers& aOther);
97 
98   bool UniCharsEqual(const UniCharsAndModifiers& aOther) const;
99   bool UniCharsCaseInsensitiveEqual(const UniCharsAndModifiers& aOther) const;
100   bool BeginsWith(const UniCharsAndModifiers& aOther) const;
101 
ToString()102   const nsString& ToString() const { return mChars; }
103 
104  private:
105   nsAutoString mChars;
106   // 5 is enough number for normal keyboard layout handling.  On Windows,
107   // a dead key sequence may cause inputting up to 5 characters per key press.
108   AutoTArray<Modifiers, 5> mModifiers;
109 };
110 
111 struct DeadKeyEntry {
112   char16_t BaseChar;
113   char16_t CompositeChar;
114 };
115 
116 class DeadKeyTable {
117   friend class KeyboardLayout;
118 
119   uint16_t mEntries;
120   // KeyboardLayout::AddDeadKeyTable() will allocate as many entries as
121   // required.  It is the only way to create new DeadKeyTable instances.
122   DeadKeyEntry mTable[1];
123 
Init(const DeadKeyEntry * aDeadKeyArray,uint32_t aEntries)124   void Init(const DeadKeyEntry* aDeadKeyArray, uint32_t aEntries) {
125     mEntries = aEntries;
126     memcpy(mTable, aDeadKeyArray, aEntries * sizeof(DeadKeyEntry));
127   }
128 
SizeInBytes(uint32_t aEntries)129   static uint32_t SizeInBytes(uint32_t aEntries) {
130     return offsetof(DeadKeyTable, mTable) + aEntries * sizeof(DeadKeyEntry);
131   }
132 
133  public:
Entries()134   uint32_t Entries() const { return mEntries; }
135 
IsEqual(const DeadKeyEntry * aDeadKeyArray,uint32_t aEntries)136   bool IsEqual(const DeadKeyEntry* aDeadKeyArray, uint32_t aEntries) const {
137     return (mEntries == aEntries &&
138             !memcmp(mTable, aDeadKeyArray, aEntries * sizeof(DeadKeyEntry)));
139   }
140 
141   char16_t GetCompositeChar(char16_t aBaseChar) const;
142 };
143 
144 class VirtualKey {
145  public:
146   //  0 - Normal
147   //  1 - Shift
148   //  2 - Control
149   //  3 - Control + Shift
150   //  4 - Alt
151   //  5 - Alt + Shift
152   //  6 - Alt + Control (AltGr)
153   //  7 - Alt + Control + Shift (AltGr + Shift)
154   //  8 - CapsLock
155   //  9 - CapsLock + Shift
156   // 10 - CapsLock + Control
157   // 11 - CapsLock + Control + Shift
158   // 12 - CapsLock + Alt
159   // 13 - CapsLock + Alt + Shift
160   // 14 - CapsLock + Alt + Control (CapsLock + AltGr)
161   // 15 - CapsLock + Alt + Control + Shift (CapsLock + AltGr + Shift)
162 
163   enum ShiftStateFlag {
164     STATE_SHIFT = 0x01,
165     STATE_CONTROL = 0x02,
166     STATE_ALT = 0x04,
167     STATE_CAPSLOCK = 0x08
168   };
169 
170   typedef uint8_t ShiftState;
171 
172   static ShiftState ModifiersToShiftState(Modifiers aModifiers);
ModifierKeyStateToShiftState(const ModifierKeyState & aModKeyState)173   static ShiftState ModifierKeyStateToShiftState(
174       const ModifierKeyState& aModKeyState) {
175     return ModifiersToShiftState(aModKeyState.GetModifiers());
176   }
177   static Modifiers ShiftStateToModifiers(ShiftState aShiftState);
178 
179  private:
180   union KeyShiftState {
181     struct {
182       char16_t Chars[4];
183     } Normal;
184     struct {
185       const DeadKeyTable* Table;
186       char16_t DeadChar;
187     } DeadKey;
188   };
189 
190   KeyShiftState mShiftStates[16];
191   uint16_t mIsDeadKey;
192 
SetDeadKey(ShiftState aShiftState,bool aIsDeadKey)193   void SetDeadKey(ShiftState aShiftState, bool aIsDeadKey) {
194     if (aIsDeadKey) {
195       mIsDeadKey |= 1 << aShiftState;
196     } else {
197       mIsDeadKey &= ~(1 << aShiftState);
198     }
199   }
200 
201  public:
202   static void FillKbdState(PBYTE aKbdState, const ShiftState aShiftState);
203 
IsDeadKey(ShiftState aShiftState)204   bool IsDeadKey(ShiftState aShiftState) const {
205     return (mIsDeadKey & (1 << aShiftState)) != 0;
206   }
207 
AttachDeadKeyTable(ShiftState aShiftState,const DeadKeyTable * aDeadKeyTable)208   void AttachDeadKeyTable(ShiftState aShiftState,
209                           const DeadKeyTable* aDeadKeyTable) {
210     mShiftStates[aShiftState].DeadKey.Table = aDeadKeyTable;
211   }
212 
213   void SetNormalChars(ShiftState aShiftState, const char16_t* aChars,
214                       uint32_t aNumOfChars);
215   void SetDeadChar(ShiftState aShiftState, char16_t aDeadChar);
216   const DeadKeyTable* MatchingDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
217                                            uint32_t aEntries) const;
GetCompositeChar(ShiftState aShiftState,char16_t aBaseChar)218   inline char16_t GetCompositeChar(ShiftState aShiftState,
219                                    char16_t aBaseChar) const {
220     return mShiftStates[aShiftState].DeadKey.Table->GetCompositeChar(aBaseChar);
221   }
222 
GetCompositeChar(const ModifierKeyState & aModKeyState,char16_t aBaseChar)223   char16_t GetCompositeChar(const ModifierKeyState& aModKeyState,
224                             char16_t aBaseChar) const {
225     return GetCompositeChar(ModifierKeyStateToShiftState(aModKeyState),
226                             aBaseChar);
227   }
228   UniCharsAndModifiers GetNativeUniChars(ShiftState aShiftState) const;
GetNativeUniChars(const ModifierKeyState & aModKeyState)229   UniCharsAndModifiers GetNativeUniChars(
230       const ModifierKeyState& aModKeyState) const {
231     return GetNativeUniChars(ModifierKeyStateToShiftState(aModKeyState));
232   }
233   UniCharsAndModifiers GetUniChars(ShiftState aShiftState) const;
GetUniChars(const ModifierKeyState & aModKeyState)234   UniCharsAndModifiers GetUniChars(const ModifierKeyState& aModKeyState) const {
235     return GetUniChars(ModifierKeyStateToShiftState(aModKeyState));
236   }
237 };
238 
239 class MOZ_STACK_CLASS NativeKey final {
240   friend class KeyboardLayout;
241 
242  public:
243   struct FakeCharMsg {
244     UINT mCharCode;
245     UINT mScanCode;
246     bool mIsSysKey;
247     bool mIsDeadKey;
248     bool mConsumed;
249 
FakeCharMsgFakeCharMsg250     FakeCharMsg()
251         : mCharCode(0),
252           mScanCode(0),
253           mIsSysKey(false),
254           mIsDeadKey(false),
255           mConsumed(false) {}
256 
GetCharMsgFakeCharMsg257     MSG GetCharMsg(HWND aWnd) const {
258       MSG msg;
259       msg.hwnd = aWnd;
260       msg.message =
261           mIsDeadKey && mIsSysKey
262               ? WM_SYSDEADCHAR
263               : mIsDeadKey ? WM_DEADCHAR : mIsSysKey ? WM_SYSCHAR : WM_CHAR;
264       msg.wParam = static_cast<WPARAM>(mCharCode);
265       msg.lParam = static_cast<LPARAM>(mScanCode << 16);
266       msg.time = 0;
267       msg.pt.x = msg.pt.y = 0;
268       return msg;
269     }
270   };
271 
272   NativeKey(nsWindowBase* aWidget, const MSG& aMessage,
273             const ModifierKeyState& aModKeyState,
274             HKL aOverrideKeyboardLayout = 0,
275             nsTArray<FakeCharMsg>* aFakeCharMsgs = nullptr);
276 
277   ~NativeKey();
278 
279   /**
280    * Handle WM_KEYDOWN message or WM_SYSKEYDOWN message.  The instance must be
281    * initialized with WM_KEYDOWN or WM_SYSKEYDOWN.
282    * Returns true if dispatched keydown event or keypress event is consumed.
283    * Otherwise, false.
284    */
285   bool HandleKeyDownMessage(bool* aEventDispatched = nullptr) const;
286 
287   /**
288    * Handles WM_CHAR message or WM_SYSCHAR message.  The instance must be
289    * initialized with them.
290    * Returns true if dispatched keypress event is consumed.  Otherwise, false.
291    */
292   bool HandleCharMessage(bool* aEventDispatched = nullptr) const;
293 
294   /**
295    * Handles keyup message.  Returns true if the event is consumed.
296    * Otherwise, false.
297    */
298   bool HandleKeyUpMessage(bool* aEventDispatched = nullptr) const;
299 
300   /**
301    * Handles WM_APPCOMMAND message.  Returns true if the event is consumed.
302    * Otherwise, false.
303    */
304   bool HandleAppCommandMessage() const;
305 
306   /**
307    * Callback of TextEventDispatcherListener::WillDispatchKeyboardEvent().
308    * This method sets alternative char codes of aKeyboardEvent.
309    */
310   void WillDispatchKeyboardEvent(WidgetKeyboardEvent& aKeyboardEvent,
311                                  uint32_t aIndex);
312 
313   /**
314    * Returns true if aChar is a control character which shouldn't be inputted
315    * into focused text editor.
316    */
317   static bool IsControlChar(char16_t aChar);
318 
319  private:
320   NativeKey* mLastInstance;
321   // mRemovingMsg is set at removing a char message from
322   // GetFollowingCharMessage().
323   MSG mRemovingMsg;
324   // mReceivedMsg is set when another instance starts to handle the message
325   // unexpectedly.
326   MSG mReceivedMsg;
327   RefPtr<nsWindowBase> mWidget;
328   RefPtr<TextEventDispatcher> mDispatcher;
329   HKL mKeyboardLayout;
330   MSG mMsg;
331   // mFollowingCharMsgs stores WM_CHAR, WM_SYSCHAR, WM_DEADCHAR or
332   // WM_SYSDEADCHAR message which follows WM_KEYDOWN.
333   // Note that the stored messaged are already removed from the queue.
334   // FYI: 5 is enough number for usual keyboard layout handling.  On Windows,
335   // a dead key sequence may cause inputting up to 5 characters per key press.
336   AutoTArray<MSG, 5> mFollowingCharMsgs;
337   // mRemovedOddCharMsgs stores WM_CHAR messages which are caused by ATOK or
338   // WXG (they are Japanese IME) when the user tries to do "Kakutei-undo"
339   // (it means "undo the last commit").
340   nsTArray<MSG> mRemovedOddCharMsgs;
341   // If dispatching eKeyDown or eKeyPress event causes focus change,
342   // the instance shouldn't handle remaning char messages.  For checking it,
343   // this should store first focused window.
344   HWND mFocusedWndBeforeDispatch;
345 
346   uint32_t mDOMKeyCode;
347   KeyNameIndex mKeyNameIndex;
348   CodeNameIndex mCodeNameIndex;
349 
350   ModifierKeyState mModKeyState;
351 
352   // mVirtualKeyCode distinguishes left key or right key of modifier key.
353   uint8_t mVirtualKeyCode;
354   // mOriginalVirtualKeyCode doesn't distinguish left key or right key of
355   // modifier key.  However, if the given keycode is VK_PROCESS, it's resolved
356   // to a keycode before it's handled by IME.
357   uint8_t mOriginalVirtualKeyCode;
358 
359   // mCommittedChars indicates the inputted characters which is committed by
360   // the key.  If dead key fail to composite a character, mCommittedChars
361   // indicates both the dead characters and the base characters.
362   UniCharsAndModifiers mCommittedCharsAndModifiers;
363 
364   // Following strings are computed by
365   // ComputeInputtingStringWithKeyboardLayout() which is typically called
366   // before dispatching keydown event.
367   // mInputtingStringAndModifiers's string is the string to be
368   // inputted into the focused editor and its modifier state is proper
369   // modifier state for inputting the string into the editor.
370   UniCharsAndModifiers mInputtingStringAndModifiers;
371   // mShiftedString is the string to be inputted into the editor with
372   // current modifier state with active shift state.
373   UniCharsAndModifiers mShiftedString;
374   // mUnshiftedString is the string to be inputted into the editor with
375   // current modifier state without shift state.
376   UniCharsAndModifiers mUnshiftedString;
377   // Following integers are computed by
378   // ComputeInputtingStringWithKeyboardLayout() which is typically called
379   // before dispatching keydown event.  The meaning of these values is same
380   // as charCode.
381   uint32_t mShiftedLatinChar;
382   uint32_t mUnshiftedLatinChar;
383 
384   WORD mScanCode;
385   bool mIsExtended;
386   // mIsRepeat is true if the key message is caused by the auto-repeat
387   // feature.
388   bool mIsRepeat;
389   bool mIsDeadKey;
390   // mIsPrintableKey is true if the key may be a printable key without
391   // any modifier keys.  Otherwise, false.
392   // Please note that the event may not cause any text input even if this
393   // is true.  E.g., it might be dead key state or Ctrl key may be pressed.
394   bool mIsPrintableKey;
395   // mIsSkippableInRemoteProcess is false if the key event shouldn't be
396   // skipped in the remote process even if it's too old event.
397   bool mIsSkippableInRemoteProcess;
398   // mCharMessageHasGone is true if the message is a keydown message and
399   // it's followed by at least one char message but it's gone at removing
400   // from the queue.  This could occur if PeekMessage() or something is
401   // hooked by odd tool.
402   bool mCharMessageHasGone;
403   // mIsOverridingKeyboardLayout is true if the instance temporarily overriding
404   // keyboard layout with specified by the constructor.
405   bool mIsOverridingKeyboardLayout;
406   // mCanIgnoreModifierStateAtKeyPress is true if it's allowed to remove
407   // Ctrl or Alt modifier state at dispatching eKeyPress.
408   bool mCanIgnoreModifierStateAtKeyPress;
409 
410   nsTArray<FakeCharMsg>* mFakeCharMsgs;
411 
412   // When a keydown event is dispatched at handling WM_APPCOMMAND, the computed
413   // virtual keycode is set to this.  Even if we consume WM_APPCOMMAND message,
414   // Windows may send WM_KEYDOWN and WM_KEYUP message for them.
415   // At that time, we should not dispatch key events for them.
416   static uint8_t sDispatchedKeyOfAppCommand;
417 
NativeKey()418   NativeKey() {
419     MOZ_CRASH("The default constructor of NativeKey isn't available");
420   }
421 
422   void InitWithAppCommand();
423   void InitWithKeyOrChar();
424 
425   /**
426    * InitIsSkippableForKeyOrChar() initializes mIsSkippableInRemoteProcess with
427    * mIsRepeat and previous key message information.  So, this must be called
428    * after mIsRepeat is initialized.
429    */
430   void InitIsSkippableForKeyOrChar(const MSG& aLastKeyMSG);
431 
432   /**
433    * InitCommittedCharsAndModifiersWithFollowingCharMessages() initializes
434    * mCommittedCharsAndModifiers with mFollowingCharMsgs and aModKeyState.
435    * If mFollowingCharMsgs includes non-printable char messages, they are
436    * ignored (skipped).
437    */
438   void InitCommittedCharsAndModifiersWithFollowingCharMessages(
439       const ModifierKeyState& aModKeyState);
440 
441   UINT GetScanCodeWithExtendedFlag() const;
442 
443   // The result is one of eKeyLocation*.
444   uint32_t GetKeyLocation() const;
445 
446   /**
447    * RemoveFollowingOddCharMessages() removes odd WM_CHAR messages from the
448    * queue when IsIMEDoingKakuteiUndo() returns true.
449    */
450   void RemoveFollowingOddCharMessages();
451 
452   /**
453    * "Kakutei-Undo" of ATOK or WXG (both of them are Japanese IME) causes
454    * strange WM_KEYDOWN/WM_KEYUP/WM_CHAR message pattern.  So, when this
455    * returns true, the caller needs to be careful for processing the messages.
456    */
457   bool IsIMEDoingKakuteiUndo() const;
458 
IsKeyDownMessage()459   bool IsKeyDownMessage() const {
460     return (mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN ||
461             mMsg.message == MOZ_WM_KEYDOWN);
462   }
IsKeyUpMessage()463   bool IsKeyUpMessage() const {
464     return (mMsg.message == WM_KEYUP || mMsg.message == WM_SYSKEYUP ||
465             mMsg.message == MOZ_WM_KEYUP);
466   }
IsCharOrSysCharMessage(const MSG & aMSG)467   bool IsCharOrSysCharMessage(const MSG& aMSG) const {
468     return IsCharOrSysCharMessage(aMSG.message);
469   }
IsCharOrSysCharMessage(UINT aMessage)470   bool IsCharOrSysCharMessage(UINT aMessage) const {
471     return (aMessage == WM_CHAR || aMessage == WM_SYSCHAR);
472   }
IsCharMessage(const MSG & aMSG)473   bool IsCharMessage(const MSG& aMSG) const {
474     return IsCharMessage(aMSG.message);
475   }
IsCharMessage(UINT aMessage)476   bool IsCharMessage(UINT aMessage) const {
477     return (IsCharOrSysCharMessage(aMessage) || IsDeadCharMessage(aMessage));
478   }
IsDeadCharMessage(const MSG & aMSG)479   bool IsDeadCharMessage(const MSG& aMSG) const {
480     return IsDeadCharMessage(aMSG.message);
481   }
IsDeadCharMessage(UINT aMessage)482   bool IsDeadCharMessage(UINT aMessage) const {
483     return (aMessage == WM_DEADCHAR || aMessage == WM_SYSDEADCHAR);
484   }
IsSysCharMessage(const MSG & aMSG)485   bool IsSysCharMessage(const MSG& aMSG) const {
486     return IsSysCharMessage(aMSG.message);
487   }
IsSysCharMessage(UINT aMessage)488   bool IsSysCharMessage(UINT aMessage) const {
489     return (aMessage == WM_SYSCHAR || aMessage == WM_SYSDEADCHAR);
490   }
491   bool MayBeSameCharMessage(const MSG& aCharMsg1, const MSG& aCharMsg2) const;
492   bool IsSamePhysicalKeyMessage(const MSG& aKeyOrCharMsg1,
493                                 const MSG& aKeyOrCharMsg2) const;
494   bool IsFollowedByPrintableCharMessage() const;
495   bool IsFollowedByPrintableCharOrSysCharMessage() const;
496   bool IsFollowedByDeadCharMessage() const;
IsKeyMessageOnPlugin()497   bool IsKeyMessageOnPlugin() const {
498     return (mMsg.message == MOZ_WM_KEYDOWN || mMsg.message == MOZ_WM_KEYUP);
499   }
IsPrintableCharMessage(const MSG & aMSG)500   bool IsPrintableCharMessage(const MSG& aMSG) const {
501     return aMSG.message == WM_CHAR &&
502            !IsControlChar(static_cast<char16_t>(aMSG.wParam));
503   }
IsEnterKeyPressCharMessage(const MSG & aMSG)504   bool IsEnterKeyPressCharMessage(const MSG& aMSG) const {
505     return aMSG.message == WM_CHAR && aMSG.wParam == '\r';
506   }
IsPrintableCharOrSysCharMessage(const MSG & aMSG)507   bool IsPrintableCharOrSysCharMessage(const MSG& aMSG) const {
508     return IsCharOrSysCharMessage(aMSG) &&
509            !IsControlChar(static_cast<char16_t>(aMSG.wParam));
510   }
IsControlCharMessage(const MSG & aMSG)511   bool IsControlCharMessage(const MSG& aMSG) const {
512     return IsCharMessage(aMSG.message) &&
513            IsControlChar(static_cast<char16_t>(aMSG.wParam));
514   }
515 
516   /**
517    * IsReservedBySystem() returns true if the key combination is reserved by
518    * the system.  Even if it's consumed by web apps, the message should be
519    * sent to next wndproc.
520    */
521   bool IsReservedBySystem() const;
522 
523   /**
524    * GetFollowingCharMessage() returns following char message of handling
525    * keydown event.  If the message is found, this method returns true.
526    * Otherwise, returns false.
527    *
528    * WARNING: Even if this returns true, aCharMsg may be WM_NULL or its
529    *          hwnd may be different window.
530    */
531   bool GetFollowingCharMessage(MSG& aCharMsg);
532 
533   /**
534    * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK.
535    */
536   uint8_t ComputeVirtualKeyCodeFromScanCode() const;
537 
538   /**
539    * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK_EX.
540    */
541   uint8_t ComputeVirtualKeyCodeFromScanCodeEx() const;
542 
543   /**
544    * Wraps MapVirtualKeyEx() with MAPVK_VK_TO_VSC_EX or MAPVK_VK_TO_VSC.
545    */
546   uint16_t ComputeScanCodeExFromVirtualKeyCode(UINT aVirtualKeyCode) const;
547 
548   /**
549    * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK and MAPVK_VK_TO_CHAR.
550    */
551   char16_t ComputeUnicharFromScanCode() const;
552 
553   /**
554    * Initializes the aKeyEvent with the information stored in the instance.
555    */
556   nsEventStatus InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
557                              const ModifierKeyState& aModKeyState,
558                              const MSG* aMsgSentToPlugin = nullptr) const;
559   nsEventStatus InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
560                              const MSG* aMsgSentToPlugin = nullptr) const;
561 
562   /**
563    * MaybeInitPluginEventOfKeyEvent() may initialize aKeyEvent::mPluginEvent
564    * with aMsgSentToPlugin if it's necessary.
565    */
566   void MaybeInitPluginEventOfKeyEvent(WidgetKeyboardEvent& aKeyEvent,
567                                       const MSG& aMsgSentToPlugin) const;
568 
569   /**
570    * Dispatches a command event for aEventCommand.
571    * Returns true if the event is consumed.  Otherwise, false.
572    */
573   bool DispatchCommandEvent(uint32_t aEventCommand) const;
574 
575   /**
576    * DispatchKeyPressEventsWithRetrievedCharMessages() dispatches keypress
577    * event(s) with retrieved char messages.
578    */
579   bool DispatchKeyPressEventsWithRetrievedCharMessages() const;
580 
581   /**
582    * DispatchKeyPressEventsWithoutCharMessage() dispatches keypress event(s)
583    * without char messages.  So, this should be used only when there are no
584    * following char messages.
585    */
586   bool DispatchKeyPressEventsWithoutCharMessage() const;
587 
588   /**
589    * MaybeDispatchPluginEventsForRemovedCharMessages() dispatches plugin events
590    * for removed char messages when a windowless plugin has focus.
591    * Returns true if the widget is destroyed or blurred during dispatching a
592    * plugin event.
593    */
594   bool MaybeDispatchPluginEventsForRemovedCharMessages() const;
595 
596   /**
597    * Checkes whether the key event down message is handled without following
598    * WM_CHAR messages.  For example, if following WM_CHAR message indicates
599    * control character input, the WM_CHAR message is unclear whether it's
600    * caused by a printable key with Ctrl or just a function key such as Enter
601    * or Backspace.
602    */
603   bool NeedsToHandleWithoutFollowingCharMessages() const;
604 
605   /**
606    * ComputeInputtingStringWithKeyboardLayout() computes string to be inputted
607    * with the key and the modifier state, without shift state and with shift
608    * state.
609    */
610   void ComputeInputtingStringWithKeyboardLayout();
611 
612   /**
613    * IsFocusedWindowChanged() returns true if focused window is changed
614    * after the instance is created.
615    */
IsFocusedWindowChanged()616   bool IsFocusedWindowChanged() const {
617     return mFocusedWndBeforeDispatch != ::GetFocus();
618   }
619 
620   /**
621    * Handles WM_CHAR message or WM_SYSCHAR message.  The instance must be
622    * initialized with WM_KEYDOWN, WM_SYSKEYDOWN or them.
623    * Returns true if dispatched keypress event is consumed.  Otherwise, false.
624    */
625   bool HandleCharMessage(const MSG& aCharMsg,
626                          bool* aEventDispatched = nullptr) const;
627 
628   // Calls of PeekMessage() from NativeKey might cause nested message handling
629   // due to (perhaps) odd API hook.  NativeKey should do nothing if given
630   // message is tried to be retrieved by another instance.
631 
632   /**
633    * sLatestInstacne is a pointer to the newest instance of NativeKey which is
634    * handling a key or char message(s).
635    */
636   static NativeKey* sLatestInstance;
637 
638   static const MSG sEmptyMSG;
639 
640   static MSG sLastKeyOrCharMSG;
641 
642   static MSG sLastKeyMSG;
643 
IsEmptyMSG(const MSG & aMSG)644   static bool IsEmptyMSG(const MSG& aMSG) {
645     return !memcmp(&aMSG, &sEmptyMSG, sizeof(MSG));
646   }
647 
IsAnotherInstanceRemovingCharMessage()648   bool IsAnotherInstanceRemovingCharMessage() const {
649     return mLastInstance && !IsEmptyMSG(mLastInstance->mRemovingMsg);
650   }
651 
652  public:
653   /**
654    * Returns last key or char MSG.  If no MSG has been received yet, the result
655    * is empty MSG (i.e., .message is WM_NULL).
656    */
LastKeyOrCharMSG()657   static const MSG& LastKeyOrCharMSG() { return sLastKeyOrCharMSG; }
658 };
659 
660 class KeyboardLayout {
661  public:
662   static KeyboardLayout* GetInstance();
663   static void Shutdown();
664   static HKL GetActiveLayout();
665   static nsCString GetActiveLayoutName();
666   static void NotifyIdleServiceOfUserActivity();
667 
668   static bool IsPrintableCharKey(uint8_t aVirtualKey);
669 
670   /**
671    * IsDeadKey() returns true if aVirtualKey is a dead key with aModKeyState.
672    * This method isn't stateful.
673    */
674   bool IsDeadKey(uint8_t aVirtualKey,
675                  const ModifierKeyState& aModKeyState) const;
676 
677   /**
678    * IsInDeadKeySequence() returns true when it's in a dead key sequence.
679    * It starts when a dead key is down and ends when another key down causes
680    * inactivating the dead key state.
681    */
IsInDeadKeySequence()682   bool IsInDeadKeySequence() const { return !mActiveDeadKeys.IsEmpty(); }
683 
684   /**
685    * IsSysKey() returns true if aVirtualKey with aModKeyState causes WM_SYSKEY*
686    * or WM_SYS*CHAR messages.
687    */
688   bool IsSysKey(uint8_t aVirtualKey,
689                 const ModifierKeyState& aModKeyState) const;
690 
691   /**
692    * GetUniCharsAndModifiers() returns characters which are inputted by
693    * aVirtualKey with aModKeyState.  This method isn't stateful.
694    * Note that if the combination causes text input, the result's Ctrl and
695    * Alt key state are never active.
696    */
GetUniCharsAndModifiers(uint8_t aVirtualKey,const ModifierKeyState & aModKeyState)697   UniCharsAndModifiers GetUniCharsAndModifiers(
698       uint8_t aVirtualKey, const ModifierKeyState& aModKeyState) const {
699     VirtualKey::ShiftState shiftState =
700         VirtualKey::ModifierKeyStateToShiftState(aModKeyState);
701     return GetUniCharsAndModifiers(aVirtualKey, shiftState);
702   }
703 
704   /**
705    * GetNativeUniCharsAndModifiers() returns characters which are inputted by
706    * aVirtualKey with aModKeyState.  The method isn't stateful.
707    * Note that different from GetUniCharsAndModifiers(), this returns
708    * actual modifier state of Ctrl and Alt.
709    */
710   UniCharsAndModifiers GetNativeUniCharsAndModifiers(
711       uint8_t aVirtualKey, const ModifierKeyState& aModKeyState) const;
712 
713   /**
714    * OnLayoutChange() must be called before the first keydown message is
715    * received.  LoadLayout() changes the keyboard state, that causes breaking
716    * dead key state.  Therefore, we need to load the layout before the first
717    * keydown message.
718    */
OnLayoutChange(HKL aKeyboardLayout)719   void OnLayoutChange(HKL aKeyboardLayout) {
720     MOZ_ASSERT(!mIsOverridden);
721     LoadLayout(aKeyboardLayout);
722   }
723 
724   /**
725    * OverrideLayout() loads the specified keyboard layout.
726    */
OverrideLayout(HKL aLayout)727   void OverrideLayout(HKL aLayout) {
728     mIsOverridden = true;
729     LoadLayout(aLayout);
730   }
731 
732   /**
733    * RestoreLayout() loads the current keyboard layout of the thread.
734    */
RestoreLayout()735   void RestoreLayout() {
736     mIsOverridden = false;
737     mIsPendingToRestoreKeyboardLayout = true;
738   }
739 
740   uint32_t ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const;
741 
742   /**
743    * ConvertNativeKeyCodeToKeyNameIndex() returns KeyNameIndex value for
744    * non-printable keys (except some special keys like space key).
745    */
746   KeyNameIndex ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const;
747 
748   /**
749    * ConvertScanCodeToCodeNameIndex() returns CodeNameIndex value for
750    * the given scan code.  aScanCode can be over 0xE000 since this method
751    * doesn't use Windows API.
752    */
753   static CodeNameIndex ConvertScanCodeToCodeNameIndex(UINT aScanCode);
754 
GetLayout()755   HKL GetLayout() const {
756     return mIsPendingToRestoreKeyboardLayout ? ::GetKeyboardLayout(0)
757                                              : mKeyboardLayout;
758   }
759 
760   /**
761    * This wraps MapVirtualKeyEx() API with MAPVK_VK_TO_VSC.
762    */
763   WORD ComputeScanCodeForVirtualKeyCode(uint8_t aVirtualKeyCode) const;
764 
765   /**
766    * Implementation of nsIWidget::SynthesizeNativeKeyEvent().
767    */
768   nsresult SynthesizeNativeKeyEvent(nsWindowBase* aWidget,
769                                     int32_t aNativeKeyboardLayout,
770                                     int32_t aNativeKeyCode,
771                                     uint32_t aModifierFlags,
772                                     const nsAString& aCharacters,
773                                     const nsAString& aUnmodifiedCharacters);
774 
775  private:
776   KeyboardLayout();
777   ~KeyboardLayout();
778 
779   static KeyboardLayout* sInstance;
780   static nsIIdleServiceInternal* sIdleService;
781 
782   struct DeadKeyTableListEntry {
783     DeadKeyTableListEntry* next;
784     uint8_t data[1];
785   };
786 
787   HKL mKeyboardLayout;
788 
789   VirtualKey mVirtualKeys[NS_NUM_OF_KEYS];
790   DeadKeyTableListEntry* mDeadKeyTableListHead;
791   // When mActiveDeadKeys is empty, it's not in dead key sequence.
792   // Otherwise, it contains virtual keycodes which are pressed in current
793   // dead key sequence.
794   nsTArray<uint8_t> mActiveDeadKeys;
795   // mDeadKeyShiftStates is always same length as mActiveDeadKeys.
796   // This stores shift states at pressing each dead key stored in
797   // mActiveDeadKeys.
798   nsTArray<VirtualKey::ShiftState> mDeadKeyShiftStates;
799 
800   bool mIsOverridden;
801   bool mIsPendingToRestoreKeyboardLayout;
802 
803   static inline int32_t GetKeyIndex(uint8_t aVirtualKey);
804   static int CompareDeadKeyEntries(const void* aArg1, const void* aArg2,
805                                    void* aData);
806   static bool AddDeadKeyEntry(char16_t aBaseChar, char16_t aCompositeChar,
807                               DeadKeyEntry* aDeadKeyArray, uint32_t aEntries);
808   bool EnsureDeadKeyActive(bool aIsActive, uint8_t aDeadKey,
809                            const PBYTE aDeadKeyKbdState);
810   uint32_t GetDeadKeyCombinations(uint8_t aDeadKey,
811                                   const PBYTE aDeadKeyKbdState,
812                                   uint16_t aShiftStatesWithBaseChars,
813                                   DeadKeyEntry* aDeadKeyArray,
814                                   uint32_t aMaxEntries);
815   /**
816    * Activates or deactivates dead key state.
817    */
818   void ActivateDeadKeyState(const NativeKey& aNativeKey,
819                             const ModifierKeyState& aModKeyState);
820   void DeactivateDeadKeyState();
821 
822   const DeadKeyTable* AddDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
823                                       uint32_t aEntries);
824   void ReleaseDeadKeyTables();
825 
826   /**
827    * Loads the specified keyboard layout. This method always clear the dead key
828    * state.
829    */
830   void LoadLayout(HKL aLayout);
831 
832   /**
833    * Gets the keyboard layout name of aLayout.  Be careful, this may be too
834    * slow to call at handling user input.
835    */
836   nsCString GetLayoutName(HKL aLayout) const;
837 
838   /**
839    * InitNativeKey() must be called when actually widget receives WM_KEYDOWN or
840    * WM_KEYUP.  This method is stateful.  This saves current dead key state at
841    * WM_KEYDOWN.  Additionally, computes current inputted character(s) and set
842    * them to the aNativeKey.
843    */
844   void InitNativeKey(NativeKey& aNativeKey,
845                      const ModifierKeyState& aModKeyState);
846 
847   /**
848    * MaybeInitNativeKeyAsDeadKey() initializes aNativeKey only when aNativeKey
849    * is a dead key's event.
850    * When it's not in a dead key sequence, this activates the dead key state.
851    * When it's in a dead key sequence, this initializes aNativeKey with a
852    * composite character or a preceding dead char and a dead char which should
853    * be caused by aNativeKey.
854    * Returns true when this initializes aNativeKey.  Otherwise, false.
855    */
856   bool MaybeInitNativeKeyAsDeadKey(NativeKey& aNativeKey,
857                                    const ModifierKeyState& aModKeyState);
858 
859   /**
860    * MaybeInitNativeKeyWithCompositeChar() may initialize aNativeKey with
861    * proper composite character when dead key produces a composite character.
862    * Otherwise, just returns false.
863    */
864   bool MaybeInitNativeKeyWithCompositeChar(
865       NativeKey& aNativeKey, const ModifierKeyState& aModKeyState);
866 
867   /**
868    * See the comment of GetUniCharsAndModifiers() below.
869    */
870   UniCharsAndModifiers GetUniCharsAndModifiers(
871       uint8_t aVirtualKey, VirtualKey::ShiftState aShiftState) const;
872 
873   /**
874    * GetDeadUniCharsAndModifiers() returns dead chars which are stored in
875    * current dead key sequence.  So, this is stateful.
876    */
877   UniCharsAndModifiers GetDeadUniCharsAndModifiers() const;
878 
879   /**
880    * GetCompositeChar() returns a composite character with dead character
881    * caused by mActiveDeadKeys, mDeadKeyShiftStates and a base character
882    * (aBaseChar).
883    * If the combination of the dead character and the base character doesn't
884    * cause a composite character, this returns 0.
885    */
886   char16_t GetCompositeChar(char16_t aBaseChar) const;
887 
888   // NativeKey class should access InitNativeKey() directly, but it shouldn't
889   // be available outside of NativeKey.  So, let's make NativeKey a friend
890   // class of this.
891   friend class NativeKey;
892 };
893 
894 class RedirectedKeyDownMessageManager {
895  public:
896   /*
897    * If a window receives WM_KEYDOWN message or WM_SYSKEYDOWM message which is
898    * a redirected message, NativeKey::DispatchKeyDownAndKeyPressEvent()
899    * prevents to dispatch eKeyDown event because it has been dispatched
900    * before the message was redirected.  However, in some cases, WM_*KEYDOWN
901    * message handler may not handle actually.  Then, the message handler needs
902    * to forget the redirected message and remove WM_CHAR message or WM_SYSCHAR
903    * message for the redirected keydown message.  AutoFlusher class is a helper
904    * class for doing it.  This must be created in the stack.
905    */
906   class MOZ_STACK_CLASS AutoFlusher final {
907    public:
AutoFlusher(nsWindowBase * aWidget,const MSG & aMsg)908     AutoFlusher(nsWindowBase* aWidget, const MSG& aMsg)
909         : mCancel(!RedirectedKeyDownMessageManager::IsRedirectedMessage(aMsg)),
910           mWidget(aWidget),
911           mMsg(aMsg) {}
912 
~AutoFlusher()913     ~AutoFlusher() {
914       if (mCancel) {
915         return;
916       }
917       // Prevent unnecessary keypress event
918       if (!mWidget->Destroyed()) {
919         RedirectedKeyDownMessageManager::RemoveNextCharMessage(mMsg.hwnd);
920       }
921       // Foreget the redirected message
922       RedirectedKeyDownMessageManager::Forget();
923     }
924 
Cancel()925     void Cancel() { mCancel = true; }
926 
927    private:
928     bool mCancel;
929     RefPtr<nsWindowBase> mWidget;
930     const MSG& mMsg;
931   };
932 
WillRedirect(const MSG & aMsg,bool aDefualtPrevented)933   static void WillRedirect(const MSG& aMsg, bool aDefualtPrevented) {
934     sRedirectedKeyDownMsg = aMsg;
935     sDefaultPreventedOfRedirectedMsg = aDefualtPrevented;
936   }
937 
Forget()938   static void Forget() { sRedirectedKeyDownMsg.message = WM_NULL; }
939 
PreventDefault()940   static void PreventDefault() { sDefaultPreventedOfRedirectedMsg = true; }
DefaultPrevented()941   static bool DefaultPrevented() { return sDefaultPreventedOfRedirectedMsg; }
942 
943   static bool IsRedirectedMessage(const MSG& aMsg);
944 
945   /**
946    * RemoveNextCharMessage() should be called by WM_KEYDOWN or WM_SYSKEYDOWM
947    * message handler.  If there is no WM_(SYS)CHAR message for it, this
948    * method does nothing.
949    * NOTE: WM_(SYS)CHAR message is posted by TranslateMessage() API which is
950    * called in message loop.  So, WM_(SYS)KEYDOWN message should have
951    * WM_(SYS)CHAR message in the queue if the keydown event causes character
952    * input.
953    */
954   static void RemoveNextCharMessage(HWND aWnd);
955 
956  private:
957   // sRedirectedKeyDownMsg is WM_KEYDOWN message or WM_SYSKEYDOWN message which
958   // is reirected with SendInput() API by
959   // widget::NativeKey::DispatchKeyDownAndKeyPressEvent()
960   static MSG sRedirectedKeyDownMsg;
961   static bool sDefaultPreventedOfRedirectedMsg;
962 };
963 
964 }  // namespace widget
965 }  // namespace mozilla
966 
967 #endif
968