mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 23:05:42 +00:00
Bug 1520263 - Make tabbrowser
wait reply event for F7 key before toggling caret browsing mode r=smaug
Unfortunately, it seems that `F7` key handling in `tabbrowser.js` cannot replaced with using XUL `<key>` element because it works with `ShortcutUtils.getSystemActionForEvent` for mapping `F7` is a toggle key of caret browsing mode. Therefore, this patch exposes some raw information of `WidgetEvent` related to cross process event propagation and makes `tabbrowser.js` check it and request reply event if it's required. So, when a remote content has focus, `tabbrowser.js` will do nothing for both `keydown` and `keypress` of `F7` key with original events, then, will request a reply event if its default is not prevented. Finally, reply `F7` keypress event will toggle caret browsing mode if the event is fired and not consumed. Differential Revision: https://phabricator.services.mozilla.com/D106591
This commit is contained in:
parent
bf87c0093b
commit
e2b7c9c6b0
@ -4966,6 +4966,34 @@
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* _maybeRequestReplyFromRemoteContent may call
|
||||
* aEvent.requestReplyFromRemoteContent if necessary.
|
||||
*
|
||||
* @param aEvent The handling event.
|
||||
* @return true if the handler should wait a reply event.
|
||||
* false if the handle can handle the immediately.
|
||||
*/
|
||||
_maybeRequestReplyFromRemoteContent(aEvent) {
|
||||
if (aEvent.defaultPrevented) {
|
||||
return false;
|
||||
}
|
||||
// If the event target is a remote browser, and the event has not been
|
||||
// handled by the remote content yet, we should wait a reply event
|
||||
// from the content.
|
||||
if (aEvent.isWaitingReplyFromRemoteContent) {
|
||||
return true; // Somebody called requestReplyFromRemoteContent already.
|
||||
}
|
||||
if (
|
||||
!aEvent.isReplyEventFromRemoteContent &&
|
||||
aEvent.target?.isRemoteBrowser === true
|
||||
) {
|
||||
aEvent.requestReplyFromRemoteContent();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_handleKeyDownEvent(aEvent) {
|
||||
if (!aEvent.isTrusted) {
|
||||
// Don't let untrusted events mess with tabs.
|
||||
@ -4981,6 +5009,9 @@
|
||||
// navigation should always work for better user experience.
|
||||
|
||||
switch (ShortcutUtils.getSystemActionForEvent(aEvent)) {
|
||||
case ShortcutUtils.TOGGLE_CARET_BROWSING:
|
||||
this._maybeRequestReplyFromRemoteContent(aEvent);
|
||||
return;
|
||||
case ShortcutUtils.MOVE_TAB_BACKWARD:
|
||||
this.moveTabBackward();
|
||||
aEvent.preventDefault();
|
||||
@ -5068,9 +5099,13 @@
|
||||
|
||||
switch (ShortcutUtils.getSystemActionForEvent(aEvent, { rtl: RTL_UI })) {
|
||||
case ShortcutUtils.TOGGLE_CARET_BROWSING:
|
||||
if (!aEvent.defaultPrevented) {
|
||||
this.toggleCaretBrowsing();
|
||||
if (
|
||||
aEvent.defaultPrevented ||
|
||||
this._maybeRequestReplyFromRemoteContent(aEvent)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
this.toggleCaretBrowsing();
|
||||
break;
|
||||
|
||||
case ShortcutUtils.NEXT_TAB:
|
||||
|
@ -2,6 +2,8 @@
|
||||
support-files = head.js
|
||||
|
||||
[browser_bookmarks_shortcut.js]
|
||||
[browser_cancel_caret_browsing_in_content.js]
|
||||
support-files = file_empty.html
|
||||
[browser_popup_keyNav.js]
|
||||
support-files = focusableContent.html
|
||||
[browser_toolbarButtonKeyPress.js]
|
||||
|
@ -0,0 +1,91 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(async function() {
|
||||
const kPrefName_CaretBrowsingOn = "accessibility.browsewithcaret";
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["accessibility.browsewithcaret_shortcut.enabled", true],
|
||||
["accessibility.warn_on_browsewithcaret", false],
|
||||
["test.events.async.enabled", true],
|
||||
[kPrefName_CaretBrowsingOn, false],
|
||||
],
|
||||
});
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
"https://example.com/browser/browser/base/content/test/keyboard/file_empty.html",
|
||||
async function(browser) {
|
||||
await SpecialPowers.spawn(browser, [], () => {
|
||||
content.document.documentElement.scrollTop; // Flush layout.
|
||||
});
|
||||
function promiseFirstAndReplyKeyEvents(aExpectedConsume) {
|
||||
return new Promise(resolve => {
|
||||
const eventType = aExpectedConsume ? "keydown" : "keypress";
|
||||
let eventCount = 0;
|
||||
let listener = () => {
|
||||
if (++eventCount === 2) {
|
||||
window.removeEventListener(eventType, listener, {
|
||||
capture: true,
|
||||
mozSystemGroup: true,
|
||||
});
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
window.addEventListener(eventType, listener, {
|
||||
capture: true,
|
||||
mozSystemGroup: true,
|
||||
});
|
||||
registerCleanupFunction(() => {
|
||||
window.removeEventListener(eventType, listener, {
|
||||
capture: true,
|
||||
mozSystemGroup: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
let promiseReplyF7KeyEvents = promiseFirstAndReplyKeyEvents(false);
|
||||
EventUtils.synthesizeKey("KEY_F7");
|
||||
info("Waiting reply F7 keypress event...");
|
||||
await promiseReplyF7KeyEvents;
|
||||
await TestUtils.waitForTick();
|
||||
is(
|
||||
Services.prefs.getBoolPref(kPrefName_CaretBrowsingOn),
|
||||
true,
|
||||
"F7 key should enable caret browsing mode"
|
||||
);
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [[kPrefName_CaretBrowsingOn, false]],
|
||||
});
|
||||
|
||||
await SpecialPowers.spawn(browser, [], () => {
|
||||
content.document.documentElement.scrollTop; // Flush layout.
|
||||
content.window.addEventListener(
|
||||
"keydown",
|
||||
event => event.preventDefault(),
|
||||
{ capture: true }
|
||||
);
|
||||
});
|
||||
promiseReplyF7KeyEvents = promiseFirstAndReplyKeyEvents(true);
|
||||
EventUtils.synthesizeKey("KEY_F7");
|
||||
info("Waiting for reply F7 keydown event...");
|
||||
await promiseReplyF7KeyEvents;
|
||||
try {
|
||||
info(`Checking reply keypress event is not fired...`);
|
||||
await TestUtils.waitForCondition(
|
||||
() => Services.prefs.getBoolPref(kPrefName_CaretBrowsingOn),
|
||||
"",
|
||||
100, // interval
|
||||
5 // maxTries
|
||||
);
|
||||
} catch (e) {}
|
||||
is(
|
||||
Services.prefs.getBoolPref(kPrefName_CaretBrowsingOn),
|
||||
false,
|
||||
"F7 key shouldn't enable caret browsing mode because F7 keydown event is consumed by web content"
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
8
browser/base/content/test/keyboard/file_empty.html
Normal file
8
browser/base/content/test/keyboard/file_empty.html
Normal file
@ -0,0 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Page left intentionally blank...</title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
@ -290,6 +290,18 @@ class Event : public nsISupports, public nsWrapperCache {
|
||||
*/
|
||||
static void GetWidgetEventType(WidgetEvent* aEvent, nsAString& aType);
|
||||
|
||||
void RequestReplyFromRemoteContent() {
|
||||
mEvent->MarkAsWaitingReplyFromRemoteProcess();
|
||||
}
|
||||
|
||||
bool IsWaitingReplyFromRemoteContent() const {
|
||||
return mEvent->IsWaitingReplyFromRemoteProcess();
|
||||
}
|
||||
|
||||
bool IsReplyEventFromRemoteContent() const {
|
||||
return mEvent->IsHandledInRemoteProcess();
|
||||
}
|
||||
|
||||
protected:
|
||||
// Internal helper functions
|
||||
void SetEventType(const nsAString& aEventTypeArg);
|
||||
|
@ -85,6 +85,19 @@ partial interface Event {
|
||||
[ChromeOnly] void preventMultipleActions();
|
||||
[ChromeOnly] readonly attribute boolean multipleActionsPrevented;
|
||||
[ChromeOnly] readonly attribute boolean isSynthesized;
|
||||
/**
|
||||
* When the event target is a remote browser, calling this will fire an
|
||||
* reply event in the chrome process.
|
||||
*/
|
||||
[ChromeOnly] void requestReplyFromRemoteContent();
|
||||
/**
|
||||
* Returns true when the event shouldn't be handled by chrome.
|
||||
*/
|
||||
[ChromeOnly] readonly attribute boolean isWaitingReplyFromRemoteContent;
|
||||
/**
|
||||
* Returns true when the event is a reply event from a remote process.
|
||||
*/
|
||||
[ChromeOnly] readonly attribute boolean isReplyEventFromRemoteContent;
|
||||
};
|
||||
|
||||
dictionary EventInit {
|
||||
|
Loading…
Reference in New Issue
Block a user