зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset e176bd45edd8 (bug 1335347) for failures on browser_alt_keyup_in_content.js. a=backout
This commit is contained in:
Родитель
244eb9e36c
Коммит
511fc14c29
|
@ -1,8 +1,5 @@
|
|||
[DEFAULT]
|
||||
|
||||
[browser_alt_keyup_in_content.js]
|
||||
skip-if = (os != 'linux' && os != 'win') || skip-if = !e10s
|
||||
|
||||
[browser_beforeinput_by_execCommand_in_contentscript.js]
|
||||
support-files =
|
||||
file_beforeinput_by_execCommand_in_contentscript.html
|
||||
|
|
|
@ -1,289 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
const { ContentTaskUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/ContentTaskUtils.jsm"
|
||||
);
|
||||
|
||||
add_task(async function runTests() {
|
||||
const menubar = document.getElementById("toolbar-menubar");
|
||||
const autohide = menubar.getAttribute("autohide");
|
||||
// This test requires that the window is active because of the limitation of
|
||||
// menubar. Therefore, we should abort if the window becomes inactive during
|
||||
// the tests.
|
||||
let runningTests = true;
|
||||
function onWindowActive(aEvent) {
|
||||
// Don't warn after timed out.
|
||||
if (runningTests && aEvent.target === window) {
|
||||
info(
|
||||
"WARNING: This window shouldn't have been inactivated during tests, but received an activated event!"
|
||||
);
|
||||
}
|
||||
}
|
||||
function onWindowInactive(aEvent) {
|
||||
// Don't warn after timed out.
|
||||
if (runningTests && aEvent.target === window) {
|
||||
info(
|
||||
"WARNING: This window should be active during tests, but inactivated!"
|
||||
);
|
||||
window.focus();
|
||||
}
|
||||
}
|
||||
let menubarActivated = false;
|
||||
function onMenubarActive() {
|
||||
menubarActivated = true;
|
||||
}
|
||||
// In this test, menu popups shouldn't be open, but this helps avoiding
|
||||
// intermittent failure after inactivating the menubar.
|
||||
let popupEvents = 0;
|
||||
function onPopupShown() {
|
||||
popupEvents++;
|
||||
info(`A popup is shown (visible popups: ${popupEvents})`);
|
||||
}
|
||||
function onPopupHidden() {
|
||||
popupEvents--;
|
||||
info(`A popup is hidden (visible popups: ${popupEvents})`);
|
||||
}
|
||||
try {
|
||||
Services.prefs.setBoolPref("ui.key.menuAccessKeyFocuses", true);
|
||||
// If this fails, you need to replace "KEY_Alt" with a variable whose
|
||||
// value is considered from the pref.
|
||||
is(
|
||||
Services.prefs.getIntPref("ui.key.menuAccessKey"),
|
||||
18,
|
||||
"This test assumes that Alt key activates the menubar"
|
||||
);
|
||||
window.addEventListener("activate", onWindowActive);
|
||||
window.addEventListener("deactivate", onWindowInactive);
|
||||
window.addEventListener("popupshown", onPopupShown);
|
||||
window.addEventListener("popuphidden", onPopupHidden);
|
||||
menubar.addEventListener("DOMMenuBarActive", onMenubarActive);
|
||||
async function doTest(aTest) {
|
||||
await new Promise(resolve => {
|
||||
if (Services.focus.activeWindow === window) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
info(
|
||||
`${aTest.description}: The testing window is inactive, trying to activate it...`
|
||||
);
|
||||
Services.focus.focusedWindow = window;
|
||||
TestUtils.waitForCondition(() => {
|
||||
if (Services.focus.activeWindow === window) {
|
||||
resolve();
|
||||
return true;
|
||||
}
|
||||
Services.focus.focusedWindow = window;
|
||||
return false;
|
||||
}, `${aTest.description}: Waiting the window is activated`);
|
||||
});
|
||||
info(`Start to test: ${aTest.description}...`);
|
||||
|
||||
async function ensureMenubarInactive() {
|
||||
if (!menubar.querySelector("[_moz-menuactive=true]")) {
|
||||
return;
|
||||
}
|
||||
info(`${aTest.description}: Inactivating the menubar...`);
|
||||
let waitForMenuBarInactive = BrowserTestUtils.waitForEvent(
|
||||
menubar,
|
||||
"DOMMenuBarInactive"
|
||||
);
|
||||
EventUtils.synthesizeKey("KEY_Escape", {}, window);
|
||||
await waitForMenuBarInactive;
|
||||
await TestUtils.waitForCondition(() => {
|
||||
return popupEvents === 0;
|
||||
}, `${aTest.description}: Waiting for closing all popups`);
|
||||
}
|
||||
|
||||
try {
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: aTest.url,
|
||||
},
|
||||
async browser => {
|
||||
info(`${aTest.description}: Waiting browser getting focus...`);
|
||||
await SimpleTest.promiseFocus(browser);
|
||||
await ensureMenubarInactive();
|
||||
menubarActivated = false;
|
||||
|
||||
let keyupEventFiredInContent = false;
|
||||
BrowserTestUtils.addContentEventListener(
|
||||
browser,
|
||||
"keyup",
|
||||
() => {
|
||||
keyupEventFiredInContent = true;
|
||||
},
|
||||
{ capture: true },
|
||||
event => {
|
||||
return event.key === "Alt";
|
||||
}
|
||||
);
|
||||
|
||||
// For making sure adding the above content event listener and
|
||||
// it'll get `keyup` event, let's run `SpecialPowers.spawn` and
|
||||
// wait for focus in the content process.
|
||||
info(
|
||||
`${aTest.description}: Waiting content process getting focus...`
|
||||
);
|
||||
await SpecialPowers.spawn(
|
||||
browser,
|
||||
[aTest.description],
|
||||
async aTestDescription => {
|
||||
await ContentTaskUtils.waitForCondition(() => {
|
||||
if (docShell.isActive && content.document.hasFocus()) {
|
||||
return true;
|
||||
}
|
||||
content.window.focus();
|
||||
return false;
|
||||
}, `${aTestDescription}: Waiting for content gets focus in content process`);
|
||||
}
|
||||
);
|
||||
|
||||
let waitForAllKeyUpEventsInChrome = new Promise(resolve => {
|
||||
// Wait 2 `keyup` events in the main process. First one is
|
||||
// synthesized one. The other is replay event from content.
|
||||
let firstKeyUpEvent;
|
||||
window.addEventListener(
|
||||
"keyup",
|
||||
function onKeyUpInChrome(event) {
|
||||
if (!firstKeyUpEvent) {
|
||||
firstKeyUpEvent = event;
|
||||
return;
|
||||
}
|
||||
window.removeEventListener("keyup", onKeyUpInChrome, {
|
||||
capture: true,
|
||||
});
|
||||
resolve();
|
||||
},
|
||||
{ capture: true }
|
||||
);
|
||||
});
|
||||
EventUtils.synthesizeKey("KEY_Alt", {}, window);
|
||||
info(
|
||||
`${aTest.description}: Waiting keyup events of Alt in chrome...`
|
||||
);
|
||||
await waitForAllKeyUpEventsInChrome;
|
||||
info(`${aTest.description}: Waiting keyup event in content...`);
|
||||
try {
|
||||
await TestUtils.waitForCondition(() => {
|
||||
return keyupEventFiredInContent;
|
||||
}, `${aTest.description}: Waiting for content gets focus in chrome process`);
|
||||
} catch (ex) {
|
||||
ok(
|
||||
false,
|
||||
`${aTest.description}: Failed to synthesize Alt key press in the content process`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aTest.expectMenubarActive) {
|
||||
ok(
|
||||
menubarActivated,
|
||||
`${aTest.description}: Menubar should've been activated by the synthesized Alt key press`
|
||||
);
|
||||
} else {
|
||||
// Wait some ticks to verify not receiving "DOMMenuBarActive" event.
|
||||
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
ok(
|
||||
!menubarActivated,
|
||||
`${aTest.description}: Menubar should not have been activated by the synthesized Alt key press`
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch (ex) {
|
||||
ok(
|
||||
false,
|
||||
`${aTest.description}: Thrown an exception: ${ex.toString()}`
|
||||
);
|
||||
} finally {
|
||||
await ensureMenubarInactive();
|
||||
info(`End testing: ${aTest.description}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Testcases for users who use collapsible menubar (by default)
|
||||
menubar.setAttribute("autohide", "true");
|
||||
await doTest({
|
||||
description: "Testing menubar is shown by Alt keyup",
|
||||
url: "data:text/html;charset=utf-8,<p>static page</p>",
|
||||
expectMenubarActive: true,
|
||||
});
|
||||
await doTest({
|
||||
description:
|
||||
"Testing menubar is shown by Alt keyup when an <input> has focus",
|
||||
url:
|
||||
"data:text/html;charset=utf-8,<input>" +
|
||||
'<script>document.querySelector("input").focus()</script>',
|
||||
expectMenubarActive: true,
|
||||
});
|
||||
await doTest({
|
||||
description:
|
||||
"Testing menubar is shown by Alt keyup when an editing host has focus",
|
||||
url:
|
||||
"data:text/html;charset=utf-8,<p contenteditable></p>" +
|
||||
'<script>document.querySelector("p[contenteditable]").focus()</script>',
|
||||
expectMenubarActive: true,
|
||||
});
|
||||
await doTest({
|
||||
description:
|
||||
"Testing menubar won't be shown by Alt keyup due to suppressed by the page",
|
||||
url:
|
||||
"data:text/html;charset=utf-8,<p>dynamic page</p>" +
|
||||
'<script>window.addEventListener("keyup", event => { event.preventDefault(); })</script>',
|
||||
expectMenubarActive: false,
|
||||
});
|
||||
|
||||
// Testcases for users who always show the menubar.
|
||||
menubar.setAttribute("autohide", "false");
|
||||
await doTest({
|
||||
description: "Testing menubar is activated by Alt keyup",
|
||||
url: "data:text/html;charset=utf-8,<p>static page</p>",
|
||||
expectMenubarActive: true,
|
||||
});
|
||||
await doTest({
|
||||
description:
|
||||
"Testing menubar is activated by Alt keyup when an <input> has focus",
|
||||
url:
|
||||
"data:text/html;charset=utf-8,<input>" +
|
||||
'<script>document.querySelector("input").focus()</script>',
|
||||
expectMenubarActive: true,
|
||||
});
|
||||
await doTest({
|
||||
description:
|
||||
"Testing menubar is activated by Alt keyup when an editing host has focus",
|
||||
url:
|
||||
"data:text/html;charset=utf-8,<p contenteditable></p>" +
|
||||
'<script>document.querySelector("p[contenteditable]").focus()</script>',
|
||||
expectMenubarActive: true,
|
||||
});
|
||||
await doTest({
|
||||
description:
|
||||
"Testing menubar won't be activated by Alt keyup due to suppressed by the page",
|
||||
url:
|
||||
"data:text/html;charset=utf-8,<p>dynamic page</p>" +
|
||||
'<script>window.addEventListener("keyup", event => { event.preventDefault(); })</script>',
|
||||
expectMenubarActive: false,
|
||||
});
|
||||
runningTests = false;
|
||||
} catch (ex) {
|
||||
ok(
|
||||
false,
|
||||
`Aborting this test due to unexpected the exception (${ex.toString()})`
|
||||
);
|
||||
runningTests = false;
|
||||
} finally {
|
||||
if (autohide !== null) {
|
||||
menubar.setAttribute("autohide", autohide);
|
||||
} else {
|
||||
menubar.removeAttribute("autohide");
|
||||
}
|
||||
Services.prefs.clearUserPref("ui.key.menuAccessKeyFocuses");
|
||||
menubar.removeEventListener("DOMMenuBarActive", onMenubarActive);
|
||||
window.removeEventListener("activate", onWindowActive);
|
||||
window.removeEventListener("deactivate", onWindowInactive);
|
||||
window.removeEventListener("popupshown", onPopupShown);
|
||||
window.removeEventListener("popuphidden", onPopupHidden);
|
||||
}
|
||||
});
|
|
@ -164,67 +164,62 @@ void nsMenuBarListener::ToggleMenuActiveState() {
|
|||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
nsresult nsMenuBarListener::KeyUp(Event* aKeyEvent) {
|
||||
WidgetKeyboardEvent* nativeKeyEvent =
|
||||
aKeyEvent->WidgetEventPtr()->AsKeyboardEvent();
|
||||
if (!nativeKeyEvent) {
|
||||
RefPtr<KeyboardEvent> keyEvent = aKeyEvent->AsKeyboardEvent();
|
||||
if (!keyEvent) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
InitAccessKey();
|
||||
|
||||
// handlers shouldn't be triggered by non-trusted events.
|
||||
if (!nativeKeyEvent->IsTrusted()) {
|
||||
if (!keyEvent->IsTrusted()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mAccessKey || !StaticPrefs::ui_key_menuAccessKeyFocuses()) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (mAccessKey && StaticPrefs::ui_key_menuAccessKeyFocuses()) {
|
||||
bool defaultPrevented = keyEvent->DefaultPrevented();
|
||||
|
||||
// On a press of the ALT key by itself, we toggle the menu's
|
||||
// active/inactive state.
|
||||
if (!nativeKeyEvent->DefaultPrevented() && mAccessKeyDown &&
|
||||
!mAccessKeyDownCanceled &&
|
||||
static_cast<int32_t>(nativeKeyEvent->mKeyCode) == mAccessKey) {
|
||||
// The access key was down and is now up, and no other
|
||||
// keys were pressed in between.
|
||||
bool toggleMenuActiveState = true;
|
||||
if (!mMenuBarFrame->IsActive()) {
|
||||
// If the focused content is in a remote process, we should allow the
|
||||
// focused web app to prevent to activate the menubar.
|
||||
if (nativeKeyEvent->WillBeSentToRemoteProcess()) {
|
||||
nativeKeyEvent->StopImmediatePropagation();
|
||||
nativeKeyEvent->MarkAsWaitingReplyFromRemoteProcess();
|
||||
return NS_OK;
|
||||
}
|
||||
// First, close all existing popups because other popups shouldn't
|
||||
// handle key events when menubar is active and IME should be
|
||||
// disabled.
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm) {
|
||||
pm->Rollup(0, false, nullptr, nullptr);
|
||||
}
|
||||
// If menubar active state is changed or the menubar is destroyed
|
||||
// during closing the popups, we should do nothing anymore.
|
||||
toggleMenuActiveState = !Destroyed() && !mMenuBarFrame->IsActive();
|
||||
}
|
||||
if (toggleMenuActiveState) {
|
||||
// On a press of the ALT key by itself, we toggle the menu's
|
||||
// active/inactive state.
|
||||
// Get the ascii key code.
|
||||
uint32_t theChar = keyEvent->KeyCode();
|
||||
|
||||
if (!defaultPrevented && mAccessKeyDown && !mAccessKeyDownCanceled &&
|
||||
(int32_t)theChar == mAccessKey) {
|
||||
// The access key was down and is now up, and no other
|
||||
// keys were pressed in between.
|
||||
bool toggleMenuActiveState = true;
|
||||
if (!mMenuBarFrame->IsActive()) {
|
||||
mMenuBarFrame->SetActiveByKeyboard();
|
||||
// First, close all existing popups because other popups shouldn't
|
||||
// handle key events when menubar is active and IME should be
|
||||
// disabled.
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm) {
|
||||
pm->Rollup(0, false, nullptr, nullptr);
|
||||
}
|
||||
// If menubar active state is changed or the menubar is destroyed
|
||||
// during closing the popups, we should do nothing anymore.
|
||||
toggleMenuActiveState = !Destroyed() && !mMenuBarFrame->IsActive();
|
||||
}
|
||||
ToggleMenuActiveState();
|
||||
if (toggleMenuActiveState) {
|
||||
if (!mMenuBarFrame->IsActive()) {
|
||||
mMenuBarFrame->SetActiveByKeyboard();
|
||||
}
|
||||
ToggleMenuActiveState();
|
||||
}
|
||||
}
|
||||
mAccessKeyDown = false;
|
||||
mAccessKeyDownCanceled = false;
|
||||
|
||||
bool active = !Destroyed() && mMenuBarFrame->IsActive();
|
||||
if (active) {
|
||||
keyEvent->StopPropagation();
|
||||
keyEvent->PreventDefault();
|
||||
return NS_OK; // I am consuming event
|
||||
}
|
||||
}
|
||||
|
||||
mAccessKeyDown = false;
|
||||
mAccessKeyDownCanceled = false;
|
||||
|
||||
if (!Destroyed() && mMenuBarFrame->IsActive()) {
|
||||
nativeKeyEvent->StopPropagation();
|
||||
nativeKeyEvent->PreventDefault();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return NS_OK; // means I am NOT consuming event
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
|
Загрузка…
Ссылка в новой задаче