Bug 1454851 - Remove gestures and all input management. r=yzen

This commit is contained in:
Eitan Isaacson 2018-04-17 17:56:02 -07:00
parent e9186f7449
commit 326a67e71e
11 changed files with 1 additions and 2245 deletions

View File

@ -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;

View File

@ -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;
};

View File

@ -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);
}
};

View File

@ -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']

View File

@ -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]

View File

@ -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();
}

View File

@ -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 }]
}
]

View File

@ -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.

View File

@ -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>

View File

@ -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>

View File

@ -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>