Source: Input/HtmlGamepad/AxHtmlGamepadInputDevice.js

/**
 * Create a new AxGamepadInputDevice.
 * This input device uses an Html Canvas element to obtain user input from
 * @constructor
*/
function AxHtmlGamepadInputDevice()
{
    AxInputDevice.call(this);

    this.context = null;
    this.gamepadsProperties = new AxDictionary();
}

AxHtmlGamepadInputDevice.prototype = Object.create(AxInputDevice.prototype);


/**
 * Sets the context for the input device
 * @param {Axis} context The instance of Axis, to which the input device will apply
 */
AxHtmlGamepadInputDevice.prototype.SetContext = function(context)
{
    this.context = context;
    
    this.AcquireGamepadProperties(0);
    this.AcquireGamepadProperties(1);
    this.AcquireGamepadProperties(2);
    this.AcquireGamepadProperties(3);
    
    window.axGamepadInputDevice = this;
    window.addEventListener("gamepadconnected", AxHtmlGamepadInputDevice.OnGamepadConnected);
    window.addEventListener("gamepaddisconnected", AxHtmlGamepadInputDevice.OnGamepadDisconnected);
};

/**
 * Updates the device.
 * This method is called continuously on each rendering iteration
 */
AxHtmlGamepadInputDevice.prototype.Update = function()
{
    var gamepadsList = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads : []);
    if (gamepadsList === null)
        return;
    
    for (var gamepadIndex = 0; gamepadIndex < gamepadsList.length; gamepadIndex++)
    {
        var gamepad = gamepadsList[gamepadIndex];
        if (gamepad !== null)
        {
            var isStandardMapping = gamepad.mapping === "standard";
                    
            var gamepadProperties = this.AcquireGamepadProperties(gamepad.index);
            gamepadProperties.padAvailable.SetBool(true);
            
            for (var buttonIndex = 0; buttonIndex < gamepad.buttons.length; buttonIndex++)
            {
                var keyProp = new AxReferenceParameter();
                if (gamepadProperties.keyProperties.GetValue(buttonIndex, keyProp))
                    AxHtmlGamepadInputDevice.SetPropertyButtonValue(keyProp.value, gamepad.buttons[buttonIndex]);
            }

           
            if (gamepad.axes.length > 1)
            {
                gamepadProperties.padAnalogXLeft.SetFloat(AxHtmlGamepadInputDevice.GetAxisValue(gamepad.axes[0]));
                gamepadProperties.padAnalogYLeft.SetFloat(-AxHtmlGamepadInputDevice.GetAxisValue(gamepad.axes[1]));
            }

            if (isStandardMapping)
            {
                if (gamepad.axes.length > 3)
                {
                    gamepadProperties.padAnalogXRight.SetFloat(AxHtmlGamepadInputDevice.GetAxisValue(gamepad.axes[2]));
                    gamepadProperties.padAnalogYRight.SetFloat(-AxHtmlGamepadInputDevice.GetAxisValue(gamepad.axes[3]));
                }
            }
            else
            {
                // Gamepad with no mapping might throw different stuff in different browser.
                // For example, multipe axes[] values mapped to the same hardware control, an axis containing value for d-pad, unmapped (zero) values in between
                // Example1: XBox360 controller, standard mapping: 0 - XLeft, 1 -YLeft, 2 - XRight, 3 - YRight
                // Example2: 0079-0006-Generic USB Joystick, no mapping, Firefox: 0 - XLeft, 1 -YLeft, 2 - XRight, 3 - XRight, 4 - YRight
                // Example3: 0079-0006-Generic USB Joystick, no mapping, Chrome: 0 - XLeft, 1 -YLeft, 2 - XRight, 3 - 0, 4 - 0, 5 - YRight, 6 - 0, 7 - 0, 8 - 0, 9 - DPad (Up: -1, Right: -0.43, Down: -0.14, Left: 0.71, None: 3.28);
                var axisIndex = 2;
                var xAxis = 0.0;
                var yAxis = xAxis;
                if (gamepadProperties.padAnalogXRightIndex === -1)
                {
                    for (axisIndex = 2; axisIndex < gamepad.axes.length; axisIndex++)
                    {
                        if (gamepad.axes[axisIndex] !== 0.0)
                        {
                            gamepadProperties.padAnalogXRightIndex = axisIndex;
                            xAxis = gamepad.axes[axisIndex];
                            break;
                        }
                    }
                }
                else
                    xAxis = gamepad.axes[gamepadProperties.padAnalogXRightIndex];

                if (gamepadProperties.padAnalogYRightIndex === -1)
                {
                    for (axisIndex++; axisIndex < gamepad.axes.length; axisIndex++)
                    {
                        var axisValue = gamepad.axes[axisIndex];
                        //var axesActive = (AxMath.Abs(xAxis) > 0.3) && (AxMath.Abs(xAxis) < 0.7) && (AxMath.Abs(axisValue) > 0.3) && (AxMath.Abs(axisValue) < 0.7);
                        var bothAxesActive = (AxMath.Abs(xAxis) > 0.3) && (AxMath.Abs(axisValue) > 0.3);
                        if ((axisValue !== 0.0) && (!bothAxesActive || (axisValue !== xAxis)))
                        {
                            if (bothAxesActive)
                                gamepadProperties.padAnalogYRightIndex = axisIndex;
                            yAxis = axisValue;
                            break;
                        }
                    }
                }
                else
                    yAxis = gamepad.axes[gamepadProperties.padAnalogYRightIndex];
                
                gamepadProperties.padAnalogXRight.SetFloat(AxHtmlGamepadInputDevice.GetAxisValue(xAxis));
                gamepadProperties.padAnalogYRight.SetFloat(-AxHtmlGamepadInputDevice.GetAxisValue(yAxis));
            }
        }
    }
};

/**
 * Acquires an object which holds properties for a given gamepad
 * For internal usage
 * @param {Integer} gamepadIndex The index of the gamepad
 * @returns {AxHtmlGamepadProperties}
 */
AxHtmlGamepadInputDevice.prototype.AcquireGamepadProperties = function(gamepadIndex)
{
    var keyProp = new AxReferenceParameter();
    if (this.gamepadsProperties.GetValue(gamepadIndex, keyProp))
        return keyProp.value;
    
    var gamepadProperties = new AxHtmlGamepadProperties();
    
    var idName = gamepadIndex === 0 ? "" : (gamepadIndex + 1).toString() + " ";

    gamepadProperties.keyProperties.Add(0, this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "A"), false)));
	gamepadProperties.keyProperties.Add(1, this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "B"), false)));
	gamepadProperties.keyProperties.Add(2, this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "X"), false)));
	gamepadProperties.keyProperties.Add(3, this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Y"), false)));
	gamepadProperties.keyProperties.Add(4, this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Trigger button left"), false)));
	gamepadProperties.keyProperties.Add(5, this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Trigger button right"), false)));
	gamepadProperties.keyProperties.Add(6, this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Trigger analog left"), 0.0)));
	gamepadProperties.keyProperties.Add(7, this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Trigger analog right"), 0.0)));
	gamepadProperties.keyProperties.Add(8, this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Select"), false)));
	gamepadProperties.keyProperties.Add(9, this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Start"), false)));
	gamepadProperties.keyProperties.Add(10, this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Thumb left"), true)));
	gamepadProperties.keyProperties.Add(11, this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Thumb right"), false)));
	gamepadProperties.keyProperties.Add(12, this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Up"), false)));
	gamepadProperties.keyProperties.Add(13, this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Down"), false)));
	gamepadProperties.keyProperties.Add(14, this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Left"), false)));
	gamepadProperties.keyProperties.Add(15, this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Right"), false)));

    gamepadProperties.padAnalogXLeft            = this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Analog X left"), 0.0));
	gamepadProperties.padAnalogYLeft            = this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Analog Y left"), 0.0));
	gamepadProperties.padAnalogXRight			= this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Analog X right"), 0.0));
	gamepadProperties.padAnalogYRight			= this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Analog Y right"), 0.0));
	gamepadProperties.padAvailable              = this.context.input.properties.Add(new AxProperty(new AxString("Pad " + idName + "Available"), false));
    
    this.gamepadsProperties.Add(gamepadIndex, gamepadProperties);
    
    return gamepadProperties;
};




// Static methods



/**
 * Returns the floating point value of an axis by eliminating small values, which appear when the axis control is actually at rest
 * The returned value is in the range [-1, 1]
 * For internal usage
 * @param {type} rawValue The original value of the analog axis
 * @returns {Number} The filtered value in the range [-1, 1] of the analog axis
 */
AxHtmlGamepadInputDevice.GetAxisValue = function(rawValue)
{
	var threshold = 0.2;
	var range = 1.0;
	var usedRange = range - threshold;

	return rawValue > threshold ? (rawValue - threshold) / usedRange : rawValue < -threshold ? (rawValue + threshold) / usedRange : 0.0;
};

AxHtmlGamepadInputDevice.FindNextUsableAxisIndex = function(axes, startIndex, initial)
{
    var axesLength = axes.length;
    if (startIndex < axesLength)
    {
        var initialValue = axes[startIndex];
        for (var i = startIndex; i < axesLength; i++)
        {
            var axisValue = axes[i];
            if ((axisValue !== 0.0) && (initial || (axisValue !== initialValue)))
                return i;
        }
    }
    
    return startIndex;
};

/**
 * Sets an AxProperty value according to the value of a gamepad button 
 * For internal usage
 * @param {AxProperty} prop The property to be set
 * @param {type} button The button value to be used
 */
AxHtmlGamepadInputDevice.SetPropertyButtonValue = function(prop, button)
{
    if (typeof button === "object")
    {
        if (prop.type === AxParameterType.Bool)
            prop.SetBool(button.pressed);
        else
            prop.SetFloat(button.value);
    }
    else
    {
        if (prop.type === AxParameterType.Bool)
            prop.SetBool(button);
        else
            prop.SetFloat(button);
    }
};
        

AxHtmlGamepadInputDevice.OnGamepadConnected = function(args)
{
    var instance = this.axGamepadInputDevice;
    
    //console.log("Gamepad " + args.gamepad.id + " connected.");
};

AxHtmlGamepadInputDevice.OnGamepadDisconnected = function(args)
{
    var instance = this.axGamepadInputDevice;

    //console.log("Gamepad " + args.gamepad.id + " disconnected.");
};



/**
 * Creates an AxHtmlGamepadProperties object, used to hold the input properties for a gamepad device
 * For internal usage
 * @constructor
*/
function AxHtmlGamepadProperties()
{
    this.keyProperties = new AxDictionary();

    this.padAnalogXLeft = null;
	this.padAnalogYLeft = null;
	this.padAnalogXRight = null;
	this.padAnalogYRight = null;
	this.padTriggerAnalogLeft = null;
	this.padTriggerAnalogRight = null;
    
	// Used for determining the indices of the right thumbstick axes for non-standard gamapad mappings
    this.padAnalogXRightIndex = -1;
	this.padAnalogYRightIndex = -1;
}

Documentation generated by JSDoc 3.5.3 on Mon Feb 19 2018 20:39:26 GMT+0200 (FLE Standard Time)