Bug 1861709 replace AudioCallbackDriver::ThreadRunning() assertions that mean to...
[gecko.git] / widget / windows / KeyboardLayout.h
blob78a0892da7beff905af69b3e6586b9e182e1f20c
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"
10 #include "nscore.h"
11 #include "nsString.h"
12 #include "nsWindow.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>
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
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
42 class nsIUserIdleServiceInternal;
44 namespace mozilla {
45 namespace widget {
47 enum ScanCode : uint16_t {
48 eCapsLock = 0x003A,
49 eNumLock = 0xE045,
50 eShiftLeft = 0x002A,
51 eShiftRight = 0x0036,
52 eControlLeft = 0x001D,
53 eControlRight = 0xE01D,
54 eAltLeft = 0x0038,
55 eAltRight = 0xE038,
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.
61 // 3: Scan code.
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}};
72 class KeyboardLayout;
74 class MOZ_STACK_CLASS UniCharsAndModifiers final {
75 public:
76 UniCharsAndModifiers() {}
77 UniCharsAndModifiers operator+(const UniCharsAndModifiers& aOther) const;
78 UniCharsAndModifiers& operator+=(const UniCharsAndModifiers& aOther);
80 /**
81 * Append a pair of unicode character and the final modifier.
83 void Append(char16_t aUniChar, Modifiers aModifiers);
84 void Clear() {
85 mChars.Truncate();
86 mModifiers.Clear();
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; }
123 private:
124 nsAutoString 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 {
131 char16_t BaseChar;
132 char16_t CompositeChar;
135 class DeadKeyTable {
136 friend class KeyboardLayout;
138 uint16_t mEntries;
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) {
144 mEntries = aEntries;
145 memcpy(mTable, aDeadKeyArray, aEntries * sizeof(DeadKeyEntry));
148 static uint32_t SizeInBytes(uint32_t aEntries) {
149 return offsetof(DeadKeyTable, mTable) + aEntries * sizeof(DeadKeyEntry);
152 public:
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;
163 class VirtualKey {
164 public:
165 enum ShiftStateIndex : uint8_t {
166 // 0 - Normal
167 eNormal = 0,
168 // 1 - Shift
169 eShift,
170 // 2 - Control
171 eControl,
172 // 3 - Control + Shift
173 eControlShift,
174 // 4 - Alt
175 eAlt,
176 // 5 - Alt + Shift
177 eAltShift,
178 // 6 - Alt + Control (AltGr)
179 eAltGr,
180 // 7 - Alt + Control + Shift (AltGr + Shift)
181 eAltGrShift,
182 // 8 - CapsLock
183 eWithCapsLock,
184 // 9 - CapsLock + Shift
185 eShiftWithCapsLock,
186 // 10 - CapsLock + Control
187 eControlWithCapsLock,
188 // 11 - CapsLock + Control + Shift
189 eControlShiftWithCapsLock,
190 // 12 - CapsLock + Alt
191 eAltWithCapsLock,
192 // 13 - CapsLock + Alt + Shift
193 eAltShiftWithCapsLock,
194 // 14 - CapsLock + Alt + Control (CapsLock + AltGr)
195 eAltGrWithCapsLock,
196 // 15 - CapsLock + Alt + Control + Shift (CapsLock + AltGr + Shift)
197 eAltGrShiftWithCapsLock,
200 enum ShiftStateFlag {
201 STATE_SHIFT = 0x01,
202 STATE_CONTROL = 0x02,
203 STATE_ALT = 0x04,
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;
224 private:
225 union KeyShiftState {
226 struct {
227 char16_t Chars[4];
228 } Normal;
229 struct {
230 const DeadKeyTable* Table;
231 char16_t DeadChar;
232 } DeadKey;
235 KeyShiftState mShiftStates[16];
236 uint16_t mIsDeadKey;
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);
246 return index;
249 void SetDeadKey(ShiftState aShiftState, bool aIsDeadKey) {
250 if (aIsDeadKey) {
251 mIsDeadKey |= 1 << ToShiftStateIndex(aShiftState);
252 } else {
253 mIsDeadKey &= ~(1 << ToShiftStateIndex(aShiftState));
257 public:
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)) {
280 return false;
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]) {
289 return true;
291 if (!mShiftStates[aShiftState].Normal.Chars[i] &&
292 !mShiftStates[kShiftStateWithoutAltGr].Normal.Chars[i]) {
293 return false;
296 return false;
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),
319 aBaseChar);
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
339 * value.
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
354 * MODIFIER_ALTGRAPH.
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;
367 public:
368 struct FakeCharMsg {
369 UINT mCharCode;
370 UINT mScanCode;
371 bool mIsSysKey;
372 bool mIsDeadKey;
373 bool mConsumed;
375 FakeCharMsg()
376 : mCharCode(0),
377 mScanCode(0),
378 mIsSysKey(false),
379 mIsDeadKey(false),
380 mConsumed(false) {}
382 MSG GetCharMsg(HWND aWnd) const {
383 MSG msg;
384 msg.hwnd = aWnd;
385 msg.message = mIsDeadKey && mIsSysKey ? WM_SYSDEADCHAR
386 : mIsDeadKey ? WM_DEADCHAR
387 : mIsSysKey ? WM_SYSCHAR
388 : WM_CHAR;
389 msg.wParam = static_cast<WPARAM>(mCharCode);
390 msg.lParam = static_cast<LPARAM>(mScanCode << 16);
391 msg.time = 0;
392 msg.pt.x = msg.pt.y = 0;
393 return msg;
397 NativeKey(nsWindow* aWidget, const MSG& aMessage,
398 const ModifierKeyState& aModKeyState,
399 HKL aOverrideKeyboardLayout = 0,
400 nsTArray<FakeCharMsg>* aFakeCharMsgs = nullptr);
402 ~NativeKey();
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.
408 * Otherwise, false.
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.
421 * Otherwise, false.
423 bool HandleKeyUpMessage(bool* aEventDispatched = nullptr) const;
426 * Handles WM_APPCOMMAND message. Returns true if the event is consumed.
427 * Otherwise, false.
429 bool HandleAppCommandMessage() const;
432 * Callback of TextEventDispatcherListener::WillDispatchKeyboardEvent().
433 * This method sets alternative char codes of aKeyboardEvent.
435 void WillDispatchKeyboardEvent(WidgetKeyboardEvent& aKeyboardEvent,
436 uint32_t aIndex);
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
457 * ControlRight.
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; }
469 private:
470 NativeKey* mLastInstance;
471 // mRemovingMsg is set at removing a char message from
472 // GetFollowingCharMessage().
473 MSG mRemovingMsg;
474 // mReceivedMsg is set when another instance starts to handle the message
475 // unexpectedly.
476 MSG mReceivedMsg;
477 RefPtr<nsWindow> mWidget;
478 RefPtr<TextEventDispatcher> mDispatcher;
479 HKL mKeyboardLayout;
480 MSG mMsg;
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
530 // as charCode.
531 uint32_t mShiftedLatinChar;
532 uint32_t mUnshiftedLatinChar;
534 WORD mScanCode;
535 bool mIsExtended;
536 // mIsRepeat is true if the key message is caused by the auto-repeat
537 // feature.
538 bool mIsRepeat;
539 bool mIsDeadKey;
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;
568 NativeKey() {
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
586 * ignored (skipped).
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;
627 bool IsKeyUpMessage() const {
628 return mMsg.message == WM_KEYUP || mMsg.message == WM_SYSKEYUP;
630 bool IsSysKeyDownOrKeyUpMessage() const {
631 return mMsg.message == WM_SYSKEYDOWN || mMsg.message == WM_SYSKEYUP;
633 bool IsCharOrSysCharMessage(const MSG& aMSG) const {
634 return IsCharOrSysCharMessage(aMSG.message);
636 bool IsCharOrSysCharMessage(UINT aMessage) const {
637 return (aMessage == WM_CHAR || aMessage == WM_SYSCHAR);
639 bool IsCharMessage(const MSG& aMSG) const {
640 return IsCharMessage(aMSG.message);
642 bool IsCharMessage(UINT aMessage) const {
643 return (IsCharOrSysCharMessage(aMessage) || IsDeadCharMessage(aMessage));
645 bool IsDeadCharMessage(const MSG& aMSG) const {
646 return IsDeadCharMessage(aMSG.message);
648 bool IsDeadCharMessage(UINT aMessage) const {
649 return (aMessage == WM_DEADCHAR || aMessage == WM_SYSDEADCHAR);
651 bool IsSysCharMessage(const MSG& aMSG) const {
652 return IsSysCharMessage(aMSG.message);
654 bool IsSysCharMessage(UINT aMessage) const {
655 return (aMessage == WM_SYSCHAR || aMessage == WM_SYSDEADCHAR);
657 bool MayBeSameCharMessage(const MSG& aCharMsg1, const MSG& aCharMsg2) const;
658 bool IsSamePhysicalKeyMessage(const MSG& aKeyOrCharMsg1,
659 const MSG& aKeyOrCharMsg2) const;
660 bool IsFollowedByPrintableCharMessage() const;
661 bool IsFollowedByPrintableCharOrSysCharMessage() const;
662 bool IsFollowedByDeadCharMessage() const;
663 bool IsPrintableCharMessage(const MSG& aMSG) const {
664 return aMSG.message == WM_CHAR &&
665 !IsControlChar(static_cast<char16_t>(aMSG.wParam));
667 bool IsEnterKeyPressCharMessage(const MSG& aMSG) const {
668 return aMSG.message == WM_CHAR && aMSG.wParam == '\r';
670 bool IsPrintableCharOrSysCharMessage(const MSG& aMSG) const {
671 return IsCharOrSysCharMessage(aMSG) &&
672 !IsControlChar(static_cast<char16_t>(aMSG.wParam));
674 bool IsControlCharMessage(const MSG& aMSG) const {
675 return IsCharMessage(aMSG.message) &&
676 IsControlChar(static_cast<char16_t>(aMSG.wParam));
680 * IsReservedBySystem() returns true if the key combination is reserved by
681 * the system. Even if it's consumed by web apps, the message should be
682 * sent to next wndproc.
684 bool IsReservedBySystem() const;
687 * GetFollowingCharMessage() returns following char message of handling
688 * keydown event. If the message is found, this method returns true.
689 * Otherwise, returns false.
691 * WARNING: Even if this returns true, aCharMsg may be WM_NULL or its
692 * hwnd may be different window.
694 bool GetFollowingCharMessage(MSG& aCharMsg);
697 * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK.
699 uint8_t ComputeVirtualKeyCodeFromScanCode() const;
702 * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK_EX.
704 uint8_t ComputeVirtualKeyCodeFromScanCodeEx() const;
707 * Wraps MapVirtualKeyEx() with MAPVK_VK_TO_VSC_EX or MAPVK_VK_TO_VSC.
709 uint16_t ComputeScanCodeExFromVirtualKeyCode(UINT aVirtualKeyCode) const;
712 * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK and MAPVK_VK_TO_CHAR.
714 char16_t ComputeUnicharFromScanCode() const;
717 * Initializes the aKeyEvent with the information stored in the instance.
719 nsEventStatus InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
720 const ModifierKeyState& aModKeyState) const;
721 nsEventStatus InitKeyEvent(WidgetKeyboardEvent& aKeyEvent) const;
724 * Dispatches a command event for aEventCommand.
725 * Returns true if the event is consumed. Otherwise, false.
727 bool DispatchCommandEvent(uint32_t aEventCommand) const;
730 * DispatchKeyPressEventsWithRetrievedCharMessages() dispatches keypress
731 * event(s) with retrieved char messages.
733 bool DispatchKeyPressEventsWithRetrievedCharMessages() const;
736 * DispatchKeyPressEventsWithoutCharMessage() dispatches keypress event(s)
737 * without char messages. So, this should be used only when there are no
738 * following char messages.
740 bool DispatchKeyPressEventsWithoutCharMessage() const;
743 * Checkes whether the key event down message is handled without following
744 * WM_CHAR messages. For example, if following WM_CHAR message indicates
745 * control character input, the WM_CHAR message is unclear whether it's
746 * caused by a printable key with Ctrl or just a function key such as Enter
747 * or Backspace.
749 bool NeedsToHandleWithoutFollowingCharMessages() const;
752 * ComputeInputtingStringWithKeyboardLayout() computes string to be inputted
753 * with the key and the modifier state, without shift state and with shift
754 * state.
756 void ComputeInputtingStringWithKeyboardLayout();
759 * IsFocusedWindowChanged() returns true if focused window is changed
760 * after the instance is created.
762 bool IsFocusedWindowChanged() const {
763 return mFocusedWndBeforeDispatch != ::GetFocus();
767 * Handles WM_CHAR message or WM_SYSCHAR message. The instance must be
768 * initialized with WM_KEYDOWN, WM_SYSKEYDOWN or them.
769 * Returns true if dispatched keypress event is consumed. Otherwise, false.
771 bool HandleCharMessage(const MSG& aCharMsg,
772 bool* aEventDispatched = nullptr) const;
774 // Calls of PeekMessage() from NativeKey might cause nested message handling
775 // due to (perhaps) odd API hook. NativeKey should do nothing if given
776 // message is tried to be retrieved by another instance.
779 * sLatestInstacne is a pointer to the newest instance of NativeKey which is
780 * handling a key or char message(s).
782 static NativeKey* sLatestInstance;
784 static const MSG sEmptyMSG;
786 static MSG sLastKeyOrCharMSG;
788 static MSG sLastKeyMSG;
790 // Set to non-zero if we receive a WM_KEYDOWN message which introduces only
791 // a high surrogate. Then, it'll be cleared when next keydown or char message
792 // is received.
793 static char16_t sPendingHighSurrogate;
795 static bool IsEmptyMSG(const MSG& aMSG) {
796 return !memcmp(&aMSG, &sEmptyMSG, sizeof(MSG));
799 bool IsAnotherInstanceRemovingCharMessage() const {
800 return mLastInstance && !IsEmptyMSG(mLastInstance->mRemovingMsg);
803 public:
805 * Returns last key or char MSG. If no MSG has been received yet, the result
806 * is empty MSG (i.e., .message is WM_NULL).
808 static const MSG& LastKeyOrCharMSG() { return sLastKeyOrCharMSG; }
811 class KeyboardLayout {
812 public:
813 static KeyboardLayout* GetInstance();
814 static void Shutdown();
815 static HKL GetActiveLayout();
816 static nsCString GetActiveLayoutName();
817 static void NotifyIdleServiceOfUserActivity();
819 static bool IsPrintableCharKey(uint8_t aVirtualKey);
822 * HasAltGr() returns true if the keyboard layout's AltRight key is AltGr
823 * key.
825 bool HasAltGr() const { return mHasAltGr; }
828 * IsDeadKey() returns true if aVirtualKey is a dead key with aModKeyState.
829 * This method isn't stateful.
831 bool IsDeadKey(uint8_t aVirtualKey,
832 const ModifierKeyState& aModKeyState) const;
833 bool IsDeadKey(const NativeKey& aNativeKey) const {
834 return IsDeadKey(aNativeKey.GenericVirtualKeyCode(),
835 aNativeKey.ModifierKeyStateRef());
839 * IsInDeadKeySequence() returns true when it's in a dead key sequence.
840 * It starts when a dead key is down and ends when another key down causes
841 * inactivating the dead key state.
843 bool IsInDeadKeySequence() const { return !mActiveDeadKeys.IsEmpty(); }
846 * IsSysKey() returns true if aVirtualKey with aModKeyState causes WM_SYSKEY*
847 * or WM_SYS*CHAR messages.
849 bool IsSysKey(uint8_t aVirtualKey,
850 const ModifierKeyState& aModKeyState) const;
851 bool IsSysKey(const NativeKey& aNativeKey) const {
852 return IsSysKey(aNativeKey.GenericVirtualKeyCode(),
853 aNativeKey.ModifierKeyStateRef());
857 * GetUniCharsAndModifiers() returns characters which are inputted by
858 * aVirtualKey with aModKeyState. This method isn't stateful.
859 * Note that if the combination causes text input, the result's Ctrl and
860 * Alt key state are never active.
862 UniCharsAndModifiers GetUniCharsAndModifiers(
863 uint8_t aVirtualKey, const ModifierKeyState& aModKeyState) const {
864 VirtualKey::ShiftState shiftState =
865 VirtualKey::ModifierKeyStateToShiftState(aModKeyState);
866 return GetUniCharsAndModifiers(aVirtualKey, shiftState);
868 UniCharsAndModifiers GetUniCharsAndModifiers(
869 const NativeKey& aNativeKey) const {
870 return GetUniCharsAndModifiers(aNativeKey.GenericVirtualKeyCode(),
871 aNativeKey.GetShiftState());
875 * OnLayoutChange() must be called before the first keydown message is
876 * received. LoadLayout() changes the keyboard state, that causes breaking
877 * dead key state. Therefore, we need to load the layout before the first
878 * keydown message.
880 void OnLayoutChange(HKL aKeyboardLayout) {
881 MOZ_ASSERT(!mIsOverridden);
882 LoadLayout(aKeyboardLayout);
886 * OverrideLayout() loads the specified keyboard layout.
888 void OverrideLayout(HKL aLayout) {
889 mIsOverridden = true;
890 LoadLayout(aLayout);
894 * RestoreLayout() loads the current keyboard layout of the thread.
896 void RestoreLayout() {
897 mIsOverridden = false;
898 mIsPendingToRestoreKeyboardLayout = true;
901 uint32_t ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const;
904 * ConvertNativeKeyCodeToKeyNameIndex() returns KeyNameIndex value for
905 * non-printable keys (except some special keys like space key).
907 KeyNameIndex ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const;
910 * ConvertScanCodeToCodeNameIndex() returns CodeNameIndex value for
911 * the given scan code. aScanCode can be over 0xE000 since this method
912 * doesn't use Windows API.
914 static CodeNameIndex ConvertScanCodeToCodeNameIndex(UINT aScanCode);
916 HKL GetLayout() const {
917 return mIsPendingToRestoreKeyboardLayout ? ::GetKeyboardLayout(0)
918 : mKeyboardLayout;
922 * This wraps MapVirtualKeyEx() API with MAPVK_VK_TO_VSC.
924 WORD ComputeScanCodeForVirtualKeyCode(uint8_t aVirtualKeyCode) const;
927 * Implementation of nsIWidget::SynthesizeNativeKeyEvent().
929 nsresult SynthesizeNativeKeyEvent(nsWindow* aWidget,
930 int32_t aNativeKeyboardLayout,
931 int32_t aNativeKeyCode,
932 uint32_t aModifierFlags,
933 const nsAString& aCharacters,
934 const nsAString& aUnmodifiedCharacters);
936 private:
937 KeyboardLayout();
938 ~KeyboardLayout();
940 static KeyboardLayout* sInstance;
941 static nsIUserIdleServiceInternal* sIdleService;
943 struct DeadKeyTableListEntry {
944 DeadKeyTableListEntry* next;
945 uint8_t data[1];
948 HKL mKeyboardLayout;
950 VirtualKey mVirtualKeys[NS_NUM_OF_KEYS];
951 DeadKeyTableListEntry* mDeadKeyTableListHead;
952 // When mActiveDeadKeys is empty, it's not in dead key sequence.
953 // Otherwise, it contains virtual keycodes which are pressed in current
954 // dead key sequence.
955 nsTArray<uint8_t> mActiveDeadKeys;
956 // mDeadKeyShiftStates is always same length as mActiveDeadKeys.
957 // This stores shift states at pressing each dead key stored in
958 // mActiveDeadKeys.
959 nsTArray<VirtualKey::ShiftState> mDeadKeyShiftStates;
961 bool mIsOverridden;
962 bool mIsPendingToRestoreKeyboardLayout;
963 bool mHasAltGr;
965 static inline int32_t GetKeyIndex(uint8_t aVirtualKey);
966 static int CompareDeadKeyEntries(const void* aArg1, const void* aArg2,
967 void* aData);
968 static bool AddDeadKeyEntry(char16_t aBaseChar, char16_t aCompositeChar,
969 DeadKeyEntry* aDeadKeyArray, uint32_t aEntries);
970 bool EnsureDeadKeyActive(bool aIsActive, uint8_t aDeadKey,
971 const PBYTE aDeadKeyKbdState);
972 uint32_t GetDeadKeyCombinations(uint8_t aDeadKey,
973 const PBYTE aDeadKeyKbdState,
974 uint16_t aShiftStatesWithBaseChars,
975 DeadKeyEntry* aDeadKeyArray,
976 uint32_t aMaxEntries);
978 * Activates or deactivates dead key state.
980 void ActivateDeadKeyState(const NativeKey& aNativeKey);
981 void DeactivateDeadKeyState();
983 const DeadKeyTable* AddDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
984 uint32_t aEntries);
985 void ReleaseDeadKeyTables();
988 * Loads the specified keyboard layout. This method always clear the dead key
989 * state.
991 void LoadLayout(HKL aLayout);
994 * Gets the keyboard layout name of aLayout. Be careful, this may be too
995 * slow to call at handling user input.
997 nsCString GetLayoutName(HKL aLayout) const;
1000 * InitNativeKey() must be called when actually widget receives WM_KEYDOWN or
1001 * WM_KEYUP. This method is stateful. This saves current dead key state at
1002 * WM_KEYDOWN. Additionally, computes current inputted character(s) and set
1003 * them to the aNativeKey.
1005 void InitNativeKey(NativeKey& aNativeKey);
1008 * MaybeInitNativeKeyAsDeadKey() initializes aNativeKey only when aNativeKey
1009 * is a dead key's event.
1010 * When it's not in a dead key sequence, this activates the dead key state.
1011 * When it's in a dead key sequence, this initializes aNativeKey with a
1012 * composite character or a preceding dead char and a dead char which should
1013 * be caused by aNativeKey.
1014 * Returns true when this initializes aNativeKey. Otherwise, false.
1016 bool MaybeInitNativeKeyAsDeadKey(NativeKey& aNativeKey);
1019 * MaybeInitNativeKeyWithCompositeChar() may initialize aNativeKey with
1020 * proper composite character when dead key produces a composite character.
1021 * Otherwise, just returns false.
1023 bool MaybeInitNativeKeyWithCompositeChar(NativeKey& aNativeKey);
1026 * See the comment of GetUniCharsAndModifiers() below.
1028 UniCharsAndModifiers GetUniCharsAndModifiers(
1029 uint8_t aVirtualKey, VirtualKey::ShiftState aShiftState) const;
1032 * GetDeadUniCharsAndModifiers() returns dead chars which are stored in
1033 * current dead key sequence. So, this is stateful.
1035 UniCharsAndModifiers GetDeadUniCharsAndModifiers() const;
1038 * GetCompositeChar() returns a composite character with dead character
1039 * caused by mActiveDeadKeys, mDeadKeyShiftStates and a base character
1040 * (aBaseChar).
1041 * If the combination of the dead character and the base character doesn't
1042 * cause a composite character, this returns 0.
1044 char16_t GetCompositeChar(char16_t aBaseChar) const;
1046 // NativeKey class should access InitNativeKey() directly, but it shouldn't
1047 // be available outside of NativeKey. So, let's make NativeKey a friend
1048 // class of this.
1049 friend class NativeKey;
1052 class RedirectedKeyDownMessageManager {
1053 public:
1055 * If a window receives WM_KEYDOWN message or WM_SYSKEYDOWM message which is
1056 * a redirected message, NativeKey::DispatchKeyDownAndKeyPressEvent()
1057 * prevents to dispatch eKeyDown event because it has been dispatched
1058 * before the message was redirected. However, in some cases, WM_*KEYDOWN
1059 * message handler may not handle actually. Then, the message handler needs
1060 * to forget the redirected message and remove WM_CHAR message or WM_SYSCHAR
1061 * message for the redirected keydown message. AutoFlusher class is a helper
1062 * class for doing it. This must be created in the stack.
1064 class MOZ_STACK_CLASS AutoFlusher final {
1065 public:
1066 AutoFlusher(nsWindow* aWidget, const MSG& aMsg)
1067 : mCancel(!RedirectedKeyDownMessageManager::IsRedirectedMessage(aMsg)),
1068 mWidget(aWidget),
1069 mMsg(aMsg) {}
1071 ~AutoFlusher() {
1072 if (mCancel) {
1073 return;
1075 // Prevent unnecessary keypress event
1076 if (!mWidget->Destroyed()) {
1077 RedirectedKeyDownMessageManager::RemoveNextCharMessage(mMsg.hwnd);
1079 // Foreget the redirected message
1080 RedirectedKeyDownMessageManager::Forget();
1083 void Cancel() { mCancel = true; }
1085 private:
1086 bool mCancel;
1087 RefPtr<nsWindow> mWidget;
1088 const MSG& mMsg;
1091 static void WillRedirect(const MSG& aMsg, bool aDefualtPrevented) {
1092 sRedirectedKeyDownMsg = aMsg;
1093 sDefaultPreventedOfRedirectedMsg = aDefualtPrevented;
1096 static void Forget() { sRedirectedKeyDownMsg.message = WM_NULL; }
1098 static void PreventDefault() { sDefaultPreventedOfRedirectedMsg = true; }
1099 static bool DefaultPrevented() { return sDefaultPreventedOfRedirectedMsg; }
1101 static bool IsRedirectedMessage(const MSG& aMsg);
1104 * RemoveNextCharMessage() should be called by WM_KEYDOWN or WM_SYSKEYDOWM
1105 * message handler. If there is no WM_(SYS)CHAR message for it, this
1106 * method does nothing.
1107 * NOTE: WM_(SYS)CHAR message is posted by TranslateMessage() API which is
1108 * called in message loop. So, WM_(SYS)KEYDOWN message should have
1109 * WM_(SYS)CHAR message in the queue if the keydown event causes character
1110 * input.
1112 static void RemoveNextCharMessage(HWND aWnd);
1114 private:
1115 // sRedirectedKeyDownMsg is WM_KEYDOWN message or WM_SYSKEYDOWN message which
1116 // is reirected with SendInput() API by
1117 // widget::NativeKey::DispatchKeyDownAndKeyPressEvent()
1118 static MSG sRedirectedKeyDownMsg;
1119 static bool sDefaultPreventedOfRedirectedMsg;
1122 } // namespace widget
1123 } // namespace mozilla
1125 #endif