зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1864614 - [remote] Refactor DoubleClickTracker to work with multiple clicks sequences. r=webdriver-reviewers,whimboo
Differential Revision: https://phabricator.services.mozilla.com/D194613
This commit is contained in:
Родитель
5665a0b5c8
Коммит
2742cacf14
|
@ -7,7 +7,6 @@
|
|||
const lazy = {};
|
||||
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
event: "chrome://remote/content/marionette/event.sys.mjs",
|
||||
Log: "chrome://remote/content/shared/Log.sys.mjs",
|
||||
});
|
||||
|
||||
|
@ -67,16 +66,6 @@ export class MarionetteEventsChild extends JSWindowActorChild {
|
|||
windowId: this.innerWindowId,
|
||||
});
|
||||
break;
|
||||
|
||||
// Listen for click event to indicate one click has happened, so actions
|
||||
// code can send dblclick event
|
||||
case "click":
|
||||
lazy.event.DoubleClickTracker.setClick();
|
||||
break;
|
||||
case "dblclick":
|
||||
case "unload":
|
||||
lazy.event.DoubleClickTracker.resetClick();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,10 +13,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
|||
/** Provides functionality for creating and sending DOM events. */
|
||||
export const event = {};
|
||||
|
||||
ChromeUtils.defineLazyGetter(lazy, "dblclickTimer", () => {
|
||||
return Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
});
|
||||
|
||||
const _eventUtils = new WeakMap();
|
||||
|
||||
function _getEventUtils(win) {
|
||||
|
@ -36,9 +32,6 @@ function _getEventUtils(win) {
|
|||
return _eventUtils.get(win);
|
||||
}
|
||||
|
||||
// Max interval between two clicks that should result in a dblclick (in ms)
|
||||
const DBLCLICK_INTERVAL = 640;
|
||||
|
||||
event.MouseEvents = {
|
||||
click: 0,
|
||||
dblclick: 1,
|
||||
|
@ -67,33 +60,6 @@ event.MouseButton = {
|
|||
},
|
||||
};
|
||||
|
||||
event.DoubleClickTracker = {
|
||||
firstClick: false,
|
||||
isClicked() {
|
||||
return event.DoubleClickTracker.firstClick;
|
||||
},
|
||||
setClick() {
|
||||
if (!event.DoubleClickTracker.firstClick) {
|
||||
event.DoubleClickTracker.firstClick = true;
|
||||
event.DoubleClickTracker.startTimer();
|
||||
}
|
||||
},
|
||||
resetClick() {
|
||||
event.DoubleClickTracker.firstClick = false;
|
||||
event.DoubleClickTracker.cancelTimer();
|
||||
},
|
||||
startTimer() {
|
||||
lazy.dblclickTimer.initWithCallback(
|
||||
event.DoubleClickTracker.resetClick,
|
||||
DBLCLICK_INTERVAL,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT
|
||||
);
|
||||
},
|
||||
cancelTimer() {
|
||||
lazy.dblclickTimer.cancel();
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Synthesise a mouse event at a point.
|
||||
*
|
||||
|
|
|
@ -10,6 +10,7 @@ const lazy = {};
|
|||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
AppInfo: "chrome://remote/content/shared/AppInfo.sys.mjs",
|
||||
assert: "chrome://remote/content/shared/webdriver/Assert.sys.mjs",
|
||||
clearTimeout: "resource://gre/modules/Timer.sys.mjs",
|
||||
dom: "chrome://remote/content/shared/DOM.sys.mjs",
|
||||
error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs",
|
||||
event: "chrome://remote/content/marionette/event.sys.mjs",
|
||||
|
@ -17,6 +18,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
|||
Log: "chrome://remote/content/shared/Log.sys.mjs",
|
||||
pprint: "chrome://remote/content/shared/Format.sys.mjs",
|
||||
Sleep: "chrome://remote/content/marionette/sync.sys.mjs",
|
||||
setTimeout: "resource://gre/modules/Timer.sys.mjs",
|
||||
});
|
||||
|
||||
ChromeUtils.defineLazyGetter(lazy, "logger", () =>
|
||||
|
@ -38,6 +40,9 @@ ChromeUtils.defineLazyGetter(lazy, "logger", () =>
|
|||
*/
|
||||
export const action = {};
|
||||
|
||||
// Max interval between two clicks that should result in a dblclick or a tripleclick (in ms)
|
||||
export const CLICK_INTERVAL = 640;
|
||||
|
||||
/** Map from normalized key value to UI Events modifier key name */
|
||||
const MODIFIER_NAME_LOOKUP = {
|
||||
Alt: "alt",
|
||||
|
@ -53,6 +58,7 @@ const MODIFIER_NAME_LOOKUP = {
|
|||
*/
|
||||
action.State = class {
|
||||
constructor() {
|
||||
this.clickTracker = new ClickTracker();
|
||||
/**
|
||||
* A map between input ID and the device state for that input
|
||||
* source, with one entry for each active input source.
|
||||
|
@ -87,7 +93,6 @@ action.State = class {
|
|||
async release(win) {
|
||||
this.inputsToCancel.reverse();
|
||||
await this.inputsToCancel.dispatch(this, win);
|
||||
lazy.event.DoubleClickTracker.resetClick();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -169,6 +174,60 @@ action.State = class {
|
|||
}
|
||||
};
|
||||
|
||||
export class ClickTracker {
|
||||
#count;
|
||||
#lastButtonClicked;
|
||||
#timer;
|
||||
|
||||
constructor() {
|
||||
this.#count = 0;
|
||||
this.#lastButtonClicked = null;
|
||||
}
|
||||
|
||||
get count() {
|
||||
return this.#count;
|
||||
}
|
||||
|
||||
#cancelTimer() {
|
||||
lazy.clearTimeout(this.#timer);
|
||||
}
|
||||
|
||||
#startTimer() {
|
||||
this.#timer = lazy.setTimeout(this.reset.bind(this), CLICK_INTERVAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset tracking mouse click counter.
|
||||
*/
|
||||
reset() {
|
||||
this.#cancelTimer();
|
||||
this.#count = 0;
|
||||
this.#lastButtonClicked = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Track |button| click to identify possible double or triple click.
|
||||
*
|
||||
* @param {number} button
|
||||
* A positive integer that refers to a mouse button.
|
||||
*/
|
||||
setClick(button) {
|
||||
this.#cancelTimer();
|
||||
|
||||
if (
|
||||
this.#lastButtonClicked === null ||
|
||||
this.#lastButtonClicked === button
|
||||
) {
|
||||
this.#count++;
|
||||
} else {
|
||||
this.#count = 1;
|
||||
}
|
||||
|
||||
this.#lastButtonClicked = button;
|
||||
this.#startTimer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Device state for an input source.
|
||||
*/
|
||||
|
@ -1790,10 +1849,10 @@ class MousePointer extends Pointer {
|
|||
if (mouseEvent.ctrlKey) {
|
||||
if (lazy.AppInfo.isMac) {
|
||||
mouseEvent.button = 2;
|
||||
lazy.event.DoubleClickTracker.resetClick();
|
||||
state.clickTracker.reset();
|
||||
}
|
||||
} else if (lazy.event.DoubleClickTracker.isClicked()) {
|
||||
mouseEvent.clickCount = 2;
|
||||
} else {
|
||||
mouseEvent.clickCount = state.clickTracker.count + 1;
|
||||
}
|
||||
|
||||
lazy.event.synthesizeMouseAtPoint(
|
||||
|
@ -1823,9 +1882,8 @@ class MousePointer extends Pointer {
|
|||
});
|
||||
mouseEvent.update(state, inputSource);
|
||||
|
||||
if (lazy.event.DoubleClickTracker.isClicked()) {
|
||||
mouseEvent.clickCount = 2;
|
||||
}
|
||||
state.clickTracker.setClick(action.button);
|
||||
mouseEvent.clickCount = state.clickTracker.count;
|
||||
|
||||
lazy.event.synthesizeMouseAtPoint(
|
||||
inputSource.x,
|
||||
|
@ -1891,6 +1949,10 @@ action.Chain = class extends Array {
|
|||
}
|
||||
})();
|
||||
|
||||
// Reset the current click tracker counter. We shouldn't be able to simulate
|
||||
// a double click with multiple action chains.
|
||||
state.clickTracker.reset();
|
||||
|
||||
return chainEvents;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,10 +4,14 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { action } = ChromeUtils.importESModule(
|
||||
const { action, CLICK_INTERVAL, ClickTracker } = ChromeUtils.importESModule(
|
||||
"chrome://remote/content/shared/webdriver/Actions.sys.mjs"
|
||||
);
|
||||
|
||||
const { setTimeout } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/Timer.sys.mjs"
|
||||
);
|
||||
|
||||
const XHTMLNS = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
const domEl = {
|
||||
|
@ -681,6 +685,35 @@ add_task(function test_computeTickDuration_noDurations() {
|
|||
equal(0, chain[0].getDuration());
|
||||
});
|
||||
|
||||
add_task(function test_ClickTracker_setClick() {
|
||||
const clickTracker = new ClickTracker();
|
||||
const button1 = 1;
|
||||
const button2 = 2;
|
||||
|
||||
clickTracker.setClick(button1);
|
||||
equal(1, clickTracker.count);
|
||||
|
||||
// Make sure that clicking different mouse buttons doesn't increase the count.
|
||||
clickTracker.setClick(button2);
|
||||
equal(1, clickTracker.count);
|
||||
|
||||
clickTracker.setClick(button2);
|
||||
equal(2, clickTracker.count);
|
||||
|
||||
clickTracker.reset();
|
||||
equal(0, clickTracker.count);
|
||||
});
|
||||
|
||||
add_task(function test_ClickTracker_reset_after_timeout() {
|
||||
const clickTracker = new ClickTracker();
|
||||
|
||||
clickTracker.setClick(1);
|
||||
equal(1, clickTracker.count);
|
||||
|
||||
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
||||
setTimeout(() => equal(0, clickTracker.count), CLICK_INTERVAL + 10);
|
||||
});
|
||||
|
||||
// helpers
|
||||
function getTypeString(obj) {
|
||||
return Object.prototype.toString.call(obj);
|
||||
|
|
|
@ -1511,12 +1511,6 @@
|
|||
"parameters": ["firefox", "webDriverBiDi"],
|
||||
"expectations": ["FAIL"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[click.spec] Page.click should double click the button",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["firefox", "webDriverBiDi"],
|
||||
"expectations": ["FAIL"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[click.spec] Page.click should scroll and click with disabled javascript",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
|
@ -1535,12 +1529,6 @@
|
|||
"parameters": ["cdp", "firefox"],
|
||||
"expectations": ["FAIL", "PASS"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[click.spec] Page.click should select the text by triple clicking",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["firefox", "webDriverBiDi"],
|
||||
"expectations": ["FAIL"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[cookies.spec] Cookie specs Page.cookies should get cookies from multiple urls",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
|
|
Загрузка…
Ссылка в новой задаче