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 "mozilla/RefPtr.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"
21 #define NS_NUM_OF_KEYS 70
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
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
39 #define VK_OEM_102 0xE2
40 #define VK_OEM_CLEAR 0xFE
42 class nsIUserIdleServiceInternal
;
47 enum ScanCode
: uint16_t {
52 eControlLeft
= 0x001D,
53 eControlRight
= 0xE01D,
58 // 0: nsIWidget's native modifier flag
59 // 1: Virtual keycode which does not distinguish whether left or right location.
60 // 2: Virtual keycode which distinguishes whether left or right location.
62 static const uint32_t sModifierKeyMap
[][4] = {
63 {nsIWidget::CAPS_LOCK
, VK_CAPITAL
, 0, ScanCode::eCapsLock
},
64 {nsIWidget::NUM_LOCK
, VK_NUMLOCK
, 0, ScanCode::eNumLock
},
65 {nsIWidget::SHIFT_L
, VK_SHIFT
, VK_LSHIFT
, ScanCode::eShiftLeft
},
66 {nsIWidget::SHIFT_R
, VK_SHIFT
, VK_RSHIFT
, ScanCode::eShiftRight
},
67 {nsIWidget::CTRL_L
, VK_CONTROL
, VK_LCONTROL
, ScanCode::eControlLeft
},
68 {nsIWidget::CTRL_R
, VK_CONTROL
, VK_RCONTROL
, ScanCode::eControlRight
},
69 {nsIWidget::ALT_L
, VK_MENU
, VK_LMENU
, ScanCode::eAltLeft
},
70 {nsIWidget::ALT_R
, VK_MENU
, VK_RMENU
, ScanCode::eAltRight
}};
74 class MOZ_STACK_CLASS UniCharsAndModifiers final
{
76 UniCharsAndModifiers() {}
77 UniCharsAndModifiers
operator+(const UniCharsAndModifiers
& aOther
) const;
78 UniCharsAndModifiers
& operator+=(const UniCharsAndModifiers
& aOther
);
81 * Append a pair of unicode character and the final modifier.
83 void Append(char16_t aUniChar
, Modifiers aModifiers
);
88 bool IsEmpty() const {
89 MOZ_ASSERT(mChars
.Length() == mModifiers
.Length());
90 return mChars
.IsEmpty();
93 char16_t
CharAt(size_t aIndex
) const {
94 MOZ_ASSERT(aIndex
< Length());
95 return mChars
[aIndex
];
97 Modifiers
ModifiersAt(size_t aIndex
) const {
98 MOZ_ASSERT(aIndex
< Length());
99 return mModifiers
[aIndex
];
101 size_t Length() const {
102 MOZ_ASSERT(mChars
.Length() == mModifiers
.Length());
103 return mChars
.Length();
106 bool IsProducingCharsWithAltGr() const {
107 return !IsEmpty() && (ModifiersAt(0) & MODIFIER_ALTGRAPH
) != 0;
110 void FillModifiers(Modifiers aModifiers
);
112 * OverwriteModifiersIfBeginsWith() assigns mModifiers with aOther between
113 * [0] and [aOther.mLength - 1] only when mChars begins with aOther.mChars.
115 void OverwriteModifiersIfBeginsWith(const UniCharsAndModifiers
& aOther
);
117 bool UniCharsEqual(const UniCharsAndModifiers
& aOther
) const;
118 bool UniCharsCaseInsensitiveEqual(const UniCharsAndModifiers
& aOther
) const;
119 bool BeginsWith(const UniCharsAndModifiers
& aOther
) const;
121 const nsString
& ToString() const { return mChars
; }
125 // 5 is enough number for normal keyboard layout handling. On Windows,
126 // a dead key sequence may cause inputting up to 5 characters per key press.
127 CopyableAutoTArray
<Modifiers
, 5> mModifiers
;
130 struct DeadKeyEntry
{
132 char16_t CompositeChar
;
136 friend class KeyboardLayout
;
139 // KeyboardLayout::AddDeadKeyTable() will allocate as many entries as
140 // required. It is the only way to create new DeadKeyTable instances.
141 DeadKeyEntry mTable
[1];
143 void Init(const DeadKeyEntry
* aDeadKeyArray
, uint32_t aEntries
) {
145 memcpy(mTable
, aDeadKeyArray
, aEntries
* sizeof(DeadKeyEntry
));
148 static uint32_t SizeInBytes(uint32_t aEntries
) {
149 return offsetof(DeadKeyTable
, mTable
) + aEntries
* sizeof(DeadKeyEntry
);
153 uint32_t Entries() const { return mEntries
; }
155 bool IsEqual(const DeadKeyEntry
* aDeadKeyArray
, uint32_t aEntries
) const {
156 return (mEntries
== aEntries
&&
157 !memcmp(mTable
, aDeadKeyArray
, aEntries
* sizeof(DeadKeyEntry
)));
160 char16_t
GetCompositeChar(char16_t aBaseChar
) const;
165 enum ShiftStateIndex
: uint8_t {
172 // 3 - Control + Shift
178 // 6 - Alt + Control (AltGr)
180 // 7 - Alt + Control + Shift (AltGr + Shift)
184 // 9 - CapsLock + Shift
186 // 10 - CapsLock + Control
187 eControlWithCapsLock
,
188 // 11 - CapsLock + Control + Shift
189 eControlShiftWithCapsLock
,
190 // 12 - CapsLock + Alt
192 // 13 - CapsLock + Alt + Shift
193 eAltShiftWithCapsLock
,
194 // 14 - CapsLock + Alt + Control (CapsLock + AltGr)
196 // 15 - CapsLock + Alt + Control + Shift (CapsLock + AltGr + Shift)
197 eAltGrShiftWithCapsLock
,
200 enum ShiftStateFlag
{
202 STATE_CONTROL
= 0x02,
204 STATE_CAPSLOCK
= 0x08,
205 // ShiftState needs to have AltGr state separately since this is necessary
206 // for lossless conversion with Modifiers.
207 STATE_ALTGRAPH
= 0x80,
208 // Useful to remove or check Ctrl and Alt flags.
209 STATE_CONTROL_ALT
= STATE_CONTROL
| STATE_ALT
,
212 typedef uint8_t ShiftState
;
214 static ShiftState
ModifiersToShiftState(Modifiers aModifiers
);
215 static ShiftState
ModifierKeyStateToShiftState(
216 const ModifierKeyState
& aModKeyState
) {
217 return ModifiersToShiftState(aModKeyState
.GetModifiers());
219 static Modifiers
ShiftStateToModifiers(ShiftState aShiftState
);
220 static bool IsAltGrIndex(uint8_t aIndex
) {
221 return (aIndex
& STATE_CONTROL_ALT
) == STATE_CONTROL_ALT
;
225 union KeyShiftState
{
230 const DeadKeyTable
* Table
;
235 KeyShiftState mShiftStates
[16];
238 static uint8_t ToShiftStateIndex(ShiftState aShiftState
) {
239 if (!(aShiftState
& STATE_ALTGRAPH
)) {
240 MOZ_ASSERT(aShiftState
<= eAltGrShiftWithCapsLock
);
241 return static_cast<uint8_t>(aShiftState
);
243 uint8_t index
= aShiftState
& ~STATE_ALTGRAPH
;
244 index
|= (STATE_ALT
| STATE_CONTROL
);
245 MOZ_ASSERT(index
<= eAltGrShiftWithCapsLock
);
249 void SetDeadKey(ShiftState aShiftState
, bool aIsDeadKey
) {
251 mIsDeadKey
|= 1 << ToShiftStateIndex(aShiftState
);
253 mIsDeadKey
&= ~(1 << ToShiftStateIndex(aShiftState
));
258 static void FillKbdState(PBYTE aKbdState
, const ShiftState aShiftState
);
260 bool IsDeadKey(ShiftState aShiftState
) const {
261 return (mIsDeadKey
& (1 << ToShiftStateIndex(aShiftState
))) != 0;
265 * IsChangedByAltGr() is useful to check if a key with AltGr produces
266 * different character(s) from the key without AltGr.
267 * Note that this is designed for checking if a keyboard layout has AltGr
268 * key. So, this result may not exactly correct for the key since it's
269 * okay to fails in some edge cases when we check all keys which produce
270 * character(s) in a layout.
272 bool IsChangedByAltGr(ShiftState aShiftState
) const {
273 MOZ_ASSERT(aShiftState
== ToShiftStateIndex(aShiftState
));
274 MOZ_ASSERT(IsAltGrIndex(aShiftState
));
275 MOZ_ASSERT(IsDeadKey(aShiftState
) ||
276 mShiftStates
[aShiftState
].Normal
.Chars
[0]);
277 const ShiftState kShiftStateWithoutAltGr
=
278 aShiftState
- ShiftStateIndex::eAltGr
;
279 if (IsDeadKey(aShiftState
) != IsDeadKey(kShiftStateWithoutAltGr
)) {
282 if (IsDeadKey(aShiftState
)) {
283 return mShiftStates
[aShiftState
].DeadKey
.DeadChar
!=
284 mShiftStates
[kShiftStateWithoutAltGr
].DeadKey
.DeadChar
;
286 for (size_t i
= 0; i
< 4; i
++) {
287 if (mShiftStates
[aShiftState
].Normal
.Chars
[i
] !=
288 mShiftStates
[kShiftStateWithoutAltGr
].Normal
.Chars
[i
]) {
291 if (!mShiftStates
[aShiftState
].Normal
.Chars
[i
] &&
292 !mShiftStates
[kShiftStateWithoutAltGr
].Normal
.Chars
[i
]) {
299 void AttachDeadKeyTable(ShiftState aShiftState
,
300 const DeadKeyTable
* aDeadKeyTable
) {
301 MOZ_ASSERT(aShiftState
== ToShiftStateIndex(aShiftState
));
302 mShiftStates
[aShiftState
].DeadKey
.Table
= aDeadKeyTable
;
305 void SetNormalChars(ShiftState aShiftState
, const char16_t
* aChars
,
306 uint32_t aNumOfChars
);
307 void SetDeadChar(ShiftState aShiftState
, char16_t aDeadChar
);
308 const DeadKeyTable
* MatchingDeadKeyTable(const DeadKeyEntry
* aDeadKeyArray
,
309 uint32_t aEntries
) const;
310 inline char16_t
GetCompositeChar(ShiftState aShiftState
,
311 char16_t aBaseChar
) const {
312 return mShiftStates
[ToShiftStateIndex(aShiftState
)]
313 .DeadKey
.Table
->GetCompositeChar(aBaseChar
);
316 char16_t
GetCompositeChar(const ModifierKeyState
& aModKeyState
,
317 char16_t aBaseChar
) const {
318 return GetCompositeChar(ModifierKeyStateToShiftState(aModKeyState
),
323 * GetNativeUniChars() returns character(s) which is produced by the
324 * key with given modifiers. This does NOT return proper MODIFIER_ALTGRAPH
325 * state because this is raw accessor of the database of this key.
327 UniCharsAndModifiers
GetNativeUniChars(ShiftState aShiftState
) const;
328 UniCharsAndModifiers
GetNativeUniChars(
329 const ModifierKeyState
& aModKeyState
) const {
330 return GetNativeUniChars(ModifierKeyStateToShiftState(aModKeyState
));
334 * GetUniChars() returns characters and modifiers which are not consumed
335 * to input the character.
336 * For example, if you specify Ctrl key but the key produces no character
337 * with Ctrl, this returns character(s) which is produced by the key
338 * without Ctrl. So, the result is useful to decide KeyboardEvent.key
340 * Another example is, if you specify Ctrl key and the key produces
341 * different character(s) from the case without Ctrl key, this returns
342 * the character(s) *without* MODIFIER_CONTROL. This modifier information
343 * is useful for eKeyPress since TextEditor does not treat eKeyPress events
344 * whose modifier includes MODIFIER_ALT and/or MODIFIER_CONTROL.
346 * @param aShiftState Modifiers which you want to retrieve
347 * KeyboardEvent.key value for the key with.
348 * If AltGr key is pressed, this should include
349 * STATE_ALTGRAPH and should NOT include
350 * STATE_ALT nor STATE_CONTROL.
351 * If both Alt and Ctrl are pressed to emulate
352 * AltGr, this should include both STATE_ALT and
353 * STATE_CONTROL but should NOT include
355 * Then, this returns proper modifiers when
356 * this key produces no character with AltGr.
358 UniCharsAndModifiers
GetUniChars(ShiftState aShiftState
) const;
359 UniCharsAndModifiers
GetUniChars(const ModifierKeyState
& aModKeyState
) const {
360 return GetUniChars(ModifierKeyStateToShiftState(aModKeyState
));
364 class MOZ_STACK_CLASS NativeKey final
{
365 friend class KeyboardLayout
;
382 MSG
GetCharMsg(HWND aWnd
) const {
386 mIsDeadKey
&& mIsSysKey
388 : mIsDeadKey
? WM_DEADCHAR
: mIsSysKey
? WM_SYSCHAR
: WM_CHAR
;
389 msg
.wParam
= static_cast<WPARAM
>(mCharCode
);
390 msg
.lParam
= static_cast<LPARAM
>(mScanCode
<< 16);
392 msg
.pt
.x
= msg
.pt
.y
= 0;
397 NativeKey(nsWindowBase
* aWidget
, const MSG
& aMessage
,
398 const ModifierKeyState
& aModKeyState
,
399 HKL aOverrideKeyboardLayout
= 0,
400 nsTArray
<FakeCharMsg
>* aFakeCharMsgs
= nullptr);
405 * Handle WM_KEYDOWN message or WM_SYSKEYDOWN message. The instance must be
406 * initialized with WM_KEYDOWN or WM_SYSKEYDOWN.
407 * Returns true if dispatched keydown event or keypress event is consumed.
410 bool HandleKeyDownMessage(bool* aEventDispatched
= nullptr) const;
413 * Handles WM_CHAR message or WM_SYSCHAR message. The instance must be
414 * initialized with them.
415 * Returns true if dispatched keypress event is consumed. Otherwise, false.
417 bool HandleCharMessage(bool* aEventDispatched
= nullptr) const;
420 * Handles keyup message. Returns true if the event is consumed.
423 bool HandleKeyUpMessage(bool* aEventDispatched
= nullptr) const;
426 * Handles WM_APPCOMMAND message. Returns true if the event is consumed.
429 bool HandleAppCommandMessage() const;
432 * Callback of TextEventDispatcherListener::WillDispatchKeyboardEvent().
433 * This method sets alternative char codes of aKeyboardEvent.
435 void WillDispatchKeyboardEvent(WidgetKeyboardEvent
& aKeyboardEvent
,
439 * Returns true if aChar is a control character which shouldn't be inputted
440 * into focused text editor.
442 static bool IsControlChar(char16_t aChar
);
444 bool IsShift() const { return mModKeyState
.IsShift(); }
445 bool IsControl() const { return mModKeyState
.IsControl(); }
446 bool IsAlt() const { return mModKeyState
.IsAlt(); }
447 bool MaybeEmulatingAltGraph() const;
448 Modifiers
GetModifiers() const { return mModKeyState
.GetModifiers(); }
449 const ModifierKeyState
& ModifierKeyStateRef() const { return mModKeyState
; }
450 VirtualKey::ShiftState
GetShiftState() const {
451 return VirtualKey::ModifierKeyStateToShiftState(mModKeyState
);
455 * GenericVirtualKeyCode() returns virtual keycode which cannot distinguish
456 * position of modifier keys. E.g., VK_CONTROL for both ControlLeft and
459 uint8_t GenericVirtualKeyCode() const { return mOriginalVirtualKeyCode
; }
462 * SpecificVirtualKeyCode() returns virtual keycode which can distinguish
463 * position of modifier keys. E.g., returns VK_LCONTROL or VK_RCONTROL
464 * instead of VK_CONTROL. If the key message is synthesized with not
465 * enough information, this prefers left position's keycode.
467 uint8_t SpecificVirtualKeyCode() const { return mVirtualKeyCode
; }
470 NativeKey
* mLastInstance
;
471 // mRemovingMsg is set at removing a char message from
472 // GetFollowingCharMessage().
474 // mReceivedMsg is set when another instance starts to handle the message
477 RefPtr
<nsWindowBase
> mWidget
;
478 RefPtr
<TextEventDispatcher
> mDispatcher
;
481 // mFollowingCharMsgs stores WM_CHAR, WM_SYSCHAR, WM_DEADCHAR or
482 // WM_SYSDEADCHAR message which follows WM_KEYDOWN.
483 // Note that the stored messaged are already removed from the queue.
484 // FYI: 5 is enough number for usual keyboard layout handling. On Windows,
485 // a dead key sequence may cause inputting up to 5 characters per key press.
486 AutoTArray
<MSG
, 5> mFollowingCharMsgs
;
487 // mRemovedOddCharMsgs stores WM_CHAR messages which are caused by ATOK or
488 // WXG (they are Japanese IME) when the user tries to do "Kakutei-undo"
489 // (it means "undo the last commit").
490 nsTArray
<MSG
> mRemovedOddCharMsgs
;
491 // If dispatching eKeyDown or eKeyPress event causes focus change,
492 // the instance shouldn't handle remaning char messages. For checking it,
493 // this should store first focused window.
494 HWND mFocusedWndBeforeDispatch
;
496 uint32_t mDOMKeyCode
;
497 KeyNameIndex mKeyNameIndex
;
498 CodeNameIndex mCodeNameIndex
;
500 ModifierKeyState mModKeyState
;
502 // mVirtualKeyCode distinguishes left key or right key of modifier key.
503 uint8_t mVirtualKeyCode
;
504 // mOriginalVirtualKeyCode doesn't distinguish left key or right key of
505 // modifier key. However, if the given keycode is VK_PROCESS, it's resolved
506 // to a keycode before it's handled by IME.
507 uint8_t mOriginalVirtualKeyCode
;
509 // mCommittedChars indicates the inputted characters which is committed by
510 // the key. If dead key fail to composite a character, mCommittedChars
511 // indicates both the dead characters and the base characters.
512 UniCharsAndModifiers mCommittedCharsAndModifiers
;
514 // Following strings are computed by
515 // ComputeInputtingStringWithKeyboardLayout() which is typically called
516 // before dispatching keydown event.
517 // mInputtingStringAndModifiers's string is the string to be
518 // inputted into the focused editor and its modifier state is proper
519 // modifier state for inputting the string into the editor.
520 UniCharsAndModifiers mInputtingStringAndModifiers
;
521 // mShiftedString is the string to be inputted into the editor with
522 // current modifier state with active shift state.
523 UniCharsAndModifiers mShiftedString
;
524 // mUnshiftedString is the string to be inputted into the editor with
525 // current modifier state without shift state.
526 UniCharsAndModifiers mUnshiftedString
;
527 // Following integers are computed by
528 // ComputeInputtingStringWithKeyboardLayout() which is typically called
529 // before dispatching keydown event. The meaning of these values is same
531 uint32_t mShiftedLatinChar
;
532 uint32_t mUnshiftedLatinChar
;
536 // mIsRepeat is true if the key message is caused by the auto-repeat
540 // mIsPrintableKey is true if the key may be a printable key without
541 // any modifier keys. Otherwise, false.
542 // Please note that the event may not cause any text input even if this
543 // is true. E.g., it might be dead key state or Ctrl key may be pressed.
544 bool mIsPrintableKey
;
545 // mIsSkippableInRemoteProcess is false if the key event shouldn't be
546 // skipped in the remote process even if it's too old event.
547 bool mIsSkippableInRemoteProcess
;
548 // mCharMessageHasGone is true if the message is a keydown message and
549 // it's followed by at least one char message but it's gone at removing
550 // from the queue. This could occur if PeekMessage() or something is
551 // hooked by odd tool.
552 bool mCharMessageHasGone
;
553 // mIsOverridingKeyboardLayout is true if the instance temporarily overriding
554 // keyboard layout with specified by the constructor.
555 bool mIsOverridingKeyboardLayout
;
556 // mCanIgnoreModifierStateAtKeyPress is true if it's allowed to remove
557 // Ctrl or Alt modifier state at dispatching eKeyPress.
558 bool mCanIgnoreModifierStateAtKeyPress
;
560 nsTArray
<FakeCharMsg
>* mFakeCharMsgs
;
562 // When a keydown event is dispatched at handling WM_APPCOMMAND, the computed
563 // virtual keycode is set to this. Even if we consume WM_APPCOMMAND message,
564 // Windows may send WM_KEYDOWN and WM_KEYUP message for them.
565 // At that time, we should not dispatch key events for them.
566 static uint8_t sDispatchedKeyOfAppCommand
;
569 MOZ_CRASH("The default constructor of NativeKey isn't available");
572 void InitWithAppCommand();
573 void InitWithKeyOrChar();
576 * InitIsSkippableForKeyOrChar() initializes mIsSkippableInRemoteProcess with
577 * mIsRepeat and previous key message information. So, this must be called
578 * after mIsRepeat is initialized.
580 void InitIsSkippableForKeyOrChar(const MSG
& aLastKeyMSG
);
583 * InitCommittedCharsAndModifiersWithFollowingCharMessages() initializes
584 * mCommittedCharsAndModifiers with mFollowingCharMsgs and mModKeyState.
585 * If mFollowingCharMsgs includes non-printable char messages, they are
588 void InitCommittedCharsAndModifiersWithFollowingCharMessages();
590 UINT
GetScanCodeWithExtendedFlag() const;
592 // The result is one of eKeyLocation*.
593 uint32_t GetKeyLocation() const;
596 * RemoveFollowingOddCharMessages() removes odd WM_CHAR messages from the
597 * queue when IsIMEDoingKakuteiUndo() returns true.
599 void RemoveFollowingOddCharMessages();
602 * "Kakutei-Undo" of ATOK or WXG (both of them are Japanese IME) causes
603 * strange WM_KEYDOWN/WM_KEYUP/WM_CHAR message pattern. So, when this
604 * returns true, the caller needs to be careful for processing the messages.
606 bool IsIMEDoingKakuteiUndo() const;
609 * This returns true if user types a number key in numpad with Alt key
610 * to input a Unicode character from its scalar value.
611 * Note that inputting Unicode scalar value is available without NumLock.
612 * Therefore, this returns true even if user presses a function key on
613 * numpad without NumLock, but that may be intended to perform a shortcut
614 * key like Alt + Home.
616 bool MaybeTypingUnicodeScalarValue() const {
617 return !mIsExtended
&& IsSysKeyDownOrKeyUpMessage() && IsAlt() &&
618 !IsControl() && !IsShift() &&
619 ((mScanCode
>= 0x004F && mScanCode
<= 0x0052) || // Numpad0-3
620 (mScanCode
>= 0x004B && mScanCode
<= 0x004D) || // Numpad4-6
621 (mScanCode
>= 0x0047 && mScanCode
<= 0x0049)); // Numpad7-9
624 bool IsKeyDownMessage() const {
625 return (mMsg
.message
== WM_KEYDOWN
|| mMsg
.message
== WM_SYSKEYDOWN
||
626 mMsg
.message
== MOZ_WM_KEYDOWN
);
628 bool IsKeyUpMessage() const {
629 return (mMsg
.message
== WM_KEYUP
|| mMsg
.message
== WM_SYSKEYUP
||
630 mMsg
.message
== MOZ_WM_KEYUP
);
632 bool IsSysKeyDownOrKeyUpMessage() const {
633 return mMsg
.message
== WM_SYSKEYDOWN
|| mMsg
.message
== WM_SYSKEYUP
;
635 bool IsCharOrSysCharMessage(const MSG
& aMSG
) const {
636 return IsCharOrSysCharMessage(aMSG
.message
);
638 bool IsCharOrSysCharMessage(UINT aMessage
) const {
639 return (aMessage
== WM_CHAR
|| aMessage
== WM_SYSCHAR
);
641 bool IsCharMessage(const MSG
& aMSG
) const {
642 return IsCharMessage(aMSG
.message
);
644 bool IsCharMessage(UINT aMessage
) const {
645 return (IsCharOrSysCharMessage(aMessage
) || IsDeadCharMessage(aMessage
));
647 bool IsDeadCharMessage(const MSG
& aMSG
) const {
648 return IsDeadCharMessage(aMSG
.message
);
650 bool IsDeadCharMessage(UINT aMessage
) const {
651 return (aMessage
== WM_DEADCHAR
|| aMessage
== WM_SYSDEADCHAR
);
653 bool IsSysCharMessage(const MSG
& aMSG
) const {
654 return IsSysCharMessage(aMSG
.message
);
656 bool IsSysCharMessage(UINT aMessage
) const {
657 return (aMessage
== WM_SYSCHAR
|| aMessage
== WM_SYSDEADCHAR
);
659 bool MayBeSameCharMessage(const MSG
& aCharMsg1
, const MSG
& aCharMsg2
) const;
660 bool IsSamePhysicalKeyMessage(const MSG
& aKeyOrCharMsg1
,
661 const MSG
& aKeyOrCharMsg2
) const;
662 bool IsFollowedByPrintableCharMessage() const;
663 bool IsFollowedByPrintableCharOrSysCharMessage() const;
664 bool IsFollowedByDeadCharMessage() const;
665 bool IsKeyMessageOnPlugin() const {
666 return (mMsg
.message
== MOZ_WM_KEYDOWN
|| mMsg
.message
== MOZ_WM_KEYUP
);
668 bool IsPrintableCharMessage(const MSG
& aMSG
) const {
669 return aMSG
.message
== WM_CHAR
&&
670 !IsControlChar(static_cast<char16_t
>(aMSG
.wParam
));
672 bool IsEnterKeyPressCharMessage(const MSG
& aMSG
) const {
673 return aMSG
.message
== WM_CHAR
&& aMSG
.wParam
== '\r';
675 bool IsPrintableCharOrSysCharMessage(const MSG
& aMSG
) const {
676 return IsCharOrSysCharMessage(aMSG
) &&
677 !IsControlChar(static_cast<char16_t
>(aMSG
.wParam
));
679 bool IsControlCharMessage(const MSG
& aMSG
) const {
680 return IsCharMessage(aMSG
.message
) &&
681 IsControlChar(static_cast<char16_t
>(aMSG
.wParam
));
685 * IsReservedBySystem() returns true if the key combination is reserved by
686 * the system. Even if it's consumed by web apps, the message should be
687 * sent to next wndproc.
689 bool IsReservedBySystem() const;
692 * GetFollowingCharMessage() returns following char message of handling
693 * keydown event. If the message is found, this method returns true.
694 * Otherwise, returns false.
696 * WARNING: Even if this returns true, aCharMsg may be WM_NULL or its
697 * hwnd may be different window.
699 bool GetFollowingCharMessage(MSG
& aCharMsg
);
702 * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK.
704 uint8_t ComputeVirtualKeyCodeFromScanCode() const;
707 * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK_EX.
709 uint8_t ComputeVirtualKeyCodeFromScanCodeEx() const;
712 * Wraps MapVirtualKeyEx() with MAPVK_VK_TO_VSC_EX or MAPVK_VK_TO_VSC.
714 uint16_t ComputeScanCodeExFromVirtualKeyCode(UINT aVirtualKeyCode
) const;
717 * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK and MAPVK_VK_TO_CHAR.
719 char16_t
ComputeUnicharFromScanCode() const;
722 * Initializes the aKeyEvent with the information stored in the instance.
724 nsEventStatus
InitKeyEvent(WidgetKeyboardEvent
& aKeyEvent
,
725 const ModifierKeyState
& aModKeyState
,
726 const MSG
* aMsgSentToPlugin
= nullptr) const;
727 nsEventStatus
InitKeyEvent(WidgetKeyboardEvent
& aKeyEvent
,
728 const MSG
* aMsgSentToPlugin
= nullptr) const;
731 * MaybeInitPluginEventOfKeyEvent() may initialize aKeyEvent::mPluginEvent
732 * with aMsgSentToPlugin if it's necessary.
734 void MaybeInitPluginEventOfKeyEvent(WidgetKeyboardEvent
& aKeyEvent
,
735 const MSG
& aMsgSentToPlugin
) const;
738 * Dispatches a command event for aEventCommand.
739 * Returns true if the event is consumed. Otherwise, false.
741 bool DispatchCommandEvent(uint32_t aEventCommand
) const;
744 * DispatchKeyPressEventsWithRetrievedCharMessages() dispatches keypress
745 * event(s) with retrieved char messages.
747 bool DispatchKeyPressEventsWithRetrievedCharMessages() const;
750 * DispatchKeyPressEventsWithoutCharMessage() dispatches keypress event(s)
751 * without char messages. So, this should be used only when there are no
752 * following char messages.
754 bool DispatchKeyPressEventsWithoutCharMessage() const;
757 * MaybeDispatchPluginEventsForRemovedCharMessages() dispatches plugin events
758 * for removed char messages when a windowless plugin has focus.
759 * Returns true if the widget is destroyed or blurred during dispatching a
762 bool MaybeDispatchPluginEventsForRemovedCharMessages() const;
765 * Checkes whether the key event down message is handled without following
766 * WM_CHAR messages. For example, if following WM_CHAR message indicates
767 * control character input, the WM_CHAR message is unclear whether it's
768 * caused by a printable key with Ctrl or just a function key such as Enter
771 bool NeedsToHandleWithoutFollowingCharMessages() const;
774 * ComputeInputtingStringWithKeyboardLayout() computes string to be inputted
775 * with the key and the modifier state, without shift state and with shift
778 void ComputeInputtingStringWithKeyboardLayout();
781 * IsFocusedWindowChanged() returns true if focused window is changed
782 * after the instance is created.
784 bool IsFocusedWindowChanged() const {
785 return mFocusedWndBeforeDispatch
!= ::GetFocus();
789 * Handles WM_CHAR message or WM_SYSCHAR message. The instance must be
790 * initialized with WM_KEYDOWN, WM_SYSKEYDOWN or them.
791 * Returns true if dispatched keypress event is consumed. Otherwise, false.
793 bool HandleCharMessage(const MSG
& aCharMsg
,
794 bool* aEventDispatched
= nullptr) const;
796 // Calls of PeekMessage() from NativeKey might cause nested message handling
797 // due to (perhaps) odd API hook. NativeKey should do nothing if given
798 // message is tried to be retrieved by another instance.
801 * sLatestInstacne is a pointer to the newest instance of NativeKey which is
802 * handling a key or char message(s).
804 static NativeKey
* sLatestInstance
;
806 static const MSG sEmptyMSG
;
808 static MSG sLastKeyOrCharMSG
;
810 static MSG sLastKeyMSG
;
812 static bool IsEmptyMSG(const MSG
& aMSG
) {
813 return !memcmp(&aMSG
, &sEmptyMSG
, sizeof(MSG
));
816 bool IsAnotherInstanceRemovingCharMessage() const {
817 return mLastInstance
&& !IsEmptyMSG(mLastInstance
->mRemovingMsg
);
822 * Returns last key or char MSG. If no MSG has been received yet, the result
823 * is empty MSG (i.e., .message is WM_NULL).
825 static const MSG
& LastKeyOrCharMSG() { return sLastKeyOrCharMSG
; }
828 class KeyboardLayout
{
830 static KeyboardLayout
* GetInstance();
831 static void Shutdown();
832 static HKL
GetActiveLayout();
833 static nsCString
GetActiveLayoutName();
834 static void NotifyIdleServiceOfUserActivity();
836 static bool IsPrintableCharKey(uint8_t aVirtualKey
);
839 * HasAltGr() returns true if the keyboard layout's AltRight key is AltGr
842 bool HasAltGr() const { return mHasAltGr
; }
845 * IsDeadKey() returns true if aVirtualKey is a dead key with aModKeyState.
846 * This method isn't stateful.
848 bool IsDeadKey(uint8_t aVirtualKey
,
849 const ModifierKeyState
& aModKeyState
) const;
850 bool IsDeadKey(const NativeKey
& aNativeKey
) const {
851 return IsDeadKey(aNativeKey
.GenericVirtualKeyCode(),
852 aNativeKey
.ModifierKeyStateRef());
856 * IsInDeadKeySequence() returns true when it's in a dead key sequence.
857 * It starts when a dead key is down and ends when another key down causes
858 * inactivating the dead key state.
860 bool IsInDeadKeySequence() const { return !mActiveDeadKeys
.IsEmpty(); }
863 * IsSysKey() returns true if aVirtualKey with aModKeyState causes WM_SYSKEY*
864 * or WM_SYS*CHAR messages.
866 bool IsSysKey(uint8_t aVirtualKey
,
867 const ModifierKeyState
& aModKeyState
) const;
868 bool IsSysKey(const NativeKey
& aNativeKey
) const {
869 return IsSysKey(aNativeKey
.GenericVirtualKeyCode(),
870 aNativeKey
.ModifierKeyStateRef());
874 * GetUniCharsAndModifiers() returns characters which are inputted by
875 * aVirtualKey with aModKeyState. This method isn't stateful.
876 * Note that if the combination causes text input, the result's Ctrl and
877 * Alt key state are never active.
879 UniCharsAndModifiers
GetUniCharsAndModifiers(
880 uint8_t aVirtualKey
, const ModifierKeyState
& aModKeyState
) const {
881 VirtualKey::ShiftState shiftState
=
882 VirtualKey::ModifierKeyStateToShiftState(aModKeyState
);
883 return GetUniCharsAndModifiers(aVirtualKey
, shiftState
);
885 UniCharsAndModifiers
GetUniCharsAndModifiers(
886 const NativeKey
& aNativeKey
) const {
887 return GetUniCharsAndModifiers(aNativeKey
.GenericVirtualKeyCode(),
888 aNativeKey
.GetShiftState());
892 * OnLayoutChange() must be called before the first keydown message is
893 * received. LoadLayout() changes the keyboard state, that causes breaking
894 * dead key state. Therefore, we need to load the layout before the first
897 void OnLayoutChange(HKL aKeyboardLayout
) {
898 MOZ_ASSERT(!mIsOverridden
);
899 LoadLayout(aKeyboardLayout
);
903 * OverrideLayout() loads the specified keyboard layout.
905 void OverrideLayout(HKL aLayout
) {
906 mIsOverridden
= true;
911 * RestoreLayout() loads the current keyboard layout of the thread.
913 void RestoreLayout() {
914 mIsOverridden
= false;
915 mIsPendingToRestoreKeyboardLayout
= true;
918 uint32_t ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode
) const;
921 * ConvertNativeKeyCodeToKeyNameIndex() returns KeyNameIndex value for
922 * non-printable keys (except some special keys like space key).
924 KeyNameIndex
ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey
) const;
927 * ConvertScanCodeToCodeNameIndex() returns CodeNameIndex value for
928 * the given scan code. aScanCode can be over 0xE000 since this method
929 * doesn't use Windows API.
931 static CodeNameIndex
ConvertScanCodeToCodeNameIndex(UINT aScanCode
);
933 HKL
GetLayout() const {
934 return mIsPendingToRestoreKeyboardLayout
? ::GetKeyboardLayout(0)
939 * This wraps MapVirtualKeyEx() API with MAPVK_VK_TO_VSC.
941 WORD
ComputeScanCodeForVirtualKeyCode(uint8_t aVirtualKeyCode
) const;
944 * Implementation of nsIWidget::SynthesizeNativeKeyEvent().
946 nsresult
SynthesizeNativeKeyEvent(nsWindowBase
* aWidget
,
947 int32_t aNativeKeyboardLayout
,
948 int32_t aNativeKeyCode
,
949 uint32_t aModifierFlags
,
950 const nsAString
& aCharacters
,
951 const nsAString
& aUnmodifiedCharacters
);
957 static KeyboardLayout
* sInstance
;
958 static nsIUserIdleServiceInternal
* sIdleService
;
960 struct DeadKeyTableListEntry
{
961 DeadKeyTableListEntry
* next
;
967 VirtualKey mVirtualKeys
[NS_NUM_OF_KEYS
];
968 DeadKeyTableListEntry
* mDeadKeyTableListHead
;
969 // When mActiveDeadKeys is empty, it's not in dead key sequence.
970 // Otherwise, it contains virtual keycodes which are pressed in current
971 // dead key sequence.
972 nsTArray
<uint8_t> mActiveDeadKeys
;
973 // mDeadKeyShiftStates is always same length as mActiveDeadKeys.
974 // This stores shift states at pressing each dead key stored in
976 nsTArray
<VirtualKey::ShiftState
> mDeadKeyShiftStates
;
979 bool mIsPendingToRestoreKeyboardLayout
;
982 static inline int32_t GetKeyIndex(uint8_t aVirtualKey
);
983 static int CompareDeadKeyEntries(const void* aArg1
, const void* aArg2
,
985 static bool AddDeadKeyEntry(char16_t aBaseChar
, char16_t aCompositeChar
,
986 DeadKeyEntry
* aDeadKeyArray
, uint32_t aEntries
);
987 bool EnsureDeadKeyActive(bool aIsActive
, uint8_t aDeadKey
,
988 const PBYTE aDeadKeyKbdState
);
989 uint32_t GetDeadKeyCombinations(uint8_t aDeadKey
,
990 const PBYTE aDeadKeyKbdState
,
991 uint16_t aShiftStatesWithBaseChars
,
992 DeadKeyEntry
* aDeadKeyArray
,
993 uint32_t aMaxEntries
);
995 * Activates or deactivates dead key state.
997 void ActivateDeadKeyState(const NativeKey
& aNativeKey
);
998 void DeactivateDeadKeyState();
1000 const DeadKeyTable
* AddDeadKeyTable(const DeadKeyEntry
* aDeadKeyArray
,
1002 void ReleaseDeadKeyTables();
1005 * Loads the specified keyboard layout. This method always clear the dead key
1008 void LoadLayout(HKL aLayout
);
1011 * Gets the keyboard layout name of aLayout. Be careful, this may be too
1012 * slow to call at handling user input.
1014 nsCString
GetLayoutName(HKL aLayout
) const;
1017 * InitNativeKey() must be called when actually widget receives WM_KEYDOWN or
1018 * WM_KEYUP. This method is stateful. This saves current dead key state at
1019 * WM_KEYDOWN. Additionally, computes current inputted character(s) and set
1020 * them to the aNativeKey.
1022 void InitNativeKey(NativeKey
& aNativeKey
);
1025 * MaybeInitNativeKeyAsDeadKey() initializes aNativeKey only when aNativeKey
1026 * is a dead key's event.
1027 * When it's not in a dead key sequence, this activates the dead key state.
1028 * When it's in a dead key sequence, this initializes aNativeKey with a
1029 * composite character or a preceding dead char and a dead char which should
1030 * be caused by aNativeKey.
1031 * Returns true when this initializes aNativeKey. Otherwise, false.
1033 bool MaybeInitNativeKeyAsDeadKey(NativeKey
& aNativeKey
);
1036 * MaybeInitNativeKeyWithCompositeChar() may initialize aNativeKey with
1037 * proper composite character when dead key produces a composite character.
1038 * Otherwise, just returns false.
1040 bool MaybeInitNativeKeyWithCompositeChar(NativeKey
& aNativeKey
);
1043 * See the comment of GetUniCharsAndModifiers() below.
1045 UniCharsAndModifiers
GetUniCharsAndModifiers(
1046 uint8_t aVirtualKey
, VirtualKey::ShiftState aShiftState
) const;
1049 * GetDeadUniCharsAndModifiers() returns dead chars which are stored in
1050 * current dead key sequence. So, this is stateful.
1052 UniCharsAndModifiers
GetDeadUniCharsAndModifiers() const;
1055 * GetCompositeChar() returns a composite character with dead character
1056 * caused by mActiveDeadKeys, mDeadKeyShiftStates and a base character
1058 * If the combination of the dead character and the base character doesn't
1059 * cause a composite character, this returns 0.
1061 char16_t
GetCompositeChar(char16_t aBaseChar
) const;
1063 // NativeKey class should access InitNativeKey() directly, but it shouldn't
1064 // be available outside of NativeKey. So, let's make NativeKey a friend
1066 friend class NativeKey
;
1069 class RedirectedKeyDownMessageManager
{
1072 * If a window receives WM_KEYDOWN message or WM_SYSKEYDOWM message which is
1073 * a redirected message, NativeKey::DispatchKeyDownAndKeyPressEvent()
1074 * prevents to dispatch eKeyDown event because it has been dispatched
1075 * before the message was redirected. However, in some cases, WM_*KEYDOWN
1076 * message handler may not handle actually. Then, the message handler needs
1077 * to forget the redirected message and remove WM_CHAR message or WM_SYSCHAR
1078 * message for the redirected keydown message. AutoFlusher class is a helper
1079 * class for doing it. This must be created in the stack.
1081 class MOZ_STACK_CLASS AutoFlusher final
{
1083 AutoFlusher(nsWindowBase
* aWidget
, const MSG
& aMsg
)
1084 : mCancel(!RedirectedKeyDownMessageManager::IsRedirectedMessage(aMsg
)),
1092 // Prevent unnecessary keypress event
1093 if (!mWidget
->Destroyed()) {
1094 RedirectedKeyDownMessageManager::RemoveNextCharMessage(mMsg
.hwnd
);
1096 // Foreget the redirected message
1097 RedirectedKeyDownMessageManager::Forget();
1100 void Cancel() { mCancel
= true; }
1104 RefPtr
<nsWindowBase
> mWidget
;
1108 static void WillRedirect(const MSG
& aMsg
, bool aDefualtPrevented
) {
1109 sRedirectedKeyDownMsg
= aMsg
;
1110 sDefaultPreventedOfRedirectedMsg
= aDefualtPrevented
;
1113 static void Forget() { sRedirectedKeyDownMsg
.message
= WM_NULL
; }
1115 static void PreventDefault() { sDefaultPreventedOfRedirectedMsg
= true; }
1116 static bool DefaultPrevented() { return sDefaultPreventedOfRedirectedMsg
; }
1118 static bool IsRedirectedMessage(const MSG
& aMsg
);
1121 * RemoveNextCharMessage() should be called by WM_KEYDOWN or WM_SYSKEYDOWM
1122 * message handler. If there is no WM_(SYS)CHAR message for it, this
1123 * method does nothing.
1124 * NOTE: WM_(SYS)CHAR message is posted by TranslateMessage() API which is
1125 * called in message loop. So, WM_(SYS)KEYDOWN message should have
1126 * WM_(SYS)CHAR message in the queue if the keydown event causes character
1129 static void RemoveNextCharMessage(HWND aWnd
);
1132 // sRedirectedKeyDownMsg is WM_KEYDOWN message or WM_SYSKEYDOWN message which
1133 // is reirected with SendInput() API by
1134 // widget::NativeKey::DispatchKeyDownAndKeyPressEvent()
1135 static MSG sRedirectedKeyDownMsg
;
1136 static bool sDefaultPreventedOfRedirectedMsg
;
1139 } // namespace widget
1140 } // namespace mozilla