author | Masayuki Nakano <masayuki@d-toybox.com> |
Thu, 31 May 2018 18:36:33 +0900 | |
changeset 478700 | 44cb540ef2fc4589c2941ab13dc6ea6b6da59474 |
parent 478699 | 311827011b111f087b862c61c14d47191a58dedc |
child 478701 | f15f24bf1131f03941efa265996f84ce8b9c61a9 |
push id | 9719 |
push user | ffxbld-merge |
push date | Fri, 24 Aug 2018 17:49:46 +0000 |
treeherder | mozilla-beta@719ec98fba77 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | m_kato, smaug |
bugs | 900750 |
milestone | 63.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/widget/NativeKeyToDOMKeyName.h +++ b/widget/NativeKeyToDOMKeyName.h @@ -79,17 +79,18 @@ #endif /****************************************************************************** * Modifier Keys ******************************************************************************/ // Alt KEY_MAP_WIN (Alt, VK_MENU) KEY_MAP_WIN (Alt, VK_LMENU) -KEY_MAP_WIN (Alt, VK_RMENU) +KEY_MAP_WIN (Alt, VK_RMENU) // This is ignored if active keyboard layout + // has AltGr. In such case, AltGraph is mapped. KEY_MAP_COCOA (Alt, kVK_Option) KEY_MAP_COCOA (Alt, kVK_RightOption) KEY_MAP_GTK (Alt, GDK_Alt_L) KEY_MAP_GTK (Alt, GDK_Alt_R) KEY_MAP_ANDROID (Alt, AKEYCODE_ALT_LEFT) KEY_MAP_ANDROID (Alt, AKEYCODE_ALT_RIGHT) // AltGraph
--- a/widget/tests/test_keycodes.xul +++ b/widget/tests/test_keycodes.xul @@ -192,16 +192,17 @@ function* runKeyEventTests() var name; // Current test name. Needs to be renamed later. var eventList, keyDownFlags, keyUpFlags, testingEvent, expectedDOMKeyCode; const kShiftFlag = 0x1; const kCtrlFlag = 0x2; const kAltFlag = 0x4; const kMetaFlag = 0x8; const kNumLockFlag = 0x10; const kCapsLockFlag = 0x20; + const kAltGraphFlag = 0x40; function onKeyEvent(e) { function removeFlag(e, aFlag) { if (e.type == "keydown") { var oldValue = keyDownFlags; keyDownFlags &= ~aFlag; @@ -256,16 +257,33 @@ function* runKeyEventTests() name + ", Alt of Alt " + e.type + " event mismatch"); is(e.shiftKey, (flags & kShiftFlag) != 0, name + ", Shift of Alt " + e.type + " event mismatch"); is(e.getModifierState("AltGraph"), e.type == "keydown" && ((IS_WIN && !!testingEvent.modifiers.altGrKey) || (IS_MAC && e.altKey)), name + ", AltGraph of Alt " + e.type + " event mismatch"); return (testingEvent.modifiers.altKey || testingEvent.modifiers.altRightKey || (IS_WIN && !!testingEvent.modifiers.altGrKey)) && removeFlag(e, kAltFlag) && expectedDOMKeyCode != e.keyCode; + case "AltGraph": + // On Windows, AltGraph events are fired only when AltRight key is + // pressed when active keyboard layout maps AltGraph to AltRight. + // Note that AltGraph is represented with pressing both Control key + // and Alt key. Therefore, when AltGraph keyboard event is fired, + // both ctrlKey and altKey are always false on Windows. + is(e.ctrlKey, (flags & kCtrlFlag) != 0 && !IS_WIN, + name + ", Ctrl of AltGraph " + e.type + " event mismatch"); + is(e.metaKey, (flags & kMetaFlag) != 0, + name + ", Command of AltGraph " + e.type + " event mismatch"); + is(e.altKey, (flags & kAltFlag) != 0 && !IS_WIN, + name + ", Alt of AltGraph " + e.type + " event mismatch"); + is(e.shiftKey, (flags & kShiftFlag) != 0, name + ", Shift of Ctrl " + e.type + " event mismatch"); + is(e.getModifierState("AltGraph"), e.type === "keydown", + name + ", AltGraph of AltGraph " + e.type + " event mismatch"); + return IS_WIN && testingEvent.modifiers.altGrKey && + removeFlag(e, kAltGraphFlag) && expectedDOMKeyCode != e.keyCode; case "Meta": is(e.ctrlKey, (flags & kCtrlFlag) != 0, name + ", Ctrl of Command " + e.type + " evnet mismatch"); is(e.metaKey, e.type == "keydown", name + ", Command of Command " + e.type + " evnet mismatch"); is(e.altKey, (flags & kAltFlag) != 0, name + ", Alt of Command " + e.type + " evnet mismatch"); is(e.shiftKey, (flags & kShiftFlag) != 0, name + ", Shift of Command " + e.type + " evnet mismatch"); is(e.getModifierState("AltGraph"), (IS_WIN && (flags & kAltGraphFlag) != 0) || (IS_MAC && e.altKey), name + ", AltGraph of Meta " + e.type + " event mismatch"); @@ -339,20 +357,22 @@ function* runKeyEventTests() // state changing for synthesizeNativeKeyEvent. if (aEvent.modifiers.shiftKey || aEvent.modifiers.shiftRightKey) { keyDownFlags |= kShiftFlag; } if (aEvent.modifiers.ctrlKey || aEvent.modifiers.ctrlRightKey || (IS_WIN && aEvent.modifiers.altGrKey)) { keyDownFlags |= kCtrlFlag; } - if (aEvent.modifiers.altKey || aEvent.modifiers.altRightKey || - (IS_WIN && aEvent.modifiers.altGrKey)) { + if (aEvent.modifiers.altKey || aEvent.modifiers.altRightKey) { keyDownFlags |= kAltFlag; } + if (aEvent.modifiers.altGrKey) { + keyDownFlags |= kAltGraphFlag; + } if (aEvent.modifiers.metaKey || aEvent.modifiers.metaRightKey) { keyDownFlags |= kMetaFlag; } if (aEvent.modifiers.numLockKey || aEvent.modifiers.numericKeyPadKey) { keyDownFlags |= kNumLockFlag; } if (aEvent.modifiers.capsLockKey) { keyDownFlags |= kCapsLockFlag; @@ -5300,22 +5320,187 @@ function* runTextInputTests() "0"); } // XXX We need to move focus for canceling to search the autocomplete // result. If we don't do here, Fx will crash at end of this tests. document.getElementById("button").focus(); } +function* runAltRightKeyOnWindows() +{ + if (!IS_WIN) { + return; + } + + var button = document.getElementById("button"); + button.focus(); + + const kKeyboardLayouts = [ + { layout: KEYBOARD_LAYOUT_ARABIC }, + { layout: KEYBOARD_LAYOUT_BRAZILIAN_ABNT }, + { layout: KEYBOARD_LAYOUT_EN_US }, + { layout: KEYBOARD_LAYOUT_FRENCH }, + { layout: KEYBOARD_LAYOUT_GREEK }, + { layout: KEYBOARD_LAYOUT_GERMAN }, + { layout: KEYBOARD_LAYOUT_HEBREW }, + { layout: KEYBOARD_LAYOUT_JAPANESE }, + { layout: KEYBOARD_LAYOUT_KHMER }, + { layout: KEYBOARD_LAYOUT_LITHUANIAN }, + { layout: KEYBOARD_LAYOUT_NORWEGIAN }, + { layout: KEYBOARD_LAYOUT_RUSSIAN_MNEMONIC, + canTestIt: function() { return OS_VERSION >= WIN8; } }, + { layout: KEYBOARD_LAYOUT_SPANISH }, + { layout: KEYBOARD_LAYOUT_SWEDISH }, + { layout: KEYBOARD_LAYOUT_THAI }, + ]; + var events = []; + function pushEvent(aEvent) { + events.push(aEvent); + if (aEvent.key === "Alt") { + // Prevent working the menubar. + aEvent.preventDefault(); + } + } + button.addEventListener("keydown", pushEvent); + button.addEventListener("keyup", pushEvent); + + function testKey(aKeyboardLayout) { + return synthesizeKey({layout: aKeyboardLayout.layout, keyCode: WIN_VK_RMENU, + modifiers: {}, chars: ""}, "button", function() { + const kDescription = + "runAltRightKeyOnWindows(" + aKeyboardLayout.layout.name + "): "; + if (aKeyboardLayout.layout.hasAltGrOnWin) { + is(events.length, 4, + kDescription + "AltRight should fire 2 pairs of keydown and keyup events"); + is(events[0].type, "keydown", + kDescription + "First event should be keydown of ControlLeft"); + is(events[0].key, "Control", + kDescription + "First event should be keydown of ControlLeft whose key should be Control"); + is(events[0].code, "ControlLeft", + kDescription + "First event should be keydown of ControlLeft"); + is(events[0].location, KeyboardEvent.DOM_KEY_LOCATION_LEFT, + kDescription + "First event should be keydown of ControlLeft whose location should be DOM_KEY_LOCATION_LEFT"); + is(events[0].keyCode, KeyboardEvent.DOM_VK_CONTROL, + kDescription + "First event should be keydown of ControlLeft whose keyCode should be DOM_VK_CONTROL"); + is(events[0].ctrlKey, true, + kDescription + "First event should be keydown of ControlLeft whose ctrlKey should be true"); + is(events[0].altKey, false, + kDescription + "First event should be keydown of ControlLeft whose altKey should be false"); + is(events[0].getModifierState("AltGraph"), false, + kDescription + "First event should be keydown of ControlLeft whose getModifierState(\"AltGraph\") should be false"); + is(events[1].type, "keydown", + kDescription + "Second event should be keydown of AltRight"); + is(events[1].key, "AltGraph", + kDescription + "Second event should be keydown of AltRight whose key should be AltGraph"); + is(events[1].code, "AltRight", + kDescription + "Second event should be keydown of AltRight"); + is(events[1].location, KeyboardEvent.DOM_KEY_LOCATION_RIGHT, + kDescription + "Second event should be keydown of AltRight whose location should be DOM_KEY_LOCATION_RIGHT"); + is(events[1].keyCode, KeyboardEvent.DOM_VK_ALT, + kDescription + "Second event should be keydown of AltRight whose keyCode should be DOM_VK_ALT"); + is(events[1].ctrlKey, false, + kDescription + "Second event should be keydown of AltRight whose ctrlKey should be false"); + is(events[1].altKey, false, + kDescription + "Second event should be keydown of AltRight whose altKey should be false"); + is(events[1].getModifierState("AltGraph"), true, + kDescription + "Second event should be keydown of AltRight whose getModifierState(\"AltGraph\") should be true"); + is(events[2].type, "keyup", + kDescription + "Third event should be keyup of ControlLeft"); + is(events[2].key, "Control", + kDescription + "Third event should be keyup of ControlLeft whose key should be Control"); + is(events[2].code, "ControlLeft", + kDescription + "Third event should be keyup of ControlLeft"); + is(events[2].location, KeyboardEvent.DOM_KEY_LOCATION_LEFT, + kDescription + "Third event should be keyup of ControlLeft whose location should be DOM_KEY_LOCATION_LEFT"); + is(events[2].keyCode, KeyboardEvent.DOM_VK_CONTROL, + kDescription + "Third event should be keyup of ControlLeft whose keyCode should be DOM_VK_CONTROL"); + is(events[2].ctrlKey, false, + kDescription + "Third event should be keyup of ControlLeft whose ctrlKey should be false"); + is(events[2].altKey, false, + kDescription + "Third event should be keyup of ControlLeft whose altKey should be false"); + is(events[2].getModifierState("AltGraph"), true, + kDescription + "Third event should be keyup of ControlLeft whose getModifierState(\"AltGraph\") should be true"); + is(events[3].type, "keyup", + kDescription + "Forth event should be keyup of AltRight"); + is(events[3].key, "AltGraph", + kDescription + "Forth event should be keyup of AltRight whose key should be AltGraph"); + is(events[3].code, "AltRight", + kDescription + "Forth event should be keyup of AltRight"); + is(events[3].location, KeyboardEvent.DOM_KEY_LOCATION_RIGHT, + kDescription + "Forth event should be keyup of AltRight whose location should be DOM_KEY_LOCATION_RIGHT"); + is(events[3].keyCode, KeyboardEvent.DOM_VK_ALT, + kDescription + "Forth event should be keyup of AltRight whose keyCode should be DOM_VK_ALT"); + is(events[3].ctrlKey, false, + kDescription + "Third event should be keyup of AltRight whose ctrlKey should be false"); + is(events[3].altKey, false, + kDescription + "Third event should be keyup of AltRight whose altKey should be false"); + is(events[3].getModifierState("AltGraph"), false, + kDescription + "Third event should be keyup of AltRight whose getModifierState(\"AltGraph\") should be false"); + } else { + is(events.length, 2, + kDescription + "AltRight should fire a pair of keydown and keyup events"); + is(events[0].type, "keydown", + kDescription + "First event should be keydown of AltRight"); + is(events[0].key, "Alt", + kDescription + "First event should be keydown of AltRight whose key should be Alt"); + is(events[0].code, "AltRight", + kDescription + "First event should be keydown of AltRight"); + is(events[0].location, KeyboardEvent.DOM_KEY_LOCATION_RIGHT, + kDescription + "First event should be keydown of AltRight whose location should be DOM_KEY_LOCATION_RIGHT"); + is(events[0].keyCode, KeyboardEvent.DOM_VK_ALT, + kDescription + "First event should be keydown of AltRight whose keyCode should be DOM_VK_ALT"); + is(events[0].ctrlKey, false, + kDescription + "First event should be keydown of AltRight whose ctrlKey should be false"); + is(events[0].altKey, true, + kDescription + "First event should be keydown of AltRight whose altKey should be true"); + is(events[0].getModifierState("AltGraph"), false, + kDescription + "First event should be keydown of AltRight whose getModifierState(\"AltGraph\") should be false"); + is(events[1].type, "keyup", + kDescription + "Second event should be keyup of AltRight"); + is(events[1].key, "Alt", + kDescription + "Second event should be keyup of AltRight whose key should be Alt"); + is(events[1].code, "AltRight", + kDescription + "Second event should be keyup of AltRight"); + is(events[1].location, KeyboardEvent.DOM_KEY_LOCATION_RIGHT, + kDescription + "Second event should be keyup of AltRight whose location should be DOM_KEY_LOCATION_RIGHT"); + is(events[1].keyCode, KeyboardEvent.DOM_VK_ALT, + kDescription + "Second event should be keyup of AltRight whose keyCode should be DOM_VK_ALT"); + is(events[1].ctrlKey, false, + kDescription + "Second event should be keyup of AltRight whose ctrlKey should be false"); + is(events[1].altKey, false, + kDescription + "Second event should be keyup of AltRight whose altKey should be false"); + is(events[1].getModifierState("AltGraph"), false, + kDescription + "Second event should be keyup of AltRight whose getModifierState(\"AltGraph\") should be false"); + } + + continueTest(); + }); + } + + for (const kKeyboardLayout of kKeyboardLayouts) { + if (typeof kKeyboardLayout.canTestIt === "function" && + !kKeyboardLayout.canTestIt()) { + continue; + } + events = []; + yield testKey(kKeyboardLayout); + } + + button.addEventListener("keydown", pushEvent); + button.addEventListener("keyup", pushEvent); +} + function* runAllTests() { yield* runKeyEventTests(); yield* runAccessKeyTests(); yield* runXULKeyTests(); yield* runReservedKeyTests(); yield* runTextInputTests(); + yield* runAltRightKeyOnWindows(); } var gTestContinuation = null; function continueTest() { if (!gTestContinuation) { gTestContinuation = runAllTests(); @@ -5331,18 +5516,21 @@ function continueTest() function runTest() { if (!IS_MAC && !IS_WIN) { todo(false, "This test is supported on MacOSX and Windows only. (Bug 431503)"); return; } if (IS_WIN && OS_VERSION >= WIN8) { - // Switching keyboard layout to Russian - Mnemonic causes 2 assertions in KeyboardLayout::LoadLayout(). - SimpleTest.expectAssertions(2, 2); + // Switching keyboard layout to Russian - Mnemonic causes 2 assertions in + // KeyboardLayout::LoadLayout(). + const kAssertionCountDueToRussainMnemonic = 2 * 2; + SimpleTest.expectAssertions(kAssertionCountDueToRussainMnemonic, + kAssertionCountDueToRussainMnemonic); } SimpleTest.waitForExplicitFinish(); clearInfobars(); continueTest(); }
--- a/widget/windows/KeyboardLayout.cpp +++ b/widget/windows/KeyboardLayout.cpp @@ -5,16 +5,17 @@ #include "mozilla/Logging.h" #include "mozilla/ArrayUtils.h" #include "mozilla/AutoRestore.h" #include "mozilla/DebugOnly.h" #include "mozilla/MouseEvents.h" #include "mozilla/MiscEvents.h" +#include "mozilla/Preferences.h" #include "mozilla/TextEvents.h" #include "nsAlgorithm.h" #include "nsExceptionHandler.h" #include "nsGkAtoms.h" #include "nsIIdleServiceInternal.h" #include "nsIWindowsRegKey.h" #include "nsMemory.h" @@ -1479,24 +1480,24 @@ NativeKey::InitWithKeyOrChar() } if (!mVirtualKeyCode) { mVirtualKeyCode = mOriginalVirtualKeyCode; } KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance(); mDOMKeyCode = - keyboardLayout->ConvertNativeKeyCodeToDOMKeyCode(mOriginalVirtualKeyCode); + keyboardLayout->ConvertNativeKeyCodeToDOMKeyCode(mVirtualKeyCode); // Be aware, keyboard utilities can change non-printable keys to printable // keys. In such case, we should make the key value as a printable key. // FYI: IsFollowedByPrintableCharMessage() returns true only when it's // handling a keydown message. mKeyNameIndex = IsFollowedByPrintableCharMessage() ? KEY_NAME_INDEX_USE_STRING : - keyboardLayout->ConvertNativeKeyCodeToKeyNameIndex(mOriginalVirtualKeyCode); + keyboardLayout->ConvertNativeKeyCodeToKeyNameIndex(mVirtualKeyCode); mCodeNameIndex = KeyboardLayout::ConvertScanCodeToCodeNameIndex( GetScanCodeWithExtendedFlag()); // If next message of WM_(SYS)KEYDOWN is WM_*CHAR message and the key // combination is not reserved by the system, let's consume it now. // TODO: We cannot initialize mCommittedCharsAndModifiers for VK_PACKET // if the message is WM_KEYUP because we don't have preceding @@ -4777,16 +4778,30 @@ KeyboardLayout::ConvertNativeKeyCodeToDO case VK_VOLUME_MUTE: return NS_VK_VOLUME_MUTE; case VK_VOLUME_DOWN: return NS_VK_VOLUME_DOWN; case VK_VOLUME_UP: return NS_VK_VOLUME_UP; + case VK_LSHIFT: + case VK_RSHIFT: + return NS_VK_SHIFT; + + case VK_LCONTROL: + case VK_RCONTROL: + return NS_VK_CONTROL; + + // Note that even if the key is AltGr, we should return NS_VK_ALT for + // compatibility with both older Gecko and the other browsers. + case VK_LMENU: + case VK_RMENU: + return NS_VK_ALT; + // Following keycodes are not defined in our DOM keycodes. case VK_BROWSER_BACK: case VK_BROWSER_FORWARD: case VK_BROWSER_REFRESH: case VK_BROWSER_STOP: case VK_BROWSER_SEARCH: case VK_BROWSER_FAVORITES: case VK_BROWSER_HOME: @@ -4975,16 +4990,22 @@ KeyboardLayout::ConvertNativeKeyCodeToDO KeyNameIndex KeyboardLayout::ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const { if (IsPrintableCharKey(aVirtualKey) || aVirtualKey == VK_PACKET) { return KEY_NAME_INDEX_USE_STRING; } + // If the keyboard layout has AltGr and AltRight key is pressed, + // return AltGraph. + if (aVirtualKey == VK_RMENU && HasAltGr()) { + return KEY_NAME_INDEX_AltGraph; + } + switch (aVirtualKey) { #undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX #define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \ case aNativeKey: return aKeyNameIndex; #include "NativeKeyToDOMKeyName.h" @@ -5096,16 +5117,17 @@ KeyboardLayout::SynthesizeNativeKeyEvent BYTE kbdState[256]; memset(kbdState, 0, sizeof(kbdState)); // This changes the state of the keyboard for the current thread only, // and we'll restore it soon, so this should be OK. ::SetKeyboardState(kbdState); OverrideLayout(loadedLayout); + bool isAltGrKeyPress = false; if (aModifierFlags & nsIWidget::ALTGRAPH) { if (!HasAltGr()) { return NS_ERROR_INVALID_ARG; } // AltGr emulates ControlLeft key press and AltRight key press. // So, we should remove those flags from aModifierFlags before // calling WinUtils::SetupKeyModifiersSequence() to create correct // key sequence. @@ -5153,31 +5175,42 @@ KeyboardLayout::SynthesizeNativeKeyEvent aModifierFlags &= ~nsIWidget::ALT_L; argumentKeySpecific = aNativeKeyCode & 0xFF; aNativeKeyCode = (aNativeKeyCode & 0xFFFF0000) | VK_MENU; break; case VK_RMENU: aModifierFlags &= ~(nsIWidget::ALT_R | nsIWidget::ALTGRAPH); argumentKeySpecific = aNativeKeyCode & 0xFF; aNativeKeyCode = (aNativeKeyCode & 0xFFFF0000) | VK_MENU; + // If AltRight key is AltGr in the keyboard layout, let's use + // SetupKeyModifiersSequence() to emulate the native behavior + // since the same event order between keydown and keyup makes + // the following code complicated. + if (HasAltGr()) { + isAltGrKeyPress = true; + aModifierFlags &= ~nsIWidget::CTRL_L; + aModifierFlags |= nsIWidget::ALTGRAPH; + } break; case VK_CAPITAL: aModifierFlags &= ~nsIWidget::CAPS_LOCK; argumentKeySpecific = VK_CAPITAL; break; case VK_NUMLOCK: aModifierFlags &= ~nsIWidget::NUM_LOCK; argumentKeySpecific = VK_NUMLOCK; break; } AutoTArray<KeyPair,10> keySequence; WinUtils::SetupKeyModifiersSequence(&keySequence, aModifierFlags, WM_KEYDOWN); - keySequence.AppendElement(KeyPair(aNativeKeyCode, argumentKeySpecific)); + if (!isAltGrKeyPress) { + keySequence.AppendElement(KeyPair(aNativeKeyCode, argumentKeySpecific)); + } // Simulate the pressing of each modifier key and then the real key // FYI: Each NativeKey instance here doesn't need to override keyboard layout // since this method overrides and restores the keyboard layout. for (uint32_t i = 0; i < keySequence.Length(); ++i) { uint8_t key = keySequence[i].mGeneral; uint8_t keySpecific = keySequence[i].mSpecific; uint16_t scanCode = keySequence[i].mScanCode; @@ -5244,17 +5277,19 @@ KeyboardLayout::SynthesizeNativeKeyEvent } } else { NativeKey nativeKey(aWidget, keyDownMsg, modKeyState); nativeKey.HandleKeyDownMessage(); } } keySequence.Clear(); - keySequence.AppendElement(KeyPair(aNativeKeyCode, argumentKeySpecific)); + if (!isAltGrKeyPress) { + keySequence.AppendElement(KeyPair(aNativeKeyCode, argumentKeySpecific)); + } WinUtils::SetupKeyModifiersSequence(&keySequence, aModifierFlags, WM_KEYUP); for (uint32_t i = 0; i < keySequence.Length(); ++i) { uint8_t key = keySequence[i].mGeneral; uint8_t keySpecific = keySequence[i].mSpecific; uint16_t scanCode = keySequence[i].mScanCode; kbdState[key] = 0; // key is up and toggled off if appropriate if (keySpecific) {