Backed out changeset 8517afe50156 (bug 540456) for reftest failures.
[gecko.git] / widget / windows / KeyboardLayout.h
blob6543a3ffaa29c463885ef1fbc3e4ea14b8c3c1a4
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef KeyboardLayout_h__
7 #define KeyboardLayout_h__
9 #include "nscore.h"
10 #include "nsAutoPtr.h"
11 #include "nsString.h"
12 #include "nsWindowBase.h"
13 #include "nsWindowDefs.h"
14 #include "mozilla/EventForwards.h"
15 #include <windows.h>
17 #define NS_NUM_OF_KEYS 70
19 #define VK_OEM_1 0xBA // ';:' for US
20 #define VK_OEM_PLUS 0xBB // '+' any country
21 #define VK_OEM_COMMA 0xBC
22 #define VK_OEM_MINUS 0xBD // '-' any country
23 #define VK_OEM_PERIOD 0xBE
24 #define VK_OEM_2 0xBF
25 #define VK_OEM_3 0xC0
26 // '/?' for Brazilian (ABNT)
27 #define VK_ABNT_C1 0xC1
28 // Separator in Numpad for Brazilian (ABNT) or JIS keyboard for Mac.
29 #define VK_ABNT_C2 0xC2
30 #define VK_OEM_4 0xDB
31 #define VK_OEM_5 0xDC
32 #define VK_OEM_6 0xDD
33 #define VK_OEM_7 0xDE
34 #define VK_OEM_8 0xDF
35 #define VK_OEM_102 0xE2
36 #define VK_OEM_CLEAR 0xFE
38 class nsIIdleServiceInternal;
39 struct nsModifierKeyState;
41 namespace mozilla {
42 namespace widget {
44 static const uint32_t sModifierKeyMap[][3] = {
45 { nsIWidget::CAPS_LOCK, VK_CAPITAL, 0 },
46 { nsIWidget::NUM_LOCK, VK_NUMLOCK, 0 },
47 { nsIWidget::SHIFT_L, VK_SHIFT, VK_LSHIFT },
48 { nsIWidget::SHIFT_R, VK_SHIFT, VK_RSHIFT },
49 { nsIWidget::CTRL_L, VK_CONTROL, VK_LCONTROL },
50 { nsIWidget::CTRL_R, VK_CONTROL, VK_RCONTROL },
51 { nsIWidget::ALT_L, VK_MENU, VK_LMENU },
52 { nsIWidget::ALT_R, VK_MENU, VK_RMENU }
55 class KeyboardLayout;
57 class ModifierKeyState {
58 public:
59 ModifierKeyState()
61 Update();
64 ModifierKeyState(bool aIsShiftDown, bool aIsControlDown, bool aIsAltDown)
66 Update();
67 Unset(MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT | MODIFIER_ALTGRAPH);
68 Modifiers modifiers = 0;
69 if (aIsShiftDown) {
70 modifiers |= MODIFIER_SHIFT;
72 if (aIsControlDown) {
73 modifiers |= MODIFIER_CONTROL;
75 if (aIsAltDown) {
76 modifiers |= MODIFIER_ALT;
78 if (modifiers) {
79 Set(modifiers);
83 ModifierKeyState(Modifiers aModifiers) :
84 mModifiers(aModifiers)
86 EnsureAltGr();
89 void Update();
91 void Unset(Modifiers aRemovingModifiers)
93 mModifiers &= ~aRemovingModifiers;
94 // Note that we don't need to unset AltGr flag here automatically.
95 // For nsEditor, we need to remove Alt and Control flags but AltGr isn't
96 // checked in nsEditor, so, it can be kept.
99 void Set(Modifiers aAddingModifiers)
101 mModifiers |= aAddingModifiers;
102 EnsureAltGr();
105 void InitInputEvent(WidgetInputEvent& aInputEvent) const;
107 bool IsShift() const { return (mModifiers & MODIFIER_SHIFT) != 0; }
108 bool IsControl() const { return (mModifiers & MODIFIER_CONTROL) != 0; }
109 bool IsAlt() const { return (mModifiers & MODIFIER_ALT) != 0; }
110 bool IsAltGr() const { return IsControl() && IsAlt(); }
111 bool IsWin() const { return (mModifiers & MODIFIER_OS) != 0; }
113 bool IsCapsLocked() const { return (mModifiers & MODIFIER_CAPSLOCK) != 0; }
114 bool IsNumLocked() const { return (mModifiers & MODIFIER_NUMLOCK) != 0; }
115 bool IsScrollLocked() const
117 return (mModifiers & MODIFIER_SCROLLLOCK) != 0;
120 Modifiers GetModifiers() const { return mModifiers; }
122 private:
123 Modifiers mModifiers;
125 void EnsureAltGr()
127 // If both Control key and Alt key are pressed, it means AltGr is pressed.
128 // Ideally, we should check whether the current keyboard layout has AltGr
129 // or not. However, setting AltGr flags for keyboard which doesn't have
130 // AltGr must not be serious bug. So, it should be OK for now.
131 if (IsAltGr()) {
132 mModifiers |= MODIFIER_ALTGRAPH;
136 void InitMouseEvent(WidgetInputEvent& aMouseEvent) const;
139 struct UniCharsAndModifiers
141 // Dead-key + up to 4 characters
142 PRUnichar mChars[5];
143 Modifiers mModifiers[5];
144 uint32_t mLength;
146 UniCharsAndModifiers() : mLength(0) {}
147 UniCharsAndModifiers operator+(const UniCharsAndModifiers& aOther) const;
148 UniCharsAndModifiers& operator+=(const UniCharsAndModifiers& aOther);
151 * Append a pair of unicode character and the final modifier.
153 void Append(PRUnichar aUniChar, Modifiers aModifiers);
154 void Clear() { mLength = 0; }
155 bool IsEmpty() const { return !mLength; }
157 void FillModifiers(Modifiers aModifiers);
159 bool UniCharsEqual(const UniCharsAndModifiers& aOther) const;
160 bool UniCharsCaseInsensitiveEqual(const UniCharsAndModifiers& aOther) const;
162 nsString ToString() const { return nsString(mChars, mLength); }
165 struct DeadKeyEntry;
166 class DeadKeyTable;
169 class VirtualKey
171 public:
172 // 0 - Normal
173 // 1 - Shift
174 // 2 - Control
175 // 3 - Control + Shift
176 // 4 - Alt
177 // 5 - Alt + Shift
178 // 6 - Alt + Control (AltGr)
179 // 7 - Alt + Control + Shift (AltGr + Shift)
180 // 8 - CapsLock
181 // 9 - CapsLock + Shift
182 // 10 - CapsLock + Control
183 // 11 - CapsLock + Control + Shift
184 // 12 - CapsLock + Alt
185 // 13 - CapsLock + Alt + Shift
186 // 14 - CapsLock + Alt + Control (CapsLock + AltGr)
187 // 15 - CapsLock + Alt + Control + Shift (CapsLock + AltGr + Shift)
189 enum ShiftStateFlag
191 STATE_SHIFT = 0x01,
192 STATE_CONTROL = 0x02,
193 STATE_ALT = 0x04,
194 STATE_CAPSLOCK = 0x08
197 typedef uint8_t ShiftState;
199 static ShiftState ModifiersToShiftState(Modifiers aModifiers)
201 ShiftState state = 0;
202 if (aModifiers & MODIFIER_SHIFT) {
203 state |= STATE_SHIFT;
205 if (aModifiers & MODIFIER_CONTROL) {
206 state |= STATE_CONTROL;
208 if (aModifiers & MODIFIER_ALT) {
209 state |= STATE_ALT;
211 if (aModifiers & MODIFIER_CAPSLOCK) {
212 state |= STATE_CAPSLOCK;
214 return state;
217 static Modifiers ShiftStateToModifiers(ShiftState aShiftState)
219 Modifiers modifiers = 0;
220 if (aShiftState & STATE_SHIFT) {
221 modifiers |= MODIFIER_SHIFT;
223 if (aShiftState & STATE_CONTROL) {
224 modifiers |= MODIFIER_CONTROL;
226 if (aShiftState & STATE_ALT) {
227 modifiers |= MODIFIER_ALT;
229 if (aShiftState & STATE_CAPSLOCK) {
230 modifiers |= MODIFIER_CAPSLOCK;
232 if ((modifiers & (MODIFIER_ALT | MODIFIER_CONTROL)) ==
233 (MODIFIER_ALT | MODIFIER_CONTROL)) {
234 modifiers |= MODIFIER_ALTGRAPH;
236 return modifiers;
239 private:
240 union KeyShiftState
242 struct
244 PRUnichar Chars[4];
245 } Normal;
246 struct
248 const DeadKeyTable* Table;
249 PRUnichar DeadChar;
250 } DeadKey;
253 KeyShiftState mShiftStates[16];
254 uint16_t mIsDeadKey;
256 void SetDeadKey(ShiftState aShiftState, bool aIsDeadKey)
258 if (aIsDeadKey) {
259 mIsDeadKey |= 1 << aShiftState;
260 } else {
261 mIsDeadKey &= ~(1 << aShiftState);
265 public:
266 static void FillKbdState(PBYTE aKbdState, const ShiftState aShiftState);
268 bool IsDeadKey(ShiftState aShiftState) const
270 return (mIsDeadKey & (1 << aShiftState)) != 0;
273 void AttachDeadKeyTable(ShiftState aShiftState,
274 const DeadKeyTable* aDeadKeyTable)
276 mShiftStates[aShiftState].DeadKey.Table = aDeadKeyTable;
279 void SetNormalChars(ShiftState aShiftState, const PRUnichar* aChars,
280 uint32_t aNumOfChars);
281 void SetDeadChar(ShiftState aShiftState, PRUnichar aDeadChar);
282 const DeadKeyTable* MatchingDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
283 uint32_t aEntries) const;
284 inline PRUnichar GetCompositeChar(ShiftState aShiftState,
285 PRUnichar aBaseChar) const;
286 UniCharsAndModifiers GetNativeUniChars(ShiftState aShiftState) const;
287 UniCharsAndModifiers GetUniChars(ShiftState aShiftState) const;
290 class MOZ_STACK_CLASS NativeKey
292 friend class KeyboardLayout;
294 public:
295 struct FakeCharMsg
297 UINT mCharCode;
298 UINT mScanCode;
299 bool mIsDeadKey;
300 bool mConsumed;
302 FakeCharMsg() :
303 mCharCode(0), mScanCode(0), mIsDeadKey(false), mConsumed(false)
307 MSG GetCharMsg(HWND aWnd) const
309 MSG msg;
310 msg.hwnd = aWnd;
311 msg.message = mIsDeadKey ? WM_DEADCHAR : WM_CHAR;
312 msg.wParam = static_cast<WPARAM>(mCharCode);
313 msg.lParam = static_cast<LPARAM>(mScanCode << 16);
314 msg.time = 0;
315 msg.pt.x = msg.pt.y = 0;
316 return msg;
320 NativeKey(nsWindowBase* aWidget,
321 const MSG& aKeyOrCharMessage,
322 const ModifierKeyState& aModKeyState,
323 nsTArray<FakeCharMsg>* aFakeCharMsgs = nullptr);
326 * Handle WM_KEYDOWN message or WM_SYSKEYDOWN message. The instance must be
327 * initialized with WM_KEYDOWN or WM_SYSKEYDOWN.
328 * Returns true if dispatched keydown event or keypress event is consumed.
329 * Otherwise, false.
331 bool HandleKeyDownMessage(bool* aEventDispatched = nullptr) const;
334 * Handles WM_CHAR message or WM_SYSCHAR message. The instance must be
335 * initialized with WM_KEYDOWN, WM_SYSKEYDOWN or them.
336 * Returns true if dispatched keypress event is consumed. Otherwise, false.
338 bool HandleCharMessage(const MSG& aCharMsg,
339 bool* aEventDispatched = nullptr) const;
342 * Handles keyup message. Returns true if the event is consumed.
343 * Otherwise, false.
345 bool HandleKeyUpMessage(bool* aEventDispatched = nullptr) const;
347 private:
348 nsRefPtr<nsWindowBase> mWidget;
349 HKL mKeyboardLayout;
350 MSG mMsg;
352 uint32_t mDOMKeyCode;
353 KeyNameIndex mKeyNameIndex;
355 ModifierKeyState mModKeyState;
357 // mVirtualKeyCode distinguishes left key or right key of modifier key.
358 uint8_t mVirtualKeyCode;
359 // mOriginalVirtualKeyCode doesn't distinguish left key or right key of
360 // modifier key. However, if the given keycode is VK_PROCESS, it's resolved
361 // to a keycode before it's handled by IME.
362 uint8_t mOriginalVirtualKeyCode;
364 // mCommittedChars indicates the inputted characters which is committed by
365 // the key. If dead key fail to composite a character, mCommittedChars
366 // indicates both the dead characters and the base characters.
367 UniCharsAndModifiers mCommittedCharsAndModifiers;
369 WORD mScanCode;
370 bool mIsExtended;
371 bool mIsDeadKey;
372 // mIsPrintableKey is true if the key may be a printable key without
373 // any modifier keys. Otherwise, false.
374 // Please note that the event may not cause any text input even if this
375 // is true. E.g., it might be dead key state or Ctrl key may be pressed.
376 bool mIsPrintableKey;
378 nsTArray<FakeCharMsg>* mFakeCharMsgs;
380 NativeKey()
382 MOZ_CRASH("The default constructor of NativeKey isn't available");
385 UINT GetScanCodeWithExtendedFlag() const;
387 // The result is one of nsIDOMKeyEvent::DOM_KEY_LOCATION_*.
388 uint32_t GetKeyLocation() const;
391 * "Kakutei-Undo" of ATOK or WXG (both of them are Japanese IME) causes
392 * strange WM_KEYDOWN/WM_KEYUP/WM_CHAR message pattern. So, when this
393 * returns true, the caller needs to be careful for processing the messages.
395 bool IsIMEDoingKakuteiUndo() const;
398 * Dispatches a plugin event after the specified message is removed.
399 * Returns true if the widget is destoyed. Otherwise, false.
401 bool RemoveMessageAndDispatchPluginEvent(UINT aFirstMsg, UINT aLastMsg) const;
403 bool IsKeyDownMessage() const
405 return (mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN);
407 bool IsFollowedByCharMessage() const;
408 bool IsFollowedByDeadCharMessage() const;
409 MSG RemoveFollowingCharMessage() const;
412 * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK.
414 uint8_t ComputeVirtualKeyCodeFromScanCode() const;
417 * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK_EX.
419 uint8_t ComputeVirtualKeyCodeFromScanCodeEx() const;
422 * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK and MAPVK_VK_TO_CHAR.
424 PRUnichar ComputeUnicharFromScanCode() const;
427 * Initializes the aKeyEvent with the information stored in the instance.
429 void InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
430 const ModifierKeyState& aModKeyState) const;
431 void InitKeyEvent(WidgetKeyboardEvent& aKeyEvent) const
433 InitKeyEvent(aKeyEvent, mModKeyState);
437 * Dispatches the key event. Returns true if the event is consumed.
438 * Otherwise, false.
440 bool DispatchKeyEvent(WidgetKeyboardEvent& aKeyEvent,
441 const MSG* aMsgSentToPlugin = nullptr) const;
444 * DispatchKeyPressEventsWithKeyboardLayout() dispatches keypress event(s)
445 * with the information provided by KeyboardLayout class.
447 bool DispatchKeyPressEventsWithKeyboardLayout() const;
450 * Remove all following WM_CHAR, WM_SYSCHAR and WM_DEADCHAR messages for the
451 * WM_KEYDOWN or WM_SYSKEYDOWN message. Additionally, dispatches plugin
452 * events if it's necessary.
453 * Returns true if the widget is destroyed. Otherwise, false.
455 bool DispatchPluginEventsAndDiscardsCharMessages() const;
458 * DispatchKeyPressEventForFollowingCharMessage() dispatches keypress event
459 * for following WM_*CHAR message.
460 * Returns true if the event is consumed. Otherwise, false.
462 bool DispatchKeyPressEventForFollowingCharMessage() const;
465 * Checkes whether the key event down message is handled without following
466 * WM_CHAR messages. For example, if following WM_CHAR message indicates
467 * control character input, the WM_CHAR message is unclear whether it's
468 * caused by a printable key with Ctrl or just a function key such as Enter
469 * or Backspace.
471 bool NeedsToHandleWithoutFollowingCharMessages() const;
474 class KeyboardLayout
476 friend class NativeKey;
478 private:
479 KeyboardLayout();
480 ~KeyboardLayout();
482 static KeyboardLayout* sInstance;
483 static nsIIdleServiceInternal* sIdleService;
485 struct DeadKeyTableListEntry
487 DeadKeyTableListEntry* next;
488 uint8_t data[1];
491 HKL mKeyboardLayout;
493 VirtualKey mVirtualKeys[NS_NUM_OF_KEYS];
494 DeadKeyTableListEntry* mDeadKeyTableListHead;
495 int32_t mActiveDeadKey; // -1 = no active dead-key
496 VirtualKey::ShiftState mDeadKeyShiftState;
498 bool mIsOverridden : 1;
499 bool mIsPendingToRestoreKeyboardLayout : 1;
501 static inline int32_t GetKeyIndex(uint8_t aVirtualKey);
502 static int CompareDeadKeyEntries(const void* aArg1, const void* aArg2,
503 void* aData);
504 static bool AddDeadKeyEntry(PRUnichar aBaseChar, PRUnichar aCompositeChar,
505 DeadKeyEntry* aDeadKeyArray, uint32_t aEntries);
506 bool EnsureDeadKeyActive(bool aIsActive, uint8_t aDeadKey,
507 const PBYTE aDeadKeyKbdState);
508 uint32_t GetDeadKeyCombinations(uint8_t aDeadKey,
509 const PBYTE aDeadKeyKbdState,
510 uint16_t aShiftStatesWithBaseChars,
511 DeadKeyEntry* aDeadKeyArray,
512 uint32_t aMaxEntries);
513 void DeactivateDeadKeyState();
514 const DeadKeyTable* AddDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
515 uint32_t aEntries);
516 void ReleaseDeadKeyTables();
519 * Loads the specified keyboard layout. This method always clear the dead key
520 * state.
522 void LoadLayout(HKL aLayout);
525 * InitNativeKey() must be called when actually widget receives WM_KEYDOWN or
526 * WM_KEYUP. This method is stateful. This saves current dead key state at
527 * WM_KEYDOWN. Additionally, computes current inputted character(s) and set
528 * them to the aNativeKey.
530 void InitNativeKey(NativeKey& aNativeKey,
531 const ModifierKeyState& aModKeyState);
533 public:
534 static KeyboardLayout* GetInstance();
535 static void Shutdown();
536 static void NotifyIdleServiceOfUserActivity();
538 static bool IsPrintableCharKey(uint8_t aVirtualKey);
541 * IsDeadKey() returns true if aVirtualKey is a dead key with aModKeyState.
542 * This method isn't stateful.
544 bool IsDeadKey(uint8_t aVirtualKey,
545 const ModifierKeyState& aModKeyState) const;
548 * GetUniCharsAndModifiers() returns characters which is inputted by the
549 * aVirtualKey with aModKeyState. This method isn't stateful.
551 UniCharsAndModifiers GetUniCharsAndModifiers(
552 uint8_t aVirtualKey,
553 const ModifierKeyState& aModKeyState) const;
556 * OnLayoutChange() must be called before the first keydown message is
557 * received. LoadLayout() changes the keyboard state, that causes breaking
558 * dead key state. Therefore, we need to load the layout before the first
559 * keydown message.
561 void OnLayoutChange(HKL aKeyboardLayout)
563 MOZ_ASSERT(!mIsOverridden);
564 LoadLayout(aKeyboardLayout);
568 * OverrideLayout() loads the specified keyboard layout.
570 void OverrideLayout(HKL aLayout)
572 mIsOverridden = true;
573 LoadLayout(aLayout);
577 * RestoreLayout() loads the current keyboard layout of the thread.
579 void RestoreLayout()
581 mIsOverridden = false;
582 mIsPendingToRestoreKeyboardLayout = true;
585 uint32_t ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const;
588 * ConvertNativeKeyCodeToKeyNameIndex() returns KeyNameIndex value for
589 * non-printable keys (except some special keys like space key).
591 KeyNameIndex ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const;
593 HKL GetLayout() const
595 return mIsPendingToRestoreKeyboardLayout ? ::GetKeyboardLayout(0) :
596 mKeyboardLayout;
600 * This wraps MapVirtualKeyEx() API with MAPVK_VK_TO_VSC.
602 WORD ComputeScanCodeForVirtualKeyCode(uint8_t aVirtualKeyCode) const;
605 * Implementation of nsIWidget::SynthesizeNativeKeyEvent().
607 nsresult SynthesizeNativeKeyEvent(nsWindowBase* aWidget,
608 int32_t aNativeKeyboardLayout,
609 int32_t aNativeKeyCode,
610 uint32_t aModifierFlags,
611 const nsAString& aCharacters,
612 const nsAString& aUnmodifiedCharacters);
615 class RedirectedKeyDownMessageManager
617 public:
619 * If a window receives WM_KEYDOWN message or WM_SYSKEYDOWM message which is
620 * a redirected message, NativeKey::DispatchKeyDownAndKeyPressEvent()
621 * prevents to dispatch NS_KEY_DOWN event because it has been dispatched
622 * before the message was redirected. However, in some cases, WM_*KEYDOWN
623 * message handler may not handle actually. Then, the message handler needs
624 * to forget the redirected message and remove WM_CHAR message or WM_SYSCHAR
625 * message for the redirected keydown message. AutoFlusher class is a helper
626 * class for doing it. This must be created in the stack.
628 class MOZ_STACK_CLASS AutoFlusher MOZ_FINAL
630 public:
631 AutoFlusher(nsWindowBase* aWidget, const MSG &aMsg) :
632 mCancel(!RedirectedKeyDownMessageManager::IsRedirectedMessage(aMsg)),
633 mWidget(aWidget), mMsg(aMsg)
637 ~AutoFlusher()
639 if (mCancel) {
640 return;
642 // Prevent unnecessary keypress event
643 if (!mWidget->Destroyed()) {
644 RedirectedKeyDownMessageManager::RemoveNextCharMessage(mMsg.hwnd);
646 // Foreget the redirected message
647 RedirectedKeyDownMessageManager::Forget();
650 void Cancel() { mCancel = true; }
652 private:
653 bool mCancel;
654 nsRefPtr<nsWindowBase> mWidget;
655 const MSG &mMsg;
658 static void WillRedirect(const MSG& aMsg, bool aDefualtPrevented)
660 sRedirectedKeyDownMsg = aMsg;
661 sDefaultPreventedOfRedirectedMsg = aDefualtPrevented;
664 static void Forget()
666 sRedirectedKeyDownMsg.message = WM_NULL;
669 static void PreventDefault() { sDefaultPreventedOfRedirectedMsg = true; }
670 static bool DefaultPrevented() { return sDefaultPreventedOfRedirectedMsg; }
672 static bool IsRedirectedMessage(const MSG& aMsg);
675 * RemoveNextCharMessage() should be called by WM_KEYDOWN or WM_SYSKEYDOWM
676 * message handler. If there is no WM_(SYS)CHAR message for it, this
677 * method does nothing.
678 * NOTE: WM_(SYS)CHAR message is posted by TranslateMessage() API which is
679 * called in message loop. So, WM_(SYS)KEYDOWN message should have
680 * WM_(SYS)CHAR message in the queue if the keydown event causes character
681 * input.
683 static void RemoveNextCharMessage(HWND aWnd);
685 private:
686 // sRedirectedKeyDownMsg is WM_KEYDOWN message or WM_SYSKEYDOWN message which
687 // is reirected with SendInput() API by
688 // widget::NativeKey::DispatchKeyDownAndKeyPressEvent()
689 static MSG sRedirectedKeyDownMsg;
690 static bool sDefaultPreventedOfRedirectedMsg;
693 } // namespace widget
694 } // namespace mozilla
696 #endif