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/. */ 5 6 #ifndef KeyboardLayout_h__ 7 #define KeyboardLayout_h__ 8 9 #include "mozilla/RefPtr.h" 10 #include "nscore.h" 11 #include "nsString.h" 12 #include "nsWindowBase.h" 13 #include "nsWindowDefs.h" 14 #include "mozilla/Attributes.h" 15 #include "mozilla/EventForwards.h" 16 #include "mozilla/TextEventDispatcher.h" 17 #include "mozilla/widget/WinMessages.h" 18 #include "mozilla/widget/WinModifierKeyState.h" 19 #include <windows.h> 20 21 #define NS_NUM_OF_KEYS 70 22 23 #define VK_OEM_1 0xBA // ';:' for US 24 #define VK_OEM_PLUS 0xBB // '+' any country 25 #define VK_OEM_COMMA 0xBC 26 #define VK_OEM_MINUS 0xBD // '-' any country 27 #define VK_OEM_PERIOD 0xBE 28 #define VK_OEM_2 0xBF 29 #define VK_OEM_3 0xC0 30 // '/?' for Brazilian (ABNT) 31 #define VK_ABNT_C1 0xC1 32 // Separator in Numpad for Brazilian (ABNT) or JIS keyboard for Mac. 33 #define VK_ABNT_C2 0xC2 34 #define VK_OEM_4 0xDB 35 #define VK_OEM_5 0xDC 36 #define VK_OEM_6 0xDD 37 #define VK_OEM_7 0xDE 38 #define VK_OEM_8 0xDF 39 #define VK_OEM_102 0xE2 40 #define VK_OEM_CLEAR 0xFE 41 42 class nsIIdleServiceInternal; 43 44 namespace mozilla { 45 namespace widget { 46 47 static const uint32_t sModifierKeyMap[][3] = { 48 {nsIWidget::CAPS_LOCK, VK_CAPITAL, 0}, 49 {nsIWidget::NUM_LOCK, VK_NUMLOCK, 0}, 50 {nsIWidget::SHIFT_L, VK_SHIFT, VK_LSHIFT}, 51 {nsIWidget::SHIFT_R, VK_SHIFT, VK_RSHIFT}, 52 {nsIWidget::CTRL_L, VK_CONTROL, VK_LCONTROL}, 53 {nsIWidget::CTRL_R, VK_CONTROL, VK_RCONTROL}, 54 {nsIWidget::ALT_L, VK_MENU, VK_LMENU}, 55 {nsIWidget::ALT_R, VK_MENU, VK_RMENU}}; 56 57 class KeyboardLayout; 58 59 class MOZ_STACK_CLASS UniCharsAndModifiers final { 60 public: UniCharsAndModifiers()61 UniCharsAndModifiers() {} 62 UniCharsAndModifiers operator+(const UniCharsAndModifiers& aOther) const; 63 UniCharsAndModifiers& operator+=(const UniCharsAndModifiers& aOther); 64 65 /** 66 * Append a pair of unicode character and the final modifier. 67 */ 68 void Append(char16_t aUniChar, Modifiers aModifiers); Clear()69 void Clear() { 70 mChars.Truncate(); 71 mModifiers.Clear(); 72 } IsEmpty()73 bool IsEmpty() const { 74 MOZ_ASSERT(mChars.Length() == mModifiers.Length()); 75 return mChars.IsEmpty(); 76 } 77 CharAt(size_t aIndex)78 char16_t CharAt(size_t aIndex) const { 79 MOZ_ASSERT(aIndex < Length()); 80 return mChars[aIndex]; 81 } ModifiersAt(size_t aIndex)82 Modifiers ModifiersAt(size_t aIndex) const { 83 MOZ_ASSERT(aIndex < Length()); 84 return mModifiers[aIndex]; 85 } Length()86 size_t Length() const { 87 MOZ_ASSERT(mChars.Length() == mModifiers.Length()); 88 return mChars.Length(); 89 } 90 91 void FillModifiers(Modifiers aModifiers); 92 /** 93 * OverwriteModifiersIfBeginsWith() assigns mModifiers with aOther between 94 * [0] and [aOther.mLength - 1] only when mChars begins with aOther.mChars. 95 */ 96 void OverwriteModifiersIfBeginsWith(const UniCharsAndModifiers& aOther); 97 98 bool UniCharsEqual(const UniCharsAndModifiers& aOther) const; 99 bool UniCharsCaseInsensitiveEqual(const UniCharsAndModifiers& aOther) const; 100 bool BeginsWith(const UniCharsAndModifiers& aOther) const; 101 ToString()102 const nsString& ToString() const { return mChars; } 103 104 private: 105 nsAutoString mChars; 106 // 5 is enough number for normal keyboard layout handling. On Windows, 107 // a dead key sequence may cause inputting up to 5 characters per key press. 108 AutoTArray<Modifiers, 5> mModifiers; 109 }; 110 111 struct DeadKeyEntry { 112 char16_t BaseChar; 113 char16_t CompositeChar; 114 }; 115 116 class DeadKeyTable { 117 friend class KeyboardLayout; 118 119 uint16_t mEntries; 120 // KeyboardLayout::AddDeadKeyTable() will allocate as many entries as 121 // required. It is the only way to create new DeadKeyTable instances. 122 DeadKeyEntry mTable[1]; 123 Init(const DeadKeyEntry * aDeadKeyArray,uint32_t aEntries)124 void Init(const DeadKeyEntry* aDeadKeyArray, uint32_t aEntries) { 125 mEntries = aEntries; 126 memcpy(mTable, aDeadKeyArray, aEntries * sizeof(DeadKeyEntry)); 127 } 128 SizeInBytes(uint32_t aEntries)129 static uint32_t SizeInBytes(uint32_t aEntries) { 130 return offsetof(DeadKeyTable, mTable) + aEntries * sizeof(DeadKeyEntry); 131 } 132 133 public: Entries()134 uint32_t Entries() const { return mEntries; } 135 IsEqual(const DeadKeyEntry * aDeadKeyArray,uint32_t aEntries)136 bool IsEqual(const DeadKeyEntry* aDeadKeyArray, uint32_t aEntries) const { 137 return (mEntries == aEntries && 138 !memcmp(mTable, aDeadKeyArray, aEntries * sizeof(DeadKeyEntry))); 139 } 140 141 char16_t GetCompositeChar(char16_t aBaseChar) const; 142 }; 143 144 class VirtualKey { 145 public: 146 // 0 - Normal 147 // 1 - Shift 148 // 2 - Control 149 // 3 - Control + Shift 150 // 4 - Alt 151 // 5 - Alt + Shift 152 // 6 - Alt + Control (AltGr) 153 // 7 - Alt + Control + Shift (AltGr + Shift) 154 // 8 - CapsLock 155 // 9 - CapsLock + Shift 156 // 10 - CapsLock + Control 157 // 11 - CapsLock + Control + Shift 158 // 12 - CapsLock + Alt 159 // 13 - CapsLock + Alt + Shift 160 // 14 - CapsLock + Alt + Control (CapsLock + AltGr) 161 // 15 - CapsLock + Alt + Control + Shift (CapsLock + AltGr + Shift) 162 163 enum ShiftStateFlag { 164 STATE_SHIFT = 0x01, 165 STATE_CONTROL = 0x02, 166 STATE_ALT = 0x04, 167 STATE_CAPSLOCK = 0x08 168 }; 169 170 typedef uint8_t ShiftState; 171 172 static ShiftState ModifiersToShiftState(Modifiers aModifiers); ModifierKeyStateToShiftState(const ModifierKeyState & aModKeyState)173 static ShiftState ModifierKeyStateToShiftState( 174 const ModifierKeyState& aModKeyState) { 175 return ModifiersToShiftState(aModKeyState.GetModifiers()); 176 } 177 static Modifiers ShiftStateToModifiers(ShiftState aShiftState); 178 179 private: 180 union KeyShiftState { 181 struct { 182 char16_t Chars[4]; 183 } Normal; 184 struct { 185 const DeadKeyTable* Table; 186 char16_t DeadChar; 187 } DeadKey; 188 }; 189 190 KeyShiftState mShiftStates[16]; 191 uint16_t mIsDeadKey; 192 SetDeadKey(ShiftState aShiftState,bool aIsDeadKey)193 void SetDeadKey(ShiftState aShiftState, bool aIsDeadKey) { 194 if (aIsDeadKey) { 195 mIsDeadKey |= 1 << aShiftState; 196 } else { 197 mIsDeadKey &= ~(1 << aShiftState); 198 } 199 } 200 201 public: 202 static void FillKbdState(PBYTE aKbdState, const ShiftState aShiftState); 203 IsDeadKey(ShiftState aShiftState)204 bool IsDeadKey(ShiftState aShiftState) const { 205 return (mIsDeadKey & (1 << aShiftState)) != 0; 206 } 207 AttachDeadKeyTable(ShiftState aShiftState,const DeadKeyTable * aDeadKeyTable)208 void AttachDeadKeyTable(ShiftState aShiftState, 209 const DeadKeyTable* aDeadKeyTable) { 210 mShiftStates[aShiftState].DeadKey.Table = aDeadKeyTable; 211 } 212 213 void SetNormalChars(ShiftState aShiftState, const char16_t* aChars, 214 uint32_t aNumOfChars); 215 void SetDeadChar(ShiftState aShiftState, char16_t aDeadChar); 216 const DeadKeyTable* MatchingDeadKeyTable(const DeadKeyEntry* aDeadKeyArray, 217 uint32_t aEntries) const; GetCompositeChar(ShiftState aShiftState,char16_t aBaseChar)218 inline char16_t GetCompositeChar(ShiftState aShiftState, 219 char16_t aBaseChar) const { 220 return mShiftStates[aShiftState].DeadKey.Table->GetCompositeChar(aBaseChar); 221 } 222 GetCompositeChar(const ModifierKeyState & aModKeyState,char16_t aBaseChar)223 char16_t GetCompositeChar(const ModifierKeyState& aModKeyState, 224 char16_t aBaseChar) const { 225 return GetCompositeChar(ModifierKeyStateToShiftState(aModKeyState), 226 aBaseChar); 227 } 228 UniCharsAndModifiers GetNativeUniChars(ShiftState aShiftState) const; GetNativeUniChars(const ModifierKeyState & aModKeyState)229 UniCharsAndModifiers GetNativeUniChars( 230 const ModifierKeyState& aModKeyState) const { 231 return GetNativeUniChars(ModifierKeyStateToShiftState(aModKeyState)); 232 } 233 UniCharsAndModifiers GetUniChars(ShiftState aShiftState) const; GetUniChars(const ModifierKeyState & aModKeyState)234 UniCharsAndModifiers GetUniChars(const ModifierKeyState& aModKeyState) const { 235 return GetUniChars(ModifierKeyStateToShiftState(aModKeyState)); 236 } 237 }; 238 239 class MOZ_STACK_CLASS NativeKey final { 240 friend class KeyboardLayout; 241 242 public: 243 struct FakeCharMsg { 244 UINT mCharCode; 245 UINT mScanCode; 246 bool mIsSysKey; 247 bool mIsDeadKey; 248 bool mConsumed; 249 FakeCharMsgFakeCharMsg250 FakeCharMsg() 251 : mCharCode(0), 252 mScanCode(0), 253 mIsSysKey(false), 254 mIsDeadKey(false), 255 mConsumed(false) {} 256 GetCharMsgFakeCharMsg257 MSG GetCharMsg(HWND aWnd) const { 258 MSG msg; 259 msg.hwnd = aWnd; 260 msg.message = 261 mIsDeadKey && mIsSysKey 262 ? WM_SYSDEADCHAR 263 : mIsDeadKey ? WM_DEADCHAR : mIsSysKey ? WM_SYSCHAR : WM_CHAR; 264 msg.wParam = static_cast<WPARAM>(mCharCode); 265 msg.lParam = static_cast<LPARAM>(mScanCode << 16); 266 msg.time = 0; 267 msg.pt.x = msg.pt.y = 0; 268 return msg; 269 } 270 }; 271 272 NativeKey(nsWindowBase* aWidget, const MSG& aMessage, 273 const ModifierKeyState& aModKeyState, 274 HKL aOverrideKeyboardLayout = 0, 275 nsTArray<FakeCharMsg>* aFakeCharMsgs = nullptr); 276 277 ~NativeKey(); 278 279 /** 280 * Handle WM_KEYDOWN message or WM_SYSKEYDOWN message. The instance must be 281 * initialized with WM_KEYDOWN or WM_SYSKEYDOWN. 282 * Returns true if dispatched keydown event or keypress event is consumed. 283 * Otherwise, false. 284 */ 285 bool HandleKeyDownMessage(bool* aEventDispatched = nullptr) const; 286 287 /** 288 * Handles WM_CHAR message or WM_SYSCHAR message. The instance must be 289 * initialized with them. 290 * Returns true if dispatched keypress event is consumed. Otherwise, false. 291 */ 292 bool HandleCharMessage(bool* aEventDispatched = nullptr) const; 293 294 /** 295 * Handles keyup message. Returns true if the event is consumed. 296 * Otherwise, false. 297 */ 298 bool HandleKeyUpMessage(bool* aEventDispatched = nullptr) const; 299 300 /** 301 * Handles WM_APPCOMMAND message. Returns true if the event is consumed. 302 * Otherwise, false. 303 */ 304 bool HandleAppCommandMessage() const; 305 306 /** 307 * Callback of TextEventDispatcherListener::WillDispatchKeyboardEvent(). 308 * This method sets alternative char codes of aKeyboardEvent. 309 */ 310 void WillDispatchKeyboardEvent(WidgetKeyboardEvent& aKeyboardEvent, 311 uint32_t aIndex); 312 313 /** 314 * Returns true if aChar is a control character which shouldn't be inputted 315 * into focused text editor. 316 */ 317 static bool IsControlChar(char16_t aChar); 318 319 private: 320 NativeKey* mLastInstance; 321 // mRemovingMsg is set at removing a char message from 322 // GetFollowingCharMessage(). 323 MSG mRemovingMsg; 324 // mReceivedMsg is set when another instance starts to handle the message 325 // unexpectedly. 326 MSG mReceivedMsg; 327 RefPtr<nsWindowBase> mWidget; 328 RefPtr<TextEventDispatcher> mDispatcher; 329 HKL mKeyboardLayout; 330 MSG mMsg; 331 // mFollowingCharMsgs stores WM_CHAR, WM_SYSCHAR, WM_DEADCHAR or 332 // WM_SYSDEADCHAR message which follows WM_KEYDOWN. 333 // Note that the stored messaged are already removed from the queue. 334 // FYI: 5 is enough number for usual keyboard layout handling. On Windows, 335 // a dead key sequence may cause inputting up to 5 characters per key press. 336 AutoTArray<MSG, 5> mFollowingCharMsgs; 337 // mRemovedOddCharMsgs stores WM_CHAR messages which are caused by ATOK or 338 // WXG (they are Japanese IME) when the user tries to do "Kakutei-undo" 339 // (it means "undo the last commit"). 340 nsTArray<MSG> mRemovedOddCharMsgs; 341 // If dispatching eKeyDown or eKeyPress event causes focus change, 342 // the instance shouldn't handle remaning char messages. For checking it, 343 // this should store first focused window. 344 HWND mFocusedWndBeforeDispatch; 345 346 uint32_t mDOMKeyCode; 347 KeyNameIndex mKeyNameIndex; 348 CodeNameIndex mCodeNameIndex; 349 350 ModifierKeyState mModKeyState; 351 352 // mVirtualKeyCode distinguishes left key or right key of modifier key. 353 uint8_t mVirtualKeyCode; 354 // mOriginalVirtualKeyCode doesn't distinguish left key or right key of 355 // modifier key. However, if the given keycode is VK_PROCESS, it's resolved 356 // to a keycode before it's handled by IME. 357 uint8_t mOriginalVirtualKeyCode; 358 359 // mCommittedChars indicates the inputted characters which is committed by 360 // the key. If dead key fail to composite a character, mCommittedChars 361 // indicates both the dead characters and the base characters. 362 UniCharsAndModifiers mCommittedCharsAndModifiers; 363 364 // Following strings are computed by 365 // ComputeInputtingStringWithKeyboardLayout() which is typically called 366 // before dispatching keydown event. 367 // mInputtingStringAndModifiers's string is the string to be 368 // inputted into the focused editor and its modifier state is proper 369 // modifier state for inputting the string into the editor. 370 UniCharsAndModifiers mInputtingStringAndModifiers; 371 // mShiftedString is the string to be inputted into the editor with 372 // current modifier state with active shift state. 373 UniCharsAndModifiers mShiftedString; 374 // mUnshiftedString is the string to be inputted into the editor with 375 // current modifier state without shift state. 376 UniCharsAndModifiers mUnshiftedString; 377 // Following integers are computed by 378 // ComputeInputtingStringWithKeyboardLayout() which is typically called 379 // before dispatching keydown event. The meaning of these values is same 380 // as charCode. 381 uint32_t mShiftedLatinChar; 382 uint32_t mUnshiftedLatinChar; 383 384 WORD mScanCode; 385 bool mIsExtended; 386 // mIsRepeat is true if the key message is caused by the auto-repeat 387 // feature. 388 bool mIsRepeat; 389 bool mIsDeadKey; 390 // mIsPrintableKey is true if the key may be a printable key without 391 // any modifier keys. Otherwise, false. 392 // Please note that the event may not cause any text input even if this 393 // is true. E.g., it might be dead key state or Ctrl key may be pressed. 394 bool mIsPrintableKey; 395 // mIsSkippableInRemoteProcess is false if the key event shouldn't be 396 // skipped in the remote process even if it's too old event. 397 bool mIsSkippableInRemoteProcess; 398 // mCharMessageHasGone is true if the message is a keydown message and 399 // it's followed by at least one char message but it's gone at removing 400 // from the queue. This could occur if PeekMessage() or something is 401 // hooked by odd tool. 402 bool mCharMessageHasGone; 403 // mIsOverridingKeyboardLayout is true if the instance temporarily overriding 404 // keyboard layout with specified by the constructor. 405 bool mIsOverridingKeyboardLayout; 406 // mCanIgnoreModifierStateAtKeyPress is true if it's allowed to remove 407 // Ctrl or Alt modifier state at dispatching eKeyPress. 408 bool mCanIgnoreModifierStateAtKeyPress; 409 410 nsTArray<FakeCharMsg>* mFakeCharMsgs; 411 412 // When a keydown event is dispatched at handling WM_APPCOMMAND, the computed 413 // virtual keycode is set to this. Even if we consume WM_APPCOMMAND message, 414 // Windows may send WM_KEYDOWN and WM_KEYUP message for them. 415 // At that time, we should not dispatch key events for them. 416 static uint8_t sDispatchedKeyOfAppCommand; 417 NativeKey()418 NativeKey() { 419 MOZ_CRASH("The default constructor of NativeKey isn't available"); 420 } 421 422 void InitWithAppCommand(); 423 void InitWithKeyOrChar(); 424 425 /** 426 * InitIsSkippableForKeyOrChar() initializes mIsSkippableInRemoteProcess with 427 * mIsRepeat and previous key message information. So, this must be called 428 * after mIsRepeat is initialized. 429 */ 430 void InitIsSkippableForKeyOrChar(const MSG& aLastKeyMSG); 431 432 /** 433 * InitCommittedCharsAndModifiersWithFollowingCharMessages() initializes 434 * mCommittedCharsAndModifiers with mFollowingCharMsgs and aModKeyState. 435 * If mFollowingCharMsgs includes non-printable char messages, they are 436 * ignored (skipped). 437 */ 438 void InitCommittedCharsAndModifiersWithFollowingCharMessages( 439 const ModifierKeyState& aModKeyState); 440 441 UINT GetScanCodeWithExtendedFlag() const; 442 443 // The result is one of eKeyLocation*. 444 uint32_t GetKeyLocation() const; 445 446 /** 447 * RemoveFollowingOddCharMessages() removes odd WM_CHAR messages from the 448 * queue when IsIMEDoingKakuteiUndo() returns true. 449 */ 450 void RemoveFollowingOddCharMessages(); 451 452 /** 453 * "Kakutei-Undo" of ATOK or WXG (both of them are Japanese IME) causes 454 * strange WM_KEYDOWN/WM_KEYUP/WM_CHAR message pattern. So, when this 455 * returns true, the caller needs to be careful for processing the messages. 456 */ 457 bool IsIMEDoingKakuteiUndo() const; 458 IsKeyDownMessage()459 bool IsKeyDownMessage() const { 460 return (mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN || 461 mMsg.message == MOZ_WM_KEYDOWN); 462 } IsKeyUpMessage()463 bool IsKeyUpMessage() const { 464 return (mMsg.message == WM_KEYUP || mMsg.message == WM_SYSKEYUP || 465 mMsg.message == MOZ_WM_KEYUP); 466 } IsCharOrSysCharMessage(const MSG & aMSG)467 bool IsCharOrSysCharMessage(const MSG& aMSG) const { 468 return IsCharOrSysCharMessage(aMSG.message); 469 } IsCharOrSysCharMessage(UINT aMessage)470 bool IsCharOrSysCharMessage(UINT aMessage) const { 471 return (aMessage == WM_CHAR || aMessage == WM_SYSCHAR); 472 } IsCharMessage(const MSG & aMSG)473 bool IsCharMessage(const MSG& aMSG) const { 474 return IsCharMessage(aMSG.message); 475 } IsCharMessage(UINT aMessage)476 bool IsCharMessage(UINT aMessage) const { 477 return (IsCharOrSysCharMessage(aMessage) || IsDeadCharMessage(aMessage)); 478 } IsDeadCharMessage(const MSG & aMSG)479 bool IsDeadCharMessage(const MSG& aMSG) const { 480 return IsDeadCharMessage(aMSG.message); 481 } IsDeadCharMessage(UINT aMessage)482 bool IsDeadCharMessage(UINT aMessage) const { 483 return (aMessage == WM_DEADCHAR || aMessage == WM_SYSDEADCHAR); 484 } IsSysCharMessage(const MSG & aMSG)485 bool IsSysCharMessage(const MSG& aMSG) const { 486 return IsSysCharMessage(aMSG.message); 487 } IsSysCharMessage(UINT aMessage)488 bool IsSysCharMessage(UINT aMessage) const { 489 return (aMessage == WM_SYSCHAR || aMessage == WM_SYSDEADCHAR); 490 } 491 bool MayBeSameCharMessage(const MSG& aCharMsg1, const MSG& aCharMsg2) const; 492 bool IsSamePhysicalKeyMessage(const MSG& aKeyOrCharMsg1, 493 const MSG& aKeyOrCharMsg2) const; 494 bool IsFollowedByPrintableCharMessage() const; 495 bool IsFollowedByPrintableCharOrSysCharMessage() const; 496 bool IsFollowedByDeadCharMessage() const; IsKeyMessageOnPlugin()497 bool IsKeyMessageOnPlugin() const { 498 return (mMsg.message == MOZ_WM_KEYDOWN || mMsg.message == MOZ_WM_KEYUP); 499 } IsPrintableCharMessage(const MSG & aMSG)500 bool IsPrintableCharMessage(const MSG& aMSG) const { 501 return aMSG.message == WM_CHAR && 502 !IsControlChar(static_cast<char16_t>(aMSG.wParam)); 503 } IsEnterKeyPressCharMessage(const MSG & aMSG)504 bool IsEnterKeyPressCharMessage(const MSG& aMSG) const { 505 return aMSG.message == WM_CHAR && aMSG.wParam == '\r'; 506 } IsPrintableCharOrSysCharMessage(const MSG & aMSG)507 bool IsPrintableCharOrSysCharMessage(const MSG& aMSG) const { 508 return IsCharOrSysCharMessage(aMSG) && 509 !IsControlChar(static_cast<char16_t>(aMSG.wParam)); 510 } IsControlCharMessage(const MSG & aMSG)511 bool IsControlCharMessage(const MSG& aMSG) const { 512 return IsCharMessage(aMSG.message) && 513 IsControlChar(static_cast<char16_t>(aMSG.wParam)); 514 } 515 516 /** 517 * IsReservedBySystem() returns true if the key combination is reserved by 518 * the system. Even if it's consumed by web apps, the message should be 519 * sent to next wndproc. 520 */ 521 bool IsReservedBySystem() const; 522 523 /** 524 * GetFollowingCharMessage() returns following char message of handling 525 * keydown event. If the message is found, this method returns true. 526 * Otherwise, returns false. 527 * 528 * WARNING: Even if this returns true, aCharMsg may be WM_NULL or its 529 * hwnd may be different window. 530 */ 531 bool GetFollowingCharMessage(MSG& aCharMsg); 532 533 /** 534 * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK. 535 */ 536 uint8_t ComputeVirtualKeyCodeFromScanCode() const; 537 538 /** 539 * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK_EX. 540 */ 541 uint8_t ComputeVirtualKeyCodeFromScanCodeEx() const; 542 543 /** 544 * Wraps MapVirtualKeyEx() with MAPVK_VK_TO_VSC_EX or MAPVK_VK_TO_VSC. 545 */ 546 uint16_t ComputeScanCodeExFromVirtualKeyCode(UINT aVirtualKeyCode) const; 547 548 /** 549 * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK and MAPVK_VK_TO_CHAR. 550 */ 551 char16_t ComputeUnicharFromScanCode() const; 552 553 /** 554 * Initializes the aKeyEvent with the information stored in the instance. 555 */ 556 nsEventStatus InitKeyEvent(WidgetKeyboardEvent& aKeyEvent, 557 const ModifierKeyState& aModKeyState, 558 const MSG* aMsgSentToPlugin = nullptr) const; 559 nsEventStatus InitKeyEvent(WidgetKeyboardEvent& aKeyEvent, 560 const MSG* aMsgSentToPlugin = nullptr) const; 561 562 /** 563 * MaybeInitPluginEventOfKeyEvent() may initialize aKeyEvent::mPluginEvent 564 * with aMsgSentToPlugin if it's necessary. 565 */ 566 void MaybeInitPluginEventOfKeyEvent(WidgetKeyboardEvent& aKeyEvent, 567 const MSG& aMsgSentToPlugin) const; 568 569 /** 570 * Dispatches a command event for aEventCommand. 571 * Returns true if the event is consumed. Otherwise, false. 572 */ 573 bool DispatchCommandEvent(uint32_t aEventCommand) const; 574 575 /** 576 * DispatchKeyPressEventsWithRetrievedCharMessages() dispatches keypress 577 * event(s) with retrieved char messages. 578 */ 579 bool DispatchKeyPressEventsWithRetrievedCharMessages() const; 580 581 /** 582 * DispatchKeyPressEventsWithoutCharMessage() dispatches keypress event(s) 583 * without char messages. So, this should be used only when there are no 584 * following char messages. 585 */ 586 bool DispatchKeyPressEventsWithoutCharMessage() const; 587 588 /** 589 * MaybeDispatchPluginEventsForRemovedCharMessages() dispatches plugin events 590 * for removed char messages when a windowless plugin has focus. 591 * Returns true if the widget is destroyed or blurred during dispatching a 592 * plugin event. 593 */ 594 bool MaybeDispatchPluginEventsForRemovedCharMessages() const; 595 596 /** 597 * Checkes whether the key event down message is handled without following 598 * WM_CHAR messages. For example, if following WM_CHAR message indicates 599 * control character input, the WM_CHAR message is unclear whether it's 600 * caused by a printable key with Ctrl or just a function key such as Enter 601 * or Backspace. 602 */ 603 bool NeedsToHandleWithoutFollowingCharMessages() const; 604 605 /** 606 * ComputeInputtingStringWithKeyboardLayout() computes string to be inputted 607 * with the key and the modifier state, without shift state and with shift 608 * state. 609 */ 610 void ComputeInputtingStringWithKeyboardLayout(); 611 612 /** 613 * IsFocusedWindowChanged() returns true if focused window is changed 614 * after the instance is created. 615 */ IsFocusedWindowChanged()616 bool IsFocusedWindowChanged() const { 617 return mFocusedWndBeforeDispatch != ::GetFocus(); 618 } 619 620 /** 621 * Handles WM_CHAR message or WM_SYSCHAR message. The instance must be 622 * initialized with WM_KEYDOWN, WM_SYSKEYDOWN or them. 623 * Returns true if dispatched keypress event is consumed. Otherwise, false. 624 */ 625 bool HandleCharMessage(const MSG& aCharMsg, 626 bool* aEventDispatched = nullptr) const; 627 628 // Calls of PeekMessage() from NativeKey might cause nested message handling 629 // due to (perhaps) odd API hook. NativeKey should do nothing if given 630 // message is tried to be retrieved by another instance. 631 632 /** 633 * sLatestInstacne is a pointer to the newest instance of NativeKey which is 634 * handling a key or char message(s). 635 */ 636 static NativeKey* sLatestInstance; 637 638 static const MSG sEmptyMSG; 639 640 static MSG sLastKeyOrCharMSG; 641 642 static MSG sLastKeyMSG; 643 IsEmptyMSG(const MSG & aMSG)644 static bool IsEmptyMSG(const MSG& aMSG) { 645 return !memcmp(&aMSG, &sEmptyMSG, sizeof(MSG)); 646 } 647 IsAnotherInstanceRemovingCharMessage()648 bool IsAnotherInstanceRemovingCharMessage() const { 649 return mLastInstance && !IsEmptyMSG(mLastInstance->mRemovingMsg); 650 } 651 652 public: 653 /** 654 * Returns last key or char MSG. If no MSG has been received yet, the result 655 * is empty MSG (i.e., .message is WM_NULL). 656 */ LastKeyOrCharMSG()657 static const MSG& LastKeyOrCharMSG() { return sLastKeyOrCharMSG; } 658 }; 659 660 class KeyboardLayout { 661 public: 662 static KeyboardLayout* GetInstance(); 663 static void Shutdown(); 664 static HKL GetActiveLayout(); 665 static nsCString GetActiveLayoutName(); 666 static void NotifyIdleServiceOfUserActivity(); 667 668 static bool IsPrintableCharKey(uint8_t aVirtualKey); 669 670 /** 671 * IsDeadKey() returns true if aVirtualKey is a dead key with aModKeyState. 672 * This method isn't stateful. 673 */ 674 bool IsDeadKey(uint8_t aVirtualKey, 675 const ModifierKeyState& aModKeyState) const; 676 677 /** 678 * IsInDeadKeySequence() returns true when it's in a dead key sequence. 679 * It starts when a dead key is down and ends when another key down causes 680 * inactivating the dead key state. 681 */ IsInDeadKeySequence()682 bool IsInDeadKeySequence() const { return !mActiveDeadKeys.IsEmpty(); } 683 684 /** 685 * IsSysKey() returns true if aVirtualKey with aModKeyState causes WM_SYSKEY* 686 * or WM_SYS*CHAR messages. 687 */ 688 bool IsSysKey(uint8_t aVirtualKey, 689 const ModifierKeyState& aModKeyState) const; 690 691 /** 692 * GetUniCharsAndModifiers() returns characters which are inputted by 693 * aVirtualKey with aModKeyState. This method isn't stateful. 694 * Note that if the combination causes text input, the result's Ctrl and 695 * Alt key state are never active. 696 */ GetUniCharsAndModifiers(uint8_t aVirtualKey,const ModifierKeyState & aModKeyState)697 UniCharsAndModifiers GetUniCharsAndModifiers( 698 uint8_t aVirtualKey, const ModifierKeyState& aModKeyState) const { 699 VirtualKey::ShiftState shiftState = 700 VirtualKey::ModifierKeyStateToShiftState(aModKeyState); 701 return GetUniCharsAndModifiers(aVirtualKey, shiftState); 702 } 703 704 /** 705 * GetNativeUniCharsAndModifiers() returns characters which are inputted by 706 * aVirtualKey with aModKeyState. The method isn't stateful. 707 * Note that different from GetUniCharsAndModifiers(), this returns 708 * actual modifier state of Ctrl and Alt. 709 */ 710 UniCharsAndModifiers GetNativeUniCharsAndModifiers( 711 uint8_t aVirtualKey, const ModifierKeyState& aModKeyState) const; 712 713 /** 714 * OnLayoutChange() must be called before the first keydown message is 715 * received. LoadLayout() changes the keyboard state, that causes breaking 716 * dead key state. Therefore, we need to load the layout before the first 717 * keydown message. 718 */ OnLayoutChange(HKL aKeyboardLayout)719 void OnLayoutChange(HKL aKeyboardLayout) { 720 MOZ_ASSERT(!mIsOverridden); 721 LoadLayout(aKeyboardLayout); 722 } 723 724 /** 725 * OverrideLayout() loads the specified keyboard layout. 726 */ OverrideLayout(HKL aLayout)727 void OverrideLayout(HKL aLayout) { 728 mIsOverridden = true; 729 LoadLayout(aLayout); 730 } 731 732 /** 733 * RestoreLayout() loads the current keyboard layout of the thread. 734 */ RestoreLayout()735 void RestoreLayout() { 736 mIsOverridden = false; 737 mIsPendingToRestoreKeyboardLayout = true; 738 } 739 740 uint32_t ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const; 741 742 /** 743 * ConvertNativeKeyCodeToKeyNameIndex() returns KeyNameIndex value for 744 * non-printable keys (except some special keys like space key). 745 */ 746 KeyNameIndex ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const; 747 748 /** 749 * ConvertScanCodeToCodeNameIndex() returns CodeNameIndex value for 750 * the given scan code. aScanCode can be over 0xE000 since this method 751 * doesn't use Windows API. 752 */ 753 static CodeNameIndex ConvertScanCodeToCodeNameIndex(UINT aScanCode); 754 GetLayout()755 HKL GetLayout() const { 756 return mIsPendingToRestoreKeyboardLayout ? ::GetKeyboardLayout(0) 757 : mKeyboardLayout; 758 } 759 760 /** 761 * This wraps MapVirtualKeyEx() API with MAPVK_VK_TO_VSC. 762 */ 763 WORD ComputeScanCodeForVirtualKeyCode(uint8_t aVirtualKeyCode) const; 764 765 /** 766 * Implementation of nsIWidget::SynthesizeNativeKeyEvent(). 767 */ 768 nsresult SynthesizeNativeKeyEvent(nsWindowBase* aWidget, 769 int32_t aNativeKeyboardLayout, 770 int32_t aNativeKeyCode, 771 uint32_t aModifierFlags, 772 const nsAString& aCharacters, 773 const nsAString& aUnmodifiedCharacters); 774 775 private: 776 KeyboardLayout(); 777 ~KeyboardLayout(); 778 779 static KeyboardLayout* sInstance; 780 static nsIIdleServiceInternal* sIdleService; 781 782 struct DeadKeyTableListEntry { 783 DeadKeyTableListEntry* next; 784 uint8_t data[1]; 785 }; 786 787 HKL mKeyboardLayout; 788 789 VirtualKey mVirtualKeys[NS_NUM_OF_KEYS]; 790 DeadKeyTableListEntry* mDeadKeyTableListHead; 791 // When mActiveDeadKeys is empty, it's not in dead key sequence. 792 // Otherwise, it contains virtual keycodes which are pressed in current 793 // dead key sequence. 794 nsTArray<uint8_t> mActiveDeadKeys; 795 // mDeadKeyShiftStates is always same length as mActiveDeadKeys. 796 // This stores shift states at pressing each dead key stored in 797 // mActiveDeadKeys. 798 nsTArray<VirtualKey::ShiftState> mDeadKeyShiftStates; 799 800 bool mIsOverridden; 801 bool mIsPendingToRestoreKeyboardLayout; 802 803 static inline int32_t GetKeyIndex(uint8_t aVirtualKey); 804 static int CompareDeadKeyEntries(const void* aArg1, const void* aArg2, 805 void* aData); 806 static bool AddDeadKeyEntry(char16_t aBaseChar, char16_t aCompositeChar, 807 DeadKeyEntry* aDeadKeyArray, uint32_t aEntries); 808 bool EnsureDeadKeyActive(bool aIsActive, uint8_t aDeadKey, 809 const PBYTE aDeadKeyKbdState); 810 uint32_t GetDeadKeyCombinations(uint8_t aDeadKey, 811 const PBYTE aDeadKeyKbdState, 812 uint16_t aShiftStatesWithBaseChars, 813 DeadKeyEntry* aDeadKeyArray, 814 uint32_t aMaxEntries); 815 /** 816 * Activates or deactivates dead key state. 817 */ 818 void ActivateDeadKeyState(const NativeKey& aNativeKey, 819 const ModifierKeyState& aModKeyState); 820 void DeactivateDeadKeyState(); 821 822 const DeadKeyTable* AddDeadKeyTable(const DeadKeyEntry* aDeadKeyArray, 823 uint32_t aEntries); 824 void ReleaseDeadKeyTables(); 825 826 /** 827 * Loads the specified keyboard layout. This method always clear the dead key 828 * state. 829 */ 830 void LoadLayout(HKL aLayout); 831 832 /** 833 * Gets the keyboard layout name of aLayout. Be careful, this may be too 834 * slow to call at handling user input. 835 */ 836 nsCString GetLayoutName(HKL aLayout) const; 837 838 /** 839 * InitNativeKey() must be called when actually widget receives WM_KEYDOWN or 840 * WM_KEYUP. This method is stateful. This saves current dead key state at 841 * WM_KEYDOWN. Additionally, computes current inputted character(s) and set 842 * them to the aNativeKey. 843 */ 844 void InitNativeKey(NativeKey& aNativeKey, 845 const ModifierKeyState& aModKeyState); 846 847 /** 848 * MaybeInitNativeKeyAsDeadKey() initializes aNativeKey only when aNativeKey 849 * is a dead key's event. 850 * When it's not in a dead key sequence, this activates the dead key state. 851 * When it's in a dead key sequence, this initializes aNativeKey with a 852 * composite character or a preceding dead char and a dead char which should 853 * be caused by aNativeKey. 854 * Returns true when this initializes aNativeKey. Otherwise, false. 855 */ 856 bool MaybeInitNativeKeyAsDeadKey(NativeKey& aNativeKey, 857 const ModifierKeyState& aModKeyState); 858 859 /** 860 * MaybeInitNativeKeyWithCompositeChar() may initialize aNativeKey with 861 * proper composite character when dead key produces a composite character. 862 * Otherwise, just returns false. 863 */ 864 bool MaybeInitNativeKeyWithCompositeChar( 865 NativeKey& aNativeKey, const ModifierKeyState& aModKeyState); 866 867 /** 868 * See the comment of GetUniCharsAndModifiers() below. 869 */ 870 UniCharsAndModifiers GetUniCharsAndModifiers( 871 uint8_t aVirtualKey, VirtualKey::ShiftState aShiftState) const; 872 873 /** 874 * GetDeadUniCharsAndModifiers() returns dead chars which are stored in 875 * current dead key sequence. So, this is stateful. 876 */ 877 UniCharsAndModifiers GetDeadUniCharsAndModifiers() const; 878 879 /** 880 * GetCompositeChar() returns a composite character with dead character 881 * caused by mActiveDeadKeys, mDeadKeyShiftStates and a base character 882 * (aBaseChar). 883 * If the combination of the dead character and the base character doesn't 884 * cause a composite character, this returns 0. 885 */ 886 char16_t GetCompositeChar(char16_t aBaseChar) const; 887 888 // NativeKey class should access InitNativeKey() directly, but it shouldn't 889 // be available outside of NativeKey. So, let's make NativeKey a friend 890 // class of this. 891 friend class NativeKey; 892 }; 893 894 class RedirectedKeyDownMessageManager { 895 public: 896 /* 897 * If a window receives WM_KEYDOWN message or WM_SYSKEYDOWM message which is 898 * a redirected message, NativeKey::DispatchKeyDownAndKeyPressEvent() 899 * prevents to dispatch eKeyDown event because it has been dispatched 900 * before the message was redirected. However, in some cases, WM_*KEYDOWN 901 * message handler may not handle actually. Then, the message handler needs 902 * to forget the redirected message and remove WM_CHAR message or WM_SYSCHAR 903 * message for the redirected keydown message. AutoFlusher class is a helper 904 * class for doing it. This must be created in the stack. 905 */ 906 class MOZ_STACK_CLASS AutoFlusher final { 907 public: AutoFlusher(nsWindowBase * aWidget,const MSG & aMsg)908 AutoFlusher(nsWindowBase* aWidget, const MSG& aMsg) 909 : mCancel(!RedirectedKeyDownMessageManager::IsRedirectedMessage(aMsg)), 910 mWidget(aWidget), 911 mMsg(aMsg) {} 912 ~AutoFlusher()913 ~AutoFlusher() { 914 if (mCancel) { 915 return; 916 } 917 // Prevent unnecessary keypress event 918 if (!mWidget->Destroyed()) { 919 RedirectedKeyDownMessageManager::RemoveNextCharMessage(mMsg.hwnd); 920 } 921 // Foreget the redirected message 922 RedirectedKeyDownMessageManager::Forget(); 923 } 924 Cancel()925 void Cancel() { mCancel = true; } 926 927 private: 928 bool mCancel; 929 RefPtr<nsWindowBase> mWidget; 930 const MSG& mMsg; 931 }; 932 WillRedirect(const MSG & aMsg,bool aDefualtPrevented)933 static void WillRedirect(const MSG& aMsg, bool aDefualtPrevented) { 934 sRedirectedKeyDownMsg = aMsg; 935 sDefaultPreventedOfRedirectedMsg = aDefualtPrevented; 936 } 937 Forget()938 static void Forget() { sRedirectedKeyDownMsg.message = WM_NULL; } 939 PreventDefault()940 static void PreventDefault() { sDefaultPreventedOfRedirectedMsg = true; } DefaultPrevented()941 static bool DefaultPrevented() { return sDefaultPreventedOfRedirectedMsg; } 942 943 static bool IsRedirectedMessage(const MSG& aMsg); 944 945 /** 946 * RemoveNextCharMessage() should be called by WM_KEYDOWN or WM_SYSKEYDOWM 947 * message handler. If there is no WM_(SYS)CHAR message for it, this 948 * method does nothing. 949 * NOTE: WM_(SYS)CHAR message is posted by TranslateMessage() API which is 950 * called in message loop. So, WM_(SYS)KEYDOWN message should have 951 * WM_(SYS)CHAR message in the queue if the keydown event causes character 952 * input. 953 */ 954 static void RemoveNextCharMessage(HWND aWnd); 955 956 private: 957 // sRedirectedKeyDownMsg is WM_KEYDOWN message or WM_SYSKEYDOWN message which 958 // is reirected with SendInput() API by 959 // widget::NativeKey::DispatchKeyDownAndKeyPressEvent() 960 static MSG sRedirectedKeyDownMsg; 961 static bool sDefaultPreventedOfRedirectedMsg; 962 }; 963 964 } // namespace widget 965 } // namespace mozilla 966 967 #endif 968