1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/windows/KeyboardLayout.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2881 @@ 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 +#include "mozilla/ArrayUtils.h" 1.10 +#include "mozilla/DebugOnly.h" 1.11 +#include "mozilla/MouseEvents.h" 1.12 +#include "mozilla/TextEvents.h" 1.13 +#include "mozilla/WindowsVersion.h" 1.14 + 1.15 +#include "KeyboardLayout.h" 1.16 +#include "nsIMM32Handler.h" 1.17 + 1.18 +#include "nsMemory.h" 1.19 +#include "nsToolkit.h" 1.20 +#include "nsQuickSort.h" 1.21 +#include "nsAlgorithm.h" 1.22 +#include "nsUnicharUtils.h" 1.23 +#include "WidgetUtils.h" 1.24 +#include "WinUtils.h" 1.25 +#include "nsWindowDbg.h" 1.26 +#include "nsServiceManagerUtils.h" 1.27 +#include "nsPrintfCString.h" 1.28 + 1.29 +#include "nsIDOMKeyEvent.h" 1.30 +#include "nsIIdleServiceInternal.h" 1.31 + 1.32 +#ifdef MOZ_CRASHREPORTER 1.33 +#include "nsExceptionHandler.h" 1.34 +#endif 1.35 + 1.36 +#include "npapi.h" 1.37 + 1.38 +#include <windows.h> 1.39 +#include <winuser.h> 1.40 +#include <algorithm> 1.41 + 1.42 +#ifndef WINABLEAPI 1.43 +#include <winable.h> 1.44 +#endif 1.45 + 1.46 +namespace mozilla { 1.47 +namespace widget { 1.48 + 1.49 +// Unique id counter associated with a keydown / keypress events. Used in 1.50 +// identifing keypress events for removal from async event dispatch queue 1.51 +// in metrofx after preventDefault is called on keydown events. 1.52 +static uint32_t sUniqueKeyEventId = 0; 1.53 + 1.54 +struct DeadKeyEntry 1.55 +{ 1.56 + char16_t BaseChar; 1.57 + char16_t CompositeChar; 1.58 +}; 1.59 + 1.60 + 1.61 +class DeadKeyTable 1.62 +{ 1.63 + friend class KeyboardLayout; 1.64 + 1.65 + uint16_t mEntries; 1.66 + // KeyboardLayout::AddDeadKeyTable() will allocate as many entries as 1.67 + // required. It is the only way to create new DeadKeyTable instances. 1.68 + DeadKeyEntry mTable[1]; 1.69 + 1.70 + void Init(const DeadKeyEntry* aDeadKeyArray, uint32_t aEntries) 1.71 + { 1.72 + mEntries = aEntries; 1.73 + memcpy(mTable, aDeadKeyArray, aEntries * sizeof(DeadKeyEntry)); 1.74 + } 1.75 + 1.76 + static uint32_t SizeInBytes(uint32_t aEntries) 1.77 + { 1.78 + return offsetof(DeadKeyTable, mTable) + aEntries * sizeof(DeadKeyEntry); 1.79 + } 1.80 + 1.81 +public: 1.82 + uint32_t Entries() const 1.83 + { 1.84 + return mEntries; 1.85 + } 1.86 + 1.87 + bool IsEqual(const DeadKeyEntry* aDeadKeyArray, uint32_t aEntries) const 1.88 + { 1.89 + return (mEntries == aEntries && 1.90 + !memcmp(mTable, aDeadKeyArray, 1.91 + aEntries * sizeof(DeadKeyEntry))); 1.92 + } 1.93 + 1.94 + char16_t GetCompositeChar(char16_t aBaseChar) const; 1.95 +}; 1.96 + 1.97 + 1.98 +/***************************************************************************** 1.99 + * mozilla::widget::ModifierKeyState 1.100 + *****************************************************************************/ 1.101 + 1.102 +ModifierKeyState::ModifierKeyState() 1.103 +{ 1.104 + Update(); 1.105 +} 1.106 + 1.107 +ModifierKeyState::ModifierKeyState(bool aIsShiftDown, 1.108 + bool aIsControlDown, 1.109 + bool aIsAltDown) 1.110 +{ 1.111 + Update(); 1.112 + Unset(MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT | MODIFIER_ALTGRAPH); 1.113 + Modifiers modifiers = 0; 1.114 + if (aIsShiftDown) { 1.115 + modifiers |= MODIFIER_SHIFT; 1.116 + } 1.117 + if (aIsControlDown) { 1.118 + modifiers |= MODIFIER_CONTROL; 1.119 + } 1.120 + if (aIsAltDown) { 1.121 + modifiers |= MODIFIER_ALT; 1.122 + } 1.123 + if (modifiers) { 1.124 + Set(modifiers); 1.125 + } 1.126 +} 1.127 + 1.128 +ModifierKeyState::ModifierKeyState(Modifiers aModifiers) : 1.129 + mModifiers(aModifiers) 1.130 +{ 1.131 + EnsureAltGr(); 1.132 +} 1.133 + 1.134 +void 1.135 +ModifierKeyState::Update() 1.136 +{ 1.137 + mModifiers = 0; 1.138 + if (IS_VK_DOWN(VK_SHIFT)) { 1.139 + mModifiers |= MODIFIER_SHIFT; 1.140 + } 1.141 + if (IS_VK_DOWN(VK_CONTROL)) { 1.142 + mModifiers |= MODIFIER_CONTROL; 1.143 + } 1.144 + if (IS_VK_DOWN(VK_MENU)) { 1.145 + mModifiers |= MODIFIER_ALT; 1.146 + } 1.147 + if (IS_VK_DOWN(VK_LWIN) || IS_VK_DOWN(VK_RWIN)) { 1.148 + mModifiers |= MODIFIER_OS; 1.149 + } 1.150 + if (::GetKeyState(VK_CAPITAL) & 1) { 1.151 + mModifiers |= MODIFIER_CAPSLOCK; 1.152 + } 1.153 + if (::GetKeyState(VK_NUMLOCK) & 1) { 1.154 + mModifiers |= MODIFIER_NUMLOCK; 1.155 + } 1.156 + if (::GetKeyState(VK_SCROLL) & 1) { 1.157 + mModifiers |= MODIFIER_SCROLLLOCK; 1.158 + } 1.159 + 1.160 + EnsureAltGr(); 1.161 +} 1.162 + 1.163 +void 1.164 +ModifierKeyState::Unset(Modifiers aRemovingModifiers) 1.165 +{ 1.166 + mModifiers &= ~aRemovingModifiers; 1.167 + // Note that we don't need to unset AltGr flag here automatically. 1.168 + // For nsEditor, we need to remove Alt and Control flags but AltGr isn't 1.169 + // checked in nsEditor, so, it can be kept. 1.170 +} 1.171 + 1.172 +void 1.173 +ModifierKeyState::Set(Modifiers aAddingModifiers) 1.174 +{ 1.175 + mModifiers |= aAddingModifiers; 1.176 + EnsureAltGr(); 1.177 +} 1.178 + 1.179 +void 1.180 +ModifierKeyState::InitInputEvent(WidgetInputEvent& aInputEvent) const 1.181 +{ 1.182 + aInputEvent.modifiers = mModifiers; 1.183 + 1.184 + switch(aInputEvent.eventStructType) { 1.185 + case NS_MOUSE_EVENT: 1.186 + case NS_MOUSE_SCROLL_EVENT: 1.187 + case NS_WHEEL_EVENT: 1.188 + case NS_DRAG_EVENT: 1.189 + case NS_SIMPLE_GESTURE_EVENT: 1.190 + InitMouseEvent(aInputEvent); 1.191 + break; 1.192 + default: 1.193 + break; 1.194 + } 1.195 +} 1.196 + 1.197 +void 1.198 +ModifierKeyState::InitMouseEvent(WidgetInputEvent& aMouseEvent) const 1.199 +{ 1.200 + NS_ASSERTION(aMouseEvent.eventStructType == NS_MOUSE_EVENT || 1.201 + aMouseEvent.eventStructType == NS_WHEEL_EVENT || 1.202 + aMouseEvent.eventStructType == NS_DRAG_EVENT || 1.203 + aMouseEvent.eventStructType == NS_SIMPLE_GESTURE_EVENT, 1.204 + "called with non-mouse event"); 1.205 + 1.206 + if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) { 1.207 + // Buttons for immersive mode are handled in MetroInput. 1.208 + return; 1.209 + } 1.210 + 1.211 + WidgetMouseEventBase& mouseEvent = *aMouseEvent.AsMouseEventBase(); 1.212 + mouseEvent.buttons = 0; 1.213 + if (::GetKeyState(VK_LBUTTON) < 0) { 1.214 + mouseEvent.buttons |= WidgetMouseEvent::eLeftButtonFlag; 1.215 + } 1.216 + if (::GetKeyState(VK_RBUTTON) < 0) { 1.217 + mouseEvent.buttons |= WidgetMouseEvent::eRightButtonFlag; 1.218 + } 1.219 + if (::GetKeyState(VK_MBUTTON) < 0) { 1.220 + mouseEvent.buttons |= WidgetMouseEvent::eMiddleButtonFlag; 1.221 + } 1.222 + if (::GetKeyState(VK_XBUTTON1) < 0) { 1.223 + mouseEvent.buttons |= WidgetMouseEvent::e4thButtonFlag; 1.224 + } 1.225 + if (::GetKeyState(VK_XBUTTON2) < 0) { 1.226 + mouseEvent.buttons |= WidgetMouseEvent::e5thButtonFlag; 1.227 + } 1.228 +} 1.229 + 1.230 +bool 1.231 +ModifierKeyState::IsShift() const 1.232 +{ 1.233 + return (mModifiers & MODIFIER_SHIFT) != 0; 1.234 +} 1.235 + 1.236 +bool 1.237 +ModifierKeyState::IsControl() const 1.238 +{ 1.239 + return (mModifiers & MODIFIER_CONTROL) != 0; 1.240 +} 1.241 + 1.242 +bool 1.243 +ModifierKeyState::IsAlt() const 1.244 +{ 1.245 + return (mModifiers & MODIFIER_ALT) != 0; 1.246 +} 1.247 + 1.248 +bool 1.249 +ModifierKeyState::IsAltGr() const 1.250 +{ 1.251 + return IsControl() && IsAlt(); 1.252 +} 1.253 + 1.254 +bool 1.255 +ModifierKeyState::IsWin() const 1.256 +{ 1.257 + return (mModifiers & MODIFIER_OS) != 0; 1.258 +} 1.259 + 1.260 +bool 1.261 +ModifierKeyState::IsCapsLocked() const 1.262 +{ 1.263 + return (mModifiers & MODIFIER_CAPSLOCK) != 0; 1.264 +} 1.265 + 1.266 +bool 1.267 +ModifierKeyState::IsNumLocked() const 1.268 +{ 1.269 + return (mModifiers & MODIFIER_NUMLOCK) != 0; 1.270 +} 1.271 + 1.272 +bool 1.273 +ModifierKeyState::IsScrollLocked() const 1.274 +{ 1.275 + return (mModifiers & MODIFIER_SCROLLLOCK) != 0; 1.276 +} 1.277 + 1.278 +Modifiers 1.279 +ModifierKeyState::GetModifiers() const 1.280 +{ 1.281 + return mModifiers; 1.282 +} 1.283 + 1.284 +void 1.285 +ModifierKeyState::EnsureAltGr() 1.286 +{ 1.287 + // If both Control key and Alt key are pressed, it means AltGr is pressed. 1.288 + // Ideally, we should check whether the current keyboard layout has AltGr 1.289 + // or not. However, setting AltGr flags for keyboard which doesn't have 1.290 + // AltGr must not be serious bug. So, it should be OK for now. 1.291 + if (IsAltGr()) { 1.292 + mModifiers |= MODIFIER_ALTGRAPH; 1.293 + } 1.294 +} 1.295 + 1.296 +/***************************************************************************** 1.297 + * mozilla::widget::UniCharsAndModifiers 1.298 + *****************************************************************************/ 1.299 + 1.300 +void 1.301 +UniCharsAndModifiers::Append(char16_t aUniChar, Modifiers aModifiers) 1.302 +{ 1.303 + MOZ_ASSERT(mLength < 5); 1.304 + mChars[mLength] = aUniChar; 1.305 + mModifiers[mLength] = aModifiers; 1.306 + mLength++; 1.307 +} 1.308 + 1.309 +void 1.310 +UniCharsAndModifiers::FillModifiers(Modifiers aModifiers) 1.311 +{ 1.312 + for (uint32_t i = 0; i < mLength; i++) { 1.313 + mModifiers[i] = aModifiers; 1.314 + } 1.315 +} 1.316 + 1.317 +bool 1.318 +UniCharsAndModifiers::UniCharsEqual(const UniCharsAndModifiers& aOther) const 1.319 +{ 1.320 + if (mLength != aOther.mLength) { 1.321 + return false; 1.322 + } 1.323 + return !memcmp(mChars, aOther.mChars, mLength * sizeof(char16_t)); 1.324 +} 1.325 + 1.326 +bool 1.327 +UniCharsAndModifiers::UniCharsCaseInsensitiveEqual( 1.328 + const UniCharsAndModifiers& aOther) const 1.329 +{ 1.330 + if (mLength != aOther.mLength) { 1.331 + return false; 1.332 + } 1.333 + 1.334 + nsCaseInsensitiveStringComparator comp; 1.335 + return !comp(mChars, aOther.mChars, mLength, aOther.mLength); 1.336 +} 1.337 + 1.338 +UniCharsAndModifiers& 1.339 +UniCharsAndModifiers::operator+=(const UniCharsAndModifiers& aOther) 1.340 +{ 1.341 + uint32_t copyCount = std::min(aOther.mLength, 5 - mLength); 1.342 + NS_ENSURE_TRUE(copyCount > 0, *this); 1.343 + memcpy(&mChars[mLength], aOther.mChars, copyCount * sizeof(char16_t)); 1.344 + memcpy(&mModifiers[mLength], aOther.mModifiers, 1.345 + copyCount * sizeof(Modifiers)); 1.346 + mLength += copyCount; 1.347 + return *this; 1.348 +} 1.349 + 1.350 +UniCharsAndModifiers 1.351 +UniCharsAndModifiers::operator+(const UniCharsAndModifiers& aOther) const 1.352 +{ 1.353 + UniCharsAndModifiers result(*this); 1.354 + result += aOther; 1.355 + return result; 1.356 +} 1.357 + 1.358 +/***************************************************************************** 1.359 + * mozilla::widget::VirtualKey 1.360 + *****************************************************************************/ 1.361 + 1.362 +// static 1.363 +VirtualKey::ShiftState 1.364 +VirtualKey::ModifiersToShiftState(Modifiers aModifiers) 1.365 +{ 1.366 + ShiftState state = 0; 1.367 + if (aModifiers & MODIFIER_SHIFT) { 1.368 + state |= STATE_SHIFT; 1.369 + } 1.370 + if (aModifiers & MODIFIER_CONTROL) { 1.371 + state |= STATE_CONTROL; 1.372 + } 1.373 + if (aModifiers & MODIFIER_ALT) { 1.374 + state |= STATE_ALT; 1.375 + } 1.376 + if (aModifiers & MODIFIER_CAPSLOCK) { 1.377 + state |= STATE_CAPSLOCK; 1.378 + } 1.379 + return state; 1.380 +} 1.381 + 1.382 +// static 1.383 +Modifiers 1.384 +VirtualKey::ShiftStateToModifiers(ShiftState aShiftState) 1.385 +{ 1.386 + Modifiers modifiers = 0; 1.387 + if (aShiftState & STATE_SHIFT) { 1.388 + modifiers |= MODIFIER_SHIFT; 1.389 + } 1.390 + if (aShiftState & STATE_CONTROL) { 1.391 + modifiers |= MODIFIER_CONTROL; 1.392 + } 1.393 + if (aShiftState & STATE_ALT) { 1.394 + modifiers |= MODIFIER_ALT; 1.395 + } 1.396 + if (aShiftState & STATE_CAPSLOCK) { 1.397 + modifiers |= MODIFIER_CAPSLOCK; 1.398 + } 1.399 + if ((modifiers & (MODIFIER_ALT | MODIFIER_CONTROL)) == 1.400 + (MODIFIER_ALT | MODIFIER_CONTROL)) { 1.401 + modifiers |= MODIFIER_ALTGRAPH; 1.402 + } 1.403 + return modifiers; 1.404 +} 1.405 + 1.406 +inline char16_t 1.407 +VirtualKey::GetCompositeChar(ShiftState aShiftState, char16_t aBaseChar) const 1.408 +{ 1.409 + return mShiftStates[aShiftState].DeadKey.Table->GetCompositeChar(aBaseChar); 1.410 +} 1.411 + 1.412 +const DeadKeyTable* 1.413 +VirtualKey::MatchingDeadKeyTable(const DeadKeyEntry* aDeadKeyArray, 1.414 + uint32_t aEntries) const 1.415 +{ 1.416 + if (!mIsDeadKey) { 1.417 + return nullptr; 1.418 + } 1.419 + 1.420 + for (ShiftState shiftState = 0; shiftState < 16; shiftState++) { 1.421 + if (!IsDeadKey(shiftState)) { 1.422 + continue; 1.423 + } 1.424 + const DeadKeyTable* dkt = mShiftStates[shiftState].DeadKey.Table; 1.425 + if (dkt && dkt->IsEqual(aDeadKeyArray, aEntries)) { 1.426 + return dkt; 1.427 + } 1.428 + } 1.429 + 1.430 + return nullptr; 1.431 +} 1.432 + 1.433 +void 1.434 +VirtualKey::SetNormalChars(ShiftState aShiftState, 1.435 + const char16_t* aChars, 1.436 + uint32_t aNumOfChars) 1.437 +{ 1.438 + NS_ASSERTION(aShiftState < ArrayLength(mShiftStates), "invalid index"); 1.439 + 1.440 + SetDeadKey(aShiftState, false); 1.441 + 1.442 + for (uint32_t index = 0; index < aNumOfChars; index++) { 1.443 + // Ignore legacy non-printable control characters 1.444 + mShiftStates[aShiftState].Normal.Chars[index] = 1.445 + (aChars[index] >= 0x20) ? aChars[index] : 0; 1.446 + } 1.447 + 1.448 + uint32_t len = ArrayLength(mShiftStates[aShiftState].Normal.Chars); 1.449 + for (uint32_t index = aNumOfChars; index < len; index++) { 1.450 + mShiftStates[aShiftState].Normal.Chars[index] = 0; 1.451 + } 1.452 +} 1.453 + 1.454 +void 1.455 +VirtualKey::SetDeadChar(ShiftState aShiftState, char16_t aDeadChar) 1.456 +{ 1.457 + NS_ASSERTION(aShiftState < ArrayLength(mShiftStates), "invalid index"); 1.458 + 1.459 + SetDeadKey(aShiftState, true); 1.460 + 1.461 + mShiftStates[aShiftState].DeadKey.DeadChar = aDeadChar; 1.462 + mShiftStates[aShiftState].DeadKey.Table = nullptr; 1.463 +} 1.464 + 1.465 +UniCharsAndModifiers 1.466 +VirtualKey::GetUniChars(ShiftState aShiftState) const 1.467 +{ 1.468 + UniCharsAndModifiers result = GetNativeUniChars(aShiftState); 1.469 + 1.470 + const ShiftState STATE_ALT_CONTROL = (STATE_ALT | STATE_CONTROL); 1.471 + if (!(aShiftState & STATE_ALT_CONTROL)) { 1.472 + return result; 1.473 + } 1.474 + 1.475 + if (!result.mLength) { 1.476 + result = GetNativeUniChars(aShiftState & ~STATE_ALT_CONTROL); 1.477 + result.FillModifiers(ShiftStateToModifiers(aShiftState)); 1.478 + return result; 1.479 + } 1.480 + 1.481 + if ((aShiftState & STATE_ALT_CONTROL) == STATE_ALT_CONTROL) { 1.482 + // Even if the shifted chars and the unshifted chars are same, we 1.483 + // should consume the Alt key state and the Ctrl key state when 1.484 + // AltGr key is pressed. Because if we don't consume them, the input 1.485 + // events are ignored on nsEditor. (I.e., Users cannot input the 1.486 + // characters with this key combination.) 1.487 + Modifiers finalModifiers = ShiftStateToModifiers(aShiftState); 1.488 + finalModifiers &= ~(MODIFIER_ALT | MODIFIER_CONTROL); 1.489 + result.FillModifiers(finalModifiers); 1.490 + return result; 1.491 + } 1.492 + 1.493 + UniCharsAndModifiers unmodifiedReslt = 1.494 + GetNativeUniChars(aShiftState & ~STATE_ALT_CONTROL); 1.495 + if (!result.UniCharsEqual(unmodifiedReslt)) { 1.496 + // Otherwise, we should consume the Alt key state and the Ctrl key state 1.497 + // only when the shifted chars and unshifted chars are different. 1.498 + Modifiers finalModifiers = ShiftStateToModifiers(aShiftState); 1.499 + finalModifiers &= ~(MODIFIER_ALT | MODIFIER_CONTROL); 1.500 + result.FillModifiers(finalModifiers); 1.501 + } 1.502 + return result; 1.503 +} 1.504 + 1.505 + 1.506 +UniCharsAndModifiers 1.507 +VirtualKey::GetNativeUniChars(ShiftState aShiftState) const 1.508 +{ 1.509 +#ifdef DEBUG 1.510 + if (aShiftState < 0 || aShiftState >= ArrayLength(mShiftStates)) { 1.511 + nsPrintfCString warning("Shift state is out of range: " 1.512 + "aShiftState=%d, ArrayLength(mShiftState)=%d", 1.513 + aShiftState, ArrayLength(mShiftStates)); 1.514 + NS_WARNING(warning.get()); 1.515 + } 1.516 +#endif 1.517 + 1.518 + UniCharsAndModifiers result; 1.519 + Modifiers modifiers = ShiftStateToModifiers(aShiftState); 1.520 + if (IsDeadKey(aShiftState)) { 1.521 + result.Append(mShiftStates[aShiftState].DeadKey.DeadChar, modifiers); 1.522 + return result; 1.523 + } 1.524 + 1.525 + uint32_t index; 1.526 + uint32_t len = ArrayLength(mShiftStates[aShiftState].Normal.Chars); 1.527 + for (index = 0; 1.528 + index < len && mShiftStates[aShiftState].Normal.Chars[index]; index++) { 1.529 + result.Append(mShiftStates[aShiftState].Normal.Chars[index], modifiers); 1.530 + } 1.531 + return result; 1.532 +} 1.533 + 1.534 +// static 1.535 +void 1.536 +VirtualKey::FillKbdState(PBYTE aKbdState, 1.537 + const ShiftState aShiftState) 1.538 +{ 1.539 + NS_ASSERTION(aShiftState < 16, "aShiftState out of range"); 1.540 + 1.541 + if (aShiftState & STATE_SHIFT) { 1.542 + aKbdState[VK_SHIFT] |= 0x80; 1.543 + } else { 1.544 + aKbdState[VK_SHIFT] &= ~0x80; 1.545 + aKbdState[VK_LSHIFT] &= ~0x80; 1.546 + aKbdState[VK_RSHIFT] &= ~0x80; 1.547 + } 1.548 + 1.549 + if (aShiftState & STATE_CONTROL) { 1.550 + aKbdState[VK_CONTROL] |= 0x80; 1.551 + } else { 1.552 + aKbdState[VK_CONTROL] &= ~0x80; 1.553 + aKbdState[VK_LCONTROL] &= ~0x80; 1.554 + aKbdState[VK_RCONTROL] &= ~0x80; 1.555 + } 1.556 + 1.557 + if (aShiftState & STATE_ALT) { 1.558 + aKbdState[VK_MENU] |= 0x80; 1.559 + } else { 1.560 + aKbdState[VK_MENU] &= ~0x80; 1.561 + aKbdState[VK_LMENU] &= ~0x80; 1.562 + aKbdState[VK_RMENU] &= ~0x80; 1.563 + } 1.564 + 1.565 + if (aShiftState & STATE_CAPSLOCK) { 1.566 + aKbdState[VK_CAPITAL] |= 0x01; 1.567 + } else { 1.568 + aKbdState[VK_CAPITAL] &= ~0x01; 1.569 + } 1.570 +} 1.571 + 1.572 +/***************************************************************************** 1.573 + * mozilla::widget::NativeKey 1.574 + *****************************************************************************/ 1.575 + 1.576 +NativeKey::NativeKey(nsWindowBase* aWidget, 1.577 + const MSG& aKeyOrCharMessage, 1.578 + const ModifierKeyState& aModKeyState, 1.579 + nsTArray<FakeCharMsg>* aFakeCharMsgs) : 1.580 + mWidget(aWidget), mMsg(aKeyOrCharMessage), mDOMKeyCode(0), 1.581 + mModKeyState(aModKeyState), mVirtualKeyCode(0), mOriginalVirtualKeyCode(0), 1.582 + mFakeCharMsgs(aFakeCharMsgs && aFakeCharMsgs->Length() ? 1.583 + aFakeCharMsgs : nullptr) 1.584 +{ 1.585 + MOZ_ASSERT(aWidget); 1.586 + KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance(); 1.587 + mKeyboardLayout = keyboardLayout->GetLayout(); 1.588 + mScanCode = WinUtils::GetScanCode(mMsg.lParam); 1.589 + mIsExtended = WinUtils::IsExtendedScanCode(mMsg.lParam); 1.590 + // On WinXP and WinServer2003, we cannot compute the virtual keycode for 1.591 + // extended keys due to the API limitation. 1.592 + bool canComputeVirtualKeyCodeFromScanCode = 1.593 + (!mIsExtended || IsVistaOrLater()); 1.594 + switch (mMsg.message) { 1.595 + case WM_KEYDOWN: 1.596 + case WM_SYSKEYDOWN: 1.597 + case WM_KEYUP: 1.598 + case WM_SYSKEYUP: { 1.599 + // First, resolve the IME converted virtual keycode to its original 1.600 + // keycode. 1.601 + if (mMsg.wParam == VK_PROCESSKEY) { 1.602 + mOriginalVirtualKeyCode = 1.603 + static_cast<uint8_t>(::ImmGetVirtualKey(mMsg.hwnd)); 1.604 + } else { 1.605 + mOriginalVirtualKeyCode = static_cast<uint8_t>(mMsg.wParam); 1.606 + } 1.607 + 1.608 + // Most keys are not distinguished as left or right keys. 1.609 + bool isLeftRightDistinguishedKey = false; 1.610 + 1.611 + // mOriginalVirtualKeyCode must not distinguish left or right of 1.612 + // Shift, Control or Alt. 1.613 + switch (mOriginalVirtualKeyCode) { 1.614 + case VK_SHIFT: 1.615 + case VK_CONTROL: 1.616 + case VK_MENU: 1.617 + isLeftRightDistinguishedKey = true; 1.618 + break; 1.619 + case VK_LSHIFT: 1.620 + case VK_RSHIFT: 1.621 + mVirtualKeyCode = mOriginalVirtualKeyCode; 1.622 + mOriginalVirtualKeyCode = VK_SHIFT; 1.623 + isLeftRightDistinguishedKey = true; 1.624 + break; 1.625 + case VK_LCONTROL: 1.626 + case VK_RCONTROL: 1.627 + mVirtualKeyCode = mOriginalVirtualKeyCode; 1.628 + mOriginalVirtualKeyCode = VK_CONTROL; 1.629 + isLeftRightDistinguishedKey = true; 1.630 + break; 1.631 + case VK_LMENU: 1.632 + case VK_RMENU: 1.633 + mVirtualKeyCode = mOriginalVirtualKeyCode; 1.634 + mOriginalVirtualKeyCode = VK_MENU; 1.635 + isLeftRightDistinguishedKey = true; 1.636 + break; 1.637 + } 1.638 + 1.639 + // If virtual keycode (left-right distinguished keycode) is already 1.640 + // computed, we don't need to do anymore. 1.641 + if (mVirtualKeyCode) { 1.642 + break; 1.643 + } 1.644 + 1.645 + // If the keycode doesn't have LR distinguished keycode, we just set 1.646 + // mOriginalVirtualKeyCode to mVirtualKeyCode. Note that don't compute 1.647 + // it from MapVirtualKeyEx() because the scan code might be wrong if 1.648 + // the message is sent/posted by other application. Then, we will compute 1.649 + // unexpected keycode from the scan code. 1.650 + if (!isLeftRightDistinguishedKey) { 1.651 + break; 1.652 + } 1.653 + 1.654 + if (!canComputeVirtualKeyCodeFromScanCode) { 1.655 + // The right control key and the right alt key are extended keys. 1.656 + // Therefore, we never get VK_RCONTRL and VK_RMENU for the result of 1.657 + // MapVirtualKeyEx() on WinXP or WinServer2003. 1.658 + // 1.659 + // If VK_CONTROL or VK_MENU key message is caused by an extended key, 1.660 + // we should assume that the right key of them is pressed. 1.661 + switch (mOriginalVirtualKeyCode) { 1.662 + case VK_CONTROL: 1.663 + mVirtualKeyCode = VK_RCONTROL; 1.664 + break; 1.665 + case VK_MENU: 1.666 + mVirtualKeyCode = VK_RMENU; 1.667 + break; 1.668 + case VK_SHIFT: 1.669 + // Neither left shift nor right shift is not an extended key, 1.670 + // let's use VK_LSHIFT for invalid scan code. 1.671 + mVirtualKeyCode = VK_LSHIFT; 1.672 + break; 1.673 + default: 1.674 + MOZ_CRASH("Unsupported mOriginalVirtualKeyCode"); 1.675 + } 1.676 + break; 1.677 + } 1.678 + 1.679 + NS_ASSERTION(!mVirtualKeyCode, 1.680 + "mVirtualKeyCode has been computed already"); 1.681 + 1.682 + // Otherwise, compute the virtual keycode with MapVirtualKeyEx(). 1.683 + mVirtualKeyCode = ComputeVirtualKeyCodeFromScanCodeEx(); 1.684 + 1.685 + // The result might be unexpected value due to the scan code is 1.686 + // wrong. For example, any key messages can be generated by 1.687 + // SendMessage() or PostMessage() from applications. So, it's possible 1.688 + // failure. Then, let's respect the extended flag even if it might be 1.689 + // set intentionally. 1.690 + switch (mOriginalVirtualKeyCode) { 1.691 + case VK_CONTROL: 1.692 + if (mVirtualKeyCode != VK_LCONTROL && 1.693 + mVirtualKeyCode != VK_RCONTROL) { 1.694 + mVirtualKeyCode = mIsExtended ? VK_RCONTROL : VK_LCONTROL; 1.695 + } 1.696 + break; 1.697 + case VK_MENU: 1.698 + if (mVirtualKeyCode != VK_LMENU && mVirtualKeyCode != VK_RMENU) { 1.699 + mVirtualKeyCode = mIsExtended ? VK_RMENU : VK_LMENU; 1.700 + } 1.701 + break; 1.702 + case VK_SHIFT: 1.703 + if (mVirtualKeyCode != VK_LSHIFT && mVirtualKeyCode != VK_RSHIFT) { 1.704 + // Neither left shift nor right shift is not an extended key, 1.705 + // let's use VK_LSHIFT for invalid scan code. 1.706 + mVirtualKeyCode = VK_LSHIFT; 1.707 + } 1.708 + break; 1.709 + default: 1.710 + MOZ_CRASH("Unsupported mOriginalVirtualKeyCode"); 1.711 + } 1.712 + break; 1.713 + } 1.714 + case WM_CHAR: 1.715 + case WM_UNICHAR: 1.716 + case WM_SYSCHAR: 1.717 + // We cannot compute the virtual key code from WM_CHAR message on WinXP 1.718 + // if it's caused by an extended key. 1.719 + if (!canComputeVirtualKeyCodeFromScanCode) { 1.720 + break; 1.721 + } 1.722 + mVirtualKeyCode = mOriginalVirtualKeyCode = 1.723 + ComputeVirtualKeyCodeFromScanCodeEx(); 1.724 + NS_ASSERTION(mVirtualKeyCode, "Failed to compute virtual keycode"); 1.725 + break; 1.726 + default: 1.727 + MOZ_CRASH("Unsupported message"); 1.728 + } 1.729 + 1.730 + if (!mVirtualKeyCode) { 1.731 + mVirtualKeyCode = mOriginalVirtualKeyCode; 1.732 + } 1.733 + 1.734 + mDOMKeyCode = 1.735 + keyboardLayout->ConvertNativeKeyCodeToDOMKeyCode(mOriginalVirtualKeyCode); 1.736 + mKeyNameIndex = 1.737 + keyboardLayout->ConvertNativeKeyCodeToKeyNameIndex(mOriginalVirtualKeyCode); 1.738 + 1.739 + keyboardLayout->InitNativeKey(*this, mModKeyState); 1.740 + 1.741 + mIsDeadKey = 1.742 + (IsFollowedByDeadCharMessage() || 1.743 + keyboardLayout->IsDeadKey(mOriginalVirtualKeyCode, mModKeyState)); 1.744 + mIsPrintableKey = KeyboardLayout::IsPrintableCharKey(mOriginalVirtualKeyCode); 1.745 +} 1.746 + 1.747 +bool 1.748 +NativeKey::IsFollowedByDeadCharMessage() const 1.749 +{ 1.750 + MSG nextMsg; 1.751 + if (mFakeCharMsgs) { 1.752 + nextMsg = mFakeCharMsgs->ElementAt(0).GetCharMsg(mMsg.hwnd); 1.753 + } else { 1.754 + if (!WinUtils::PeekMessage(&nextMsg, mMsg.hwnd, WM_KEYFIRST, WM_KEYLAST, 1.755 + PM_NOREMOVE | PM_NOYIELD)) { 1.756 + return false; 1.757 + } 1.758 + } 1.759 + return IsDeadCharMessage(nextMsg); 1.760 +} 1.761 + 1.762 +bool 1.763 +NativeKey::IsIMEDoingKakuteiUndo() const 1.764 +{ 1.765 + // Following message pattern is caused by "Kakutei-Undo" of ATOK or WXG: 1.766 + // --------------------------------------------------------------------------- 1.767 + // WM_KEYDOWN * n (wParam = VK_BACK, lParam = 0x1) 1.768 + // WM_KEYUP * 1 (wParam = VK_BACK, lParam = 0xC0000001) # ATOK 1.769 + // WM_IME_STARTCOMPOSITION * 1 (wParam = 0x0, lParam = 0x0) 1.770 + // WM_IME_COMPOSITION * 1 (wParam = 0x0, lParam = 0x1BF) 1.771 + // WM_CHAR * n (wParam = VK_BACK, lParam = 0x1) 1.772 + // WM_KEYUP * 1 (wParam = VK_BACK, lParam = 0xC00E0001) 1.773 + // --------------------------------------------------------------------------- 1.774 + // This doesn't match usual key message pattern such as: 1.775 + // WM_KEYDOWN -> WM_CHAR -> WM_KEYDOWN -> WM_CHAR -> ... -> WM_KEYUP 1.776 + // See following bugs for the detail. 1.777 + // https://bugzilla.mozilla.gr.jp/show_bug.cgi?id=2885 (written in Japanese) 1.778 + // https://bugzilla.mozilla.org/show_bug.cgi?id=194559 (written in English) 1.779 + MSG startCompositionMsg, compositionMsg, charMsg; 1.780 + return WinUtils::PeekMessage(&startCompositionMsg, mMsg.hwnd, 1.781 + WM_IME_STARTCOMPOSITION, WM_IME_STARTCOMPOSITION, 1.782 + PM_NOREMOVE | PM_NOYIELD) && 1.783 + WinUtils::PeekMessage(&compositionMsg, mMsg.hwnd, WM_IME_COMPOSITION, 1.784 + WM_IME_COMPOSITION, PM_NOREMOVE | PM_NOYIELD) && 1.785 + WinUtils::PeekMessage(&charMsg, mMsg.hwnd, WM_CHAR, WM_CHAR, 1.786 + PM_NOREMOVE | PM_NOYIELD) && 1.787 + startCompositionMsg.wParam == 0x0 && 1.788 + startCompositionMsg.lParam == 0x0 && 1.789 + compositionMsg.wParam == 0x0 && 1.790 + compositionMsg.lParam == 0x1BF && 1.791 + charMsg.wParam == VK_BACK && charMsg.lParam == 0x1 && 1.792 + startCompositionMsg.time <= compositionMsg.time && 1.793 + compositionMsg.time <= charMsg.time; 1.794 +} 1.795 + 1.796 +UINT 1.797 +NativeKey::GetScanCodeWithExtendedFlag() const 1.798 +{ 1.799 + // MapVirtualKeyEx() has been improved for supporting extended keys since 1.800 + // Vista. When we call it for mapping a scancode of an extended key and 1.801 + // a virtual keycode, we need to add 0xE000 to the scancode. 1.802 + // On Win XP and Win Server 2003, this doesn't support. On them, we have 1.803 + // no way to get virtual keycodes from scancode of extended keys. 1.804 + if (!mIsExtended || !IsVistaOrLater()) { 1.805 + return mScanCode; 1.806 + } 1.807 + return (0xE000 | mScanCode); 1.808 +} 1.809 + 1.810 +uint32_t 1.811 +NativeKey::GetKeyLocation() const 1.812 +{ 1.813 + switch (mVirtualKeyCode) { 1.814 + case VK_LSHIFT: 1.815 + case VK_LCONTROL: 1.816 + case VK_LMENU: 1.817 + case VK_LWIN: 1.818 + return nsIDOMKeyEvent::DOM_KEY_LOCATION_LEFT; 1.819 + 1.820 + case VK_RSHIFT: 1.821 + case VK_RCONTROL: 1.822 + case VK_RMENU: 1.823 + case VK_RWIN: 1.824 + return nsIDOMKeyEvent::DOM_KEY_LOCATION_RIGHT; 1.825 + 1.826 + case VK_RETURN: 1.827 + // XXX This code assumes that all keyboard drivers use same mapping. 1.828 + return !mIsExtended ? nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD : 1.829 + nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD; 1.830 + 1.831 + case VK_INSERT: 1.832 + case VK_DELETE: 1.833 + case VK_END: 1.834 + case VK_DOWN: 1.835 + case VK_NEXT: 1.836 + case VK_LEFT: 1.837 + case VK_CLEAR: 1.838 + case VK_RIGHT: 1.839 + case VK_HOME: 1.840 + case VK_UP: 1.841 + case VK_PRIOR: 1.842 + // XXX This code assumes that all keyboard drivers use same mapping. 1.843 + return mIsExtended ? nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD : 1.844 + nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD; 1.845 + 1.846 + // NumLock key isn't included due to IE9's behavior. 1.847 + case VK_NUMPAD0: 1.848 + case VK_NUMPAD1: 1.849 + case VK_NUMPAD2: 1.850 + case VK_NUMPAD3: 1.851 + case VK_NUMPAD4: 1.852 + case VK_NUMPAD5: 1.853 + case VK_NUMPAD6: 1.854 + case VK_NUMPAD7: 1.855 + case VK_NUMPAD8: 1.856 + case VK_NUMPAD9: 1.857 + case VK_DECIMAL: 1.858 + case VK_DIVIDE: 1.859 + case VK_MULTIPLY: 1.860 + case VK_SUBTRACT: 1.861 + case VK_ADD: 1.862 + // Separator key of Brazilian keyboard or JIS keyboard for Mac 1.863 + case VK_ABNT_C2: 1.864 + return nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD; 1.865 + 1.866 + case VK_SHIFT: 1.867 + case VK_CONTROL: 1.868 + case VK_MENU: 1.869 + NS_WARNING("Failed to decide the key location?"); 1.870 + 1.871 + default: 1.872 + return nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD; 1.873 + } 1.874 +} 1.875 + 1.876 +uint8_t 1.877 +NativeKey::ComputeVirtualKeyCodeFromScanCode() const 1.878 +{ 1.879 + return static_cast<uint8_t>( 1.880 + ::MapVirtualKeyEx(mScanCode, MAPVK_VSC_TO_VK, mKeyboardLayout)); 1.881 +} 1.882 + 1.883 +uint8_t 1.884 +NativeKey::ComputeVirtualKeyCodeFromScanCodeEx() const 1.885 +{ 1.886 + // NOTE: WinXP doesn't support mapping scan code to virtual keycode of 1.887 + // extended keys. 1.888 + NS_ENSURE_TRUE(!mIsExtended || IsVistaOrLater(), 0); 1.889 + return static_cast<uint8_t>( 1.890 + ::MapVirtualKeyEx(GetScanCodeWithExtendedFlag(), MAPVK_VSC_TO_VK_EX, 1.891 + mKeyboardLayout)); 1.892 +} 1.893 + 1.894 +char16_t 1.895 +NativeKey::ComputeUnicharFromScanCode() const 1.896 +{ 1.897 + return static_cast<char16_t>( 1.898 + ::MapVirtualKeyEx(ComputeVirtualKeyCodeFromScanCode(), 1.899 + MAPVK_VK_TO_CHAR, mKeyboardLayout)); 1.900 +} 1.901 + 1.902 +void 1.903 +NativeKey::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent) const 1.904 +{ 1.905 + InitKeyEvent(aKeyEvent, mModKeyState); 1.906 +} 1.907 + 1.908 +void 1.909 +NativeKey::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent, 1.910 + const ModifierKeyState& aModKeyState) const 1.911 +{ 1.912 + nsIntPoint point(0, 0); 1.913 + mWidget->InitEvent(aKeyEvent, &point); 1.914 + 1.915 + switch (aKeyEvent.message) { 1.916 + case NS_KEY_DOWN: 1.917 + aKeyEvent.keyCode = mDOMKeyCode; 1.918 + // Unique id for this keydown event and its associated keypress. 1.919 + sUniqueKeyEventId++; 1.920 + aKeyEvent.mUniqueId = sUniqueKeyEventId; 1.921 + break; 1.922 + case NS_KEY_UP: 1.923 + aKeyEvent.keyCode = mDOMKeyCode; 1.924 + // Set defaultPrevented of the key event if the VK_MENU is not a system 1.925 + // key release, so that the menu bar does not trigger. This helps avoid 1.926 + // triggering the menu bar for ALT key accelerators used in assistive 1.927 + // technologies such as Window-Eyes and ZoomText or for switching open 1.928 + // state of IME. 1.929 + aKeyEvent.mFlags.mDefaultPrevented = 1.930 + (mOriginalVirtualKeyCode == VK_MENU && mMsg.message != WM_SYSKEYUP); 1.931 + break; 1.932 + case NS_KEY_PRESS: 1.933 + aKeyEvent.mUniqueId = sUniqueKeyEventId; 1.934 + break; 1.935 + default: 1.936 + MOZ_CRASH("Invalid event message"); 1.937 + } 1.938 + 1.939 + aKeyEvent.mIsRepeat = IsRepeat(); 1.940 + aKeyEvent.mKeyNameIndex = mKeyNameIndex; 1.941 + if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) { 1.942 + aKeyEvent.mKeyValue = mCommittedCharsAndModifiers.ToString(); 1.943 + } 1.944 + aKeyEvent.location = GetKeyLocation(); 1.945 + aModKeyState.InitInputEvent(aKeyEvent); 1.946 +} 1.947 + 1.948 +bool 1.949 +NativeKey::DispatchKeyEvent(WidgetKeyboardEvent& aKeyEvent, 1.950 + const MSG* aMsgSentToPlugin) const 1.951 +{ 1.952 + if (mWidget->Destroyed()) { 1.953 + MOZ_CRASH("NativeKey tries to dispatch a key event on destroyed widget"); 1.954 + } 1.955 + 1.956 + KeyboardLayout::NotifyIdleServiceOfUserActivity(); 1.957 + 1.958 + NPEvent pluginEvent; 1.959 + if (aMsgSentToPlugin && 1.960 + mWidget->GetInputContext().mIMEState.mEnabled == IMEState::PLUGIN) { 1.961 + pluginEvent.event = aMsgSentToPlugin->message; 1.962 + pluginEvent.wParam = aMsgSentToPlugin->wParam; 1.963 + pluginEvent.lParam = aMsgSentToPlugin->lParam; 1.964 + aKeyEvent.pluginEvent = static_cast<void*>(&pluginEvent); 1.965 + } 1.966 + 1.967 + return (mWidget->DispatchKeyboardEvent(&aKeyEvent) || mWidget->Destroyed()); 1.968 +} 1.969 + 1.970 +bool 1.971 +NativeKey::HandleKeyDownMessage(bool* aEventDispatched) const 1.972 +{ 1.973 + MOZ_ASSERT(IsKeyDownMessage()); 1.974 + 1.975 + if (aEventDispatched) { 1.976 + *aEventDispatched = false; 1.977 + } 1.978 + 1.979 + bool defaultPrevented = false; 1.980 + if (mFakeCharMsgs || 1.981 + !RedirectedKeyDownMessageManager::IsRedirectedMessage(mMsg)) { 1.982 + // Ignore [shift+]alt+space so the OS can handle it. 1.983 + if (mModKeyState.IsAlt() && !mModKeyState.IsControl() && 1.984 + mVirtualKeyCode == VK_SPACE) { 1.985 + return false; 1.986 + } 1.987 + 1.988 + bool isIMEEnabled = WinUtils::IsIMEEnabled(mWidget->GetInputContext()); 1.989 + WidgetKeyboardEvent keydownEvent(true, NS_KEY_DOWN, mWidget); 1.990 + InitKeyEvent(keydownEvent, mModKeyState); 1.991 + if (aEventDispatched) { 1.992 + *aEventDispatched = true; 1.993 + } 1.994 + defaultPrevented = DispatchKeyEvent(keydownEvent, &mMsg); 1.995 + 1.996 + if (mWidget->Destroyed()) { 1.997 + return true; 1.998 + } 1.999 + 1.1000 + // If IMC wasn't associated to the window but is associated it now (i.e., 1.1001 + // focus is moved from a non-editable editor to an editor by keydown 1.1002 + // event handler), WM_CHAR and WM_SYSCHAR shouldn't cause first character 1.1003 + // inputting if IME is opened. But then, we should redirect the native 1.1004 + // keydown message to IME. 1.1005 + // However, note that if focus has been already moved to another 1.1006 + // application, we shouldn't redirect the message to it because the keydown 1.1007 + // message is processed by us, so, nobody shouldn't process it. 1.1008 + HWND focusedWnd = ::GetFocus(); 1.1009 + if (!defaultPrevented && !mFakeCharMsgs && focusedWnd && 1.1010 + !mWidget->PluginHasFocus() && !isIMEEnabled && 1.1011 + WinUtils::IsIMEEnabled(mWidget->GetInputContext())) { 1.1012 + RedirectedKeyDownMessageManager::RemoveNextCharMessage(focusedWnd); 1.1013 + 1.1014 + INPUT keyinput; 1.1015 + keyinput.type = INPUT_KEYBOARD; 1.1016 + keyinput.ki.wVk = mOriginalVirtualKeyCode; 1.1017 + keyinput.ki.wScan = mScanCode; 1.1018 + keyinput.ki.dwFlags = KEYEVENTF_SCANCODE; 1.1019 + if (mIsExtended) { 1.1020 + keyinput.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY; 1.1021 + } 1.1022 + keyinput.ki.time = 0; 1.1023 + keyinput.ki.dwExtraInfo = 0; 1.1024 + 1.1025 + RedirectedKeyDownMessageManager::WillRedirect(mMsg, defaultPrevented); 1.1026 + 1.1027 + ::SendInput(1, &keyinput, sizeof(keyinput)); 1.1028 + 1.1029 + // Return here. We shouldn't dispatch keypress event for this WM_KEYDOWN. 1.1030 + // If it's needed, it will be dispatched after next (redirected) 1.1031 + // WM_KEYDOWN. 1.1032 + return true; 1.1033 + } 1.1034 + } else { 1.1035 + defaultPrevented = RedirectedKeyDownMessageManager::DefaultPrevented(); 1.1036 + // If this is redirected keydown message, we have dispatched the keydown 1.1037 + // event already. 1.1038 + if (aEventDispatched) { 1.1039 + *aEventDispatched = true; 1.1040 + } 1.1041 + } 1.1042 + 1.1043 + RedirectedKeyDownMessageManager::Forget(); 1.1044 + 1.1045 + // If the key was processed by IME, we shouldn't dispatch keypress event. 1.1046 + if (mOriginalVirtualKeyCode == VK_PROCESSKEY) { 1.1047 + return defaultPrevented; 1.1048 + } 1.1049 + 1.1050 + // Don't dispatch keypress event for modifier keys. 1.1051 + switch (mDOMKeyCode) { 1.1052 + case NS_VK_SHIFT: 1.1053 + case NS_VK_CONTROL: 1.1054 + case NS_VK_ALT: 1.1055 + case NS_VK_CAPS_LOCK: 1.1056 + case NS_VK_NUM_LOCK: 1.1057 + case NS_VK_SCROLL_LOCK: 1.1058 + case NS_VK_WIN: 1.1059 + return defaultPrevented; 1.1060 + } 1.1061 + 1.1062 + if (defaultPrevented) { 1.1063 + DispatchPluginEventsAndDiscardsCharMessages(); 1.1064 + return true; 1.1065 + } 1.1066 + 1.1067 + // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a 1.1068 + // keypress for almost all keys 1.1069 + if (NeedsToHandleWithoutFollowingCharMessages()) { 1.1070 + return (DispatchPluginEventsAndDiscardsCharMessages() || 1.1071 + DispatchKeyPressEventsWithKeyboardLayout()); 1.1072 + } 1.1073 + 1.1074 + MSG followingCharMsg; 1.1075 + if (GetFollowingCharMessage(followingCharMsg)) { 1.1076 + // Even if there was char message, it might be redirected by different 1.1077 + // window (perhaps, focus move?). Then, we shouldn't continue to handle 1.1078 + // the message since no input should occur on the window. 1.1079 + if (followingCharMsg.message == WM_NULL || 1.1080 + followingCharMsg.hwnd != mMsg.hwnd) { 1.1081 + return false; 1.1082 + } 1.1083 + return DispatchKeyPressEventForFollowingCharMessage(followingCharMsg); 1.1084 + } 1.1085 + 1.1086 + if (!mModKeyState.IsControl() && !mModKeyState.IsAlt() && 1.1087 + !mModKeyState.IsWin() && mIsPrintableKey) { 1.1088 + // If this is simple KeyDown event but next message is not WM_CHAR, 1.1089 + // this event may not input text, so we should ignore this event. 1.1090 + // See bug 314130. 1.1091 + return false; 1.1092 + } 1.1093 + 1.1094 + if (mIsDeadKey) { 1.1095 + return false; 1.1096 + } 1.1097 + 1.1098 + return DispatchKeyPressEventsWithKeyboardLayout(); 1.1099 +} 1.1100 + 1.1101 +bool 1.1102 +NativeKey::HandleCharMessage(const MSG& aCharMsg, 1.1103 + bool* aEventDispatched) const 1.1104 +{ 1.1105 + MOZ_ASSERT(IsKeyDownMessage() || IsPrintableCharMessage(mMsg)); 1.1106 + MOZ_ASSERT(IsPrintableCharMessage(aCharMsg.message)); 1.1107 + 1.1108 + if (aEventDispatched) { 1.1109 + *aEventDispatched = false; 1.1110 + } 1.1111 + 1.1112 + // Alt+Space key is handled by OS, we shouldn't touch it. 1.1113 + if (mModKeyState.IsAlt() && !mModKeyState.IsControl() && 1.1114 + mVirtualKeyCode == VK_SPACE) { 1.1115 + return false; 1.1116 + } 1.1117 + 1.1118 + // Bug 818235: Ignore Ctrl+Enter. 1.1119 + if (!mModKeyState.IsAlt() && mModKeyState.IsControl() && 1.1120 + mVirtualKeyCode == VK_RETURN) { 1.1121 + return false; 1.1122 + } 1.1123 + 1.1124 + // XXXmnakao I think that if aNativeKeyDown is null, such lonely WM_CHAR 1.1125 + // should cause composition events because they are not caused 1.1126 + // by actual keyboard operation. 1.1127 + 1.1128 + static const char16_t U_SPACE = 0x20; 1.1129 + static const char16_t U_EQUAL = 0x3D; 1.1130 + 1.1131 + // First, handle normal text input or non-printable key case here. 1.1132 + if ((!mModKeyState.IsAlt() && !mModKeyState.IsControl()) || 1.1133 + mModKeyState.IsAltGr() || 1.1134 + (mOriginalVirtualKeyCode && 1.1135 + !KeyboardLayout::IsPrintableCharKey(mOriginalVirtualKeyCode))) { 1.1136 + WidgetKeyboardEvent keypressEvent(true, NS_KEY_PRESS, mWidget); 1.1137 + if (aCharMsg.wParam >= U_SPACE) { 1.1138 + keypressEvent.charCode = static_cast<uint32_t>(aCharMsg.wParam); 1.1139 + } else { 1.1140 + keypressEvent.keyCode = mDOMKeyCode; 1.1141 + } 1.1142 + // When AltGr (Alt+Ctrl) is pressed, that causes normal text input. 1.1143 + // At this time, if either alt or ctrl flag is set, nsEditor ignores the 1.1144 + // keypress event. For avoiding this issue, we should remove ctrl and alt 1.1145 + // flags. 1.1146 + ModifierKeyState modKeyState(mModKeyState); 1.1147 + modKeyState.Unset(MODIFIER_ALT | MODIFIER_CONTROL); 1.1148 + InitKeyEvent(keypressEvent, modKeyState); 1.1149 + if (aEventDispatched) { 1.1150 + *aEventDispatched = true; 1.1151 + } 1.1152 + return DispatchKeyEvent(keypressEvent, &aCharMsg); 1.1153 + } 1.1154 + 1.1155 + // XXX It seems that following code was implemented for shortcut key 1.1156 + // handling. However, it's now handled in WM_KEYDOWN message handler. 1.1157 + // So, this actually runs only when WM_CHAR is sent/posted without 1.1158 + // WM_KEYDOWN. I think that we don't need to keypress event in such 1.1159 + // case especially for shortcut keys. 1.1160 + 1.1161 + char16_t uniChar; 1.1162 + // Ctrl+A Ctrl+Z, see Programming Windows 3.1 page 110 for details 1.1163 + if (mModKeyState.IsControl() && aCharMsg.wParam <= 0x1A) { 1.1164 + // Bug 16486: Need to account for shift here. 1.1165 + uniChar = aCharMsg.wParam - 1 + (mModKeyState.IsShift() ? 'A' : 'a'); 1.1166 + } else if (mModKeyState.IsControl() && aCharMsg.wParam <= 0x1F) { 1.1167 + // Bug 50255: <ctrl><[> and <ctrl><]> are not being processed. 1.1168 + // also fixes ctrl+\ (x1c), ctrl+^ (x1e) and ctrl+_ (x1f) 1.1169 + // for some reason the keypress handler need to have the uniChar code set 1.1170 + // with the addition of a upper case A not the lower case. 1.1171 + uniChar = aCharMsg.wParam - 1 + 'A'; 1.1172 + } else if (aCharMsg.wParam < U_SPACE || 1.1173 + (aCharMsg.wParam == U_EQUAL && mModKeyState.IsControl())) { 1.1174 + uniChar = 0; 1.1175 + } else { 1.1176 + uniChar = aCharMsg.wParam; 1.1177 + } 1.1178 + 1.1179 + // Bug 50255 and Bug 351310: Keep the characters unshifted for shortcuts and 1.1180 + // accesskeys and make sure that numbers are always passed as such. 1.1181 + if (uniChar && (mModKeyState.IsControl() || mModKeyState.IsAlt())) { 1.1182 + KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance(); 1.1183 + char16_t unshiftedCharCode = 1.1184 + (mVirtualKeyCode >= '0' && mVirtualKeyCode <= '9') ? 1.1185 + mVirtualKeyCode : mModKeyState.IsShift() ? 1.1186 + ComputeUnicharFromScanCode() : 0; 1.1187 + // Ignore diacritics (top bit set) and key mapping errors (char code 0) 1.1188 + if (static_cast<int32_t>(unshiftedCharCode) > 0) { 1.1189 + uniChar = unshiftedCharCode; 1.1190 + } 1.1191 + } 1.1192 + 1.1193 + // Bug 285161 and Bug 295095: They were caused by the initial fix for 1.1194 + // bug 178110. When pressing (alt|ctrl)+char, the char must be lowercase 1.1195 + // unless shift is pressed too. 1.1196 + if (!mModKeyState.IsShift() && 1.1197 + (mModKeyState.IsAlt() || mModKeyState.IsControl())) { 1.1198 + uniChar = towlower(uniChar); 1.1199 + } 1.1200 + 1.1201 + WidgetKeyboardEvent keypressEvent(true, NS_KEY_PRESS, mWidget); 1.1202 + keypressEvent.charCode = uniChar; 1.1203 + if (!keypressEvent.charCode) { 1.1204 + keypressEvent.keyCode = mDOMKeyCode; 1.1205 + } 1.1206 + InitKeyEvent(keypressEvent, mModKeyState); 1.1207 + if (aEventDispatched) { 1.1208 + *aEventDispatched = true; 1.1209 + } 1.1210 + return DispatchKeyEvent(keypressEvent, &aCharMsg); 1.1211 +} 1.1212 + 1.1213 +bool 1.1214 +NativeKey::HandleKeyUpMessage(bool* aEventDispatched) const 1.1215 +{ 1.1216 + MOZ_ASSERT(IsKeyUpMessage()); 1.1217 + 1.1218 + if (aEventDispatched) { 1.1219 + *aEventDispatched = false; 1.1220 + } 1.1221 + 1.1222 + // Ignore [shift+]alt+space so the OS can handle it. 1.1223 + if (mModKeyState.IsAlt() && !mModKeyState.IsControl() && 1.1224 + mVirtualKeyCode == VK_SPACE) { 1.1225 + return false; 1.1226 + } 1.1227 + 1.1228 + WidgetKeyboardEvent keyupEvent(true, NS_KEY_UP, mWidget); 1.1229 + InitKeyEvent(keyupEvent, mModKeyState); 1.1230 + if (aEventDispatched) { 1.1231 + *aEventDispatched = true; 1.1232 + } 1.1233 + return DispatchKeyEvent(keyupEvent, &mMsg); 1.1234 +} 1.1235 + 1.1236 +bool 1.1237 +NativeKey::NeedsToHandleWithoutFollowingCharMessages() const 1.1238 +{ 1.1239 + MOZ_ASSERT(IsKeyDownMessage()); 1.1240 + 1.1241 + // Enter and backspace are always handled here to avoid for example the 1.1242 + // confusion between ctrl-enter and ctrl-J. 1.1243 + if (mDOMKeyCode == NS_VK_RETURN || mDOMKeyCode == NS_VK_BACK) { 1.1244 + return true; 1.1245 + } 1.1246 + 1.1247 + // If any modifier keys which may cause printable keys becoming non-printable 1.1248 + // are not pressed, we don't need special handling for the key. 1.1249 + if (!mModKeyState.IsControl() && !mModKeyState.IsAlt() && 1.1250 + !mModKeyState.IsWin()) { 1.1251 + return false; 1.1252 + } 1.1253 + 1.1254 + // If the key event causes dead key event, we don't need to dispatch keypress 1.1255 + // event. 1.1256 + if (mIsDeadKey && mCommittedCharsAndModifiers.IsEmpty()) { 1.1257 + return false; 1.1258 + } 1.1259 + 1.1260 + // Even if the key is a printable key, it might cause non-printable character 1.1261 + // input with modifier key(s). 1.1262 + return mIsPrintableKey; 1.1263 +} 1.1264 + 1.1265 +#ifdef MOZ_CRASHREPORTER 1.1266 + 1.1267 +static nsCString 1.1268 +GetResultOfInSendMessageEx() 1.1269 +{ 1.1270 + DWORD ret = ::InSendMessageEx(nullptr); 1.1271 + if (!ret) { 1.1272 + return NS_LITERAL_CSTRING("ISMEX_NOSEND"); 1.1273 + } 1.1274 + nsAutoCString result; 1.1275 + if (ret & ISMEX_CALLBACK) { 1.1276 + result = "ISMEX_CALLBACK"; 1.1277 + } 1.1278 + if (ret & ISMEX_NOTIFY) { 1.1279 + if (!result.IsEmpty()) { 1.1280 + result += " | "; 1.1281 + } 1.1282 + result += "ISMEX_NOTIFY"; 1.1283 + } 1.1284 + if (ret & ISMEX_REPLIED) { 1.1285 + if (!result.IsEmpty()) { 1.1286 + result += " | "; 1.1287 + } 1.1288 + result += "ISMEX_REPLIED"; 1.1289 + } 1.1290 + if (ret & ISMEX_SEND) { 1.1291 + if (!result.IsEmpty()) { 1.1292 + result += " | "; 1.1293 + } 1.1294 + result += "ISMEX_SEND"; 1.1295 + } 1.1296 + return result; 1.1297 +} 1.1298 + 1.1299 +static const char* 1.1300 +GetMessageName(UINT aMessage) 1.1301 +{ 1.1302 + switch (aMessage) { 1.1303 + case WM_KEYDOWN: return "WM_KEYDOWN"; 1.1304 + case WM_SYSKEYDOWN: return "WM_SYSKEYDOWN"; 1.1305 + case WM_KEYUP: return "WM_KEYUP"; 1.1306 + case WM_SYSKEYUP: return "WM_SYSKEYUP"; 1.1307 + case WM_CHAR: return "WM_CHAR"; 1.1308 + case WM_DEADCHAR: return "WM_DEADCHAR"; 1.1309 + case WM_SYSCHAR: return "WM_SYSCHAR"; 1.1310 + case WM_SYSDEADCHAR: return "WM_SYSDEADCHAR"; 1.1311 + case WM_UNICHAR: return "WM_UNICHAR"; 1.1312 + case WM_QUIT: return "WM_QUIT"; 1.1313 + case WM_NULL: return "WM_NULL"; 1.1314 + default: return "Unknown"; 1.1315 + } 1.1316 +} 1.1317 + 1.1318 +#endif // #ifdef MOZ_CRASHREPORTER 1.1319 + 1.1320 +bool 1.1321 +NativeKey::MayBeSameCharMessage(const MSG& aCharMsg1, 1.1322 + const MSG& aCharMsg2) const 1.1323 +{ 1.1324 + // NOTE: Although, we don't know when this case occurs, the scan code value 1.1325 + // in lParam may be changed from 0 to something. The changed value 1.1326 + // is different from the scan code of handling keydown message. 1.1327 + static const LPARAM kScanCodeMask = 0x00FF0000; 1.1328 + return 1.1329 + aCharMsg1.message == aCharMsg2.message && 1.1330 + aCharMsg1.wParam == aCharMsg2.wParam && 1.1331 + (aCharMsg1.lParam & ~kScanCodeMask) == (aCharMsg2.lParam & ~kScanCodeMask); 1.1332 +} 1.1333 + 1.1334 +bool 1.1335 +NativeKey::GetFollowingCharMessage(MSG& aCharMsg) const 1.1336 +{ 1.1337 + MOZ_ASSERT(IsKeyDownMessage()); 1.1338 + 1.1339 + aCharMsg.message = WM_NULL; 1.1340 + 1.1341 + if (mFakeCharMsgs) { 1.1342 + FakeCharMsg& fakeCharMsg = mFakeCharMsgs->ElementAt(0); 1.1343 + if (fakeCharMsg.mConsumed) { 1.1344 + return false; 1.1345 + } 1.1346 + MSG charMsg = fakeCharMsg.GetCharMsg(mMsg.hwnd); 1.1347 + fakeCharMsg.mConsumed = true; 1.1348 + if (!IsCharMessage(charMsg)) { 1.1349 + return false; 1.1350 + } 1.1351 + aCharMsg = charMsg; 1.1352 + return true; 1.1353 + } 1.1354 + 1.1355 + // If next key message is not char message, we should give up to find a 1.1356 + // related char message for the handling keydown event for now. 1.1357 + // Note that it's possible other applications may send other key message 1.1358 + // after we call TranslateMessage(). That may cause PeekMessage() failing 1.1359 + // to get char message for the handling keydown message. 1.1360 + MSG nextKeyMsg; 1.1361 + if (!WinUtils::PeekMessage(&nextKeyMsg, mMsg.hwnd, WM_KEYFIRST, WM_KEYLAST, 1.1362 + PM_NOREMOVE | PM_NOYIELD) || 1.1363 + !IsCharMessage(nextKeyMsg)) { 1.1364 + return false; 1.1365 + } 1.1366 + 1.1367 + // On Metrofox, PeekMessage() sometimes returns WM_NULL even if we specify 1.1368 + // the message range. So, if it returns WM_NULL, we should retry to get 1.1369 + // the following char message it was found above. 1.1370 + for (uint32_t i = 0; i < 5; i++) { 1.1371 + MSG removedMsg, nextKeyMsgInAllWindows; 1.1372 + bool doCrash = false; 1.1373 + if (!WinUtils::PeekMessage(&removedMsg, mMsg.hwnd, 1.1374 + nextKeyMsg.message, nextKeyMsg.message, 1.1375 + PM_REMOVE | PM_NOYIELD)) { 1.1376 + // We meets unexpected case. We should collect the message queue state 1.1377 + // and crash for reporting the bug. 1.1378 + doCrash = true; 1.1379 + // The char message is redirected to different thread's window by focus 1.1380 + // move or something or just cancelled by external application. 1.1381 + if (!WinUtils::PeekMessage(&nextKeyMsgInAllWindows, 0, 1.1382 + WM_KEYFIRST, WM_KEYLAST, 1.1383 + PM_NOREMOVE | PM_NOYIELD)) { 1.1384 + return true; 1.1385 + } 1.1386 + if (MayBeSameCharMessage(nextKeyMsgInAllWindows, nextKeyMsg)) { 1.1387 + // The char message is redirected to different window created by our 1.1388 + // thread. 1.1389 + if (nextKeyMsgInAllWindows.hwnd != mMsg.hwnd) { 1.1390 + aCharMsg = nextKeyMsgInAllWindows; 1.1391 + return true; 1.1392 + } 1.1393 + // The found char message still in the queue, but PeekMessage() failed 1.1394 + // to remove it only with PM_REMOVE. Although, we don't know why this 1.1395 + // occurs. However, this occurs acctually. 1.1396 + // Try to remove the char message with GetMessage() again. 1.1397 + if (WinUtils::GetMessage(&removedMsg, mMsg.hwnd, 1.1398 + nextKeyMsg.message, nextKeyMsg.message)) { 1.1399 + // Cancel to crash, but we need to check the removed message value. 1.1400 + doCrash = false; 1.1401 + } 1.1402 + } 1.1403 + } 1.1404 + 1.1405 + if (doCrash) { 1.1406 +#ifdef MOZ_CRASHREPORTER 1.1407 + nsPrintfCString info("\nPeekMessage() failed to remove char message! " 1.1408 + "\nHandling message: %s (0x%08X), wParam: 0x%08X, " 1.1409 + "lParam: 0x%08X, hwnd=0x%p, InSendMessageEx()=%s, \n" 1.1410 + "Found message: %s (0x%08X), wParam: 0x%08X, " 1.1411 + "lParam: 0x%08X, hwnd=0x%p, " 1.1412 + "\nWM_NULL has been removed: %d, " 1.1413 + "\nNext key message in all windows: %s (0x%08X), " 1.1414 + "wParam: 0x%08X, lParam: 0x%08X, hwnd=0x%p, " 1.1415 + "time=%d, ", 1.1416 + GetMessageName(mMsg.message), 1.1417 + mMsg.message, mMsg.wParam, mMsg.lParam, 1.1418 + nextKeyMsg.hwnd, 1.1419 + GetResultOfInSendMessageEx().get(), 1.1420 + GetMessageName(nextKeyMsg.message), 1.1421 + nextKeyMsg.message, nextKeyMsg.wParam, 1.1422 + nextKeyMsg.lParam, nextKeyMsg.hwnd, i, 1.1423 + GetMessageName(nextKeyMsgInAllWindows.message), 1.1424 + nextKeyMsgInAllWindows.message, 1.1425 + nextKeyMsgInAllWindows.wParam, 1.1426 + nextKeyMsgInAllWindows.lParam, 1.1427 + nextKeyMsgInAllWindows.hwnd, 1.1428 + nextKeyMsgInAllWindows.time); 1.1429 + CrashReporter::AppendAppNotesToCrashReport(info); 1.1430 + MSG nextMsg; 1.1431 + if (WinUtils::PeekMessage(&nextMsg, 0, 0, 0, 1.1432 + PM_NOREMOVE | PM_NOYIELD)) { 1.1433 + nsPrintfCString info("\nNext message in all windows: %s (0x%08X), " 1.1434 + "wParam: 0x%08X, lParam: 0x%08X, hwnd=0x%p, " 1.1435 + "time=%d", 1.1436 + GetMessageName(nextMsg.message), 1.1437 + nextMsg.message, nextMsg.wParam, nextMsg.lParam, 1.1438 + nextMsg.hwnd, nextMsg.time); 1.1439 + CrashReporter::AppendAppNotesToCrashReport(info); 1.1440 + } else { 1.1441 + CrashReporter::AppendAppNotesToCrashReport( 1.1442 + NS_LITERAL_CSTRING("\nThere is no message in any window")); 1.1443 + } 1.1444 +#endif // #ifdef MOZ_CRASHREPORTER 1.1445 + MOZ_CRASH("We lost the following char message"); 1.1446 + } 1.1447 + 1.1448 + // Retry for the strange case. 1.1449 + if (removedMsg.message == WM_NULL) { 1.1450 + continue; 1.1451 + } 1.1452 + 1.1453 + // Typically, this case occurs with WM_DEADCHAR. If the removed message's 1.1454 + // wParam becomes 0, that means that the key event shouldn't cause text 1.1455 + // input. So, let's ignore the strange char message. 1.1456 + if (removedMsg.message == nextKeyMsg.message && !removedMsg.wParam) { 1.1457 + return false; 1.1458 + } 1.1459 + 1.1460 + // NOTE: Although, we don't know when this case occurs, the scan code value 1.1461 + // in lParam may be changed from 0 to something. The changed value 1.1462 + // is different from the scan code of handling keydown message. 1.1463 + if (!MayBeSameCharMessage(removedMsg, nextKeyMsg)) { 1.1464 +#ifdef MOZ_CRASHREPORTER 1.1465 + nsPrintfCString info("\nPeekMessage() removed unexpcted char message! " 1.1466 + "\nHandling message: %s (0x%08X), wParam: 0x%08X, " 1.1467 + "lParam: 0x%08X, hwnd=0x%p, InSendMessageEx()=%s, " 1.1468 + "\nFound message: %s (0x%08X), wParam: 0x%08X, " 1.1469 + "lParam: 0x%08X, hwnd=0x%p, " 1.1470 + "\nRemoved message: %s (0x%08X), wParam: 0x%08X, " 1.1471 + "lParam: 0x%08X, hwnd=0x%p, ", 1.1472 + GetMessageName(mMsg.message), 1.1473 + mMsg.message, mMsg.wParam, mMsg.lParam, mMsg.hwnd, 1.1474 + GetResultOfInSendMessageEx().get(), 1.1475 + GetMessageName(nextKeyMsg.message), 1.1476 + nextKeyMsg.message, nextKeyMsg.wParam, 1.1477 + nextKeyMsg.lParam, nextKeyMsg.hwnd, 1.1478 + GetMessageName(removedMsg.message), 1.1479 + removedMsg.message, removedMsg.wParam, 1.1480 + removedMsg.lParam, removedMsg.hwnd); 1.1481 + CrashReporter::AppendAppNotesToCrashReport(info); 1.1482 + // What's the next key message? 1.1483 + MSG nextKeyMsgAfter; 1.1484 + if (WinUtils::PeekMessage(&nextKeyMsgAfter, mMsg.hwnd, 1.1485 + WM_KEYFIRST, WM_KEYLAST, 1.1486 + PM_NOREMOVE | PM_NOYIELD)) { 1.1487 + nsPrintfCString info("\nNext key message after unexpected char message " 1.1488 + "removed: %s (0x%08X), wParam: 0x%08X, " 1.1489 + "lParam: 0x%08X, hwnd=0x%p, ", 1.1490 + GetMessageName(nextKeyMsgAfter.message), 1.1491 + nextKeyMsgAfter.message, nextKeyMsgAfter.wParam, 1.1492 + nextKeyMsgAfter.lParam, nextKeyMsgAfter.hwnd); 1.1493 + CrashReporter::AppendAppNotesToCrashReport(info); 1.1494 + } else { 1.1495 + CrashReporter::AppendAppNotesToCrashReport( 1.1496 + NS_LITERAL_CSTRING("\nThere is no key message after unexpected char " 1.1497 + "message removed, ")); 1.1498 + } 1.1499 + // Another window has a key message? 1.1500 + MSG nextKeyMsgInAllWindows; 1.1501 + if (WinUtils::PeekMessage(&nextKeyMsgInAllWindows, 0, 1.1502 + WM_KEYFIRST, WM_KEYLAST, 1.1503 + PM_NOREMOVE | PM_NOYIELD)) { 1.1504 + nsPrintfCString info("\nNext key message in all windows: %s (0x%08X), " 1.1505 + "wParam: 0x%08X, lParam: 0x%08X, hwnd=0x%p.", 1.1506 + GetMessageName(nextKeyMsgInAllWindows.message), 1.1507 + nextKeyMsgInAllWindows.message, 1.1508 + nextKeyMsgInAllWindows.wParam, 1.1509 + nextKeyMsgInAllWindows.lParam, 1.1510 + nextKeyMsgInAllWindows.hwnd); 1.1511 + CrashReporter::AppendAppNotesToCrashReport(info); 1.1512 + } else { 1.1513 + CrashReporter::AppendAppNotesToCrashReport( 1.1514 + NS_LITERAL_CSTRING("\nThere is no key message in any windows.")); 1.1515 + } 1.1516 +#endif // #ifdef MOZ_CRASHREPORTER 1.1517 + MOZ_CRASH("PeekMessage() removed unexpected message"); 1.1518 + } 1.1519 + 1.1520 + aCharMsg = removedMsg; 1.1521 + return true; 1.1522 + } 1.1523 +#ifdef MOZ_CRASHREPORTER 1.1524 + nsPrintfCString info("\nWe lost following char message! " 1.1525 + "\nHandling message: %s (0x%08X), wParam: 0x%08X, " 1.1526 + "lParam: 0x%08X, InSendMessageEx()=%s, \n" 1.1527 + "Found message: %s (0x%08X), wParam: 0x%08X, " 1.1528 + "lParam: 0x%08X, removed a lot of WM_NULL", 1.1529 + GetMessageName(mMsg.message), 1.1530 + mMsg.message, mMsg.wParam, mMsg.lParam, 1.1531 + GetResultOfInSendMessageEx().get(), 1.1532 + GetMessageName(nextKeyMsg.message), 1.1533 + nextKeyMsg.message, nextKeyMsg.wParam, 1.1534 + nextKeyMsg.lParam); 1.1535 + CrashReporter::AppendAppNotesToCrashReport(info); 1.1536 +#endif // #ifdef MOZ_CRASHREPORTER 1.1537 + MOZ_CRASH("We lost the following char message"); 1.1538 + return false; 1.1539 +} 1.1540 + 1.1541 +bool 1.1542 +NativeKey::DispatchPluginEventsAndDiscardsCharMessages() const 1.1543 +{ 1.1544 + MOZ_ASSERT(IsKeyDownMessage()); 1.1545 + 1.1546 + // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue. 1.1547 + // They can be more than one because of: 1.1548 + // * Dead-keys not pairing with base character 1.1549 + // * Some keyboard layouts may map up to 4 characters to the single key 1.1550 + bool anyCharMessagesRemoved = false; 1.1551 + MSG msg; 1.1552 + while (GetFollowingCharMessage(msg)) { 1.1553 + if (msg.message == WM_NULL) { 1.1554 + continue; 1.1555 + } 1.1556 + anyCharMessagesRemoved = true; 1.1557 + // If the window handle is changed, focused window must be changed. 1.1558 + // So, plugin shouldn't handle it anymore. 1.1559 + if (msg.hwnd != mMsg.hwnd) { 1.1560 + break; 1.1561 + } 1.1562 + MOZ_RELEASE_ASSERT(!mWidget->Destroyed(), 1.1563 + "NativeKey tries to dispatch a plugin event on destroyed widget"); 1.1564 + mWidget->DispatchPluginEvent(msg); 1.1565 + if (mWidget->Destroyed()) { 1.1566 + return true; 1.1567 + } 1.1568 + } 1.1569 + 1.1570 + if (!mFakeCharMsgs && !anyCharMessagesRemoved && 1.1571 + mDOMKeyCode == NS_VK_BACK && IsIMEDoingKakuteiUndo()) { 1.1572 + // This is for a hack for ATOK and WXG. So, PeekMessage() must scceed! 1.1573 + while (WinUtils::PeekMessage(&msg, mMsg.hwnd, WM_CHAR, WM_CHAR, 1.1574 + PM_REMOVE | PM_NOYIELD)) { 1.1575 + if (msg.message != WM_CHAR) { 1.1576 + MOZ_RELEASE_ASSERT(msg.message == WM_NULL, 1.1577 + "Unexpected message was removed"); 1.1578 + continue; 1.1579 + } 1.1580 + MOZ_RELEASE_ASSERT(!mWidget->Destroyed(), 1.1581 + "NativeKey tries to dispatch a plugin event on destroyed widget"); 1.1582 + mWidget->DispatchPluginEvent(msg); 1.1583 + return mWidget->Destroyed(); 1.1584 + } 1.1585 + MOZ_CRASH("NativeKey failed to get WM_CHAR for ATOK or WXG"); 1.1586 + } 1.1587 + 1.1588 + return false; 1.1589 +} 1.1590 + 1.1591 +bool 1.1592 +NativeKey::DispatchKeyPressEventsWithKeyboardLayout() const 1.1593 +{ 1.1594 + MOZ_ASSERT(IsKeyDownMessage()); 1.1595 + MOZ_ASSERT(!mIsDeadKey); 1.1596 + 1.1597 + KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance(); 1.1598 + 1.1599 + UniCharsAndModifiers inputtingChars(mCommittedCharsAndModifiers); 1.1600 + UniCharsAndModifiers shiftedChars; 1.1601 + UniCharsAndModifiers unshiftedChars; 1.1602 + uint32_t shiftedLatinChar = 0; 1.1603 + uint32_t unshiftedLatinChar = 0; 1.1604 + 1.1605 + if (!KeyboardLayout::IsPrintableCharKey(mVirtualKeyCode)) { 1.1606 + inputtingChars.Clear(); 1.1607 + } 1.1608 + 1.1609 + if (mModKeyState.IsControl() ^ mModKeyState.IsAlt()) { 1.1610 + ModifierKeyState capsLockState( 1.1611 + mModKeyState.GetModifiers() & MODIFIER_CAPSLOCK); 1.1612 + 1.1613 + unshiftedChars = 1.1614 + keyboardLayout->GetUniCharsAndModifiers(mVirtualKeyCode, capsLockState); 1.1615 + capsLockState.Set(MODIFIER_SHIFT); 1.1616 + shiftedChars = 1.1617 + keyboardLayout->GetUniCharsAndModifiers(mVirtualKeyCode, capsLockState); 1.1618 + 1.1619 + // The current keyboard cannot input alphabets or numerics, 1.1620 + // we should append them for Shortcut/Access keys. 1.1621 + // E.g., for Cyrillic keyboard layout. 1.1622 + capsLockState.Unset(MODIFIER_SHIFT); 1.1623 + WidgetUtils::GetLatinCharCodeForKeyCode(mDOMKeyCode, 1.1624 + capsLockState.GetModifiers(), 1.1625 + &unshiftedLatinChar, 1.1626 + &shiftedLatinChar); 1.1627 + 1.1628 + // If the shiftedLatinChar isn't 0, the key code is NS_VK_[A-Z]. 1.1629 + if (shiftedLatinChar) { 1.1630 + // If the produced characters of the key on current keyboard layout 1.1631 + // are same as computed Latin characters, we shouldn't append the 1.1632 + // Latin characters to alternativeCharCode. 1.1633 + if (unshiftedLatinChar == unshiftedChars.mChars[0] && 1.1634 + shiftedLatinChar == shiftedChars.mChars[0]) { 1.1635 + shiftedLatinChar = unshiftedLatinChar = 0; 1.1636 + } 1.1637 + } else if (unshiftedLatinChar) { 1.1638 + // If the shiftedLatinChar is 0, the keyCode doesn't produce 1.1639 + // alphabet character. At that time, the character may be produced 1.1640 + // with Shift key. E.g., on French keyboard layout, NS_VK_PERCENT 1.1641 + // key produces LATIN SMALL LETTER U WITH GRAVE (U+00F9) without 1.1642 + // Shift key but with Shift key, it produces '%'. 1.1643 + // If the unshiftedLatinChar is produced by the key on current 1.1644 + // keyboard layout, we shouldn't append it to alternativeCharCode. 1.1645 + if (unshiftedLatinChar == unshiftedChars.mChars[0] || 1.1646 + unshiftedLatinChar == shiftedChars.mChars[0]) { 1.1647 + unshiftedLatinChar = 0; 1.1648 + } 1.1649 + } 1.1650 + 1.1651 + // If the charCode is not ASCII character, we should replace the 1.1652 + // charCode with ASCII character only when Ctrl is pressed. 1.1653 + // But don't replace the charCode when the charCode is not same as 1.1654 + // unmodified characters. In such case, Ctrl is sometimes used for a 1.1655 + // part of character inputting key combination like Shift. 1.1656 + if (mModKeyState.IsControl()) { 1.1657 + uint32_t ch = 1.1658 + mModKeyState.IsShift() ? shiftedLatinChar : unshiftedLatinChar; 1.1659 + if (ch && 1.1660 + (!inputtingChars.mLength || 1.1661 + inputtingChars.UniCharsCaseInsensitiveEqual( 1.1662 + mModKeyState.IsShift() ? shiftedChars : unshiftedChars))) { 1.1663 + inputtingChars.Clear(); 1.1664 + inputtingChars.Append(ch, mModKeyState.GetModifiers()); 1.1665 + } 1.1666 + } 1.1667 + } 1.1668 + 1.1669 + if (inputtingChars.IsEmpty() && 1.1670 + shiftedChars.IsEmpty() && unshiftedChars.IsEmpty()) { 1.1671 + WidgetKeyboardEvent keypressEvent(true, NS_KEY_PRESS, mWidget); 1.1672 + keypressEvent.keyCode = mDOMKeyCode; 1.1673 + InitKeyEvent(keypressEvent, mModKeyState); 1.1674 + return DispatchKeyEvent(keypressEvent); 1.1675 + } 1.1676 + 1.1677 + uint32_t longestLength = 1.1678 + std::max(inputtingChars.mLength, 1.1679 + std::max(shiftedChars.mLength, unshiftedChars.mLength)); 1.1680 + uint32_t skipUniChars = longestLength - inputtingChars.mLength; 1.1681 + uint32_t skipShiftedChars = longestLength - shiftedChars.mLength; 1.1682 + uint32_t skipUnshiftedChars = longestLength - unshiftedChars.mLength; 1.1683 + UINT keyCode = !inputtingChars.mLength ? mDOMKeyCode : 0; 1.1684 + bool defaultPrevented = false; 1.1685 + for (uint32_t cnt = 0; cnt < longestLength; cnt++) { 1.1686 + uint16_t uniChar, shiftedChar, unshiftedChar; 1.1687 + uniChar = shiftedChar = unshiftedChar = 0; 1.1688 + ModifierKeyState modKeyState(mModKeyState); 1.1689 + if (skipUniChars <= cnt) { 1.1690 + if (cnt - skipUniChars < inputtingChars.mLength) { 1.1691 + // If key in combination with Alt and/or Ctrl produces a different 1.1692 + // character than without them then do not report these flags 1.1693 + // because it is separate keyboard layout shift state. If dead-key 1.1694 + // and base character does not produce a valid composite character 1.1695 + // then both produced dead-key character and following base 1.1696 + // character may have different modifier flags, too. 1.1697 + modKeyState.Unset(MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT | 1.1698 + MODIFIER_ALTGRAPH | MODIFIER_CAPSLOCK); 1.1699 + modKeyState.Set(inputtingChars.mModifiers[cnt - skipUniChars]); 1.1700 + } 1.1701 + uniChar = inputtingChars.mChars[cnt - skipUniChars]; 1.1702 + } 1.1703 + if (skipShiftedChars <= cnt) 1.1704 + shiftedChar = shiftedChars.mChars[cnt - skipShiftedChars]; 1.1705 + if (skipUnshiftedChars <= cnt) 1.1706 + unshiftedChar = unshiftedChars.mChars[cnt - skipUnshiftedChars]; 1.1707 + nsAutoTArray<AlternativeCharCode, 5> altArray; 1.1708 + 1.1709 + if (shiftedChar || unshiftedChar) { 1.1710 + AlternativeCharCode chars(unshiftedChar, shiftedChar); 1.1711 + altArray.AppendElement(chars); 1.1712 + } 1.1713 + if (cnt == longestLength - 1) { 1.1714 + if (unshiftedLatinChar || shiftedLatinChar) { 1.1715 + AlternativeCharCode chars(unshiftedLatinChar, shiftedLatinChar); 1.1716 + altArray.AppendElement(chars); 1.1717 + } 1.1718 + 1.1719 + // Typically, following virtual keycodes are used for a key which can 1.1720 + // input the character. However, these keycodes are also used for 1.1721 + // other keys on some keyboard layout. E.g., in spite of Shift+'1' 1.1722 + // inputs '+' on Thai keyboard layout, a key which is at '=/+' 1.1723 + // key on ANSI keyboard layout is VK_OEM_PLUS. Native applications 1.1724 + // handle it as '+' key if Ctrl key is pressed. 1.1725 + char16_t charForOEMKeyCode = 0; 1.1726 + switch (mVirtualKeyCode) { 1.1727 + case VK_OEM_PLUS: charForOEMKeyCode = '+'; break; 1.1728 + case VK_OEM_COMMA: charForOEMKeyCode = ','; break; 1.1729 + case VK_OEM_MINUS: charForOEMKeyCode = '-'; break; 1.1730 + case VK_OEM_PERIOD: charForOEMKeyCode = '.'; break; 1.1731 + } 1.1732 + if (charForOEMKeyCode && 1.1733 + charForOEMKeyCode != unshiftedChars.mChars[0] && 1.1734 + charForOEMKeyCode != shiftedChars.mChars[0] && 1.1735 + charForOEMKeyCode != unshiftedLatinChar && 1.1736 + charForOEMKeyCode != shiftedLatinChar) { 1.1737 + AlternativeCharCode OEMChars(charForOEMKeyCode, charForOEMKeyCode); 1.1738 + altArray.AppendElement(OEMChars); 1.1739 + } 1.1740 + } 1.1741 + 1.1742 + WidgetKeyboardEvent keypressEvent(true, NS_KEY_PRESS, mWidget); 1.1743 + keypressEvent.charCode = uniChar; 1.1744 + keypressEvent.alternativeCharCodes.AppendElements(altArray); 1.1745 + InitKeyEvent(keypressEvent, modKeyState); 1.1746 + defaultPrevented = (DispatchKeyEvent(keypressEvent) || defaultPrevented); 1.1747 + if (mWidget->Destroyed()) { 1.1748 + return true; 1.1749 + } 1.1750 + } 1.1751 + 1.1752 + return defaultPrevented; 1.1753 +} 1.1754 + 1.1755 +bool 1.1756 +NativeKey::DispatchKeyPressEventForFollowingCharMessage( 1.1757 + const MSG& aCharMsg) const 1.1758 +{ 1.1759 + MOZ_ASSERT(IsKeyDownMessage()); 1.1760 + 1.1761 + if (mFakeCharMsgs) { 1.1762 + if (IsDeadCharMessage(aCharMsg)) { 1.1763 + return false; 1.1764 + } 1.1765 +#ifdef DEBUG 1.1766 + if (mIsPrintableKey) { 1.1767 + nsPrintfCString log( 1.1768 + "mOriginalVirtualKeyCode=0x%02X, mCommittedCharsAndModifiers={ " 1.1769 + "mChars=[ 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X ], mLength=%d }, " 1.1770 + "wParam=0x%04X", 1.1771 + mOriginalVirtualKeyCode, mCommittedCharsAndModifiers.mChars[0], 1.1772 + mCommittedCharsAndModifiers.mChars[1], 1.1773 + mCommittedCharsAndModifiers.mChars[2], 1.1774 + mCommittedCharsAndModifiers.mChars[3], 1.1775 + mCommittedCharsAndModifiers.mChars[4], 1.1776 + mCommittedCharsAndModifiers.mLength, aCharMsg.wParam); 1.1777 + if (mCommittedCharsAndModifiers.IsEmpty()) { 1.1778 + log.Insert("length is zero: ", 0); 1.1779 + NS_ERROR(log.get()); 1.1780 + NS_ABORT(); 1.1781 + } else if (mCommittedCharsAndModifiers.mChars[0] != aCharMsg.wParam) { 1.1782 + log.Insert("character mismatch: ", 0); 1.1783 + NS_ERROR(log.get()); 1.1784 + NS_ABORT(); 1.1785 + } 1.1786 + } 1.1787 +#endif // #ifdef DEBUG 1.1788 + return HandleCharMessage(aCharMsg); 1.1789 + } 1.1790 + 1.1791 + if (IsDeadCharMessage(aCharMsg)) { 1.1792 + if (!mWidget->PluginHasFocus()) { 1.1793 + return false; 1.1794 + } 1.1795 + return (mWidget->DispatchPluginEvent(aCharMsg) || mWidget->Destroyed()); 1.1796 + } 1.1797 + 1.1798 + bool defaultPrevented = HandleCharMessage(aCharMsg); 1.1799 + // If a syschar keypress wasn't processed, Windows may want to 1.1800 + // handle it to activate a native menu. 1.1801 + if (!defaultPrevented && IsSysCharMessage(aCharMsg)) { 1.1802 + ::DefWindowProcW(aCharMsg.hwnd, aCharMsg.message, 1.1803 + aCharMsg.wParam, aCharMsg.lParam); 1.1804 + } 1.1805 + return defaultPrevented; 1.1806 +} 1.1807 + 1.1808 +/***************************************************************************** 1.1809 + * mozilla::widget::KeyboardLayout 1.1810 + *****************************************************************************/ 1.1811 + 1.1812 +KeyboardLayout* KeyboardLayout::sInstance = nullptr; 1.1813 +nsIIdleServiceInternal* KeyboardLayout::sIdleService = nullptr; 1.1814 + 1.1815 +// static 1.1816 +KeyboardLayout* 1.1817 +KeyboardLayout::GetInstance() 1.1818 +{ 1.1819 + if (!sInstance) { 1.1820 + sInstance = new KeyboardLayout(); 1.1821 + nsCOMPtr<nsIIdleServiceInternal> idleService = 1.1822 + do_GetService("@mozilla.org/widget/idleservice;1"); 1.1823 + // The refcount will be decreased at shut down. 1.1824 + sIdleService = idleService.forget().take(); 1.1825 + } 1.1826 + return sInstance; 1.1827 +} 1.1828 + 1.1829 +// static 1.1830 +void 1.1831 +KeyboardLayout::Shutdown() 1.1832 +{ 1.1833 + delete sInstance; 1.1834 + sInstance = nullptr; 1.1835 + NS_IF_RELEASE(sIdleService); 1.1836 +} 1.1837 + 1.1838 +// static 1.1839 +void 1.1840 +KeyboardLayout::NotifyIdleServiceOfUserActivity() 1.1841 +{ 1.1842 + sIdleService->ResetIdleTimeOut(0); 1.1843 +} 1.1844 + 1.1845 +KeyboardLayout::KeyboardLayout() : 1.1846 + mKeyboardLayout(0), mIsOverridden(false), 1.1847 + mIsPendingToRestoreKeyboardLayout(false) 1.1848 +{ 1.1849 + mDeadKeyTableListHead = nullptr; 1.1850 + 1.1851 + // NOTE: LoadLayout() should be called via OnLayoutChange(). 1.1852 +} 1.1853 + 1.1854 +KeyboardLayout::~KeyboardLayout() 1.1855 +{ 1.1856 + ReleaseDeadKeyTables(); 1.1857 +} 1.1858 + 1.1859 +bool 1.1860 +KeyboardLayout::IsPrintableCharKey(uint8_t aVirtualKey) 1.1861 +{ 1.1862 + return GetKeyIndex(aVirtualKey) >= 0; 1.1863 +} 1.1864 + 1.1865 +WORD 1.1866 +KeyboardLayout::ComputeScanCodeForVirtualKeyCode(uint8_t aVirtualKeyCode) const 1.1867 +{ 1.1868 + return static_cast<WORD>( 1.1869 + ::MapVirtualKeyEx(aVirtualKeyCode, MAPVK_VK_TO_VSC, GetLayout())); 1.1870 +} 1.1871 + 1.1872 +bool 1.1873 +KeyboardLayout::IsDeadKey(uint8_t aVirtualKey, 1.1874 + const ModifierKeyState& aModKeyState) const 1.1875 +{ 1.1876 + int32_t virtualKeyIndex = GetKeyIndex(aVirtualKey); 1.1877 + if (virtualKeyIndex < 0) { 1.1878 + return false; 1.1879 + } 1.1880 + 1.1881 + return mVirtualKeys[virtualKeyIndex].IsDeadKey( 1.1882 + VirtualKey::ModifiersToShiftState(aModKeyState.GetModifiers())); 1.1883 +} 1.1884 + 1.1885 +void 1.1886 +KeyboardLayout::InitNativeKey(NativeKey& aNativeKey, 1.1887 + const ModifierKeyState& aModKeyState) 1.1888 +{ 1.1889 + if (mIsPendingToRestoreKeyboardLayout) { 1.1890 + LoadLayout(::GetKeyboardLayout(0)); 1.1891 + } 1.1892 + 1.1893 + uint8_t virtualKey = aNativeKey.mOriginalVirtualKeyCode; 1.1894 + int32_t virtualKeyIndex = GetKeyIndex(virtualKey); 1.1895 + 1.1896 + if (virtualKeyIndex < 0) { 1.1897 + // Does not produce any printable characters, but still preserves the 1.1898 + // dead-key state. 1.1899 + return; 1.1900 + } 1.1901 + 1.1902 + MOZ_ASSERT(aNativeKey.mKeyNameIndex == KEY_NAME_INDEX_USE_STRING, 1.1903 + "Printable key's key name index must be KEY_NAME_INDEX_USE_STRING"); 1.1904 + 1.1905 + bool isKeyDown = aNativeKey.IsKeyDownMessage(); 1.1906 + uint8_t shiftState = 1.1907 + VirtualKey::ModifiersToShiftState(aModKeyState.GetModifiers()); 1.1908 + 1.1909 + if (mVirtualKeys[virtualKeyIndex].IsDeadKey(shiftState)) { 1.1910 + if ((isKeyDown && mActiveDeadKey < 0) || 1.1911 + (!isKeyDown && mActiveDeadKey == virtualKey)) { 1.1912 + // First dead key event doesn't generate characters. 1.1913 + if (isKeyDown) { 1.1914 + // Dead-key state activated at keydown. 1.1915 + mActiveDeadKey = virtualKey; 1.1916 + mDeadKeyShiftState = shiftState; 1.1917 + } 1.1918 + UniCharsAndModifiers deadChars = 1.1919 + mVirtualKeys[virtualKeyIndex].GetNativeUniChars(shiftState); 1.1920 + NS_ASSERTION(deadChars.mLength == 1, 1.1921 + "dead key must generate only one character"); 1.1922 + aNativeKey.mKeyNameIndex = 1.1923 + WidgetUtils::GetDeadKeyNameIndex(deadChars.mChars[0]); 1.1924 + return; 1.1925 + } 1.1926 + 1.1927 + // Dead key followed by another dead key causes inputting both character. 1.1928 + // However, at keydown message handling, we need to forget the first 1.1929 + // dead key because there is no guarantee coming WM_KEYUP for the second 1.1930 + // dead key before next WM_KEYDOWN. E.g., due to auto key repeat or 1.1931 + // pressing another dead key before releasing current key. Therefore, 1.1932 + // we can set only a character for current key for keyup event. 1.1933 + if (mActiveDeadKey < 0) { 1.1934 + aNativeKey.mCommittedCharsAndModifiers = 1.1935 + mVirtualKeys[virtualKeyIndex].GetUniChars(shiftState); 1.1936 + return; 1.1937 + } 1.1938 + 1.1939 + int32_t activeDeadKeyIndex = GetKeyIndex(mActiveDeadKey); 1.1940 + if (activeDeadKeyIndex < 0 || activeDeadKeyIndex >= NS_NUM_OF_KEYS) { 1.1941 +#if defined(DEBUG) || defined(MOZ_CRASHREPORTER) 1.1942 + nsPrintfCString warning("The virtual key index (%d) of mActiveDeadKey " 1.1943 + "(0x%02X) is not a printable key (virtualKey=" 1.1944 + "0x%02X)", 1.1945 + activeDeadKeyIndex, mActiveDeadKey, virtualKey); 1.1946 + NS_WARNING(warning.get()); 1.1947 +#ifdef MOZ_CRASHREPORTER 1.1948 + CrashReporter::AppendAppNotesToCrashReport( 1.1949 + NS_LITERAL_CSTRING("\n") + warning); 1.1950 +#endif // #ifdef MOZ_CRASHREPORTER 1.1951 +#endif // #if defined(DEBUG) || defined(MOZ_CRASHREPORTER) 1.1952 + MOZ_CRASH("Trying to reference out of range of mVirtualKeys"); 1.1953 + } 1.1954 + UniCharsAndModifiers prevDeadChars = 1.1955 + mVirtualKeys[activeDeadKeyIndex].GetUniChars(mDeadKeyShiftState); 1.1956 + UniCharsAndModifiers newChars = 1.1957 + mVirtualKeys[virtualKeyIndex].GetUniChars(shiftState); 1.1958 + // But keypress events should be fired for each committed character. 1.1959 + aNativeKey.mCommittedCharsAndModifiers = prevDeadChars + newChars; 1.1960 + if (isKeyDown) { 1.1961 + DeactivateDeadKeyState(); 1.1962 + } 1.1963 + return; 1.1964 + } 1.1965 + 1.1966 + UniCharsAndModifiers baseChars = 1.1967 + mVirtualKeys[virtualKeyIndex].GetUniChars(shiftState); 1.1968 + if (mActiveDeadKey < 0) { 1.1969 + // No dead-keys are active. Just return the produced characters. 1.1970 + aNativeKey.mCommittedCharsAndModifiers = baseChars; 1.1971 + return; 1.1972 + } 1.1973 + 1.1974 + // Dead-key was active. See if pressed base character does produce 1.1975 + // valid composite character. 1.1976 + int32_t activeDeadKeyIndex = GetKeyIndex(mActiveDeadKey); 1.1977 + char16_t compositeChar = (baseChars.mLength == 1 && baseChars.mChars[0]) ? 1.1978 + mVirtualKeys[activeDeadKeyIndex].GetCompositeChar(mDeadKeyShiftState, 1.1979 + baseChars.mChars[0]) : 0; 1.1980 + if (compositeChar) { 1.1981 + // Active dead-key and base character does produce exactly one 1.1982 + // composite character. 1.1983 + aNativeKey.mCommittedCharsAndModifiers.Append(compositeChar, 1.1984 + baseChars.mModifiers[0]); 1.1985 + if (isKeyDown) { 1.1986 + DeactivateDeadKeyState(); 1.1987 + } 1.1988 + return; 1.1989 + } 1.1990 + 1.1991 + // There is no valid dead-key and base character combination. 1.1992 + // Return dead-key character followed by base character. 1.1993 + UniCharsAndModifiers deadChars = 1.1994 + mVirtualKeys[activeDeadKeyIndex].GetUniChars(mDeadKeyShiftState); 1.1995 + // But keypress events should be fired for each committed character. 1.1996 + aNativeKey.mCommittedCharsAndModifiers = deadChars + baseChars; 1.1997 + if (isKeyDown) { 1.1998 + DeactivateDeadKeyState(); 1.1999 + } 1.2000 + 1.2001 + return; 1.2002 +} 1.2003 + 1.2004 +UniCharsAndModifiers 1.2005 +KeyboardLayout::GetUniCharsAndModifiers( 1.2006 + uint8_t aVirtualKey, 1.2007 + const ModifierKeyState& aModKeyState) const 1.2008 +{ 1.2009 + UniCharsAndModifiers result; 1.2010 + int32_t key = GetKeyIndex(aVirtualKey); 1.2011 + if (key < 0) { 1.2012 + return result; 1.2013 + } 1.2014 + return mVirtualKeys[key]. 1.2015 + GetUniChars(VirtualKey::ModifiersToShiftState(aModKeyState.GetModifiers())); 1.2016 +} 1.2017 + 1.2018 +void 1.2019 +KeyboardLayout::LoadLayout(HKL aLayout) 1.2020 +{ 1.2021 + mIsPendingToRestoreKeyboardLayout = false; 1.2022 + 1.2023 + if (mKeyboardLayout == aLayout) { 1.2024 + return; 1.2025 + } 1.2026 + 1.2027 + mKeyboardLayout = aLayout; 1.2028 + 1.2029 + BYTE kbdState[256]; 1.2030 + memset(kbdState, 0, sizeof(kbdState)); 1.2031 + 1.2032 + BYTE originalKbdState[256]; 1.2033 + // Bitfield with all shift states that have at least one dead-key. 1.2034 + uint16_t shiftStatesWithDeadKeys = 0; 1.2035 + // Bitfield with all shift states that produce any possible dead-key base 1.2036 + // characters. 1.2037 + uint16_t shiftStatesWithBaseChars = 0; 1.2038 + 1.2039 + mActiveDeadKey = -1; 1.2040 + 1.2041 + ReleaseDeadKeyTables(); 1.2042 + 1.2043 + ::GetKeyboardState(originalKbdState); 1.2044 + 1.2045 + // For each shift state gather all printable characters that are produced 1.2046 + // for normal case when no any dead-key is active. 1.2047 + 1.2048 + for (VirtualKey::ShiftState shiftState = 0; shiftState < 16; shiftState++) { 1.2049 + VirtualKey::FillKbdState(kbdState, shiftState); 1.2050 + for (uint32_t virtualKey = 0; virtualKey < 256; virtualKey++) { 1.2051 + int32_t vki = GetKeyIndex(virtualKey); 1.2052 + if (vki < 0) { 1.2053 + continue; 1.2054 + } 1.2055 + NS_ASSERTION(uint32_t(vki) < ArrayLength(mVirtualKeys), "invalid index"); 1.2056 + char16_t uniChars[5]; 1.2057 + int32_t ret = 1.2058 + ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)uniChars, 1.2059 + ArrayLength(uniChars), 0, mKeyboardLayout); 1.2060 + // dead-key 1.2061 + if (ret < 0) { 1.2062 + shiftStatesWithDeadKeys |= (1 << shiftState); 1.2063 + // Repeat dead-key to deactivate it and get its character 1.2064 + // representation. 1.2065 + char16_t deadChar[2]; 1.2066 + ret = ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)deadChar, 1.2067 + ArrayLength(deadChar), 0, mKeyboardLayout); 1.2068 + NS_ASSERTION(ret == 2, "Expecting twice repeated dead-key character"); 1.2069 + mVirtualKeys[vki].SetDeadChar(shiftState, deadChar[0]); 1.2070 + } else { 1.2071 + if (ret == 1) { 1.2072 + // dead-key can pair only with exactly one base character. 1.2073 + shiftStatesWithBaseChars |= (1 << shiftState); 1.2074 + } 1.2075 + mVirtualKeys[vki].SetNormalChars(shiftState, uniChars, ret); 1.2076 + } 1.2077 + } 1.2078 + } 1.2079 + 1.2080 + // Now process each dead-key to find all its base characters and resulting 1.2081 + // composite characters. 1.2082 + for (VirtualKey::ShiftState shiftState = 0; shiftState < 16; shiftState++) { 1.2083 + if (!(shiftStatesWithDeadKeys & (1 << shiftState))) { 1.2084 + continue; 1.2085 + } 1.2086 + 1.2087 + VirtualKey::FillKbdState(kbdState, shiftState); 1.2088 + 1.2089 + for (uint32_t virtualKey = 0; virtualKey < 256; virtualKey++) { 1.2090 + int32_t vki = GetKeyIndex(virtualKey); 1.2091 + if (vki >= 0 && mVirtualKeys[vki].IsDeadKey(shiftState)) { 1.2092 + DeadKeyEntry deadKeyArray[256]; 1.2093 + int32_t n = GetDeadKeyCombinations(virtualKey, kbdState, 1.2094 + shiftStatesWithBaseChars, 1.2095 + deadKeyArray, 1.2096 + ArrayLength(deadKeyArray)); 1.2097 + const DeadKeyTable* dkt = 1.2098 + mVirtualKeys[vki].MatchingDeadKeyTable(deadKeyArray, n); 1.2099 + if (!dkt) { 1.2100 + dkt = AddDeadKeyTable(deadKeyArray, n); 1.2101 + } 1.2102 + mVirtualKeys[vki].AttachDeadKeyTable(shiftState, dkt); 1.2103 + } 1.2104 + } 1.2105 + } 1.2106 + 1.2107 + ::SetKeyboardState(originalKbdState); 1.2108 +} 1.2109 + 1.2110 +inline int32_t 1.2111 +KeyboardLayout::GetKeyIndex(uint8_t aVirtualKey) 1.2112 +{ 1.2113 +// Currently these 68 (NS_NUM_OF_KEYS) virtual keys are assumed 1.2114 +// to produce visible representation: 1.2115 +// 0x20 - VK_SPACE ' ' 1.2116 +// 0x30..0x39 '0'..'9' 1.2117 +// 0x41..0x5A 'A'..'Z' 1.2118 +// 0x60..0x69 '0'..'9' on numpad 1.2119 +// 0x6A - VK_MULTIPLY '*' on numpad 1.2120 +// 0x6B - VK_ADD '+' on numpad 1.2121 +// 0x6D - VK_SUBTRACT '-' on numpad 1.2122 +// 0x6E - VK_DECIMAL '.' on numpad 1.2123 +// 0x6F - VK_DIVIDE '/' on numpad 1.2124 +// 0x6E - VK_DECIMAL '.' 1.2125 +// 0xBA - VK_OEM_1 ';:' for US 1.2126 +// 0xBB - VK_OEM_PLUS '+' any country 1.2127 +// 0xBC - VK_OEM_COMMA ',' any country 1.2128 +// 0xBD - VK_OEM_MINUS '-' any country 1.2129 +// 0xBE - VK_OEM_PERIOD '.' any country 1.2130 +// 0xBF - VK_OEM_2 '/?' for US 1.2131 +// 0xC0 - VK_OEM_3 '`~' for US 1.2132 +// 0xC1 - VK_ABNT_C1 '/?' for Brazilian 1.2133 +// 0xC2 - VK_ABNT_C2 separator key on numpad (Brazilian or JIS for Mac) 1.2134 +// 0xDB - VK_OEM_4 '[{' for US 1.2135 +// 0xDC - VK_OEM_5 '\|' for US 1.2136 +// 0xDD - VK_OEM_6 ']}' for US 1.2137 +// 0xDE - VK_OEM_7 ''"' for US 1.2138 +// 0xDF - VK_OEM_8 1.2139 +// 0xE1 - no name 1.2140 +// 0xE2 - VK_OEM_102 '\_' for JIS 1.2141 +// 0xE3 - no name 1.2142 +// 0xE4 - no name 1.2143 + 1.2144 + static const int8_t xlat[256] = 1.2145 + { 1.2146 + // 0 1 2 3 4 5 6 7 8 9 A B C D E F 1.2147 + //----------------------------------------------------------------------- 1.2148 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00 1.2149 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10 1.2150 + 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 20 1.2151 + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, // 30 1.2152 + -1, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 40 1.2153 + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, -1, -1, -1, // 50 1.2154 + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, -1, 49, 50, 51, // 60 1.2155 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 70 1.2156 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 80 1.2157 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 90 1.2158 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // A0 1.2159 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 52, 53, 54, 55, 56, 57, // B0 1.2160 + 58, 59, 60, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // C0 1.2161 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 61, 62, 63, 64, 65, // D0 1.2162 + -1, 66, 67, 68, 69, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // E0 1.2163 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // F0 1.2164 + }; 1.2165 + 1.2166 + return xlat[aVirtualKey]; 1.2167 +} 1.2168 + 1.2169 +int 1.2170 +KeyboardLayout::CompareDeadKeyEntries(const void* aArg1, 1.2171 + const void* aArg2, 1.2172 + void*) 1.2173 +{ 1.2174 + const DeadKeyEntry* arg1 = static_cast<const DeadKeyEntry*>(aArg1); 1.2175 + const DeadKeyEntry* arg2 = static_cast<const DeadKeyEntry*>(aArg2); 1.2176 + 1.2177 + return arg1->BaseChar - arg2->BaseChar; 1.2178 +} 1.2179 + 1.2180 +const DeadKeyTable* 1.2181 +KeyboardLayout::AddDeadKeyTable(const DeadKeyEntry* aDeadKeyArray, 1.2182 + uint32_t aEntries) 1.2183 +{ 1.2184 + DeadKeyTableListEntry* next = mDeadKeyTableListHead; 1.2185 + 1.2186 + const size_t bytes = offsetof(DeadKeyTableListEntry, data) + 1.2187 + DeadKeyTable::SizeInBytes(aEntries); 1.2188 + uint8_t* p = new uint8_t[bytes]; 1.2189 + 1.2190 + mDeadKeyTableListHead = reinterpret_cast<DeadKeyTableListEntry*>(p); 1.2191 + mDeadKeyTableListHead->next = next; 1.2192 + 1.2193 + DeadKeyTable* dkt = 1.2194 + reinterpret_cast<DeadKeyTable*>(mDeadKeyTableListHead->data); 1.2195 + 1.2196 + dkt->Init(aDeadKeyArray, aEntries); 1.2197 + 1.2198 + return dkt; 1.2199 +} 1.2200 + 1.2201 +void 1.2202 +KeyboardLayout::ReleaseDeadKeyTables() 1.2203 +{ 1.2204 + while (mDeadKeyTableListHead) { 1.2205 + uint8_t* p = reinterpret_cast<uint8_t*>(mDeadKeyTableListHead); 1.2206 + mDeadKeyTableListHead = mDeadKeyTableListHead->next; 1.2207 + 1.2208 + delete [] p; 1.2209 + } 1.2210 +} 1.2211 + 1.2212 +bool 1.2213 +KeyboardLayout::EnsureDeadKeyActive(bool aIsActive, 1.2214 + uint8_t aDeadKey, 1.2215 + const PBYTE aDeadKeyKbdState) 1.2216 +{ 1.2217 + int32_t ret; 1.2218 + do { 1.2219 + char16_t dummyChars[5]; 1.2220 + ret = ::ToUnicodeEx(aDeadKey, 0, (PBYTE)aDeadKeyKbdState, 1.2221 + (LPWSTR)dummyChars, ArrayLength(dummyChars), 0, 1.2222 + mKeyboardLayout); 1.2223 + // returned values: 1.2224 + // <0 - Dead key state is active. The keyboard driver will wait for next 1.2225 + // character. 1.2226 + // 1 - Previous pressed key was a valid base character that produced 1.2227 + // exactly one composite character. 1.2228 + // >1 - Previous pressed key does not produce any composite characters. 1.2229 + // Return dead-key character followed by base character(s). 1.2230 + } while ((ret < 0) != aIsActive); 1.2231 + 1.2232 + return (ret < 0); 1.2233 +} 1.2234 + 1.2235 +void 1.2236 +KeyboardLayout::DeactivateDeadKeyState() 1.2237 +{ 1.2238 + if (mActiveDeadKey < 0) { 1.2239 + return; 1.2240 + } 1.2241 + 1.2242 + BYTE kbdState[256]; 1.2243 + memset(kbdState, 0, sizeof(kbdState)); 1.2244 + 1.2245 + VirtualKey::FillKbdState(kbdState, mDeadKeyShiftState); 1.2246 + 1.2247 + EnsureDeadKeyActive(false, mActiveDeadKey, kbdState); 1.2248 + mActiveDeadKey = -1; 1.2249 +} 1.2250 + 1.2251 +bool 1.2252 +KeyboardLayout::AddDeadKeyEntry(char16_t aBaseChar, 1.2253 + char16_t aCompositeChar, 1.2254 + DeadKeyEntry* aDeadKeyArray, 1.2255 + uint32_t aEntries) 1.2256 +{ 1.2257 + for (uint32_t index = 0; index < aEntries; index++) { 1.2258 + if (aDeadKeyArray[index].BaseChar == aBaseChar) { 1.2259 + return false; 1.2260 + } 1.2261 + } 1.2262 + 1.2263 + aDeadKeyArray[aEntries].BaseChar = aBaseChar; 1.2264 + aDeadKeyArray[aEntries].CompositeChar = aCompositeChar; 1.2265 + 1.2266 + return true; 1.2267 +} 1.2268 + 1.2269 +uint32_t 1.2270 +KeyboardLayout::GetDeadKeyCombinations(uint8_t aDeadKey, 1.2271 + const PBYTE aDeadKeyKbdState, 1.2272 + uint16_t aShiftStatesWithBaseChars, 1.2273 + DeadKeyEntry* aDeadKeyArray, 1.2274 + uint32_t aMaxEntries) 1.2275 +{ 1.2276 + bool deadKeyActive = false; 1.2277 + uint32_t entries = 0; 1.2278 + BYTE kbdState[256]; 1.2279 + memset(kbdState, 0, sizeof(kbdState)); 1.2280 + 1.2281 + for (uint32_t shiftState = 0; shiftState < 16; shiftState++) { 1.2282 + if (!(aShiftStatesWithBaseChars & (1 << shiftState))) { 1.2283 + continue; 1.2284 + } 1.2285 + 1.2286 + VirtualKey::FillKbdState(kbdState, shiftState); 1.2287 + 1.2288 + for (uint32_t virtualKey = 0; virtualKey < 256; virtualKey++) { 1.2289 + int32_t vki = GetKeyIndex(virtualKey); 1.2290 + // Dead-key can pair only with such key that produces exactly one base 1.2291 + // character. 1.2292 + if (vki >= 0 && 1.2293 + mVirtualKeys[vki].GetNativeUniChars(shiftState).mLength == 1) { 1.2294 + // Ensure dead-key is in active state, when it swallows entered 1.2295 + // character and waits for the next pressed key. 1.2296 + if (!deadKeyActive) { 1.2297 + deadKeyActive = EnsureDeadKeyActive(true, aDeadKey, 1.2298 + aDeadKeyKbdState); 1.2299 + } 1.2300 + 1.2301 + // Depending on the character the followed the dead-key, the keyboard 1.2302 + // driver can produce one composite character, or a dead-key character 1.2303 + // followed by a second character. 1.2304 + char16_t compositeChars[5]; 1.2305 + int32_t ret = 1.2306 + ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)compositeChars, 1.2307 + ArrayLength(compositeChars), 0, mKeyboardLayout); 1.2308 + switch (ret) { 1.2309 + case 0: 1.2310 + // This key combination does not produce any characters. The 1.2311 + // dead-key is still in active state. 1.2312 + break; 1.2313 + case 1: { 1.2314 + // Exactly one composite character produced. Now, when dead-key 1.2315 + // is not active, repeat the last character one more time to 1.2316 + // determine the base character. 1.2317 + char16_t baseChars[5]; 1.2318 + ret = ::ToUnicodeEx(virtualKey, 0, kbdState, (LPWSTR)baseChars, 1.2319 + ArrayLength(baseChars), 0, mKeyboardLayout); 1.2320 + NS_ASSERTION(ret == 1, "One base character expected"); 1.2321 + if (ret == 1 && entries < aMaxEntries && 1.2322 + AddDeadKeyEntry(baseChars[0], compositeChars[0], 1.2323 + aDeadKeyArray, entries)) { 1.2324 + entries++; 1.2325 + } 1.2326 + deadKeyActive = false; 1.2327 + break; 1.2328 + } 1.2329 + default: 1.2330 + // 1. Unexpected dead-key. Dead-key chaining is not supported. 1.2331 + // 2. More than one character generated. This is not a valid 1.2332 + // dead-key and base character combination. 1.2333 + deadKeyActive = false; 1.2334 + break; 1.2335 + } 1.2336 + } 1.2337 + } 1.2338 + } 1.2339 + 1.2340 + if (deadKeyActive) { 1.2341 + deadKeyActive = EnsureDeadKeyActive(false, aDeadKey, aDeadKeyKbdState); 1.2342 + } 1.2343 + 1.2344 + NS_QuickSort(aDeadKeyArray, entries, sizeof(DeadKeyEntry), 1.2345 + CompareDeadKeyEntries, nullptr); 1.2346 + return entries; 1.2347 +} 1.2348 + 1.2349 +uint32_t 1.2350 +KeyboardLayout::ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const 1.2351 +{ 1.2352 + // Alphabet or Numeric or Numpad or Function keys 1.2353 + if ((aNativeKeyCode >= 0x30 && aNativeKeyCode <= 0x39) || 1.2354 + (aNativeKeyCode >= 0x41 && aNativeKeyCode <= 0x5A) || 1.2355 + (aNativeKeyCode >= 0x60 && aNativeKeyCode <= 0x87)) { 1.2356 + return static_cast<uint32_t>(aNativeKeyCode); 1.2357 + } 1.2358 + switch (aNativeKeyCode) { 1.2359 + // Following keycodes are same as our DOM keycodes 1.2360 + case VK_CANCEL: 1.2361 + case VK_BACK: 1.2362 + case VK_TAB: 1.2363 + case VK_CLEAR: 1.2364 + case VK_RETURN: 1.2365 + case VK_SHIFT: 1.2366 + case VK_CONTROL: 1.2367 + case VK_MENU: // Alt 1.2368 + case VK_PAUSE: 1.2369 + case VK_CAPITAL: // CAPS LOCK 1.2370 + case VK_KANA: // same as VK_HANGUL 1.2371 + case VK_JUNJA: 1.2372 + case VK_FINAL: 1.2373 + case VK_HANJA: // same as VK_KANJI 1.2374 + case VK_ESCAPE: 1.2375 + case VK_CONVERT: 1.2376 + case VK_NONCONVERT: 1.2377 + case VK_ACCEPT: 1.2378 + case VK_MODECHANGE: 1.2379 + case VK_SPACE: 1.2380 + case VK_PRIOR: // PAGE UP 1.2381 + case VK_NEXT: // PAGE DOWN 1.2382 + case VK_END: 1.2383 + case VK_HOME: 1.2384 + case VK_LEFT: 1.2385 + case VK_UP: 1.2386 + case VK_RIGHT: 1.2387 + case VK_DOWN: 1.2388 + case VK_SELECT: 1.2389 + case VK_PRINT: 1.2390 + case VK_EXECUTE: 1.2391 + case VK_SNAPSHOT: 1.2392 + case VK_INSERT: 1.2393 + case VK_DELETE: 1.2394 + case VK_APPS: // Context Menu 1.2395 + case VK_SLEEP: 1.2396 + case VK_NUMLOCK: 1.2397 + case VK_SCROLL: // SCROLL LOCK 1.2398 + case VK_ATTN: // Attension key of IBM midrange computers, e.g., AS/400 1.2399 + case VK_CRSEL: // Cursor Selection 1.2400 + case VK_EXSEL: // Extend Selection 1.2401 + case VK_EREOF: // Erase EOF key of IBM 3270 keyboard layout 1.2402 + case VK_PLAY: 1.2403 + case VK_ZOOM: 1.2404 + case VK_PA1: // PA1 key of IBM 3270 keyboard layout 1.2405 + return uint32_t(aNativeKeyCode); 1.2406 + 1.2407 + case VK_HELP: 1.2408 + return NS_VK_HELP; 1.2409 + 1.2410 + // Windows key should be mapped to a Win keycode 1.2411 + // They should be able to be distinguished by DOM3 KeyboardEvent.location 1.2412 + case VK_LWIN: 1.2413 + case VK_RWIN: 1.2414 + return NS_VK_WIN; 1.2415 + 1.2416 + case VK_VOLUME_MUTE: 1.2417 + return NS_VK_VOLUME_MUTE; 1.2418 + case VK_VOLUME_DOWN: 1.2419 + return NS_VK_VOLUME_DOWN; 1.2420 + case VK_VOLUME_UP: 1.2421 + return NS_VK_VOLUME_UP; 1.2422 + 1.2423 + // Following keycodes are not defined in our DOM keycodes. 1.2424 + case VK_BROWSER_BACK: 1.2425 + case VK_BROWSER_FORWARD: 1.2426 + case VK_BROWSER_REFRESH: 1.2427 + case VK_BROWSER_STOP: 1.2428 + case VK_BROWSER_SEARCH: 1.2429 + case VK_BROWSER_FAVORITES: 1.2430 + case VK_BROWSER_HOME: 1.2431 + case VK_MEDIA_NEXT_TRACK: 1.2432 + case VK_MEDIA_STOP: 1.2433 + case VK_MEDIA_PLAY_PAUSE: 1.2434 + case VK_LAUNCH_MAIL: 1.2435 + case VK_LAUNCH_MEDIA_SELECT: 1.2436 + case VK_LAUNCH_APP1: 1.2437 + case VK_LAUNCH_APP2: 1.2438 + return 0; 1.2439 + 1.2440 + // Following OEM specific virtual keycodes should pass through DOM keyCode 1.2441 + // for compatibility with the other browsers on Windows. 1.2442 + 1.2443 + // Following OEM specific virtual keycodes are defined for Fujitsu/OASYS. 1.2444 + case VK_OEM_FJ_JISHO: 1.2445 + case VK_OEM_FJ_MASSHOU: 1.2446 + case VK_OEM_FJ_TOUROKU: 1.2447 + case VK_OEM_FJ_LOYA: 1.2448 + case VK_OEM_FJ_ROYA: 1.2449 + // Not sure what means "ICO". 1.2450 + case VK_ICO_HELP: 1.2451 + case VK_ICO_00: 1.2452 + case VK_ICO_CLEAR: 1.2453 + // Following OEM specific virtual keycodes are defined for Nokia/Ericsson. 1.2454 + case VK_OEM_RESET: 1.2455 + case VK_OEM_JUMP: 1.2456 + case VK_OEM_PA1: 1.2457 + case VK_OEM_PA2: 1.2458 + case VK_OEM_PA3: 1.2459 + case VK_OEM_WSCTRL: 1.2460 + case VK_OEM_CUSEL: 1.2461 + case VK_OEM_ATTN: 1.2462 + case VK_OEM_FINISH: 1.2463 + case VK_OEM_COPY: 1.2464 + case VK_OEM_AUTO: 1.2465 + case VK_OEM_ENLW: 1.2466 + case VK_OEM_BACKTAB: 1.2467 + // VK_OEM_CLEAR is defined as not OEM specific, but let's pass though 1.2468 + // DOM keyCode like other OEM specific virtual keycodes. 1.2469 + case VK_OEM_CLEAR: 1.2470 + return uint32_t(aNativeKeyCode); 1.2471 + 1.2472 + // 0xE1 is an OEM specific virtual keycode. However, the value is already 1.2473 + // used in our DOM keyCode for AltGr on Linux. So, this virtual keycode 1.2474 + // cannot pass through DOM keyCode. 1.2475 + case 0xE1: 1.2476 + return 0; 1.2477 + 1.2478 + // Following keycodes are OEM keys which are keycodes for non-alphabet and 1.2479 + // non-numeric keys, we should compute each keycode of them from unshifted 1.2480 + // character which is inputted by each key. But if the unshifted character 1.2481 + // is not an ASCII character but shifted character is an ASCII character, 1.2482 + // we should refer it. 1.2483 + case VK_OEM_1: 1.2484 + case VK_OEM_PLUS: 1.2485 + case VK_OEM_COMMA: 1.2486 + case VK_OEM_MINUS: 1.2487 + case VK_OEM_PERIOD: 1.2488 + case VK_OEM_2: 1.2489 + case VK_OEM_3: 1.2490 + case VK_OEM_4: 1.2491 + case VK_OEM_5: 1.2492 + case VK_OEM_6: 1.2493 + case VK_OEM_7: 1.2494 + case VK_OEM_8: 1.2495 + case VK_OEM_102: 1.2496 + case VK_ABNT_C1: 1.2497 + { 1.2498 + NS_ASSERTION(IsPrintableCharKey(aNativeKeyCode), 1.2499 + "The key must be printable"); 1.2500 + ModifierKeyState modKeyState(0); 1.2501 + UniCharsAndModifiers uniChars = 1.2502 + GetUniCharsAndModifiers(aNativeKeyCode, modKeyState); 1.2503 + if (uniChars.mLength != 1 || 1.2504 + uniChars.mChars[0] < ' ' || uniChars.mChars[0] > 0x7F) { 1.2505 + modKeyState.Set(MODIFIER_SHIFT); 1.2506 + uniChars = GetUniCharsAndModifiers(aNativeKeyCode, modKeyState); 1.2507 + if (uniChars.mLength != 1 || 1.2508 + uniChars.mChars[0] < ' ' || uniChars.mChars[0] > 0x7F) { 1.2509 + return 0; 1.2510 + } 1.2511 + } 1.2512 + return WidgetUtils::ComputeKeyCodeFromChar(uniChars.mChars[0]); 1.2513 + } 1.2514 + 1.2515 + // IE sets 0xC2 to the DOM keyCode for VK_ABNT_C2. However, we're already 1.2516 + // using NS_VK_SEPARATOR for the separator key on Mac and Linux. Therefore, 1.2517 + // We should keep consistency between Gecko on all platforms rather than 1.2518 + // with other browsers since a lot of keyCode values are already different 1.2519 + // between browsers. 1.2520 + case VK_ABNT_C2: 1.2521 + return NS_VK_SEPARATOR; 1.2522 + 1.2523 + // VK_PROCESSKEY means IME already consumed the key event. 1.2524 + case VK_PROCESSKEY: 1.2525 + return 0; 1.2526 + // VK_PACKET is generated by SendInput() API, we don't need to 1.2527 + // care this message as key event. 1.2528 + case VK_PACKET: 1.2529 + return 0; 1.2530 + // If a key is not mapped to a virtual keycode, 0xFF is used. 1.2531 + case 0xFF: 1.2532 + NS_WARNING("The key is failed to be converted to a virtual keycode"); 1.2533 + return 0; 1.2534 + } 1.2535 +#ifdef DEBUG 1.2536 + nsPrintfCString warning("Unknown virtual keycode (0x%08X), please check the " 1.2537 + "latest MSDN document, there may be some new " 1.2538 + "keycodes we've never known.", 1.2539 + aNativeKeyCode); 1.2540 + NS_WARNING(warning.get()); 1.2541 +#endif 1.2542 + return 0; 1.2543 +} 1.2544 + 1.2545 +KeyNameIndex 1.2546 +KeyboardLayout::ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const 1.2547 +{ 1.2548 + if (IsPrintableCharKey(aVirtualKey)) { 1.2549 + return KEY_NAME_INDEX_USE_STRING; 1.2550 + } 1.2551 + 1.2552 +#define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) 1.2553 +#define NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) 1.2554 +#define NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) 1.2555 +#define NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) 1.2556 + 1.2557 + switch (aVirtualKey) { 1.2558 + 1.2559 +#undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX 1.2560 +#define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \ 1.2561 + case aNativeKey: return aKeyNameIndex; 1.2562 + 1.2563 +#include "NativeKeyToDOMKeyName.h" 1.2564 + 1.2565 +#undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX 1.2566 +#define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) 1.2567 + 1.2568 + default: 1.2569 + break; 1.2570 + } 1.2571 + 1.2572 + HKL layout = GetLayout(); 1.2573 + WORD langID = LOWORD(static_cast<HKL>(layout)); 1.2574 + WORD primaryLangID = PRIMARYLANGID(langID); 1.2575 + 1.2576 + if (primaryLangID == LANG_JAPANESE) { 1.2577 + switch (aVirtualKey) { 1.2578 + 1.2579 +#undef NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX 1.2580 +#define NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)\ 1.2581 + case aNativeKey: return aKeyNameIndex; 1.2582 + 1.2583 +#include "NativeKeyToDOMKeyName.h" 1.2584 + 1.2585 +#undef NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX 1.2586 +#define NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) 1.2587 + 1.2588 + default: 1.2589 + break; 1.2590 + } 1.2591 + } else if (primaryLangID == LANG_KOREAN) { 1.2592 + switch (aVirtualKey) { 1.2593 + 1.2594 +#undef NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX 1.2595 +#define NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)\ 1.2596 + case aNativeKey: return aKeyNameIndex; 1.2597 + 1.2598 +#include "NativeKeyToDOMKeyName.h" 1.2599 + 1.2600 +#undef NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX 1.2601 +#define NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) 1.2602 + 1.2603 + default: 1.2604 + return KEY_NAME_INDEX_Unidentified; 1.2605 + } 1.2606 + } 1.2607 + 1.2608 + switch (aVirtualKey) { 1.2609 + 1.2610 +#undef NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX 1.2611 +#define NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex)\ 1.2612 + case aNativeKey: return aKeyNameIndex; 1.2613 + 1.2614 +#include "NativeKeyToDOMKeyName.h" 1.2615 + 1.2616 +#undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX 1.2617 +#undef NS_JAPANESE_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX 1.2618 +#undef NS_KOREAN_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX 1.2619 +#undef NS_OTHER_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX 1.2620 + 1.2621 + default: 1.2622 + return KEY_NAME_INDEX_Unidentified; 1.2623 + } 1.2624 +} 1.2625 + 1.2626 +nsresult 1.2627 +KeyboardLayout::SynthesizeNativeKeyEvent(nsWindowBase* aWidget, 1.2628 + int32_t aNativeKeyboardLayout, 1.2629 + int32_t aNativeKeyCode, 1.2630 + uint32_t aModifierFlags, 1.2631 + const nsAString& aCharacters, 1.2632 + const nsAString& aUnmodifiedCharacters) 1.2633 +{ 1.2634 + UINT keyboardLayoutListCount = ::GetKeyboardLayoutList(0, nullptr); 1.2635 + NS_ASSERTION(keyboardLayoutListCount > 0, 1.2636 + "One keyboard layout must be installed at least"); 1.2637 + HKL keyboardLayoutListBuff[50]; 1.2638 + HKL* keyboardLayoutList = 1.2639 + keyboardLayoutListCount < 50 ? keyboardLayoutListBuff : 1.2640 + new HKL[keyboardLayoutListCount]; 1.2641 + keyboardLayoutListCount = 1.2642 + ::GetKeyboardLayoutList(keyboardLayoutListCount, keyboardLayoutList); 1.2643 + NS_ASSERTION(keyboardLayoutListCount > 0, 1.2644 + "Failed to get all keyboard layouts installed on the system"); 1.2645 + 1.2646 + nsPrintfCString layoutName("%08x", aNativeKeyboardLayout); 1.2647 + HKL loadedLayout = LoadKeyboardLayoutA(layoutName.get(), KLF_NOTELLSHELL); 1.2648 + if (loadedLayout == nullptr) { 1.2649 + if (keyboardLayoutListBuff != keyboardLayoutList) { 1.2650 + delete [] keyboardLayoutList; 1.2651 + } 1.2652 + return NS_ERROR_NOT_AVAILABLE; 1.2653 + } 1.2654 + 1.2655 + // Setup clean key state and load desired layout 1.2656 + BYTE originalKbdState[256]; 1.2657 + ::GetKeyboardState(originalKbdState); 1.2658 + BYTE kbdState[256]; 1.2659 + memset(kbdState, 0, sizeof(kbdState)); 1.2660 + // This changes the state of the keyboard for the current thread only, 1.2661 + // and we'll restore it soon, so this should be OK. 1.2662 + ::SetKeyboardState(kbdState); 1.2663 + 1.2664 + OverrideLayout(loadedLayout); 1.2665 + 1.2666 + uint8_t argumentKeySpecific = 0; 1.2667 + switch (aNativeKeyCode) { 1.2668 + case VK_SHIFT: 1.2669 + aModifierFlags &= ~(nsIWidget::SHIFT_L | nsIWidget::SHIFT_R); 1.2670 + argumentKeySpecific = VK_LSHIFT; 1.2671 + break; 1.2672 + case VK_LSHIFT: 1.2673 + aModifierFlags &= ~nsIWidget::SHIFT_L; 1.2674 + argumentKeySpecific = aNativeKeyCode; 1.2675 + aNativeKeyCode = VK_SHIFT; 1.2676 + break; 1.2677 + case VK_RSHIFT: 1.2678 + aModifierFlags &= ~nsIWidget::SHIFT_R; 1.2679 + argumentKeySpecific = aNativeKeyCode; 1.2680 + aNativeKeyCode = VK_SHIFT; 1.2681 + break; 1.2682 + case VK_CONTROL: 1.2683 + aModifierFlags &= ~(nsIWidget::CTRL_L | nsIWidget::CTRL_R); 1.2684 + argumentKeySpecific = VK_LCONTROL; 1.2685 + break; 1.2686 + case VK_LCONTROL: 1.2687 + aModifierFlags &= ~nsIWidget::CTRL_L; 1.2688 + argumentKeySpecific = aNativeKeyCode; 1.2689 + aNativeKeyCode = VK_CONTROL; 1.2690 + break; 1.2691 + case VK_RCONTROL: 1.2692 + aModifierFlags &= ~nsIWidget::CTRL_R; 1.2693 + argumentKeySpecific = aNativeKeyCode; 1.2694 + aNativeKeyCode = VK_CONTROL; 1.2695 + break; 1.2696 + case VK_MENU: 1.2697 + aModifierFlags &= ~(nsIWidget::ALT_L | nsIWidget::ALT_R); 1.2698 + argumentKeySpecific = VK_LMENU; 1.2699 + break; 1.2700 + case VK_LMENU: 1.2701 + aModifierFlags &= ~nsIWidget::ALT_L; 1.2702 + argumentKeySpecific = aNativeKeyCode; 1.2703 + aNativeKeyCode = VK_MENU; 1.2704 + break; 1.2705 + case VK_RMENU: 1.2706 + aModifierFlags &= ~nsIWidget::ALT_R; 1.2707 + argumentKeySpecific = aNativeKeyCode; 1.2708 + aNativeKeyCode = VK_MENU; 1.2709 + break; 1.2710 + case VK_CAPITAL: 1.2711 + aModifierFlags &= ~nsIWidget::CAPS_LOCK; 1.2712 + argumentKeySpecific = VK_CAPITAL; 1.2713 + break; 1.2714 + case VK_NUMLOCK: 1.2715 + aModifierFlags &= ~nsIWidget::NUM_LOCK; 1.2716 + argumentKeySpecific = VK_NUMLOCK; 1.2717 + break; 1.2718 + } 1.2719 + 1.2720 + nsAutoTArray<KeyPair,10> keySequence; 1.2721 + WinUtils::SetupKeyModifiersSequence(&keySequence, aModifierFlags); 1.2722 + NS_ASSERTION(aNativeKeyCode >= 0 && aNativeKeyCode < 256, 1.2723 + "Native VK key code out of range"); 1.2724 + keySequence.AppendElement(KeyPair(aNativeKeyCode, argumentKeySpecific)); 1.2725 + 1.2726 + // Simulate the pressing of each modifier key and then the real key 1.2727 + for (uint32_t i = 0; i < keySequence.Length(); ++i) { 1.2728 + uint8_t key = keySequence[i].mGeneral; 1.2729 + uint8_t keySpecific = keySequence[i].mSpecific; 1.2730 + kbdState[key] = 0x81; // key is down and toggled on if appropriate 1.2731 + if (keySpecific) { 1.2732 + kbdState[keySpecific] = 0x81; 1.2733 + } 1.2734 + ::SetKeyboardState(kbdState); 1.2735 + ModifierKeyState modKeyState; 1.2736 + UINT scanCode = 1.2737 + ComputeScanCodeForVirtualKeyCode(keySpecific ? keySpecific : key); 1.2738 + LPARAM lParam = static_cast<LPARAM>(scanCode << 16); 1.2739 + // Add extended key flag to the lParam for right control key and right alt 1.2740 + // key. 1.2741 + if (keySpecific == VK_RCONTROL || keySpecific == VK_RMENU) { 1.2742 + lParam |= 0x1000000; 1.2743 + } 1.2744 + MSG keyDownMsg = WinUtils::InitMSG(WM_KEYDOWN, key, lParam, 1.2745 + aWidget->GetWindowHandle()); 1.2746 + if (i == keySequence.Length() - 1) { 1.2747 + bool makeDeadCharMsg = 1.2748 + (IsDeadKey(key, modKeyState) && aCharacters.IsEmpty()); 1.2749 + nsAutoString chars(aCharacters); 1.2750 + if (makeDeadCharMsg) { 1.2751 + UniCharsAndModifiers deadChars = 1.2752 + GetUniCharsAndModifiers(key, modKeyState); 1.2753 + chars = deadChars.ToString(); 1.2754 + NS_ASSERTION(chars.Length() == 1, 1.2755 + "Dead char must be only one character"); 1.2756 + } 1.2757 + if (chars.IsEmpty()) { 1.2758 + NativeKey nativeKey(aWidget, keyDownMsg, modKeyState); 1.2759 + nativeKey.HandleKeyDownMessage(); 1.2760 + } else { 1.2761 + nsAutoTArray<NativeKey::FakeCharMsg, 10> fakeCharMsgs; 1.2762 + for (uint32_t j = 0; j < chars.Length(); j++) { 1.2763 + NativeKey::FakeCharMsg* fakeCharMsg = fakeCharMsgs.AppendElement(); 1.2764 + fakeCharMsg->mCharCode = chars.CharAt(j); 1.2765 + fakeCharMsg->mScanCode = scanCode; 1.2766 + fakeCharMsg->mIsDeadKey = makeDeadCharMsg; 1.2767 + } 1.2768 + NativeKey nativeKey(aWidget, keyDownMsg, modKeyState, &fakeCharMsgs); 1.2769 + bool dispatched; 1.2770 + nativeKey.HandleKeyDownMessage(&dispatched); 1.2771 + // If some char messages are not consumed, let's emulate the widget 1.2772 + // receiving the message directly. 1.2773 + for (uint32_t j = 1; j < fakeCharMsgs.Length(); j++) { 1.2774 + if (fakeCharMsgs[j].mConsumed) { 1.2775 + continue; 1.2776 + } 1.2777 + MSG charMsg = fakeCharMsgs[j].GetCharMsg(aWidget->GetWindowHandle()); 1.2778 + NativeKey nativeKey(aWidget, charMsg, modKeyState); 1.2779 + nativeKey.HandleCharMessage(charMsg); 1.2780 + } 1.2781 + } 1.2782 + } else { 1.2783 + NativeKey nativeKey(aWidget, keyDownMsg, modKeyState); 1.2784 + nativeKey.HandleKeyDownMessage(); 1.2785 + } 1.2786 + } 1.2787 + for (uint32_t i = keySequence.Length(); i > 0; --i) { 1.2788 + uint8_t key = keySequence[i - 1].mGeneral; 1.2789 + uint8_t keySpecific = keySequence[i - 1].mSpecific; 1.2790 + kbdState[key] = 0; // key is up and toggled off if appropriate 1.2791 + if (keySpecific) { 1.2792 + kbdState[keySpecific] = 0; 1.2793 + } 1.2794 + ::SetKeyboardState(kbdState); 1.2795 + ModifierKeyState modKeyState; 1.2796 + UINT scanCode = 1.2797 + ComputeScanCodeForVirtualKeyCode(keySpecific ? keySpecific : key); 1.2798 + LPARAM lParam = static_cast<LPARAM>(scanCode << 16); 1.2799 + // Add extended key flag to the lParam for right control key and right alt 1.2800 + // key. 1.2801 + if (keySpecific == VK_RCONTROL || keySpecific == VK_RMENU) { 1.2802 + lParam |= 0x1000000; 1.2803 + } 1.2804 + MSG keyUpMsg = WinUtils::InitMSG(WM_KEYUP, key, lParam, 1.2805 + aWidget->GetWindowHandle()); 1.2806 + NativeKey nativeKey(aWidget, keyUpMsg, modKeyState); 1.2807 + nativeKey.HandleKeyUpMessage(); 1.2808 + } 1.2809 + 1.2810 + // Restore old key state and layout 1.2811 + ::SetKeyboardState(originalKbdState); 1.2812 + RestoreLayout(); 1.2813 + 1.2814 + // Don't unload the layout if it's installed actually. 1.2815 + for (uint32_t i = 0; i < keyboardLayoutListCount; i++) { 1.2816 + if (keyboardLayoutList[i] == loadedLayout) { 1.2817 + loadedLayout = 0; 1.2818 + break; 1.2819 + } 1.2820 + } 1.2821 + if (keyboardLayoutListBuff != keyboardLayoutList) { 1.2822 + delete [] keyboardLayoutList; 1.2823 + } 1.2824 + if (loadedLayout) { 1.2825 + ::UnloadKeyboardLayout(loadedLayout); 1.2826 + } 1.2827 + return NS_OK; 1.2828 +} 1.2829 + 1.2830 +/***************************************************************************** 1.2831 + * mozilla::widget::DeadKeyTable 1.2832 + *****************************************************************************/ 1.2833 + 1.2834 +char16_t 1.2835 +DeadKeyTable::GetCompositeChar(char16_t aBaseChar) const 1.2836 +{ 1.2837 + // Dead-key table is sorted by BaseChar in ascending order. 1.2838 + // Usually they are too small to use binary search. 1.2839 + 1.2840 + for (uint32_t index = 0; index < mEntries; index++) { 1.2841 + if (mTable[index].BaseChar == aBaseChar) { 1.2842 + return mTable[index].CompositeChar; 1.2843 + } 1.2844 + if (mTable[index].BaseChar > aBaseChar) { 1.2845 + break; 1.2846 + } 1.2847 + } 1.2848 + 1.2849 + return 0; 1.2850 +} 1.2851 + 1.2852 +/***************************************************************************** 1.2853 + * mozilla::widget::RedirectedKeyDownMessage 1.2854 + *****************************************************************************/ 1.2855 + 1.2856 +MSG RedirectedKeyDownMessageManager::sRedirectedKeyDownMsg; 1.2857 +bool RedirectedKeyDownMessageManager::sDefaultPreventedOfRedirectedMsg = false; 1.2858 + 1.2859 +// static 1.2860 +bool 1.2861 +RedirectedKeyDownMessageManager::IsRedirectedMessage(const MSG& aMsg) 1.2862 +{ 1.2863 + return (aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN) && 1.2864 + (sRedirectedKeyDownMsg.message == aMsg.message && 1.2865 + WinUtils::GetScanCode(sRedirectedKeyDownMsg.lParam) == 1.2866 + WinUtils::GetScanCode(aMsg.lParam)); 1.2867 +} 1.2868 + 1.2869 +// static 1.2870 +void 1.2871 +RedirectedKeyDownMessageManager::RemoveNextCharMessage(HWND aWnd) 1.2872 +{ 1.2873 + MSG msg; 1.2874 + if (WinUtils::PeekMessage(&msg, aWnd, WM_KEYFIRST, WM_KEYLAST, 1.2875 + PM_NOREMOVE | PM_NOYIELD) && 1.2876 + (msg.message == WM_CHAR || msg.message == WM_SYSCHAR)) { 1.2877 + WinUtils::PeekMessage(&msg, aWnd, msg.message, msg.message, 1.2878 + PM_REMOVE | PM_NOYIELD); 1.2879 + } 1.2880 +} 1.2881 + 1.2882 +} // namespace widget 1.2883 +} // namespace mozilla 1.2884 +