зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1821886 - Reserve shortcut keys exiting from the fullscreen mode r=Gijs,edgar,smaug
Chrome for Windows does not dispatch `keydown` event for shortcut keys existing from the fullscreen mode. Therefore, we can follow it. For reserving only shortcut keys in fullscreen mode, we need to duplicate XUL `<key>` elements which define the shortcut keys (only one in Windows/Linux, but 3 in macOS). Then, their `disabled` attributes should be managed when toggling the fullscreen mode. Finally, we need to make `XULKeySetGlobalKeyListener` check the `disabled` attribute **of** `<key>` elements because it's check in `DispatchXULKeyCommand` in the final step: https://searchfox.org/mozilla-central/rev/11a4d97a7b5cdfa133f4bda4525649f651703018/dom/events/KeyEventHandler.cpp#315-316 and it stops handling everything with doing nothing. I'm not sure whether this was intentionally implemented or just a inefficient code which we didn't take care the performance. However, I think that ignoring the disabled `<key>` elements is reasonable behavior from `<key>` element users point of view. (I found only one `<key>` which is disabled by default: https://searchfox.org/mozilla-central/rev/11a4d97a7b5cdfa133f4bda4525649f651703018/browser/base/content/browser-sets.inc#225-233) Differential Revision: https://phabricator.services.mozilla.com/D178262
This commit is contained in:
Родитель
9e821bba0e
Коммит
6b54cbe573
|
@ -365,6 +365,7 @@ var FullScreen = {
|
|||
this._isPopupOpen = false;
|
||||
this.cleanup();
|
||||
}
|
||||
this._toggleShortcutKeys();
|
||||
},
|
||||
|
||||
exitDomFullScreen() {
|
||||
|
@ -556,6 +557,25 @@ var FullScreen = {
|
|||
}
|
||||
},
|
||||
|
||||
_toggleShortcutKeys() {
|
||||
const kEnterKeyIds = [
|
||||
"key_enterFullScreen",
|
||||
"key_enterFullScreen_old",
|
||||
"key_enterFullScreen_compat",
|
||||
];
|
||||
const kExitKeyIds = [
|
||||
"key_exitFullScreen",
|
||||
"key_exitFullScreen_old",
|
||||
"key_exitFullScreen_compat",
|
||||
];
|
||||
for (let id of window.fullScreen ? kEnterKeyIds : kExitKeyIds) {
|
||||
document.getElementById(id)?.setAttribute("disabled", "true");
|
||||
}
|
||||
for (let id of window.fullScreen ? kExitKeyIds : kEnterKeyIds) {
|
||||
document.getElementById(id)?.removeAttribute("disabled");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Clean up full screen, starting from the request origin's first ancestor
|
||||
* frame that is OOP.
|
||||
|
|
|
@ -215,12 +215,16 @@
|
|||
#ifndef XP_MACOSX
|
||||
<key id="showAllHistoryKb" data-l10n-id="history-show-all-shortcut" command="Browser:ShowAllHistory" modifiers="accel,shift"/>
|
||||
<key keycode="VK_F5" command="Browser:ReloadSkipCache" modifiers="accel"/>
|
||||
<key id="key_fullScreen" keycode="VK_F11" command="View:FullScreen"/>
|
||||
<key id="key_enterFullScreen" keycode="VK_F11" command="View:FullScreen"/>
|
||||
<key id="key_exitFullScreen" keycode="VK_F11" command="View:FullScreen" reserved="true" disabled="true"/>
|
||||
#else
|
||||
<key id="showAllHistoryKb" data-l10n-id="history-show-all-shortcut-mac" command="Browser:ShowAllHistory" modifiers="accel"/>
|
||||
<key id="key_fullScreen" data-l10n-id="full-screen-shortcut" command="View:FullScreen" modifiers="accel,control"/>
|
||||
<key id="key_fullScreen_old" data-l10n-id="full-screen-shortcut" command="View:FullScreen" modifiers="accel,shift"/>
|
||||
<key keycode="VK_F11" command="View:FullScreen"/>
|
||||
<key id="key_enterFullScreen" data-l10n-id="full-screen-shortcut" command="View:FullScreen" modifiers="accel,control"/>
|
||||
<key id="key_enterFullScreen_old" data-l10n-id="full-screen-shortcut" command="View:FullScreen" modifiers="accel,shift"/>
|
||||
<key id="key_enterFullScreen_compat" keycode="VK_F11" command="View:FullScreen"/>
|
||||
<key id="key_exitFullScreen" data-l10n-id="full-screen-shortcut" command="View:FullScreen" modifiers="accel,control" reserved="true" disabled="true"/>
|
||||
<key id="key_exitFullScreen_old" data-l10n-id="full-screen-shortcut" command="View:FullScreen" modifiers="accel,shift" reserved="true" disabled="true"/>
|
||||
<key id="key_exitFullScreen_compat" keycode="VK_F11" command="View:FullScreen" reserved="true" disabled="true"/>
|
||||
#endif
|
||||
<key id="key_toggleReaderMode"
|
||||
command="View:ReaderView"
|
||||
|
|
|
@ -16,6 +16,7 @@ support-files = fullscreen.html fullscreen_frame.html
|
|||
skip-if = (os == 'mac') || (os == 'linux') # Bug 1648649
|
||||
[browser_fullscreen_from_minimize.js]
|
||||
skip-if = (os == 'linux') || (os == 'win') # Bug 1818795 and Bug 1818796
|
||||
[browser_fullscreen_keydown_reservation.js]
|
||||
[browser_fullscreen_newtab.js]
|
||||
[browser_fullscreen_newwindow.js]
|
||||
[browser_fullscreen_permissions_prompt.js]
|
||||
|
|
|
@ -47,5 +47,10 @@ add_task(async function test() {
|
|||
await onToolboxHidden;
|
||||
|
||||
Assert.ok(true, "Nav toolbox hidden");
|
||||
|
||||
info("Waiting for exiting from the fullscreen mode...");
|
||||
onFullscreen = BrowserTestUtils.waitForEvent(window, "fullscreen");
|
||||
document.getElementById("View:FullScreen").doCommand();
|
||||
await onFullscreen;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// This test verifies that whether shortcut keys of toggling fullscreen modes
|
||||
// are reserved.
|
||||
add_task(async function test_keydown_event_reservation_toggling_fullscreen() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["full-screen-api.transition-duration.enter", "0 0"],
|
||||
["full-screen-api.transition-duration.leave", "0 0"],
|
||||
],
|
||||
});
|
||||
|
||||
let shortcutKeys = [{ key: "KEY_F11", modifiers: {} }];
|
||||
if (navigator.platform.startsWith("Mac")) {
|
||||
shortcutKeys.push({
|
||||
key: "f",
|
||||
modifiers: { metaKey: true, ctrlKey: true },
|
||||
});
|
||||
shortcutKeys.push({
|
||||
key: "F",
|
||||
modifiers: { metaKey: true, shiftKey: true },
|
||||
});
|
||||
}
|
||||
function shortcutDescription(aShortcutKey) {
|
||||
return `${
|
||||
aShortcutKey.metaKey ? "Meta + " : ""
|
||||
}${aShortcutKey.shiftKey ? "Shift + " : ""}${aShortcutKey.ctrlKey ? "Ctrl + " : ""}${aShortcutKey.key.replace("KEY_", "")}`;
|
||||
}
|
||||
for (const shortcutKey of shortcutKeys) {
|
||||
const tab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
"https://example.org/browser/browser/base/content/test/fullscreen/fullscreen.html"
|
||||
);
|
||||
|
||||
await SimpleTest.promiseFocus(tab.linkedBrowser);
|
||||
|
||||
const fullScreenEntered = BrowserTestUtils.waitForEvent(
|
||||
window,
|
||||
"fullscreen"
|
||||
);
|
||||
|
||||
await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
|
||||
content.wrappedJSObject.keydown = null;
|
||||
content.window.addEventListener("keydown", event => {
|
||||
switch (event.key) {
|
||||
case "Shift":
|
||||
case "Meta":
|
||||
case "Control":
|
||||
break;
|
||||
default:
|
||||
content.wrappedJSObject.keydown = event;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
EventUtils.synthesizeKey(shortcutKey.key, shortcutKey.modifiers);
|
||||
|
||||
info(
|
||||
`Waiting for entering the fullscreen mode with synthesizing ${shortcutDescription(
|
||||
shortcutKey
|
||||
)}...`
|
||||
);
|
||||
await fullScreenEntered;
|
||||
|
||||
info("Retrieving the result...");
|
||||
Assert.ok(
|
||||
await SpecialPowers.spawn(
|
||||
tab.linkedBrowser,
|
||||
[],
|
||||
async () => !!content.wrappedJSObject.keydown
|
||||
),
|
||||
`Entering the fullscreen mode with ${shortcutDescription(
|
||||
shortcutKey
|
||||
)} should cause "keydown" event`
|
||||
);
|
||||
|
||||
const fullScreenExited = BrowserTestUtils.waitForEvent(
|
||||
window,
|
||||
"fullscreen"
|
||||
);
|
||||
|
||||
await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
|
||||
content.wrappedJSObject.keydown = null;
|
||||
});
|
||||
|
||||
EventUtils.synthesizeKey(shortcutKey.key, shortcutKey.modifiers);
|
||||
|
||||
info(
|
||||
`Waiting for exiting from the fullscreen mode with synthesizing ${shortcutDescription(
|
||||
shortcutKey
|
||||
)}...`
|
||||
);
|
||||
await fullScreenExited;
|
||||
|
||||
info("Retrieving the result...");
|
||||
Assert.ok(
|
||||
await SpecialPowers.spawn(
|
||||
tab.linkedBrowser,
|
||||
[],
|
||||
async () => !content.wrappedJSObject.keydown
|
||||
),
|
||||
`Exiting from the fullscreen mode with ${shortcutDescription(
|
||||
shortcutKey
|
||||
)} should not cause "keydown" event`
|
||||
);
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
});
|
|
@ -23,6 +23,11 @@ function receiveExpectedKeyEvents(aBrowser, aKeyCode, aTrusted) {
|
|||
let events = trusted
|
||||
? ["keydown", "keyup"]
|
||||
: ["keydown", "keypress", "keyup"];
|
||||
if (trusted && keyCode == content.wrappedJSObject.KeyEvent.DOM_VK_F11) {
|
||||
// trusted `F11` key shouldn't be fired because of reserved when it's
|
||||
// a shortcut key for exiting from the full screen mode.
|
||||
events.shift();
|
||||
}
|
||||
function listener(event) {
|
||||
let expected = events.shift();
|
||||
Assert.equal(
|
||||
|
@ -197,7 +202,7 @@ add_task(async function () {
|
|||
"correct number of fullscreen events occurred"
|
||||
);
|
||||
if (!suppressed) {
|
||||
expectedKeyEventsCount += keyCode == "VK_F11" ? 2 : 3;
|
||||
expectedKeyEventsCount += keyCode == "VK_F11" ? 1 : 3;
|
||||
}
|
||||
is(
|
||||
keyEventsCount,
|
||||
|
|
|
@ -623,6 +623,11 @@ already_AddRefed<dom::EventTarget> XULKeySetGlobalKeyListener::GetHandlerTarget(
|
|||
|
||||
bool XULKeySetGlobalKeyListener::CanHandle(KeyEventHandler* aHandler,
|
||||
bool aWillExecute) const {
|
||||
// If the <key> element itself is disabled, ignore it.
|
||||
if (aHandler->KeyElementIsDisabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<dom::Element> commandElement;
|
||||
if (!GetElementForHandler(aHandler, getter_AddRefs(commandElement))) {
|
||||
return false;
|
||||
|
|
|
@ -166,7 +166,14 @@ bool KeyEventHandler::TryConvertToKeyboardShortcut(
|
|||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<dom::Element> KeyEventHandler::GetHandlerElement() {
|
||||
bool KeyEventHandler::KeyElementIsDisabled() const {
|
||||
RefPtr<dom::Element> keyElement = GetHandlerElement();
|
||||
return keyElement &&
|
||||
keyElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
|
||||
nsGkAtoms::_true, eCaseMatters);
|
||||
}
|
||||
|
||||
already_AddRefed<dom::Element> KeyEventHandler::GetHandlerElement() const {
|
||||
if (mIsXULKey) {
|
||||
nsCOMPtr<dom::Element> element = do_QueryReferent(mHandlerElement);
|
||||
return element.forget();
|
||||
|
|
|
@ -75,7 +75,14 @@ class KeyEventHandler final {
|
|||
uint32_t aCharCode,
|
||||
const IgnoreModifierState& aIgnoreModifierState);
|
||||
|
||||
already_AddRefed<dom::Element> GetHandlerElement();
|
||||
/**
|
||||
* Check whether the handler element is disabled. Note that this requires
|
||||
* a QI to getting GetHandlerELement(). Therefore, this should not be used
|
||||
* first in multiple checks.
|
||||
*/
|
||||
bool KeyElementIsDisabled() const;
|
||||
|
||||
already_AddRefed<dom::Element> GetHandlerElement() const;
|
||||
|
||||
ReservedKey GetIsReserved() { return mReserved; }
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче