diff options
Diffstat (limited to 'accessible/jsat/PointerAdapter.jsm')
-rw-r--r-- | accessible/jsat/PointerAdapter.jsm | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/accessible/jsat/PointerAdapter.jsm b/accessible/jsat/PointerAdapter.jsm new file mode 100644 index 000000000..ff54976b7 --- /dev/null +++ b/accessible/jsat/PointerAdapter.jsm @@ -0,0 +1,174 @@ +/* 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/. */ + +/* global Components, XPCOMUtils, Utils, Logger, GestureSettings, + GestureTracker */ +/* exported PointerRelay, PointerAdapter */ + +'use strict'; + +const Ci = Components.interfaces; +const Cu = Components.utils; + +this.EXPORTED_SYMBOLS = ['PointerRelay', 'PointerAdapter']; // jshint ignore:line + +Cu.import('resource://gre/modules/XPCOMUtils.jsm'); + +XPCOMUtils.defineLazyModuleGetter(this, 'Utils', // jshint ignore:line + 'resource://gre/modules/accessibility/Utils.jsm'); +XPCOMUtils.defineLazyModuleGetter(this, 'Logger', // jshint ignore:line + 'resource://gre/modules/accessibility/Utils.jsm'); +XPCOMUtils.defineLazyModuleGetter(this, 'GestureSettings', // jshint ignore:line + 'resource://gre/modules/accessibility/Gestures.jsm'); +XPCOMUtils.defineLazyModuleGetter(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; + + case 'gonk': + this._eventsOfInterest = { + 'touchstart' : true, + 'touchmove' : true, + 'touchend' : true, + 'mousedown' : false, + 'mousemove' : false, + 'mouseup': false, + 'click': false }; + 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 instanceof Ci.nsIDOMChromeWindow) { + return; + } + if (aEvent.mozInputSource === Ci.nsIDOMMouseEvent.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 + }; + } + ) + }); + } +}; + +this.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); + } +}; |