Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/ArrayUtils.h"
7 #include "mozilla/DebugOnly.h"
8 #include "mozilla/MouseEvents.h"
9 #include "mozilla/TextEvents.h"
10 #include "mozilla/WindowsVersion.h"
12 #include "KeyboardLayout.h"
13 #include "nsIMM32Handler.h"
15 #include "nsMemory.h"
16 #include "nsToolkit.h"
17 #include "nsQuickSort.h"
18 #include "nsAlgorithm.h"
19 #include "nsUnicharUtils.h"
20 #include "WidgetUtils.h"
21 #include "WinUtils.h"
22 #include "nsWindowDbg.h"
23 #include "nsServiceManagerUtils.h"
24 #include "nsPrintfCString.h"
26 #include "nsIDOMKeyEvent.h"
27 #include "nsIIdleServiceInternal.h"
29 #ifdef MOZ_CRASHREPORTER
30 #include "nsExceptionHandler.h"
31 #endif
33 #include "npapi.h"
35 #include <windows.h>
36 #include <winuser.h>
37 #include <algorithm>
39 #ifndef WINABLEAPI
40 #include <winable.h>
41 #endif
43 namespace mozilla {
44 namespace widget {
46 // Unique id counter associated with a keydown / keypress events. Used in
47 // identifing keypress events for removal from async event dispatch queue
48 // in metrofx after preventDefault is called on keydown events.
49 static uint32_t sUniqueKeyEventId = 0;
51 struct DeadKeyEntry
52 {
53 char16_t BaseChar;
54 char16_t CompositeChar;
55 };
58 class DeadKeyTable
59 {
60 friend class KeyboardLayout;
62 uint16_t mEntries;
63 // KeyboardLayout::AddDeadKeyTable() will allocate as many entries as
64 // required. It is the only way to create new DeadKeyTable instances.
65 DeadKeyEntry mTable[1];
67 void Init(const DeadKeyEntry* aDeadKeyArray, uint32_t aEntries)
68 {
69 mEntries = aEntries;
70 memcpy(mTable, aDeadKeyArray, aEntries * sizeof(DeadKeyEntry));
71 }
73 static uint32_t SizeInBytes(uint32_t aEntries)
74 {
75 return offsetof(DeadKeyTable, mTable) + aEntries * sizeof(DeadKeyEntry);
76 }
78 public:
79 uint32_t Entries() const
80 {
81 return mEntries;
82 }
84 bool IsEqual(const DeadKeyEntry* aDeadKeyArray, uint32_t aEntries) const
85 {
86 return (mEntries == aEntries &&
87 !memcmp(mTable, aDeadKeyArray,
88 aEntries * sizeof(DeadKeyEntry)));
89 }
91 char16_t GetCompositeChar(char16_t aBaseChar) const;
92 };
95 /*****************************************************************************
96 * mozilla::widget::ModifierKeyState
97 *****************************************************************************/
99 ModifierKeyState::ModifierKeyState()
100 {
101 Update();
102 }
104 ModifierKeyState::ModifierKeyState(bool aIsShiftDown,
105 bool aIsControlDown,
106 bool aIsAltDown)
107 {
108 Update();
109 Unset(MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT | MODIFIER_ALTGRAPH);
110 Modifiers modifiers = 0;
111 if (aIsShiftDown) {
112 modifiers |= MODIFIER_SHIFT;
113 }
114 if (aIsControlDown) {
115 modifiers |= MODIFIER_CONTROL;
116 }
117 if (aIsAltDown) {
118 modifiers |= MODIFIER_ALT;
119 }
120 if (modifiers) {
121 Set(modifiers);
122 }
123 }
125 ModifierKeyState::ModifierKeyState(Modifiers aModifiers) :
126 mModifiers(aModifiers)
127 {
128 EnsureAltGr();
129 }
131 void
132 ModifierKeyState::Update()
133 {
134 mModifiers = 0;
135 if (IS_VK_DOWN(VK_SHIFT)) {
136 mModifiers |= MODIFIER_SHIFT;
137 }
138 if (IS_VK_DOWN(VK_CONTROL)) {
139 mModifiers |= MODIFIER_CONTROL;
140 }
141 if (IS_VK_DOWN(VK_MENU)) {
142 mModifiers |= MODIFIER_ALT;
143 }
144 if (IS_VK_DOWN(VK_LWIN) || IS_VK_DOWN(VK_RWIN)) {
145 mModifiers |= MODIFIER_OS;
146 }
147 if (::GetKeyState(VK_CAPITAL) & 1) {
148 mModifiers |= MODIFIER_CAPSLOCK;
149 }
150 if (::GetKeyState(VK_NUMLOCK) & 1) {
151 mModifiers |= MODIFIER_NUMLOCK;
152 }
153 if (::GetKeyState(VK_SCROLL) & 1) {
154 mModifiers |= MODIFIER_SCROLLLOCK;
155 }
157 EnsureAltGr();
158 }
160 void
161 ModifierKeyState::Unset(Modifiers aRemovingModifiers)
162 {
163 mModifiers &= ~aRemovingModifiers;
164 // Note that we don't need to unset AltGr flag here automatically.
165 // For nsEditor, we need to remove Alt and Control flags but AltGr isn't
166 // checked in nsEditor, so, it can be kept.
167 }
169 void
170 ModifierKeyState::Set(Modifiers aAddingModifiers)
171 {
172 mModifiers |= aAddingModifiers;
173 EnsureAltGr();
174 }
176 void
177 ModifierKeyState::InitInputEvent(WidgetInputEvent& aInputEvent) const
178 {
179 aInputEvent.modifiers = mModifiers;
181 switch(aInputEvent.eventStructType) {
182 case NS_MOUSE_EVENT:
183 case NS_MOUSE_SCROLL_EVENT:
184 case NS_WHEEL_EVENT:
185 case NS_DRAG_EVENT:
186 case NS_SIMPLE_GESTURE_EVENT:
187 InitMouseEvent(aInputEvent);
188 break;
189 default:
190 break;
191 }
192 }
194 void
195 ModifierKeyState::InitMouseEvent(WidgetInputEvent& aMouseEvent) const
196 {
197 NS_ASSERTION(aMouseEvent.eventStructType == NS_MOUSE_EVENT ||
198 aMouseEvent.eventStructType == NS_WHEEL_EVENT ||
199 aMouseEvent.eventStructType == NS_DRAG_EVENT ||
200 aMouseEvent.eventStructType == NS_SIMPLE_GESTURE_EVENT,
201 "called with non-mouse event");
203 if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) {
204 // Buttons for immersive mode are handled in MetroInput.
205 return;
206 }
208 WidgetMouseEventBase& mouseEvent = *aMouseEvent.AsMouseEventBase();
209 mouseEvent.buttons = 0;
210 if (::GetKeyState(VK_LBUTTON) < 0) {
211 mouseEvent.buttons |= WidgetMouseEvent::eLeftButtonFlag;
212 }
213 if (::GetKeyState(VK_RBUTTON) < 0) {
214 mouseEvent.buttons |= WidgetMouseEvent::eRightButtonFlag;
215 }
216 if (::GetKeyState(VK_MBUTTON) < 0) {
217 mouseEvent.buttons |= WidgetMouseEvent::eMiddleButtonFlag;
218 }
219 if (::GetKeyState(VK_XBUTTON1) < 0) {
220 mouseEvent.buttons |= WidgetMouseEvent::e4thButtonFlag;
221 }
222 if (::GetKeyState(VK_XBUTTON2) < 0) {
223 mouseEvent.buttons |= WidgetMouseEvent::e5thButtonFlag;
224 }
225 }
227 bool
228 ModifierKeyState::IsShift() const
229 {
230 return (mModifiers & MODIFIER_SHIFT) != 0;
231 }
233 bool
234 ModifierKeyState::IsControl() const
235 {
236 return (mModifiers & MODIFIER_CONTROL) != 0;
237 }
239 bool
240 ModifierKeyState::IsAlt() const
241 {
242 return (mModifiers & MODIFIER_ALT) != 0;
243 }
245 bool
246 ModifierKeyState::IsAltGr() const
247 {
248 return IsControl() && IsAlt();
249 }
251 bool
252 ModifierKeyState::IsWin() const
253 {
254 return (mModifiers & MODIFIER_OS) != 0;
255 }
257 bool
258 ModifierKeyState::IsCapsLocked() const
259 {
260 return (mModifiers & MODIFIER_CAPSLOCK) != 0;
261 }
263 bool
264 ModifierKeyState::IsNumLocked() const
265 {
266 return (mModifiers & MODIFIER_NUMLOCK) != 0;
267 }
269 bool
270 ModifierKeyState::IsScrollLocked() const
271 {
272 return (mModifiers & MODIFIER_SCROLLLOCK) != 0;
273 }
275 Modifiers
276 ModifierKeyState::GetModifiers() const
277 {
278 return mModifiers;
279 }
281 void
282 ModifierKeyState::EnsureAltGr()
283 {
284 // If both Control key and Alt key are pressed, it means AltGr is pressed.
285 // Ideally, we should check whether the current keyboard layout has AltGr
286 // or not. However, setting AltGr flags for keyboard which doesn't have
287 // AltGr must not be serious bug. So, it should be OK for now.
288 if (IsAltGr()) {
289 mModifiers |= MODIFIER_ALTGRAPH;
290 }
291 }
293 /*****************************************************************************
294 * mozilla::widget::UniCharsAndModifiers
295 *****************************************************************************/
297 void
298 UniCharsAndModifiers::Append(char16_t aUniChar, Modifiers aModifiers)
299 {
300 MOZ_ASSERT(mLength < 5);
301 mChars[mLength] = aUniChar;
302 mModifiers[mLength] = aModifiers;
303 mLength++;
304 }
306 void
307 UniCharsAndModifiers::FillModifiers(Modifiers aModifiers)
308 {
309 for (uint32_t i = 0; i < mLength; i++) {
310 mModifiers[i] = aModifiers;
311 }
312 }
314 bool
315 UniCharsAndModifiers::UniCharsEqual(const UniCharsAndModifiers& aOther) const
316 {
317 if (mLength != aOther.mLength) {
318 return false;
319 }
320 return !memcmp(mChars, aOther.mChars, mLength * sizeof(char16_t));
321 }
323 bool
324 UniCharsAndModifiers::UniCharsCaseInsensitiveEqual(
325 const UniCharsAndModifiers& aOther) const
326 {
327 if (mLength != aOther.mLength) {
328 return false;
329 }
331 nsCaseInsensitiveStringComparator comp;
332 return !comp(mChars, aOther.mChars, mLength, aOther.mLength);
333 }
335 UniCharsAndModifiers&
336 UniCharsAndModifiers::operator+=(const UniCharsAndModifiers& aOther)
337 {
338 uint32_t copyCount = std::min(aOther.mLength, 5 - mLength);
339 NS_ENSURE_TRUE(copyCount > 0, *this);
340 memcpy(&mChars[mLength], aOther.mChars, copyCount * sizeof(char16_t));
341 memcpy(&mModifiers[mLength], aOther.mModifiers,
342 copyCount * sizeof(Modifiers));
343 mLength += copyCount;
344 return *this;
345 }
347 UniCharsAndModifiers
348 UniCharsAndModifiers::operator+(const UniCharsAndModifiers& aOther) const
349 {
350 UniCharsAndModifiers result(*this);
351 result += aOther;
352 return result;
353 }
355 /*****************************************************************************
356 * mozilla::widget::VirtualKey
357 *****************************************************************************/
359 // static
360 VirtualKey::ShiftState
361 VirtualKey::ModifiersToShiftState(Modifiers aModifiers)
362 {
363 ShiftState state = 0;
364 if (aModifiers & MODIFIER_SHIFT) {
365 state |= STATE_SHIFT;
366 }
367 if (aModifiers & MODIFIER_CONTROL) {
368 state |= STATE_CONTROL;
369 }
370 if (aModifiers & MODIFIER_ALT) {
371 state |= STATE_ALT;
372 }
373 if (aModifiers & MODIFIER_CAPSLOCK) {
374 state |= STATE_CAPSLOCK;
375 }
376 return state;
377 }
379 // static
380 Modifiers
381 VirtualKey::ShiftStateToModifiers(ShiftState aShiftState)
382 {
383 Modifiers modifiers = 0;
384 if (aShiftState & STATE_SHIFT) {
385 modifiers |= MODIFIER_SHIFT;
386 }
387 if (aShiftState & STATE_CONTROL) {
388 modifiers |= MODIFIER_CONTROL;
389 }
390 if (aShiftState & STATE_ALT) {
391 modifiers |= MODIFIER_ALT;
392 }
393 if (aShiftState & STATE_CAPSLOCK) {
394 modifiers |= MODIFIER_CAPSLOCK;
395 }
396 if ((modifiers & (MODIFIER_ALT | MODIFIER_CONTROL)) ==
397 (MODIFIER_ALT | MODIFIER_CONTROL)) {
398 modifiers |= MODIFIER_ALTGRAPH;
399 }
400 return modifiers;
401 }
403 inline char16_t
404 VirtualKey::GetCompositeChar(ShiftState aShiftState, char16_t aBaseChar) const
405 {
406 return mShiftStates[aShiftState].DeadKey.Table->GetCompositeChar(aBaseChar);
407 }
409 const DeadKeyTable*
410 VirtualKey::MatchingDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
411 uint32_t aEntries) const
412 {
413 if (!mIsDeadKey) {
414 return nullptr;
415 }
417 for (ShiftState shiftState = 0; shiftState < 16; shiftState++) {
418 if (!IsDeadKey(shiftState)) {
419 continue;
420 }
421 const DeadKeyTable* dkt = mShiftStates[shiftState].DeadKey.Table;
422 if (dkt && dkt->IsEqual(aDeadKeyArray, aEntries)) {
423 return dkt;
424 }
425 }
427 return nullptr;
428 }
430 void
431 VirtualKey::SetNormalChars(ShiftState aShiftState,
432 const char16_t* aChars,
433 uint32_t aNumOfChars)
434 {
435 NS_ASSERTION(aShiftState < ArrayLength(mShiftStates), "invalid index");
437 SetDeadKey(aShiftState, false);
439 for (uint32_t index = 0; index < aNumOfChars; index++) {
440 // Ignore legacy non-printable control characters
441 mShiftStates[aShiftState].Normal.Chars[index] =
442 (aChars[index] >= 0x20) ? aChars[index] : 0;
443 }
445 uint32_t len = ArrayLength(mShiftStates[aShiftState].Normal.Chars);
446 for (uint32_t index = aNumOfChars; index < len; index++) {
447 mShiftStates[aShiftState].Normal.Chars[index] = 0;
448 }
449 }
451 void
452 VirtualKey::SetDeadChar(ShiftState aShiftState, char16_t aDeadChar)
453 {
454 NS_ASSERTION(aShiftState < ArrayLength(mShiftStates), "invalid index");
456 SetDeadKey(aShiftState, true);
458 mShiftStates[aShiftState].DeadKey.DeadChar = aDeadChar;
459 mShiftStates[aShiftState].DeadKey.Table = nullptr;
460 }
462 UniCharsAndModifiers
463 VirtualKey::GetUniChars(ShiftState aShiftState) const
464 {
465 UniCharsAndModifiers result = GetNativeUniChars(aShiftState);
467 const ShiftState STATE_ALT_CONTROL = (STATE_ALT | STATE_CONTROL);
468 if (!(aShiftState & STATE_ALT_CONTROL)) {
469 return result;
470 }
472 if (!result.mLength) {
473 result = GetNativeUniChars(aShiftState & ~STATE_ALT_CONTROL);
474 result.FillModifiers(ShiftStateToModifiers(aShiftState));
475 return result;
476 }
478 if ((aShiftState & STATE_ALT_CONTROL) == STATE_ALT_CONTROL) {
479 // Even if the shifted chars and the unshifted chars are same, we
480 // should consume the Alt key state and the Ctrl key state when
481 // AltGr key is pressed. Because if we don't consume them, the input
482 // events are ignored on nsEditor. (I.e., Users cannot input the
483 // characters with this key combination.)
484 Modifiers finalModifiers = ShiftStateToModifiers(aShiftState);
485 finalModifiers &= ~(MODIFIER_ALT | MODIFIER_CONTROL);
486 result.FillModifiers(finalModifiers);
487 return result;
488 }
490 UniCharsAndModifiers unmodifiedReslt =
491 GetNativeUniChars(aShiftState & ~STATE_ALT_CONTROL);
492 if (!result.UniCharsEqual(unmodifiedReslt)) {
493 // Otherwise, we should consume the Alt key state and the Ctrl key state
494 // only when the shifted chars and unshifted chars are different.
495 Modifiers finalModifiers = ShiftStateToModifiers(aShiftState);
496 finalModifiers &= ~(MODIFIER_ALT | MODIFIER_CONTROL);
497 result.FillModifiers(finalModifiers);
498 }
499 return result;
500 }
503 UniCharsAndModifiers
504 VirtualKey::GetNativeUniChars(ShiftState aShiftState) const
505 {
506 #ifdef DEBUG
507 if (aShiftState < 0 || aShiftState >= ArrayLength(mShiftStates)) {
508 nsPrintfCString warning("Shift state is out of range: "
509 "aShiftState=%d, ArrayLength(mShiftState)=%d",
510 aShiftState, ArrayLength(mShiftStates));
511 NS_WARNING(warning.get());
512 }
513 #endif
515 UniCharsAndModifiers result;
516 Modifiers modifiers = ShiftStateToModifiers(aShiftState);
517 if (IsDeadKey(aShiftState)) {
518 result.Append(mShiftStates[aShiftState].DeadKey.DeadChar, modifiers);
519 return result;
520 }
522 uint32_t index;
523 uint32_t len = ArrayLength(mShiftStates[aShiftState].Normal.Chars);
524 for (index = 0;
525 index < len && mShiftStates[aShiftState].Normal.Chars[index]; index++) {
526 result.Append(mShiftStates[aShiftState].Normal.Chars[index], modifiers);
527 }
528 return result;
529 }
531 // static
532 void
533 VirtualKey::FillKbdState(PBYTE aKbdState,
534 const ShiftState aShiftState)
535 {
536 NS_ASSERTION(aShiftState < 16, "aShiftState out of range");
538 if (aShiftState & STATE_SHIFT) {
539 aKbdState[VK_SHIFT] |= 0x80;
540 } else {
541 aKbdState[VK_SHIFT] &= ~0x80;
542 aKbdState[VK_LSHIFT] &= ~0x80;
543 aKbdState[VK_RSHIFT] &= ~0x80;
544 }
546 if (aShiftState & STATE_CONTROL) {
547 aKbdState[VK_CONTROL] |= 0x80;
548 } else {
549 aKbdState[VK_CONTROL] &= ~0x80;
550 aKbdState[VK_LCONTROL] &= ~0x80;
551 aKbdState[VK_RCONTROL] &= ~0x80;
552 }
554 if (aShiftState & STATE_ALT) {
555 aKbdState[VK_MENU] |= 0x80;
556 } else {
557 aKbdState[VK_MENU] &= ~0x80;
558 aKbdState[VK_LMENU] &= ~0x80;
559 aKbdState[VK_RMENU] &= ~0x80;
560 }
562 if (aShiftState & STATE_CAPSLOCK) {
563 aKbdState[VK_CAPITAL] |= 0x01;
564 } else {
565 aKbdState[VK_CAPITAL] &= ~0x01;
566 }
567 }
569 /*****************************************************************************
570 * mozilla::widget::NativeKey
571 *****************************************************************************/
573 NativeKey::NativeKey(nsWindowBase* aWidget,
574 const MSG& aKeyOrCharMessage,
575 const ModifierKeyState& aModKeyState,
576 nsTArray<FakeCharMsg>* aFakeCharMsgs) :
577 mWidget(aWidget), mMsg(aKeyOrCharMessage), mDOMKeyCode(0),
578 mModKeyState(aModKeyState), mVirtualKeyCode(0), mOriginalVirtualKeyCode(0),
579 mFakeCharMsgs(aFakeCharMsgs && aFakeCharMsgs->Length() ?
580 aFakeCharMsgs : nullptr)
581 {
582 MOZ_ASSERT(aWidget);
583 KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
584 mKeyboardLayout = keyboardLayout->GetLayout();
585 mScanCode = WinUtils::GetScanCode(mMsg.lParam);
586 mIsExtended = WinUtils::IsExtendedScanCode(mMsg.lParam);
587 // On WinXP and WinServer2003, we cannot compute the virtual keycode for
588 // extended keys due to the API limitation.
589 bool canComputeVirtualKeyCodeFromScanCode =
590 (!mIsExtended || IsVistaOrLater());
591 switch (mMsg.message) {
592 case WM_KEYDOWN:
593 case WM_SYSKEYDOWN:
594 case WM_KEYUP:
595 case WM_SYSKEYUP: {
596 // First, resolve the IME converted virtual keycode to its original
597 // keycode.
598 if (mMsg.wParam == VK_PROCESSKEY) {
599 mOriginalVirtualKeyCode =
600 static_cast<uint8_t>(::ImmGetVirtualKey(mMsg.hwnd));
601 } else {
602 mOriginalVirtualKeyCode = static_cast<uint8_t>(mMsg.wParam);
603 }
605 // Most keys are not distinguished as left or right keys.
606 bool isLeftRightDistinguishedKey = false;
608 // mOriginalVirtualKeyCode must not distinguish left or right of
609 // Shift, Control or Alt.
610 switch (mOriginalVirtualKeyCode) {
611 case VK_SHIFT:
612 case VK_CONTROL:
613 case VK_MENU:
614 isLeftRightDistinguishedKey = true;
615 break;
616 case VK_LSHIFT:
617 case VK_RSHIFT:
618 mVirtualKeyCode = mOriginalVirtualKeyCode;
619 mOriginalVirtualKeyCode = VK_SHIFT;
620 isLeftRightDistinguishedKey = true;
621 break;
622 case VK_LCONTROL:
623 case VK_RCONTROL:
624 mVirtualKeyCode = mOriginalVirtualKeyCode;
625 mOriginalVirtualKeyCode = VK_CONTROL;
626 isLeftRightDistinguishedKey = true;
627 break;
628 case VK_LMENU:
629 case VK_RMENU:
630 mVirtualKeyCode = mOriginalVirtualKeyCode;
631 mOriginalVirtualKeyCode = VK_MENU;
632 isLeftRightDistinguishedKey = true;
633 break;
634 }
636 // If virtual keycode (left-right distinguished keycode) is already
637 // computed, we don't need to do anymore.
638 if (mVirtualKeyCode) {
639 break;
640 }
642 // If the keycode doesn't have LR distinguished keycode, we just set
643 // mOriginalVirtualKeyCode to mVirtualKeyCode. Note that don't compute
644 // it from MapVirtualKeyEx() because the scan code might be wrong if
645 // the message is sent/posted by other application. Then, we will compute
646 // unexpected keycode from the scan code.
647 if (!isLeftRightDistinguishedKey) {
648 break;
649 }
651 if (!canComputeVirtualKeyCodeFromScanCode) {
652 // The right control key and the right alt key are extended keys.
653 // Therefore, we never get VK_RCONTRL and VK_RMENU for the result of
654 // MapVirtualKeyEx() on WinXP or WinServer2003.
655 //
656 // If VK_CONTROL or VK_MENU key message is caused by an extended key,
657 // we should assume that the right key of them is pressed.
658 switch (mOriginalVirtualKeyCode) {
659 case VK_CONTROL:
660 mVirtualKeyCode = VK_RCONTROL;
661 break;
662 case VK_MENU:
663 mVirtualKeyCode = VK_RMENU;
664 break;
665 case VK_SHIFT:
666 // Neither left shift nor right shift is not an extended key,
667 // let's use VK_LSHIFT for invalid scan code.
668 mVirtualKeyCode = VK_LSHIFT;
669 break;
670 default:
671 MOZ_CRASH("Unsupported mOriginalVirtualKeyCode");
672 }
673 break;
674 }
676 NS_ASSERTION(!mVirtualKeyCode,
677 "mVirtualKeyCode has been computed already");
679 // Otherwise, compute the virtual keycode with MapVirtualKeyEx().
680 mVirtualKeyCode = ComputeVirtualKeyCodeFromScanCodeEx();
682 // The result might be unexpected value due to the scan code is
683 // wrong. For example, any key messages can be generated by
684 // SendMessage() or PostMessage() from applications. So, it's possible
685 // failure. Then, let's respect the extended flag even if it might be
686 // set intentionally.
687 switch (mOriginalVirtualKeyCode) {
688 case VK_CONTROL:
689 if (mVirtualKeyCode != VK_LCONTROL &&
690 mVirtualKeyCode != VK_RCONTROL) {
691 mVirtualKeyCode = mIsExtended ? VK_RCONTROL : VK_LCONTROL;
692 }
693 break;
694 case VK_MENU:
695 if (mVirtualKeyCode != VK_LMENU && mVirtualKeyCode != VK_RMENU) {
696 mVirtualKeyCode = mIsExtended ? VK_RMENU : VK_LMENU;
697 }
698 break;
699 case VK_SHIFT:
700 if (mVirtualKeyCode != VK_LSHIFT && mVirtualKeyCode != VK_RSHIFT) {
701 // Neither left shift nor right shift is not an extended key,
702 // let's use VK_LSHIFT for invalid scan code.
703 mVirtualKeyCode = VK_LSHIFT;
704 }
705 break;
706 default:
707 MOZ_CRASH("Unsupported mOriginalVirtualKeyCode");
708 }
709 break;
710 }
711 case WM_CHAR:
712 case WM_UNICHAR:
713 case WM_SYSCHAR:
714 // We cannot compute the virtual key code from WM_CHAR message on WinXP
715 // if it's caused by an extended key.
716 if (!canComputeVirtualKeyCodeFromScanCode) {
717 break;
718 }
719 mVirtualKeyCode = mOriginalVirtualKeyCode =
720 ComputeVirtualKeyCodeFromScanCodeEx();
721 NS_ASSERTION(mVirtualKeyCode, "Failed to compute virtual keycode");
722 break;
723 default:
724 MOZ_CRASH("Unsupported message");
725 }
727 if (!mVirtualKeyCode) {
728 mVirtualKeyCode = mOriginalVirtualKeyCode;
729 }
731 mDOMKeyCode =
732 keyboardLayout->ConvertNativeKeyCodeToDOMKeyCode(mOriginalVirtualKeyCode);
733 mKeyNameIndex =
734 keyboardLayout->ConvertNativeKeyCodeToKeyNameIndex(mOriginalVirtualKeyCode);
736 keyboardLayout->InitNativeKey(*this, mModKeyState);
738 mIsDeadKey =
739 (IsFollowedByDeadCharMessage() ||
740 keyboardLayout->IsDeadKey(mOriginalVirtualKeyCode, mModKeyState));
741 mIsPrintableKey = KeyboardLayout::IsPrintableCharKey(mOriginalVirtualKeyCode);
742 }
744 bool
745 NativeKey::IsFollowedByDeadCharMessage() const
746 {
747 MSG nextMsg;
748 if (mFakeCharMsgs) {
749 nextMsg = mFakeCharMsgs->ElementAt(0).GetCharMsg(mMsg.hwnd);
750 } else {
751 if (!WinUtils::PeekMessage(&nextMsg, mMsg.hwnd, WM_KEYFIRST, WM_KEYLAST,
752 PM_NOREMOVE | PM_NOYIELD)) {
753 return false;
754 }
755 }
756 return IsDeadCharMessage(nextMsg);
757 }
759 bool
760 NativeKey::IsIMEDoingKakuteiUndo() const
761 {
762 // Following message pattern is caused by "Kakutei-Undo" of ATOK or WXG:
763 // ---------------------------------------------------------------------------
764 // WM_KEYDOWN * n (wParam = VK_BACK, lParam = 0x1)
765 // WM_KEYUP * 1 (wParam = VK_BACK, lParam = 0xC0000001) # ATOK
766 // WM_IME_STARTCOMPOSITION * 1 (wParam = 0x0, lParam = 0x0)
767 // WM_IME_COMPOSITION * 1 (wParam = 0x0, lParam = 0x1BF)
768 // WM_CHAR * n (wParam = VK_BACK, lParam = 0x1)
769 // WM_KEYUP * 1 (wParam = VK_BACK, lParam = 0xC00E0001)
770 // ---------------------------------------------------------------------------
771 // This doesn't match usual key message pattern such as:
772 // WM_KEYDOWN -> WM_CHAR -> WM_KEYDOWN -> WM_CHAR -> ... -> WM_KEYUP
773 // See following bugs for the detail.
774 // https://bugzilla.mozilla.gr.jp/show_bug.cgi?id=2885 (written in Japanese)
775 // https://bugzilla.mozilla.org/show_bug.cgi?id=194559 (written in English)
776 MSG startCompositionMsg, compositionMsg, charMsg;
777 return WinUtils::PeekMessage(&startCompositionMsg, mMsg.hwnd,
778 WM_IME_STARTCOMPOSITION, WM_IME_STARTCOMPOSITION,
779 PM_NOREMOVE | PM_NOYIELD) &&
780 WinUtils::PeekMessage(&compositionMsg, mMsg.hwnd, WM_IME_COMPOSITION,
781 WM_IME_COMPOSITION, PM_NOREMOVE | PM_NOYIELD) &&
782 WinUtils::PeekMessage(&charMsg, mMsg.hwnd, WM_CHAR, WM_CHAR,
783 PM_NOREMOVE | PM_NOYIELD) &&
784 startCompositionMsg.wParam == 0x0 &&
785 startCompositionMsg.lParam == 0x0 &&
786 compositionMsg.wParam == 0x0 &&
787 compositionMsg.lParam == 0x1BF &&
788 charMsg.wParam == VK_BACK && charMsg.lParam == 0x1 &&
789 startCompositionMsg.time <= compositionMsg.time &&
790 compositionMsg.time <= charMsg.time;
791 }
793 UINT
794 NativeKey::GetScanCodeWithExtendedFlag() const
795 {
796 // MapVirtualKeyEx() has been improved for supporting extended keys since
797 // Vista. When we call it for mapping a scancode of an extended key and
798 // a virtual keycode, we need to add 0xE000 to the scancode.
799 // On Win XP and Win Server 2003, this doesn't support. On them, we have
800 // no way to get virtual keycodes from scancode of extended keys.
801 if (!mIsExtended || !IsVistaOrLater()) {
802 return mScanCode;
803 }
804 return (0xE000 | mScanCode);
805 }
807 uint32_t
808 NativeKey::GetKeyLocation() const
809 {
810 switch (mVirtualKeyCode) {
811 case VK_LSHIFT:
812 case VK_LCONTROL:
813 case VK_LMENU:
814 case VK_LWIN:
815 return nsIDOMKeyEvent::DOM_KEY_LOCATION_LEFT;
817 case VK_RSHIFT:
818 case VK_RCONTROL:
819 case VK_RMENU:
820 case VK_RWIN:
821 return nsIDOMKeyEvent::DOM_KEY_LOCATION_RIGHT;
823 case VK_RETURN:
824 // XXX This code assumes that all keyboard drivers use same mapping.
825 return !mIsExtended ? nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD :
826 nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD;
828 case VK_INSERT:
829 case VK_DELETE:
830 case VK_END:
831 case VK_DOWN:
832 case VK_NEXT:
833 case VK_LEFT:
834 case VK_CLEAR:
835 case VK_RIGHT:
836 case VK_HOME:
837 case VK_UP:
838 case VK_PRIOR:
839 // XXX This code assumes that all keyboard drivers use same mapping.
840 return mIsExtended ? nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD :
841 nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD;
843 // NumLock key isn't included due to IE9's behavior.
844 case VK_NUMPAD0:
845 case VK_NUMPAD1:
846 case VK_NUMPAD2:
847 case VK_NUMPAD3:
848 case VK_NUMPAD4:
849 case VK_NUMPAD5:
850 case VK_NUMPAD6:
851 case VK_NUMPAD7:
852 case VK_NUMPAD8:
853 case VK_NUMPAD9:
854 case VK_DECIMAL:
855 case VK_DIVIDE:
856 case VK_MULTIPLY:
857 case VK_SUBTRACT:
858 case VK_ADD:
859 // Separator key of Brazilian keyboard or JIS keyboard for Mac
860 case VK_ABNT_C2:
861 return nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD;
863 case VK_SHIFT:
864 case VK_CONTROL:
865 case VK_MENU:
866 NS_WARNING("Failed to decide the key location?");
868 default:
869 return nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD;
870 }
871 }
873 uint8_t
874 NativeKey::ComputeVirtualKeyCodeFromScanCode() const
875 {
876 return static_cast<uint8_t>(
877 ::MapVirtualKeyEx(mScanCode, MAPVK_VSC_TO_VK, mKeyboardLayout));
878 }
880 uint8_t
881 NativeKey::ComputeVirtualKeyCodeFromScanCodeEx() const
882 {
883 // NOTE: WinXP doesn't support mapping scan code to virtual keycode of
884 // extended keys.
885 NS_ENSURE_TRUE(!mIsExtended || IsVistaOrLater(), 0);
886 return static_cast<uint8_t>(
887 ::MapVirtualKeyEx(GetScanCodeWithExtendedFlag(), MAPVK_VSC_TO_VK_EX,
888 mKeyboardLayout));
889 }
891 char16_t
892 NativeKey::ComputeUnicharFromScanCode() const
893 {
894 return static_cast<char16_t>(
895 ::MapVirtualKeyEx(ComputeVirtualKeyCodeFromScanCode(),
896 MAPVK_VK_TO_CHAR, mKeyboardLayout));
897 }
899 void
900 NativeKey::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent) const
901 {
902 InitKeyEvent(aKeyEvent, mModKeyState);
903 }
905 void
906 NativeKey::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
907 const ModifierKeyState& aModKeyState) const
908 {
909 nsIntPoint point(0, 0);
910 mWidget->InitEvent(aKeyEvent, &point);
912 switch (aKeyEvent.message) {
913 case NS_KEY_DOWN:
914 aKeyEvent.keyCode = mDOMKeyCode;
915 // Unique id for this keydown event and its associated keypress.
916 sUniqueKeyEventId++;
917 aKeyEvent.mUniqueId = sUniqueKeyEventId;
918 break;
919 case NS_KEY_UP:
920 aKeyEvent.keyCode = mDOMKeyCode;
921 // Set defaultPrevented of the key event if the VK_MENU is not a system
922 // key release, so that the menu bar does not trigger. This helps avoid
923 // triggering the menu bar for ALT key accelerators used in assistive
924 // technologies such as Window-Eyes and ZoomText or for switching open
925 // state of IME.
926 aKeyEvent.mFlags.mDefaultPrevented =
927 (mOriginalVirtualKeyCode == VK_MENU && mMsg.message != WM_SYSKEYUP);
928 break;
929 case NS_KEY_PRESS:
930 aKeyEvent.mUniqueId = sUniqueKeyEventId;
931 break;
932 default:
933 MOZ_CRASH("Invalid event message");
934 }
936 aKeyEvent.mIsRepeat = IsRepeat();
937 aKeyEvent.mKeyNameIndex = mKeyNameIndex;
938 if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) {
939 aKeyEvent.mKeyValue = mCommittedCharsAndModifiers.ToString();
940 }
941 aKeyEvent.location = GetKeyLocation();
942 aModKeyState.InitInputEvent(aKeyEvent);
943 }
945 bool
946 NativeKey::DispatchKeyEvent(WidgetKeyboardEvent& aKeyEvent,
947 const MSG* aMsgSentToPlugin) const
948 {
949 if (mWidget->Destroyed()) {
950 MOZ_CRASH("NativeKey tries to dispatch a key event on destroyed widget");
951 }
953 KeyboardLayout::NotifyIdleServiceOfUserActivity();
955 NPEvent pluginEvent;
956 if (aMsgSentToPlugin &&
957 mWidget->GetInputContext().mIMEState.mEnabled == IMEState::PLUGIN) {
958 pluginEvent.event = aMsgSentToPlugin->message;
959 pluginEvent.wParam = aMsgSentToPlugin->wParam;
960 pluginEvent.lParam = aMsgSentToPlugin->lParam;
961 aKeyEvent.pluginEvent = static_cast<void*>(&pluginEvent);
962 }
964 return (mWidget->DispatchKeyboardEvent(&aKeyEvent) || mWidget->Destroyed());
965 }
967 bool
968 NativeKey::HandleKeyDownMessage(bool* aEventDispatched) const
969 {
970 MOZ_ASSERT(IsKeyDownMessage());
972 if (aEventDispatched) {
973 *aEventDispatched = false;
974 }
976 bool defaultPrevented = false;
977 if (mFakeCharMsgs ||
978 !RedirectedKeyDownMessageManager::IsRedirectedMessage(mMsg)) {
979 // Ignore [shift+]alt+space so the OS can handle it.
980 if (mModKeyState.IsAlt() && !mModKeyState.IsControl() &&
981 mVirtualKeyCode == VK_SPACE) {
982 return false;
983 }
985 bool isIMEEnabled = WinUtils::IsIMEEnabled(mWidget->GetInputContext());
986 WidgetKeyboardEvent keydownEvent(true, NS_KEY_DOWN, mWidget);
987 InitKeyEvent(keydownEvent, mModKeyState);
988 if (aEventDispatched) {
989 *aEventDispatched = true;
990 }
991 defaultPrevented = DispatchKeyEvent(keydownEvent, &mMsg);
993 if (mWidget->Destroyed()) {
994 return true;
995 }
997 // If IMC wasn't associated to the window but is associated it now (i.e.,
998 // focus is moved from a non-editable editor to an editor by keydown
999 // event handler), WM_CHAR and WM_SYSCHAR shouldn't cause first character
1000 // inputting if IME is opened. But then, we should redirect the native
1001 // keydown message to IME.
1002 // However, note that if focus has been already moved to another
1003 // application, we shouldn't redirect the message to it because the keydown
1004 // message is processed by us, so, nobody shouldn't process it.
1005 HWND focusedWnd = ::GetFocus();
1006 if (!defaultPrevented && !mFakeCharMsgs && focusedWnd &&
1007 !mWidget->PluginHasFocus() && !isIMEEnabled &&
1008 WinUtils::IsIMEEnabled(mWidget->GetInputContext())) {
1009 RedirectedKeyDownMessageManager::RemoveNextCharMessage(focusedWnd);
1011 INPUT keyinput;
1012 keyinput.type = INPUT_KEYBOARD;
1013 keyinput.ki.wVk = mOriginalVirtualKeyCode;
1014 keyinput.ki.wScan = mScanCode;
1015 keyinput.ki.dwFlags = KEYEVENTF_SCANCODE;
1016 if (mIsExtended) {
1017 keyinput.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
1018 }
1019 keyinput.ki.time = 0;
1020 keyinput.ki.dwExtraInfo = 0;
1022 RedirectedKeyDownMessageManager::WillRedirect(mMsg, defaultPrevented);
1024 ::SendInput(1, &keyinput, sizeof(keyinput));
1026 // Return here. We shouldn't dispatch keypress event for this WM_KEYDOWN.
1027 // If it's needed, it will be dispatched after next (redirected)
1028 // WM_KEYDOWN.
1029 return true;
1030 }
1031 } else {
1032 defaultPrevented = RedirectedKeyDownMessageManager::DefaultPrevented();
1033 // If this is redirected keydown message, we have dispatched the keydown
1034 // event already.
1035 if (aEventDispatched) {
1036 *aEventDispatched = true;
1037 }
1038 }
1040 RedirectedKeyDownMessageManager::Forget();
1042 // If the key was processed by IME, we shouldn't dispatch keypress event.
1043 if (mOriginalVirtualKeyCode == VK_PROCESSKEY) {
1044 return defaultPrevented;
1045 }
1047 // Don't dispatch keypress event for modifier keys.
1048 switch (mDOMKeyCode) {
1049 case NS_VK_SHIFT:
1050 case NS_VK_CONTROL:
1051 case NS_VK_ALT:
1052 case NS_VK_CAPS_LOCK:
1053 case NS_VK_NUM_LOCK:
1054 case NS_VK_SCROLL_LOCK:
1055 case NS_VK_WIN:
1056 return defaultPrevented;
1057 }
1059 if (defaultPrevented) {
1060 DispatchPluginEventsAndDiscardsCharMessages();
1061 return true;
1062 }
1064 // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a
1065 // keypress for almost all keys
1066 if (NeedsToHandleWithoutFollowingCharMessages()) {
1067 return (DispatchPluginEventsAndDiscardsCharMessages() ||
1068 DispatchKeyPressEventsWithKeyboardLayout());
1069 }
1071 MSG followingCharMsg;
1072 if (GetFollowingCharMessage(followingCharMsg)) {
1073 // Even if there was char message, it might be redirected by different
1074 // window (perhaps, focus move?). Then, we shouldn't continue to handle
1075 // the message since no input should occur on the window.
1076 if (followingCharMsg.message == WM_NULL ||
1077 followingCharMsg.hwnd != mMsg.hwnd) {
1078 return false;
1079 }
1080 return DispatchKeyPressEventForFollowingCharMessage(followingCharMsg);
1081 }
1083 if (!mModKeyState.IsControl() && !mModKeyState.IsAlt() &&
1084 !mModKeyState.IsWin() && mIsPrintableKey) {
1085 // If this is simple KeyDown event but next message is not WM_CHAR,
1086 // this event may not input text, so we should ignore this event.
1087 // See bug 314130.
1088 return false;
1089 }
1091 if (mIsDeadKey) {
1092 return false;
1093 }
1095 return DispatchKeyPressEventsWithKeyboardLayout();
1096 }
1098 bool
1099 NativeKey::HandleCharMessage(const MSG& aCharMsg,
1100 bool* aEventDispatched) const
1101 {
1102 MOZ_ASSERT(IsKeyDownMessage() || IsPrintableCharMessage(mMsg));
1103 MOZ_ASSERT(IsPrintableCharMessage(aCharMsg.message));
1105 if (aEventDispatched) {
1106 *aEventDispatched = false;
1107 }
1109 // Alt+Space key is handled by OS, we shouldn't touch it.
1110 if (mModKeyState.IsAlt() && !mModKeyState.IsControl() &&
1111 mVirtualKeyCode == VK_SPACE) {
1112 return false;
1113 }
1115 // Bug 818235: Ignore Ctrl+Enter.
1116 if (!mModKeyState.IsAlt() && mModKeyState.IsControl() &&
1117 mVirtualKeyCode == VK_RETURN) {
1118 return false;
1119 }
1121 // XXXmnakao I think that if aNativeKeyDown is null, such lonely WM_CHAR
1122 // should cause composition events because they are not caused
1123 // by actual keyboard operation.
1125 static const char16_t U_SPACE = 0x20;
1126 static const char16_t U_EQUAL = 0x3D;
1128 // First, handle normal text input or non-printable key case here.
1129 if ((!mModKeyState.IsAlt() && !mModKeyState.IsControl()) ||
1130 mModKeyState.IsAltGr() ||
1131 (mOriginalVirtualKeyCode &&
1132 !KeyboardLayout::IsPrintableCharKey(mOriginalVirtualKeyCode))) {
1133 WidgetKeyboardEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
1134 if (aCharMsg.wParam >= U_SPACE) {
1135 keypressEvent.charCode = static_cast<uint32_t>(aCharMsg.wParam);
1136 } else {
1137 keypressEvent.keyCode = mDOMKeyCode;
1138 }
1139 // When AltGr (Alt+Ctrl) is pressed, that causes normal text input.
1140 // At this time, if either alt or ctrl flag is set, nsEditor ignores the
1141 // keypress event. For avoiding this issue, we should remove ctrl and alt
1142 // flags.
1143 ModifierKeyState modKeyState(mModKeyState);
1144 modKeyState.Unset(MODIFIER_ALT | MODIFIER_CONTROL);
1145 InitKeyEvent(keypressEvent, modKeyState);
1146 if (aEventDispatched) {
1147 *aEventDispatched = true;
1148 }
1149 return DispatchKeyEvent(keypressEvent, &aCharMsg);
1150 }
1152 // XXX It seems that following code was implemented for shortcut key
1153 // handling. However, it's now handled in WM_KEYDOWN message handler.
1154 // So, this actually runs only when WM_CHAR is sent/posted without
1155 // WM_KEYDOWN. I think that we don't need to keypress event in such
1156 // case especially for shortcut keys.
1158 char16_t uniChar;
1159 // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details
1160 if (mModKeyState.IsControl() && aCharMsg.wParam <= 0x1A) {
1161 // Bug 16486: Need to account for shift here.
1162 uniChar = aCharMsg.wParam - 1 + (mModKeyState.IsShift() ? 'A' : 'a');
1163 } else if (mModKeyState.IsControl() && aCharMsg.wParam <= 0x1F) {
1164 // Bug 50255: <ctrl><[> and <ctrl><]> are not being processed.
1165 // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f)
1166 // for some reason the keypress handler need to have the uniChar code set
1167 // with the addition of a upper case A not the lower case.
1168 uniChar = aCharMsg.wParam - 1 + 'A';
1169 } else if (aCharMsg.wParam < U_SPACE ||
1170 (aCharMsg.wParam == U_EQUAL && mModKeyState.IsControl())) {
1171 uniChar = 0;
1172 } else {
1173 uniChar = aCharMsg.wParam;
1174 }
1176 // Bug 50255 and Bug 351310: Keep the characters unshifted for shortcuts and
1177 // accesskeys and make sure that numbers are always passed as such.
1178 if (uniChar && (mModKeyState.IsControl() || mModKeyState.IsAlt())) {
1179 KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
1180 char16_t unshiftedCharCode =
1181 (mVirtualKeyCode >= '0' && mVirtualKeyCode <= '9') ?
1182 mVirtualKeyCode : mModKeyState.IsShift() ?
1183 ComputeUnicharFromScanCode() : 0;
1184 // Ignore diacritics (top bit set) and key mapping errors (char code 0)
1185 if (static_cast<int32_t>(unshiftedCharCode) > 0) {
1186 uniChar = unshiftedCharCode;
1187 }
1188 }
1190 // Bug 285161 and Bug 295095: They were caused by the initial fix for
1191 // bug 178110. When pressing (alt|ctrl)+char, the char must be lowercase
1192 // unless shift is pressed too.
1193 if (!mModKeyState.IsShift() &&
1194 (mModKeyState.IsAlt() || mModKeyState.IsControl())) {
1195 uniChar = towlower(uniChar);
1196 }
1198 WidgetKeyboardEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
1199 keypressEvent.charCode = uniChar;
1200 if (!keypressEvent.charCode) {
1201 keypressEvent.keyCode = mDOMKeyCode;
1202 }
1203 InitKeyEvent(keypressEvent, mModKeyState);
1204 if (aEventDispatched) {
1205 *aEventDispatched = true;
1206 }
1207 return DispatchKeyEvent(keypressEvent, &aCharMsg);
1208 }
1210 bool
1211 NativeKey::HandleKeyUpMessage(bool* aEventDispatched) const
1212 {
1213 MOZ_ASSERT(IsKeyUpMessage());
1215 if (aEventDispatched) {
1216 *aEventDispatched = false;
1217 }
1219 // Ignore [shift+]alt+space so the OS can handle it.
1220 if (mModKeyState.IsAlt() && !mModKeyState.IsControl() &&
1221 mVirtualKeyCode == VK_SPACE) {
1222 return false;
1223 }
1225 WidgetKeyboardEvent keyupEvent(true, NS_KEY_UP, mWidget);
1226 InitKeyEvent(keyupEvent, mModKeyState);
1227 if (aEventDispatched) {
1228 *aEventDispatched = true;
1229 }
1230 return DispatchKeyEvent(keyupEvent, &mMsg);
1231 }
1233 bool
1234 NativeKey::NeedsToHandleWithoutFollowingCharMessages() const
1235 {
1236 MOZ_ASSERT(IsKeyDownMessage());
1238 // Enter and backspace are always handled here to avoid for example the
1239 // confusion between ctrl-enter and ctrl-J.
1240 if (mDOMKeyCode == NS_VK_RETURN || mDOMKeyCode == NS_VK_BACK) {
1241 return true;
1242 }
1244 // If any modifier keys which may cause printable keys becoming non-printable
1245 // are not pressed, we don't need special handling for the key.
1246 if (!mModKeyState.IsControl() && !mModKeyState.IsAlt() &&
1247 !mModKeyState.IsWin()) {
1248 return false;
1249 }
1251 // If the key event causes dead key event, we don't need to dispatch keypress
1252 // event.
1253 if (mIsDeadKey && mCommittedCharsAndModifiers.IsEmpty()) {
1254 return false;
1255 }
1257 // Even if the key is a printable key, it might cause non-printable character
1258 // input with modifier key(s).
1259 return mIsPrintableKey;
1260 }
1262 #ifdef MOZ_CRASHREPORTER
1264 static nsCString
1265 GetResultOfInSendMessageEx()
1266 {
1267 DWORD ret = ::InSendMessageEx(nullptr);
1268 if (!ret) {
1269 return NS_LITERAL_CSTRING("ISMEX_NOSEND");
1270 }
1271 nsAutoCString result;
1272 if (ret & ISMEX_CALLBACK) {
1273 result = "ISMEX_CALLBACK";
1274 }
1275 if (ret & ISMEX_NOTIFY) {
1276 if (!result.IsEmpty()) {
1277 result += " | ";
1278 }
1279 result += "ISMEX_NOTIFY";
1280 }
1281 if (ret & ISMEX_REPLIED) {
1282 if (!result.IsEmpty()) {
1283 result += " | ";
1284 }
1285 result += "ISMEX_REPLIED";
1286 }
1287 if (ret & ISMEX_SEND) {
1288 if (!result.IsEmpty()) {
1289 result += " | ";
1290 }
1291 result += "ISMEX_SEND";
1292 }
1293 return result;
1294 }
1296 static const char*
1297 GetMessageName(UINT aMessage)
1298 {
1299 switch (aMessage) {
1300 case WM_KEYDOWN: return "WM_KEYDOWN";
1301 case WM_SYSKEYDOWN: return "WM_SYSKEYDOWN";
1302 case WM_KEYUP: return "WM_KEYUP";
1303 case WM_SYSKEYUP: return "WM_SYSKEYUP";
1304 case WM_CHAR: return "WM_CHAR";
1305 case WM_DEADCHAR: return "WM_DEADCHAR";
1306 case WM_SYSCHAR: return "WM_SYSCHAR";
1307 case WM_SYSDEADCHAR: return "WM_SYSDEADCHAR";
1308 case WM_UNICHAR: return "WM_UNICHAR";
1309 case WM_QUIT: return "WM_QUIT";
1310 case WM_NULL: return "WM_NULL";
1311 default: return "Unknown";
1312 }
1313 }
1315 #endif // #ifdef MOZ_CRASHREPORTER
1317 bool
1318 NativeKey::MayBeSameCharMessage(const MSG& aCharMsg1,
1319 const MSG& aCharMsg2) const
1320 {
1321 // NOTE: Although, we don't know when this case occurs, the scan code value
1322 // in lParam may be changed from 0 to something. The changed value
1323 // is different from the scan code of handling keydown message.
1324 static const LPARAM kScanCodeMask = 0x00FF0000;
1325 return
1326 aCharMsg1.message == aCharMsg2.message &&
1327 aCharMsg1.wParam == aCharMsg2.wParam &&
1328 (aCharMsg1.lParam & ~kScanCodeMask) == (aCharMsg2.lParam & ~kScanCodeMask);
1329 }
1331 bool
1332 NativeKey::GetFollowingCharMessage(MSG& aCharMsg) const
1333 {
1334 MOZ_ASSERT(IsKeyDownMessage());
1336 aCharMsg.message = WM_NULL;
1338 if (mFakeCharMsgs) {
1339 FakeCharMsg& fakeCharMsg = mFakeCharMsgs->ElementAt(0);
1340 if (fakeCharMsg.mConsumed) {
1341 return false;
1342 }
1343 MSG charMsg = fakeCharMsg.GetCharMsg(mMsg.hwnd);
1344 fakeCharMsg.mConsumed = true;
1345 if (!IsCharMessage(charMsg)) {
1346 return false;
1347 }
1348 aCharMsg = charMsg;
1349 return true;
1350 }
1352 // If next key message is not char message, we should give up to find a
1353 // related char message for the handling keydown event for now.
1354 // Note that it's possible other applications may send other key message
1355 // after we call TranslateMessage(). That may cause PeekMessage() failing
1356 // to get char message for the handling keydown message.
1357 MSG nextKeyMsg;
1358 if (!WinUtils::PeekMessage(&nextKeyMsg, mMsg.hwnd, WM_KEYFIRST, WM_KEYLAST,
1359 PM_NOREMOVE | PM_NOYIELD) ||
1360 !IsCharMessage(nextKeyMsg)) {
1361 return false;
1362 }
1364 // On Metrofox, PeekMessage() sometimes returns WM_NULL even if we specify
1365 // the message range. So, if it returns WM_NULL, we should retry to get
1366 // the following char message it was found above.
1367 for (uint32_t i = 0; i < 5; i++) {
1368 MSG removedMsg, nextKeyMsgInAllWindows;
1369 bool doCrash = false;
1370 if (!WinUtils::PeekMessage(&removedMsg, mMsg.hwnd,
1371 nextKeyMsg.message, nextKeyMsg.message,
1372 PM_REMOVE | PM_NOYIELD)) {
1373 // We meets unexpected case. We should collect the message queue state
1374 // and crash for reporting the bug.
1375 doCrash = true;
1376 // The char message is redirected to different thread's window by focus
1377 // move or something or just cancelled by external application.
1378 if (!WinUtils::PeekMessage(&nextKeyMsgInAllWindows, 0,
1379 WM_KEYFIRST, WM_KEYLAST,
1380 PM_NOREMOVE | PM_NOYIELD)) {
1381 return true;
1382 }
1383 if (MayBeSameCharMessage(nextKeyMsgInAllWindows, nextKeyMsg)) {
1384 // The char message is redirected to different window created by our
1385 // thread.
1386 if (nextKeyMsgInAllWindows.hwnd != mMsg.hwnd) {
1387 aCharMsg = nextKeyMsgInAllWindows;
1388 return true;
1389 }
1390 // The found char message still in the queue, but PeekMessage() failed
1391 // to remove it only with PM_REMOVE. Although, we don't know why this
1392 // occurs. However, this occurs acctually.
1393 // Try to remove the char message with GetMessage() again.
1394 if (WinUtils::GetMessage(&removedMsg, mMsg.hwnd,
1395 nextKeyMsg.message, nextKeyMsg.message)) {
1396 // Cancel to crash, but we need to check the removed message value.
1397 doCrash = false;
1398 }
1399 }
1400 }
1402 if (doCrash) {
1403 #ifdef MOZ_CRASHREPORTER
1404 nsPrintfCString info("\nPeekMessage() failed to remove char message! "
1405 "\nHandling message: %s (0x%08X), wParam: 0x%08X, "
1406 "lParam: 0x%08X, hwnd=0x%p, InSendMessageEx()=%s, \n"
1407 "Found message: %s (0x%08X), wParam: 0x%08X, "
1408 "lParam: 0x%08X, hwnd=0x%p, "
1409 "\nWM_NULL has been removed: %d, "
1410 "\nNext key message in all windows: %s (0x%08X), "
1411 "wParam: 0x%08X, lParam: 0x%08X, hwnd=0x%p, "
1412 "time=%d, ",
1413 GetMessageName(mMsg.message),
1414 mMsg.message, mMsg.wParam, mMsg.lParam,
1415 nextKeyMsg.hwnd,
1416 GetResultOfInSendMessageEx().get(),
1417 GetMessageName(nextKeyMsg.message),
1418 nextKeyMsg.message, nextKeyMsg.wParam,
1419 nextKeyMsg.lParam, nextKeyMsg.hwnd, i,
1420 GetMessageName(nextKeyMsgInAllWindows.message),
1421 nextKeyMsgInAllWindows.message,
1422 nextKeyMsgInAllWindows.wParam,
1423 nextKeyMsgInAllWindows.lParam,
1424 nextKeyMsgInAllWindows.hwnd,
1425 nextKeyMsgInAllWindows.time);
1426 CrashReporter::AppendAppNotesToCrashReport(info);
1427 MSG nextMsg;
1428 if (WinUtils::PeekMessage(&nextMsg, 0, 0, 0,
1429 PM_NOREMOVE | PM_NOYIELD)) {
1430 nsPrintfCString info("\nNext message in all windows: %s (0x%08X), "
1431 "wParam: 0x%08X, lParam: 0x%08X, hwnd=0x%p, "
1432 "time=%d",
1433 GetMessageName(nextMsg.message),
1434 nextMsg.message, nextMsg.wParam, nextMsg.lParam,
1435 nextMsg.hwnd, nextMsg.time);
1436 CrashReporter::AppendAppNotesToCrashReport(info);
1437 } else {
1438 CrashReporter::AppendAppNotesToCrashReport(
1439 NS_LITERAL_CSTRING("\nThere is no message in any window"));
1440 }
1441 #endif // #ifdef MOZ_CRASHREPORTER
1442 MOZ_CRASH("We lost the following char message");
1443 }
1445 // Retry for the strange case.
1446 if (removedMsg.message == WM_NULL) {
1447 continue;
1448 }
1450 // Typically, this case occurs with WM_DEADCHAR. If the removed message's
1451 // wParam becomes 0, that means that the key event shouldn't cause text
1452 // input. So, let's ignore the strange char message.
1453 if (removedMsg.message == nextKeyMsg.message && !removedMsg.wParam) {
1454 return false;
1455 }
1457 // NOTE: Although, we don't know when this case occurs, the scan code value
1458 // in lParam may be changed from 0 to something. The changed value
1459 // is different from the scan code of handling keydown message.
1460 if (!MayBeSameCharMessage(removedMsg, nextKeyMsg)) {
1461 #ifdef MOZ_CRASHREPORTER
1462 nsPrintfCString info("\nPeekMessage() removed unexpcted char message! "
1463 "\nHandling message: %s (0x%08X), wParam: 0x%08X, "
1464 "lParam: 0x%08X, hwnd=0x%p, InSendMessageEx()=%s, "
1465 "\nFound message: %s (0x%08X), wParam: 0x%08X, "
1466 "lParam: 0x%08X, hwnd=0x%p, "
1467 "\nRemoved message: %s (0x%08X), wParam: 0x%08X, "
1468 "lParam: 0x%08X, hwnd=0x%p, ",
1469 GetMessageName(mMsg.message),
1470 mMsg.message, mMsg.wParam, mMsg.lParam, mMsg.hwnd,
1471 GetResultOfInSendMessageEx().get(),
1472 GetMessageName(nextKeyMsg.message),
1473 nextKeyMsg.message, nextKeyMsg.wParam,
1474 nextKeyMsg.lParam, nextKeyMsg.hwnd,
1475 GetMessageName(removedMsg.message),
1476 removedMsg.message, removedMsg.wParam,
1477 removedMsg.lParam, removedMsg.hwnd);
1478 CrashReporter::AppendAppNotesToCrashReport(info);
1479 // What's the next key message?
1480 MSG nextKeyMsgAfter;
1481 if (WinUtils::PeekMessage(&nextKeyMsgAfter, mMsg.hwnd,
1482 WM_KEYFIRST, WM_KEYLAST,
1483 PM_NOREMOVE | PM_NOYIELD)) {
1484 nsPrintfCString info("\nNext key message after unexpected char message "
1485 "removed: %s (0x%08X), wParam: 0x%08X, "
1486 "lParam: 0x%08X, hwnd=0x%p, ",
1487 GetMessageName(nextKeyMsgAfter.message),
1488 nextKeyMsgAfter.message, nextKeyMsgAfter.wParam,
1489 nextKeyMsgAfter.lParam, nextKeyMsgAfter.hwnd);
1490 CrashReporter::AppendAppNotesToCrashReport(info);
1491 } else {
1492 CrashReporter::AppendAppNotesToCrashReport(
1493 NS_LITERAL_CSTRING("\nThere is no key message after unexpected char "
1494 "message removed, "));
1495 }
1496 // Another window has a key message?
1497 MSG nextKeyMsgInAllWindows;
1498 if (WinUtils::PeekMessage(&nextKeyMsgInAllWindows, 0,
1499 WM_KEYFIRST, WM_KEYLAST,
1500 PM_NOREMOVE | PM_NOYIELD)) {
1501 nsPrintfCString info("\nNext key message in all windows: %s (0x%08X), "
1502 "wParam: 0x%08X, lParam: 0x%08X, hwnd=0x%p.",
1503 GetMessageName(nextKeyMsgInAllWindows.message),
1504 nextKeyMsgInAllWindows.message,
1505 nextKeyMsgInAllWindows.wParam,
1506 nextKeyMsgInAllWindows.lParam,
1507 nextKeyMsgInAllWindows.hwnd);
1508 CrashReporter::AppendAppNotesToCrashReport(info);
1509 } else {
1510 CrashReporter::AppendAppNotesToCrashReport(
1511 NS_LITERAL_CSTRING("\nThere is no key message in any windows."));
1512 }
1513 #endif // #ifdef MOZ_CRASHREPORTER
1514 MOZ_CRASH("PeekMessage() removed unexpected message");
1515 }
1517 aCharMsg = removedMsg;
1518 return true;
1519 }
1520 #ifdef MOZ_CRASHREPORTER
1521 nsPrintfCString info("\nWe lost following char message! "
1522 "\nHandling message: %s (0x%08X), wParam: 0x%08X, "
1523 "lParam: 0x%08X, InSendMessageEx()=%s, \n"
1524 "Found message: %s (0x%08X), wParam: 0x%08X, "
1525 "lParam: 0x%08X, removed a lot of WM_NULL",
1526 GetMessageName(mMsg.message),
1527 mMsg.message, mMsg.wParam, mMsg.lParam,
1528 GetResultOfInSendMessageEx().get(),
1529 GetMessageName(nextKeyMsg.message),
1530 nextKeyMsg.message, nextKeyMsg.wParam,
1531 nextKeyMsg.lParam);
1532 CrashReporter::AppendAppNotesToCrashReport(info);
1533 #endif // #ifdef MOZ_CRASHREPORTER
1534 MOZ_CRASH("We lost the following char message");
1535 return false;
1536 }
1538 bool
1539 NativeKey::DispatchPluginEventsAndDiscardsCharMessages() const
1540 {
1541 MOZ_ASSERT(IsKeyDownMessage());
1543 // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
1544 // They can be more than one because of:
1545 // * Dead-keys not pairing with base character
1546 // * Some keyboard layouts may map up to 4 characters to the single key
1547 bool anyCharMessagesRemoved = false;
1548 MSG msg;
1549 while (GetFollowingCharMessage(msg)) {
1550 if (msg.message == WM_NULL) {
1551 continue;
1552 }
1553 anyCharMessagesRemoved = true;
1554 // If the window handle is changed, focused window must be changed.
1555 // So, plugin shouldn't handle it anymore.
1556 if (msg.hwnd != mMsg.hwnd) {
1557 break;
1558 }
1559 MOZ_RELEASE_ASSERT(!mWidget->Destroyed(),
1560 "NativeKey tries to dispatch a plugin event on destroyed widget");
1561 mWidget->DispatchPluginEvent(msg);
1562 if (mWidget->Destroyed()) {
1563 return true;
1564 }
1565 }
1567 if (!mFakeCharMsgs && !anyCharMessagesRemoved &&
1568 mDOMKeyCode == NS_VK_BACK && IsIMEDoingKakuteiUndo()) {
1569 // This is for a hack for ATOK and WXG. So, PeekMessage() must scceed!
1570 while (WinUtils::PeekMessage(&msg, mMsg.hwnd, WM_CHAR, WM_CHAR,
1571 PM_REMOVE | PM_NOYIELD)) {
1572 if (msg.message != WM_CHAR) {
1573 MOZ_RELEASE_ASSERT(msg.message == WM_NULL,
1574 "Unexpected message was removed");
1575 continue;
1576 }
1577 MOZ_RELEASE_ASSERT(!mWidget->Destroyed(),
1578 "NativeKey tries to dispatch a plugin event on destroyed widget");
1579 mWidget->DispatchPluginEvent(msg);
1580 return mWidget->Destroyed();
1581 }
1582 MOZ_CRASH("NativeKey failed to get WM_CHAR for ATOK or WXG");
1583 }
1585 return false;
1586 }
1588 bool
1589 NativeKey::DispatchKeyPressEventsWithKeyboardLayout() const
1590 {
1591 MOZ_ASSERT(IsKeyDownMessage());
1592 MOZ_ASSERT(!mIsDeadKey);
1594 KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
1596 UniCharsAndModifiers inputtingChars(mCommittedCharsAndModifiers);
1597 UniCharsAndModifiers shiftedChars;
1598 UniCharsAndModifiers unshiftedChars;
1599 uint32_t shiftedLatinChar = 0;
1600 uint32_t unshiftedLatinChar = 0;
1602 if (!KeyboardLayout::IsPrintableCharKey(mVirtualKeyCode)) {
1603 inputtingChars.Clear();
1604 }
1606 if (mModKeyState.IsControl() ^ mModKeyState.IsAlt()) {
1607 ModifierKeyState capsLockState(
1608 mModKeyState.GetModifiers() & MODIFIER_CAPSLOCK);
1610 unshiftedChars =
1611 keyboardLayout->GetUniCharsAndModifiers(mVirtualKeyCode, capsLockState);
1612 capsLockState.Set(MODIFIER_SHIFT);
1613 shiftedChars =
1614 keyboardLayout->GetUniCharsAndModifiers(mVirtualKeyCode, capsLockState);
1616 // The current keyboard cannot input alphabets or numerics,
1617 // we should append them for Shortcut/Access keys.
1618 // E.g., for Cyrillic keyboard layout.
1619 capsLockState.Unset(MODIFIER_SHIFT);
1620 WidgetUtils::GetLatinCharCodeForKeyCode(mDOMKeyCode,
1621 capsLockState.GetModifiers(),
1622 &unshiftedLatinChar,
1623 &shiftedLatinChar);
1625 // If the shiftedLatinChar isn't 0, the key code is NS_VK_[A-Z].
1626 if (shiftedLatinChar) {
1627 // If the produced characters of the key on current keyboard layout
1628 // are same as computed Latin characters, we shouldn't append the
1629 // Latin characters to alternativeCharCode.
1630 if (unshiftedLatinChar == unshiftedChars.mChars[0] &&
1631 shiftedLatinChar == shiftedChars.mChars[0]) {
1632 shiftedLatinChar = unshiftedLatinChar = 0;
1633 }
1634 } else if (unshiftedLatinChar) {
1635 // If the shiftedLatinChar is 0, the keyCode doesn't produce
1636 // alphabet character. At that time, the character may be produced
1637 // with Shift key. E.g., on French keyboard layout, NS_VK_PERCENT
1638 // key produces LATIN SMALL LETTER U WITH GRAVE (U+00F9) without
1639 // Shift key but with Shift key, it produces '%'.
1640 // If the unshiftedLatinChar is produced by the key on current
1641 // keyboard layout, we shouldn't append it to alternativeCharCode.
1642 if (unshiftedLatinChar == unshiftedChars.mChars[0] ||
1643 unshiftedLatinChar == shiftedChars.mChars[0]) {
1644 unshiftedLatinChar = 0;
1645 }
1646 }
1648 // If the charCode is not ASCII character, we should replace the
1649 // charCode with ASCII character only when Ctrl is pressed.
1650 // But don't replace the charCode when the charCode is not same as
1651 // unmodified characters. In such case, Ctrl is sometimes used for a
1652 // part of character inputting key combination like Shift.
1653 if (mModKeyState.IsControl()) {
1654 uint32_t ch =
1655 mModKeyState.IsShift() ? shiftedLatinChar : unshiftedLatinChar;
1656 if (ch &&
1657 (!inputtingChars.mLength ||
1658 inputtingChars.UniCharsCaseInsensitiveEqual(
1659 mModKeyState.IsShift() ? shiftedChars : unshiftedChars))) {
1660 inputtingChars.Clear();
1661 inputtingChars.Append(ch, mModKeyState.GetModifiers());
1662 }
1663 }
1664 }
1666 if (inputtingChars.IsEmpty() &&
1667 shiftedChars.IsEmpty() && unshiftedChars.IsEmpty()) {
1668 WidgetKeyboardEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
1669 keypressEvent.keyCode = mDOMKeyCode;
1670 InitKeyEvent(keypressEvent, mModKeyState);
1671 return DispatchKeyEvent(keypressEvent);
1672 }
1674 uint32_t longestLength =
1675 std::max(inputtingChars.mLength,
1676 std::max(shiftedChars.mLength, unshiftedChars.mLength));
1677 uint32_t skipUniChars = longestLength - inputtingChars.mLength;
1678 uint32_t skipShiftedChars = longestLength - shiftedChars.mLength;
1679 uint32_t skipUnshiftedChars = longestLength - unshiftedChars.mLength;
1680 UINT keyCode = !inputtingChars.mLength ? mDOMKeyCode : 0;
1681 bool defaultPrevented = false;
1682 for (uint32_t cnt = 0; cnt < longestLength; cnt++) {
1683 uint16_t uniChar, shiftedChar, unshiftedChar;
1684 uniChar = shiftedChar = unshiftedChar = 0;
1685 ModifierKeyState modKeyState(mModKeyState);
1686 if (skipUniChars <= cnt) {
1687 if (cnt - skipUniChars < inputtingChars.mLength) {
1688 // If key in combination with Alt and/or Ctrl produces a different
1689 // character than without them then do not report these flags
1690 // because it is separate keyboard layout shift state. If dead-key
1691 // and base character does not produce a valid composite character
1692 // then both produced dead-key character and following base
1693 // character may have different modifier flags, too.
1694 modKeyState.Unset(MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT |
1695 MODIFIER_ALTGRAPH | MODIFIER_CAPSLOCK);
1696 modKeyState.Set(inputtingChars.mModifiers[cnt - skipUniChars]);
1697 }
1698 uniChar = inputtingChars.mChars[cnt - skipUniChars];
1699 }
1700 if (skipShiftedChars <= cnt)
1701 shiftedChar = shiftedChars.mChars[cnt - skipShiftedChars];
1702 if (skipUnshiftedChars <= cnt)
1703 unshiftedChar = unshiftedChars.mChars[cnt - skipUnshiftedChars];
1704 nsAutoTArray<AlternativeCharCode, 5> altArray;
1706 if (shiftedChar || unshiftedChar) {
1707 AlternativeCharCode chars(unshiftedChar, shiftedChar);
1708 altArray.AppendElement(chars);
1709 }
1710 if (cnt == longestLength - 1) {
1711 if (unshiftedLatinChar || shiftedLatinChar) {
1712 AlternativeCharCode chars(unshiftedLatinChar, shiftedLatinChar);
1713 altArray.AppendElement(chars);
1714 }
1716 // Typically, following virtual keycodes are used for a key which can
1717 // input the character. However, these keycodes are also used for
1718 // other keys on some keyboard layout. E.g., in spite of Shift+'1'
1719 // inputs '+' on Thai keyboard layout, a key which is at '=/+'
1720 // key on ANSI keyboard layout is VK_OEM_PLUS. Native applications
1721 // handle it as '+' key if Ctrl key is pressed.
1722 char16_t charForOEMKeyCode = 0;
1723 switch (mVirtualKeyCode) {
1724 case VK_OEM_PLUS: charForOEMKeyCode = '+'; break;
1725 case VK_OEM_COMMA: charForOEMKeyCode = ','; break;
1726 case VK_OEM_MINUS: charForOEMKeyCode = '-'; break;
1727 case VK_OEM_PERIOD: charForOEMKeyCode = '.'; break;
1728 }
1729 if (charForOEMKeyCode &&
1730 charForOEMKeyCode != unshiftedChars.mChars[0] &&
1731 charForOEMKeyCode != shiftedChars.mChars[0] &&
1732 charForOEMKeyCode != unshiftedLatinChar &&
1733 charForOEMKeyCode != shiftedLatinChar) {
1734 AlternativeCharCode OEMChars(charForOEMKeyCode, charForOEMKeyCode);
1735 altArray.AppendElement(OEMChars);
1736 }
1737 }
1739 WidgetKeyboardEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
1740 keypressEvent.charCode = uniChar;
1741 keypressEvent.alternativeCharCodes.AppendElements(altArray);
1742 InitKeyEvent(keypressEvent, modKeyState);
1743 defaultPrevented = (DispatchKeyEvent(keypressEvent) || defaultPrevented);
1744 if (mWidget->Destroyed()) {
1745 return true;
1746 }
1747 }
1749 return defaultPrevented;
1750 }
1752 bool
1753 NativeKey::DispatchKeyPressEventForFollowingCharMessage(
1754 const MSG& aCharMsg) const
1755 {
1756 MOZ_ASSERT(IsKeyDownMessage());
1758 if (mFakeCharMsgs) {
1759 if (IsDeadCharMessage(aCharMsg)) {
1760 return false;
1761 }
1762 #ifdef DEBUG
1763 if (mIsPrintableKey) {
1764 nsPrintfCString log(
1765 "mOriginalVirtualKeyCode=0x%02X, mCommittedCharsAndModifiers={ "
1766 "mChars=[ 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X ], mLength=%d }, "
1767 "wParam=0x%04X",
1768 mOriginalVirtualKeyCode, mCommittedCharsAndModifiers.mChars[0],
1769 mCommittedCharsAndModifiers.mChars[1],
1770 mCommittedCharsAndModifiers.mChars[2],
1771 mCommittedCharsAndModifiers.mChars[3],
1772 mCommittedCharsAndModifiers.mChars[4],
1773 mCommittedCharsAndModifiers.mLength, aCharMsg.wParam);
1774 if (mCommittedCharsAndModifiers.IsEmpty()) {
1775 log.Insert("length is zero: ", 0);
1776 NS_ERROR(log.get());
1777 NS_ABORT();
1778 } else if (mCommittedCharsAndModifiers.mChars[0] != aCharMsg.wParam) {
1779 log.Insert("character mismatch: ", 0);
1780 NS_ERROR(log.get());
1781 NS_ABORT();
1782 }
1783 }
1784 #endif // #ifdef DEBUG
1785 return HandleCharMessage(aCharMsg);
1786 }
1788 if (IsDeadCharMessage(aCharMsg)) {
1789 if (!mWidget->PluginHasFocus()) {
1790 return false;
1791 }
1792 return (mWidget->DispatchPluginEvent(aCharMsg) || mWidget->Destroyed());
1793 }
1795 bool defaultPrevented = HandleCharMessage(aCharMsg);
1796 // If a syschar keypress wasn't processed, Windows may want to
1797 // handle it to activate a native menu.
1798 if (!defaultPrevented && IsSysCharMessage(aCharMsg)) {
1799 ::DefWindowProcW(aCharMsg.hwnd, aCharMsg.message,
1800 aCharMsg.wParam, aCharMsg.lParam);
1801 }
1802 return defaultPrevented;
1803 }
1805 /*****************************************************************************
1806 * mozilla::widget::KeyboardLayout
1807 *****************************************************************************/
1809 KeyboardLayout* KeyboardLayout::sInstance = nullptr;
1810 nsIIdleServiceInternal* KeyboardLayout::sIdleService = nullptr;
1812 // static
1813 KeyboardLayout*
1814 KeyboardLayout::GetInstance()
1815 {
1816 if (!sInstance) {
1817 sInstance = new KeyboardLayout();
1818 nsCOMPtr<nsIIdleServiceInternal> idleService =
1819 do_GetService("@mozilla.org/widget/idleservice;1");
1820 // The refcount will be decreased at shut down.
1821 sIdleService = idleService.forget().take();
1822 }
1823 return sInstance;
1824 }
1826 // static
1827 void
1828 KeyboardLayout::Shutdown()
1829 {
1830 delete sInstance;
1831 sInstance = nullptr;
1832 NS_IF_RELEASE(sIdleService);
1833 }
1835 // static
1836 void
1837 KeyboardLayout::NotifyIdleServiceOfUserActivity()
1838 {
1839 sIdleService->ResetIdleTimeOut(0);
1840 }
1842 KeyboardLayout::KeyboardLayout() :
1843 mKeyboardLayout(0), mIsOverridden(false),
1844 mIsPendingToRestoreKeyboardLayout(false)
1845 {
1846 mDeadKeyTableListHead = nullptr;
1848 // NOTE: LoadLayout() should be called via OnLayoutChange().
1849 }
1851 KeyboardLayout::~KeyboardLayout()
1852 {
1853 ReleaseDeadKeyTables();
1854 }
1856 bool
1857 KeyboardLayout::IsPrintableCharKey(uint8_t aVirtualKey)
1858 {
1859 return GetKeyIndex(aVirtualKey) >= 0;
1860 }
1862 WORD
1863 KeyboardLayout::ComputeScanCodeForVirtualKeyCode(uint8_t aVirtualKeyCode) const
1864 {
1865 return static_cast<WORD>(
1866 ::MapVirtualKeyEx(aVirtualKeyCode, MAPVK_VK_TO_VSC, GetLayout()));
1867 }
1869 bool
1870 KeyboardLayout::IsDeadKey(uint8_t aVirtualKey,
1871 const ModifierKeyState& aModKeyState) const
1872 {
1873 int32_t virtualKeyIndex = GetKeyIndex(aVirtualKey);
1874 if (virtualKeyIndex < 0) {
1875 return false;
1876 }
1878 return mVirtualKeys[virtualKeyIndex].IsDeadKey(
1879 VirtualKey::ModifiersToShiftState(aModKeyState.GetModifiers()));
1880 }
1882 void
1883 KeyboardLayout::InitNativeKey(NativeKey& aNativeKey,
1884 const ModifierKeyState& aModKeyState)
1885 {
1886 if (mIsPendingToRestoreKeyboardLayout) {
1887 LoadLayout(::GetKeyboardLayout(0));
1888 }
1890 uint8_t virtualKey = aNativeKey.mOriginalVirtualKeyCode;
1891 int32_t virtualKeyIndex = GetKeyIndex(virtualKey);
1893 if (virtualKeyIndex < 0) {
1894 // Does not produce any printable characters, but still preserves the
1895 // dead-key state.
1896 return;
1897 }
1899 MOZ_ASSERT(aNativeKey.mKeyNameIndex == KEY_NAME_INDEX_USE_STRING,
1900 "Printable key's key name index must be KEY_NAME_INDEX_USE_STRING");
1902 bool isKeyDown = aNativeKey.IsKeyDownMessage();
1903 uint8_t shiftState =
1904 VirtualKey::ModifiersToShiftState(aModKeyState.GetModifiers());
1906 if (mVirtualKeys[virtualKeyIndex].IsDeadKey(shiftState)) {
1907 if ((isKeyDown && mActiveDeadKey < 0) ||
1908 (!isKeyDown && mActiveDeadKey == virtualKey)) {
1909 // First dead key event doesn't generate characters.
1910 if (isKeyDown) {
1911 // Dead-key state activated at keydown.
1912 mActiveDeadKey = virtualKey;
1913 mDeadKeyShiftState = shiftState;
1914 }
1915 UniCharsAndModifiers deadChars =
1916 mVirtualKeys[virtualKeyIndex].GetNativeUniChars(shiftState);
1917 NS_ASSERTION(deadChars.mLength == 1,
1918 "dead key must generate only one character");
1919 aNativeKey.mKeyNameIndex =
1920 WidgetUtils::GetDeadKeyNameIndex(deadChars.mChars[0]);
1921 return;
1922 }
1924 // Dead key followed by another dead key causes inputting both character.
1925 // However, at keydown message handling, we need to forget the first
1926 // dead key because there is no guarantee coming WM_KEYUP for the second
1927 // dead key before next WM_KEYDOWN. E.g., due to auto key repeat or
1928 // pressing another dead key before releasing current key. Therefore,
1929 // we can set only a character for current key for keyup event.
1930 if (mActiveDeadKey < 0) {
1931 aNativeKey.mCommittedCharsAndModifiers =
1932 mVirtualKeys[virtualKeyIndex].GetUniChars(shiftState);
1933 return;
1934 }
1936 int32_t activeDeadKeyIndex = GetKeyIndex(mActiveDeadKey);
1937 if (activeDeadKeyIndex < 0 || activeDeadKeyIndex >= NS_NUM_OF_KEYS) {
1938 #if defined(DEBUG) || defined(MOZ_CRASHREPORTER)
1939 nsPrintfCString warning("The virtual key index (%d) of mActiveDeadKey "
1940 "(0x%02X) is not a printable key (virtualKey="
1941 "0x%02X)",
1942 activeDeadKeyIndex, mActiveDeadKey, virtualKey);
1943 NS_WARNING(warning.get());
1944 #ifdef MOZ_CRASHREPORTER
1945 CrashReporter::AppendAppNotesToCrashReport(
1946 NS_LITERAL_CSTRING("\n") + warning);
1947 #endif // #ifdef MOZ_CRASHREPORTER
1948 #endif // #if defined(DEBUG) || defined(MOZ_CRASHREPORTER)
1949 MOZ_CRASH("Trying to reference out of range of mVirtualKeys");
1950 }
1951 UniCharsAndModifiers prevDeadChars =
1952 mVirtualKeys[activeDeadKeyIndex].GetUniChars(mDeadKeyShiftState);
1953 UniCharsAndModifiers newChars =
1954 mVirtualKeys[virtualKeyIndex].GetUniChars(shiftState);
1955 // But keypress events should be fired for each committed character.
1956 aNativeKey.mCommittedCharsAndModifiers = prevDeadChars + newChars;
1957 if (isKeyDown) {
1958 DeactivateDeadKeyState();
1959 }
1960 return;
1961 }
1963 UniCharsAndModifiers baseChars =
1964 mVirtualKeys[virtualKeyIndex].GetUniChars(shiftState);
1965 if (mActiveDeadKey < 0) {
1966 // No dead-keys are active. Just return the produced characters.
1967 aNativeKey.mCommittedCharsAndModifiers = baseChars;
1968 return;
1969 }
1971 // Dead-key was active. See if pressed base character does produce
1972 // valid composite character.
1973 int32_t activeDeadKeyIndex = GetKeyIndex(mActiveDeadKey);
1974 char16_t compositeChar = (baseChars.mLength == 1 && baseChars.mChars[0]) ?
1975 mVirtualKeys[activeDeadKeyIndex].GetCompositeChar(mDeadKeyShiftState,
1976 baseChars.mChars[0]) : 0;
1977 if (compositeChar) {
1978 // Active dead-key and base character does produce exactly one
1979 // composite character.
1980 aNativeKey.mCommittedCharsAndModifiers.Append(compositeChar,
1981 baseChars.mModifiers[0]);
1982 if (isKeyDown) {
1983 DeactivateDeadKeyState();
1984 }
1985 return;
1986 }
1988 // There is no valid dead-key and base character combination.
1989 // Return dead-key character followed by base character.
1990 UniCharsAndModifiers deadChars =
1991 mVirtualKeys[activeDeadKeyIndex].GetUniChars(mDeadKeyShiftState);
1992 // But keypress events should be fired for each committed character.
1993 aNativeKey.mCommittedCharsAndModifiers = deadChars + baseChars;
1994 if (isKeyDown) {
1995 DeactivateDeadKeyState();
1996 }
1998 return;
1999 }
2001 UniCharsAndModifiers
2002 KeyboardLayout::GetUniCharsAndModifiers(
2003 uint8_t aVirtualKey,
2004 const ModifierKeyState& aModKeyState) const
2005 {
2006 UniCharsAndModifiers result;
2007 int32_t key = GetKeyIndex(aVirtualKey);
2008 if (key < 0) {
2009 return result;
2010 }
2011 return mVirtualKeys[key].
2012 GetUniChars(VirtualKey::ModifiersToShiftState(aModKeyState.GetModifiers()));
2013 }
2015 void
2016 KeyboardLayout::LoadLayout(HKL aLayout)
2017 {
2018 mIsPendingToRestoreKeyboardLayout = false;
2020 if (mKeyboardLayout == aLayout) {
2021 return;
2022 }
2024 mKeyboardLayout = aLayout;
2026 BYTE kbdState[256];
2027 memset(kbdState, 0, sizeof(kbdState));
2029 BYTE originalKbdState[256];
2030 // Bitfield with all shift states that have at least one dead-key.
2031 uint16_t shiftStatesWithDeadKeys = 0;
2032 // Bitfield with all shift states that produce any possible dead-key base
2033 // characters.
2034 uint16_t shiftStatesWithBaseChars = 0;
2036 mActiveDeadKey = -1;
2038 ReleaseDeadKeyTables();
2040 ::GetKeyboardState(originalKbdState);
2042 // For each shift state gather all printable characters that are produced
2043 // for normal case when no any dead-key is active.
2045 for (VirtualKey::ShiftState shiftState = 0; shiftState < 16; shiftState++) {
2046 VirtualKey::FillKbdState(kbdState, shiftState);
2047 for (uint32_t virtualKey = 0; virtualKey < 256; virtualKey++) {
2048 int32_t vki = GetKeyIndex(virtualKey);
2049 if (vki < 0) {
2050 continue;
2051 }
2052 NS_ASSERTION(uint32_t(vki) < ArrayLength(mVirtualKeys), "invalid index");
2053 char16_t uniChars[5];
2054 int32_t ret =
2055 ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)uniChars,
2056 ArrayLength(uniChars), 0, mKeyboardLayout);
2057 // dead-key
2058 if (ret < 0) {
2059 shiftStatesWithDeadKeys |= (1 << shiftState);
2060 // Repeat dead-key to deactivate it and get its character
2061 // representation.
2062 char16_t deadChar[2];
2063 ret = ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)deadChar,
2064 ArrayLength(deadChar), 0, mKeyboardLayout);
2065 NS_ASSERTION(ret == 2, "Expecting twice repeated dead-key character");
2066 mVirtualKeys[vki].SetDeadChar(shiftState, deadChar[0]);
2067 } else {
2068 if (ret == 1) {
2069 // dead-key can pair only with exactly one base character.
2070 shiftStatesWithBaseChars |= (1 << shiftState);
2071 }
2072 mVirtualKeys[vki].SetNormalChars(shiftState, uniChars, ret);
2073 }
2074 }
2075 }
2077 // Now process each dead-key to find all its base characters and resulting
2078 // composite characters.
2079 for (VirtualKey::ShiftState shiftState = 0; shiftState < 16; shiftState++) {
2080 if (!(shiftStatesWithDeadKeys & (1 << shiftState))) {
2081 continue;
2082 }
2084 VirtualKey::FillKbdState(kbdState, shiftState);
2086 for (uint32_t virtualKey = 0; virtualKey < 256; virtualKey++) {
2087 int32_t vki = GetKeyIndex(virtualKey);
2088 if (vki >= 0 && mVirtualKeys[vki].IsDeadKey(shiftState)) {
2089 DeadKeyEntry deadKeyArray[256];
2090 int32_t n = GetDeadKeyCombinations(virtualKey, kbdState,
2091 shiftStatesWithBaseChars,
2092 deadKeyArray,
2093 ArrayLength(deadKeyArray));
2094 const DeadKeyTable* dkt =
2095 mVirtualKeys[vki].MatchingDeadKeyTable(deadKeyArray, n);
2096 if (!dkt) {
2097 dkt = AddDeadKeyTable(deadKeyArray, n);
2098 }
2099 mVirtualKeys[vki].AttachDeadKeyTable(shiftState, dkt);
2100 }
2101 }
2102 }
2104 ::SetKeyboardState(originalKbdState);
2105 }
2107 inline int32_t
2108 KeyboardLayout::GetKeyIndex(uint8_t aVirtualKey)
2109 {
2110 // Currently these 68 (NS_NUM_OF_KEYS) virtual keys are assumed
2111 // to produce visible representation:
2112 // 0x20 - VK_SPACE ' '
2113 // 0x30..0x39 '0'..'9'
2114 // 0x41..0x5A 'A'..'Z'
2115 // 0x60..0x69 '0'..'9' on numpad
2116 // 0x6A - VK_MULTIPLY '*' on numpad
2117 // 0x6B - VK_ADD '+' on numpad
2118 // 0x6D - VK_SUBTRACT '-' on numpad
2119 // 0x6E - VK_DECIMAL '.' on numpad
2120 // 0x6F - VK_DIVIDE '/' on numpad
2121 // 0x6E - VK_DECIMAL '.'
2122 // 0xBA - VK_OEM_1 ';:' for US
2123 // 0xBB - VK_OEM_PLUS '+' any country
2124 // 0xBC - VK_OEM_COMMA ',' any country
2125 // 0xBD - VK_OEM_MINUS '-' any country
2126 // 0xBE - VK_OEM_PERIOD '.' any country
2127 // 0xBF - VK_OEM_2 '/?' for US
2128 // 0xC0 - VK_OEM_3 '`~' for US
2129 // 0xC1 - VK_ABNT_C1 '/?' for Brazilian
2130 // 0xC2 - VK_ABNT_C2 separator key on numpad (Brazilian or JIS for Mac)
2131 // 0xDB - VK_OEM_4 '[{' for US
2132 // 0xDC - VK_OEM_5 '\|' for US
2133 // 0xDD - VK_OEM_6 ']}' for US
2134 // 0xDE - VK_OEM_7 ''"' for US
2135 // 0xDF - VK_OEM_8
2136 // 0xE1 - no name
2137 // 0xE2 - VK_OEM_102 '\_' for JIS
2138 // 0xE3 - no name
2139 // 0xE4 - no name
2141 static const int8_t xlat[256] =
2142 {
2143 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2144 //-----------------------------------------------------------------------
2145 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00
2146 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10
2147 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 20
2148 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, // 30
2149 -1, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 40
2150 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, -1, -1, -1, // 50
2151 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, -1, 49, 50, 51, // 60
2152 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 70
2153 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 80
2154 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 90
2155 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // A0
2156 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 52, 53, 54, 55, 56, 57, // B0
2157 58, 59, 60, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // C0
2158 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 61, 62, 63, 64, 65, // D0
2159 -1, 66, 67, 68, 69, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // E0
2160 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // F0
2161 };
2163 return xlat[aVirtualKey];
2164 }
2166 int
2167 KeyboardLayout::CompareDeadKeyEntries(const void* aArg1,
2168 const void* aArg2,
2169 void*)
2170 {
2171 const DeadKeyEntry* arg1 = static_cast<const DeadKeyEntry*>(aArg1);
2172 const DeadKeyEntry* arg2 = static_cast<const DeadKeyEntry*>(aArg2);
2174 return arg1->BaseChar - arg2->BaseChar;
2175 }
2177 const DeadKeyTable*
2178 KeyboardLayout::AddDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
2179 uint32_t aEntries)
2180 {
2181 DeadKeyTableListEntry* next = mDeadKeyTableListHead;
2183 const size_t bytes = offsetof(DeadKeyTableListEntry, data) +
2184 DeadKeyTable::SizeInBytes(aEntries);
2185 uint8_t* p = new uint8_t[bytes];
2187 mDeadKeyTableListHead = reinterpret_cast<DeadKeyTableListEntry*>(p);
2188 mDeadKeyTableListHead->next = next;
2190 DeadKeyTable* dkt =
2191 reinterpret_cast<DeadKeyTable*>(mDeadKeyTableListHead->data);
2193 dkt->Init(aDeadKeyArray, aEntries);
2195 return dkt;
2196 }
2198 void
2199 KeyboardLayout::ReleaseDeadKeyTables()
2200 {
2201 while (mDeadKeyTableListHead) {
2202 uint8_t* p = reinterpret_cast<uint8_t*>(mDeadKeyTableListHead);
2203 mDeadKeyTableListHead = mDeadKeyTableListHead->next;
2205 delete [] p;
2206 }
2207 }
2209 bool
2210 KeyboardLayout::EnsureDeadKeyActive(bool aIsActive,
2211 uint8_t aDeadKey,
2212 const PBYTE aDeadKeyKbdState)
2213 {
2214 int32_t ret;
2215 do {
2216 char16_t dummyChars[5];
2217 ret = ::ToUnicodeEx(aDeadKey, 0, (PBYTE)aDeadKeyKbdState,
2218 (LPWSTR)dummyChars, ArrayLength(dummyChars), 0,
2219 mKeyboardLayout);
2220 // returned values:
2221 // <0 - Dead key state is active. The keyboard driver will wait for next
2222 // character.
2223 // 1 - Previous pressed key was a valid base character that produced
2224 // exactly one composite character.
2225 // >1 - Previous pressed key does not produce any composite characters.
2226 // Return dead-key character followed by base character(s).
2227 } while ((ret < 0) != aIsActive);
2229 return (ret < 0);
2230 }
2232 void
2233 KeyboardLayout::DeactivateDeadKeyState()
2234 {
2235 if (mActiveDeadKey < 0) {
2236 return;
2237 }
2239 BYTE kbdState[256];
2240 memset(kbdState, 0, sizeof(kbdState));
2242 VirtualKey::FillKbdState(kbdState, mDeadKeyShiftState);
2244 EnsureDeadKeyActive(false, mActiveDeadKey, kbdState);
2245 mActiveDeadKey = -1;
2246 }
2248 bool
2249 KeyboardLayout::AddDeadKeyEntry(char16_t aBaseChar,
2250 char16_t aCompositeChar,
2251 DeadKeyEntry* aDeadKeyArray,
2252 uint32_t aEntries)
2253 {
2254 for (uint32_t index = 0; index < aEntries; index++) {
2255 if (aDeadKeyArray[index].BaseChar == aBaseChar) {
2256 return false;
2257 }
2258 }
2260 aDeadKeyArray[aEntries].BaseChar = aBaseChar;
2261 aDeadKeyArray[aEntries].CompositeChar = aCompositeChar;
2263 return true;
2264 }
2266 uint32_t
2267 KeyboardLayout::GetDeadKeyCombinations(uint8_t aDeadKey,
2268 const PBYTE aDeadKeyKbdState,
2269 uint16_t aShiftStatesWithBaseChars,
2270 DeadKeyEntry* aDeadKeyArray,
2271 uint32_t aMaxEntries)
2272 {
2273 bool deadKeyActive = false;
2274 uint32_t entries = 0;
2275 BYTE kbdState[256];
2276 memset(kbdState, 0, sizeof(kbdState));
2278 for (uint32_t shiftState = 0; shiftState < 16; shiftState++) {
2279 if (!(aShiftStatesWithBaseChars & (1 << shiftState))) {
2280 continue;
2281 }
2283 VirtualKey::FillKbdState(kbdState, shiftState);
2285 for (uint32_t virtualKey = 0; virtualKey < 256; virtualKey++) {
2286 int32_t vki = GetKeyIndex(virtualKey);
2287 // Dead-key can pair only with such key that produces exactly one base
2288 // character.
2289 if (vki >= 0 &&
2290 mVirtualKeys[vki].GetNativeUniChars(shiftState).mLength == 1) {
2291 // Ensure dead-key is in active state, when it swallows entered
2292 // character and waits for the next pressed key.
2293 if (!deadKeyActive) {
2294 deadKeyActive = EnsureDeadKeyActive(true, aDeadKey,
2295 aDeadKeyKbdState);
2296 }
2298 // Depending on the character the followed the dead-key, the keyboard
2299 // driver can produce one composite character, or a dead-key character
2300 // followed by a second character.
2301 char16_t compositeChars[5];
2302 int32_t ret =
2303 ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)compositeChars,
2304 ArrayLength(compositeChars), 0, mKeyboardLayout);
2305 switch (ret) {
2306 case 0:
2307 // This key combination does not produce any characters. The
2308 // dead-key is still in active state.
2309 break;
2310 case 1: {
2311 // Exactly one composite character produced. Now, when dead-key
2312 // is not active, repeat the last character one more time to
2313 // determine the base character.
2314 char16_t baseChars[5];
2315 ret = ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)baseChars,
2316 ArrayLength(baseChars), 0, mKeyboardLayout);
2317 NS_ASSERTION(ret == 1, "One base character expected");
2318 if (ret == 1 && entries < aMaxEntries &&
2319 AddDeadKeyEntry(baseChars[0], compositeChars[0],
2320 aDeadKeyArray, entries)) {
2321 entries++;
2322 }
2323 deadKeyActive = false;
2324 break;
2325 }
2326 default:
2327 // 1. Unexpected dead-key. Dead-key chaining is not supported.
2328 // 2. More than one character generated. This is not a valid
2329 // dead-key and base character combination.
2330 deadKeyActive = false;
2331 break;
2332 }
2333 }
2334 }
2335 }
2337 if (deadKeyActive) {
2338 deadKeyActive = EnsureDeadKeyActive(false, aDeadKey, aDeadKeyKbdState);
2339 }
2341 NS_QuickSort(aDeadKeyArray, entries, sizeof(DeadKeyEntry),
2342 CompareDeadKeyEntries, nullptr);
2343 return entries;
2344 }
2346 uint32_t
2347 KeyboardLayout::ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const
2348 {
2349 // Alphabet or Numeric or Numpad or Function keys
2350 if ((aNativeKeyCode >= 0x30 && aNativeKeyCode <= 0x39) ||
2351 (aNativeKeyCode >= 0x41 && aNativeKeyCode <= 0x5A) ||
2352 (aNativeKeyCode >= 0x60 && aNativeKeyCode <= 0x87)) {
2353 return static_cast<uint32_t>(aNativeKeyCode);
2354 }
2355 switch (aNativeKeyCode) {
2356 // Following keycodes are same as our DOM keycodes
2357 case VK_CANCEL:
2358 case VK_BACK:
2359 case VK_TAB:
2360 case VK_CLEAR:
2361 case VK_RETURN:
2362 case VK_SHIFT:
2363 case VK_CONTROL:
2364 case VK_MENU: // Alt
2365 case VK_PAUSE:
2366 case VK_CAPITAL: // CAPS LOCK
2367 case VK_KANA: // same as VK_HANGUL
2368 case VK_JUNJA:
2369 case VK_FINAL:
2370 case VK_HANJA: // same as VK_KANJI
2371 case VK_ESCAPE:
2372 case VK_CONVERT:
2373 case VK_NONCONVERT:
2374 case VK_ACCEPT:
2375 case VK_MODECHANGE:
2376 case VK_SPACE:
2377 case VK_PRIOR: // PAGE UP
2378 case VK_NEXT: // PAGE DOWN
2379 case VK_END:
2380 case VK_HOME:
2381 case VK_LEFT:
2382 case VK_UP:
2383 case VK_RIGHT:
2384 case VK_DOWN:
2385 case VK_SELECT:
2386 case VK_PRINT:
2387 case VK_EXECUTE:
2388 case VK_SNAPSHOT:
2389 case VK_INSERT:
2390 case VK_DELETE:
2391 case VK_APPS: // Context Menu
2392 case VK_SLEEP:
2393 case VK_NUMLOCK:
2394 case VK_SCROLL: // SCROLL LOCK
2395 case VK_ATTN: // Attension key of IBM midrange computers, e.g., AS/400
2396 case VK_CRSEL: // Cursor Selection
2397 case VK_EXSEL: // Extend Selection
2398 case VK_EREOF: // Erase EOF key of IBM 3270 keyboard layout
2399 case VK_PLAY:
2400 case VK_ZOOM:
2401 case VK_PA1: // PA1 key of IBM 3270 keyboard layout
2402 return uint32_t(aNativeKeyCode);
2404 case VK_HELP:
2405 return NS_VK_HELP;
2407 // Windows key should be mapped to a Win keycode
2408 // They should be able to be distinguished by DOM3 KeyboardEvent.location
2409 case VK_LWIN:
2410 case VK_RWIN:
2411 return NS_VK_WIN;
2413 case VK_VOLUME_MUTE:
2414 return NS_VK_VOLUME_MUTE;
2415 case VK_VOLUME_DOWN:
2416 return NS_VK_VOLUME_DOWN;
2417 case VK_VOLUME_UP:
2418 return NS_VK_VOLUME_UP;
2420 // Following keycodes are not defined in our DOM keycodes.
2421 case VK_BROWSER_BACK:
2422 case VK_BROWSER_FORWARD:
2423 case VK_BROWSER_REFRESH:
2424 case VK_BROWSER_STOP:
2425 case VK_BROWSER_SEARCH:
2426 case VK_BROWSER_FAVORITES:
2427 case VK_BROWSER_HOME:
2428 case VK_MEDIA_NEXT_TRACK:
2429 case VK_MEDIA_STOP:
2430 case VK_MEDIA_PLAY_PAUSE:
2431 case VK_LAUNCH_MAIL:
2432 case VK_LAUNCH_MEDIA_SELECT:
2433 case VK_LAUNCH_APP1:
2434 case VK_LAUNCH_APP2:
2435 return 0;
2437 // Following OEM specific virtual keycodes should pass through DOM keyCode
2438 // for compatibility with the other browsers on Windows.
2440 // Following OEM specific virtual keycodes are defined for Fujitsu/OASYS.
2441 case VK_OEM_FJ_JISHO:
2442 case VK_OEM_FJ_MASSHOU:
2443 case VK_OEM_FJ_TOUROKU:
2444 case VK_OEM_FJ_LOYA:
2445 case VK_OEM_FJ_ROYA:
2446 // Not sure what means "ICO".
2447 case VK_ICO_HELP:
2448 case VK_ICO_00:
2449 case VK_ICO_CLEAR:
2450 // Following OEM specific virtual keycodes are defined for Nokia/Ericsson.
2451 case VK_OEM_RESET:
2452 case VK_OEM_JUMP:
2453 case VK_OEM_PA1:
2454 case VK_OEM_PA2:
2455 case VK_OEM_PA3:
2456 case VK_OEM_WSCTRL:
2457 case VK_OEM_CUSEL:
2458 case VK_OEM_ATTN:
2459 case VK_OEM_FINISH:
2460 case VK_OEM_COPY:
2461 case VK_OEM_AUTO:
2462 case VK_OEM_ENLW:
2463 case VK_OEM_BACKTAB:
2464 // VK_OEM_CLEAR is defined as not OEM specific, but let's pass though
2465 // DOM keyCode like other OEM specific virtual keycodes.
2466 case VK_OEM_CLEAR:
2467 return uint32_t(aNativeKeyCode);
2469 // 0xE1 is an OEM specific virtual keycode. However, the value is already
2470 // used in our DOM keyCode for AltGr on Linux. So, this virtual keycode
2471 // cannot pass through DOM keyCode.
2472 case 0xE1:
2473 return 0;
2475 // Following keycodes are OEM keys which are keycodes for non-alphabet and
2476 // non-numeric keys, we should compute each keycode of them from unshifted
2477 // character which is inputted by each key. But if the unshifted character
2478 // is not an ASCII character but shifted character is an ASCII character,
2479 // we should refer it.
2480 case VK_OEM_1:
2481 case VK_OEM_PLUS:
2482 case VK_OEM_COMMA:
2483 case VK_OEM_MINUS:
2484 case VK_OEM_PERIOD:
2485 case VK_OEM_2:
2486 case VK_OEM_3:
2487 case VK_OEM_4:
2488 case VK_OEM_5:
2489 case VK_OEM_6:
2490 case VK_OEM_7:
2491 case VK_OEM_8:
2492 case VK_OEM_102:
2493 case VK_ABNT_C1:
2494 {
2495 NS_ASSERTION(IsPrintableCharKey(aNativeKeyCode),
2496 "The key must be printable");
2497 ModifierKeyState modKeyState(0);
2498 UniCharsAndModifiers uniChars =
2499 GetUniCharsAndModifiers(aNativeKeyCode, modKeyState);
2500 if (uniChars.mLength != 1 ||
2501 uniChars.mChars[0] < ' ' || uniChars.mChars[0] > 0x7F) {
2502 modKeyState.Set(MODIFIER_SHIFT);
2503 uniChars = GetUniCharsAndModifiers(aNativeKeyCode, modKeyState);
2504 if (uniChars.mLength != 1 ||
2505 uniChars.mChars[0] < ' ' || uniChars.mChars[0] > 0x7F) {
2506 return 0;
2507 }
2508 }
2509 return WidgetUtils::ComputeKeyCodeFromChar(uniChars.mChars[0]);
2510 }
2512 // IE sets 0xC2 to the DOM keyCode for VK_ABNT_C2. However, we're already
2513 // using NS_VK_SEPARATOR for the separator key on Mac and Linux. Therefore,
2514 // We should keep consistency between Gecko on all platforms rather than
2515 // with other browsers since a lot of keyCode values are already different
2516 // between browsers.
2517 case VK_ABNT_C2:
2518 return NS_VK_SEPARATOR;
2520 // VK_PROCESSKEY means IME already consumed the key event.
2521 case VK_PROCESSKEY:
2522 return 0;
2523 // VK_PACKET is generated by SendInput() API, we don't need to
2524 // care this message as key event.
2525 case VK_PACKET:
2526 return 0;
2527 // If a key is not mapped to a virtual keycode, 0xFF is used.
2528 case 0xFF:
2529 NS_WARNING("The key is failed to be converted to a virtual keycode");
2530 return 0;
2531 }
2532 #ifdef DEBUG
2533 nsPrintfCString warning("Unknown virtual keycode (0x%08X), please check the "
2534 "latest MSDN document, there may be some new "
2535 "keycodes we've never known.",
2536 aNativeKeyCode);
2537 NS_WARNING(warning.get());
2538 #endif
2539 return 0;
2540 }
2542 KeyNameIndex
2543 KeyboardLayout::ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const
2544 {
2545 if (IsPrintableCharKey(aVirtualKey)) {
2546 return KEY_NAME_INDEX_USE_STRING;
2547 }
2549 #define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
2550 #define NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
2551 #define NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
2552 #define NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
2554 switch (aVirtualKey) {
2556 #undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
2557 #define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \
2558 case aNativeKey: return aKeyNameIndex;
2560 #include "NativeKeyToDOMKeyName.h"
2562 #undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
2563 #define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
2565 default:
2566 break;
2567 }
2569 HKL layout = GetLayout();
2570 WORD langID = LOWORD(static_cast<HKL>(layout));
2571 WORD primaryLangID = PRIMARYLANGID(langID);
2573 if (primaryLangID == LANG_JAPANESE) {
2574 switch (aVirtualKey) {
2576 #undef NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
2577 #define NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)\
2578 case aNativeKey: return aKeyNameIndex;
2580 #include "NativeKeyToDOMKeyName.h"
2582 #undef NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
2583 #define NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
2585 default:
2586 break;
2587 }
2588 } else if (primaryLangID == LANG_KOREAN) {
2589 switch (aVirtualKey) {
2591 #undef NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
2592 #define NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)\
2593 case aNativeKey: return aKeyNameIndex;
2595 #include "NativeKeyToDOMKeyName.h"
2597 #undef NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
2598 #define NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)
2600 default:
2601 return KEY_NAME_INDEX_Unidentified;
2602 }
2603 }
2605 switch (aVirtualKey) {
2607 #undef NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
2608 #define NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)\
2609 case aNativeKey: return aKeyNameIndex;
2611 #include "NativeKeyToDOMKeyName.h"
2613 #undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
2614 #undef NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
2615 #undef NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
2616 #undef NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
2618 default:
2619 return KEY_NAME_INDEX_Unidentified;
2620 }
2621 }
2623 nsresult
2624 KeyboardLayout::SynthesizeNativeKeyEvent(nsWindowBase* aWidget,
2625 int32_t aNativeKeyboardLayout,
2626 int32_t aNativeKeyCode,
2627 uint32_t aModifierFlags,
2628 const nsAString& aCharacters,
2629 const nsAString& aUnmodifiedCharacters)
2630 {
2631 UINT keyboardLayoutListCount = ::GetKeyboardLayoutList(0, nullptr);
2632 NS_ASSERTION(keyboardLayoutListCount > 0,
2633 "One keyboard layout must be installed at least");
2634 HKL keyboardLayoutListBuff[50];
2635 HKL* keyboardLayoutList =
2636 keyboardLayoutListCount < 50 ? keyboardLayoutListBuff :
2637 new HKL[keyboardLayoutListCount];
2638 keyboardLayoutListCount =
2639 ::GetKeyboardLayoutList(keyboardLayoutListCount, keyboardLayoutList);
2640 NS_ASSERTION(keyboardLayoutListCount > 0,
2641 "Failed to get all keyboard layouts installed on the system");
2643 nsPrintfCString layoutName("%08x", aNativeKeyboardLayout);
2644 HKL loadedLayout = LoadKeyboardLayoutA(layoutName.get(), KLF_NOTELLSHELL);
2645 if (loadedLayout == nullptr) {
2646 if (keyboardLayoutListBuff != keyboardLayoutList) {
2647 delete [] keyboardLayoutList;
2648 }
2649 return NS_ERROR_NOT_AVAILABLE;
2650 }
2652 // Setup clean key state and load desired layout
2653 BYTE originalKbdState[256];
2654 ::GetKeyboardState(originalKbdState);
2655 BYTE kbdState[256];
2656 memset(kbdState, 0, sizeof(kbdState));
2657 // This changes the state of the keyboard for the current thread only,
2658 // and we'll restore it soon, so this should be OK.
2659 ::SetKeyboardState(kbdState);
2661 OverrideLayout(loadedLayout);
2663 uint8_t argumentKeySpecific = 0;
2664 switch (aNativeKeyCode) {
2665 case VK_SHIFT:
2666 aModifierFlags &= ~(nsIWidget::SHIFT_L | nsIWidget::SHIFT_R);
2667 argumentKeySpecific = VK_LSHIFT;
2668 break;
2669 case VK_LSHIFT:
2670 aModifierFlags &= ~nsIWidget::SHIFT_L;
2671 argumentKeySpecific = aNativeKeyCode;
2672 aNativeKeyCode = VK_SHIFT;
2673 break;
2674 case VK_RSHIFT:
2675 aModifierFlags &= ~nsIWidget::SHIFT_R;
2676 argumentKeySpecific = aNativeKeyCode;
2677 aNativeKeyCode = VK_SHIFT;
2678 break;
2679 case VK_CONTROL:
2680 aModifierFlags &= ~(nsIWidget::CTRL_L | nsIWidget::CTRL_R);
2681 argumentKeySpecific = VK_LCONTROL;
2682 break;
2683 case VK_LCONTROL:
2684 aModifierFlags &= ~nsIWidget::CTRL_L;
2685 argumentKeySpecific = aNativeKeyCode;
2686 aNativeKeyCode = VK_CONTROL;
2687 break;
2688 case VK_RCONTROL:
2689 aModifierFlags &= ~nsIWidget::CTRL_R;
2690 argumentKeySpecific = aNativeKeyCode;
2691 aNativeKeyCode = VK_CONTROL;
2692 break;
2693 case VK_MENU:
2694 aModifierFlags &= ~(nsIWidget::ALT_L | nsIWidget::ALT_R);
2695 argumentKeySpecific = VK_LMENU;
2696 break;
2697 case VK_LMENU:
2698 aModifierFlags &= ~nsIWidget::ALT_L;
2699 argumentKeySpecific = aNativeKeyCode;
2700 aNativeKeyCode = VK_MENU;
2701 break;
2702 case VK_RMENU:
2703 aModifierFlags &= ~nsIWidget::ALT_R;
2704 argumentKeySpecific = aNativeKeyCode;
2705 aNativeKeyCode = VK_MENU;
2706 break;
2707 case VK_CAPITAL:
2708 aModifierFlags &= ~nsIWidget::CAPS_LOCK;
2709 argumentKeySpecific = VK_CAPITAL;
2710 break;
2711 case VK_NUMLOCK:
2712 aModifierFlags &= ~nsIWidget::NUM_LOCK;
2713 argumentKeySpecific = VK_NUMLOCK;
2714 break;
2715 }
2717 nsAutoTArray<KeyPair,10> keySequence;
2718 WinUtils::SetupKeyModifiersSequence(&keySequence, aModifierFlags);
2719 NS_ASSERTION(aNativeKeyCode >= 0 && aNativeKeyCode < 256,
2720 "Native VK key code out of range");
2721 keySequence.AppendElement(KeyPair(aNativeKeyCode, argumentKeySpecific));
2723 // Simulate the pressing of each modifier key and then the real key
2724 for (uint32_t i = 0; i < keySequence.Length(); ++i) {
2725 uint8_t key = keySequence[i].mGeneral;
2726 uint8_t keySpecific = keySequence[i].mSpecific;
2727 kbdState[key] = 0x81; // key is down and toggled on if appropriate
2728 if (keySpecific) {
2729 kbdState[keySpecific] = 0x81;
2730 }
2731 ::SetKeyboardState(kbdState);
2732 ModifierKeyState modKeyState;
2733 UINT scanCode =
2734 ComputeScanCodeForVirtualKeyCode(keySpecific ? keySpecific : key);
2735 LPARAM lParam = static_cast<LPARAM>(scanCode << 16);
2736 // Add extended key flag to the lParam for right control key and right alt
2737 // key.
2738 if (keySpecific == VK_RCONTROL || keySpecific == VK_RMENU) {
2739 lParam |= 0x1000000;
2740 }
2741 MSG keyDownMsg = WinUtils::InitMSG(WM_KEYDOWN, key, lParam,
2742 aWidget->GetWindowHandle());
2743 if (i == keySequence.Length() - 1) {
2744 bool makeDeadCharMsg =
2745 (IsDeadKey(key, modKeyState) && aCharacters.IsEmpty());
2746 nsAutoString chars(aCharacters);
2747 if (makeDeadCharMsg) {
2748 UniCharsAndModifiers deadChars =
2749 GetUniCharsAndModifiers(key, modKeyState);
2750 chars = deadChars.ToString();
2751 NS_ASSERTION(chars.Length() == 1,
2752 "Dead char must be only one character");
2753 }
2754 if (chars.IsEmpty()) {
2755 NativeKey nativeKey(aWidget, keyDownMsg, modKeyState);
2756 nativeKey.HandleKeyDownMessage();
2757 } else {
2758 nsAutoTArray<NativeKey::FakeCharMsg, 10> fakeCharMsgs;
2759 for (uint32_t j = 0; j < chars.Length(); j++) {
2760 NativeKey::FakeCharMsg* fakeCharMsg = fakeCharMsgs.AppendElement();
2761 fakeCharMsg->mCharCode = chars.CharAt(j);
2762 fakeCharMsg->mScanCode = scanCode;
2763 fakeCharMsg->mIsDeadKey = makeDeadCharMsg;
2764 }
2765 NativeKey nativeKey(aWidget, keyDownMsg, modKeyState, &fakeCharMsgs);
2766 bool dispatched;
2767 nativeKey.HandleKeyDownMessage(&dispatched);
2768 // If some char messages are not consumed, let's emulate the widget
2769 // receiving the message directly.
2770 for (uint32_t j = 1; j < fakeCharMsgs.Length(); j++) {
2771 if (fakeCharMsgs[j].mConsumed) {
2772 continue;
2773 }
2774 MSG charMsg = fakeCharMsgs[j].GetCharMsg(aWidget->GetWindowHandle());
2775 NativeKey nativeKey(aWidget, charMsg, modKeyState);
2776 nativeKey.HandleCharMessage(charMsg);
2777 }
2778 }
2779 } else {
2780 NativeKey nativeKey(aWidget, keyDownMsg, modKeyState);
2781 nativeKey.HandleKeyDownMessage();
2782 }
2783 }
2784 for (uint32_t i = keySequence.Length(); i > 0; --i) {
2785 uint8_t key = keySequence[i - 1].mGeneral;
2786 uint8_t keySpecific = keySequence[i - 1].mSpecific;
2787 kbdState[key] = 0; // key is up and toggled off if appropriate
2788 if (keySpecific) {
2789 kbdState[keySpecific] = 0;
2790 }
2791 ::SetKeyboardState(kbdState);
2792 ModifierKeyState modKeyState;
2793 UINT scanCode =
2794 ComputeScanCodeForVirtualKeyCode(keySpecific ? keySpecific : key);
2795 LPARAM lParam = static_cast<LPARAM>(scanCode << 16);
2796 // Add extended key flag to the lParam for right control key and right alt
2797 // key.
2798 if (keySpecific == VK_RCONTROL || keySpecific == VK_RMENU) {
2799 lParam |= 0x1000000;
2800 }
2801 MSG keyUpMsg = WinUtils::InitMSG(WM_KEYUP, key, lParam,
2802 aWidget->GetWindowHandle());
2803 NativeKey nativeKey(aWidget, keyUpMsg, modKeyState);
2804 nativeKey.HandleKeyUpMessage();
2805 }
2807 // Restore old key state and layout
2808 ::SetKeyboardState(originalKbdState);
2809 RestoreLayout();
2811 // Don't unload the layout if it's installed actually.
2812 for (uint32_t i = 0; i < keyboardLayoutListCount; i++) {
2813 if (keyboardLayoutList[i] == loadedLayout) {
2814 loadedLayout = 0;
2815 break;
2816 }
2817 }
2818 if (keyboardLayoutListBuff != keyboardLayoutList) {
2819 delete [] keyboardLayoutList;
2820 }
2821 if (loadedLayout) {
2822 ::UnloadKeyboardLayout(loadedLayout);
2823 }
2824 return NS_OK;
2825 }
2827 /*****************************************************************************
2828 * mozilla::widget::DeadKeyTable
2829 *****************************************************************************/
2831 char16_t
2832 DeadKeyTable::GetCompositeChar(char16_t aBaseChar) const
2833 {
2834 // Dead-key table is sorted by BaseChar in ascending order.
2835 // Usually they are too small to use binary search.
2837 for (uint32_t index = 0; index < mEntries; index++) {
2838 if (mTable[index].BaseChar == aBaseChar) {
2839 return mTable[index].CompositeChar;
2840 }
2841 if (mTable[index].BaseChar > aBaseChar) {
2842 break;
2843 }
2844 }
2846 return 0;
2847 }
2849 /*****************************************************************************
2850 * mozilla::widget::RedirectedKeyDownMessage
2851 *****************************************************************************/
2853 MSG RedirectedKeyDownMessageManager::sRedirectedKeyDownMsg;
2854 bool RedirectedKeyDownMessageManager::sDefaultPreventedOfRedirectedMsg = false;
2856 // static
2857 bool
2858 RedirectedKeyDownMessageManager::IsRedirectedMessage(const MSG& aMsg)
2859 {
2860 return (aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN) &&
2861 (sRedirectedKeyDownMsg.message == aMsg.message &&
2862 WinUtils::GetScanCode(sRedirectedKeyDownMsg.lParam) ==
2863 WinUtils::GetScanCode(aMsg.lParam));
2864 }
2866 // static
2867 void
2868 RedirectedKeyDownMessageManager::RemoveNextCharMessage(HWND aWnd)
2869 {
2870 MSG msg;
2871 if (WinUtils::PeekMessage(&msg, aWnd, WM_KEYFIRST, WM_KEYLAST,
2872 PM_NOREMOVE | PM_NOYIELD) &&
2873 (msg.message == WM_CHAR || msg.message == WM_SYSCHAR)) {
2874 WinUtils::PeekMessage(&msg, aWnd, msg.message, msg.message,
2875 PM_REMOVE | PM_NOYIELD);
2876 }
2877 }
2879 } // namespace widget
2880 } // namespace mozilla