mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1454851 - Remove gestures and all input management. r=yzen
This commit is contained in:
parent
e9186f7449
commit
326a67e71e
@ -13,9 +13,6 @@ if (Utils.MozBuildApp === "mobile/android") {
|
||||
ChromeUtils.import("resource://gre/modules/Messaging.jsm");
|
||||
}
|
||||
|
||||
const QUICKNAV_MODES_PREF = "accessibility.accessfu.quicknav_modes";
|
||||
const QUICKNAV_INDEX_PREF = "accessibility.accessfu.quicknav_index";
|
||||
|
||||
const GECKOVIEW_MESSAGE = {
|
||||
ACTIVATE: "GeckoView:AccessibilityActivate",
|
||||
VIEW_FOCUSED: "GeckoView:AccessibilityViewFocused",
|
||||
@ -74,7 +71,6 @@ var AccessFu = {
|
||||
this._enabled = true;
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/accessibility/PointerAdapter.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/accessibility/Presentation.jsm");
|
||||
|
||||
for (let mm of Utils.AllMessageManagers) {
|
||||
@ -89,30 +85,11 @@ var AccessFu = {
|
||||
Utils.win.document.insertBefore(stylesheet, Utils.win.document.firstChild);
|
||||
this.stylesheet = Cu.getWeakReference(stylesheet);
|
||||
|
||||
|
||||
// Populate quicknav modes
|
||||
this._quicknavModesPref =
|
||||
new PrefCache(QUICKNAV_MODES_PREF, (aName, aValue, aFirstRun) => {
|
||||
this.Input.quickNavMode.updateModes(aValue);
|
||||
if (!aFirstRun) {
|
||||
// If the modes change, reset the current mode index to 0.
|
||||
Services.prefs.setIntPref(QUICKNAV_INDEX_PREF, 0);
|
||||
}
|
||||
}, true);
|
||||
|
||||
this._quicknavCurrentModePref =
|
||||
new PrefCache(QUICKNAV_INDEX_PREF, (aName, aValue) => {
|
||||
this.Input.quickNavMode.updateCurrentMode(Number(aValue));
|
||||
}, true);
|
||||
|
||||
// Check for output notification
|
||||
this._notifyOutputPref =
|
||||
new PrefCache("accessibility.accessfu.notify_output");
|
||||
|
||||
|
||||
this.Input.start();
|
||||
Output.start();
|
||||
PointerAdapter.start();
|
||||
|
||||
if (Utils.MozBuildApp === "mobile/android") {
|
||||
Utils.win.WindowEventDispatcher.registerListener(this,
|
||||
@ -150,9 +127,7 @@ var AccessFu = {
|
||||
this._removeMessageListeners(mm);
|
||||
}
|
||||
|
||||
this.Input.stop();
|
||||
Output.stop();
|
||||
PointerAdapter.stop();
|
||||
|
||||
Utils.win.removeEventListener("TabOpen", this);
|
||||
Utils.win.removeEventListener("TabClose", this);
|
||||
@ -166,7 +141,6 @@ var AccessFu = {
|
||||
Object.values(GECKOVIEW_MESSAGE));
|
||||
}
|
||||
|
||||
delete this._quicknavModesPref;
|
||||
delete this._notifyOutputPref;
|
||||
|
||||
if (this.doneCallback) {
|
||||
@ -567,207 +541,6 @@ var Output = {
|
||||
var Input = {
|
||||
editState: {},
|
||||
|
||||
start: function start() {
|
||||
// XXX: This is too disruptive on desktop for now.
|
||||
// Might need to add special modifiers.
|
||||
if (Utils.MozBuildApp != "browser") {
|
||||
Utils.win.document.addEventListener("keypress", this, true);
|
||||
}
|
||||
Utils.win.addEventListener("mozAccessFuGesture", this, true);
|
||||
},
|
||||
|
||||
stop: function stop() {
|
||||
if (Utils.MozBuildApp != "browser") {
|
||||
Utils.win.document.removeEventListener("keypress", this, true);
|
||||
}
|
||||
Utils.win.removeEventListener("mozAccessFuGesture", this, true);
|
||||
},
|
||||
|
||||
handleEvent: function Input_handleEvent(aEvent) {
|
||||
try {
|
||||
switch (aEvent.type) {
|
||||
case "keypress":
|
||||
this._handleKeypress(aEvent);
|
||||
break;
|
||||
case "mozAccessFuGesture":
|
||||
this._handleGesture(aEvent.detail);
|
||||
break;
|
||||
}
|
||||
} catch (x) {
|
||||
Logger.logException(x);
|
||||
}
|
||||
},
|
||||
|
||||
_handleGesture: function _handleGesture(aGesture) {
|
||||
let gestureName = aGesture.type + aGesture.touches.length;
|
||||
Logger.debug("Gesture", aGesture.type,
|
||||
"(fingers: " + aGesture.touches.length + ")");
|
||||
|
||||
switch (gestureName) {
|
||||
case "dwell1":
|
||||
case "explore1":
|
||||
this.moveToPoint("Simple", aGesture.touches[0].x,
|
||||
aGesture.touches[0].y);
|
||||
break;
|
||||
case "doubletap1":
|
||||
this.activateCurrent();
|
||||
break;
|
||||
case "doubletaphold1":
|
||||
Utils.dispatchChromeEvent("accessibility-control", "quicknav-menu");
|
||||
break;
|
||||
case "swiperight1":
|
||||
this.moveCursor("moveNext", "Simple", "gestures");
|
||||
break;
|
||||
case "swipeleft1":
|
||||
this.moveCursor("movePrevious", "Simple", "gesture");
|
||||
break;
|
||||
case "swipeup1":
|
||||
this.moveCursor(
|
||||
"movePrevious", this.quickNavMode.current, "gesture", true);
|
||||
break;
|
||||
case "swipedown1":
|
||||
this.moveCursor("moveNext", this.quickNavMode.current, "gesture", true);
|
||||
break;
|
||||
case "exploreend1":
|
||||
case "dwellend1":
|
||||
this.activateCurrent(null, true);
|
||||
break;
|
||||
case "swiperight2":
|
||||
if (aGesture.edge) {
|
||||
Utils.dispatchChromeEvent("accessibility-control",
|
||||
"edge-swipe-right");
|
||||
break;
|
||||
}
|
||||
this.sendScrollMessage(-1, true);
|
||||
break;
|
||||
case "swipedown2":
|
||||
if (aGesture.edge) {
|
||||
Utils.dispatchChromeEvent("accessibility-control", "edge-swipe-down");
|
||||
break;
|
||||
}
|
||||
this.sendScrollMessage(-1);
|
||||
break;
|
||||
case "swipeleft2":
|
||||
if (aGesture.edge) {
|
||||
Utils.dispatchChromeEvent("accessibility-control", "edge-swipe-left");
|
||||
break;
|
||||
}
|
||||
this.sendScrollMessage(1, true);
|
||||
break;
|
||||
case "swipeup2":
|
||||
if (aGesture.edge) {
|
||||
Utils.dispatchChromeEvent("accessibility-control", "edge-swipe-up");
|
||||
break;
|
||||
}
|
||||
this.sendScrollMessage(1);
|
||||
break;
|
||||
case "explore2":
|
||||
Utils.CurrentBrowser.contentWindow.scrollBy(
|
||||
-aGesture.deltaX, -aGesture.deltaY);
|
||||
break;
|
||||
case "swiperight3":
|
||||
this.moveCursor("moveNext", this.quickNavMode.current, "gesture");
|
||||
break;
|
||||
case "swipeleft3":
|
||||
this.moveCursor("movePrevious", this.quickNavMode.current, "gesture");
|
||||
break;
|
||||
case "swipedown3":
|
||||
this.quickNavMode.next();
|
||||
AccessFu.announce("quicknav_" + this.quickNavMode.current);
|
||||
break;
|
||||
case "swipeup3":
|
||||
this.quickNavMode.previous();
|
||||
AccessFu.announce("quicknav_" + this.quickNavMode.current);
|
||||
break;
|
||||
case "tripletap3":
|
||||
Utils.dispatchChromeEvent("accessibility-control", "toggle-shade");
|
||||
break;
|
||||
case "tap2":
|
||||
Utils.dispatchChromeEvent("accessibility-control", "toggle-pause");
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_handleKeypress: function _handleKeypress(aEvent) {
|
||||
let target = aEvent.target;
|
||||
|
||||
// Ignore keys with modifiers so the content could take advantage of them.
|
||||
if (aEvent.ctrlKey || aEvent.altKey || aEvent.metaKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aEvent.keyCode) {
|
||||
case 0:
|
||||
// an alphanumeric key was pressed, handle it separately.
|
||||
// If it was pressed with either alt or ctrl, just pass through.
|
||||
// If it was pressed with meta, pass the key on without the meta.
|
||||
if (this.editState.editing) {
|
||||
return;
|
||||
}
|
||||
|
||||
let key = String.fromCharCode(aEvent.charCode);
|
||||
try {
|
||||
let [methodName, rule] = this.keyMap[key];
|
||||
this.moveCursor(methodName, rule, "keyboard");
|
||||
} catch (x) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case aEvent.DOM_VK_RIGHT:
|
||||
if (this.editState.editing) {
|
||||
if (!this.editState.atEnd) {
|
||||
// Don't move forward if caret is not at end of entry.
|
||||
// XXX: Fix for rtl
|
||||
return;
|
||||
}
|
||||
target.blur();
|
||||
|
||||
}
|
||||
this.moveCursor(aEvent.shiftKey ?
|
||||
"moveLast" : "moveNext", "Simple", "keyboard");
|
||||
break;
|
||||
case aEvent.DOM_VK_LEFT:
|
||||
if (this.editState.editing) {
|
||||
if (!this.editState.atStart) {
|
||||
// Don't move backward if caret is not at start of entry.
|
||||
// XXX: Fix for rtl
|
||||
return;
|
||||
}
|
||||
target.blur();
|
||||
|
||||
}
|
||||
this.moveCursor(aEvent.shiftKey ?
|
||||
"moveFirst" : "movePrevious", "Simple", "keyboard");
|
||||
break;
|
||||
case aEvent.DOM_VK_UP:
|
||||
if (this.editState.multiline) {
|
||||
if (!this.editState.atStart) {
|
||||
// Don't blur content if caret is not at start of text area.
|
||||
return;
|
||||
}
|
||||
target.blur();
|
||||
|
||||
}
|
||||
|
||||
if (Utils.MozBuildApp == "mobile/android") {
|
||||
// Return focus to native Android browser chrome.
|
||||
Utils.win.WindowEventDispatcher.dispatch("ToggleChrome:Focus");
|
||||
}
|
||||
break;
|
||||
case aEvent.DOM_VK_RETURN:
|
||||
if (this.editState.editing) {
|
||||
return;
|
||||
}
|
||||
this.activateCurrent();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
aEvent.preventDefault();
|
||||
aEvent.stopPropagation();
|
||||
},
|
||||
|
||||
moveToPoint: function moveToPoint(aRule, aX, aY) {
|
||||
// XXX: Bug 1013408 - There is no alignment between the chrome window's
|
||||
// viewport size and the content viewport size in Android. This makes
|
||||
@ -850,77 +623,6 @@ var Input = {
|
||||
Utils.winUtils.sendWheelEvent(p.x, p.y,
|
||||
horizontal ? page : 0, horizontal ? 0 : page, 0,
|
||||
Utils.win.WheelEvent.DOM_DELTA_PAGE, 0, 0, 0, 0);
|
||||
},
|
||||
|
||||
get keyMap() {
|
||||
delete this.keyMap;
|
||||
this.keyMap = {
|
||||
a: ["moveNext", "Anchor"],
|
||||
A: ["movePrevious", "Anchor"],
|
||||
b: ["moveNext", "Button"],
|
||||
B: ["movePrevious", "Button"],
|
||||
c: ["moveNext", "Combobox"],
|
||||
C: ["movePrevious", "Combobox"],
|
||||
d: ["moveNext", "Landmark"],
|
||||
D: ["movePrevious", "Landmark"],
|
||||
e: ["moveNext", "Entry"],
|
||||
E: ["movePrevious", "Entry"],
|
||||
f: ["moveNext", "FormElement"],
|
||||
F: ["movePrevious", "FormElement"],
|
||||
g: ["moveNext", "Graphic"],
|
||||
G: ["movePrevious", "Graphic"],
|
||||
h: ["moveNext", "Heading"],
|
||||
H: ["movePrevious", "Heading"],
|
||||
i: ["moveNext", "ListItem"],
|
||||
I: ["movePrevious", "ListItem"],
|
||||
k: ["moveNext", "Link"],
|
||||
K: ["movePrevious", "Link"],
|
||||
l: ["moveNext", "List"],
|
||||
L: ["movePrevious", "List"],
|
||||
p: ["moveNext", "PageTab"],
|
||||
P: ["movePrevious", "PageTab"],
|
||||
r: ["moveNext", "RadioButton"],
|
||||
R: ["movePrevious", "RadioButton"],
|
||||
s: ["moveNext", "Separator"],
|
||||
S: ["movePrevious", "Separator"],
|
||||
t: ["moveNext", "Table"],
|
||||
T: ["movePrevious", "Table"],
|
||||
x: ["moveNext", "Checkbox"],
|
||||
X: ["movePrevious", "Checkbox"]
|
||||
};
|
||||
|
||||
return this.keyMap;
|
||||
},
|
||||
|
||||
quickNavMode: {
|
||||
get current() {
|
||||
return this.modes[this._currentIndex];
|
||||
},
|
||||
|
||||
previous: function quickNavMode_previous() {
|
||||
Services.prefs.setIntPref(QUICKNAV_INDEX_PREF,
|
||||
this._currentIndex > 0 ?
|
||||
this._currentIndex - 1 : this.modes.length - 1);
|
||||
},
|
||||
|
||||
next: function quickNavMode_next() {
|
||||
Services.prefs.setIntPref(QUICKNAV_INDEX_PREF,
|
||||
this._currentIndex + 1 >= this.modes.length ?
|
||||
0 : this._currentIndex + 1);
|
||||
},
|
||||
|
||||
updateModes: function updateModes(aModes) {
|
||||
if (aModes) {
|
||||
this.modes = aModes.split(",");
|
||||
} else {
|
||||
this.modes = [];
|
||||
}
|
||||
},
|
||||
|
||||
updateCurrentMode: function updateCurrentMode(aModeIndex) {
|
||||
Logger.debug("Quicknav mode:", this.modes[aModeIndex]);
|
||||
this._currentIndex = aModeIndex;
|
||||
}
|
||||
}
|
||||
};
|
||||
AccessFu.Input = Input;
|
||||
|
@ -1,951 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* exported GestureSettings, GestureTracker */
|
||||
|
||||
/** ****************************************************************************
|
||||
All gestures have the following pathways when being resolved(v)/rejected(x):
|
||||
Tap -> DoubleTap (x)
|
||||
-> Dwell (x)
|
||||
-> Swipe (x)
|
||||
|
||||
DoubleTap -> TripleTap (x)
|
||||
-> TapHold (x)
|
||||
|
||||
TripleTap -> DoubleTapHold (x)
|
||||
|
||||
Dwell -> DwellEnd (v)
|
||||
|
||||
Swipe -> Explore (x)
|
||||
|
||||
TapHold -> TapHoldEnd (v)
|
||||
|
||||
DoubleTapHold -> DoubleTapHoldEnd (v)
|
||||
|
||||
DwellEnd -> Explore (x)
|
||||
|
||||
TapHoldEnd -> Explore (x)
|
||||
|
||||
DoubleTapHoldEnd -> Explore (x)
|
||||
|
||||
ExploreEnd -> Explore (x)
|
||||
|
||||
Explore -> ExploreEnd (v)
|
||||
******************************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["GestureSettings", "GestureTracker"]; // jshint ignore:line
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Utils", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Utils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Logger", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Utils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "setTimeout", // jshint ignore:line
|
||||
"resource://gre/modules/Timer.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "clearTimeout", // jshint ignore:line
|
||||
"resource://gre/modules/Timer.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "PromiseUtils", // jshint ignore:line
|
||||
"resource://gre/modules/PromiseUtils.jsm");
|
||||
|
||||
// Default maximum duration of swipe
|
||||
const SWIPE_MAX_DURATION = 200;
|
||||
// Default maximum amount of time allowed for a gesture to be considered a
|
||||
// multitouch
|
||||
const MAX_MULTITOUCH = 125;
|
||||
// Default maximum consecutive pointer event timeout
|
||||
const MAX_CONSECUTIVE_GESTURE_DELAY = 200;
|
||||
// Default delay before tap turns into dwell
|
||||
const DWELL_THRESHOLD = 250;
|
||||
// Minimal swipe distance in inches
|
||||
const SWIPE_MIN_DISTANCE = 0.4;
|
||||
// Maximum distance the pointer could move during a tap in inches
|
||||
const TAP_MAX_RADIUS = 0.2;
|
||||
// Directness coefficient. It is based on the maximum 15 degree angle between
|
||||
// consequent pointer move lines.
|
||||
const DIRECTNESS_COEFF = 1.44;
|
||||
// Amount in inches from the edges of the screen for it to be an edge swipe
|
||||
const EDGE = 0.1;
|
||||
// Multiply timeouts by this constant, x2 works great too for slower users.
|
||||
const TIMEOUT_MULTIPLIER = 1;
|
||||
// A single pointer down/up sequence periodically precedes the tripple swipe
|
||||
// gesture on Android. This delay acounts for that.
|
||||
const IS_ANDROID = Utils.MozBuildApp === "mobile/android" &&
|
||||
Utils.AndroidSdkVersion >= 14;
|
||||
|
||||
/**
|
||||
* A point object containing distance travelled data.
|
||||
* @param {Object} aPoint A point object that looks like: {
|
||||
* x: x coordinate in pixels,
|
||||
* y: y coordinate in pixels
|
||||
* }
|
||||
*/
|
||||
function Point(aPoint) {
|
||||
this.startX = this.x = aPoint.x;
|
||||
this.startY = this.y = aPoint.y;
|
||||
this.distanceTraveled = 0;
|
||||
this.totalDistanceTraveled = 0;
|
||||
}
|
||||
|
||||
Point.prototype = {
|
||||
/**
|
||||
* Update the current point coordiates.
|
||||
* @param {Object} aPoint A new point coordinates.
|
||||
*/
|
||||
update: function Point_update(aPoint) {
|
||||
let lastX = this.x;
|
||||
let lastY = this.y;
|
||||
this.x = aPoint.x;
|
||||
this.y = aPoint.y;
|
||||
this.distanceTraveled = this.getDistanceToCoord(lastX, lastY);
|
||||
this.totalDistanceTraveled += this.distanceTraveled;
|
||||
},
|
||||
|
||||
reset: function Point_reset() {
|
||||
this.distanceTraveled = 0;
|
||||
this.totalDistanceTraveled = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get distance between the current point coordinates and the given ones.
|
||||
* @param {Number} aX A pixel value for the x coordinate.
|
||||
* @param {Number} aY A pixel value for the y coordinate.
|
||||
* @return {Number} A distance between point's current and the given
|
||||
* coordinates.
|
||||
*/
|
||||
getDistanceToCoord: function Point_getDistanceToCoord(aX, aY) {
|
||||
return Math.hypot(this.x - aX, this.y - aY);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the direct distance travelled by the point so far.
|
||||
*/
|
||||
get directDistanceTraveled() {
|
||||
return this.getDistanceToCoord(this.startX, this.startY);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An externally accessible collection of settings used in gesture resolition.
|
||||
* @type {Object}
|
||||
*/
|
||||
var GestureSettings = { // jshint ignore:line
|
||||
/**
|
||||
* Maximum duration of swipe
|
||||
* @type {Number}
|
||||
*/
|
||||
swipeMaxDuration: SWIPE_MAX_DURATION * TIMEOUT_MULTIPLIER,
|
||||
|
||||
/**
|
||||
* Maximum amount of time allowed for a gesture to be considered a multitouch.
|
||||
* @type {Number}
|
||||
*/
|
||||
maxMultitouch: MAX_MULTITOUCH * TIMEOUT_MULTIPLIER,
|
||||
|
||||
/**
|
||||
* Maximum consecutive pointer event timeout.
|
||||
* @type {Number}
|
||||
*/
|
||||
maxConsecutiveGestureDelay:
|
||||
MAX_CONSECUTIVE_GESTURE_DELAY * TIMEOUT_MULTIPLIER,
|
||||
|
||||
/**
|
||||
* A maximum time we wait for a next pointer down event to consider a sequence
|
||||
* a multi-action gesture.
|
||||
* @type {Number}
|
||||
*/
|
||||
maxGestureResolveTimeout:
|
||||
MAX_CONSECUTIVE_GESTURE_DELAY * TIMEOUT_MULTIPLIER,
|
||||
|
||||
/**
|
||||
* Delay before tap turns into dwell
|
||||
* @type {Number}
|
||||
*/
|
||||
dwellThreshold: DWELL_THRESHOLD * TIMEOUT_MULTIPLIER,
|
||||
|
||||
/**
|
||||
* Minimum distance that needs to be travelled for the pointer move to be
|
||||
* fired.
|
||||
* @type {Number}
|
||||
*/
|
||||
travelThreshold: 0.025
|
||||
};
|
||||
|
||||
/**
|
||||
* An interface that handles the pointer events and calculates the appropriate
|
||||
* gestures.
|
||||
* @type {Object}
|
||||
*/
|
||||
var GestureTracker = { // jshint ignore:line
|
||||
/**
|
||||
* Reset GestureTracker to its initial state.
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
reset: function GestureTracker_reset() {
|
||||
if (this.current) {
|
||||
this.current.clearTimer();
|
||||
}
|
||||
delete this.current;
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new gesture object and attach resolution handler to it as well as
|
||||
* handle the incoming pointer event.
|
||||
* @param {Object} aDetail A new pointer event detail.
|
||||
* @param {Number} aTimeStamp A new pointer event timeStamp.
|
||||
* @param {Function} aGesture A gesture constructor (default: Tap).
|
||||
*/
|
||||
_init: function GestureTracker__init(aDetail, aTimeStamp, aGesture) {
|
||||
// Only create a new gesture on |pointerdown| event.
|
||||
if (aDetail.type !== "pointerdown") {
|
||||
return;
|
||||
}
|
||||
let GestureConstructor = aGesture || (IS_ANDROID ? DoubleTap : Tap);
|
||||
this._create(GestureConstructor);
|
||||
this._update(aDetail, aTimeStamp);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle the incoming pointer event with the existing gesture object(if
|
||||
* present) or with the newly created one.
|
||||
* @param {Object} aDetail A new pointer event detail.
|
||||
* @param {Number} aTimeStamp A new pointer event timeStamp.
|
||||
*/
|
||||
handle: function GestureTracker_handle(aDetail, aTimeStamp) {
|
||||
Logger.gesture(() => {
|
||||
return ["Pointer event", Utils.dpi, "at:", aTimeStamp, JSON.stringify(aDetail)];
|
||||
});
|
||||
this[this.current ? "_update" : "_init"](aDetail, aTimeStamp);
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new gesture object and attach resolution handler to it.
|
||||
* @param {Function} aGesture A gesture constructor.
|
||||
* @param {Number} aTimeStamp An original pointer event timeStamp.
|
||||
* @param {Array} aPoints All changed points associated with the new pointer
|
||||
* event.
|
||||
* @param {?String} aLastEvent Last pointer event type.
|
||||
*/
|
||||
_create: function GestureTracker__create(aGesture, aTimeStamp, aPoints, aLastEvent) {
|
||||
this.current = new aGesture(aTimeStamp, aPoints, aLastEvent); /* A constructor name should start with an uppercase letter. */ // jshint ignore:line
|
||||
this.current.then(this._onFulfill.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle the incoming pointer event with the existing gesture object.
|
||||
* @param {Object} aDetail A new pointer event detail.
|
||||
* @param {Number} aTimeStamp A new pointer event timeStamp.
|
||||
*/
|
||||
_update: function GestureTracker_update(aDetail, aTimeStamp) {
|
||||
this.current[aDetail.type](aDetail.points, aTimeStamp);
|
||||
},
|
||||
|
||||
/**
|
||||
* A resolution handler function for the current gesture promise.
|
||||
* @param {Object} aResult A resolution payload with the relevant gesture id
|
||||
* and an optional new gesture contructor.
|
||||
*/
|
||||
_onFulfill: function GestureTracker__onFulfill(aResult) {
|
||||
let {id, gestureType} = aResult;
|
||||
let current = this.current;
|
||||
// Do nothing if there's no existing gesture or there's already a newer
|
||||
// gesture.
|
||||
if (!current || current.id !== id) {
|
||||
return;
|
||||
}
|
||||
// Only create a gesture if we got a constructor.
|
||||
if (gestureType) {
|
||||
this._create(gestureType, current.startTime, current.points,
|
||||
current.lastEvent);
|
||||
} else {
|
||||
this.current.clearTimer();
|
||||
delete this.current;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Compile a mozAccessFuGesture detail structure.
|
||||
* @param {String} aType A gesture type.
|
||||
* @param {Object} aPoints Gesture's points.
|
||||
* @param {String} xKey A default key for the x coordinate. Default is
|
||||
* 'startX'.
|
||||
* @param {String} yKey A default key for the y coordinate. Default is
|
||||
* 'startY'.
|
||||
* @return {Object} a mozAccessFuGesture detail structure.
|
||||
*/
|
||||
function compileDetail(aType, aPoints, keyMap = {x: "startX", y: "startY"}) {
|
||||
let touches = [];
|
||||
let maxDeltaX = 0;
|
||||
let maxDeltaY = 0;
|
||||
for (let identifier in aPoints) {
|
||||
let point = aPoints[identifier];
|
||||
let touch = {};
|
||||
for (let key in keyMap) {
|
||||
touch[key] = point[keyMap[key]];
|
||||
}
|
||||
touches.push(touch);
|
||||
let deltaX = point.x - point.startX;
|
||||
let deltaY = point.y - point.startY;
|
||||
// Determine the maximum x and y travel intervals.
|
||||
if (Math.abs(maxDeltaX) < Math.abs(deltaX)) {
|
||||
maxDeltaX = deltaX;
|
||||
}
|
||||
if (Math.abs(maxDeltaY) < Math.abs(deltaY)) {
|
||||
maxDeltaY = deltaY;
|
||||
}
|
||||
// Since the gesture is resolving, reset the points' distance information
|
||||
// since they are passed to the next potential gesture.
|
||||
point.reset();
|
||||
}
|
||||
return {
|
||||
type: aType,
|
||||
touches,
|
||||
deltaX: maxDeltaX,
|
||||
deltaY: maxDeltaY
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A general gesture object.
|
||||
* @param {Number} aTimeStamp An original pointer event's timeStamp that started
|
||||
* the gesture resolution sequence.
|
||||
* @param {Object} aPoints An existing set of points (from previous events).
|
||||
* Default is an empty object.
|
||||
* @param {?String} aLastEvent Last pointer event type.
|
||||
*/
|
||||
function Gesture(aTimeStamp, aPoints = {}, aLastEvent = undefined) {
|
||||
this.startTime = Date.now();
|
||||
Logger.gesture("Creating", this.id, "gesture.");
|
||||
this.points = aPoints;
|
||||
this.lastEvent = aLastEvent;
|
||||
this._deferred = PromiseUtils.defer();
|
||||
// Call this._handleResolve or this._handleReject when the promise is
|
||||
// fulfilled with either resolve or reject.
|
||||
this.promise = this._deferred.promise.then(this._handleResolve.bind(this),
|
||||
this._handleReject.bind(this));
|
||||
this.startTimer(aTimeStamp);
|
||||
}
|
||||
|
||||
Gesture.prototype = {
|
||||
/**
|
||||
* Get the gesture timeout delay.
|
||||
* @return {Number}
|
||||
*/
|
||||
_getDelay: function Gesture__getDelay() {
|
||||
// If nothing happens withing the
|
||||
// GestureSettings.maxConsecutiveGestureDelay, we should not wait for any
|
||||
// more pointer events and consider them the part of the same gesture -
|
||||
// reject this gesture promise.
|
||||
return GestureSettings.maxConsecutiveGestureDelay;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear the existing timer.
|
||||
*/
|
||||
clearTimer: function Gesture_clearTimer() {
|
||||
Logger.gesture("clearTimeout", this.type);
|
||||
clearTimeout(this._timer);
|
||||
delete this._timer;
|
||||
},
|
||||
|
||||
/**
|
||||
* Start the timer for gesture timeout.
|
||||
* @param {Number} aTimeStamp An original pointer event's timeStamp that
|
||||
* started the gesture resolution sequence.
|
||||
*/
|
||||
startTimer: function Gesture_startTimer(aTimeStamp) {
|
||||
Logger.gesture("startTimer", this.type);
|
||||
this.clearTimer();
|
||||
let delay = this._getDelay(aTimeStamp);
|
||||
let handler = () => {
|
||||
Logger.gesture("timer handler");
|
||||
this.clearTimer();
|
||||
if (!this._inProgress) {
|
||||
this._deferred.reject();
|
||||
} else if (this._rejectToOnWait) {
|
||||
this._deferred.reject(this._rejectToOnWait);
|
||||
}
|
||||
};
|
||||
if (delay <= 0) {
|
||||
handler();
|
||||
} else {
|
||||
this._timer = setTimeout(handler, delay);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a gesture promise resolution callback.
|
||||
* @param {Function} aCallback
|
||||
*/
|
||||
then: function Gesture_then(aCallback) {
|
||||
this.promise.then(aCallback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Update gesture's points. Test the points set with the optional gesture test
|
||||
* function.
|
||||
* @param {Array} aPoints An array with the changed points from the new
|
||||
* pointer event.
|
||||
* @param {String} aType Pointer event type.
|
||||
* @param {Boolean} aCanCreate A flag that enables including the new points.
|
||||
* Default is false.
|
||||
* @param {Boolean} aNeedComplete A flag that indicates that the gesture is
|
||||
* completing. Default is false.
|
||||
* @return {Boolean} Indicates whether the gesture can be complete (it is
|
||||
* set to true iff the aNeedComplete is true and there was a change to at
|
||||
* least one point that belongs to the gesture).
|
||||
*/
|
||||
_update: function Gesture__update(aPoints, aType, aCanCreate = false, aNeedComplete = false) {
|
||||
let complete;
|
||||
let lastEvent;
|
||||
for (let point of aPoints) {
|
||||
let identifier = point.identifier;
|
||||
let gesturePoint = this.points[identifier];
|
||||
if (gesturePoint) {
|
||||
if (aType === "pointerdown" && aCanCreate) {
|
||||
// scratch the previous pointer with that id.
|
||||
this.points[identifier] = new Point(point);
|
||||
} else {
|
||||
gesturePoint.update(point);
|
||||
}
|
||||
if (aNeedComplete) {
|
||||
// Since the gesture is completing and at least one of the gesture
|
||||
// points is updated, set the return value to true.
|
||||
complete = true;
|
||||
}
|
||||
lastEvent = lastEvent || aType;
|
||||
} else if (aCanCreate) {
|
||||
// Only create a new point if aCanCreate is true.
|
||||
this.points[identifier] =
|
||||
new Point(point);
|
||||
lastEvent = lastEvent || aType;
|
||||
}
|
||||
}
|
||||
this.lastEvent = lastEvent || this.lastEvent;
|
||||
// If test function is defined test the points.
|
||||
if (this.test) {
|
||||
this.test(complete);
|
||||
}
|
||||
return complete;
|
||||
},
|
||||
|
||||
/**
|
||||
* Emit a mozAccessFuGesture (when the gesture is resolved).
|
||||
* @param {Object} aDetail a compiled mozAccessFuGesture detail structure.
|
||||
*/
|
||||
_emit: function Gesture__emit(aDetail) {
|
||||
let evt = new Utils.win.CustomEvent("mozAccessFuGesture", {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
detail: aDetail
|
||||
});
|
||||
Utils.win.dispatchEvent(evt);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle the pointer down event.
|
||||
* @param {Array} aPoints A new pointer down points.
|
||||
* @param {Number} aTimeStamp A new pointer down timeStamp.
|
||||
*/
|
||||
pointerdown: function Gesture_pointerdown(aPoints, aTimeStamp) {
|
||||
this._inProgress = true;
|
||||
this._update(aPoints, "pointerdown",
|
||||
aTimeStamp - this.startTime < GestureSettings.maxMultitouch);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle the pointer move event.
|
||||
* @param {Array} aPoints A new pointer move points.
|
||||
*/
|
||||
pointermove: function Gesture_pointermove(aPoints) {
|
||||
this._update(aPoints, "pointermove");
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle the pointer up event.
|
||||
* @param {Array} aPoints A new pointer up points.
|
||||
*/
|
||||
pointerup: function Gesture_pointerup(aPoints) {
|
||||
let complete = this._update(aPoints, "pointerup", false, true);
|
||||
if (complete) {
|
||||
this._deferred.resolve();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A subsequent gesture constructor to resolve the current one to. E.g.
|
||||
* tap->doubletap, dwell->dwellend, etc.
|
||||
* @type {Function}
|
||||
*/
|
||||
resolveTo: null,
|
||||
|
||||
/**
|
||||
* A unique id for the gesture. Composed of the type + timeStamp.
|
||||
*/
|
||||
get id() {
|
||||
delete this._id;
|
||||
this._id = this.type + this.startTime;
|
||||
return this._id;
|
||||
},
|
||||
|
||||
/**
|
||||
* A gesture promise resolve callback. Compile and emit the gesture.
|
||||
* @return {Object} Returns a structure to the gesture handler that looks like
|
||||
* this: {
|
||||
* id: current gesture id,
|
||||
* gestureType: an optional subsequent gesture constructor.
|
||||
* }
|
||||
*/
|
||||
_handleResolve: function Gesture__handleResolve() {
|
||||
if (this.isComplete) {
|
||||
return;
|
||||
}
|
||||
Logger.gesture("Resolving", this.id, "gesture.");
|
||||
this.isComplete = true;
|
||||
this.clearTimer();
|
||||
let detail = this.compile();
|
||||
if (detail) {
|
||||
this._emit(detail);
|
||||
}
|
||||
return {
|
||||
id: this.id,
|
||||
gestureType: this.resolveTo
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* A gesture promise reject callback.
|
||||
* @return {Object} Returns a structure to the gesture handler that looks like
|
||||
* this: {
|
||||
* id: current gesture id,
|
||||
* gestureType: an optional subsequent gesture constructor.
|
||||
* }
|
||||
*/
|
||||
_handleReject: function Gesture__handleReject(aRejectTo) {
|
||||
if (this.isComplete) {
|
||||
return;
|
||||
}
|
||||
Logger.gesture("Rejecting", this.id, "gesture.");
|
||||
this.isComplete = true;
|
||||
this.clearTimer();
|
||||
return {
|
||||
id: this.id,
|
||||
gestureType: aRejectTo
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* A default compilation function used to build the mozAccessFuGesture event
|
||||
* detail. The detail always includes the type and the touches associated
|
||||
* with the gesture.
|
||||
* @return {Object} Gesture event detail.
|
||||
*/
|
||||
compile: function Gesture_compile() {
|
||||
return compileDetail(this.type, this.points);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A mixin for an explore related object.
|
||||
*/
|
||||
function ExploreGesture() {
|
||||
this.compile = () => {
|
||||
// Unlike most of other gestures explore based gestures compile using the
|
||||
// current point position and not the start one.
|
||||
return compileDetail(this.type, this.points, {x: "x", y: "y"});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the in progress gesture for completion.
|
||||
*/
|
||||
function checkProgressGesture(aGesture) {
|
||||
aGesture._inProgress = true;
|
||||
if (aGesture.lastEvent === "pointerup") {
|
||||
if (aGesture.test) {
|
||||
aGesture.test(true);
|
||||
}
|
||||
aGesture._deferred.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A common travel gesture. When the travel gesture is created, all subsequent
|
||||
* pointer events' points are tested for their total distance traveled. If that
|
||||
* distance exceeds the _threshold distance, the gesture will be rejected to a
|
||||
* _travelTo gesture.
|
||||
* @param {Number} aTimeStamp An original pointer event's timeStamp that started
|
||||
* the gesture resolution sequence.
|
||||
* @param {Object} aPoints An existing set of points (from previous events).
|
||||
* @param {?String} aLastEvent Last pointer event type.
|
||||
* @param {Function} aTravelTo A contructor for the gesture to reject to when
|
||||
* travelling (default: Explore).
|
||||
* @param {Number} aThreshold Travel threshold (default:
|
||||
* GestureSettings.travelThreshold).
|
||||
*/
|
||||
function TravelGesture(aTimeStamp, aPoints, aLastEvent, aTravelTo = Explore, aThreshold = GestureSettings.travelThreshold) {
|
||||
Gesture.call(this, aTimeStamp, aPoints, aLastEvent);
|
||||
this._travelTo = aTravelTo;
|
||||
this._threshold = aThreshold;
|
||||
}
|
||||
|
||||
TravelGesture.prototype = Object.create(Gesture.prototype);
|
||||
|
||||
/**
|
||||
* Test the gesture points for travel. The gesture will be rejected to
|
||||
* this._travelTo gesture iff at least one point crosses this._threshold.
|
||||
*/
|
||||
TravelGesture.prototype.test = function TravelGesture_test() {
|
||||
if (!this._travelTo) {
|
||||
return;
|
||||
}
|
||||
for (let identifier in this.points) {
|
||||
let point = this.points[identifier];
|
||||
if (point.totalDistanceTraveled / Utils.dpi > this._threshold) {
|
||||
this._deferred.reject(this._travelTo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* DwellEnd gesture.
|
||||
* @param {Number} aTimeStamp An original pointer event's timeStamp that started
|
||||
* the gesture resolution sequence.
|
||||
* @param {Object} aPoints An existing set of points (from previous events).
|
||||
* @param {?String} aLastEvent Last pointer event type.
|
||||
*/
|
||||
function DwellEnd(aTimeStamp, aPoints, aLastEvent) {
|
||||
this._inProgress = true;
|
||||
// If the pointer travels, reject to Explore.
|
||||
TravelGesture.call(this, aTimeStamp, aPoints, aLastEvent);
|
||||
checkProgressGesture(this);
|
||||
}
|
||||
|
||||
DwellEnd.prototype = Object.create(TravelGesture.prototype);
|
||||
DwellEnd.prototype.type = "dwellend";
|
||||
|
||||
/**
|
||||
* TapHoldEnd gesture. This gesture can be represented as the following diagram:
|
||||
* pointerdown-pointerup-pointerdown-*wait*-pointerup.
|
||||
* @param {Number} aTimeStamp An original pointer event's timeStamp that started
|
||||
* the gesture resolution sequence.
|
||||
* @param {Object} aPoints An existing set of points (from previous events).
|
||||
* @param {?String} aLastEvent Last pointer event type.
|
||||
*/
|
||||
function TapHoldEnd(aTimeStamp, aPoints, aLastEvent) {
|
||||
this._inProgress = true;
|
||||
// If the pointer travels, reject to Explore.
|
||||
TravelGesture.call(this, aTimeStamp, aPoints, aLastEvent);
|
||||
checkProgressGesture(this);
|
||||
}
|
||||
|
||||
TapHoldEnd.prototype = Object.create(TravelGesture.prototype);
|
||||
TapHoldEnd.prototype.type = "tapholdend";
|
||||
|
||||
/**
|
||||
* DoubleTapHoldEnd gesture. This gesture can be represented as the following
|
||||
* diagram:
|
||||
* pointerdown-pointerup-pointerdown-pointerup-pointerdown-*wait*-pointerup.
|
||||
* @param {Number} aTimeStamp An original pointer event's timeStamp that started
|
||||
* the gesture resolution sequence.
|
||||
* @param {Object} aPoints An existing set of points (from previous events).
|
||||
* @param {?String} aLastEvent Last pointer event type.
|
||||
*/
|
||||
function DoubleTapHoldEnd(aTimeStamp, aPoints, aLastEvent) {
|
||||
this._inProgress = true;
|
||||
// If the pointer travels, reject to Explore.
|
||||
TravelGesture.call(this, aTimeStamp, aPoints, aLastEvent);
|
||||
checkProgressGesture(this);
|
||||
}
|
||||
|
||||
DoubleTapHoldEnd.prototype = Object.create(TravelGesture.prototype);
|
||||
DoubleTapHoldEnd.prototype.type = "doubletapholdend";
|
||||
|
||||
/**
|
||||
* A common tap gesture object.
|
||||
* @param {Number} aTimeStamp An original pointer event's timeStamp that started
|
||||
* the gesture resolution sequence.
|
||||
* @param {Object} aPoints An existing set of points (from previous events).
|
||||
* @param {?String} aLastEvent Last pointer event type.
|
||||
* @param {Function} aRejectToOnWait A constructor for the next gesture to
|
||||
* reject to in case no pointermove or pointerup happens within the
|
||||
* GestureSettings.dwellThreshold.
|
||||
* @param {Function} aTravelTo An optional constuctor for the next gesture to
|
||||
* reject to in case the the TravelGesture test fails.
|
||||
* @param {Function} aRejectToOnPointerDown A constructor for the gesture to
|
||||
* reject to if a finger comes down immediately after the tap.
|
||||
*/
|
||||
function TapGesture(aTimeStamp, aPoints, aLastEvent, aRejectToOnWait, aTravelTo, aRejectToOnPointerDown) {
|
||||
this._rejectToOnWait = aRejectToOnWait;
|
||||
this._rejectToOnPointerDown = aRejectToOnPointerDown;
|
||||
// If the pointer travels, reject to aTravelTo.
|
||||
TravelGesture.call(this, aTimeStamp, aPoints, aLastEvent, aTravelTo,
|
||||
TAP_MAX_RADIUS);
|
||||
}
|
||||
|
||||
TapGesture.prototype = Object.create(TravelGesture.prototype);
|
||||
TapGesture.prototype._getDelay = function TapGesture__getDelay() {
|
||||
// If, for TapGesture, no pointermove or pointerup happens within the
|
||||
// GestureSettings.dwellThreshold, reject.
|
||||
// Note: the original pointer event's timeStamp is irrelevant here.
|
||||
return GestureSettings.dwellThreshold;
|
||||
};
|
||||
|
||||
TapGesture.prototype.pointerup = function TapGesture_pointerup(aPoints) {
|
||||
if (this._rejectToOnPointerDown) {
|
||||
let complete = this._update(aPoints, "pointerup", false, true);
|
||||
if (complete) {
|
||||
this.clearTimer();
|
||||
if (GestureSettings.maxGestureResolveTimeout) {
|
||||
this._pointerUpTimer = setTimeout(() => {
|
||||
clearTimeout(this._pointerUpTimer);
|
||||
delete this._pointerUpTimer;
|
||||
this._deferred.resolve();
|
||||
}, GestureSettings.maxGestureResolveTimeout);
|
||||
} else {
|
||||
this._deferred.resolve();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TravelGesture.prototype.pointerup.call(this, aPoints);
|
||||
}
|
||||
};
|
||||
|
||||
TapGesture.prototype.pointerdown = function TapGesture_pointerdown(aPoints, aTimeStamp) {
|
||||
if (this._pointerUpTimer) {
|
||||
clearTimeout(this._pointerUpTimer);
|
||||
delete this._pointerUpTimer;
|
||||
this._deferred.reject(this._rejectToOnPointerDown);
|
||||
} else {
|
||||
TravelGesture.prototype.pointerdown.call(this, aPoints, aTimeStamp);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tap gesture.
|
||||
* @param {Number} aTimeStamp An original pointer event's timeStamp that started
|
||||
* the gesture resolution sequence.
|
||||
* @param {Object} aPoints An existing set of points (from previous events).
|
||||
* @param {?String} aLastEvent Last pointer event type.
|
||||
*/
|
||||
function Tap(aTimeStamp, aPoints, aLastEvent) {
|
||||
// If the pointer travels, reject to Swipe.
|
||||
TapGesture.call(this, aTimeStamp, aPoints, aLastEvent, Dwell, Swipe, DoubleTap);
|
||||
}
|
||||
|
||||
Tap.prototype = Object.create(TapGesture.prototype);
|
||||
Tap.prototype.type = "tap";
|
||||
|
||||
|
||||
/**
|
||||
* Double Tap gesture.
|
||||
* @param {Number} aTimeStamp An original pointer event's timeStamp that started
|
||||
* the gesture resolution sequence.
|
||||
* @param {Object} aPoints An existing set of points (from previous events).
|
||||
* @param {?String} aLastEvent Last pointer event type.
|
||||
*/
|
||||
function DoubleTap(aTimeStamp, aPoints, aLastEvent) {
|
||||
this._inProgress = true;
|
||||
TapGesture.call(this, aTimeStamp, aPoints, aLastEvent, TapHold, null, TripleTap);
|
||||
}
|
||||
|
||||
DoubleTap.prototype = Object.create(TapGesture.prototype);
|
||||
DoubleTap.prototype.type = "doubletap";
|
||||
|
||||
/**
|
||||
* Triple Tap gesture.
|
||||
* @param {Number} aTimeStamp An original pointer event's timeStamp that started
|
||||
* the gesture resolution sequence.
|
||||
* @param {Object} aPoints An existing set of points (from previous events).
|
||||
* @param {?String} aLastEvent Last pointer event type.
|
||||
*/
|
||||
function TripleTap(aTimeStamp, aPoints, aLastEvent) {
|
||||
this._inProgress = true;
|
||||
TapGesture.call(this, aTimeStamp, aPoints, aLastEvent, DoubleTapHold, null, null);
|
||||
}
|
||||
|
||||
TripleTap.prototype = Object.create(TapGesture.prototype);
|
||||
TripleTap.prototype.type = "tripletap";
|
||||
|
||||
/**
|
||||
* Common base object for gestures that are created as resolved.
|
||||
* @param {Number} aTimeStamp An original pointer event's timeStamp that started
|
||||
* the gesture resolution sequence.
|
||||
* @param {Object} aPoints An existing set of points (from previous events).
|
||||
* @param {?String} aLastEvent Last pointer event type.
|
||||
*/
|
||||
function ResolvedGesture(aTimeStamp, aPoints, aLastEvent) {
|
||||
Gesture.call(this, aTimeStamp, aPoints, aLastEvent);
|
||||
// Resolve the guesture right away.
|
||||
this._deferred.resolve();
|
||||
}
|
||||
|
||||
ResolvedGesture.prototype = Object.create(Gesture.prototype);
|
||||
|
||||
/**
|
||||
* Dwell gesture
|
||||
* @param {Number} aTimeStamp An original pointer event's timeStamp that started
|
||||
* the gesture resolution sequence.
|
||||
* @param {Object} aPoints An existing set of points (from previous events).
|
||||
* @param {?String} aLastEvent Last pointer event type.
|
||||
*/
|
||||
function Dwell(aTimeStamp, aPoints, aLastEvent) {
|
||||
ResolvedGesture.call(this, aTimeStamp, aPoints, aLastEvent);
|
||||
}
|
||||
|
||||
Dwell.prototype = Object.create(ResolvedGesture.prototype);
|
||||
Dwell.prototype.type = "dwell";
|
||||
Dwell.prototype.resolveTo = DwellEnd;
|
||||
|
||||
/**
|
||||
* TapHold gesture
|
||||
* @param {Number} aTimeStamp An original pointer event's timeStamp that started
|
||||
* the gesture resolution sequence.
|
||||
* @param {Object} aPoints An existing set of points (from previous events).
|
||||
* @param {?String} aLastEvent Last pointer event type.
|
||||
*/
|
||||
function TapHold(aTimeStamp, aPoints, aLastEvent) {
|
||||
ResolvedGesture.call(this, aTimeStamp, aPoints, aLastEvent);
|
||||
}
|
||||
|
||||
TapHold.prototype = Object.create(ResolvedGesture.prototype);
|
||||
TapHold.prototype.type = "taphold";
|
||||
TapHold.prototype.resolveTo = TapHoldEnd;
|
||||
|
||||
/**
|
||||
* DoubleTapHold gesture
|
||||
* @param {Number} aTimeStamp An original pointer event's timeStamp that started
|
||||
* the gesture resolution sequence.
|
||||
* @param {Object} aPoints An existing set of points (from previous events).
|
||||
* @param {?String} aLastEvent Last pointer event type.
|
||||
*/
|
||||
function DoubleTapHold(aTimeStamp, aPoints, aLastEvent) {
|
||||
ResolvedGesture.call(this, aTimeStamp, aPoints, aLastEvent);
|
||||
}
|
||||
|
||||
DoubleTapHold.prototype = Object.create(ResolvedGesture.prototype);
|
||||
DoubleTapHold.prototype.type = "doubletaphold";
|
||||
DoubleTapHold.prototype.resolveTo = DoubleTapHoldEnd;
|
||||
|
||||
/**
|
||||
* Explore gesture
|
||||
* @param {Number} aTimeStamp An original pointer event's timeStamp that started
|
||||
* the gesture resolution sequence.
|
||||
* @param {Object} aPoints An existing set of points (from previous events).
|
||||
* @param {?String} aLastEvent Last pointer event type.
|
||||
*/
|
||||
function Explore(aTimeStamp, aPoints, aLastEvent) {
|
||||
ExploreGesture.call(this);
|
||||
ResolvedGesture.call(this, aTimeStamp, aPoints, aLastEvent);
|
||||
}
|
||||
|
||||
Explore.prototype = Object.create(ResolvedGesture.prototype);
|
||||
Explore.prototype.type = "explore";
|
||||
Explore.prototype.resolveTo = ExploreEnd;
|
||||
|
||||
/**
|
||||
* ExploreEnd gesture.
|
||||
* @param {Number} aTimeStamp An original pointer event's timeStamp that started
|
||||
* the gesture resolution sequence.
|
||||
* @param {Object} aPoints An existing set of points (from previous events).
|
||||
* @param {?String} aLastEvent Last pointer event type.
|
||||
*/
|
||||
function ExploreEnd(aTimeStamp, aPoints, aLastEvent) {
|
||||
this._inProgress = true;
|
||||
ExploreGesture.call(this);
|
||||
// If the pointer travels, reject to Explore.
|
||||
TravelGesture.call(this, aTimeStamp, aPoints, aLastEvent);
|
||||
checkProgressGesture(this);
|
||||
}
|
||||
|
||||
ExploreEnd.prototype = Object.create(TravelGesture.prototype);
|
||||
ExploreEnd.prototype.type = "exploreend";
|
||||
|
||||
/**
|
||||
* Swipe gesture.
|
||||
* @param {Number} aTimeStamp An original pointer event's timeStamp that started
|
||||
* the gesture resolution sequence.
|
||||
* @param {Object} aPoints An existing set of points (from previous events).
|
||||
* @param {?String} aLastEvent Last pointer event type.
|
||||
*/
|
||||
function Swipe(aTimeStamp, aPoints, aLastEvent) {
|
||||
this._inProgress = true;
|
||||
this._rejectToOnWait = Explore;
|
||||
Gesture.call(this, aTimeStamp, aPoints, aLastEvent);
|
||||
checkProgressGesture(this);
|
||||
}
|
||||
|
||||
Swipe.prototype = Object.create(Gesture.prototype);
|
||||
Swipe.prototype.type = "swipe";
|
||||
Swipe.prototype._getDelay = function Swipe__getDelay(aTimeStamp) {
|
||||
// Swipe should be completed within the GestureSettings.swipeMaxDuration from
|
||||
// the initial pointer down event.
|
||||
return GestureSettings.swipeMaxDuration - this.startTime + aTimeStamp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine wither the gesture was Swipe or Explore.
|
||||
* @param {Booler} aComplete A flag that indicates whether the gesture is and
|
||||
* will be complete after the test.
|
||||
*/
|
||||
Swipe.prototype.test = function Swipe_test(aComplete) {
|
||||
if (!aComplete) {
|
||||
// No need to test if the gesture is not completing or can't be complete.
|
||||
return;
|
||||
}
|
||||
let reject = true;
|
||||
// If at least one point travelled for more than SWIPE_MIN_DISTANCE and it was
|
||||
// direct enough, consider it a Swipe.
|
||||
for (let identifier in this.points) {
|
||||
let point = this.points[identifier];
|
||||
let directDistance = point.directDistanceTraveled;
|
||||
if (directDistance / Utils.dpi >= SWIPE_MIN_DISTANCE ||
|
||||
directDistance * DIRECTNESS_COEFF >= point.totalDistanceTraveled) {
|
||||
reject = false;
|
||||
}
|
||||
}
|
||||
if (reject) {
|
||||
this._deferred.reject(Explore);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Compile a swipe related mozAccessFuGesture event detail.
|
||||
* @return {Object} A mozAccessFuGesture detail object.
|
||||
*/
|
||||
Swipe.prototype.compile = function Swipe_compile() {
|
||||
let type = this.type;
|
||||
let detail = compileDetail(type, this.points,
|
||||
{x1: "startX", y1: "startY", x2: "x", y2: "y"});
|
||||
let deltaX = detail.deltaX;
|
||||
let deltaY = detail.deltaY;
|
||||
let edge = EDGE * Utils.dpi;
|
||||
if (Math.abs(deltaX) > Math.abs(deltaY)) {
|
||||
// Horizontal swipe.
|
||||
let startPoints = detail.touches.map(touch => touch.x1);
|
||||
if (deltaX > 0) {
|
||||
detail.type = type + "right";
|
||||
detail.edge = Math.min.apply(null, startPoints) <= edge;
|
||||
} else {
|
||||
detail.type = type + "left";
|
||||
detail.edge =
|
||||
Utils.win.screen.width - Math.max.apply(null, startPoints) <= edge;
|
||||
}
|
||||
} else {
|
||||
// Vertical swipe.
|
||||
let startPoints = detail.touches.map(touch => touch.y1);
|
||||
if (deltaY > 0) {
|
||||
detail.type = type + "down";
|
||||
detail.edge = Math.min.apply(null, startPoints) <= edge;
|
||||
} else {
|
||||
detail.type = type + "up";
|
||||
detail.edge =
|
||||
Utils.win.screen.height - Math.max.apply(null, startPoints) <= edge;
|
||||
}
|
||||
}
|
||||
return detail;
|
||||
};
|
@ -1,158 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* exported PointerRelay, PointerAdapter */
|
||||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["PointerRelay", "PointerAdapter"]; // jshint ignore:line
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Utils", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Utils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Logger", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Utils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "GestureSettings", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Gestures.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "GestureTracker", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Gestures.jsm");
|
||||
|
||||
// The virtual touch ID generated by a mouse event.
|
||||
const MOUSE_ID = "mouse";
|
||||
// Synthesized touch ID.
|
||||
const SYNTH_ID = -1;
|
||||
|
||||
var PointerRelay = { // jshint ignore:line
|
||||
/**
|
||||
* A mapping of events we should be intercepting. Entries with a value of
|
||||
* |true| are used for compiling high-level gesture events. Entries with a
|
||||
* value of |false| are cancelled and do not propogate to content.
|
||||
*/
|
||||
get _eventsOfInterest() {
|
||||
delete this._eventsOfInterest;
|
||||
|
||||
switch (Utils.widgetToolkit) {
|
||||
case "android":
|
||||
this._eventsOfInterest = {
|
||||
"touchstart": true,
|
||||
"touchmove": true,
|
||||
"touchend": true };
|
||||
break;
|
||||
|
||||
default:
|
||||
// Desktop.
|
||||
this._eventsOfInterest = {
|
||||
"mousemove": true,
|
||||
"mousedown": true,
|
||||
"mouseup": true,
|
||||
"click": false
|
||||
};
|
||||
if ("ontouchstart" in Utils.win) {
|
||||
for (let eventType of ["touchstart", "touchmove", "touchend"]) {
|
||||
this._eventsOfInterest[eventType] = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return this._eventsOfInterest;
|
||||
},
|
||||
|
||||
_eventMap: {
|
||||
"touchstart": "pointerdown",
|
||||
"mousedown": "pointerdown",
|
||||
"touchmove": "pointermove",
|
||||
"mousemove": "pointermove",
|
||||
"touchend": "pointerup",
|
||||
"mouseup": "pointerup"
|
||||
},
|
||||
|
||||
start: function PointerRelay_start(aOnPointerEvent) {
|
||||
Logger.debug("PointerRelay.start");
|
||||
this.onPointerEvent = aOnPointerEvent;
|
||||
for (let eventType in this._eventsOfInterest) {
|
||||
Utils.win.addEventListener(eventType, this, true, true);
|
||||
}
|
||||
},
|
||||
|
||||
stop: function PointerRelay_stop() {
|
||||
Logger.debug("PointerRelay.stop");
|
||||
delete this.lastPointerMove;
|
||||
delete this.onPointerEvent;
|
||||
for (let eventType in this._eventsOfInterest) {
|
||||
Utils.win.removeEventListener(eventType, this, true, true);
|
||||
}
|
||||
},
|
||||
|
||||
handleEvent: function PointerRelay_handleEvent(aEvent) {
|
||||
// Don't bother with chrome mouse events.
|
||||
if (Utils.MozBuildApp === "browser" && aEvent.view.top.isChromeWindow) {
|
||||
return;
|
||||
}
|
||||
// aEvent might not be a mouse event here at all; don't do the
|
||||
// mozInputSource check unless it is.
|
||||
if (("mozInputSource" in aEvent &&
|
||||
aEvent.mozInputSource === aEvent.MOZ_SOURCE_UNKNOWN) ||
|
||||
aEvent.isSynthesized) {
|
||||
// Ignore events that are scripted or clicks from the a11y API.
|
||||
return;
|
||||
}
|
||||
|
||||
let changedTouches = aEvent.changedTouches || [{
|
||||
identifier: MOUSE_ID,
|
||||
screenX: aEvent.screenX,
|
||||
screenY: aEvent.screenY,
|
||||
target: aEvent.target
|
||||
}];
|
||||
|
||||
if (Utils.widgetToolkit === "android" &&
|
||||
changedTouches.length === 1 && changedTouches[0].identifier === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (changedTouches.length === 1 &&
|
||||
changedTouches[0].identifier === SYNTH_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
aEvent.preventDefault();
|
||||
aEvent.stopImmediatePropagation();
|
||||
|
||||
let type = aEvent.type;
|
||||
if (!this._eventsOfInterest[type]) {
|
||||
return;
|
||||
}
|
||||
let pointerType = this._eventMap[type];
|
||||
this.onPointerEvent({
|
||||
type: pointerType,
|
||||
points: Array.prototype.map.call(changedTouches,
|
||||
function mapTouch(aTouch) {
|
||||
return {
|
||||
identifier: aTouch.identifier,
|
||||
x: aTouch.screenX,
|
||||
y: aTouch.screenY
|
||||
};
|
||||
}
|
||||
)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var PointerAdapter = { // jshint ignore:line
|
||||
start: function PointerAdapter_start() {
|
||||
Logger.debug("PointerAdapter.start");
|
||||
GestureTracker.reset();
|
||||
PointerRelay.start(this.handleEvent);
|
||||
},
|
||||
|
||||
stop: function PointerAdapter_stop() {
|
||||
Logger.debug("PointerAdapter.stop");
|
||||
PointerRelay.stop();
|
||||
GestureTracker.reset();
|
||||
},
|
||||
|
||||
handleEvent: function PointerAdapter_handleEvent(aDetail) {
|
||||
let timeStamp = Date.now();
|
||||
GestureTracker.handle(aDetail, timeStamp);
|
||||
}
|
||||
};
|
@ -9,12 +9,10 @@ EXTRA_JS_MODULES.accessibility += [
|
||||
'Constants.jsm',
|
||||
'ContentControl.jsm',
|
||||
'EventManager.jsm',
|
||||
'Gestures.jsm',
|
||||
'OutputGenerator.jsm',
|
||||
'PointerAdapter.jsm',
|
||||
'Presentation.jsm',
|
||||
'Traversal.jsm',
|
||||
'Utils.jsm'
|
||||
]
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
@ -1,7 +1,5 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
dom_helper.js
|
||||
gestures.json
|
||||
jsatcommon.js
|
||||
output.js
|
||||
doc_traversal.html
|
||||
@ -17,14 +15,11 @@ skip-if = buildapp == 'mulet'
|
||||
[test_content_text.html]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[test_explicit_names.html]
|
||||
[test_gesture_tracker.html]
|
||||
[test_hints.html]
|
||||
[test_landmarks.html]
|
||||
[test_live_regions.html]
|
||||
[test_output_mathml.html]
|
||||
[test_output.html]
|
||||
[test_quicknav_modes.html]
|
||||
[test_tables.html]
|
||||
[test_pointer_relay.html]
|
||||
[test_traversal.html]
|
||||
[test_traversal_helper.html]
|
||||
|
@ -1,204 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
/* exported loadJSON, eventMap */
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Geometry.jsm");
|
||||
|
||||
var win = getMainChromeWindow(window);
|
||||
|
||||
/**
|
||||
* Convert inch based point coordinates into pixels.
|
||||
* @param {Array} aPoints Array of coordinates in inches.
|
||||
* @return {Array} Array of coordinates in pixels.
|
||||
*/
|
||||
function convertPointCoordinates(aPoints) {
|
||||
var dpi = Utils.dpi;
|
||||
return aPoints.map(function convert(aPoint) {
|
||||
return {
|
||||
x: aPoint.x * dpi,
|
||||
y: aPoint.y * dpi,
|
||||
identifier: aPoint.identifier
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given list of points calculate their coordinates in relation to the
|
||||
* document body.
|
||||
* @param {Array} aTouchPoints An array of objects of the following format: {
|
||||
* base: {String}, // Id of an element to server as a base for the touch.
|
||||
* x: {Number}, // An optional x offset from the base element's geometric
|
||||
* // centre.
|
||||
* y: {Number} // An optional y offset from the base element's geometric
|
||||
* // centre.
|
||||
* }
|
||||
* @return {JSON} An array of {x, y} coordinations.
|
||||
*/
|
||||
function calculateTouchListCoordinates(aTouchPoints) {
|
||||
var coords = [];
|
||||
for (var i = 0, target = aTouchPoints[i]; i < aTouchPoints.length; ++i) {
|
||||
var bounds = getBoundsForDOMElm(target.base);
|
||||
var parentBounds = getBoundsForDOMElm("root");
|
||||
var point = new Point(target.x || 0, target.y || 0);
|
||||
point.scale(Utils.dpi);
|
||||
point.add(bounds[0], bounds[1]);
|
||||
point.add(bounds[2] / 2, bounds[3] / 2);
|
||||
point.subtract(parentBounds[0], parentBounds[0]);
|
||||
coords.push({
|
||||
x: point.x,
|
||||
y: point.y
|
||||
});
|
||||
}
|
||||
return coords;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a touch event with specified touchPoints.
|
||||
* @param {Array} aTouchPoints An array of points to be associated with
|
||||
* touches.
|
||||
* @param {String} aName A name of the touch event.
|
||||
*/
|
||||
function sendTouchEvent(aTouchPoints, aName) {
|
||||
var touchList = sendTouchEvent.touchList;
|
||||
if (aName === "touchend") {
|
||||
sendTouchEvent.touchList = null;
|
||||
} else {
|
||||
var coords = calculateTouchListCoordinates(aTouchPoints);
|
||||
var touches = [];
|
||||
for (var i = 0; i < coords.length; ++i) {
|
||||
var {x, y} = coords[i];
|
||||
var node = document.elementFromPoint(x, y);
|
||||
var touch = document.createTouch(window, node, aName === "touchstart" ?
|
||||
1 : touchList.item(i).identifier, x, y, x, y);
|
||||
touches.push(touch);
|
||||
}
|
||||
touchList = document.createTouchList(touches);
|
||||
sendTouchEvent.touchList = touchList;
|
||||
}
|
||||
var evt = document.createEvent("TouchEvent");
|
||||
evt.initTouchEvent(aName, true, true, window, 0, false, false, false, false,
|
||||
touchList, touchList, touchList);
|
||||
document.dispatchEvent(evt);
|
||||
}
|
||||
|
||||
sendTouchEvent.touchList = null;
|
||||
|
||||
/**
|
||||
* A map of event names to the functions that actually send them.
|
||||
* @type {Object}
|
||||
*/
|
||||
var eventMap = {
|
||||
touchstart: sendTouchEvent,
|
||||
touchend: sendTouchEvent,
|
||||
touchmove: sendTouchEvent
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach a listener for the mozAccessFuGesture event that tests its
|
||||
* type.
|
||||
* @param {Array} aExpectedGestures A stack of expected event types.
|
||||
* @param {String} aTitle Title of this sequence, if any.
|
||||
* Note: the listener is removed once the stack reaches 0.
|
||||
*/
|
||||
function testMozAccessFuGesture(aExpectedGestures, aTitle) {
|
||||
var types = aExpectedGestures;
|
||||
function handleGesture(aEvent) {
|
||||
if (aEvent.detail.type !== types[0].type) {
|
||||
info("Got " + aEvent.detail.type + " waiting for " + types[0].type);
|
||||
// The is not the event of interest.
|
||||
return;
|
||||
}
|
||||
is(!!aEvent.detail.edge, !!types[0].edge);
|
||||
is(aEvent.detail.touches.length, types[0].fingers || 1,
|
||||
"failed to count fingers: " + types[0].type);
|
||||
ok(true, "Received correct mozAccessFuGesture: " +
|
||||
JSON.stringify(types.shift()) + ". (" + aTitle + ")");
|
||||
if (types.length === 0) {
|
||||
win.removeEventListener("mozAccessFuGesture", handleGesture);
|
||||
if (AccessFuTest.sequenceCleanup) {
|
||||
AccessFuTest.sequenceCleanup();
|
||||
}
|
||||
AccessFuTest.nextTest();
|
||||
}
|
||||
}
|
||||
win.addEventListener("mozAccessFuGesture", handleGesture);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the thresholds and max delays that affect gesture rejection.
|
||||
* @param {Number} aTimeStamp Gesture time stamp.
|
||||
* @param {Boolean} aRemoveDwellThreshold An optional flag to reset dwell
|
||||
* threshold.
|
||||
* @param {Boolean} aRemoveSwipeMaxDuration An optional flag to reset swipe max
|
||||
* duration.
|
||||
*/
|
||||
function setTimers(aTimeStamp, aRemoveDwellThreshold, aRemoveSwipeMaxDuration) {
|
||||
if (!aRemoveDwellThreshold && !aRemoveSwipeMaxDuration) {
|
||||
return;
|
||||
}
|
||||
if (aRemoveDwellThreshold) {
|
||||
GestureSettings.dwellThreshold = 0;
|
||||
}
|
||||
if (aRemoveSwipeMaxDuration) {
|
||||
GestureSettings.swipeMaxDuration = 0;
|
||||
}
|
||||
GestureTracker.current.clearTimer();
|
||||
GestureTracker.current.startTimer(aTimeStamp);
|
||||
}
|
||||
|
||||
function resetTimers(aRemoveGestureResolveDelay) {
|
||||
GestureSettings.dwellThreshold = AccessFuTest.dwellThreshold;
|
||||
GestureSettings.swipeMaxDuration = AccessFuTest.swipeMaxDuration;
|
||||
GestureSettings.maxGestureResolveTimeout = aRemoveGestureResolveDelay ?
|
||||
0 : AccessFuTest.maxGestureResolveTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* An extention to AccessFuTest that adds an ability to test a sequence of
|
||||
* pointer events and their expected mozAccessFuGesture events.
|
||||
* @param {Object} aSequence An object that has a list of pointer events to be
|
||||
* generated and the expected mozAccessFuGesture events.
|
||||
*/
|
||||
AccessFuTest.addSequence = function AccessFuTest_addSequence(aSequence) {
|
||||
AccessFuTest.addFunc(function testSequence() {
|
||||
testMozAccessFuGesture(aSequence.expectedGestures, aSequence.title);
|
||||
var events = aSequence.events;
|
||||
function fireEvent(aEvent) {
|
||||
var event = {
|
||||
points: convertPointCoordinates(aEvent.points),
|
||||
type: aEvent.type
|
||||
};
|
||||
var timeStamp = Date.now();
|
||||
resetTimers(aEvent.removeGestureResolveDelay);
|
||||
GestureTracker.handle(event, timeStamp);
|
||||
setTimers(timeStamp, aEvent.removeDwellThreshold,
|
||||
aEvent.removeSwipeMaxDuration);
|
||||
processEvents();
|
||||
}
|
||||
function processEvents() {
|
||||
if (events.length === 0) {
|
||||
return;
|
||||
}
|
||||
var event = events.shift();
|
||||
SimpleTest.executeSoon(function() {
|
||||
fireEvent(event);
|
||||
});
|
||||
}
|
||||
processEvents();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* A helper function that loads JSON files.
|
||||
* @param {String} aPath A path to a JSON file.
|
||||
* @param {Function} aCallback A callback to be called on success.
|
||||
*/
|
||||
function loadJSON(aPath, aCallback) {
|
||||
var request = new XMLHttpRequest();
|
||||
request.open("GET", aPath, true);
|
||||
request.responseType = "json";
|
||||
request.onload = function onload() {
|
||||
aCallback(request.response);
|
||||
};
|
||||
request.send();
|
||||
}
|
@ -1,352 +0,0 @@
|
||||
[
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}],
|
||||
"removeGestureResolveDelay": true }
|
||||
],
|
||||
"expectedGestures": [{ "type": "tap" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"x": 1.03, "y": 1.03, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1.03, "y": 1.03, "identifier": 1}],
|
||||
"removeGestureResolveDelay": true }
|
||||
],
|
||||
"expectedGestures": [{ "type": "tap" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}],
|
||||
"removeDwellThreshold": true},
|
||||
{"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "dwell" }, { "type": "dwellend" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"x": 1.03, "y": 1.02, "identifier": 1}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"x": 1.03, "y": 1.02, "identifier": 1}]},
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"x": 0.97, "y": 1.01, "identifier": 1}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"x": 0.97, "y": 1.01, "identifier": 1}],
|
||||
"removeGestureResolveDelay": true }
|
||||
],
|
||||
"expectedGestures": [{ "type": "doubletap" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}],
|
||||
"removeGestureResolveDelay": true }
|
||||
],
|
||||
"expectedGestures": [{ "type": "tripletap" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}],
|
||||
"removeDwellThreshold": true},
|
||||
{"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "doubletaphold" },
|
||||
{ "type": "doubletapholdend" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}],
|
||||
"removeDwellThreshold": true},
|
||||
{"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "taphold" }, { "type": "tapholdend" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "swiperight" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointermove", "points": [{"x": 1.15, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointermove", "points": [{"x": 1.3, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1.3, "y": 1, "identifier": 1}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "swiperight" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1.5, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "swipeleft" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointermove", "points": [{"x": 1, "y": 1.5, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1, "y": 1.5, "identifier": 1}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "swipedown" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1.5, "identifier": 1}]},
|
||||
{"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "swipeup" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"x": 1.5, "y": 1.1, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1.5, "y": 1.1, "identifier": 1}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "swiperight" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown",
|
||||
"points": [{"x": 1.5, "y": 1.1, "identifier": 1}]},
|
||||
{"type": "pointermove", "points": [{"x": 1, "y": 0.95, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1, "y": 0.95, "identifier": 1}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "swipeleft" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"x": 0.9, "y": 1.5, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 0.9, "y": 1.5, "identifier": 1}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "swipedown" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown",
|
||||
"points": [{"x": 1.1, "y": 1.5, "identifier": 1}]},
|
||||
{"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "swipeup" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1},
|
||||
{"x": 1, "y": 1.5, "identifier": 2}]},
|
||||
{"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1},
|
||||
{"x": 1.5, "y": 1.5, "identifier": 2}]},
|
||||
{"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1},
|
||||
{"x": 1.5, "y": 1.5, "identifier": 2}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "swiperight", "fingers": 2 }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1},
|
||||
{"x": 1, "y": 1.5, "identifier": 2}]},
|
||||
{"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1},
|
||||
{"x": 1.5, "y": 1.5, "identifier": 2}]},
|
||||
{"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1.5, "y": 1.5, "identifier": 2}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "swiperight", "fingers": 2 }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1},
|
||||
{"x": 1, "y": 1.5, "identifier": 2},
|
||||
{"x": 1, "y": 2, "identifier": 3}]},
|
||||
{"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1},
|
||||
{"x": 1.5, "y": 1.5, "identifier": 2},
|
||||
{"x": 1.5, "y": 2, "identifier": 3}]},
|
||||
{"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1},
|
||||
{"x": 1.5, "y": 1.5, "identifier": 2},
|
||||
{"x": 1.5, "y": 2, "identifier": 3}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "swiperight", "fingers": 3 }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown",
|
||||
"points": [{"x": 1.6, "y": 1.5, "identifier": 1}],
|
||||
"removeDwellThreshold": true},
|
||||
{"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "dwell" }, { "type": "explore" },
|
||||
{ "type": "exploreend" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown",
|
||||
"points": [{"x": 1.6, "y": 1.5, "identifier": 1}],
|
||||
"removeDwellThreshold": true},
|
||||
{"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointermove", "points": [{"x": 2, "y": 2, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 2, "y": 2, "identifier": 1}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "dwell" }, { "type": "explore" },
|
||||
{ "type": "explore" }, { "type": "exploreend" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown",
|
||||
"points": [{"x": 1.6, "y": 1.5, "identifier": 1}]},
|
||||
{"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}],
|
||||
"removeSwipeMaxDuration": true},
|
||||
{"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "explore" }, { "type": "exploreend" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1.5, "identifier": 1}]},
|
||||
{"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}],
|
||||
"removeSwipeMaxDuration": true},
|
||||
{"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "explore" }, { "type": "explore" },
|
||||
{ "type": "exploreend" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}],
|
||||
"removeDwellThreshold": true},
|
||||
{"type": "pointermove",
|
||||
"points": [{"x": 1.5, "y": 1.5, "identifier": 1}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"x": 1.55, "y": 1.5, "identifier": 1}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"x": 1.6, "y": 1.5, "identifier": 1}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"x": 1.65, "y": 1.5, "identifier": 1}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"x": 1.7, "y": 1.5, "identifier": 1}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"x": 1.75, "y": 1.5, "identifier": 1}]},
|
||||
{"type": "pointerup", "points": [{"x": 1.75, "y": 1.5, "identifier": 1}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "dwell" }, { "type": "explore" },
|
||||
{ "type": "explore" }, { "type": "exploreend" }]
|
||||
},
|
||||
{
|
||||
"events": [
|
||||
{"type": "pointerdown", "points": [{"x": 0.075, "y": 1, "identifier": 1},
|
||||
{"x": 1, "y": 1.5, "identifier": 2}]},
|
||||
{"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1},
|
||||
{"x": 1.5, "y": 1.5, "identifier": 2}]},
|
||||
{"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1},
|
||||
{"x": 1.5, "y": 1.5, "identifier": 2}]}
|
||||
],
|
||||
"expectedGestures": [{ "type": "swiperight", "edge": true, "fingers": 2 }]
|
||||
},
|
||||
{
|
||||
"title": "Bug 1182311 - 3 finger triple tap is not reliable 1/2",
|
||||
"events": [
|
||||
{"points": [
|
||||
{"y": 1.88467, "x": 0.89311, "identifier": 0},
|
||||
{"y": 2.78481, "x": 0.56259, "identifier": 1},
|
||||
{"y": 1.35021, "x": 1.37834, "identifier": 2}], "type": "pointerdown"},
|
||||
{"points": [
|
||||
{"y": 1.88467, "x": 0.89311, "identifier": 0},
|
||||
{"y": 2.78481, "x": 0.56259, "identifier": 1},
|
||||
{"y": 1.35021, "x": 1.37834, "identifier": 2}], "type": "pointerup"},
|
||||
{"points": [
|
||||
{"y": 1.76512, "x": 0.98453, "identifier": 0},
|
||||
{"y": 1.1744, "x": 1.4346, "identifier": 1},
|
||||
{"y": 2.5879, "x": 0.61181, "identifier": 2}], "type": "pointerdown"},
|
||||
{"points": [
|
||||
{"y": 1.76512, "x": 0.98453, "identifier": 0},
|
||||
{"y": 1.1744, "x": 1.4346, "identifier": 1},
|
||||
{"y": 2.5879, "x": 0.61181, "identifier": 2}], "type": "pointerup"},
|
||||
{"points": [
|
||||
{"y": 1.30098, "x": 1.52602, "identifier": 0},
|
||||
{"y": 1.94093, "x": 1.02672, "identifier": 1},
|
||||
{"y": 2.67229, "x": 0.75246, "identifier": 2}], "type": "pointerdown"},
|
||||
{"points": [
|
||||
{"y": 1.30098, "x": 1.52602, "identifier": 0},
|
||||
{"y": 1.94093, "x": 1.02672, "identifier": 1},
|
||||
{"y": 2.67229, "x": 0.75246, "identifier": 2}], "type": "pointerup",
|
||||
"removeGestureResolveDelay": true}],
|
||||
"expectedGestures": [{ "type": "tripletap", "fingers": 3 }]
|
||||
},
|
||||
{
|
||||
"title": "Bug 1182311 - 3 finger triple tap is not reliable 2/2",
|
||||
"events": [
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 0, "x": 2.21875, "y": 1.510417}]},
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 1, "x": 1.479167, "y": 2.53125}]},
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 2, "x": 1.072917, "y": 3.739583}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"identifier": 1, "x": 1.46875, "y": 2.53125}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"identifier": 1, "x": 1.447917, "y": 2.46875}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"identifier": 0, "x": 2.21875, "y": 1.510417}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"identifier": 1, "x": 1.447917, "y": 2.489583}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"identifier": 2, "x": 1.072917, "y": 3.739583}]},
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 0, "x": 2.114583, "y": 1.572917}]},
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 1, "x": 1.364583, "y": 2.614583}]},
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 2, "x": 0.927083, "y": 3.864583}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"identifier": 1, "x": 1.364583, "y": 2.614583}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"identifier": 0, "x": 2.114583, "y": 1.572917}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"identifier": 1, "x": 1.364583, "y": 2.614583}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"identifier": 2, "x": 0.927083, "y": 3.864583}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"identifier": 0, "x": 2.114583, "y": 1.572917}]},
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 0, "x": 1.4375, "y": 2.59375}]},
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 1, "x": 1.083333, "y": 3.71875}]},
|
||||
{"type": "pointerdown",
|
||||
"points": [{"identifier": 2, "x": 2.15625, "y": 1.489583}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"identifier": 0, "x": 1.4375, "y": 2.59375},
|
||||
{"identifier": 2, "x": 2.15625, "y": 1.489583}]},
|
||||
{"type": "pointermove",
|
||||
"points": [{"identifier": 0, "x": 1.4375, "y": 2.59375},
|
||||
{"identifier": 2, "x": 2.15625, "y": 1.489583}]},
|
||||
{"type": "pointerup",
|
||||
"points": [{"identifier": 1, "x": 1.083333, "y": 3.71875}],
|
||||
"removeGestureResolveDelay": true}
|
||||
],
|
||||
"expectedGestures": [{ "type": "tripletap", "fingers": 3 }]
|
||||
}
|
||||
|
||||
]
|
@ -17,7 +17,6 @@ var gIterator;
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/accessibility/EventManager.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/accessibility/Gestures.jsm");
|
||||
|
||||
var AccessFuTest = {
|
||||
|
||||
@ -99,14 +98,6 @@ var AccessFuTest = {
|
||||
// Disable the console service logging.
|
||||
Logger.test = false;
|
||||
Logger.logLevel = Logger.INFO;
|
||||
// Reset Gesture Settings.
|
||||
GestureSettings.dwellThreshold = this.dwellThreshold =
|
||||
this.originalDwellThreshold;
|
||||
GestureSettings.swipeMaxDuration = this.swipeMaxDuration =
|
||||
this.originalSwipeMaxDuration;
|
||||
GestureSettings.maxGestureResolveTimeout =
|
||||
this.maxGestureResolveTimeout =
|
||||
this.originalMaxGestureResolveTimeout;
|
||||
// Finish through idle callback to let AccessFu._disable complete.
|
||||
SimpleTest.executeSoon(function() {
|
||||
AccessFu.detach();
|
||||
@ -158,20 +149,6 @@ var AccessFuTest = {
|
||||
var prefs = [["accessibility.accessfu.notify_output", 1]];
|
||||
prefs.push.apply(prefs, aAdditionalPrefs);
|
||||
|
||||
this.originalDwellThreshold = GestureSettings.dwellThreshold;
|
||||
this.originalSwipeMaxDuration = GestureSettings.swipeMaxDuration;
|
||||
this.originalMaxGestureResolveTimeout =
|
||||
GestureSettings.maxGestureResolveTimeout;
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1001945 - sometimes
|
||||
// SimpleTest.executeSoon timeout is bigger than the timer settings in
|
||||
// GestureSettings that causes intermittents.
|
||||
this.dwellThreshold = GestureSettings.dwellThreshold =
|
||||
GestureSettings.dwellThreshold * 10;
|
||||
this.swipeMaxDuration = GestureSettings.swipeMaxDuration =
|
||||
GestureSettings.swipeMaxDuration * 10;
|
||||
this.maxGestureResolveTimeout = GestureSettings.maxGestureResolveTimeout =
|
||||
GestureSettings.maxGestureResolveTimeout * 10;
|
||||
|
||||
SpecialPowers.pushPrefEnv({ "set": prefs }, function() {
|
||||
if (AccessFuTest._waitForExplicitFinish) {
|
||||
// Run all test functions asynchronously.
|
||||
|
@ -1,51 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>AccessFu tests for gesture tracker.</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="../common.js"></script>
|
||||
<script type="application/javascript" src="../layout.js"></script>
|
||||
<script type="application/javascript" src="./jsatcommon.js"></script>
|
||||
<script type="application/javascript" src="./dom_helper.js"></script>
|
||||
<script type="application/javascript">
|
||||
|
||||
function startGestureTracker() {
|
||||
GestureTracker.reset();
|
||||
AccessFuTest.nextTest();
|
||||
}
|
||||
|
||||
function stopGestureTracker() {
|
||||
GestureTracker.reset();
|
||||
AccessFuTest.finish();
|
||||
}
|
||||
|
||||
function doTest() {
|
||||
loadJSON("./gestures.json", function onSuccess(gestures) {
|
||||
AccessFuTest.addFunc(startGestureTracker);
|
||||
AccessFuTest.sequenceCleanup = GestureTracker.reset.bind(
|
||||
GestureTracker);
|
||||
gestures.forEach(AccessFuTest.addSequence);
|
||||
AccessFuTest.addFunc(stopGestureTracker);
|
||||
AccessFuTest.waitForExplicitFinish();
|
||||
Logger.logLevel = Logger.GESTURE;
|
||||
AccessFuTest.runTests();
|
||||
});
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=981015"
|
||||
title="AccessFu tests for gesture tracker.">
|
||||
Mozilla Bug 981015
|
||||
</a>
|
||||
</body>
|
||||
</html>
|
@ -1,95 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>AccessFu tests for pointer relay.</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="../common.js"></script>
|
||||
<script type="application/javascript" src="../layout.js"></script>
|
||||
<script type="application/javascript" src="./jsatcommon.js"></script>
|
||||
<script type="application/javascript" src="./dom_helper.js"></script>
|
||||
<script type="application/javascript">
|
||||
|
||||
ChromeUtils.import(
|
||||
"resource://gre/modules/accessibility/PointerAdapter.jsm");
|
||||
|
||||
var tests = [
|
||||
{
|
||||
type: "touchstart", target: [{base: "button"}],
|
||||
expected: {type: "pointerdown", length: 1}
|
||||
},
|
||||
{
|
||||
type: "touchmove", target: [{base: "button"}],
|
||||
expected: {type: "pointermove", length: 1}
|
||||
},
|
||||
{
|
||||
type: "touchend", target: [{base: "button"}],
|
||||
expected: {type: "pointerup"}
|
||||
},
|
||||
{
|
||||
type: "touchstart", target: [{base: "button"},
|
||||
{base: "button", x: 0.5, y: 0.3}],
|
||||
expected: {type: "pointerdown", length: 2}
|
||||
},
|
||||
{
|
||||
type: "touchend", target: [{base: "button"},
|
||||
{base: "button", x: 0.5, y: 0.3}],
|
||||
expected: {type: "pointerup"}
|
||||
},
|
||||
{
|
||||
type: "touchstart", target: [{base: "button"},
|
||||
{base: "button", x: 0.5, y: 0.3},
|
||||
{base: "button", x: 0.5, y: -0.3}],
|
||||
expected: {type: "pointerdown", length: 3}
|
||||
},
|
||||
{
|
||||
type: "touchend", target: [{base: "button"},
|
||||
{base: "button", x: 0.5, y: 0.3},
|
||||
{base: "button", x: 0.5, y: -0.3}],
|
||||
expected: {type: "pointerup"}
|
||||
}
|
||||
];
|
||||
|
||||
function makeTestFromSpec(test) {
|
||||
return function runTest() {
|
||||
PointerRelay.start(function onPointerEvent(aDetail) {
|
||||
is(aDetail.type, test.expected.type,
|
||||
"mozAccessFuPointerEvent is correct.");
|
||||
if (test.expected.length) {
|
||||
is(aDetail.points.length, test.expected.length,
|
||||
"mozAccessFuPointerEvent points length is correct.");
|
||||
}
|
||||
PointerRelay.stop();
|
||||
AccessFuTest.nextTest();
|
||||
});
|
||||
eventMap[test.type](test.target, test.type);
|
||||
};
|
||||
}
|
||||
|
||||
function doTest() {
|
||||
tests.forEach(function addTest(test) {
|
||||
AccessFuTest.addFunc(makeTestFromSpec(test));
|
||||
});
|
||||
AccessFuTest.waitForExplicitFinish();
|
||||
AccessFuTest.runTests();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body id="root">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=976082"
|
||||
title="[AccessFu] Provide tests for pointer relay.">
|
||||
Mozilla Bug 981015
|
||||
</a>
|
||||
<div>
|
||||
<button id="button">I am a button</button>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,105 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>AccessFu test for enabling</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="./jsatcommon.js"></script>
|
||||
<script type="application/javascript">
|
||||
|
||||
function startAccessFu() {
|
||||
AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest);
|
||||
AccessFu._enable();
|
||||
}
|
||||
|
||||
function nextMode(aCurrentMode, aNextMode) {
|
||||
return function() {
|
||||
is(AccessFu.Input.quickNavMode.current, aCurrentMode,
|
||||
"initial current mode is correct");
|
||||
AccessFu.Input.quickNavMode.next();
|
||||
_expectMode(aNextMode, AccessFuTest.nextTest);
|
||||
};
|
||||
}
|
||||
|
||||
function prevMode(aCurrentMode, aNextMode) {
|
||||
return function() {
|
||||
is(AccessFu.Input.quickNavMode.current, aCurrentMode,
|
||||
"initial current mode is correct");
|
||||
AccessFu.Input.quickNavMode.previous();
|
||||
_expectMode(aNextMode, AccessFuTest.nextTest);
|
||||
};
|
||||
}
|
||||
|
||||
function setMode(aModeIndex, aExpectedMode) {
|
||||
return function() {
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{"set": [["accessibility.accessfu.quicknav_index", aModeIndex]]},
|
||||
function() {
|
||||
_expectMode(aExpectedMode, AccessFuTest.nextTest);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function reconfigureModes() {
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{"set": [["accessibility.accessfu.quicknav_modes", "Landmark,Button,Entry,Graphic"]]},
|
||||
function() {
|
||||
// When the modes are reconfigured, the current mode should
|
||||
// be set to the first in the new list.
|
||||
_expectMode("Landmark", AccessFuTest.nextTest);
|
||||
});
|
||||
}
|
||||
|
||||
function _expectMode(aExpectedMode, aCallback) {
|
||||
if (AccessFu.Input.quickNavMode.current === aExpectedMode) {
|
||||
ok(true, "correct mode");
|
||||
aCallback();
|
||||
} else {
|
||||
AccessFuTest.once_log("Quicknav mode: " + aExpectedMode, function() {
|
||||
ok(true, "correct mode");
|
||||
aCallback();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function stopAccessFu() {
|
||||
ok(AccessFu._enabled, "AccessFu is enabled.");
|
||||
AccessFuTest.once_log("EventManager.stop", () => AccessFuTest.finish());
|
||||
AccessFu._disable();
|
||||
}
|
||||
|
||||
function doTest() {
|
||||
AccessFuTest.addFunc(startAccessFu);
|
||||
AccessFuTest.addFunc(nextMode("Link", "Heading"));
|
||||
AccessFuTest.addFunc(nextMode("Heading", "FormElement"));
|
||||
AccessFuTest.addFunc(nextMode("FormElement", "Link"));
|
||||
AccessFuTest.addFunc(nextMode("Link", "Heading"));
|
||||
AccessFuTest.addFunc(prevMode("Heading", "Link"));
|
||||
AccessFuTest.addFunc(prevMode("Link", "FormElement"));
|
||||
AccessFuTest.addFunc(setMode(1, "Heading"));
|
||||
AccessFuTest.addFunc(reconfigureModes);
|
||||
AccessFuTest.addFunc(stopAccessFu);
|
||||
AccessFuTest.waitForExplicitFinish();
|
||||
AccessFuTest.runTests([ // Will call SimpleTest.finish();
|
||||
["accessibility.accessfu.quicknav_modes", "Link,Heading,FormElement"]]);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=811307"
|
||||
title="[AccessFu] Add mochitest for enabling">
|
||||
Mozilla Bug 811307
|
||||
</a>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user