11cb0ef41Sopenharmony_ci(function() {
21cb0ef41Sopenharmony_ci  let sourceNameIdx = 0;
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ci  /**
51cb0ef41Sopenharmony_ci   * @class
61cb0ef41Sopenharmony_ci   * Builder for creating a sequence of actions
71cb0ef41Sopenharmony_ci   *
81cb0ef41Sopenharmony_ci   *
91cb0ef41Sopenharmony_ci   * The actions are dispatched once
101cb0ef41Sopenharmony_ci   * :js:func:`test_driver.Actions.send` is called. This returns a
111cb0ef41Sopenharmony_ci   * promise which resolves once the actions are complete.
121cb0ef41Sopenharmony_ci   *
131cb0ef41Sopenharmony_ci   * The other methods on :js:class:`test_driver.Actions` object are
141cb0ef41Sopenharmony_ci   * used to build the sequence of actions that will be sent. These
151cb0ef41Sopenharmony_ci   * return the `Actions` object itself, so the actions sequence can
161cb0ef41Sopenharmony_ci   * be constructed by chaining method calls.
171cb0ef41Sopenharmony_ci   *
181cb0ef41Sopenharmony_ci   * Internally :js:func:`test_driver.Actions.send` invokes
191cb0ef41Sopenharmony_ci   * :js:func:`test_driver.action_sequence`.
201cb0ef41Sopenharmony_ci   *
211cb0ef41Sopenharmony_ci   * @example
221cb0ef41Sopenharmony_ci   * let text_box = document.getElementById("text");
231cb0ef41Sopenharmony_ci   *
241cb0ef41Sopenharmony_ci   * let actions = new test_driver.Actions()
251cb0ef41Sopenharmony_ci   *    .pointerMove(0, 0, {origin: text_box})
261cb0ef41Sopenharmony_ci   *    .pointerDown()
271cb0ef41Sopenharmony_ci   *    .pointerUp()
281cb0ef41Sopenharmony_ci   *    .addTick()
291cb0ef41Sopenharmony_ci   *    .keyDown("p")
301cb0ef41Sopenharmony_ci   *    .keyUp("p");
311cb0ef41Sopenharmony_ci   *
321cb0ef41Sopenharmony_ci   * await actions.send();
331cb0ef41Sopenharmony_ci   *
341cb0ef41Sopenharmony_ci   * @param {number} [defaultTickDuration] - The default duration of a
351cb0ef41Sopenharmony_ci   * tick. Be default this is set ot 16ms, which is one frame time
361cb0ef41Sopenharmony_ci   * based on 60Hz display.
371cb0ef41Sopenharmony_ci   */
381cb0ef41Sopenharmony_ci  function Actions(defaultTickDuration=16) {
391cb0ef41Sopenharmony_ci    this.sourceTypes = new Map([["key", KeySource],
401cb0ef41Sopenharmony_ci                                ["pointer", PointerSource],
411cb0ef41Sopenharmony_ci                                ["wheel", WheelSource],
421cb0ef41Sopenharmony_ci                                ["none", GeneralSource]]);
431cb0ef41Sopenharmony_ci    this.sources = new Map();
441cb0ef41Sopenharmony_ci    this.sourceOrder = [];
451cb0ef41Sopenharmony_ci    for (let sourceType of this.sourceTypes.keys()) {
461cb0ef41Sopenharmony_ci      this.sources.set(sourceType, new Map());
471cb0ef41Sopenharmony_ci    }
481cb0ef41Sopenharmony_ci    this.currentSources = new Map();
491cb0ef41Sopenharmony_ci    for (let sourceType of this.sourceTypes.keys()) {
501cb0ef41Sopenharmony_ci      this.currentSources.set(sourceType, null);
511cb0ef41Sopenharmony_ci    }
521cb0ef41Sopenharmony_ci    this.createSource("none");
531cb0ef41Sopenharmony_ci    this.tickIdx = 0;
541cb0ef41Sopenharmony_ci    this.defaultTickDuration = defaultTickDuration;
551cb0ef41Sopenharmony_ci    this.context = null;
561cb0ef41Sopenharmony_ci  }
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci  Actions.prototype = {
591cb0ef41Sopenharmony_ci    ButtonType: {
601cb0ef41Sopenharmony_ci      LEFT: 0,
611cb0ef41Sopenharmony_ci      MIDDLE: 1,
621cb0ef41Sopenharmony_ci      RIGHT: 2,
631cb0ef41Sopenharmony_ci      BACK: 3,
641cb0ef41Sopenharmony_ci      FORWARD: 4,
651cb0ef41Sopenharmony_ci    },
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci    /**
681cb0ef41Sopenharmony_ci     * Generate the action sequence suitable for passing to
691cb0ef41Sopenharmony_ci     * test_driver.action_sequence
701cb0ef41Sopenharmony_ci     *
711cb0ef41Sopenharmony_ci     * @returns {Array} Array of WebDriver-compatible actions sequences
721cb0ef41Sopenharmony_ci     */
731cb0ef41Sopenharmony_ci    serialize: function() {
741cb0ef41Sopenharmony_ci      let actions = [];
751cb0ef41Sopenharmony_ci      for (let [sourceType, sourceName] of this.sourceOrder) {
761cb0ef41Sopenharmony_ci        let source = this.sources.get(sourceType).get(sourceName);
771cb0ef41Sopenharmony_ci        let serialized = source.serialize(this.tickIdx + 1, this.defaultTickDuration);
781cb0ef41Sopenharmony_ci        if (serialized) {
791cb0ef41Sopenharmony_ci          serialized.id = sourceName;
801cb0ef41Sopenharmony_ci          actions.push(serialized);
811cb0ef41Sopenharmony_ci        }
821cb0ef41Sopenharmony_ci      }
831cb0ef41Sopenharmony_ci      return actions;
841cb0ef41Sopenharmony_ci    },
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci    /**
871cb0ef41Sopenharmony_ci     * Generate and send the action sequence
881cb0ef41Sopenharmony_ci     *
891cb0ef41Sopenharmony_ci     * @returns {Promise} fulfilled after the sequence is executed,
901cb0ef41Sopenharmony_ci     *                    rejected if any actions fail.
911cb0ef41Sopenharmony_ci     */
921cb0ef41Sopenharmony_ci    send: function() {
931cb0ef41Sopenharmony_ci      let actions;
941cb0ef41Sopenharmony_ci      try {
951cb0ef41Sopenharmony_ci        actions = this.serialize();
961cb0ef41Sopenharmony_ci      } catch(e) {
971cb0ef41Sopenharmony_ci        return Promise.reject(e);
981cb0ef41Sopenharmony_ci      }
991cb0ef41Sopenharmony_ci      return test_driver.action_sequence(actions, this.context);
1001cb0ef41Sopenharmony_ci    },
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci    /**
1031cb0ef41Sopenharmony_ci     * Set the context for the actions
1041cb0ef41Sopenharmony_ci     *
1051cb0ef41Sopenharmony_ci     * @param {WindowProxy} context - Context in which to run the action sequence
1061cb0ef41Sopenharmony_ci     */
1071cb0ef41Sopenharmony_ci    setContext: function(context) {
1081cb0ef41Sopenharmony_ci      this.context = context;
1091cb0ef41Sopenharmony_ci      return this;
1101cb0ef41Sopenharmony_ci    },
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci    /**
1131cb0ef41Sopenharmony_ci     * Get the action source with a particular source type and name.
1141cb0ef41Sopenharmony_ci     * If no name is passed, a new source with the given type is
1151cb0ef41Sopenharmony_ci     * created.
1161cb0ef41Sopenharmony_ci     *
1171cb0ef41Sopenharmony_ci     * @param {String} type - Source type ('none', 'key', 'pointer', or 'wheel')
1181cb0ef41Sopenharmony_ci     * @param {String?} name - Name of the source
1191cb0ef41Sopenharmony_ci     * @returns {Source} Source object for that source.
1201cb0ef41Sopenharmony_ci     */
1211cb0ef41Sopenharmony_ci    getSource: function(type, name) {
1221cb0ef41Sopenharmony_ci      if (!this.sources.has(type)) {
1231cb0ef41Sopenharmony_ci        throw new Error(`${type} is not a valid action type`);
1241cb0ef41Sopenharmony_ci      }
1251cb0ef41Sopenharmony_ci      if (name === null || name === undefined) {
1261cb0ef41Sopenharmony_ci        name = this.currentSources.get(type);
1271cb0ef41Sopenharmony_ci      }
1281cb0ef41Sopenharmony_ci      if (name === null || name === undefined) {
1291cb0ef41Sopenharmony_ci        return this.createSource(type, null);
1301cb0ef41Sopenharmony_ci      }
1311cb0ef41Sopenharmony_ci      return this.sources.get(type).get(name);
1321cb0ef41Sopenharmony_ci    },
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci    setSource: function(type, name) {
1351cb0ef41Sopenharmony_ci      if (!this.sources.has(type)) {
1361cb0ef41Sopenharmony_ci        throw new Error(`${type} is not a valid action type`);
1371cb0ef41Sopenharmony_ci      }
1381cb0ef41Sopenharmony_ci      if (!this.sources.get(type).has(name)) {
1391cb0ef41Sopenharmony_ci        throw new Error(`${name} is not a valid source for ${type}`);
1401cb0ef41Sopenharmony_ci      }
1411cb0ef41Sopenharmony_ci      this.currentSources.set(type, name);
1421cb0ef41Sopenharmony_ci      return this;
1431cb0ef41Sopenharmony_ci    },
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci    /**
1461cb0ef41Sopenharmony_ci     * Add a new key input source with the given name
1471cb0ef41Sopenharmony_ci     *
1481cb0ef41Sopenharmony_ci     * @param {String} name - Name of the key source
1491cb0ef41Sopenharmony_ci     * @param {Bool} set - Set source as the default key source
1501cb0ef41Sopenharmony_ci     * @returns {Actions}
1511cb0ef41Sopenharmony_ci     */
1521cb0ef41Sopenharmony_ci    addKeyboard: function(name, set=true) {
1531cb0ef41Sopenharmony_ci      this.createSource("key", name);
1541cb0ef41Sopenharmony_ci      if (set) {
1551cb0ef41Sopenharmony_ci        this.setKeyboard(name);
1561cb0ef41Sopenharmony_ci      }
1571cb0ef41Sopenharmony_ci      return this;
1581cb0ef41Sopenharmony_ci    },
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci    /**
1611cb0ef41Sopenharmony_ci     * Set the current default key source
1621cb0ef41Sopenharmony_ci     *
1631cb0ef41Sopenharmony_ci     * @param {String} name - Name of the key source
1641cb0ef41Sopenharmony_ci     * @returns {Actions}
1651cb0ef41Sopenharmony_ci     */
1661cb0ef41Sopenharmony_ci    setKeyboard: function(name) {
1671cb0ef41Sopenharmony_ci      this.setSource("key", name);
1681cb0ef41Sopenharmony_ci      return this;
1691cb0ef41Sopenharmony_ci    },
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_ci    /**
1721cb0ef41Sopenharmony_ci     * Add a new pointer input source with the given name
1731cb0ef41Sopenharmony_ci     *
1741cb0ef41Sopenharmony_ci     * @param {String} type - Name of the pointer source
1751cb0ef41Sopenharmony_ci     * @param {String} pointerType - Type of pointing device
1761cb0ef41Sopenharmony_ci     * @param {Bool} set - Set source as the default pointer source
1771cb0ef41Sopenharmony_ci     * @returns {Actions}
1781cb0ef41Sopenharmony_ci     */
1791cb0ef41Sopenharmony_ci    addPointer: function(name, pointerType="mouse", set=true) {
1801cb0ef41Sopenharmony_ci      this.createSource("pointer", name, {pointerType: pointerType});
1811cb0ef41Sopenharmony_ci      if (set) {
1821cb0ef41Sopenharmony_ci        this.setPointer(name);
1831cb0ef41Sopenharmony_ci      }
1841cb0ef41Sopenharmony_ci      return this;
1851cb0ef41Sopenharmony_ci    },
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ci    /**
1881cb0ef41Sopenharmony_ci     * Set the current default pointer source
1891cb0ef41Sopenharmony_ci     *
1901cb0ef41Sopenharmony_ci     * @param {String} name - Name of the pointer source
1911cb0ef41Sopenharmony_ci     * @returns {Actions}
1921cb0ef41Sopenharmony_ci     */
1931cb0ef41Sopenharmony_ci    setPointer: function(name) {
1941cb0ef41Sopenharmony_ci      this.setSource("pointer", name);
1951cb0ef41Sopenharmony_ci      return this;
1961cb0ef41Sopenharmony_ci    },
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ci    /**
1991cb0ef41Sopenharmony_ci     * Add a new wheel input source with the given name
2001cb0ef41Sopenharmony_ci     *
2011cb0ef41Sopenharmony_ci     * @param {String} type - Name of the wheel source
2021cb0ef41Sopenharmony_ci     * @param {Bool} set - Set source as the default wheel source
2031cb0ef41Sopenharmony_ci     * @returns {Actions}
2041cb0ef41Sopenharmony_ci     */
2051cb0ef41Sopenharmony_ci    addWheel: function(name, set=true) {
2061cb0ef41Sopenharmony_ci      this.createSource("wheel", name);
2071cb0ef41Sopenharmony_ci      if (set) {
2081cb0ef41Sopenharmony_ci        this.setWheel(name);
2091cb0ef41Sopenharmony_ci      }
2101cb0ef41Sopenharmony_ci      return this;
2111cb0ef41Sopenharmony_ci    },
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci    /**
2141cb0ef41Sopenharmony_ci     * Set the current default wheel source
2151cb0ef41Sopenharmony_ci     *
2161cb0ef41Sopenharmony_ci     * @param {String} name - Name of the wheel source
2171cb0ef41Sopenharmony_ci     * @returns {Actions}
2181cb0ef41Sopenharmony_ci     */
2191cb0ef41Sopenharmony_ci    setWheel: function(name) {
2201cb0ef41Sopenharmony_ci      this.setSource("wheel", name);
2211cb0ef41Sopenharmony_ci      return this;
2221cb0ef41Sopenharmony_ci    },
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_ci    createSource: function(type, name, parameters={}) {
2251cb0ef41Sopenharmony_ci      if (!this.sources.has(type)) {
2261cb0ef41Sopenharmony_ci        throw new Error(`${type} is not a valid action type`);
2271cb0ef41Sopenharmony_ci      }
2281cb0ef41Sopenharmony_ci      let sourceNames = new Set();
2291cb0ef41Sopenharmony_ci      for (let [_, name] of this.sourceOrder) {
2301cb0ef41Sopenharmony_ci        sourceNames.add(name);
2311cb0ef41Sopenharmony_ci      }
2321cb0ef41Sopenharmony_ci      if (!name) {
2331cb0ef41Sopenharmony_ci        do {
2341cb0ef41Sopenharmony_ci          name = "" + sourceNameIdx++;
2351cb0ef41Sopenharmony_ci        } while (sourceNames.has(name))
2361cb0ef41Sopenharmony_ci      } else {
2371cb0ef41Sopenharmony_ci        if (sourceNames.has(name)) {
2381cb0ef41Sopenharmony_ci          throw new Error(`Alreay have a source of type ${type} named ${name}.`);
2391cb0ef41Sopenharmony_ci        }
2401cb0ef41Sopenharmony_ci      }
2411cb0ef41Sopenharmony_ci      this.sources.get(type).set(name, new (this.sourceTypes.get(type))(parameters));
2421cb0ef41Sopenharmony_ci      this.currentSources.set(type, name);
2431cb0ef41Sopenharmony_ci      this.sourceOrder.push([type, name]);
2441cb0ef41Sopenharmony_ci      return this.sources.get(type).get(name);
2451cb0ef41Sopenharmony_ci    },
2461cb0ef41Sopenharmony_ci
2471cb0ef41Sopenharmony_ci    /**
2481cb0ef41Sopenharmony_ci     * Insert a new actions tick
2491cb0ef41Sopenharmony_ci     *
2501cb0ef41Sopenharmony_ci     * @param {Number?} duration - Minimum length of the tick in ms.
2511cb0ef41Sopenharmony_ci     * @returns {Actions}
2521cb0ef41Sopenharmony_ci     */
2531cb0ef41Sopenharmony_ci    addTick: function(duration) {
2541cb0ef41Sopenharmony_ci      this.tickIdx += 1;
2551cb0ef41Sopenharmony_ci      if (duration) {
2561cb0ef41Sopenharmony_ci        this.pause(duration);
2571cb0ef41Sopenharmony_ci      }
2581cb0ef41Sopenharmony_ci      return this;
2591cb0ef41Sopenharmony_ci    },
2601cb0ef41Sopenharmony_ci
2611cb0ef41Sopenharmony_ci    /**
2621cb0ef41Sopenharmony_ci     * Add a pause to the current tick
2631cb0ef41Sopenharmony_ci     *
2641cb0ef41Sopenharmony_ci     * @param {Number?} duration - Minimum length of the tick in ms.
2651cb0ef41Sopenharmony_ci     * @param {String} sourceType - source type
2661cb0ef41Sopenharmony_ci     * @param {String?} sourceName - Named key, pointer or wheel source to use
2671cb0ef41Sopenharmony_ci     *                               or null for the default key, pointer or
2681cb0ef41Sopenharmony_ci     *                               wheel source
2691cb0ef41Sopenharmony_ci     * @returns {Actions}
2701cb0ef41Sopenharmony_ci     */
2711cb0ef41Sopenharmony_ci    pause: function(duration=0, sourceType="none", {sourceName=null}={}) {
2721cb0ef41Sopenharmony_ci      if (sourceType=="none")
2731cb0ef41Sopenharmony_ci        this.getSource("none").addPause(this, duration);
2741cb0ef41Sopenharmony_ci      else
2751cb0ef41Sopenharmony_ci        this.getSource(sourceType, sourceName).addPause(this, duration);
2761cb0ef41Sopenharmony_ci      return this;
2771cb0ef41Sopenharmony_ci    },
2781cb0ef41Sopenharmony_ci
2791cb0ef41Sopenharmony_ci    /**
2801cb0ef41Sopenharmony_ci     * Create a keyDown event for the current default key source
2811cb0ef41Sopenharmony_ci     *
2821cb0ef41Sopenharmony_ci     * @param {String} key - Key to press
2831cb0ef41Sopenharmony_ci     * @param {String?} sourceName - Named key source to use or null for the default key source
2841cb0ef41Sopenharmony_ci     * @returns {Actions}
2851cb0ef41Sopenharmony_ci     */
2861cb0ef41Sopenharmony_ci    keyDown: function(key, {sourceName=null}={}) {
2871cb0ef41Sopenharmony_ci      let source = this.getSource("key", sourceName);
2881cb0ef41Sopenharmony_ci      source.keyDown(this, key);
2891cb0ef41Sopenharmony_ci      return this;
2901cb0ef41Sopenharmony_ci    },
2911cb0ef41Sopenharmony_ci
2921cb0ef41Sopenharmony_ci    /**
2931cb0ef41Sopenharmony_ci     * Create a keyDown event for the current default key source
2941cb0ef41Sopenharmony_ci     *
2951cb0ef41Sopenharmony_ci     * @param {String} key - Key to release
2961cb0ef41Sopenharmony_ci     * @param {String?} sourceName - Named key source to use or null for the default key source
2971cb0ef41Sopenharmony_ci     * @returns {Actions}
2981cb0ef41Sopenharmony_ci     */
2991cb0ef41Sopenharmony_ci    keyUp: function(key, {sourceName=null}={}) {
3001cb0ef41Sopenharmony_ci      let source = this.getSource("key", sourceName);
3011cb0ef41Sopenharmony_ci      source.keyUp(this, key);
3021cb0ef41Sopenharmony_ci      return this;
3031cb0ef41Sopenharmony_ci    },
3041cb0ef41Sopenharmony_ci
3051cb0ef41Sopenharmony_ci    /**
3061cb0ef41Sopenharmony_ci     * Create a pointerDown event for the current default pointer source
3071cb0ef41Sopenharmony_ci     *
3081cb0ef41Sopenharmony_ci     * @param {String} button - Button to press
3091cb0ef41Sopenharmony_ci     * @param {String?} sourceName - Named pointer source to use or null for the default
3101cb0ef41Sopenharmony_ci     *                               pointer source
3111cb0ef41Sopenharmony_ci     * @returns {Actions}
3121cb0ef41Sopenharmony_ci     */
3131cb0ef41Sopenharmony_ci    pointerDown: function({button=this.ButtonType.LEFT, sourceName=null,
3141cb0ef41Sopenharmony_ci                           width, height, pressure, tangentialPressure,
3151cb0ef41Sopenharmony_ci                           tiltX, tiltY, twist, altitudeAngle, azimuthAngle}={}) {
3161cb0ef41Sopenharmony_ci      let source = this.getSource("pointer", sourceName);
3171cb0ef41Sopenharmony_ci      source.pointerDown(this, button, width, height, pressure, tangentialPressure,
3181cb0ef41Sopenharmony_ci                         tiltX, tiltY, twist, altitudeAngle, azimuthAngle);
3191cb0ef41Sopenharmony_ci      return this;
3201cb0ef41Sopenharmony_ci    },
3211cb0ef41Sopenharmony_ci
3221cb0ef41Sopenharmony_ci    /**
3231cb0ef41Sopenharmony_ci     * Create a pointerUp event for the current default pointer source
3241cb0ef41Sopenharmony_ci     *
3251cb0ef41Sopenharmony_ci     * @param {String} button - Button to release
3261cb0ef41Sopenharmony_ci     * @param {String?} sourceName - Named pointer source to use or null for the default pointer
3271cb0ef41Sopenharmony_ci     *                               source
3281cb0ef41Sopenharmony_ci     * @returns {Actions}
3291cb0ef41Sopenharmony_ci     */
3301cb0ef41Sopenharmony_ci    pointerUp: function({button=this.ButtonType.LEFT, sourceName=null}={}) {
3311cb0ef41Sopenharmony_ci      let source = this.getSource("pointer", sourceName);
3321cb0ef41Sopenharmony_ci      source.pointerUp(this, button);
3331cb0ef41Sopenharmony_ci      return this;
3341cb0ef41Sopenharmony_ci    },
3351cb0ef41Sopenharmony_ci
3361cb0ef41Sopenharmony_ci    /**
3371cb0ef41Sopenharmony_ci     * Create a move event for the current default pointer source
3381cb0ef41Sopenharmony_ci     *
3391cb0ef41Sopenharmony_ci     * @param {Number} x - Destination x coordinate
3401cb0ef41Sopenharmony_ci     * @param {Number} y - Destination y coordinate
3411cb0ef41Sopenharmony_ci     * @param {String|Element} origin - Origin of the coordinate system.
3421cb0ef41Sopenharmony_ci     *                                  Either "pointer", "viewport" or an Element
3431cb0ef41Sopenharmony_ci     * @param {Number?} duration - Time in ms for the move
3441cb0ef41Sopenharmony_ci     * @param {String?} sourceName - Named pointer source to use or null for the default pointer
3451cb0ef41Sopenharmony_ci     *                               source
3461cb0ef41Sopenharmony_ci     * @returns {Actions}
3471cb0ef41Sopenharmony_ci     */
3481cb0ef41Sopenharmony_ci    pointerMove: function(x, y,
3491cb0ef41Sopenharmony_ci                          {origin="viewport", duration, sourceName=null,
3501cb0ef41Sopenharmony_ci                           width, height, pressure, tangentialPressure,
3511cb0ef41Sopenharmony_ci                           tiltX, tiltY, twist, altitudeAngle, azimuthAngle}={}) {
3521cb0ef41Sopenharmony_ci      let source = this.getSource("pointer", sourceName);
3531cb0ef41Sopenharmony_ci      source.pointerMove(this, x, y, duration, origin, width, height, pressure,
3541cb0ef41Sopenharmony_ci                         tangentialPressure, tiltX, tiltY, twist, altitudeAngle,
3551cb0ef41Sopenharmony_ci                         azimuthAngle);
3561cb0ef41Sopenharmony_ci      return this;
3571cb0ef41Sopenharmony_ci    },
3581cb0ef41Sopenharmony_ci
3591cb0ef41Sopenharmony_ci    /**
3601cb0ef41Sopenharmony_ci     * Create a scroll event for the current default wheel source
3611cb0ef41Sopenharmony_ci     *
3621cb0ef41Sopenharmony_ci     * @param {Number} x - mouse cursor x coordinate
3631cb0ef41Sopenharmony_ci     * @param {Number} y - mouse cursor y coordinate
3641cb0ef41Sopenharmony_ci     * @param {Number} deltaX - scroll delta value along the x-axis in pixels
3651cb0ef41Sopenharmony_ci     * @param {Number} deltaY - scroll delta value along the y-axis in pixels
3661cb0ef41Sopenharmony_ci     * @param {String|Element} origin - Origin of the coordinate system.
3671cb0ef41Sopenharmony_ci     *                                  Either "viewport" or an Element
3681cb0ef41Sopenharmony_ci     * @param {Number?} duration - Time in ms for the scroll
3691cb0ef41Sopenharmony_ci     * @param {String?} sourceName - Named wheel source to use or null for the
3701cb0ef41Sopenharmony_ci     *                               default wheel source
3711cb0ef41Sopenharmony_ci     * @returns {Actions}
3721cb0ef41Sopenharmony_ci     */
3731cb0ef41Sopenharmony_ci    scroll: function(x, y, deltaX, deltaY,
3741cb0ef41Sopenharmony_ci                     {origin="viewport", duration, sourceName=null}={}) {
3751cb0ef41Sopenharmony_ci      let source = this.getSource("wheel", sourceName);
3761cb0ef41Sopenharmony_ci      source.scroll(this, x, y, deltaX, deltaY, duration, origin);
3771cb0ef41Sopenharmony_ci      return this;
3781cb0ef41Sopenharmony_ci    },
3791cb0ef41Sopenharmony_ci  };
3801cb0ef41Sopenharmony_ci
3811cb0ef41Sopenharmony_ci  function GeneralSource() {
3821cb0ef41Sopenharmony_ci    this.actions = new Map();
3831cb0ef41Sopenharmony_ci  }
3841cb0ef41Sopenharmony_ci
3851cb0ef41Sopenharmony_ci  GeneralSource.prototype = {
3861cb0ef41Sopenharmony_ci    serialize: function(tickCount, defaultTickDuration) {
3871cb0ef41Sopenharmony_ci      let actions = [];
3881cb0ef41Sopenharmony_ci      let data = {"type": "none", "actions": actions};
3891cb0ef41Sopenharmony_ci      for (let i=0; i<tickCount; i++) {
3901cb0ef41Sopenharmony_ci        if (this.actions.has(i)) {
3911cb0ef41Sopenharmony_ci          actions.push(this.actions.get(i));
3921cb0ef41Sopenharmony_ci        } else {
3931cb0ef41Sopenharmony_ci          actions.push({"type": "pause", duration: defaultTickDuration});
3941cb0ef41Sopenharmony_ci        }
3951cb0ef41Sopenharmony_ci      }
3961cb0ef41Sopenharmony_ci      return data;
3971cb0ef41Sopenharmony_ci    },
3981cb0ef41Sopenharmony_ci
3991cb0ef41Sopenharmony_ci    addPause: function(actions, duration) {
4001cb0ef41Sopenharmony_ci      let tick = actions.tickIdx;
4011cb0ef41Sopenharmony_ci      if (this.actions.has(tick)) {
4021cb0ef41Sopenharmony_ci        throw new Error(`Already have a pause action for the current tick`);
4031cb0ef41Sopenharmony_ci      }
4041cb0ef41Sopenharmony_ci      this.actions.set(tick, {type: "pause", duration: duration});
4051cb0ef41Sopenharmony_ci    },
4061cb0ef41Sopenharmony_ci  };
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_ci  function KeySource() {
4091cb0ef41Sopenharmony_ci    this.actions = new Map();
4101cb0ef41Sopenharmony_ci  }
4111cb0ef41Sopenharmony_ci
4121cb0ef41Sopenharmony_ci  KeySource.prototype = {
4131cb0ef41Sopenharmony_ci    serialize: function(tickCount) {
4141cb0ef41Sopenharmony_ci      if (!this.actions.size) {
4151cb0ef41Sopenharmony_ci        return undefined;
4161cb0ef41Sopenharmony_ci      }
4171cb0ef41Sopenharmony_ci      let actions = [];
4181cb0ef41Sopenharmony_ci      let data = {"type": "key", "actions": actions};
4191cb0ef41Sopenharmony_ci      for (let i=0; i<tickCount; i++) {
4201cb0ef41Sopenharmony_ci        if (this.actions.has(i)) {
4211cb0ef41Sopenharmony_ci          actions.push(this.actions.get(i));
4221cb0ef41Sopenharmony_ci        } else {
4231cb0ef41Sopenharmony_ci          actions.push({"type": "pause"});
4241cb0ef41Sopenharmony_ci        }
4251cb0ef41Sopenharmony_ci      }
4261cb0ef41Sopenharmony_ci      return data;
4271cb0ef41Sopenharmony_ci    },
4281cb0ef41Sopenharmony_ci
4291cb0ef41Sopenharmony_ci    keyDown: function(actions, key) {
4301cb0ef41Sopenharmony_ci      let tick = actions.tickIdx;
4311cb0ef41Sopenharmony_ci      if (this.actions.has(tick)) {
4321cb0ef41Sopenharmony_ci        tick = actions.addTick().tickIdx;
4331cb0ef41Sopenharmony_ci      }
4341cb0ef41Sopenharmony_ci      this.actions.set(tick, {type: "keyDown", value: key});
4351cb0ef41Sopenharmony_ci    },
4361cb0ef41Sopenharmony_ci
4371cb0ef41Sopenharmony_ci    keyUp: function(actions, key) {
4381cb0ef41Sopenharmony_ci      let tick = actions.tickIdx;
4391cb0ef41Sopenharmony_ci      if (this.actions.has(tick)) {
4401cb0ef41Sopenharmony_ci        tick = actions.addTick().tickIdx;
4411cb0ef41Sopenharmony_ci      }
4421cb0ef41Sopenharmony_ci      this.actions.set(tick, {type: "keyUp", value: key});
4431cb0ef41Sopenharmony_ci    },
4441cb0ef41Sopenharmony_ci
4451cb0ef41Sopenharmony_ci    addPause: function(actions, duration) {
4461cb0ef41Sopenharmony_ci      let tick = actions.tickIdx;
4471cb0ef41Sopenharmony_ci      if (this.actions.has(tick)) {
4481cb0ef41Sopenharmony_ci        tick = actions.addTick().tickIdx;
4491cb0ef41Sopenharmony_ci      }
4501cb0ef41Sopenharmony_ci      this.actions.set(tick, {type: "pause", duration: duration});
4511cb0ef41Sopenharmony_ci    },
4521cb0ef41Sopenharmony_ci  };
4531cb0ef41Sopenharmony_ci
4541cb0ef41Sopenharmony_ci  function PointerSource(parameters={pointerType: "mouse"}) {
4551cb0ef41Sopenharmony_ci    let pointerType = parameters.pointerType || "mouse";
4561cb0ef41Sopenharmony_ci    if (!["mouse", "pen", "touch"].includes(pointerType)) {
4571cb0ef41Sopenharmony_ci      throw new Error(`Invalid pointerType ${pointerType}`);
4581cb0ef41Sopenharmony_ci    }
4591cb0ef41Sopenharmony_ci    this.type = pointerType;
4601cb0ef41Sopenharmony_ci    this.actions = new Map();
4611cb0ef41Sopenharmony_ci  }
4621cb0ef41Sopenharmony_ci
4631cb0ef41Sopenharmony_ci  function setPointerProperties(action, width, height, pressure, tangentialPressure,
4641cb0ef41Sopenharmony_ci                                tiltX, tiltY, twist, altitudeAngle, azimuthAngle) {
4651cb0ef41Sopenharmony_ci    if (width) {
4661cb0ef41Sopenharmony_ci      action.width = width;
4671cb0ef41Sopenharmony_ci    }
4681cb0ef41Sopenharmony_ci    if (height) {
4691cb0ef41Sopenharmony_ci      action.height = height;
4701cb0ef41Sopenharmony_ci    }
4711cb0ef41Sopenharmony_ci    if (pressure) {
4721cb0ef41Sopenharmony_ci      action.pressure = pressure;
4731cb0ef41Sopenharmony_ci    }
4741cb0ef41Sopenharmony_ci    if (tangentialPressure) {
4751cb0ef41Sopenharmony_ci      action.tangentialPressure = tangentialPressure;
4761cb0ef41Sopenharmony_ci    }
4771cb0ef41Sopenharmony_ci    if (tiltX) {
4781cb0ef41Sopenharmony_ci      action.tiltX = tiltX;
4791cb0ef41Sopenharmony_ci    }
4801cb0ef41Sopenharmony_ci    if (tiltY) {
4811cb0ef41Sopenharmony_ci      action.tiltY = tiltY;
4821cb0ef41Sopenharmony_ci    }
4831cb0ef41Sopenharmony_ci    if (twist) {
4841cb0ef41Sopenharmony_ci      action.twist = twist;
4851cb0ef41Sopenharmony_ci    }
4861cb0ef41Sopenharmony_ci    if (altitudeAngle) {
4871cb0ef41Sopenharmony_ci      action.altitudeAngle = altitudeAngle;
4881cb0ef41Sopenharmony_ci    }
4891cb0ef41Sopenharmony_ci    if (azimuthAngle) {
4901cb0ef41Sopenharmony_ci      action.azimuthAngle = azimuthAngle;
4911cb0ef41Sopenharmony_ci    }
4921cb0ef41Sopenharmony_ci    return action;
4931cb0ef41Sopenharmony_ci  }
4941cb0ef41Sopenharmony_ci
4951cb0ef41Sopenharmony_ci  PointerSource.prototype = {
4961cb0ef41Sopenharmony_ci    serialize: function(tickCount) {
4971cb0ef41Sopenharmony_ci      if (!this.actions.size) {
4981cb0ef41Sopenharmony_ci        return undefined;
4991cb0ef41Sopenharmony_ci      }
5001cb0ef41Sopenharmony_ci      let actions = [];
5011cb0ef41Sopenharmony_ci      let data = {"type": "pointer", "actions": actions, "parameters": {"pointerType": this.type}};
5021cb0ef41Sopenharmony_ci      for (let i=0; i<tickCount; i++) {
5031cb0ef41Sopenharmony_ci        if (this.actions.has(i)) {
5041cb0ef41Sopenharmony_ci          actions.push(this.actions.get(i));
5051cb0ef41Sopenharmony_ci        } else {
5061cb0ef41Sopenharmony_ci          actions.push({"type": "pause"});
5071cb0ef41Sopenharmony_ci        }
5081cb0ef41Sopenharmony_ci      }
5091cb0ef41Sopenharmony_ci      return data;
5101cb0ef41Sopenharmony_ci    },
5111cb0ef41Sopenharmony_ci
5121cb0ef41Sopenharmony_ci    pointerDown: function(actions, button, width, height, pressure, tangentialPressure,
5131cb0ef41Sopenharmony_ci                          tiltX, tiltY, twist, altitudeAngle, azimuthAngle) {
5141cb0ef41Sopenharmony_ci      let tick = actions.tickIdx;
5151cb0ef41Sopenharmony_ci      if (this.actions.has(tick)) {
5161cb0ef41Sopenharmony_ci        tick = actions.addTick().tickIdx;
5171cb0ef41Sopenharmony_ci      }
5181cb0ef41Sopenharmony_ci      let actionProperties = setPointerProperties({type: "pointerDown", button}, width, height,
5191cb0ef41Sopenharmony_ci                                                  pressure, tangentialPressure, tiltX, tiltY,
5201cb0ef41Sopenharmony_ci                                                  twist, altitudeAngle, azimuthAngle);
5211cb0ef41Sopenharmony_ci      this.actions.set(tick, actionProperties);
5221cb0ef41Sopenharmony_ci    },
5231cb0ef41Sopenharmony_ci
5241cb0ef41Sopenharmony_ci    pointerUp: function(actions, button) {
5251cb0ef41Sopenharmony_ci      let tick = actions.tickIdx;
5261cb0ef41Sopenharmony_ci      if (this.actions.has(tick)) {
5271cb0ef41Sopenharmony_ci        tick = actions.addTick().tickIdx;
5281cb0ef41Sopenharmony_ci      }
5291cb0ef41Sopenharmony_ci      this.actions.set(tick, {type: "pointerUp", button});
5301cb0ef41Sopenharmony_ci    },
5311cb0ef41Sopenharmony_ci
5321cb0ef41Sopenharmony_ci    pointerMove: function(actions, x, y, duration, origin, width, height, pressure,
5331cb0ef41Sopenharmony_ci                          tangentialPressure, tiltX, tiltY, twist, altitudeAngle, azimuthAngle) {
5341cb0ef41Sopenharmony_ci      let tick = actions.tickIdx;
5351cb0ef41Sopenharmony_ci      if (this.actions.has(tick)) {
5361cb0ef41Sopenharmony_ci        tick = actions.addTick().tickIdx;
5371cb0ef41Sopenharmony_ci      }
5381cb0ef41Sopenharmony_ci      let moveAction = {type: "pointerMove", x, y, origin};
5391cb0ef41Sopenharmony_ci      if (duration) {
5401cb0ef41Sopenharmony_ci        moveAction.duration = duration;
5411cb0ef41Sopenharmony_ci      }
5421cb0ef41Sopenharmony_ci      let actionProperties = setPointerProperties(moveAction, width, height, pressure,
5431cb0ef41Sopenharmony_ci                                                  tangentialPressure, tiltX, tiltY, twist,
5441cb0ef41Sopenharmony_ci                                                  altitudeAngle, azimuthAngle);
5451cb0ef41Sopenharmony_ci      this.actions.set(tick, actionProperties);
5461cb0ef41Sopenharmony_ci    },
5471cb0ef41Sopenharmony_ci
5481cb0ef41Sopenharmony_ci    addPause: function(actions, duration) {
5491cb0ef41Sopenharmony_ci      let tick = actions.tickIdx;
5501cb0ef41Sopenharmony_ci      if (this.actions.has(tick)) {
5511cb0ef41Sopenharmony_ci        tick = actions.addTick().tickIdx;
5521cb0ef41Sopenharmony_ci      }
5531cb0ef41Sopenharmony_ci      this.actions.set(tick, {type: "pause", duration: duration});
5541cb0ef41Sopenharmony_ci    },
5551cb0ef41Sopenharmony_ci  };
5561cb0ef41Sopenharmony_ci
5571cb0ef41Sopenharmony_ci  function WheelSource() {
5581cb0ef41Sopenharmony_ci    this.actions = new Map();
5591cb0ef41Sopenharmony_ci  }
5601cb0ef41Sopenharmony_ci
5611cb0ef41Sopenharmony_ci  WheelSource.prototype = {
5621cb0ef41Sopenharmony_ci    serialize: function(tickCount) {
5631cb0ef41Sopenharmony_ci      if (!this.actions.size) {
5641cb0ef41Sopenharmony_ci        return undefined;
5651cb0ef41Sopenharmony_ci      }
5661cb0ef41Sopenharmony_ci      let actions = [];
5671cb0ef41Sopenharmony_ci      let data = {"type": "wheel", "actions": actions};
5681cb0ef41Sopenharmony_ci      for (let i=0; i<tickCount; i++) {
5691cb0ef41Sopenharmony_ci        if (this.actions.has(i)) {
5701cb0ef41Sopenharmony_ci          actions.push(this.actions.get(i));
5711cb0ef41Sopenharmony_ci        } else {
5721cb0ef41Sopenharmony_ci          actions.push({"type": "pause"});
5731cb0ef41Sopenharmony_ci        }
5741cb0ef41Sopenharmony_ci      }
5751cb0ef41Sopenharmony_ci      return data;
5761cb0ef41Sopenharmony_ci    },
5771cb0ef41Sopenharmony_ci
5781cb0ef41Sopenharmony_ci    scroll: function(actions, x, y, deltaX, deltaY, duration, origin) {
5791cb0ef41Sopenharmony_ci      let tick = actions.tickIdx;
5801cb0ef41Sopenharmony_ci      if (this.actions.has(tick)) {
5811cb0ef41Sopenharmony_ci        tick = actions.addTick().tickIdx;
5821cb0ef41Sopenharmony_ci      }
5831cb0ef41Sopenharmony_ci      this.actions.set(tick, {type: "scroll", x, y, deltaX, deltaY, origin});
5841cb0ef41Sopenharmony_ci      if (duration) {
5851cb0ef41Sopenharmony_ci        this.actions.get(tick).duration = duration;
5861cb0ef41Sopenharmony_ci      }
5871cb0ef41Sopenharmony_ci    },
5881cb0ef41Sopenharmony_ci
5891cb0ef41Sopenharmony_ci    addPause: function(actions, duration) {
5901cb0ef41Sopenharmony_ci      let tick = actions.tickIdx;
5911cb0ef41Sopenharmony_ci      if (this.actions.has(tick)) {
5921cb0ef41Sopenharmony_ci        tick = actions.addTick().tickIdx;
5931cb0ef41Sopenharmony_ci      }
5941cb0ef41Sopenharmony_ci      this.actions.set(tick, {type: "pause", duration: duration});
5951cb0ef41Sopenharmony_ci    },
5961cb0ef41Sopenharmony_ci  };
5971cb0ef41Sopenharmony_ci
5981cb0ef41Sopenharmony_ci  test_driver.Actions = Actions;
5991cb0ef41Sopenharmony_ci})();
600