accessible/jsat/PointerAdapter.jsm
author Kris Maglione <maglione.k@gmail.com>
Wed, 24 Jan 2018 15:48:47 -0800
changeset 455769 d4a7c018420e408fbe0a13ffddd2861623fda5a7
parent 438728 f6b5bbc888413b87292a34fcfb4a039dc1712fe4
child 455772 cc87ad81ff86109c7ea0187424fa9a8ed3b4af6c
permissions -rw-r--r--
Bug 1431533: Part 5a - Auto-rewrite code to use ChromeUtils import methods. r=florian MozReview-Commit-ID: 8V1ZT53ReiP

/* 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";

const Ci = Components.interfaces;
const Cu = Components.utils;

this.EXPORTED_SYMBOLS = ["PointerRelay", "PointerAdapter"]; // jshint ignore:line

ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");

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