Bug 773651 Guess VK_RCONTROL and VK_RMENU from extended key flag on XP and don't trust the scan code of key messages r=jimm

This commit is contained in:
Masayuki Nakano 2012-07-19 10:28:17 +09:00
parent 7e4f389cbe
commit 084ca1d1c9
3 changed files with 1002 additions and 810 deletions

File diff suppressed because it is too large Load Diff

View File

@ -386,37 +386,141 @@ NativeKey::NativeKey(const KeyboardLayout& aKeyboardLayout,
{
mScanCode = WinUtils::GetScanCode(aKeyOrCharMessage.lParam);
mIsExtended = WinUtils::IsExtendedScanCode(aKeyOrCharMessage.lParam);
// On WinXP and WinServer2003, we cannot compute the virtual keycode for
// extended keys due to the API limitation.
bool canComputeVirtualKeyCodeFromScanCode =
(!mIsExtended || WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION);
switch (aKeyOrCharMessage.message) {
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
mOriginalVirtualKeyCode = static_cast<PRUint8>(aKeyOrCharMessage.wParam);
switch (aKeyOrCharMessage.wParam) {
case WM_SYSKEYUP: {
// First, resolve the IME converted virtual keycode to its original
// keycode.
if (aKeyOrCharMessage.wParam == VK_PROCESSKEY) {
mOriginalVirtualKeyCode = static_cast<PRUint8>(
::ImmGetVirtualKey(aWindow->GetWindowHandle()));
} else {
mOriginalVirtualKeyCode =
static_cast<PRUint8>(aKeyOrCharMessage.wParam);
}
// Most keys are not distinguished as left or right keys.
bool isLeftRightDistinguishedKey = false;
// mOriginalVirtualKeyCode must not distinguish left or right of
// Shift, Control or Alt.
switch (mOriginalVirtualKeyCode) {
case VK_SHIFT:
case VK_CONTROL:
case VK_MENU:
case VK_SHIFT:
mVirtualKeyCode = static_cast<PRUint8>(
::MapVirtualKeyEx(GetScanCodeWithExtendedFlag(),
MAPVK_VSC_TO_VK_EX, aKeyboardLayout.GetLayout()));
isLeftRightDistinguishedKey = true;
break;
case VK_PROCESSKEY:
mVirtualKeyCode = mOriginalVirtualKeyCode =
static_cast<PRUint8>(
::ImmGetVirtualKey(aWindow->GetWindowHandle()));
case VK_LSHIFT:
case VK_RSHIFT:
mVirtualKeyCode = mOriginalVirtualKeyCode;
mOriginalVirtualKeyCode = VK_SHIFT;
isLeftRightDistinguishedKey = true;
break;
case VK_LCONTROL:
case VK_RCONTROL:
mVirtualKeyCode = mOriginalVirtualKeyCode;
mOriginalVirtualKeyCode = VK_CONTROL;
isLeftRightDistinguishedKey = true;
break;
case VK_LMENU:
case VK_RMENU:
mVirtualKeyCode = mOriginalVirtualKeyCode;
mOriginalVirtualKeyCode = VK_MENU;
isLeftRightDistinguishedKey = true;
break;
}
// If virtual keycode (left-right distinguished keycode) is already
// computed, we don't need to do anymore.
if (mVirtualKeyCode) {
break;
}
// If the keycode doesn't have LR distinguished keycode, we just set
// mOriginalVirtualKeyCode to mVirtualKeyCode. Note that don't compute
// it from MapVirtualKeyEx() because the scan code might be wrong if
// the message is sent/posted by other application. Then, we will compute
// unexpected keycode from the scan code.
if (!isLeftRightDistinguishedKey) {
break;
}
if (!canComputeVirtualKeyCodeFromScanCode) {
// The right control key and the right alt key are extended keys.
// Therefore, we never get VK_RCONTRL and VK_RMENU for the result of
// MapVirtualKeyEx() on WinXP or WinServer2003.
//
// If VK_CONTROL or VK_MENU key message is caused by an extended key,
// we should assume that the right key of them is pressed.
switch (mOriginalVirtualKeyCode) {
case VK_CONTROL:
mVirtualKeyCode = VK_RCONTROL;
break;
case VK_MENU:
mVirtualKeyCode = VK_RMENU;
break;
case VK_SHIFT:
// Neither left shift nor right shift is not an extended key,
// let's use VK_LSHIFT for invalid scan code.
mVirtualKeyCode = VK_LSHIFT;
break;
default:
MOZ_NOT_REACHED("Unsupported mOriginalVirtualKeyCode");
break;
}
break;
}
NS_ASSERTION(!mVirtualKeyCode,
"mVirtualKeyCode has been computed already");
// Otherwise, compute the virtual keycode with MapVirtualKeyEx().
mVirtualKeyCode = static_cast<PRUint8>(
::MapVirtualKeyEx(GetScanCodeWithExtendedFlag(),
MAPVK_VSC_TO_VK_EX, aKeyboardLayout.GetLayout()));
// The result might be unexpected value due to the scan code is
// wrong. For example, any key messages can be generated by
// SendMessage() or PostMessage() from applications. So, it's possible
// failure. Then, let's respect the extended flag even if it might be
// set intentionally.
switch (mOriginalVirtualKeyCode) {
case VK_CONTROL:
if (mVirtualKeyCode != VK_LCONTROL &&
mVirtualKeyCode != VK_RCONTROL) {
mVirtualKeyCode = mIsExtended ? VK_RCONTROL : VK_LCONTROL;
}
break;
case VK_MENU:
if (mVirtualKeyCode != VK_LMENU && mVirtualKeyCode != VK_RMENU) {
mVirtualKeyCode = mIsExtended ? VK_RMENU : VK_LMENU;
}
break;
case VK_SHIFT:
if (mVirtualKeyCode != VK_LSHIFT && mVirtualKeyCode != VK_RSHIFT) {
// Neither left shift nor right shift is not an extended key,
// let's use VK_LSHIFT for invalid scan code.
mVirtualKeyCode = VK_LSHIFT;
}
break;
default:
mVirtualKeyCode = mOriginalVirtualKeyCode;
MOZ_NOT_REACHED("Unsupported mOriginalVirtualKeyCode");
break;
}
break;
}
case WM_CHAR:
case WM_UNICHAR:
case WM_SYSCHAR:
// We cannot compute the virtual key code from WM_CHAR message on WinXP
// and
if (mIsExtended &&
WinUtils::GetWindowsVersion() < WinUtils::VISTA_VERSION) {
// if it's caused by an extended key.
if (!canComputeVirtualKeyCodeFromScanCode) {
break;
}
mVirtualKeyCode = mOriginalVirtualKeyCode = static_cast<PRUint8>(
@ -446,6 +550,7 @@ NativeKey::GetScanCodeWithExtendedFlag() const
// no way to get virtual keycodes from scancode of extended keys.
if (!mIsExtended ||
WinUtils::GetWindowsVersion() < WinUtils::VISTA_VERSION) {
NS_WARNING("GetScanCodeWithExtendedFlat() returns without extended flag");
return mScanCode;
}
return (0xE000 | mScanCode);
@ -468,6 +573,7 @@ NativeKey::GetKeyLocation() const
return nsIDOMKeyEvent::DOM_KEY_LOCATION_RIGHT;
case VK_RETURN:
// XXX This code assumes that all keyboard drivers use same mapping.
return !mIsExtended ? nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD :
nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD;
@ -482,6 +588,7 @@ NativeKey::GetKeyLocation() const
case VK_HOME:
case VK_UP:
case VK_PRIOR:
// XXX This code assumes that all keyboard drivers use same mapping.
return mIsExtended ? nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD :
nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD;
@ -503,6 +610,11 @@ NativeKey::GetKeyLocation() const
case VK_ADD:
return nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD;
case VK_SHIFT:
case VK_CONTROL:
case VK_MENU:
NS_WARNING("Failed to decide the key location?");
default:
return nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD;
}

View File

@ -5700,11 +5700,65 @@ nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
HKL oldLayout = gKbdLayout.GetLayout();
gKbdLayout.LoadLayout(loadedLayout);
PRUint8 argumentKeySpecific = 0;
switch (aNativeKeyCode) {
case VK_SHIFT:
aModifierFlags &= ~(nsIWidget::SHIFT_L | nsIWidget::SHIFT_R);
argumentKeySpecific = VK_LSHIFT;
break;
case VK_LSHIFT:
aModifierFlags &= ~nsIWidget::SHIFT_L;
argumentKeySpecific = aNativeKeyCode;
aNativeKeyCode = VK_SHIFT;
break;
case VK_RSHIFT:
aModifierFlags &= ~nsIWidget::SHIFT_R;
argumentKeySpecific = aNativeKeyCode;
aNativeKeyCode = VK_SHIFT;
break;
case VK_CONTROL:
aModifierFlags &= ~(nsIWidget::CTRL_L | nsIWidget::CTRL_R);
argumentKeySpecific = VK_LCONTROL;
break;
case VK_LCONTROL:
aModifierFlags &= ~nsIWidget::CTRL_L;
argumentKeySpecific = aNativeKeyCode;
aNativeKeyCode = VK_CONTROL;
break;
case VK_RCONTROL:
aModifierFlags &= ~nsIWidget::CTRL_R;
argumentKeySpecific = aNativeKeyCode;
aNativeKeyCode = VK_CONTROL;
break;
case VK_MENU:
aModifierFlags &= ~(nsIWidget::ALT_L | nsIWidget::ALT_R);
argumentKeySpecific = VK_LMENU;
break;
case VK_LMENU:
aModifierFlags &= ~nsIWidget::ALT_L;
argumentKeySpecific = aNativeKeyCode;
aNativeKeyCode = VK_MENU;
break;
case VK_RMENU:
aModifierFlags &= ~nsIWidget::ALT_R;
argumentKeySpecific = aNativeKeyCode;
aNativeKeyCode = VK_MENU;
break;
case VK_CAPITAL:
aModifierFlags &= ~nsIWidget::CAPS_LOCK;
argumentKeySpecific = VK_CAPITAL;
break;
case VK_NUMLOCK:
aModifierFlags &= ~nsIWidget::NUM_LOCK;
argumentKeySpecific = VK_NUMLOCK;
break;
}
nsAutoTArray<KeyPair,10> keySequence;
SetupKeyModifiersSequence(&keySequence, aModifierFlags);
NS_ASSERTION(aNativeKeyCode >= 0 && aNativeKeyCode < 256,
"Native VK key code out of range");
keySequence.AppendElement(KeyPair(aNativeKeyCode, 0));
keySequence.AppendElement(KeyPair(aNativeKeyCode, argumentKeySpecific));
// Simulate the pressing of each modifier key and then the real key
for (PRUint32 i = 0; i < keySequence.Length(); ++i) {
@ -5716,8 +5770,9 @@ nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
}
::SetKeyboardState(kbdState);
ModifierKeyState modKeyState;
UINT scanCode = ::MapVirtualKeyEx(aNativeKeyCode, MAPVK_VK_TO_VSC,
gKbdLayout.GetLayout());
UINT scanCode = ::MapVirtualKeyEx(argumentKeySpecific ?
argumentKeySpecific : aNativeKeyCode,
MAPVK_VK_TO_VSC, gKbdLayout.GetLayout());
LPARAM lParam = static_cast<LPARAM>(scanCode << 16);
// Add extended key flag to the lParam for right control key and right alt
// key.
@ -5762,8 +5817,9 @@ nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
}
::SetKeyboardState(kbdState);
ModifierKeyState modKeyState;
UINT scanCode = ::MapVirtualKeyEx(aNativeKeyCode, MAPVK_VK_TO_VSC,
gKbdLayout.GetLayout());
UINT scanCode = ::MapVirtualKeyEx(argumentKeySpecific ?
argumentKeySpecific : aNativeKeyCode,
MAPVK_VK_TO_VSC, gKbdLayout.GetLayout());
LPARAM lParam = static_cast<LPARAM>(scanCode << 16);
// Add extended key flag to the lParam for right control key and right alt
// key.