widget/windows/KeyboardLayout.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #ifndef KeyboardLayout_h__
michael@0 7 #define KeyboardLayout_h__
michael@0 8
michael@0 9 #include "nscore.h"
michael@0 10 #include "nsAutoPtr.h"
michael@0 11 #include "nsString.h"
michael@0 12 #include "nsWindowBase.h"
michael@0 13 #include "nsWindowDefs.h"
michael@0 14 #include "mozilla/Attributes.h"
michael@0 15 #include "mozilla/EventForwards.h"
michael@0 16 #include <windows.h>
michael@0 17
michael@0 18 #define NS_NUM_OF_KEYS 70
michael@0 19
michael@0 20 #define VK_OEM_1 0xBA // ';:' for US
michael@0 21 #define VK_OEM_PLUS 0xBB // '+' any country
michael@0 22 #define VK_OEM_COMMA 0xBC
michael@0 23 #define VK_OEM_MINUS 0xBD // '-' any country
michael@0 24 #define VK_OEM_PERIOD 0xBE
michael@0 25 #define VK_OEM_2 0xBF
michael@0 26 #define VK_OEM_3 0xC0
michael@0 27 // '/?' for Brazilian (ABNT)
michael@0 28 #define VK_ABNT_C1 0xC1
michael@0 29 // Separator in Numpad for Brazilian (ABNT) or JIS keyboard for Mac.
michael@0 30 #define VK_ABNT_C2 0xC2
michael@0 31 #define VK_OEM_4 0xDB
michael@0 32 #define VK_OEM_5 0xDC
michael@0 33 #define VK_OEM_6 0xDD
michael@0 34 #define VK_OEM_7 0xDE
michael@0 35 #define VK_OEM_8 0xDF
michael@0 36 #define VK_OEM_102 0xE2
michael@0 37 #define VK_OEM_CLEAR 0xFE
michael@0 38
michael@0 39 class nsIIdleServiceInternal;
michael@0 40 struct nsModifierKeyState;
michael@0 41
michael@0 42 namespace mozilla {
michael@0 43 namespace widget {
michael@0 44
michael@0 45 static const uint32_t sModifierKeyMap[][3] = {
michael@0 46 { nsIWidget::CAPS_LOCK, VK_CAPITAL, 0 },
michael@0 47 { nsIWidget::NUM_LOCK, VK_NUMLOCK, 0 },
michael@0 48 { nsIWidget::SHIFT_L, VK_SHIFT, VK_LSHIFT },
michael@0 49 { nsIWidget::SHIFT_R, VK_SHIFT, VK_RSHIFT },
michael@0 50 { nsIWidget::CTRL_L, VK_CONTROL, VK_LCONTROL },
michael@0 51 { nsIWidget::CTRL_R, VK_CONTROL, VK_RCONTROL },
michael@0 52 { nsIWidget::ALT_L, VK_MENU, VK_LMENU },
michael@0 53 { nsIWidget::ALT_R, VK_MENU, VK_RMENU }
michael@0 54 };
michael@0 55
michael@0 56 class KeyboardLayout;
michael@0 57
michael@0 58 class ModifierKeyState
michael@0 59 {
michael@0 60 public:
michael@0 61 ModifierKeyState();
michael@0 62 ModifierKeyState(bool aIsShiftDown, bool aIsControlDown, bool aIsAltDown);
michael@0 63 ModifierKeyState(Modifiers aModifiers);
michael@0 64
michael@0 65 MOZ_ALWAYS_INLINE void Update();
michael@0 66
michael@0 67 MOZ_ALWAYS_INLINE void Unset(Modifiers aRemovingModifiers);
michael@0 68 void Set(Modifiers aAddingModifiers);
michael@0 69
michael@0 70 void InitInputEvent(WidgetInputEvent& aInputEvent) const;
michael@0 71
michael@0 72 bool IsShift() const;
michael@0 73 bool IsControl() const;
michael@0 74 MOZ_ALWAYS_INLINE bool IsAlt() const;
michael@0 75 MOZ_ALWAYS_INLINE bool IsAltGr() const;
michael@0 76 MOZ_ALWAYS_INLINE bool IsWin() const;
michael@0 77
michael@0 78 MOZ_ALWAYS_INLINE bool IsCapsLocked() const;
michael@0 79 MOZ_ALWAYS_INLINE bool IsNumLocked() const;
michael@0 80 MOZ_ALWAYS_INLINE bool IsScrollLocked() const;
michael@0 81
michael@0 82 MOZ_ALWAYS_INLINE Modifiers GetModifiers() const;
michael@0 83
michael@0 84 private:
michael@0 85 Modifiers mModifiers;
michael@0 86
michael@0 87 MOZ_ALWAYS_INLINE void EnsureAltGr();
michael@0 88
michael@0 89 void InitMouseEvent(WidgetInputEvent& aMouseEvent) const;
michael@0 90 };
michael@0 91
michael@0 92 struct UniCharsAndModifiers
michael@0 93 {
michael@0 94 // Dead-key + up to 4 characters
michael@0 95 char16_t mChars[5];
michael@0 96 Modifiers mModifiers[5];
michael@0 97 uint32_t mLength;
michael@0 98
michael@0 99 UniCharsAndModifiers() : mLength(0) {}
michael@0 100 UniCharsAndModifiers operator+(const UniCharsAndModifiers& aOther) const;
michael@0 101 UniCharsAndModifiers& operator+=(const UniCharsAndModifiers& aOther);
michael@0 102
michael@0 103 /**
michael@0 104 * Append a pair of unicode character and the final modifier.
michael@0 105 */
michael@0 106 void Append(char16_t aUniChar, Modifiers aModifiers);
michael@0 107 void Clear() { mLength = 0; }
michael@0 108 bool IsEmpty() const { return !mLength; }
michael@0 109
michael@0 110 void FillModifiers(Modifiers aModifiers);
michael@0 111
michael@0 112 bool UniCharsEqual(const UniCharsAndModifiers& aOther) const;
michael@0 113 bool UniCharsCaseInsensitiveEqual(const UniCharsAndModifiers& aOther) const;
michael@0 114
michael@0 115 nsString ToString() const { return nsString(mChars, mLength); }
michael@0 116 };
michael@0 117
michael@0 118 struct DeadKeyEntry;
michael@0 119 class DeadKeyTable;
michael@0 120
michael@0 121
michael@0 122 class VirtualKey
michael@0 123 {
michael@0 124 public:
michael@0 125 // 0 - Normal
michael@0 126 // 1 - Shift
michael@0 127 // 2 - Control
michael@0 128 // 3 - Control + Shift
michael@0 129 // 4 - Alt
michael@0 130 // 5 - Alt + Shift
michael@0 131 // 6 - Alt + Control (AltGr)
michael@0 132 // 7 - Alt + Control + Shift (AltGr + Shift)
michael@0 133 // 8 - CapsLock
michael@0 134 // 9 - CapsLock + Shift
michael@0 135 // 10 - CapsLock + Control
michael@0 136 // 11 - CapsLock + Control + Shift
michael@0 137 // 12 - CapsLock + Alt
michael@0 138 // 13 - CapsLock + Alt + Shift
michael@0 139 // 14 - CapsLock + Alt + Control (CapsLock + AltGr)
michael@0 140 // 15 - CapsLock + Alt + Control + Shift (CapsLock + AltGr + Shift)
michael@0 141
michael@0 142 enum ShiftStateFlag
michael@0 143 {
michael@0 144 STATE_SHIFT = 0x01,
michael@0 145 STATE_CONTROL = 0x02,
michael@0 146 STATE_ALT = 0x04,
michael@0 147 STATE_CAPSLOCK = 0x08
michael@0 148 };
michael@0 149
michael@0 150 typedef uint8_t ShiftState;
michael@0 151
michael@0 152 static ShiftState ModifiersToShiftState(Modifiers aModifiers);
michael@0 153 static Modifiers ShiftStateToModifiers(ShiftState aShiftState);
michael@0 154
michael@0 155 private:
michael@0 156 union KeyShiftState
michael@0 157 {
michael@0 158 struct
michael@0 159 {
michael@0 160 char16_t Chars[4];
michael@0 161 } Normal;
michael@0 162 struct
michael@0 163 {
michael@0 164 const DeadKeyTable* Table;
michael@0 165 char16_t DeadChar;
michael@0 166 } DeadKey;
michael@0 167 };
michael@0 168
michael@0 169 KeyShiftState mShiftStates[16];
michael@0 170 uint16_t mIsDeadKey;
michael@0 171
michael@0 172 void SetDeadKey(ShiftState aShiftState, bool aIsDeadKey)
michael@0 173 {
michael@0 174 if (aIsDeadKey) {
michael@0 175 mIsDeadKey |= 1 << aShiftState;
michael@0 176 } else {
michael@0 177 mIsDeadKey &= ~(1 << aShiftState);
michael@0 178 }
michael@0 179 }
michael@0 180
michael@0 181 public:
michael@0 182 static void FillKbdState(PBYTE aKbdState, const ShiftState aShiftState);
michael@0 183
michael@0 184 bool IsDeadKey(ShiftState aShiftState) const
michael@0 185 {
michael@0 186 return (mIsDeadKey & (1 << aShiftState)) != 0;
michael@0 187 }
michael@0 188
michael@0 189 void AttachDeadKeyTable(ShiftState aShiftState,
michael@0 190 const DeadKeyTable* aDeadKeyTable)
michael@0 191 {
michael@0 192 mShiftStates[aShiftState].DeadKey.Table = aDeadKeyTable;
michael@0 193 }
michael@0 194
michael@0 195 void SetNormalChars(ShiftState aShiftState, const char16_t* aChars,
michael@0 196 uint32_t aNumOfChars);
michael@0 197 void SetDeadChar(ShiftState aShiftState, char16_t aDeadChar);
michael@0 198 const DeadKeyTable* MatchingDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
michael@0 199 uint32_t aEntries) const;
michael@0 200 inline char16_t GetCompositeChar(ShiftState aShiftState,
michael@0 201 char16_t aBaseChar) const;
michael@0 202 UniCharsAndModifiers GetNativeUniChars(ShiftState aShiftState) const;
michael@0 203 UniCharsAndModifiers GetUniChars(ShiftState aShiftState) const;
michael@0 204 };
michael@0 205
michael@0 206 class MOZ_STACK_CLASS NativeKey
michael@0 207 {
michael@0 208 friend class KeyboardLayout;
michael@0 209
michael@0 210 public:
michael@0 211 struct FakeCharMsg
michael@0 212 {
michael@0 213 UINT mCharCode;
michael@0 214 UINT mScanCode;
michael@0 215 bool mIsDeadKey;
michael@0 216 bool mConsumed;
michael@0 217
michael@0 218 FakeCharMsg() :
michael@0 219 mCharCode(0), mScanCode(0), mIsDeadKey(false), mConsumed(false)
michael@0 220 {
michael@0 221 }
michael@0 222
michael@0 223 MSG GetCharMsg(HWND aWnd) const
michael@0 224 {
michael@0 225 MSG msg;
michael@0 226 msg.hwnd = aWnd;
michael@0 227 msg.message = mIsDeadKey ? WM_DEADCHAR : WM_CHAR;
michael@0 228 msg.wParam = static_cast<WPARAM>(mCharCode);
michael@0 229 msg.lParam = static_cast<LPARAM>(mScanCode << 16);
michael@0 230 msg.time = 0;
michael@0 231 msg.pt.x = msg.pt.y = 0;
michael@0 232 return msg;
michael@0 233 }
michael@0 234 };
michael@0 235
michael@0 236 NativeKey(nsWindowBase* aWidget,
michael@0 237 const MSG& aKeyOrCharMessage,
michael@0 238 const ModifierKeyState& aModKeyState,
michael@0 239 nsTArray<FakeCharMsg>* aFakeCharMsgs = nullptr);
michael@0 240
michael@0 241 /**
michael@0 242 * Handle WM_KEYDOWN message or WM_SYSKEYDOWN message. The instance must be
michael@0 243 * initialized with WM_KEYDOWN or WM_SYSKEYDOWN.
michael@0 244 * Returns true if dispatched keydown event or keypress event is consumed.
michael@0 245 * Otherwise, false.
michael@0 246 */
michael@0 247 bool HandleKeyDownMessage(bool* aEventDispatched = nullptr) const;
michael@0 248
michael@0 249 /**
michael@0 250 * Handles WM_CHAR message or WM_SYSCHAR message. The instance must be
michael@0 251 * initialized with WM_KEYDOWN, WM_SYSKEYDOWN or them.
michael@0 252 * Returns true if dispatched keypress event is consumed. Otherwise, false.
michael@0 253 */
michael@0 254 bool HandleCharMessage(const MSG& aCharMsg,
michael@0 255 bool* aEventDispatched = nullptr) const;
michael@0 256
michael@0 257 /**
michael@0 258 * Handles keyup message. Returns true if the event is consumed.
michael@0 259 * Otherwise, false.
michael@0 260 */
michael@0 261 bool HandleKeyUpMessage(bool* aEventDispatched = nullptr) const;
michael@0 262
michael@0 263 private:
michael@0 264 nsRefPtr<nsWindowBase> mWidget;
michael@0 265 HKL mKeyboardLayout;
michael@0 266 MSG mMsg;
michael@0 267
michael@0 268 uint32_t mDOMKeyCode;
michael@0 269 KeyNameIndex mKeyNameIndex;
michael@0 270
michael@0 271 ModifierKeyState mModKeyState;
michael@0 272
michael@0 273 // mVirtualKeyCode distinguishes left key or right key of modifier key.
michael@0 274 uint8_t mVirtualKeyCode;
michael@0 275 // mOriginalVirtualKeyCode doesn't distinguish left key or right key of
michael@0 276 // modifier key. However, if the given keycode is VK_PROCESS, it's resolved
michael@0 277 // to a keycode before it's handled by IME.
michael@0 278 uint8_t mOriginalVirtualKeyCode;
michael@0 279
michael@0 280 // mCommittedChars indicates the inputted characters which is committed by
michael@0 281 // the key. If dead key fail to composite a character, mCommittedChars
michael@0 282 // indicates both the dead characters and the base characters.
michael@0 283 UniCharsAndModifiers mCommittedCharsAndModifiers;
michael@0 284
michael@0 285 WORD mScanCode;
michael@0 286 bool mIsExtended;
michael@0 287 bool mIsDeadKey;
michael@0 288 // mIsPrintableKey is true if the key may be a printable key without
michael@0 289 // any modifier keys. Otherwise, false.
michael@0 290 // Please note that the event may not cause any text input even if this
michael@0 291 // is true. E.g., it might be dead key state or Ctrl key may be pressed.
michael@0 292 bool mIsPrintableKey;
michael@0 293
michael@0 294 nsTArray<FakeCharMsg>* mFakeCharMsgs;
michael@0 295
michael@0 296 NativeKey()
michael@0 297 {
michael@0 298 MOZ_CRASH("The default constructor of NativeKey isn't available");
michael@0 299 }
michael@0 300
michael@0 301 /**
michael@0 302 * Returns true if the key event is caused by auto repeat.
michael@0 303 */
michael@0 304 bool IsRepeat() const
michael@0 305 {
michael@0 306 switch (mMsg.message) {
michael@0 307 case WM_KEYDOWN:
michael@0 308 case WM_SYSKEYDOWN:
michael@0 309 case WM_CHAR:
michael@0 310 case WM_SYSCHAR:
michael@0 311 case WM_DEADCHAR:
michael@0 312 case WM_SYSDEADCHAR:
michael@0 313 return ((mMsg.lParam & (1 << 30)) != 0);
michael@0 314 default:
michael@0 315 return false;
michael@0 316 }
michael@0 317 }
michael@0 318
michael@0 319 UINT GetScanCodeWithExtendedFlag() const;
michael@0 320
michael@0 321 // The result is one of nsIDOMKeyEvent::DOM_KEY_LOCATION_*.
michael@0 322 uint32_t GetKeyLocation() const;
michael@0 323
michael@0 324 /**
michael@0 325 * "Kakutei-Undo" of ATOK or WXG (both of them are Japanese IME) causes
michael@0 326 * strange WM_KEYDOWN/WM_KEYUP/WM_CHAR message pattern. So, when this
michael@0 327 * returns true, the caller needs to be careful for processing the messages.
michael@0 328 */
michael@0 329 bool IsIMEDoingKakuteiUndo() const;
michael@0 330
michael@0 331 bool IsKeyDownMessage() const
michael@0 332 {
michael@0 333 return (mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN);
michael@0 334 }
michael@0 335 bool IsKeyUpMessage() const
michael@0 336 {
michael@0 337 return (mMsg.message == WM_KEYUP || mMsg.message == WM_SYSKEYUP);
michael@0 338 }
michael@0 339 bool IsPrintableCharMessage(const MSG& aMSG) const
michael@0 340 {
michael@0 341 return IsPrintableCharMessage(aMSG.message);
michael@0 342 }
michael@0 343 bool IsPrintableCharMessage(UINT aMessage) const
michael@0 344 {
michael@0 345 return (aMessage == WM_CHAR || aMessage == WM_SYSCHAR);
michael@0 346 }
michael@0 347 bool IsCharMessage(const MSG& aMSG) const
michael@0 348 {
michael@0 349 return IsCharMessage(aMSG.message);
michael@0 350 }
michael@0 351 bool IsCharMessage(UINT aMessage) const
michael@0 352 {
michael@0 353 return (IsPrintableCharMessage(aMessage) || IsDeadCharMessage(aMessage));
michael@0 354 }
michael@0 355 bool IsDeadCharMessage(const MSG& aMSG) const
michael@0 356 {
michael@0 357 return IsDeadCharMessage(aMSG.message);
michael@0 358 }
michael@0 359 bool IsDeadCharMessage(UINT aMessage) const
michael@0 360 {
michael@0 361 return (aMessage == WM_DEADCHAR || aMessage == WM_SYSDEADCHAR);
michael@0 362 }
michael@0 363 bool IsSysCharMessage(const MSG& aMSG) const
michael@0 364 {
michael@0 365 return IsSysCharMessage(aMSG.message);
michael@0 366 }
michael@0 367 bool IsSysCharMessage(UINT aMessage) const
michael@0 368 {
michael@0 369 return (aMessage == WM_SYSCHAR || aMessage == WM_SYSDEADCHAR);
michael@0 370 }
michael@0 371 bool MayBeSameCharMessage(const MSG& aCharMsg1, const MSG& aCharMsg2) const;
michael@0 372 bool IsFollowedByDeadCharMessage() const;
michael@0 373
michael@0 374 /**
michael@0 375 * GetFollowingCharMessage() returns following char message of handling
michael@0 376 * keydown event. If the message is found, this method returns true.
michael@0 377 * Otherwise, returns false.
michael@0 378 *
michael@0 379 * WARNING: Even if this returns true, aCharMsg may be WM_NULL or its
michael@0 380 * hwnd may be different window.
michael@0 381 */
michael@0 382 bool GetFollowingCharMessage(MSG& aCharMsg) const;
michael@0 383
michael@0 384 /**
michael@0 385 * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK.
michael@0 386 */
michael@0 387 uint8_t ComputeVirtualKeyCodeFromScanCode() const;
michael@0 388
michael@0 389 /**
michael@0 390 * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK_EX.
michael@0 391 */
michael@0 392 uint8_t ComputeVirtualKeyCodeFromScanCodeEx() const;
michael@0 393
michael@0 394 /**
michael@0 395 * Wraps MapVirtualKeyEx() with MAPVK_VSC_TO_VK and MAPVK_VK_TO_CHAR.
michael@0 396 */
michael@0 397 char16_t ComputeUnicharFromScanCode() const;
michael@0 398
michael@0 399 /**
michael@0 400 * Initializes the aKeyEvent with the information stored in the instance.
michael@0 401 */
michael@0 402 void InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
michael@0 403 const ModifierKeyState& aModKeyState) const;
michael@0 404 void InitKeyEvent(WidgetKeyboardEvent& aKeyEvent) const;
michael@0 405
michael@0 406 /**
michael@0 407 * Dispatches the key event. Returns true if the event is consumed.
michael@0 408 * Otherwise, false.
michael@0 409 */
michael@0 410 bool DispatchKeyEvent(WidgetKeyboardEvent& aKeyEvent,
michael@0 411 const MSG* aMsgSentToPlugin = nullptr) const;
michael@0 412
michael@0 413 /**
michael@0 414 * DispatchKeyPressEventsWithKeyboardLayout() dispatches keypress event(s)
michael@0 415 * with the information provided by KeyboardLayout class.
michael@0 416 */
michael@0 417 bool DispatchKeyPressEventsWithKeyboardLayout() const;
michael@0 418
michael@0 419 /**
michael@0 420 * Remove all following WM_CHAR, WM_SYSCHAR and WM_DEADCHAR messages for the
michael@0 421 * WM_KEYDOWN or WM_SYSKEYDOWN message. Additionally, dispatches plugin
michael@0 422 * events if it's necessary.
michael@0 423 * Returns true if the widget is destroyed. Otherwise, false.
michael@0 424 */
michael@0 425 bool DispatchPluginEventsAndDiscardsCharMessages() const;
michael@0 426
michael@0 427 /**
michael@0 428 * DispatchKeyPressEventForFollowingCharMessage() dispatches keypress event
michael@0 429 * for following WM_*CHAR message which is removed and set to aCharMsg.
michael@0 430 * Returns true if the event is consumed. Otherwise, false.
michael@0 431 */
michael@0 432 bool DispatchKeyPressEventForFollowingCharMessage(const MSG& aCharMsg) const;
michael@0 433
michael@0 434 /**
michael@0 435 * Checkes whether the key event down message is handled without following
michael@0 436 * WM_CHAR messages. For example, if following WM_CHAR message indicates
michael@0 437 * control character input, the WM_CHAR message is unclear whether it's
michael@0 438 * caused by a printable key with Ctrl or just a function key such as Enter
michael@0 439 * or Backspace.
michael@0 440 */
michael@0 441 bool NeedsToHandleWithoutFollowingCharMessages() const;
michael@0 442 };
michael@0 443
michael@0 444 class KeyboardLayout
michael@0 445 {
michael@0 446 friend class NativeKey;
michael@0 447
michael@0 448 private:
michael@0 449 KeyboardLayout();
michael@0 450 ~KeyboardLayout();
michael@0 451
michael@0 452 static KeyboardLayout* sInstance;
michael@0 453 static nsIIdleServiceInternal* sIdleService;
michael@0 454
michael@0 455 struct DeadKeyTableListEntry
michael@0 456 {
michael@0 457 DeadKeyTableListEntry* next;
michael@0 458 uint8_t data[1];
michael@0 459 };
michael@0 460
michael@0 461 HKL mKeyboardLayout;
michael@0 462
michael@0 463 VirtualKey mVirtualKeys[NS_NUM_OF_KEYS];
michael@0 464 DeadKeyTableListEntry* mDeadKeyTableListHead;
michael@0 465 int32_t mActiveDeadKey; // -1 = no active dead-key
michael@0 466 VirtualKey::ShiftState mDeadKeyShiftState;
michael@0 467
michael@0 468 bool mIsOverridden : 1;
michael@0 469 bool mIsPendingToRestoreKeyboardLayout : 1;
michael@0 470
michael@0 471 static inline int32_t GetKeyIndex(uint8_t aVirtualKey);
michael@0 472 static int CompareDeadKeyEntries(const void* aArg1, const void* aArg2,
michael@0 473 void* aData);
michael@0 474 static bool AddDeadKeyEntry(char16_t aBaseChar, char16_t aCompositeChar,
michael@0 475 DeadKeyEntry* aDeadKeyArray, uint32_t aEntries);
michael@0 476 bool EnsureDeadKeyActive(bool aIsActive, uint8_t aDeadKey,
michael@0 477 const PBYTE aDeadKeyKbdState);
michael@0 478 uint32_t GetDeadKeyCombinations(uint8_t aDeadKey,
michael@0 479 const PBYTE aDeadKeyKbdState,
michael@0 480 uint16_t aShiftStatesWithBaseChars,
michael@0 481 DeadKeyEntry* aDeadKeyArray,
michael@0 482 uint32_t aMaxEntries);
michael@0 483 void DeactivateDeadKeyState();
michael@0 484 const DeadKeyTable* AddDeadKeyTable(const DeadKeyEntry* aDeadKeyArray,
michael@0 485 uint32_t aEntries);
michael@0 486 void ReleaseDeadKeyTables();
michael@0 487
michael@0 488 /**
michael@0 489 * Loads the specified keyboard layout. This method always clear the dead key
michael@0 490 * state.
michael@0 491 */
michael@0 492 void LoadLayout(HKL aLayout);
michael@0 493
michael@0 494 /**
michael@0 495 * InitNativeKey() must be called when actually widget receives WM_KEYDOWN or
michael@0 496 * WM_KEYUP. This method is stateful. This saves current dead key state at
michael@0 497 * WM_KEYDOWN. Additionally, computes current inputted character(s) and set
michael@0 498 * them to the aNativeKey.
michael@0 499 */
michael@0 500 void InitNativeKey(NativeKey& aNativeKey,
michael@0 501 const ModifierKeyState& aModKeyState);
michael@0 502
michael@0 503 public:
michael@0 504 static KeyboardLayout* GetInstance();
michael@0 505 static void Shutdown();
michael@0 506 static void NotifyIdleServiceOfUserActivity();
michael@0 507
michael@0 508 static bool IsPrintableCharKey(uint8_t aVirtualKey);
michael@0 509
michael@0 510 /**
michael@0 511 * IsDeadKey() returns true if aVirtualKey is a dead key with aModKeyState.
michael@0 512 * This method isn't stateful.
michael@0 513 */
michael@0 514 bool IsDeadKey(uint8_t aVirtualKey,
michael@0 515 const ModifierKeyState& aModKeyState) const;
michael@0 516
michael@0 517 /**
michael@0 518 * GetUniCharsAndModifiers() returns characters which is inputted by the
michael@0 519 * aVirtualKey with aModKeyState. This method isn't stateful.
michael@0 520 */
michael@0 521 UniCharsAndModifiers GetUniCharsAndModifiers(
michael@0 522 uint8_t aVirtualKey,
michael@0 523 const ModifierKeyState& aModKeyState) const;
michael@0 524
michael@0 525 /**
michael@0 526 * OnLayoutChange() must be called before the first keydown message is
michael@0 527 * received. LoadLayout() changes the keyboard state, that causes breaking
michael@0 528 * dead key state. Therefore, we need to load the layout before the first
michael@0 529 * keydown message.
michael@0 530 */
michael@0 531 void OnLayoutChange(HKL aKeyboardLayout)
michael@0 532 {
michael@0 533 MOZ_ASSERT(!mIsOverridden);
michael@0 534 LoadLayout(aKeyboardLayout);
michael@0 535 }
michael@0 536
michael@0 537 /**
michael@0 538 * OverrideLayout() loads the specified keyboard layout.
michael@0 539 */
michael@0 540 void OverrideLayout(HKL aLayout)
michael@0 541 {
michael@0 542 mIsOverridden = true;
michael@0 543 LoadLayout(aLayout);
michael@0 544 }
michael@0 545
michael@0 546 /**
michael@0 547 * RestoreLayout() loads the current keyboard layout of the thread.
michael@0 548 */
michael@0 549 void RestoreLayout()
michael@0 550 {
michael@0 551 mIsOverridden = false;
michael@0 552 mIsPendingToRestoreKeyboardLayout = true;
michael@0 553 }
michael@0 554
michael@0 555 uint32_t ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const;
michael@0 556
michael@0 557 /**
michael@0 558 * ConvertNativeKeyCodeToKeyNameIndex() returns KeyNameIndex value for
michael@0 559 * non-printable keys (except some special keys like space key).
michael@0 560 */
michael@0 561 KeyNameIndex ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const;
michael@0 562
michael@0 563 HKL GetLayout() const
michael@0 564 {
michael@0 565 return mIsPendingToRestoreKeyboardLayout ? ::GetKeyboardLayout(0) :
michael@0 566 mKeyboardLayout;
michael@0 567 }
michael@0 568
michael@0 569 /**
michael@0 570 * This wraps MapVirtualKeyEx() API with MAPVK_VK_TO_VSC.
michael@0 571 */
michael@0 572 WORD ComputeScanCodeForVirtualKeyCode(uint8_t aVirtualKeyCode) const;
michael@0 573
michael@0 574 /**
michael@0 575 * Implementation of nsIWidget::SynthesizeNativeKeyEvent().
michael@0 576 */
michael@0 577 nsresult SynthesizeNativeKeyEvent(nsWindowBase* aWidget,
michael@0 578 int32_t aNativeKeyboardLayout,
michael@0 579 int32_t aNativeKeyCode,
michael@0 580 uint32_t aModifierFlags,
michael@0 581 const nsAString& aCharacters,
michael@0 582 const nsAString& aUnmodifiedCharacters);
michael@0 583 };
michael@0 584
michael@0 585 class RedirectedKeyDownMessageManager
michael@0 586 {
michael@0 587 public:
michael@0 588 /*
michael@0 589 * If a window receives WM_KEYDOWN message or WM_SYSKEYDOWM message which is
michael@0 590 * a redirected message, NativeKey::DispatchKeyDownAndKeyPressEvent()
michael@0 591 * prevents to dispatch NS_KEY_DOWN event because it has been dispatched
michael@0 592 * before the message was redirected. However, in some cases, WM_*KEYDOWN
michael@0 593 * message handler may not handle actually. Then, the message handler needs
michael@0 594 * to forget the redirected message and remove WM_CHAR message or WM_SYSCHAR
michael@0 595 * message for the redirected keydown message. AutoFlusher class is a helper
michael@0 596 * class for doing it. This must be created in the stack.
michael@0 597 */
michael@0 598 class MOZ_STACK_CLASS AutoFlusher MOZ_FINAL
michael@0 599 {
michael@0 600 public:
michael@0 601 AutoFlusher(nsWindowBase* aWidget, const MSG &aMsg) :
michael@0 602 mCancel(!RedirectedKeyDownMessageManager::IsRedirectedMessage(aMsg)),
michael@0 603 mWidget(aWidget), mMsg(aMsg)
michael@0 604 {
michael@0 605 }
michael@0 606
michael@0 607 ~AutoFlusher()
michael@0 608 {
michael@0 609 if (mCancel) {
michael@0 610 return;
michael@0 611 }
michael@0 612 // Prevent unnecessary keypress event
michael@0 613 if (!mWidget->Destroyed()) {
michael@0 614 RedirectedKeyDownMessageManager::RemoveNextCharMessage(mMsg.hwnd);
michael@0 615 }
michael@0 616 // Foreget the redirected message
michael@0 617 RedirectedKeyDownMessageManager::Forget();
michael@0 618 }
michael@0 619
michael@0 620 void Cancel() { mCancel = true; }
michael@0 621
michael@0 622 private:
michael@0 623 bool mCancel;
michael@0 624 nsRefPtr<nsWindowBase> mWidget;
michael@0 625 const MSG &mMsg;
michael@0 626 };
michael@0 627
michael@0 628 static void WillRedirect(const MSG& aMsg, bool aDefualtPrevented)
michael@0 629 {
michael@0 630 sRedirectedKeyDownMsg = aMsg;
michael@0 631 sDefaultPreventedOfRedirectedMsg = aDefualtPrevented;
michael@0 632 }
michael@0 633
michael@0 634 static void Forget()
michael@0 635 {
michael@0 636 sRedirectedKeyDownMsg.message = WM_NULL;
michael@0 637 }
michael@0 638
michael@0 639 static void PreventDefault() { sDefaultPreventedOfRedirectedMsg = true; }
michael@0 640 static bool DefaultPrevented() { return sDefaultPreventedOfRedirectedMsg; }
michael@0 641
michael@0 642 static bool IsRedirectedMessage(const MSG& aMsg);
michael@0 643
michael@0 644 /**
michael@0 645 * RemoveNextCharMessage() should be called by WM_KEYDOWN or WM_SYSKEYDOWM
michael@0 646 * message handler. If there is no WM_(SYS)CHAR message for it, this
michael@0 647 * method does nothing.
michael@0 648 * NOTE: WM_(SYS)CHAR message is posted by TranslateMessage() API which is
michael@0 649 * called in message loop. So, WM_(SYS)KEYDOWN message should have
michael@0 650 * WM_(SYS)CHAR message in the queue if the keydown event causes character
michael@0 651 * input.
michael@0 652 */
michael@0 653 static void RemoveNextCharMessage(HWND aWnd);
michael@0 654
michael@0 655 private:
michael@0 656 // sRedirectedKeyDownMsg is WM_KEYDOWN message or WM_SYSKEYDOWN message which
michael@0 657 // is reirected with SendInput() API by
michael@0 658 // widget::NativeKey::DispatchKeyDownAndKeyPressEvent()
michael@0 659 static MSG sRedirectedKeyDownMsg;
michael@0 660 static bool sDefaultPreventedOfRedirectedMsg;
michael@0 661 };
michael@0 662
michael@0 663 } // namespace widget
michael@0 664 } // namespace mozilla
michael@0 665
michael@0 666 #endif

mercurial