add_task(async function test_reserved_shortcuts() { let keyset = document.createXULElement("keyset"); let key1 = document.createXULElement("key"); key1.setAttribute("id", "kt_reserved"); key1.setAttribute("modifiers", "shift"); key1.setAttribute("key", "O"); key1.setAttribute("reserved", "true"); key1.setAttribute("count", "0"); key1.addEventListener("command", () => { let attribute = key1.getAttribute("count"); key1.setAttribute("count", Number(attribute) + 1); }); let key2 = document.createXULElement("key"); key2.setAttribute("id", "kt_notreserved"); key2.setAttribute("modifiers", "shift"); key2.setAttribute("key", "P"); key2.setAttribute("reserved", "false"); key2.setAttribute("count", "0"); key2.addEventListener("command", () => { let attribute = key2.getAttribute("count"); key2.setAttribute("count", Number(attribute) + 1); }); let key3 = document.createXULElement("key"); key3.setAttribute("id", "kt_reserveddefault"); key3.setAttribute("modifiers", "shift"); key3.setAttribute("key", "Q"); key3.setAttribute("count", "0"); key3.addEventListener("command", () => { let attribute = key3.getAttribute("count"); key3.setAttribute("count", Number(attribute) + 1); }); keyset.appendChild(key1); keyset.appendChild(key2); keyset.appendChild(key3); let container = document.createXULElement("box"); container.appendChild(keyset); document.documentElement.appendChild(container); const pageUrl = "data:text/html,
Test
"; let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl); EventUtils.sendString("OPQ"); is( document.getElementById("kt_reserved").getAttribute("count"), "1", "reserved='true' with preference off" ); is( document.getElementById("kt_notreserved").getAttribute("count"), "0", "reserved='false' with preference off" ); is( document.getElementById("kt_reserveddefault").getAttribute("count"), "0", "default reserved with preference off" ); // Now try with reserved shortcut key handling enabled. await new Promise(resolve => { SpecialPowers.pushPrefEnv( { set: [["permissions.default.shortcuts", 2]] }, resolve ); }); EventUtils.sendString("OPQ"); is( document.getElementById("kt_reserved").getAttribute("count"), "2", "reserved='true' with preference on" ); is( document.getElementById("kt_notreserved").getAttribute("count"), "0", "reserved='false' with preference on" ); is( document.getElementById("kt_reserveddefault").getAttribute("count"), "1", "default reserved with preference on" ); document.documentElement.removeChild(container); BrowserTestUtils.removeTab(tab); }); // This test checks that Alt+ and F10 cannot be blocked when the preference is set. if (!navigator.platform.includes("Mac")) { add_task(async function test_accesskeys_menus() { await new Promise(resolve => { SpecialPowers.pushPrefEnv( { set: [["permissions.default.shortcuts", 2]] }, resolve ); }); const uri = 'data:text/html,'; let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, uri); // Pressing Alt+H should open the Help menu. let helpPopup = document.getElementById("menu_HelpPopup"); let popupShown = BrowserTestUtils.waitForEvent(helpPopup, "popupshown"); EventUtils.synthesizeKey("KEY_Alt", { type: "keydown" }); EventUtils.synthesizeKey("h", { altKey: true }); EventUtils.synthesizeKey("KEY_Alt", { type: "keyup" }); await popupShown; ok(true, "Help menu opened"); let popupHidden = BrowserTestUtils.waitForEvent(helpPopup, "popuphidden"); helpPopup.hidePopup(); await popupHidden; // Pressing F10 should focus the menubar. On Linux, the file menu should open, but on Windows, // pressing Down will open the file menu. let menubar = document.getElementById("main-menubar"); let menubarActive = BrowserTestUtils.waitForEvent( menubar, "DOMMenuBarActive" ); EventUtils.synthesizeKey("KEY_F10"); await menubarActive; let filePopup = document.getElementById("menu_FilePopup"); popupShown = BrowserTestUtils.waitForEvent(filePopup, "popupshown"); if (navigator.platform.includes("Win")) { EventUtils.synthesizeKey("KEY_ArrowDown"); } await popupShown; ok(true, "File menu opened"); popupHidden = BrowserTestUtils.waitForEvent(filePopup, "popuphidden"); filePopup.hidePopup(); await popupHidden; BrowserTestUtils.removeTab(tab1); }); } // There is a element for Backspace and delete with reserved="false", // so make sure that it is not treated as a blocked shortcut key. add_task(async function test_backspace_delete() { await new Promise(resolve => { SpecialPowers.pushPrefEnv( { set: [["permissions.default.shortcuts", 2]] }, resolve ); }); // The input field is autofocused. If this test fails, backspace can go back // in history so cancel the beforeunload event and adjust the field to make the test fail. const uri = 'data:text/html,' + ""; let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, uri); await SpecialPowers.spawn(tab.linkedBrowser, [], async function() { content.document.getElementById("field").focus(); // Add a promise that resolves when the backspace key gets received // so we can ensure the key gets received before checking the result. content.keysPromise = new Promise(resolve => { content.addEventListener("keyup", event => { if (event.code == "Backspace") { resolve(content.document.getElementById("field").value); } }); }); }); // Move the caret so backspace will delete the first character. EventUtils.synthesizeKey("KEY_ArrowRight", {}); EventUtils.synthesizeKey("KEY_Backspace", {}); let fieldValue = await SpecialPowers.spawn( tab.linkedBrowser, [], async function() { return content.keysPromise; } ); is(fieldValue, "omething", "backspace not prevented"); // now do the same thing for the delete key: await SpecialPowers.spawn(tab.linkedBrowser, [], async function() { content.document.getElementById("field").focus(); // Add a promise that resolves when the backspace key gets received // so we can ensure the key gets received before checking the result. content.keysPromise = new Promise(resolve => { content.addEventListener("keyup", event => { if (event.code == "Delete") { resolve(content.document.getElementById("field").value); } }); }); }); // Move the caret so backspace will delete the first character. EventUtils.synthesizeKey("KEY_Delete", {}); fieldValue = await SpecialPowers.spawn( tab.linkedBrowser, [], async function() { return content.keysPromise; } ); is(fieldValue, "mething", "delete not prevented"); BrowserTestUtils.removeTab(tab); }); // TODO: Make this to run on Windows too to have automated tests also there. if ( navigator.platform.includes("Mac") || navigator.platform.includes("Linux") ) { add_task( async function test_reserved_shortcuts_conflict_with_user_settings() { await new Promise(resolve => { SpecialPowers.pushPrefEnv( { set: [["test.events.async.enabled", true]] }, resolve ); }); const keyset = document.createXULElement("keyset"); const key = document.createXULElement("key"); key.setAttribute("id", "conflict_with_known_native_key_binding"); if (navigator.platform.includes("Mac")) { // Select to end of the paragraph key.setAttribute("modifiers", "ctrl,shift"); key.setAttribute("key", "E"); } else { // Select All key.setAttribute("modifiers", "ctrl"); key.setAttribute("key", "a"); } key.setAttribute("reserved", "true"); key.setAttribute("count", "0"); key.addEventListener("command", () => { const attribute = key.getAttribute("count"); key.setAttribute("count", Number(attribute) + 1); }); keyset.appendChild(key); const container = document.createXULElement("box"); container.appendChild(keyset); document.documentElement.appendChild(container); const pageUrl = "data:text/html,
Test
"; const tab = await BrowserTestUtils.openNewForegroundTab( gBrowser, pageUrl ); await SpecialPowers.spawn( tab.linkedBrowser, [key.getAttribute("key")], async function(aExpectedKeyValue) { content.promiseTestResult = new Promise(resolve => { content.addEventListener("keyup", event => { if (event.key.toLowerCase() == aExpectedKeyValue.toLowerCase()) { resolve( content .getSelection() .getRangeAt(0) .toString() ); } }); }); } ); EventUtils.synthesizeKey(key.getAttribute("key"), { ctrlKey: key.getAttribute("modifiers").includes("ctrl"), shiftKey: key.getAttribute("modifiers").includes("shift"), }); const selectedText = await SpecialPowers.spawn( tab.linkedBrowser, [], async function() { return content.promiseTestResult; } ); is( selectedText, "Test", "The shortcut key should select all text in the editor" ); is( key.getAttribute("count"), "0", "The reserved shortcut key should be consumed by the focused editor instead" ); document.documentElement.removeChild(container); BrowserTestUtils.removeTab(tab); } ); }