accessible/src/jsat/PointerAdapter.jsm

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 /* global Components, XPCOMUtils, Utils, Logger, GestureSettings,
     6    GestureTracker */
     7 /* exported PointerRelay, PointerAdapter */
     9 'use strict';
    11 const Ci = Components.interfaces;
    12 const Cu = Components.utils;
    14 this.EXPORTED_SYMBOLS = ['PointerRelay', 'PointerAdapter']; // jshint ignore:line
    16 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
    18 XPCOMUtils.defineLazyModuleGetter(this, 'Utils', // jshint ignore:line
    19   'resource://gre/modules/accessibility/Utils.jsm');
    20 XPCOMUtils.defineLazyModuleGetter(this, 'Logger', // jshint ignore:line
    21   'resource://gre/modules/accessibility/Utils.jsm');
    22 XPCOMUtils.defineLazyModuleGetter(this, 'GestureSettings', // jshint ignore:line
    23   'resource://gre/modules/accessibility/Gestures.jsm');
    24 XPCOMUtils.defineLazyModuleGetter(this, 'GestureTracker', // jshint ignore:line
    25   'resource://gre/modules/accessibility/Gestures.jsm');
    27 // The virtual touch ID generated by a mouse event.
    28 const MOUSE_ID = 'mouse';
    29 // Synthesized touch ID.
    30 const SYNTH_ID = -1;
    32 let PointerRelay = { // jshint ignore:line
    33   /**
    34    * A mapping of events we should be intercepting. Entries with a value of
    35    * |true| are used for compiling high-level gesture events. Entries with a
    36    * value of |false| are cancelled and do not propogate to content.
    37    */
    38   get _eventsOfInterest() {
    39     delete this._eventsOfInterest;
    41     switch (Utils.widgetToolkit) {
    42       case 'gonk':
    43         this._eventsOfInterest = {
    44           'touchstart' : true,
    45           'touchmove' : true,
    46           'touchend' : true,
    47           'mousedown' : false,
    48           'mousemove' : false,
    49           'mouseup': false,
    50           'click': false };
    51         break;
    53       case 'android':
    54         this._eventsOfInterest = {
    55           'touchstart' : true,
    56           'touchmove' : true,
    57           'touchend' : true,
    58           'mousemove' : true,
    59           'mouseenter' : true,
    60           'mouseleave' : true,
    61           'mousedown' : false,
    62           'mouseup': false,
    63           'click': false };
    64         break;
    66       default:
    67         // Desktop.
    68         this._eventsOfInterest = {
    69           'mousemove' : true,
    70           'mousedown' : true,
    71           'mouseup': true,
    72           'click': false
    73         };
    74         if ('ontouchstart' in Utils.win) {
    75           for (let eventType of ['touchstart', 'touchmove', 'touchend']) {
    76             this._eventsOfInterest[eventType] = true;
    77           }
    78         }
    79         break;
    80     }
    82     return this._eventsOfInterest;
    83   },
    85   _eventMap: {
    86     'touchstart' : 'pointerdown',
    87     'mousedown' : 'pointerdown',
    88     'mouseenter' : 'pointerdown',
    89     'touchmove' : 'pointermove',
    90     'mousemove' : 'pointermove',
    91     'touchend' : 'pointerup',
    92     'mouseup': 'pointerup',
    93     'mouseleave': 'pointerup'
    94   },
    96   start: function PointerRelay_start(aOnPointerEvent) {
    97     Logger.debug('PointerRelay.start');
    98     this.onPointerEvent = aOnPointerEvent;
    99     for (let eventType in this._eventsOfInterest) {
   100       Utils.win.addEventListener(eventType, this, true, true);
   101     }
   102   },
   104   stop: function PointerRelay_stop() {
   105     Logger.debug('PointerRelay.stop');
   106     delete this.lastPointerMove;
   107     delete this.onPointerEvent;
   108     for (let eventType in this._eventsOfInterest) {
   109       Utils.win.removeEventListener(eventType, this, true, true);
   110     }
   111   },
   113   _suppressPointerMove: function PointerRelay__suppressPointerMove(aChangedTouches) {
   114     if (!this.lastPointerMove) {
   115       return false;
   116     }
   117     for (let i = 0; i < aChangedTouches.length; ++i) {
   118       let touch = aChangedTouches[i];
   119       let lastTouch;
   120       try {
   121         lastTouch = this.lastPointerMove.identifiedTouch ?
   122           this.lastPointerMove.identifiedTouch(touch.identifier) :
   123           this.lastPointerMove[i];
   124       } catch (x) {
   125         // Sometimes touch object can't be accessed after page navigation.
   126       }
   127       if (!lastTouch || lastTouch.target !== touch.target ||
   128         Math.hypot(touch.screenX - lastTouch.screenX, touch.screenY -
   129           lastTouch.screenY) / Utils.dpi >= GestureSettings.travelThreshold) {
   130         return false;
   131       }
   132     }
   133     return true;
   134   },
   136   handleEvent: function PointerRelay_handleEvent(aEvent) {
   137     // Don't bother with chrome mouse events.
   138     if (Utils.MozBuildApp === 'browser' &&
   139       aEvent.view.top instanceof Ci.nsIDOMChromeWindow) {
   140       return;
   141     }
   142     if (aEvent.mozInputSource === Ci.nsIDOMMouseEvent.MOZ_SOURCE_UNKNOWN) {
   143       // Ignore events that are scripted or clicks from the a11y API.
   144       return;
   145     }
   147     let changedTouches = aEvent.changedTouches || [{
   148       identifier: MOUSE_ID,
   149       screenX: aEvent.screenX,
   150       screenY: aEvent.screenY,
   151       target: aEvent.target
   152     }];
   154     if (changedTouches.length === 1 &&
   155         changedTouches[0].identifier === SYNTH_ID) {
   156       return;
   157     }
   159     aEvent.preventDefault();
   160     aEvent.stopImmediatePropagation();
   162     let type = aEvent.type;
   163     if (!this._eventsOfInterest[type]) {
   164       return;
   165     }
   166     let pointerType = this._eventMap[type];
   167     if (pointerType === 'pointermove') {
   168       if (this._suppressPointerMove(changedTouches)) {
   169         // Do not fire pointermove more than every POINTERMOVE_THROTTLE.
   170         return;
   171       }
   172       this.lastPointerMove = changedTouches;
   173     }
   174     this.onPointerEvent({
   175       type: pointerType,
   176       points: Array.prototype.map.call(changedTouches,
   177         function mapTouch(aTouch) {
   178           return {
   179             identifier: aTouch.identifier,
   180             x: aTouch.screenX,
   181             y: aTouch.screenY
   182           };
   183         }
   184       )
   185     });
   186   }
   187 };
   189 this.PointerAdapter = { // jshint ignore:line
   190   start: function PointerAdapter_start() {
   191     Logger.debug('PointerAdapter.start');
   192     GestureTracker.reset();
   193     PointerRelay.start(this.handleEvent);
   194   },
   196   stop: function PointerAdapter_stop() {
   197     Logger.debug('PointerAdapter.stop');
   198     PointerRelay.stop();
   199     GestureTracker.reset();
   200   },
   202   handleEvent: function PointerAdapter_handleEvent(aDetail) {
   203     let timeStamp = Date.now();
   204     GestureTracker.handle(aDetail, timeStamp);
   205   }
   206 };

mercurial