├── .gitignore ├── .jshintrc ├── .node-version ├── .npmignore ├── LICENSE ├── bower.json ├── demo ├── package.json ├── play.html ├── play.js └── play.webpack.config.js ├── docs ├── 4-ways.png ├── 8-ways.png ├── axial.png ├── horizontal.png ├── none.png ├── radial.png └── vertical.png ├── package.json ├── readme.md ├── src ├── deadzones.js ├── get-mapping.js ├── index.js └── mapping.json └── tests ├── mapping-tests.js └── visual.html /.gitignore: -------------------------------------------------------------------------------- 1 | /lib/ 2 | node_modules 3 | .DS_Store 4 | bower_componentsplay.bundled.js 5 | demo/play.bundled.js 6 | npm-debug.log 7 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "camelcase": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "forin": true, 7 | "freeze": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": true, 11 | "noempty": true, 12 | "nonew": true, 13 | "nonbsp": true, 14 | "plusplus": true, 15 | "quotmark": "single", 16 | "undef": true, 17 | "unused": true, 18 | "strict": true, 19 | "maxparams": false, 20 | "maxdepth": 2, 21 | "maxcomplexity": 5, 22 | "esversion": 6, 23 | "node": true, 24 | "globals": { 25 | "describe": false, 26 | "it": false, 27 | "beforeEach": false, 28 | "afterEach": false, 29 | "before": false, 30 | "after": false, 31 | "Modernizr": false 32 | } 33 | } -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 4.2.4 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /src/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bower-for-visual-test", 3 | "private": true, 4 | "version": "0.0.0", 5 | "homepage": "https://github.com/ensemblejs/gamepad-api-mappings", 6 | "authors": ["Ryan Boucher "], 7 | "license": "MIT", 8 | "ignore": [ 9 | "**/.*", 10 | "node_modules", 11 | "bower_components", 12 | "test", 13 | "tests" 14 | ], 15 | "dependencies": { 16 | "c3": "~0.4.10" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo-gamepad-api-mappings", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "A demo project for gamepad-api-mappings", 6 | "scripts": { 7 | "start": "webpack --config ./play.webpack.config.js" 8 | }, 9 | "devDependencies": { 10 | "gamepad-api-mappings": "latest", 11 | "webpack": "^3.3.0" 12 | }, 13 | "author": "Gaspard Beernaert", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/ensemblejs/gamepad-api-mappings/issues" 17 | }, 18 | "homepage": "https://github.com/ensemblejs/gamepad-api-mappings" 19 | } 20 | -------------------------------------------------------------------------------- /demo/play.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | play 6 | 7 | 8 | 9 |

10 |   
11 | 
12 | 


--------------------------------------------------------------------------------
/demo/play.js:
--------------------------------------------------------------------------------
 1 | import {getMapping} from '../src/index.js';
 2 | 
 3 | let $d = document.createElement('div'); // fake, overwritten
 4 | 
 5 | 
 6 | window.addEventListener('load', () =>{
 7 |   $d = document.querySelector('#debug');
 8 |   debug('waiting for gamepad...');
 9 | 
10 |   let check = setInterval(() => {
11 |     let gamepads = window.navigator.getGamepads();
12 |     if (!gamepads.length) return; //ffox no gamepad
13 |     if (gamepads[0] === null) return; // chrome no gamepaD
14 |     clearInterval(check);
15 |     debug('gamepad detected !');
16 |     gmap();
17 |   }, 1000);
18 | 
19 | });
20 | 
21 | const debug = (text) => {
22 |   const $line = document.createElement('div');
23 |   $line.innerText = text;
24 |   $d.appendChild($line);
25 | };
26 | 
27 | const gmap = () => {
28 |   let gamepad = window.navigator.getGamepads()[0];
29 |   const deadZonesTable = [];
30 |   console.log(gamepad);
31 | 
32 |   let deviceMap = getMapping(gamepad.id, gamepad.mapping);
33 |   let deadZones = deadZonesTable[deviceMap.deadZone];
34 |   console.log(deviceMap)
35 |   listen();
36 | };
37 | 
38 | const listen = () => {
39 |   let gamepad = window.navigator.getGamepads()[0];
40 |   let deviceMap = getMapping(gamepad.id, gamepad.mapping);
41 |   gamepad.buttons.forEach((b, i)=>{
42 |     if (b.pressed === true) {
43 |       debug(`${deviceMap.buttons[i]} is down`);
44 |     }
45 |   });
46 |   setTimeout(()=>listen(), 200);
47 | };
48 | 


--------------------------------------------------------------------------------
/demo/play.webpack.config.js:
--------------------------------------------------------------------------------
 1 | var path = require('path');
 2 | 
 3 | module.exports = {
 4 |   entry: './play.js',
 5 |   output: {
 6 |     filename: 'play.bundled.js',
 7 |     path: path.resolve(__dirname, './')
 8 |   }
 9 | };
10 | 


--------------------------------------------------------------------------------
/docs/4-ways.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ensemblejs/gamepad-api-mappings/528d8bbf67717232b5b622a8344e2276a7242258/docs/4-ways.png


--------------------------------------------------------------------------------
/docs/8-ways.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ensemblejs/gamepad-api-mappings/528d8bbf67717232b5b622a8344e2276a7242258/docs/8-ways.png


--------------------------------------------------------------------------------
/docs/axial.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ensemblejs/gamepad-api-mappings/528d8bbf67717232b5b622a8344e2276a7242258/docs/axial.png


--------------------------------------------------------------------------------
/docs/horizontal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ensemblejs/gamepad-api-mappings/528d8bbf67717232b5b622a8344e2276a7242258/docs/horizontal.png


--------------------------------------------------------------------------------
/docs/none.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ensemblejs/gamepad-api-mappings/528d8bbf67717232b5b622a8344e2276a7242258/docs/none.png


--------------------------------------------------------------------------------
/docs/radial.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ensemblejs/gamepad-api-mappings/528d8bbf67717232b5b622a8344e2276a7242258/docs/radial.png


--------------------------------------------------------------------------------
/docs/vertical.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ensemblejs/gamepad-api-mappings/528d8bbf67717232b5b622a8344e2276a7242258/docs/vertical.png


--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "gamepad-api-mappings",
 3 |   "version": "4.1.0",
 4 |   "description": "A package for mapping browser gamepad configurations",
 5 |   "main": "lib/index.js",
 6 |   "repository": {
 7 |     "type": "git",
 8 |     "url": "https://github.com/ensemblejs/gamepad-api-mappings.git"
 9 |   },
10 |   "files": [
11 |     "lib/"
12 |   ],
13 |   "scripts": {
14 |     "pretest": "babel src --out-dir lib --copy-files",
15 |     "test": "mocha tests",
16 |     "prepublish": "babel src --out-dir lib --copy-files"
17 |   },
18 |   "babel": {
19 |     "presets": [
20 |       "es2015"
21 |     ]
22 |   },
23 |   "devDependencies": {
24 |     "babel-cli": "^6.4.0",
25 |     "babel-preset-es2015": "^6.3.13",
26 |     "babel-register": "^6.3.13",
27 |     "expect": "^1.13.4",
28 |     "mocha": "^2.4.5"
29 |   },
30 |   "keywords": [
31 |     "gamepad",
32 |     "api",
33 |     "browser",
34 |     "device",
35 |     "xbox",
36 |     "playstation",
37 |     "ps",
38 |     "wii",
39 |     "gamecube",
40 |     "nintendo",
41 |     "logitech",
42 |     "mapping",
43 |     "game",
44 |     "ensemble",
45 |     "ensemblejs"
46 |   ],
47 |   "author": "Ryan Boucher",
48 |   "license": "MIT",
49 |   "bugs": {
50 |     "url": "https://github.com/ensemblejs/gamepad-api-mappings/issues"
51 |   },
52 |   "homepage": "https://github.com/ensemblejs/gamepad-api-mappings"
53 | }
54 | 


--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
  1 | # gamepad-api-mappings
  2 | 
  3 | The Gamepad API has a standard mapping of axes and buttons. Not all browsers and devices align.
  4 | 
  5 | This library is for:
  6 |  - mapping the button and stick combinations onto common names
  7 |  - factoring in dead zones and adjusting the stick magnitude to suit your needs
  8 | 
  9 | This library is not about reading the input from the gamepad controllers. This library is after you've got the input and now you want to make sense of it but you're not sure what controller the player has nor do you know what browser the client is on.
 10 | 
 11 | # Usage
 12 | ~~~shell
 13 | npm i gamepad-api-mappings -S
 14 | ~~~
 15 | 
 16 | ## Get the map and deadzone information
 17 | ~~~javascript
 18 | import {getMapping} from 'gamepad-api-mappings';
 19 | 
 20 | let gamepads = window.navigator.getGamepads();
 21 | let gamepad = gamepads[0];
 22 | 
 23 | let deviceMap = getMapping(gamepad.id, gamepad.mapping);
 24 | let deadZones = deadZonesTable[deviceMap.deadZone];
 25 | ~~~
 26 | 
 27 | ## Considering Stick Deadzones
 28 | Deadzones are a way to ignore small input near the centre of the stick (or along an axis). This stops jittery movement when there are no fingers on the stick (human hands are good dampeners).
 29 | 
 30 | Included are different ways of factoring deadzones into getting the force. One was is to consider the two axes independently, this results in better snapping along the two axes. Another approach considers the axes as one and this results in a better circular dead zone.
 31 | 
 32 | This library has the following algorithms:
 33 | - axial (consider each axis independantly)
 34 | - radial (consider the two axis together)
 35 | - 8 way directional (constrain movement to 4 axes)
 36 | - 4 way directional (constrain movement to 2 axes)
 37 | - horizontal (constrain movement to the x-axis)
 38 | - vertical (constrain movement to y-axis)
 39 | 
 40 | ### axial deadzones
 41 | ~~~javascript
 42 | import {axialVector, axial, raw} from 'gamepad-api-mappings';
 43 | 
 44 | let force = axial(gamepad.buttons[0].value, deadZones['leftTrigger'], raw);
 45 | console.log(force);
 46 | let force2 = axialVector(gamepad.axes[0], deadZones['leftStick'], raw);
 47 | console.log(force2.x, force2.y);
 48 | ~~~
 49 | 
 50 | ![Axial](https://raw.githubusercontent.com/ensemblejs/gamepad-api-mappings/master/docs/axial.png)
 51 | 
 52 | ### radial deadzones
 53 | ~~~javascript
 54 | import {radial, raw} from 'gamepad-api-mappings';
 55 | 
 56 | const coord = {x: gamepad.axes[0], y: gamepad.axes[1]};
 57 | let force = radial(coord, deadZones['leftStick'], raw);
 58 | console.log(force.x, force.y);
 59 | ~~~
 60 | 
 61 | ![Radial](https://raw.githubusercontent.com/ensemblejs/gamepad-api-mappings/master/docs/radial.png)
 62 | 
 63 | ### 8 Way Directional
 64 | ~~~javascript
 65 | import {way8, normalise} from 'gamepad-api-mappings';
 66 | 
 67 | const coord = {x: gamepad.axes[0], y: gamepad.axes[1]};
 68 | let force = way8(coord, deadZones['leftStick'], normalise);
 69 | console.log(force.x, force.y);
 70 | ~~~
 71 | 
 72 | ![8 ways](https://raw.githubusercontent.com/ensemblejs/gamepad-api-mappings/master/docs/8-ways.png)
 73 | 
 74 | ### 4 Way Directional
 75 | ~~~javascript
 76 | import {way4, normalise} from 'gamepad-api-mappings';
 77 | 
 78 | const coord = {x: gamepad.axes[0], y: gamepad.axes[1]};
 79 | let force = way4(coord, deadZones['leftStick'], normalise);
 80 | console.log(force.x, force.y);
 81 | ~~~
 82 | 
 83 | ![4 ways](https://raw.githubusercontent.com/ensemblejs/gamepad-api-mappings/master/docs/4-ways.png)
 84 | 
 85 | ### Vertical
 86 | ~~~javascript
 87 | import {vertical, normalise} from 'gamepad-api-mappings';
 88 | 
 89 | const coord = {x: gamepad.axes[0], y: gamepad.axes[1]};
 90 | let force = vertical(coord, deadZones['leftStick'], normalise);
 91 | console.log(force.x, force.y);
 92 | ~~~
 93 | 
 94 | ![Vertical](https://raw.githubusercontent.com/ensemblejs/gamepad-api-mappings/master/docs/vertical.png)
 95 | 
 96 | ### Horizontal
 97 | ~~~javascript
 98 | import {horizontal, normalise} from 'gamepad-api-mappings';
 99 | 
100 | const coord = {x: gamepad.axes[0], y: gamepad.axes[1]};
101 | let force = horizontal(coord, deadZones['leftStick'], normalise);
102 | console.log(force.x, force.y);
103 | ~~~
104 | 
105 | ![Horiztonal](https://raw.githubusercontent.com/ensemblejs/gamepad-api-mappings/master/docs/horizontal.png)
106 | 
107 | 
108 | ## Post processing
109 | The problem with the functions above is that input is zero within the deadzone and then jumps to 0.2 or 0.25 or whatever the size of the dead zone is. The jump is but half of it. With a dead zone of 0.25 we are losing a quarter of the resolution.
110 | 
111 | This library allows you to pass a function into the algorithms above and adjust the magnitude to suit your game's needs.
112 | 
113 | We have two mapping algorithms: `raw` and `normalised`. The raw version is in the examples above and does not change the output. Normalisation adjusts the remaining distance so it scales linearly after the dead zone from 0.0 to 1.0. You can supply your own function if it takes a scalar and returns one.
114 | 
115 | ~~~javascript
116 | import {radial, raw, normalise} from 'gamepad-api-mappings';
117 | 
118 | function myMagnitureAdjuster (scalar, deadzone) {
119 |   return scalar * deadzone;
120 | }
121 | 
122 | const coord = {x: 0.3, y: 0.9};
123 | const deadzone = 0.25;
124 | let rawPost = radial(coord, deadzone, raw);
125 | let normalisedPost = radial(coord, deadzone, normalise);
126 | let myFuncPost = radial(coord, deadzone, myMagnitureAdjuster);
127 | console.log(rawPost.x, rawPost.y);                //(0.30, 0.90)
128 | console.log(normalisedPost.x, normalisedPost.y);  //(0.07, 0.86)
129 | console.log(myFuncPost.x, myFuncPost.y);          //(0.08, 0.24)
130 | ~~~
131 | 
132 | An alias for `normalize` exists.
133 | 


--------------------------------------------------------------------------------
/src/deadzones.js:
--------------------------------------------------------------------------------
 1 | 'use strict';
 2 | 
 3 | export function raw (scalar) {
 4 |   return scalar;
 5 | }
 6 | 
 7 | export function normalise (scalar, deadzone = 0) {
 8 |   if (scalar === 0) {
 9 |     return scalar;
10 |   }
11 | 
12 |   let absScalar = Math.abs(scalar);
13 |   const normalised = (absScalar - deadzone) / (1 - deadzone);
14 | 
15 |   return scalar < 0 ? -normalised : normalised;
16 | }
17 | 
18 | export function axial (scalar, deadzone = 0, post = raw) {
19 |   let magnitude = Math.sqrt(scalar * scalar);
20 | 
21 |   if (magnitude <= deadzone) {
22 |     return 0;
23 |   }
24 | 
25 |   if (magnitude > 1) {
26 |     return (scalar < 0) ? -1 : 1;
27 |   }
28 | 
29 |   return (scalar < 0) ? -post(magnitude, deadzone) : post(magnitude, deadzone);
30 | }
31 | 
32 | export function radial (coord, deadzone = 0, post = raw) {
33 |   const angle = Math.atan2(coord.y, coord.x);
34 |   let magnitude = Math.sqrt(coord.x * coord.x + coord.y * coord.y);
35 | 
36 |   if (magnitude <= deadzone) {
37 |     return { x: 0, y: 0 };
38 |   }
39 | 
40 |   if (magnitude > 1) {
41 |     magnitude = 1;
42 |   }
43 | 
44 |   return {
45 |     x: Math.cos(angle) * post(magnitude, deadzone),
46 |     y: Math.sin(angle) * post(magnitude, deadzone)
47 |   };
48 | }
49 | 
50 | function snapToRadian (coord, deadzone, axes, post = raw) {
51 |   const angle = Math.atan2(coord.y, coord.x);
52 |   const snapRadians = Math.PI / axes;
53 |   const newAngle = snapRadians * Math.round(angle / snapRadians);
54 |   let magnitude = Math.sqrt(coord.x * coord.x + coord.y * coord.y);
55 | 
56 |   if (magnitude <= deadzone) {
57 |     return { x: 0, y: 0 };
58 |   }
59 | 
60 |   if (magnitude > 1) {
61 |     magnitude = 1;
62 |   }
63 | 
64 |   return {
65 |     x: Math.cos(newAngle) * post(magnitude, deadzone),
66 |     y: Math.sin(newAngle) * post(magnitude, deadzone)
67 |   };
68 | }
69 | 
70 | export function way8 (coord, deadzone = 0, post = raw) {
71 |   return snapToRadian(coord, deadzone, 4, post);
72 | }
73 | 
74 | export function way4 (coord, deadzone = 0, post = raw) {
75 |   return snapToRadian(coord, deadzone, 2, post);
76 | }
77 | 
78 | export function vertical (coord, deadzone, post = raw) {
79 |   return {
80 |     x: 0,
81 |     y: snapToRadian(coord, deadzone, 2, post).y
82 |   };
83 | }
84 | 
85 | export function horizontal (coord, deadzone, post = raw) {
86 |   return {
87 |     x: snapToRadian(coord, deadzone, 2, post).x,
88 |     y: 0
89 |   };
90 | }


--------------------------------------------------------------------------------
/src/get-mapping.js:
--------------------------------------------------------------------------------
 1 | 'use strict';
 2 | 
 3 | const mappingTable = require('./mapping.json');
 4 | 
 5 | export function getMapping (id, mapping) {
 6 | 
 7 |   var deviceMap = mappingTable[`${id}-${mapping}`];
 8 |   if (!deviceMap) {
 9 |     deviceMap = mappingTable[mapping];
10 |   }
11 |   if (!deviceMap) {
12 |     deviceMap = mappingTable.standard;
13 |   }
14 | 
15 |   return deviceMap;
16 | }
17 | 


--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
 1 | 'use strict';
 2 | 
 3 | export const getMapping = require('./get-mapping').getMapping;
 4 | export const deadZones = require('./mapping.json').deadZones;
 5 | 
 6 | export const raw = require('./deadzones').raw;
 7 | export const normalise = require('./deadzones').normalise;
 8 | export const normalize = require('./deadzones').normalise;
 9 | 
10 | export const axial = require('./deadzones').axial;
11 | export const radial = require('./deadzones').radial;
12 | export const way8 = require('./deadzones').way8;
13 | export const way4 = require('./deadzones').way4;
14 | export const vertical = require('./deadzones').vertical;
15 | export const horizontal = require('./deadzones').horizontal;
16 | 
17 | const postMapping = {
18 |   'raw': raw,
19 |   'normalised': normalise,
20 |   'normalized': normalize
21 | };
22 | 
23 | 
24 | export function axialVector (coord, deadzone, post) {
25 |   return {
26 |     x: axial(coord.x, deadzone, post),
27 |     y: axial(coord.y, deadzone, post),
28 |   };
29 | }
30 | 
31 | const algorithms = {
32 |   'axial': axialVector,
33 |   'radial': radial,
34 |   '8-way': way8,
35 |   '4-way': way4,
36 |   'horizontal': horizontal,
37 |   'vertical': vertical
38 | };
39 | 
40 | function build (algorithm, mapper = postMapping.normalised) {
41 |   return function applyAlgorithmAndMapping (coord, deadzone) {
42 |     return algorithm(coord, deadzone, mapper);
43 |   } ;
44 | }
45 | 
46 | export function getDeadzoneAlgorithm (algorithm, mapper) {
47 |   return build(algorithms[algorithm], postMapping[mapper]);
48 | }


--------------------------------------------------------------------------------
/src/mapping.json:
--------------------------------------------------------------------------------
  1 | {
  2 |   "deadZones": {
  3 |     "Xbox 360 Wired Controller": {
  4 |       "left-stick": 0.24,
  5 |       "right-stick": 0.27,
  6 |       "left-trigger": 0.12,
  7 |       "right-trigger": 0.12
  8 |     },
  9 |     "RetroLink": {
 10 |       "left-stick": 0.2,
 11 |       "right-stick": 0.2,
 12 |       "left-trigger": 0.1,
 13 |       "right-trigger": 0.1
 14 |     }
 15 |   },
 16 |   "Xbox 360 Wired Controller (STANDARD GAMEPAD Vendor: 045e Product: 028e)-standard": {
 17 |     "deadZone": "Xbox 360 Wired Controller",
 18 |     "axes": [
 19 |       {"id": "left-stick", "prop": "x"},
 20 |       {"id": "left-stick", "prop": "y"},
 21 |       {"id": "right-stick", "prop": "x"},
 22 |       {"id": "right-stick", "prop": "y"}
 23 |     ],
 24 |     "buttons": [
 25 |       "face-bottom",
 26 |       "face-right",
 27 |       "face-left",
 28 |       "face-top",
 29 |       "left-shoulder",
 30 |       "right-shoulder",
 31 |       "left-trigger",
 32 |       "right-trigger",
 33 |       "select-back",
 34 |       "start-forward",
 35 |       "left-stick-button",
 36 |       "right-stick-button",
 37 |       "up",
 38 |       "down",
 39 |       "left",
 40 |       "right",
 41 |       "home"
 42 |     ]
 43 |   },
 44 |   "45e-28e-Xbox 360 Wired Controller-": {
 45 |     "deadZone": "Xbox 360 Wired Controller",
 46 |     "axes": [
 47 |       {"id": "left-stick", "prop": "x"},
 48 |       {"id": "left-stick", "prop": "y"},
 49 |       {"id": "left-trigger"},
 50 |       {"id": "right-stick", "prop": "x"},
 51 |       {"id": "right-stick", "prop": "y"},
 52 |       {"id": "right-trigger"}
 53 |     ],
 54 |     "buttons": [
 55 |       "up",
 56 |       "down",
 57 |       "left",
 58 |       "right",
 59 |       "start-forward",
 60 |       "select-back",
 61 |       "left-stick-button",
 62 |       "right-stick-button",
 63 |       "left-shoulder",
 64 |       "right-shoulder",
 65 |       "home",
 66 |       "face-bottom",
 67 |       "face-right",
 68 |       "face-left",
 69 |       "face-top"
 70 |     ]
 71 |   },
 72 |   "Generic   USB  Joystick   (STANDARD GAMEPAD Vendor: 0079 Product: 0006)-standard": {
 73 |     "description": "RetroLink gamecube Controller",
 74 |     "deadZone": "RetroLink",
 75 |     "axes": [
 76 |       {"id": "right-stick", "prop": "x"},
 77 |       {"id": "right-stick", "prop": "y"},
 78 |       {"id": "left-stick", "prop": "x"},
 79 |       {"id": "left-stick", "prop": "y"}
 80 |     ],
 81 |     "buttons": [
 82 |       "face-top",
 83 |       "face-right",
 84 |       "face-bottom",
 85 |       "face-left",
 86 |       "left-trigger",
 87 |       "right-trigger",
 88 |       "right-shoulder",
 89 |       "unknown",
 90 |       "unknown",
 91 |       "home",
 92 |       "unknown",
 93 |       "unknown",
 94 |       "up",
 95 |       "down",
 96 |       "left",
 97 |       "right"
 98 |     ]
 99 |   },
100 |   "standard": {
101 |     "deadZone": "Xbox 360 Wired Controller",
102 |     "axes": [
103 |       {"id": "left-stick", "prop": "x"},
104 |       {"id": "left-stick", "prop": "y"},
105 |       {"id": "right-stick", "prop": "x"},
106 |       {"id": "right-stick", "prop": "y"}
107 |     ],
108 |     "buttons": [
109 |       "face-bottom",
110 |       "face-right",
111 |       "face-left",
112 |       "face-top",
113 |       "left-shoulder",
114 |       "right-shoulder",
115 |       "left-trigger",
116 |       "right-trigger",
117 |       "select-back",
118 |       "start-forward",
119 |       "left-stick-button",
120 |       "right-stick-button",
121 |       "up",
122 |       "down",
123 |       "left",
124 |       "right",
125 |       "home"
126 |     ]
127 |   }
128 | }
129 | 


--------------------------------------------------------------------------------
/tests/mapping-tests.js:
--------------------------------------------------------------------------------
 1 | 'use strict';
 2 | 
 3 | var expect = require('expect');
 4 | var raw = require('../lib/deadzones').raw;
 5 | var normalise = require('../lib/deadzones').normalise;
 6 | 
 7 | describe('raw results', function () {
 8 |   it('should return the supplied value.', function () {
 9 |     expect(raw(-1.0, 0.25)).toEqual(-1.0);
10 |     expect(raw(-0.75, 0.25)).toEqual(-0.75);
11 |     expect(raw(-0.5, 0.25)).toEqual(-0.5);
12 |     expect(raw(-0.26, 0.25)).toEqual(-0.26);
13 |     expect(raw(-0.25, 0.25)).toEqual(-0.25);
14 |     expect(raw(0, 0.25)).toEqual(0.0);
15 |     expect(raw(0.25, 0.25)).toEqual(0.25);
16 |     expect(raw(0.26, 0.25)).toEqual(0.26);
17 |     expect(raw(0.5, 0.25)).toEqual(0.5);
18 |     expect(raw(0.75, 0.25)).toEqual(0.75);
19 |     expect(raw(1.0, 0.25)).toEqual(1.0);
20 |   });
21 | });
22 | 
23 | describe('normalise result', function () {
24 |   it('should normalise input greater than the deadzone', function () {
25 |     expect(normalise(-1.0, 0.25)).toEqual(-1.0);
26 |     expect(normalise(-0.75, 0.25)).toEqual(-0.6666666666666666);
27 |     expect(normalise(-0.5, 0.25)).toEqual(-0.3333333333333333);
28 |     expect(normalise(-0.26, 0.25)).toEqual(-0.013333333333333345);
29 |     expect(normalise(-0.25, 0.25)).toEqual(0.0);
30 |     expect(normalise(0, 0.25)).toEqual(0.0);
31 |     expect(normalise(0.25, 0.25)).toEqual(0.0);
32 |     expect(normalise(0.26, 0.25)).toEqual(0.013333333333333345);
33 |     expect(normalise(0.5, 0.25)).toEqual(0.3333333333333333);
34 |     expect(normalise(0.75, 0.25)).toEqual(0.6666666666666666);
35 |     expect(normalise(1.0, 0.25)).toEqual(1.0);
36 |   });
37 | });


--------------------------------------------------------------------------------
/tests/visual.html:
--------------------------------------------------------------------------------
  1 | 
  2 | 
  3 | 
  4 |   
  5 |   
  6 |   
  7 |   
 18 | 
 19 | 
 20 |   
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | 35 | 36 | 37 | 41 | 42 | 124 | --------------------------------------------------------------------------------