phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers.
408 lines (354 loc) • 13.1 kB
JavaScript
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2020 Photon Storm Ltd.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var Class = require('../../utils/Class');
var InputEvents = require('../events');
var NOOP = require('../../utils/NOOP');
// https://developer.mozilla.org/en-US/docs/Web/API/Touch_events
// https://patrickhlauke.github.io/touch/tests/results/
// https://www.html5rocks.com/en/mobile/touch/
/**
* @classdesc
* The Touch Manager is a helper class that belongs to the Input Manager.
*
* Its role is to listen for native DOM Touch Events and then pass them onto the Input Manager for further processing.
*
* You do not need to create this class directly, the Input Manager will create an instance of it automatically.
*
* @class TouchManager
* @memberof Phaser.Input.Touch
* @constructor
* @since 3.0.0
*
* @param {Phaser.Input.InputManager} inputManager - A reference to the Input Manager.
*/
var TouchManager = new Class({
initialize:
function TouchManager (inputManager)
{
/**
* A reference to the Input Manager.
*
* @name Phaser.Input.Touch.TouchManager#manager
* @type {Phaser.Input.InputManager}
* @since 3.0.0
*/
this.manager = inputManager;
/**
* If true the DOM events will have event.preventDefault applied to them, if false they will propagate fully.
*
* @name Phaser.Input.Touch.TouchManager#capture
* @type {boolean}
* @default true
* @since 3.0.0
*/
this.capture = true;
/**
* A boolean that controls if the Touch Manager is enabled or not.
* Can be toggled on the fly.
*
* @name Phaser.Input.Touch.TouchManager#enabled
* @type {boolean}
* @default false
* @since 3.0.0
*/
this.enabled = false;
/**
* The Touch Event target, as defined in the Game Config.
* Typically the canvas to which the game is rendering, but can be any interactive DOM element.
*
* @name Phaser.Input.Touch.TouchManager#target
* @type {any}
* @since 3.0.0
*/
this.target;
/**
* The Touch Start event handler function.
* Initially empty and bound in the `startListeners` method.
*
* @name Phaser.Input.Touch.TouchManager#onTouchStart
* @type {function}
* @since 3.0.0
*/
this.onTouchStart = NOOP;
/**
* The Touch Start event handler function specifically for events on the Window.
* Initially empty and bound in the `startListeners` method.
*
* @name Phaser.Input.Touch.TouchManager#onTouchStartWindow
* @type {function}
* @since 3.17.0
*/
this.onTouchStartWindow = NOOP;
/**
* The Touch Move event handler function.
* Initially empty and bound in the `startListeners` method.
*
* @name Phaser.Input.Touch.TouchManager#onTouchMove
* @type {function}
* @since 3.0.0
*/
this.onTouchMove = NOOP;
/**
* The Touch End event handler function.
* Initially empty and bound in the `startListeners` method.
*
* @name Phaser.Input.Touch.TouchManager#onTouchEnd
* @type {function}
* @since 3.0.0
*/
this.onTouchEnd = NOOP;
/**
* The Touch End event handler function specifically for events on the Window.
* Initially empty and bound in the `startListeners` method.
*
* @name Phaser.Input.Touch.TouchManager#onTouchEndWindow
* @type {function}
* @since 3.17.0
*/
this.onTouchEndWindow = NOOP;
/**
* The Touch Cancel event handler function.
* Initially empty and bound in the `startListeners` method.
*
* @name Phaser.Input.Touch.TouchManager#onTouchCancel
* @type {function}
* @since 3.15.0
*/
this.onTouchCancel = NOOP;
/**
* The Touch Cancel event handler function specifically for events on the Window.
* Initially empty and bound in the `startListeners` method.
*
* @name Phaser.Input.Touch.TouchManager#onTouchCancelWindow
* @type {function}
* @since 3.18.0
*/
this.onTouchCancelWindow = NOOP;
/**
* The Touch Over event handler function.
* Initially empty and bound in the `startListeners` method.
*
* @name Phaser.Input.Touch.TouchManager#onTouchOver
* @type {function}
* @since 3.16.0
*/
this.onTouchOver = NOOP;
/**
* The Touch Out event handler function.
* Initially empty and bound in the `startListeners` method.
*
* @name Phaser.Input.Touch.TouchManager#onTouchOut
* @type {function}
* @since 3.16.0
*/
this.onTouchOut = NOOP;
inputManager.events.once(InputEvents.MANAGER_BOOT, this.boot, this);
},
/**
* The Touch Manager boot process.
*
* @method Phaser.Input.Touch.TouchManager#boot
* @private
* @since 3.0.0
*/
boot: function ()
{
var config = this.manager.config;
this.enabled = config.inputTouch;
this.target = config.inputTouchEventTarget;
this.capture = config.inputTouchCapture;
if (!this.target)
{
this.target = this.manager.game.canvas;
}
if (config.disableContextMenu)
{
this.disableContextMenu();
}
if (this.enabled && this.target)
{
this.startListeners();
}
},
/**
* Attempts to disable the context menu from appearing if you touch-hold on the browser.
*
* Works by listening for the `contextmenu` event and prevent defaulting it.
*
* Use this if you need to disable the OS context menu on mobile.
*
* @method Phaser.Input.Touch.TouchManager#disableContextMenu
* @since 3.20.0
*
* @return {this} This Touch Manager instance.
*/
disableContextMenu: function ()
{
document.body.addEventListener('contextmenu', function (event)
{
event.preventDefault();
return false;
});
return this;
},
/**
* Starts the Touch Event listeners running as long as an input target is set.
*
* This method is called automatically if Touch Input is enabled in the game config,
* which it is by default. However, you can call it manually should you need to
* delay input capturing until later in the game.
*
* @method Phaser.Input.Touch.TouchManager#startListeners
* @since 3.0.0
*/
startListeners: function ()
{
var _this = this;
var canvas = this.manager.canvas;
var autoFocus = (window && window.focus && this.manager.game.config.autoFocus);
this.onTouchStart = function (event)
{
if (autoFocus)
{
window.focus();
}
if (!event.defaultPrevented && _this.enabled && _this.manager && _this.manager.enabled)
{
_this.manager.onTouchStart(event);
if (_this.capture && event.cancelable && event.target === canvas)
{
event.preventDefault();
}
}
};
this.onTouchStartWindow = function (event)
{
if (!event.defaultPrevented && _this.enabled && _this.manager && _this.manager.enabled && event.target !== canvas)
{
// Only process the event if the target isn't the canvas
_this.manager.onTouchStart(event);
}
};
this.onTouchMove = function (event)
{
if (!event.defaultPrevented && _this.enabled && _this.manager && _this.manager.enabled)
{
_this.manager.onTouchMove(event);
if (_this.capture && event.cancelable)
{
event.preventDefault();
}
}
};
this.onTouchEnd = function (event)
{
if (!event.defaultPrevented && _this.enabled && _this.manager && _this.manager.enabled)
{
_this.manager.onTouchEnd(event);
if (_this.capture && event.cancelable && event.target === canvas)
{
event.preventDefault();
}
}
};
this.onTouchEndWindow = function (event)
{
if (!event.defaultPrevented && _this.enabled && _this.manager && _this.manager.enabled && event.target !== canvas)
{
// Only process the event if the target isn't the canvas
_this.manager.onTouchEnd(event);
}
};
this.onTouchCancel = function (event)
{
if (!event.defaultPrevented && _this.enabled && _this.manager && _this.manager.enabled)
{
_this.manager.onTouchCancel(event);
if (_this.capture)
{
event.preventDefault();
}
}
};
this.onTouchCancelWindow = function (event)
{
if (!event.defaultPrevented && _this.enabled && _this.manager && _this.manager.enabled)
{
_this.manager.onTouchCancel(event);
}
};
this.onTouchOver = function (event)
{
if (!event.defaultPrevented && _this.enabled && _this.manager && _this.manager.enabled)
{
_this.manager.setCanvasOver(event);
}
};
this.onTouchOut = function (event)
{
if (!event.defaultPrevented && _this.enabled && _this.manager && _this.manager.enabled)
{
_this.manager.setCanvasOut(event);
}
};
var target = this.target;
if (!target)
{
return;
}
var passive = { passive: true };
var nonPassive = { passive: false };
target.addEventListener('touchstart', this.onTouchStart, (this.capture) ? nonPassive : passive);
target.addEventListener('touchmove', this.onTouchMove, (this.capture) ? nonPassive : passive);
target.addEventListener('touchend', this.onTouchEnd, (this.capture) ? nonPassive : passive);
target.addEventListener('touchcancel', this.onTouchCancel, (this.capture) ? nonPassive : passive);
target.addEventListener('touchover', this.onTouchOver, (this.capture) ? nonPassive : passive);
target.addEventListener('touchout', this.onTouchOut, (this.capture) ? nonPassive : passive);
if (window && this.manager.game.config.inputWindowEvents)
{
window.addEventListener('touchstart', this.onTouchStartWindow, nonPassive);
window.addEventListener('touchend', this.onTouchEndWindow, nonPassive);
window.addEventListener('touchcancel', this.onTouchCancelWindow, nonPassive);
}
this.enabled = true;
},
/**
* Stops the Touch Event listeners.
* This is called automatically and does not need to be manually invoked.
*
* @method Phaser.Input.Touch.TouchManager#stopListeners
* @since 3.0.0
*/
stopListeners: function ()
{
var target = this.target;
target.removeEventListener('touchstart', this.onTouchStart);
target.removeEventListener('touchmove', this.onTouchMove);
target.removeEventListener('touchend', this.onTouchEnd);
target.removeEventListener('touchcancel', this.onTouchCancel);
target.removeEventListener('touchover', this.onTouchOver);
target.removeEventListener('touchout', this.onTouchOut);
if (window)
{
window.removeEventListener('touchstart', this.onTouchStartWindow);
window.removeEventListener('touchend', this.onTouchEndWindow);
}
},
/**
* Destroys this Touch Manager instance.
*
* @method Phaser.Input.Touch.TouchManager#destroy
* @since 3.0.0
*/
destroy: function ()
{
this.stopListeners();
this.target = null;
this.enabled = false;
this.manager = null;
}
});
module.exports = TouchManager;