1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/windows/KeyboardLayout.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,666 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef KeyboardLayout_h__ 1.10 +#define KeyboardLayout_h__ 1.11 + 1.12 +#include "nscore.h" 1.13 +#include "nsAutoPtr.h" 1.14 +#include "nsString.h" 1.15 +#include "nsWindowBase.h" 1.16 +#include "nsWindowDefs.h" 1.17 +#include "mozilla/Attributes.h" 1.18 +#include "mozilla/EventForwards.h" 1.19 +#include <windows.h> 1.20 + 1.21 +#define NS_NUM_OF_KEYS 70 1.22 + 1.23 +#define VK_OEM_1 0xBA // ';:' for US 1.24 +#define VK_OEM_PLUS 0xBB // '+' any country 1.25 +#define VK_OEM_COMMA 0xBC 1.26 +#define VK_OEM_MINUS 0xBD // '-' any country 1.27 +#define VK_OEM_PERIOD 0xBE 1.28 +#define VK_OEM_2 0xBF 1.29 +#define VK_OEM_3 0xC0 1.30 +// '/?' for Brazilian (ABNT) 1.31 +#define VK_ABNT_C1 0xC1 1.32 +// Separator in Numpad for Brazilian (ABNT) or JIS keyboard for Mac. 1.33 +#define VK_ABNT_C2 0xC2 1.34 +#define VK_OEM_4 0xDB 1.35 +#define VK_OEM_5 0xDC 1.36 +#define VK_OEM_6 0xDD 1.37 +#define VK_OEM_7 0xDE 1.38 +#define VK_OEM_8 0xDF 1.39 +#define VK_OEM_102 0xE2 1.40 +#define VK_OEM_CLEAR 0xFE 1.41 + 1.42 +class nsIIdleServiceInternal; 1.43 +struct nsModifierKeyState; 1.44 + 1.45 +namespace mozilla { 1.46 +namespace widget { 1.47 + 1.48 +static const uint32_t sModifierKeyMap[][3] = { 1.49 + { nsIWidget::CAPS_LOCK, VK_CAPITAL, 0 }, 1.50 + { nsIWidget::NUM_LOCK, VK_NUMLOCK, 0 }, 1.51 + { nsIWidget::SHIFT_L, VK_SHIFT, VK_LSHIFT }, 1.52 + { nsIWidget::SHIFT_R, VK_SHIFT, VK_RSHIFT }, 1.53 + { nsIWidget::CTRL_L, VK_CONTROL, VK_LCONTROL }, 1.54 + { nsIWidget::CTRL_R, VK_CONTROL, VK_RCONTROL }, 1.55 + { nsIWidget::ALT_L, VK_MENU, VK_LMENU }, 1.56 + { nsIWidget::ALT_R, VK_MENU, VK_RMENU } 1.57 +}; 1.58 + 1.59 +class KeyboardLayout; 1.60 + 1.61 +class ModifierKeyState 1.62 +{ 1.63 +public: 1.64 + ModifierKeyState(); 1.65 + ModifierKeyState(bool aIsShiftDown, bool aIsControlDown, bool aIsAltDown); 1.66 + ModifierKeyState(Modifiers aModifiers); 1.67 + 1.68 + MOZ_ALWAYS_INLINE void Update(); 1.69 + 1.70 + MOZ_ALWAYS_INLINE void Unset(Modifiers aRemovingModifiers); 1.71 + void Set(Modifiers aAddingModifiers); 1.72 + 1.73 + void InitInputEvent(WidgetInputEvent& aInputEvent) const; 1.74 + 1.75 + bool IsShift() const; 1.76 + bool IsControl() const; 1.77 + MOZ_ALWAYS_INLINE bool IsAlt() const; 1.78 + MOZ_ALWAYS_INLINE bool IsAltGr() const; 1.79 + MOZ_ALWAYS_INLINE bool IsWin() const; 1.80 + 1.81 + MOZ_ALWAYS_INLINE bool IsCapsLocked() const; 1.82 + MOZ_ALWAYS_INLINE bool IsNumLocked() const; 1.83 + MOZ_ALWAYS_INLINE bool IsScrollLocked() const; 1.84 + 1.85 + MOZ_ALWAYS_INLINE Modifiers GetModifiers() const; 1.86 + 1.87 +private: 1.88 + Modifiers mModifiers; 1.89 + 1.90 + MOZ_ALWAYS_INLINE void EnsureAltGr(); 1.91 + 1.92 + void InitMouseEvent(WidgetInputEvent& aMouseEvent) const; 1.93 +}; 1.94 + 1.95 +struct UniCharsAndModifiers 1.96 +{ 1.97 + // Dead-key + up to 4 characters 1.98 + char16_t mChars[5]; 1.99 + Modifiers mModifiers[5]; 1.100 + uint32_t mLength; 1.101 + 1.102 + UniCharsAndModifiers() : mLength(0) {} 1.103 + UniCharsAndModifiers operator+(const UniCharsAndModifiers& aOther) const; 1.104 + UniCharsAndModifiers& operator+=(const UniCharsAndModifiers& aOther); 1.105 + 1.106 + /** 1.107 + * Append a pair of unicode character and the final modifier. 1.108 + */ 1.109 + void Append(char16_t aUniChar, Modifiers aModifiers); 1.110 + void Clear() { mLength = 0; } 1.111 + bool IsEmpty() const { return !mLength; } 1.112 + 1.113 + void FillModifiers(Modifiers aModifiers); 1.114 + 1.115 + bool UniCharsEqual(const UniCharsAndModifiers& aOther) const; 1.116 + bool UniCharsCaseInsensitiveEqual(const UniCharsAndModifiers& aOther) const; 1.117 + 1.118 + nsString ToString() const { return nsString(mChars, mLength); } 1.119 +}; 1.120 + 1.121 +struct DeadKeyEntry; 1.122 +class DeadKeyTable; 1.123 + 1.124 + 1.125 +class VirtualKey 1.126 +{ 1.127 +public: 1.128 + // 0 - Normal 1.129 + // 1 - Shift 1.130 + // 2 - Control 1.131 + // 3 - Control + Shift 1.132 + // 4 - Alt 1.133 + // 5 - Alt + Shift 1.134 + // 6 - Alt + Control (AltGr) 1.135 + // 7 - Alt + Control + Shift (AltGr + Shift) 1.136 + // 8 - CapsLock 1.137 + // 9 - CapsLock + Shift 1.138 + // 10 - CapsLock + Control 1.139 + // 11 - CapsLock + Control + Shift 1.140 + // 12 - CapsLock + Alt 1.141 + // 13 - CapsLock + Alt + Shift 1.142 + // 14 - CapsLock + Alt + Control (CapsLock + AltGr) 1.143 + // 15 - CapsLock + Alt + Control + Shift (CapsLock + AltGr + Shift) 1.144 + 1.145 + enum ShiftStateFlag 1.146 + { 1.147 + STATE_SHIFT = 0x01, 1.148 + STATE_CONTROL = 0x02, 1.149 + STATE_ALT = 0x04, 1.150 + STATE_CAPSLOCK = 0x08 1.151 + }; 1.152 + 1.153 + typedef uint8_t ShiftState; 1.154 + 1.155 + static ShiftState ModifiersToShiftState(Modifiers aModifiers); 1.156 + static Modifiers ShiftStateToModifiers(ShiftState aShiftState); 1.157 + 1.158 +private: 1.159 + union KeyShiftState 1.160 + { 1.161 + struct 1.162 + { 1.163 + char16_t Chars[4]; 1.164 + } Normal; 1.165 + struct 1.166 + { 1.167 + const DeadKeyTable* Table; 1.168 + char16_t DeadChar; 1.169 + } DeadKey; 1.170 + }; 1.171 + 1.172 + KeyShiftState mShiftStates[16]; 1.173 + uint16_t mIsDeadKey; 1.174 + 1.175 + void SetDeadKey(ShiftState aShiftState, bool aIsDeadKey) 1.176 + { 1.177 + if (aIsDeadKey) { 1.178 + mIsDeadKey |= 1 << aShiftState; 1.179 + } else { 1.180 + mIsDeadKey &= ~(1 << aShiftState); 1.181 + } 1.182 + } 1.183 + 1.184 +public: 1.185 + static void FillKbdState(PBYTE aKbdState, const ShiftState aShiftState); 1.186 + 1.187 + bool IsDeadKey(ShiftState aShiftState) const 1.188 + { 1.189 + return (mIsDeadKey & (1 << aShiftState)) != 0; 1.190 + } 1.191 + 1.192 + void AttachDeadKeyTable(ShiftState aShiftState, 1.193 + const DeadKeyTable* aDeadKeyTable) 1.194 + { 1.195 + mShiftStates[aShiftState].DeadKey.Table = aDeadKeyTable; 1.196 + } 1.197 + 1.198 + void SetNormalChars(ShiftState aShiftState, const char16_t* aChars, 1.199 + uint32_t aNumOfChars); 1.200 + void SetDeadChar(ShiftState aShiftState, char16_t aDeadChar); 1.201 + const DeadKeyTable* MatchingDeadKeyTable(const DeadKeyEntry* aDeadKeyArray, 1.202 + uint32_t aEntries) const; 1.203 + inline char16_t GetCompositeChar(ShiftState aShiftState, 1.204 + char16_t aBaseChar) const; 1.205 + UniCharsAndModifiers GetNativeUniChars(ShiftState aShiftState) const; 1.206 + UniCharsAndModifiers GetUniChars(ShiftState aShiftState) const; 1.207 +}; 1.208 + 1.209 +class MOZ_STACK_CLASS NativeKey 1.210 +{ 1.211 + friend class KeyboardLayout; 1.212 + 1.213 +public: 1.214 + struct FakeCharMsg 1.215 + { 1.216 + UINT mCharCode; 1.217 + UINT mScanCode; 1.218 + bool mIsDeadKey; 1.219 + bool mConsumed; 1.220 + 1.221 + FakeCharMsg() : 1.222 + mCharCode(0), mScanCode(0), mIsDeadKey(false), mConsumed(false) 1.223 + { 1.224 + } 1.225 + 1.226 + MSG GetCharMsg(HWND aWnd) const 1.227 + { 1.228 + MSG msg; 1.229 + msg.hwnd = aWnd; 1.230 + msg.message = mIsDeadKey ? WM_DEADCHAR : WM_CHAR; 1.231 + msg.wParam = static_cast<WPARAM>(mCharCode); 1.232 + msg.lParam = static_cast<LPARAM>(mScanCode << 16); 1.233 + msg.time = 0; 1.234 + msg.pt.x = msg.pt.y = 0; 1.235 + return msg; 1.236 + } 1.237 + }; 1.238 + 1.239 + NativeKey(nsWindowBase* aWidget, 1.240 + const MSG& aKeyOrCharMessage, 1.241 + const ModifierKeyState& aModKeyState, 1.242 + nsTArray<FakeCharMsg>* aFakeCharMsgs = nullptr); 1.243 + 1.244 + /** 1.245 + * Handle WM_KEYDOWN message or WM_SYSKEYDOWN message. The instance must be 1.246 + * initialized with WM_KEYDOWN or WM_SYSKEYDOWN. 1.247 + * Returns true if dispatched keydown event or keypress event is consumed. 1.248 + * Otherwise, false. 1.249 + */ 1.250 + bool HandleKeyDownMessage(bool* aEventDispatched = nullptr) const; 1.251 + 1.252 + /** 1.253 + * Handles WM_CHAR message or WM_SYSCHAR message. The instance must be 1.254 + * initialized with WM_KEYDOWN, WM_SYSKEYDOWN or them. 1.255 + * Returns true if dispatched keypress event is consumed. Otherwise, false. 1.256 + */ 1.257 + bool HandleCharMessage(const MSG& aCharMsg, 1.258 + bool* aEventDispatched = nullptr) const; 1.259 + 1.260 + /** 1.261 + * Handles keyup message. Returns true if the event is consumed. 1.262 + * Otherwise, false. 1.263 + */ 1.264 + bool HandleKeyUpMessage(bool* aEventDispatched = nullptr) const; 1.265 + 1.266 +private: 1.267 + nsRefPtr<nsWindowBase> mWidget; 1.268 + HKL mKeyboardLayout; 1.269 + MSG mMsg; 1.270 + 1.271 + uint32_t mDOMKeyCode; 1.272 + KeyNameIndex mKeyNameIndex; 1.273 + 1.274 + ModifierKeyState mModKeyState; 1.275 + 1.276 + // mVirtualKeyCode distinguishes left key or right key of modifier key. 1.277 + uint8_t mVirtualKeyCode; 1.278 + // mOriginalVirtualKeyCode doesn't distinguish left key or right key of 1.279 + // modifier key. However, if the given keycode is VK_PROCESS, it's resolved 1.280 + // to a keycode before it's handled by IME. 1.281 + uint8_t mOriginalVirtualKeyCode; 1.282 + 1.283 + // mCommittedChars indicates the inputted characters which is committed by 1.284 + // the key. If dead key fail to composite a character, mCommittedChars 1.285 + // indicates both the dead characters and the base characters. 1.286 + UniCharsAndModifiers mCommittedCharsAndModifiers; 1.287 + 1.288 + WORD mScanCode; 1.289 + bool mIsExtended; 1.290 + bool mIsDeadKey; 1.291 + // mIsPrintableKey is true if the key may be a printable key without 1.292 + // any modifier keys. Otherwise, false. 1.293 + // Please note that the event may not cause any text input even if this 1.294 + // is true. E.g., it might be dead key state or Ctrl key may be pressed. 1.295 + bool mIsPrintableKey; 1.296 + 1.297 + nsTArray<FakeCharMsg>* mFakeCharMsgs; 1.298 + 1.299 + NativeKey() 1.300 + { 1.301 + MOZ_CRASH("The default constructor of NativeKey isn't available"); 1.302 + } 1.303 + 1.304 + /** 1.305 + * Returns true if the key event is caused by auto repeat. 1.306 + */ 1.307 + bool IsRepeat() const 1.308 + { 1.309 + switch (mMsg.message) { 1.310 + case WM_KEYDOWN: 1.311 + case WM_SYSKEYDOWN: 1.312 + case WM_CHAR: 1.313 + case WM_SYSCHAR: 1.314 + case WM_DEADCHAR: 1.315 + case WM_SYSDEADCHAR: 1.316 + return ((mMsg.lParam & (1 << 30)) != 0); 1.317 + default: 1.318 + return false; 1.319 + } 1.320 + } 1.321 + 1.322 + UINT GetScanCodeWithExtendedFlag() const; 1.323 + 1.324 + // The result is one of nsIDOMKeyEvent::DOM_KEY_LOCATION_*. 1.325 + uint32_t GetKeyLocation() const; 1.326 + 1.327 + /** 1.328 + * "Kakutei-Undo" of ATOK or WXG (both of them are Japanese IME) causes 1.329 + * strange WM_KEYDOWN/WM_KEYUP/WM_CHAR message pattern. So, when this 1.330 + * returns true, the caller needs to be careful for processing the messages. 1.331 + */ 1.332 + bool IsIMEDoingKakuteiUndo() const; 1.333 + 1.334 + bool IsKeyDownMessage() const 1.335 + { 1.336 + return (mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN); 1.337 + } 1.338 + bool IsKeyUpMessage() const 1.339 + { 1.340 + return (mMsg.message == WM_KEYUP || mMsg.message == WM_SYSKEYUP); 1.341 + } 1.342 + bool IsPrintableCharMessage(const MSG& aMSG) const 1.343 + { 1.344 + return IsPrintableCharMessage(aMSG.message); 1.345 + } 1.346 + bool IsPrintableCharMessage(UINT aMessage) const 1.347 + { 1.348 + return (aMessage == WM_CHAR || aMessage == WM_SYSCHAR); 1.349 + } 1.350 + bool IsCharMessage(const MSG& aMSG) const 1.351 + { 1.352 + return IsCharMessage(aMSG.message); 1.353 + } 1.354 + bool IsCharMessage(UINT aMessage) const 1.355 + { 1.356 + return (IsPrintableCharMessage(aMessage) || IsDeadCharMessage(aMessage)); 1.357 + } 1.358 + bool IsDeadCharMessage(const MSG& aMSG) const 1.359 + { 1.360 + return IsDeadCharMessage(aMSG.message); 1.361 + } 1.362 + bool IsDeadCharMessage(UINT aMessage) const 1.363 + { 1.364 + return (aMessage == WM_DEADCHAR || aMessage == WM_SYSDEADCHAR); 1.365 + } 1.366 + bool IsSysCharMessage(const MSG& aMSG) const 1.367 + { 1.368 + return IsSysCharMessage(aMSG.message); 1.369 + } 1.370 + bool IsSysCharMessage(UINT aMessage) const 1.371 + { 1.372 + return (aMessage == WM_SYSCHAR || aMessage == WM_SYSDEADCHAR); 1.373 + } 1.374 + bool MayBeSameCharMessage(const MSG& aCharMsg1, const MSG& aCharMsg2) const; 1.375 + bool IsFollowedByDeadCharMessage() const; 1.376 + 1.377 + /** 1.378 + * GetFollowingCharMessage() returns following char message of handling 1.379 + * keydown event. If the message is found, this method returns true. 1.380 + * Otherwise, returns false. 1.381 + * 1.382 + * WARNING: Even if this returns true, aCharMsg may be WM_NULL or its 1.383 + * hwnd may be different window. 1.384 + */ 1.385 + bool GetFollowingCharMessage(MSG& aCharMsg) const; 1.386 + 1.387 + /** 1.388 + * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK. 1.389 + */ 1.390 + uint8_t ComputeVirtualKeyCodeFromScanCode() const; 1.391 + 1.392 + /** 1.393 + * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK_EX. 1.394 + */ 1.395 + uint8_t ComputeVirtualKeyCodeFromScanCodeEx() const; 1.396 + 1.397 + /** 1.398 + * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK and MAPVK_VK_TO_CHAR. 1.399 + */ 1.400 + char16_t ComputeUnicharFromScanCode() const; 1.401 + 1.402 + /** 1.403 + * Initializes the aKeyEvent with the information stored in the instance. 1.404 + */ 1.405 + void InitKeyEvent(WidgetKeyboardEvent& aKeyEvent, 1.406 + const ModifierKeyState& aModKeyState) const; 1.407 + void InitKeyEvent(WidgetKeyboardEvent& aKeyEvent) const; 1.408 + 1.409 + /** 1.410 + * Dispatches the key event. Returns true if the event is consumed. 1.411 + * Otherwise, false. 1.412 + */ 1.413 + bool DispatchKeyEvent(WidgetKeyboardEvent& aKeyEvent, 1.414 + const MSG* aMsgSentToPlugin = nullptr) const; 1.415 + 1.416 + /** 1.417 + * DispatchKeyPressEventsWithKeyboardLayout() dispatches keypress event(s) 1.418 + * with the information provided by KeyboardLayout class. 1.419 + */ 1.420 + bool DispatchKeyPressEventsWithKeyboardLayout() const; 1.421 + 1.422 + /** 1.423 + * Remove all following WM_CHAR, WM_SYSCHAR and WM_DEADCHAR messages for the 1.424 + * WM_KEYDOWN or WM_SYSKEYDOWN message. Additionally, dispatches plugin 1.425 + * events if it's necessary. 1.426 + * Returns true if the widget is destroyed. Otherwise, false. 1.427 + */ 1.428 + bool DispatchPluginEventsAndDiscardsCharMessages() const; 1.429 + 1.430 + /** 1.431 + * DispatchKeyPressEventForFollowingCharMessage() dispatches keypress event 1.432 + * for following WM_*CHAR message which is removed and set to aCharMsg. 1.433 + * Returns true if the event is consumed. Otherwise, false. 1.434 + */ 1.435 + bool DispatchKeyPressEventForFollowingCharMessage(const MSG& aCharMsg) const; 1.436 + 1.437 + /** 1.438 + * Checkes whether the key event down message is handled without following 1.439 + * WM_CHAR messages. For example, if following WM_CHAR message indicates 1.440 + * control character input, the WM_CHAR message is unclear whether it's 1.441 + * caused by a printable key with Ctrl or just a function key such as Enter 1.442 + * or Backspace. 1.443 + */ 1.444 + bool NeedsToHandleWithoutFollowingCharMessages() const; 1.445 +}; 1.446 + 1.447 +class KeyboardLayout 1.448 +{ 1.449 + friend class NativeKey; 1.450 + 1.451 +private: 1.452 + KeyboardLayout(); 1.453 + ~KeyboardLayout(); 1.454 + 1.455 + static KeyboardLayout* sInstance; 1.456 + static nsIIdleServiceInternal* sIdleService; 1.457 + 1.458 + struct DeadKeyTableListEntry 1.459 + { 1.460 + DeadKeyTableListEntry* next; 1.461 + uint8_t data[1]; 1.462 + }; 1.463 + 1.464 + HKL mKeyboardLayout; 1.465 + 1.466 + VirtualKey mVirtualKeys[NS_NUM_OF_KEYS]; 1.467 + DeadKeyTableListEntry* mDeadKeyTableListHead; 1.468 + int32_t mActiveDeadKey; // -1 = no active dead-key 1.469 + VirtualKey::ShiftState mDeadKeyShiftState; 1.470 + 1.471 + bool mIsOverridden : 1; 1.472 + bool mIsPendingToRestoreKeyboardLayout : 1; 1.473 + 1.474 + static inline int32_t GetKeyIndex(uint8_t aVirtualKey); 1.475 + static int CompareDeadKeyEntries(const void* aArg1, const void* aArg2, 1.476 + void* aData); 1.477 + static bool AddDeadKeyEntry(char16_t aBaseChar, char16_t aCompositeChar, 1.478 + DeadKeyEntry* aDeadKeyArray, uint32_t aEntries); 1.479 + bool EnsureDeadKeyActive(bool aIsActive, uint8_t aDeadKey, 1.480 + const PBYTE aDeadKeyKbdState); 1.481 + uint32_t GetDeadKeyCombinations(uint8_t aDeadKey, 1.482 + const PBYTE aDeadKeyKbdState, 1.483 + uint16_t aShiftStatesWithBaseChars, 1.484 + DeadKeyEntry* aDeadKeyArray, 1.485 + uint32_t aMaxEntries); 1.486 + void DeactivateDeadKeyState(); 1.487 + const DeadKeyTable* AddDeadKeyTable(const DeadKeyEntry* aDeadKeyArray, 1.488 + uint32_t aEntries); 1.489 + void ReleaseDeadKeyTables(); 1.490 + 1.491 + /** 1.492 + * Loads the specified keyboard layout. This method always clear the dead key 1.493 + * state. 1.494 + */ 1.495 + void LoadLayout(HKL aLayout); 1.496 + 1.497 + /** 1.498 + * InitNativeKey() must be called when actually widget receives WM_KEYDOWN or 1.499 + * WM_KEYUP. This method is stateful. This saves current dead key state at 1.500 + * WM_KEYDOWN. Additionally, computes current inputted character(s) and set 1.501 + * them to the aNativeKey. 1.502 + */ 1.503 + void InitNativeKey(NativeKey& aNativeKey, 1.504 + const ModifierKeyState& aModKeyState); 1.505 + 1.506 +public: 1.507 + static KeyboardLayout* GetInstance(); 1.508 + static void Shutdown(); 1.509 + static void NotifyIdleServiceOfUserActivity(); 1.510 + 1.511 + static bool IsPrintableCharKey(uint8_t aVirtualKey); 1.512 + 1.513 + /** 1.514 + * IsDeadKey() returns true if aVirtualKey is a dead key with aModKeyState. 1.515 + * This method isn't stateful. 1.516 + */ 1.517 + bool IsDeadKey(uint8_t aVirtualKey, 1.518 + const ModifierKeyState& aModKeyState) const; 1.519 + 1.520 + /** 1.521 + * GetUniCharsAndModifiers() returns characters which is inputted by the 1.522 + * aVirtualKey with aModKeyState. This method isn't stateful. 1.523 + */ 1.524 + UniCharsAndModifiers GetUniCharsAndModifiers( 1.525 + uint8_t aVirtualKey, 1.526 + const ModifierKeyState& aModKeyState) const; 1.527 + 1.528 + /** 1.529 + * OnLayoutChange() must be called before the first keydown message is 1.530 + * received. LoadLayout() changes the keyboard state, that causes breaking 1.531 + * dead key state. Therefore, we need to load the layout before the first 1.532 + * keydown message. 1.533 + */ 1.534 + void OnLayoutChange(HKL aKeyboardLayout) 1.535 + { 1.536 + MOZ_ASSERT(!mIsOverridden); 1.537 + LoadLayout(aKeyboardLayout); 1.538 + } 1.539 + 1.540 + /** 1.541 + * OverrideLayout() loads the specified keyboard layout. 1.542 + */ 1.543 + void OverrideLayout(HKL aLayout) 1.544 + { 1.545 + mIsOverridden = true; 1.546 + LoadLayout(aLayout); 1.547 + } 1.548 + 1.549 + /** 1.550 + * RestoreLayout() loads the current keyboard layout of the thread. 1.551 + */ 1.552 + void RestoreLayout() 1.553 + { 1.554 + mIsOverridden = false; 1.555 + mIsPendingToRestoreKeyboardLayout = true; 1.556 + } 1.557 + 1.558 + uint32_t ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const; 1.559 + 1.560 + /** 1.561 + * ConvertNativeKeyCodeToKeyNameIndex() returns KeyNameIndex value for 1.562 + * non-printable keys (except some special keys like space key). 1.563 + */ 1.564 + KeyNameIndex ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const; 1.565 + 1.566 + HKL GetLayout() const 1.567 + { 1.568 + return mIsPendingToRestoreKeyboardLayout ? ::GetKeyboardLayout(0) : 1.569 + mKeyboardLayout; 1.570 + } 1.571 + 1.572 + /** 1.573 + * This wraps MapVirtualKeyEx() API with MAPVK_VK_TO_VSC. 1.574 + */ 1.575 + WORD ComputeScanCodeForVirtualKeyCode(uint8_t aVirtualKeyCode) const; 1.576 + 1.577 + /** 1.578 + * Implementation of nsIWidget::SynthesizeNativeKeyEvent(). 1.579 + */ 1.580 + nsresult SynthesizeNativeKeyEvent(nsWindowBase* aWidget, 1.581 + int32_t aNativeKeyboardLayout, 1.582 + int32_t aNativeKeyCode, 1.583 + uint32_t aModifierFlags, 1.584 + const nsAString& aCharacters, 1.585 + const nsAString& aUnmodifiedCharacters); 1.586 +}; 1.587 + 1.588 +class RedirectedKeyDownMessageManager 1.589 +{ 1.590 +public: 1.591 + /* 1.592 + * If a window receives WM_KEYDOWN message or WM_SYSKEYDOWM message which is 1.593 + * a redirected message, NativeKey::DispatchKeyDownAndKeyPressEvent() 1.594 + * prevents to dispatch NS_KEY_DOWN event because it has been dispatched 1.595 + * before the message was redirected. However, in some cases, WM_*KEYDOWN 1.596 + * message handler may not handle actually. Then, the message handler needs 1.597 + * to forget the redirected message and remove WM_CHAR message or WM_SYSCHAR 1.598 + * message for the redirected keydown message. AutoFlusher class is a helper 1.599 + * class for doing it. This must be created in the stack. 1.600 + */ 1.601 + class MOZ_STACK_CLASS AutoFlusher MOZ_FINAL 1.602 + { 1.603 + public: 1.604 + AutoFlusher(nsWindowBase* aWidget, const MSG &aMsg) : 1.605 + mCancel(!RedirectedKeyDownMessageManager::IsRedirectedMessage(aMsg)), 1.606 + mWidget(aWidget), mMsg(aMsg) 1.607 + { 1.608 + } 1.609 + 1.610 + ~AutoFlusher() 1.611 + { 1.612 + if (mCancel) { 1.613 + return; 1.614 + } 1.615 + // Prevent unnecessary keypress event 1.616 + if (!mWidget->Destroyed()) { 1.617 + RedirectedKeyDownMessageManager::RemoveNextCharMessage(mMsg.hwnd); 1.618 + } 1.619 + // Foreget the redirected message 1.620 + RedirectedKeyDownMessageManager::Forget(); 1.621 + } 1.622 + 1.623 + void Cancel() { mCancel = true; } 1.624 + 1.625 + private: 1.626 + bool mCancel; 1.627 + nsRefPtr<nsWindowBase> mWidget; 1.628 + const MSG &mMsg; 1.629 + }; 1.630 + 1.631 + static void WillRedirect(const MSG& aMsg, bool aDefualtPrevented) 1.632 + { 1.633 + sRedirectedKeyDownMsg = aMsg; 1.634 + sDefaultPreventedOfRedirectedMsg = aDefualtPrevented; 1.635 + } 1.636 + 1.637 + static void Forget() 1.638 + { 1.639 + sRedirectedKeyDownMsg.message = WM_NULL; 1.640 + } 1.641 + 1.642 + static void PreventDefault() { sDefaultPreventedOfRedirectedMsg = true; } 1.643 + static bool DefaultPrevented() { return sDefaultPreventedOfRedirectedMsg; } 1.644 + 1.645 + static bool IsRedirectedMessage(const MSG& aMsg); 1.646 + 1.647 + /** 1.648 + * RemoveNextCharMessage() should be called by WM_KEYDOWN or WM_SYSKEYDOWM 1.649 + * message handler. If there is no WM_(SYS)CHAR message for it, this 1.650 + * method does nothing. 1.651 + * NOTE: WM_(SYS)CHAR message is posted by TranslateMessage() API which is 1.652 + * called in message loop. So, WM_(SYS)KEYDOWN message should have 1.653 + * WM_(SYS)CHAR message in the queue if the keydown event causes character 1.654 + * input. 1.655 + */ 1.656 + static void RemoveNextCharMessage(HWND aWnd); 1.657 + 1.658 +private: 1.659 + // sRedirectedKeyDownMsg is WM_KEYDOWN message or WM_SYSKEYDOWN message which 1.660 + // is reirected with SendInput() API by 1.661 + // widget::NativeKey::DispatchKeyDownAndKeyPressEvent() 1.662 + static MSG sRedirectedKeyDownMsg; 1.663 + static bool sDefaultPreventedOfRedirectedMsg; 1.664 +}; 1.665 + 1.666 +} // namespace widget 1.667 +} // namespace mozilla 1.668 + 1.669 +#endif