diff --git a/LICENSE b/LICENSE deleted file mode 100644 index a67ab1d..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017-2020 Michaël "e7d" Ferrand - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md index 53592e6..0f563ab 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,60 @@ # gamepad-viewer + Displays live status about gaming devices connected to your computer. ## Demo + [gamepad.e7d.io](https://gamepad.e7d.io/) +## Adding to OBS + +> [!IMPORTANT] +> For OBS to display real-time controller inputs when the window isn't focused, OBS needs to be started with the command line flag `--disable-features=EnableWindowsGamingInputDataFetcher` + +1. Start a listening server for gamepad-viewer with `node app.js` +2. Add a new browser source and paste the url (e.g. `http://localhost:8080/?color=white&triggers=meter&type=dualsense`) +3. Uncheck the following options + - Shutdown source when not visible +4. Set **_Page permissions_** to **_Full access to OBS (Start/Stop streaming without warning, etc.)_** +5. Click **_Refresh cache of current page_** +6. Press a button on your gamepad + +If done correctly, the controller should vibrate and you should see your gamepad's inputs being displayed in real-time! + ## Shortcuts -- `+`: Zoom in -- `-`: Zoom out -- `0`: Reset zoom to 100% -- `5`: Adjust zoom automatically to window -- `B`: Change background style -- `C`: Change active gamepad color -- `D`: Toggle debug mode for active gamepad -- `H`: Toggle help menu -- `T`: Toggle triggers mode (opacity / meter) + +- `+`: Zoom in +- `-`: Zoom out +- `0`: Reset zoom to 100% +- `5`: Adjust zoom automatically to window +- `B`: Change background style +- `C`: Change active gamepad color +- `D`: Toggle debug mode for active gamepad +- `H`: Toggle help menu +- `T`: Toggle triggers mode (opacity / meter) - `Delete` or `Esc`: Clear active gamepad ## Supported gamepads -- Sony DualSense* -- Sony DualShock 4* -- Microsoft Xbox Series Controller* -- Microsoft Xbox One Controller* +- Sony DualSense\* +- Sony DualShock 4\* +- Microsoft Xbox Series Controller\* +- Microsoft Xbox One Controller\* - Microsoft Xbox 360 Controller -- Nintendo Switch Pro Controller* +- Nintendo Switch Pro Controller\* - Xinput compatible gamepads ## Parameters All the parameters are set in the URL. -| **Parameter** | **Description** | **Value** | **Default** | +| **Parameter** | **Description** | **Value** | **Default** | |---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------| -| gamepad | The controller ID of a specific gamepad to use. Please find the controller ID by using the help displayed using the `h` keyboard button. | i.e.: `Microsoft Controller (STANDARD GAMEPAD Vendor: 045e Product: 0b00)` | | -| type | The type of controller (the "skin") to display to the screen.
When possible, the type of controller is auto detected to display the corresponding skin. | - `debug`
- `dualsense`
- `ds4`
- `xbox-one`
- `telemetry` (beta mode for wheels that requires specific configuration) | | -| background | The background color. | - `transparent`
- `checkered`
- `grey`
- `black`
- `white`
- `lime`
- `magenta` | `transparent` | -| color | The displayed gamepad color. | Depending of the selected display `type`. | | -| triggers | The triggers display mode, when applicable. | - `opacity`
- `meter` | `opacity` | -| zoom | The zoom level of the display controller. | Any integer value from `0.1` to `4`, corresponding to a zoom value for 10% to 400%.
When no value is set, the zoom is auto adjusted to fit the window size. | | +| gamepad | The controller ID of a specific gamepad to use. Please find the controller ID by using the help displayed using the `h` keyboard button. | i.e.: `Microsoft Controller (STANDARD GAMEPAD Vendor: 045e Product: 0b00)` | | +| type | The type of controller (the "skin") to display to the screen.
When possible, the type of controller is auto detected to display the corresponding skin. | - `debug`
- `dualsense`
- `ds4`
- `xbox-one`
- `telemetry` (beta mode for wheels that requires specific configuration) | | +| background | The background color. | - `transparent`
- `checkered`
- `grey`
- `black`
- `white`
- `lime`
- `magenta` | `transparent` | +| color | The displayed gamepad color. | Depending of the selected display `type`. | | +| triggers | The triggers display mode, when applicable. | - `opacity`
- `meter` | `opacity` | +| zoom | The zoom level of the display controller. | Any integer value from `0.1` to `4`, corresponding to a zoom value for 10% to 400%.
When no value is set, the zoom is auto adjusted to fit the window size. | | ## Telemetry configuration @@ -49,18 +67,21 @@ The `telemetry` mode requires for you to determine which axes or buttons will be To help you do so, you need to access the Gamepad Viewer with the `debug` skin. To do so, you can go to https://gamepad.e7d.io/?type=debug, and press any button for detection. For each of the axes or buttons you want to use, activate them one by one, and proceed as following: + - observe the changing value in the `Axes` and `Buttons` sections to determine the correct entry - note down its type (axis or button) and its index. - for the clutch, brake and throttle, note down the minimum (when released) and maximum (when pressed) values - for the direction, note down the minimum (left) and maximum (right) values For example with a **Thrustmaster T818**, you should get the following values: + - clutch: axis 6, min 1, max -1 - brake: axis 1, min 1, max -1 - throttle: axis 5, min 1, max -1 - direction: axis 0, min -1, max 1 Another example with a **Xbox one controller** with the A button used as clutch, the triggers as brake and throttle, and the left stick as direction. You should get the following values: + - clutch: button 0, min 0, max 1 - brake: button 6, min 0, max 1 - throttle: button 7, min 0, max 1 @@ -72,19 +93,19 @@ All the parameters are set in the URL. | **Parameter** | **Description** | **Value** | **Default** | |---|---|---|---| | clutchType | The clutch type, either an axis or a button. | `axis` or `button` | `axis` | -| clutchIndex | The index of the clutch axis or button. | A positive integer. | | +| clutchIndex | The index of the clutch axis or button. | A positive integer. | | | clutchMin | The minimum value when the clutch is fully released. | `-1`, `0` or `1` | `-1` | | clutchMax | The maximum value when the clutch is fully pressed. | `-1`, `0` or `1` | `1` | | brakeType | The brake type, either an axis or a button. | `axis` or `button` | `axis` | -| brakeIndex | The index of the brake axis or button. | A positive integer. | | +| brakeIndex | The index of the brake axis or button. | A positive integer. | | | brakeMin | The minimum value when the brake is fully released. | `-1`, `0` or `1` | `-1` | | brakeMax | The maximum value when the brake is fully pressed. | `-1`, `0` or `1` | `1` | | throttleType | The throttle type, either an axis or a button. | `axis` or `button` | `axis` | -| throttleIndex | The index of the throttle axis or button. | A positive integer. | | +| throttleIndex | The index of the throttle axis or button. | A positive integer. | | | throttleMin | The minimum value when the throttle is fully released. | `-1`, `0` or `1` | `-1` | | throttleMax | The maximum value when the throttle is fully pressed. | `-1`, `0` or `1` | `1` | | directionType | The direction type, either an axis or a button. | `axis` or `button` | `axis` | -| directionIndex | The index of the direction axis or button. | A positive integer. | | +| directionIndex | The index of the direction axis or button. | A positive integer. | | | directionMin | The value when the direction is fully on the left. | `-1`, `0` or `1` | `-1` | | directionMax | The value when the direction is fully on the right. | `-1`, `0` or `1` | `1` | | directionDegrees | The angle in degrees to represent the direction changes.
Common wheel values are `360`, `900` and `1080`. | A positive integer. | `360` | @@ -94,12 +115,15 @@ All the parameters are set in the URL. ### Examples Some working examples: + - Thrustmaster T818, with 900 degrees direction: http://gamepad.e7d.io/?gamepad=044f-b696&type=telemetry&clutchIndex=6&clutchMin=1&clutchMax=-1&brakeIndex=1&brakeMin=1&brakeMax=-1&throttleIndex=5&throttleMin=1&throttleMax=-1&directionIndex=0&directionDegrees=900 - DualShock 4 or Xbox Controller, with 180 degrees direction representation: http://gamepad.e7d.io/?gamepad=045e-0b00&type=telemetry&brakeType=button&brakeIndex=6&brakeMin=0&brakeMax=1&throttleType=button&throttleIndex=7&throttleMin=0&throttleMax=1&directionIndex=0&directionDegrees=180 - DualShock 4 or Xbox Controller, with clutch as A or Cross button, and 180 degrees direction representation: http://gamepad.e7d.io/?gamepad=045e-0b00&type=telemetry&clutchType=button&clutchIndex=0&clutchMin=0&clutchMax=1&brakeType=button&brakeIndex=6&brakeMin=0&brakeMax=1&throttleType=button&throttleIndex=7&throttleMin=0&throttleMax=1&directionIndex=0&directionDegrees=180 ## How to use with OBS Studio + Please read below: + - Open [gamepad.e7d.io](https://gamepad.e7d.io/) in your browser - Activate the controller you want to display in OBS by long pressing one of its buttons - Configure it as desired: change skin, controller color, gamepad color, zoom... @@ -111,8 +135,9 @@ Please read below: - Press OK - Adjust position and size of the source as you will -*: These gamepads work both wired and wireless via Bluetooth +\*: These gamepads work both wired and wireless via Bluetooth ## Credits + DualShock 4 and Xbox One skins from [gamepadviewer.com](https://gamepadviewer.com/) DualSense skin from [justEhCupcake](https://github.com/justEhCupcake/justEhCupcake.github.io/tree/main/PS5_Display_Pics) diff --git a/app.js b/app.js new file mode 100644 index 0000000..5156b0c --- /dev/null +++ b/app.js @@ -0,0 +1,43 @@ +// app.js +const http = require("http"); +const fs = require("fs"); +const path = require("path"); +const url = require("url"); + +const port = 8080; +const host = "0.0.0.0"; +const mimeTypes = { + ".html": "text/html", + ".css": "text/css", + ".js": "application/javascript", + ".svg": "image/svg+xml", + ".png": "image/png", + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".gif": "image/gif", + ".ico": "image/x-icon", + ".json": "application/json", + ".txt": "text/plain", +}; + +http.createServer((req, res) => { + // Parse the URL and extract just the pathname, ignoring query parameters + const parsedUrl = url.parse(req.url); + let filePath = "." + decodeURIComponent(parsedUrl.pathname); + if (filePath === "./") filePath = "./index.html"; + + const ext = path.extname(filePath).toLowerCase(); + const contentType = mimeTypes[ext] || "application/octet-stream"; + + fs.readFile(filePath, (err, content) => { + if (err) { + res.writeHead(404); + res.end("404 Not Found"); + } else { + res.writeHead(200, { "Content-Type": contentType }); + res.end(content); + } + }); +}).listen(port, host, () => { + console.log(`Server running at http://${host}:${port}/`); +}); diff --git a/browserconfig.xml b/browserconfig.xml index 345a5c8..21175d9 100644 --- a/browserconfig.xml +++ b/browserconfig.xml @@ -2,7 +2,7 @@ - + #666666 diff --git a/css/gamepad.css b/css/gamepad.css index a4cf8d5..b234117 100644 --- a/css/gamepad.css +++ b/css/gamepad.css @@ -141,7 +141,7 @@ body.unsupported #gamepad { align-self: center; } -#overlay>span { +#overlay > span { padding: 0 8px; } @@ -228,7 +228,7 @@ body.unsupported #gamepad { vertical-align: top; } -.popout table>thead>tr>th { +.popout table > thead > tr > th { border-bottom: 2px solid #ddd; border-top: 0; vertical-align: bottom; @@ -261,21 +261,29 @@ kbd[title], } kbd { - -moz-box-shadow: inset 0 0 1px rgb(150, 150, 150), - inset 0 -0.05em 0.4em rgb(80, 80, 80), 0 0.1em 0 rgb(30, 30, 30), + -moz-box-shadow: + inset 0 0 1px rgb(150, 150, 150), + inset 0 -0.05em 0.4em rgb(80, 80, 80), + 0 0.1em 0 rgb(30, 30, 30), 0 0.1em 0.1em rgba(0, 0, 0, 0.3); - -webkit-box-shadow: inset 0 0 1px rgb(150, 150, 150), - inset 0 -0.05em 0.4em rgb(80, 80, 80), 0 0.1em 0 rgb(30, 30, 30), + -webkit-box-shadow: + inset 0 0 1px rgb(150, 150, 150), + inset 0 -0.05em 0.4em rgb(80, 80, 80), + 0 0.1em 0 rgb(30, 30, 30), 0 0.1em 0.1em rgba(0, 0, 0, 0.3); background: -moz-linear-gradient(top, rgb(60, 60, 60), rgb(80, 80, 80)); - background: -webkit-gradient(linear, - left top, - left bottom, - from(rgb(60, 60, 60)), - to(rgb(80, 80, 80))); + background: -webkit-gradient( + linear, + left top, + left bottom, + from(rgb(60, 60, 60)), + to(rgb(80, 80, 80)) + ); background: rgb(80, 80, 80); - box-shadow: inset 0 0 1px rgb(150, 150, 150), - inset 0 -0.05em 0.4em rgb(80, 80, 80), 0 0.1em 0 rgb(30, 30, 30), + box-shadow: + inset 0 0 1px rgb(150, 150, 150), + inset 0 -0.05em 0.4em rgb(80, 80, 80), + 0 0.1em 0 rgb(30, 30, 30), 0 0.1em 0.1em rgba(0, 0, 0, 0.3); color: rgb(250, 250, 250); text-shadow: -1px -1px 0 rgb(70, 70, 70); diff --git a/docker-compose.yml b/docker-compose.yml index 76b6c60..3574951 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ services: - web: - image: nginx - ports: - - 8081:80 - volumes: - - .:/usr/share/nginx/html:ro + web: + image: nginx + ports: + - 8081:80 + volumes: + - .:/usr/share/nginx/html:ro diff --git a/android-chrome-192x192.png b/img/android-chrome-192x192.png similarity index 100% rename from android-chrome-192x192.png rename to img/android-chrome-192x192.png diff --git a/android-chrome-512x512.png b/img/android-chrome-512x512.png similarity index 100% rename from android-chrome-512x512.png rename to img/android-chrome-512x512.png diff --git a/apple-touch-icon.png b/img/apple-touch-icon.png similarity index 100% rename from apple-touch-icon.png rename to img/apple-touch-icon.png diff --git a/favicon-16x16.png b/img/favicon-16x16.png similarity index 100% rename from favicon-16x16.png rename to img/favicon-16x16.png diff --git a/favicon-32x32.png b/img/favicon-32x32.png similarity index 100% rename from favicon-32x32.png rename to img/favicon-32x32.png diff --git a/favicon.ico b/img/favicon.ico similarity index 100% rename from favicon.ico rename to img/favicon.ico diff --git a/mstile-150x150.png b/img/mstile-150x150.png similarity index 100% rename from mstile-150x150.png rename to img/mstile-150x150.png diff --git a/safari-pinned-tab.svg b/img/safari-pinned-tab.svg similarity index 100% rename from safari-pinned-tab.svg rename to img/safari-pinned-tab.svg diff --git a/index.html b/index.html index d86eb6d..7c42c5e 100644 --- a/index.html +++ b/index.html @@ -1,227 +1,281 @@ - + + + + + Gamepad Viewer + + + + + + + + + + + - - - - Gamepad Viewer - - - - - - - - - - - + + - - - - -
Sorry, but your browser does not support the Gamepad API.
-
- - - - - - - - - + +
+ Sorry, but your browser does not support the + Gamepad API. +
+
+ + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + d="m0 294.39h439.45v-294.39h-439.45v294.39z" + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - -
Press and hold any button to start.
-
-
- - -
-
-
- -

Help

- -

Instructions

-

Press and hold any of your gamepad buttons for at least 1 second. If your gamepad is supported, it shows - up. -

- -

Detected Controllers

- - - - - - - - - - - - -
IndexController ID
No gamepad detected.
- -

Keyboard shortcuts

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyAction
+Zoom in
-Zoom out
0Reset zoom to 100%
5Adjust zoom automatically to window
BChange background style
CChange active gamepad color
DToggle debug mode for active gamepad
HToggle this help menu
TToggle triggers meter mode
Delete, EscapeClear active gamepad
- -

Credits

-

All information and source code can be found on GitHub at e7d/gamepad-viewer.

-

DualShock 4 and Xbox One skins from gamepadviewer.com.

+ +
+ Press and hold any button to start. +
-
+
+ + +
+
+
- - +

Help

+

Instructions

+

+ Press and hold any of your gamepad buttons for at least 1 + second. If your gamepad is supported, it shows up. +

+ +

Detected Controllers

+ + + + + + + + + + + + +
IndexController ID
No gamepad detected.
+ +

Keyboard shortcuts

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyAction
+Zoom in
-Zoom out
0Reset zoom to 100%
5Adjust zoom automatically to window
BChange background style
CChange active gamepad color
DToggle debug mode for active gamepad
HToggle this help menu
TToggle triggers meter mode
Delete, EscapeClear active gamepad
+ +

Credits

+

+ All information and source code can be found on GitHub at + e7d/gamepad-viewer. +

+

+ DualShock 4 and Xbox One skins from + gamepadviewer.com. +

+
+
+ + + diff --git a/js/gamepad.js b/js/gamepad.js index f07eeb6..ebd4200 100644 --- a/js/gamepad.js +++ b/js/gamepad.js @@ -6,44 +6,58 @@ class Gamepad { REGEX = { CHROME: /^(?.*) \((?:.*?Vendor: (?[0-9a-f]{4}) Product: (?[0-9a-f]{4})|(?.*))\)$/i, - FIREFOX: /^((?[0-9a-f]{4})-(?[0-9a-f]{4})-(?.*))$/i, + FIREFOX: + /^((?[0-9a-f]{4})-(?[0-9a-f]{4})-(?.*))$/i, OTHER: /^(?.*)$/i, - } + }; /** * Creates an instance of Gamepad. */ constructor() { // cached DOM references - this.$body = document.querySelector('body'); - this.$instructions = document.querySelector('#instructions'); - this.$instructionsLink = this.$instructions.querySelector('a'); - this.$placeholder = document.querySelector('#placeholder'); - this.$gamepad = document.querySelector('#gamepad'); - this.$overlay = document.querySelector('#overlay'); - this.$gamepadSelect = document.querySelector('select[name=gamepad-id]'); - this.$skinSelect = document.querySelector('select[name=skin]'); - this.$backgroundSelect = document.querySelector('select[name=background]'); - this.$colorOverlay = this.$overlay.querySelector('#color'); - this.$colorSelect = this.$colorOverlay.querySelector('select[name=color]'); - this.$triggersOverlay = this.$overlay.querySelector('#triggers'); - this.$triggersSelect = this.$triggersOverlay.querySelector('select[name=triggers]'); - this.$helpPopout = document.querySelector('#help.popout'); - this.$helpPopoutClose = this.$helpPopout.querySelector('.close'); - this.$gamepadList = document.querySelector('#gamepad-list'); + this.$body = document.querySelector("body"); + this.$instructions = document.querySelector("#instructions"); + this.$instructionsLink = this.$instructions.querySelector("a"); + this.$placeholder = document.querySelector("#placeholder"); + this.$gamepad = document.querySelector("#gamepad"); + this.$overlay = document.querySelector("#overlay"); + this.$gamepadSelect = document.querySelector("select[name=gamepad-id]"); + this.$skinSelect = document.querySelector("select[name=skin]"); + this.$backgroundSelect = document.querySelector( + "select[name=background]", + ); + this.$colorOverlay = this.$overlay.querySelector("#color"); + this.$colorSelect = + this.$colorOverlay.querySelector("select[name=color]"); + this.$triggersOverlay = this.$overlay.querySelector("#triggers"); + this.$triggersSelect = this.$triggersOverlay.querySelector( + "select[name=triggers]", + ); + this.$helpPopout = document.querySelector("#help.popout"); + this.$helpPopoutClose = this.$helpPopout.querySelector(".close"); + this.$gamepadList = document.querySelector("#gamepad-list"); // ensure the GamePad API is available on this browser this.assertGamepadAPI(); // overlay selectors this.backgrounds = [ - { name: 'transparent', backgroundColor: 'transparent', textColor: 'black' }, - { name: 'checkered', backgroundColor: 'url(css/transparent-bg.png)', textColor: 'black' }, - { name: 'dimgrey', backgroundColor: 'dimgrey', textColor: 'black' }, - { name: 'black', backgroundColor: 'black', textColor: 'white' }, - { name: 'white', backgroundColor: 'white', textColor: 'black' }, - { name: 'lime', backgroundColor: 'lime', textColor: 'black' }, - { name: 'magenta', backgroundColor: 'magenta', textColor: 'black' }, + { + name: "transparent", + backgroundColor: "transparent", + textColor: "black", + }, + { + name: "checkered", + backgroundColor: "url(css/transparent-bg.png)", + textColor: "black", + }, + { name: "dimgrey", backgroundColor: "dimgrey", textColor: "black" }, + { name: "black", backgroundColor: "black", textColor: "white" }, + { name: "white", backgroundColor: "white", textColor: "black" }, + { name: "lime", backgroundColor: "lime", textColor: "black" }, + { name: "magenta", backgroundColor: "magenta", textColor: "black" }, ]; this.initOverlaySelectors(); @@ -53,19 +67,19 @@ class Gamepad { // See: https://html5gamepad.com/codes debug: { id: /debug/, - name: 'Debug', + name: "Debug", }, ds4: { id: /05c4|09cc|0104|046d|0810|2563/, // 05c4,09cc,0104 = DS4 controllers product codes, 046d,0810,2563 = PS-like controllers vendor codes - name: 'DualShock 4', - colors: ['black', 'white', 'red', 'blue'], + name: "DualShock 4", + colors: ["black", "white", "red", "blue"], triggers: true, zoom: true, }, dualsense: { id: /0ce6/, // 0ce6 = DualSense controller product code - name: 'DualSense', - colors: ['white', 'black'], + name: "DualSense", + colors: ["white", "black"], triggers: true, zoom: true, }, @@ -91,13 +105,13 @@ class Gamepad { // }, telemetry: { id: /telemetry/, - name: 'Telemetry', - zoom: true + name: "Telemetry", + zoom: true, }, - 'xbox-one': { + "xbox-one": { id: /045e|xinput|XInput/, // 045e = Microsoft vendor code, xinput = standard Windows controller - name: 'Xbox One', - colors: ['black', 'white'], + name: "Xbox One", + colors: ["black", "white"], triggers: true, zoom: true, }, @@ -124,7 +138,7 @@ class Gamepad { this.colorIndex = null; this.colorName = null; this.useMeterTriggers = false; - this.zoomMode = 'auto'; + this.zoomMode = "auto"; this.zoomLevel = 1; this.mapping = { buttons: [], @@ -132,44 +146,50 @@ class Gamepad { }; // listen for gamepad related events - this.haveEvents = 'GamepadEvent' in window; + this.haveEvents = "GamepadEvent" in window; if (this.haveEvents) { window.addEventListener( - 'gamepadconnected', - this.onGamepadConnect.bind(this) + "gamepadconnected", + this.onGamepadConnect.bind(this), ); window.addEventListener( - 'gamepaddisconnected', - this.onGamepadDisconnect.bind(this) + "gamepaddisconnected", + this.onGamepadDisconnect.bind(this), ); } // listen for mouse move events - window.addEventListener('mousemove', this.onMouseMove.bind(this)); + window.addEventListener("mousemove", this.onMouseMove.bind(this)); // listen for keyboard events - window.addEventListener('keydown', this.onKeyDown.bind(this)); + window.addEventListener("keydown", this.onKeyDown.bind(this)); // listen for keyboard events - window.addEventListener('resize', this.onResize.bind(this)); + window.addEventListener("resize", this.onResize.bind(this)); // bind a gamepads scan window.setInterval(this.scan.bind(this), this.scanDelay); // change the type if specified - const skin = this.getUrlParam('type'); + const skin = this.getUrlParam("type"); if (skin) { this.changeSkin(skin); } // change the background if specified - const background = this.getUrlParam('background'); + const background = this.getUrlParam("background"); if (background) this.changeBackground(background); // by default, enqueue a delayed display of the placeholder animation this.displayPlaceholder(); // listen for click events - this.$instructionsLink.addEventListener('click', this.toggleHelp.bind(this)); - this.$helpPopoutClose.addEventListener('click', this.toggleHelp.bind(this)); + this.$instructionsLink.addEventListener( + "click", + this.toggleHelp.bind(this), + ); + this.$helpPopoutClose.addEventListener( + "click", + this.toggleHelp.bind(this), + ); } /** @@ -179,11 +199,11 @@ class Gamepad { const getGamepadsFn = navigator.getGamepads ? () => navigator.getGamepads() : navigator.webkitGetGamepads - ? () => navigator.webkitGetGamepads() - : null; + ? () => navigator.webkitGetGamepads() + : null; if (!getGamepadsFn) { - this.$body.classList.add('unsupported'); - throw new Error('Unsupported gamepad API'); + this.$body.classList.add("unsupported"); + throw new Error("Unsupported gamepad API"); } this.getNavigatorGamepads = getGamepadsFn; } @@ -192,20 +212,20 @@ class Gamepad { * Initialises the overlay selectors */ initOverlaySelectors() { - this.$gamepadSelect.addEventListener('change', () => - this.changeGamepad(this.$gamepadSelect.value) + this.$gamepadSelect.addEventListener("change", () => + this.changeGamepad(this.$gamepadSelect.value), ); - this.$skinSelect.addEventListener('change', () => - this.changeSkin(this.$skinSelect.value) + this.$skinSelect.addEventListener("change", () => + this.changeSkin(this.$skinSelect.value), ); - this.$backgroundSelect.addEventListener('change', () => - this.changeBackground(this.$backgroundSelect.value) + this.$backgroundSelect.addEventListener("change", () => + this.changeBackground(this.$backgroundSelect.value), ); - this.$colorSelect.addEventListener('change', () => - this.changeGamepadColor(this.$colorSelect.value) + this.$colorSelect.addEventListener("change", () => + this.changeGamepadColor(this.$colorSelect.value), ); - this.$triggersSelect.addEventListener('change', () => - this.toggleTriggers(this.$triggersSelect.value === 'meter') + this.$triggersSelect.addEventListener("change", () => + this.toggleTriggers(this.$triggersSelect.value === "meter"), ); } @@ -215,8 +235,8 @@ class Gamepad { * @param {HTMLElement} $element */ show($element) { - $element.style.removeProperty('display'); - $element.classList.remove('fadeIn', 'fadeOut'); + $element.style.removeProperty("display"); + $element.classList.remove("fadeIn", "fadeOut"); } /** @@ -225,8 +245,8 @@ class Gamepad { * @param {HTMLElement} $element */ hide($element) { - $element.style.setProperty('display', 'none'); - $element.classList.remove('fadeIn', 'fadeOut'); + $element.style.setProperty("display", "none"); + $element.classList.remove("fadeIn", "fadeOut"); } /** @@ -235,9 +255,9 @@ class Gamepad { * @param {HTMLElement} $element */ fadeIn($element) { - $element.style.removeProperty('display'); - $element.classList.remove('fadeOut'); - $element.classList.add('fadeIn'); + $element.style.removeProperty("display"); + $element.classList.remove("fadeOut"); + $element.classList.add("fadeIn"); } /** @@ -246,9 +266,9 @@ class Gamepad { * @param {HTMLElement} $element */ fadeOut($element) { - $element.style.removeProperty('display'); - $element.classList.remove('fadeIn'); - $element.classList.add('fadeOut'); + $element.style.removeProperty("display"); + $element.classList.remove("fadeIn"); + $element.classList.add("fadeOut"); } /** @@ -283,7 +303,7 @@ class Gamepad { // hide instructions animation if no gamepad is active after X ms this.instructionsTimeout = window.setTimeout( () => this.fadeOut(this.$instructions), - this.instructionsDelay + this.instructionsDelay, ); } @@ -319,7 +339,7 @@ class Gamepad { // hide placeholder animation if no gamepad is active after X ms this.placeholderTimeout = window.setTimeout( () => this.fadeOut(this.$placeholder), - this.placeholderDelay + this.placeholderDelay, ); } @@ -352,7 +372,7 @@ class Gamepad { // hide overlay animation if no gamepad is active after X ms this.overlayTimeout = window.setTimeout( () => this.fadeOut(this.$overlay), - this.overlayDelay + this.overlayDelay, ); } @@ -369,14 +389,14 @@ class Gamepad { if (firefoxResults) return firefoxResults.groups; const otherResults = this.REGEX.OTHER.exec(id); if (otherResults) return otherResults.groups; - return { name: id, vendor: '', product: '' }; + return { name: id, vendor: "", product: "" }; } /** * Updates the list of connected gamepads in the overlay */ updateGamepadList() { - for (const $entry of this.$gamepadSelect.querySelectorAll('.entry')) { + for (const $entry of this.$gamepadSelect.querySelectorAll(".entry")) { $entry.remove(); } const $options = []; @@ -385,10 +405,10 @@ class Gamepad { if (!gamepad) continue; const { name } = this.toGamepadInfo(gamepad.id); $options.push( - `` + ``, ); } - this.$gamepadSelect.innerHTML += $options.join(''); + this.$gamepadSelect.innerHTML += $options.join(""); } /** @@ -407,9 +427,10 @@ class Gamepad { } const colorOptions = colors.map( - (color) => `` + (color) => + ``, ); - this.$colorSelect.innerHTML = colorOptions.join(''); + this.$colorSelect.innerHTML = colorOptions.join(""); this.show(this.$colorOverlay); } @@ -461,7 +482,7 @@ class Gamepad { if (e.gamepad.index === this.index) { // display a disconnection indicator - this.$gamepad.classList.add('disconnected'); + this.$gamepad.classList.add("disconnected"); this.disconnectedIndex = e.gamepad.index; // refresh gamepad list on help, if displayed @@ -485,43 +506,43 @@ class Gamepad { */ onKeyDown(e) { switch (e.code) { - case 'Delete': - case 'Escape': + case "Delete": + case "Escape": this.clear(); this.displayPlaceholder(); break; - case 'KeyB': + case "KeyB": this.changeBackground(); break; - case 'KeyC': + case "KeyC": this.changeGamepadColor(); break; - case 'KeyD': + case "KeyD": this.toggleDebug(); break; - case 'KeyG': + case "KeyG": this.toggleGamepadType(); break; - case 'KeyH': + case "KeyH": this.toggleHelp(); break; - case 'KeyT': + case "KeyT": this.toggleTriggers(); break; - case 'NumpadAdd': - case 'Equal': - this.changeZoom('+'); + case "NumpadAdd": + case "Equal": + this.changeZoom("+"); break; - case 'NumpadSubtract': - case 'Minus': - this.changeZoom('-'); + case "NumpadSubtract": + case "Minus": + this.changeZoom("-"); break; - case 'Numpad5': - case 'Digit5': - this.changeZoom('auto'); + case "Numpad5": + case "Digit5": + this.changeZoom("auto"); break; - case 'Numpad0': - case 'Digit0': + case "Numpad0": + case "Digit0": this.changeZoom(0); break; } @@ -531,7 +552,7 @@ class Gamepad { * Handles the keyboard 'keydown' event */ onResize() { - if (this.zoomMode === 'auto') this.changeZoom('auto'); + if (this.zoomMode === "auto") this.changeZoom("auto"); } /** @@ -554,15 +575,18 @@ class Gamepad { for (let key = 0; key < this.gamepads.length; key++) { const gamepad = this.gamepads[key]; if (!gamepad) continue; - $tbody.push(`${gamepad.index}${gamepad.id}`); + $tbody.push( + `${gamepad.index}${gamepad.id}`, + ); } if ($tbody.length === 0) { - this.$gamepadList.innerHTML = 'No gamepad detected.'; + this.$gamepadList.innerHTML = + 'No gamepad detected.'; return; } - this.$gamepadList.innerHTML = $tbody.join(''); + this.$gamepadList.innerHTML = $tbody.join(""); } /** @@ -581,12 +605,12 @@ class Gamepad { * @returns {string} */ getType(gamepad) { - const type = this.getUrlParam('type'); + const type = this.getUrlParam("type"); // if the debug option is active, use the associated template - if (type === 'debug') this.debug = true; + if (type === "debug") this.debug = true; if (this.debug) { - return 'debug'; + return "debug"; } // if the gamepad type is set through params, apply it @@ -601,7 +625,7 @@ class Gamepad { } } - return 'debug'; + return "debug"; } /** @@ -624,13 +648,14 @@ class Gamepad { if ( null !== this.disconnectedIndex && index !== this.disconnectedIndex - ) continue; + ) + continue; const gamepad = this.gamepads[index]; if (!gamepad) continue; // check the parameters for a selected gamepad - const gamepadId = this.getUrlParam('gamepad'); + const gamepadId = this.getUrlParam("gamepad"); if (gamepadId === gamepad.id) { this.map(gamepad.index); return; @@ -658,7 +683,7 @@ class Gamepad { strongMagnitude: 0.2, weakMagnitude: 1, startDelay: 0, - } + }, ); } @@ -675,7 +700,7 @@ class Gamepad { */ map(index) { // ensure a gamepad need to be mapped - if ('undefined' === typeof index) return; + if ("undefined" === typeof index) return; // hide the help messages this.hideInstructions(true); @@ -684,7 +709,7 @@ class Gamepad { // update local references this.index = index; this.disconnectedIndex = null; - this.$gamepad.classList.remove('disconnected'); + this.$gamepad.classList.remove("disconnected"); const gamepad = this.getActive(); // ensure that a gamepad was actually found for this index @@ -722,8 +747,12 @@ class Gamepad { */ async toHash(value) { return crypto.subtle - .digest('SHA-1', new TextEncoder().encode(value)) - .then(ab => encodeURIComponent(String.fromCharCode.apply(null, new Uint8Array(ab)))); + .digest("SHA-1", new TextEncoder().encode(value)) + .then((ab) => + encodeURIComponent( + String.fromCharCode.apply(null, new Uint8Array(ab)), + ), + ); } /** @@ -746,9 +775,9 @@ class Gamepad { this.colorIndex = null; this.colorName = null; this.zoomLevel = 1; - this.$gamepad.innerHTML = ''; - this.$gamepad.classList.remove('fadeIn'); - this.$gamepadSelect.value = 'auto'; + this.$gamepad.innerHTML = ""; + this.$gamepad.classList.remove("fadeIn"); + this.$gamepadSelect.value = "auto"; this.updateColors(); this.updateTriggers(); this.clearUrlParams(); @@ -758,12 +787,12 @@ class Gamepad { * Loads the template script and stylesheet */ loadTemplateAssets() { - const link = document.createElement('link'); - link.rel = 'stylesheet'; + const link = document.createElement("link"); + link.rel = "stylesheet"; link.href = `templates/${this.type}/template.css`; this.$gamepad.appendChild(link); - const script = document.createElement('script'); + const script = document.createElement("script"); script.async = true; script.src = `templates/${this.type}/template.js`; script.onload = () => { @@ -772,7 +801,7 @@ class Gamepad { // enqueue the initial display refresh this.startTemplate(); - } + }; this.$gamepad.appendChild(script); } @@ -781,7 +810,7 @@ class Gamepad { */ loadTemplate() { // hide the gamepad while we prepare it - this.$gamepad.style.setProperty('display', 'none'); + this.$gamepad.style.setProperty("display", "none"); fetch(`templates/${this.type}/template.html`) .then((response) => response.text()) @@ -794,13 +823,15 @@ class Gamepad { const identifier = this.identifiers[this.type]; // - color if (identifier.colors) { - this.changeGamepadColor(this.getUrlParam('color')); + this.changeGamepadColor(this.getUrlParam("color")); } else { this.updateUrlParams({ color: undefined }); } // - triggers mode if (identifier.triggers) { - this.toggleTriggers(this.getUrlParam('triggers') === 'meter'); + this.toggleTriggers( + this.getUrlParam("triggers") === "meter", + ); } else { this.updateUrlParams({ triggers: undefined }); } @@ -808,19 +839,19 @@ class Gamepad { if (identifier.zoom) { window.setTimeout(() => this.changeZoom( - this.type === 'debug' - ? 'auto' - : this.getUrlParam('zoom') || 'auto' - ) + this.type === "debug" + ? "auto" + : this.getUrlParam("zoom") || "auto", + ), ); } else { this.updateUrlParams({ zoom: undefined }); } // once fully loaded, display the gamepad - this.$gamepad.style.removeProperty('display'); - this.$gamepad.classList.remove('fadeOut'); - this.$gamepad.classList.add('fadeIn'); + this.$gamepad.style.removeProperty("display"); + this.$gamepad.classList.remove("fadeOut"); + this.$gamepad.classList.add("fadeIn"); }); } @@ -834,14 +865,23 @@ class Gamepad { // save the buttons mapping of this template this.mapping.buttons = activeGamepad.buttons.map((_, index) => { const $button = document.querySelector(`[data-button='${index}']`); - return { $button, button: { pressed: null, touched: null, value: null } }; + return { + $button, + button: { pressed: null, touched: null, value: null }, + }; }); // save the axes mapping of this template this.mapping.axes = activeGamepad.axes.map((_, index) => { - const { $axis, attribute } = ['data-axis', 'data-axis-x', 'data-axis-y'].reduce((acc, attribute) => { + const { $axis, attribute } = [ + "data-axis", + "data-axis-x", + "data-axis-y", + ].reduce((acc, attribute) => { if (acc.$axis) return acc; - const $axis = document.querySelector(`[${attribute}='${index}']`); + const $axis = document.querySelector( + `[${attribute}='${index}']`, + ); return $axis ? { $axis, attribute, axis: null } : acc; }, {}); return { $axis, attribute }; @@ -870,7 +910,8 @@ class Gamepad { */ pollStatus(force = false) { // ensure that a gamepad is currently active - if (this.index === null || this.index === this.disconnectedIndex) return; + if (this.index === null || this.index === this.disconnectedIndex) + return; // enqueue the next refresh window.requestAnimationFrame(this.pollStatus.bind(this)); @@ -907,12 +948,13 @@ class Gamepad { updatedButton.touched !== button.touched || updatedButton.value !== button.value ) { - $button.setAttribute('data-pressed', updatedButton.pressed); - $button.setAttribute('data-touched', updatedButton.touched); - $button.setAttribute('data-value', updatedButton.value); + $button.setAttribute("data-pressed", updatedButton.pressed); + $button.setAttribute("data-touched", updatedButton.touched); + $button.setAttribute("data-value", updatedButton.value); // ensure we have a button updater callback and hook the template defined button update method - if ('function' === typeof this.updateButton) this.updateButton($button, updatedButton); + if ("function" === typeof this.updateButton) + this.updateButton($button, updatedButton); } // save the updated button @@ -935,10 +977,14 @@ class Gamepad { // update the display value if (updatedAxis !== axis) { - $axis.setAttribute(attribute.replace('-axis', '-value'), updatedAxis); + $axis.setAttribute( + attribute.replace("-axis", "-value"), + updatedAxis, + ); // ensure we have an axis updater callback and hook the template defined axis update method - if ('function' === typeof this.updateAxis) this.updateAxis($axis, attribute, updatedAxis); + if ("function" === typeof this.updateAxis) + this.updateAxis($axis, attribute, updatedAxis); } // save the updated button @@ -953,10 +999,10 @@ class Gamepad { */ changeGamepad(id) { // get the index corresponding to the identifier of the gamepad - const index = this.gamepads.findIndex(g => g && id === g.id); + const index = this.gamepads.findIndex((g) => g && id === g.id); // set the selected gamepad - this.updateUrlParams({ gamepad: id !== 'auto' ? id : undefined }); + this.updateUrlParams({ gamepad: id !== "auto" ? id : undefined }); index === -1 ? this.clear() : this.map(index); } @@ -973,8 +1019,8 @@ class Gamepad { this.$skinSelect.value = skin; // set the selected skin - this.debug = skin === 'debug'; - this.updateUrlParams({ type: skin !== 'auto' ? skin : undefined }); + this.debug = skin === "debug"; + this.updateUrlParams({ type: skin !== "auto" ? skin : undefined }); this.map(this.index); } @@ -984,20 +1030,23 @@ class Gamepad { * @param {string|number|undefined} indexOrName */ changeBackground(indexOrName) { - if ('undefined' === typeof indexOrName) { + if ("undefined" === typeof indexOrName) { this.backgroundIndex++; if (this.backgroundIndex > this.backgrounds.length - 1) { this.backgroundIndex = 0; } - } else if ('string' === typeof indexOrName) { - this.backgroundIndex = this.backgrounds.findIndex(({ name }) => name === indexOrName); + } else if ("string" === typeof indexOrName) { + this.backgroundIndex = this.backgrounds.findIndex( + ({ name }) => name === indexOrName, + ); } else { this.backgroundIndex = indexOrName; } - const { name, backgroundColor, textColor } = this.backgrounds[this.backgroundIndex]; + const { name, backgroundColor, textColor } = + this.backgrounds[this.backgroundIndex]; - this.$body.style.setProperty('background', backgroundColor); - this.$body.style.setProperty('color', textColor); + this.$body.style.setProperty("background", backgroundColor); + this.$body.style.setProperty("color", textColor); // update current settings this.updateUrlParams({ background: name }); @@ -1013,15 +1062,15 @@ class Gamepad { // ensure that a gamepad is currently active if (this.index === null) return; - if ('undefined' === typeof color) { + if ("undefined" === typeof color) { // no color was specified, load the next one in list this.colorIndex++; if (this.colorIndex > this.identifier.colors.length - 1) { this.colorIndex = 0; } - } else if ('string' === typeof style) { + } else if ("string" === typeof style) { this.colorIndex = this.identifier.colors.findIndex( - (c) => c === color + (c) => c === color, ); } else { if (!Number.isNaN(Number.parseInt(color))) { @@ -1043,7 +1092,7 @@ class Gamepad { : null; // update the DOM with the color value - this.$gamepad.setAttribute('data-color', this.colorName); + this.$gamepad.setAttribute("data-color", this.colorName); // update current settings this.updateUrlParams({ color: this.colorName }); @@ -1060,25 +1109,25 @@ class Gamepad { if (this.index === null) return; // ensure we have some data to process - if (typeof level === 'undefined') return; + if (typeof level === "undefined") return; - this.zoomMode = level === 'auto' ? 'auto' : 'manual'; + this.zoomMode = level === "auto" ? "auto" : "manual"; - if (this.zoomMode === 'auto') { + if (this.zoomMode === "auto") { // 'auto' means a 'contained in window' zoom, with a max zoom of 1 const { width, height } = this.$gamepad.getBoundingClientRect(); this.zoomLevel = Math.min( window.innerWidth / width, window.innerHeight / height, - 1 + 1, ); } else if (level === 0) { // 0 means a zoom reset this.zoomLevel = 1; - } else if (level === '+' && this.zoomLevel < 4) { + } else if (level === "+" && this.zoomLevel < 4) { // '+' means a zoom in if we still can this.zoomLevel += 0.1; - } else if (level === '-' && this.zoomLevel > 0.1) { + } else if (level === "-" && this.zoomLevel > 0.1) { // '-' means a zoom out if we still can this.zoomLevel -= 0.1; } else if (!Number.isNaN(+level)) { @@ -1091,13 +1140,13 @@ class Gamepad { // update the DOM with the zoom value this.$gamepad.style.setProperty( - 'transform', - `scale(${this.zoomLevel}, ${this.zoomLevel})` + "transform", + `scale(${this.zoomLevel}, ${this.zoomLevel})`, ); // update current settings this.updateUrlParams({ - zoom: this.zoomMode === 'auto' ? undefined : this.zoomLevel, + zoom: this.zoomMode === "auto" ? undefined : this.zoomLevel, }); } @@ -1113,7 +1162,7 @@ class Gamepad { // compute next type const types = Object.keys(this.identifiers).filter( - (i) => i !== 'debug' + (i) => i !== "debug", ); let typeIndex = types.reduce((typeIndex, type, index) => { return type === this.type ? index : typeIndex; @@ -1140,7 +1189,7 @@ class Gamepad { this.debug = debug !== undefined ? debug : !this.debug; // update current settings - this.changeSkin(this.debug ? 'debug' : 'auto') + this.changeSkin(this.debug ? "debug" : "auto"); } /** @@ -1148,8 +1197,8 @@ class Gamepad { */ toggleHelp() { // display the help popout - this.$helpPopout.classList.toggle('active'); - this.helpVisible = this.$helpPopout.classList.contains('active'); + this.$helpPopout.classList.toggle("active"); + this.helpVisible = this.$helpPopout.classList.contains("active"); } /** @@ -1162,9 +1211,12 @@ class Gamepad { if (this.index === null) return; // update current settings - this.useMeterTriggers = useMeter !== undefined ? useMeter : !this.useMeterTriggers; - this.$gamepad.classList[this.useMeterTriggers ? 'add' : 'remove']('triggers-meter'); - const triggers = this.useMeterTriggers ? 'meter' : 'opacity'; + this.useMeterTriggers = + useMeter !== undefined ? useMeter : !this.useMeterTriggers; + this.$gamepad.classList[this.useMeterTriggers ? "add" : "remove"]( + "triggers-meter", + ); + const triggers = this.useMeterTriggers ? "meter" : "opacity"; this.updateUrlParams({ triggers }); this.$triggersSelect.value = triggers; } @@ -1177,7 +1229,7 @@ class Gamepad { */ getUrlParam(name) { const matches = new RegExp(`[?&]${name}(=([^&#]*))?`).exec( - window.location.search + window.location.search, ); return matches ? decodeURIComponent(matches[2] || true) || true : null; } @@ -1189,14 +1241,14 @@ class Gamepad { */ getUrlParams() { const settingsArr = window.location.search - .replace('?', '') - .split('&') - .map((param) => param.split('=')); + .replace("?", "") + .split("&") + .map((param) => param.split("=")); const settings = {}; for (const key of Object.keys(settingsArr)) { const [k, v] = settingsArr[key]; settings[k] = v; - }; + } return settings; } @@ -1224,7 +1276,7 @@ class Gamepad { const query = Object.entries(params) .filter(([, value]) => value !== undefined && value !== null) .map(([key, value]) => `${key}=${value}`) - .join('&'); + .join("&"); window.history.replaceState({}, document.title, `/?${query}`); } } diff --git a/obs-commandline.txt b/obs-commandline.txt new file mode 100644 index 0000000..1f2b644 --- /dev/null +++ b/obs-commandline.txt @@ -0,0 +1 @@ +--disable-features=EnableWindowsGamingInputDataFetcher \ No newline at end of file diff --git a/templates/debug/template.js b/templates/debug/template.js index 2c2e170..2799681 100644 --- a/templates/debug/template.js +++ b/templates/debug/template.js @@ -5,8 +5,10 @@ window.gamepad.TemplateClass = class DebugTemplate { constructor() { this.gamepad = window.gamepad; this.init(); - this.gamepad.updateButton = ($button, { value }) => this.updateElem($button, value); - this.gamepad.updateAxis = ($axis, _, axis) => this.updateElem($axis, axis, 6); + this.gamepad.updateButton = ($button, { value }) => + this.updateElem($button, value); + this.gamepad.updateAxis = ($axis, _, axis) => + this.updateElem($axis, axis, 6); } /** @@ -21,35 +23,37 @@ window.gamepad.TemplateClass = class DebugTemplate { * Initializes the template */ init() { - this.$name = document.querySelector('#info-name .value'); - this.$vendor = document.querySelector('#info-vendor'); - this.$product = document.querySelector('#info-product'); - this.$id = document.querySelector('#info-id'); - this.$timestamp = document.querySelector('#info-timestamp .value'); - this.$index = document.querySelector('#info-index .value'); - this.$mapping = document.querySelector('#info-mapping .value'); - this.$rumble = document.querySelector('#info-rumble .value'); - this.$axes = document.querySelector('.axes .container'); - this.$buttons = document.querySelector('.buttons .container'); + this.$name = document.querySelector("#info-name .value"); + this.$vendor = document.querySelector("#info-vendor"); + this.$product = document.querySelector("#info-product"); + this.$id = document.querySelector("#info-id"); + this.$timestamp = document.querySelector("#info-timestamp .value"); + this.$index = document.querySelector("#info-index .value"); + this.$mapping = document.querySelector("#info-mapping .value"); + this.$rumble = document.querySelector("#info-rumble .value"); + this.$axes = document.querySelector(".axes .container"); + this.$buttons = document.querySelector(".buttons .container"); const activeGamepad = this.gamepad.getActive(); - const { name, vendor, product, id } = this.gamepad.toGamepadInfo(activeGamepad.id); + const { name, vendor, product, id } = this.gamepad.toGamepadInfo( + activeGamepad.id, + ); this.$name.innerHTML = name; - this.$name.setAttribute('title', activeGamepad.id); + this.$name.setAttribute("title", activeGamepad.id); if (vendor && product) { - this.$vendor.querySelector('.value').innerHTML = vendor; - this.$product.querySelector('.value').innerHTML = product; - this.$vendor.style.setProperty('display', 'block'); - this.$product.style.setProperty('display', 'block'); + this.$vendor.querySelector(".value").innerHTML = vendor; + this.$product.querySelector(".value").innerHTML = product; + this.$vendor.style.setProperty("display", "block"); + this.$product.style.setProperty("display", "block"); } else { - this.$id.querySelector('.value').innerHTML = id; - this.$id.style.setProperty('display', 'block'); + this.$id.querySelector(".value").innerHTML = id; + this.$id.style.setProperty("display", "block"); } this.updateTimestamp(); this.$index.innerHTML = this.activeGamepad.index; - this.$mapping.innerHTML = this.activeGamepad.mapping || 'N/A'; + this.$mapping.innerHTML = this.activeGamepad.mapping || "N/A"; this.$rumble.innerHTML = this.activeGamepad.vibrationActuator ? this.activeGamepad.vibrationActuator.type - : 'N/A'; + : "N/A"; this.initAxes(); this.initButtons(); } @@ -75,8 +79,8 @@ window.gamepad.TemplateClass = class DebugTemplate { } /** - * Initializes the buttons - */ + * Initializes the buttons + */ initButtons() { for ( let buttonIndex = 0; @@ -104,7 +108,7 @@ window.gamepad.TemplateClass = class DebugTemplate { this.updateTimestamp(); $elem.innerHTML = value.toFixed(precision); const color = Math.floor(255 * 0.3 + 255 * 0.7 * Math.abs(value)); - $elem.style.setProperty('color', `rgb(${color}, ${color}, ${color})`); + $elem.style.setProperty("color", `rgb(${color}, ${color}, ${color})`); } /** @@ -115,6 +119,8 @@ window.gamepad.TemplateClass = class DebugTemplate { if (!this.activeGamepad) { return; } - this.$timestamp.innerHTML = Number.parseFloat(this.activeGamepad.timestamp).toFixed(3); + this.$timestamp.innerHTML = Number.parseFloat( + this.activeGamepad.timestamp, + ).toFixed(3); } }; diff --git a/templates/ds4/template.html b/templates/ds4/template.html index 3760646..82bfec6 100644 --- a/templates/ds4/template.html +++ b/templates/ds4/template.html @@ -23,8 +23,18 @@
- - + +
diff --git a/templates/ds4/template.js b/templates/ds4/template.js index 71cc428..bb990eb 100644 --- a/templates/ds4/template.js +++ b/templates/ds4/template.js @@ -19,26 +19,41 @@ window.gamepad.TemplateClass = class DualShock4Template { } updateButton($button, button) { - if (!$button.matches('.trigger') || !button) return; - $button.style.setProperty('opacity', this.gamepad.useMeterTriggers ? 1 : `${button.value * 100}%`); - $button.style.setProperty('clip-path', this.gamepad.useMeterTriggers ? `inset(${100 - button.value * 100}% 0px 0px 0pc)` : 'none'); + if (!$button.matches(".trigger") || !button) return; + $button.style.setProperty( + "opacity", + this.gamepad.useMeterTriggers ? 1 : `${button.value * 100}%`, + ); + $button.style.setProperty( + "clip-path", + this.gamepad.useMeterTriggers + ? `inset(${100 - button.value * 100}% 0px 0px 0pc)` + : "none", + ); } updateAxis($axis, attribute, axis) { - if (!$axis.matches('.stick')) return; - if (attribute === 'data-axis-x') { - $axis.style.setProperty('margin-left', `${axis * 25}px`); + if (!$axis.matches(".stick")) return; + if (attribute === "data-axis-x") { + $axis.style.setProperty("margin-left", `${axis * 25}px`); this.updateRotate($axis); } - if (attribute === 'data-axis-y') { - $axis.style.setProperty('margin-top', `${axis * 25}px`); + if (attribute === "data-axis-y") { + $axis.style.setProperty("margin-top", `${axis * 25}px`); this.updateRotate($axis); } } updateRotate($axis) { - const rotateX = Number.parseFloat($axis.getAttribute('data-value-y') * 30); - const rotateY = -Number.parseFloat($axis.getAttribute('data-value-x') * 30); - $axis.style.setProperty('transform', `rotateX(${rotateX}deg) rotateY(${rotateY}deg)`); + const rotateX = Number.parseFloat( + $axis.getAttribute("data-value-y") * 30, + ); + const rotateY = -Number.parseFloat( + $axis.getAttribute("data-value-x") * 30, + ); + $axis.style.setProperty( + "transform", + `rotateX(${rotateX}deg) rotateY(${rotateY}deg)`, + ); } }; diff --git a/templates/dualsense/template.html b/templates/dualsense/template.html index 3760646..82bfec6 100644 --- a/templates/dualsense/template.html +++ b/templates/dualsense/template.html @@ -23,8 +23,18 @@
- - + +
diff --git a/templates/dualsense/template.js b/templates/dualsense/template.js index 2e34d47..0ece1bc 100644 --- a/templates/dualsense/template.js +++ b/templates/dualsense/template.js @@ -19,26 +19,41 @@ window.gamepad.TemplateClass = class DualSenseTemplate { } updateButton($button, button) { - if (!$button.matches('.trigger') || !button) return; - $button.style.setProperty('opacity', this.gamepad.useMeterTriggers ? 1 : `${button.value * 100}%`); - $button.style.setProperty('clip-path', this.gamepad.useMeterTriggers ? `inset(${100 - button.value * 100}% 0px 0px 0pc)` : 'none'); + if (!$button.matches(".trigger") || !button) return; + $button.style.setProperty( + "opacity", + this.gamepad.useMeterTriggers ? 1 : `${button.value * 100}%`, + ); + $button.style.setProperty( + "clip-path", + this.gamepad.useMeterTriggers + ? `inset(${100 - button.value * 100}% 0px 0px 0pc)` + : "none", + ); } updateAxis($axis, attribute, axis) { - if (!$axis.matches('.stick')) return; - if (attribute === 'data-axis-x') { - $axis.style.setProperty('margin-left', `${axis * 25}px`); + if (!$axis.matches(".stick")) return; + if (attribute === "data-axis-x") { + $axis.style.setProperty("margin-left", `${axis * 25}px`); this.updateRotate($axis); } - if (attribute === 'data-axis-y') { - $axis.style.setProperty('margin-top', `${axis * 25}px`); + if (attribute === "data-axis-y") { + $axis.style.setProperty("margin-top", `${axis * 25}px`); this.updateRotate($axis); } } updateRotate($axis) { - const rotateX = Number.parseFloat($axis.getAttribute('data-value-y') * 30); - const rotateY = -Number.parseFloat($axis.getAttribute('data-value-x') * 30); - $axis.style.setProperty('transform', `rotateX(${rotateX}deg) rotateY(${rotateY}deg)`); + const rotateX = Number.parseFloat( + $axis.getAttribute("data-value-y") * 30, + ); + const rotateY = -Number.parseFloat( + $axis.getAttribute("data-value-x") * 30, + ); + $axis.style.setProperty( + "transform", + `rotateX(${rotateX}deg) rotateY(${rotateY}deg)`, + ); } }; diff --git a/templates/telemetry/template.css b/templates/telemetry/template.css index e8ab925..8c70452 100644 --- a/templates/telemetry/template.css +++ b/templates/telemetry/template.css @@ -11,9 +11,9 @@ --white-color: white; --main-bg-color: black; --main-component-color: #333; - --clutch-color: #2D64B9; - --brake-color: #A52725; - --throttle-color: #0CA818; + --clutch-color: #2d64b9; + --brake-color: #a52725; + --throttle-color: #0ca818; } #gamepad #telemetry:has(#steering:not([style*="display: none"])) { @@ -26,7 +26,7 @@ box-sizing: border-box; } -#gamepad #telemetry>*+* { +#gamepad #telemetry > * + * { margin-left: 2px; } @@ -53,7 +53,7 @@ width: 30px; } -#gamepad #telemetry #meters .meter+.meter { +#gamepad #telemetry #meters .meter + .meter { margin-left: 2px; } @@ -133,7 +133,6 @@ text-align: center; } - #wizard .wizard-options { display: flex; margin: auto; diff --git a/templates/telemetry/template.js b/templates/telemetry/template.js index 1eff37f..ee2da1e 100644 --- a/templates/telemetry/template.js +++ b/templates/telemetry/template.js @@ -3,7 +3,7 @@ window.gamepad.TemplateClass = class TelemetryTemplate { * Instanciates a new telemetry template */ constructor() { - this.AXES = ['clutch', 'brake', 'throttle', 'steering']; + this.AXES = ["clutch", "brake", "throttle", "steering"]; this.gamepad = window.gamepad; this.loadSelectors(); @@ -33,7 +33,10 @@ window.gamepad.TemplateClass = class TelemetryTemplate { * @returns {number} */ toPercentage(value, min, max) { - return Math.max(0, Math.min(100, Math.round((value - min) * (100 / (max - min))))); + return Math.max( + 0, + Math.min(100, Math.round((value - min) * (100 / (max - min)))), + ); } /** @@ -46,7 +49,7 @@ window.gamepad.TemplateClass = class TelemetryTemplate { */ toDegrees(value, min, max) { const percentage = this.toPercentage(value, min, max); - return (this.angle) * (percentage - 50) / 100; + return (this.angle * (percentage - 50)) / 100; } /** @@ -59,10 +62,11 @@ window.gamepad.TemplateClass = class TelemetryTemplate { toAxisValue(gamepad, axis) { const { type, index, min, max } = this[axis]; if (!type || !index) return null; - const value = type === 'button' - ? gamepad.buttons[index].value - : gamepad.axes[index]; - return axis === 'steering' + const value = + type === "button" + ? gamepad.buttons[index].value + : gamepad.axes[index]; + return axis === "steering" ? this.toDegrees(value, min, max) : this.toPercentage(value, min, max); } @@ -71,49 +75,53 @@ window.gamepad.TemplateClass = class TelemetryTemplate { * Loads the DOM selectors */ loadSelectors() { - this.$telemetry = document.querySelector('#telemetry'); - this.$chart = this.$telemetry.querySelector('#chart'); - this.chartContext = this.$chart.getContext('2d'); - this.$meters = this.$telemetry.querySelector('#meters'); - this.$clutch = this.$telemetry.querySelector('#clutch'); - this.$clutchBar = this.$clutch.querySelector('.bar'); - this.$clutchValue = this.$clutch.querySelector('.value'); - this.$brake = this.$telemetry.querySelector('#brake'); - this.$brakeBar = this.$brake.querySelector('.bar'); - this.$brakeValue = this.$brake.querySelector('.value'); - this.$throttle = this.$telemetry.querySelector('#throttle'); - this.$throttleBar = this.$throttle.querySelector('.bar'); - this.$throttleValue = this.$throttle.querySelector('.value'); - this.$steering = this.$telemetry.querySelector('#steering'); - this.$steeringIndicator = this.$steering.querySelector('.indicator'); - this.$wizard = document.querySelector('#wizard'); - this.$wizardPreview = this.$wizard.querySelector('#wizard-preview'); - this.$wizardInstructions = this.$wizard.querySelector('#wizard-instructions'); + this.$telemetry = document.querySelector("#telemetry"); + this.$chart = this.$telemetry.querySelector("#chart"); + this.chartContext = this.$chart.getContext("2d"); + this.$meters = this.$telemetry.querySelector("#meters"); + this.$clutch = this.$telemetry.querySelector("#clutch"); + this.$clutchBar = this.$clutch.querySelector(".bar"); + this.$clutchValue = this.$clutch.querySelector(".value"); + this.$brake = this.$telemetry.querySelector("#brake"); + this.$brakeBar = this.$brake.querySelector(".bar"); + this.$brakeValue = this.$brake.querySelector(".value"); + this.$throttle = this.$telemetry.querySelector("#throttle"); + this.$throttleBar = this.$throttle.querySelector(".bar"); + this.$throttleValue = this.$throttle.querySelector(".value"); + this.$steering = this.$telemetry.querySelector("#steering"); + this.$steeringIndicator = this.$steering.querySelector(".indicator"); + this.$wizard = document.querySelector("#wizard"); + this.$wizardPreview = this.$wizard.querySelector("#wizard-preview"); + this.$wizardInstructions = this.$wizard.querySelector( + "#wizard-instructions", + ); } /** * Loads the params from the URL */ loadParams() { - this.withChart = gamepad.getUrlParam('chart') !== 'false'; + this.withChart = gamepad.getUrlParam("chart") !== "false"; this.chartColors = { - clutch: '#2D64B9', - brake: '#A52725', - throttle: '#0CA818', - } - this.historyLength = +(gamepad.getUrlParam('history') || 5000); - this.withMeters = gamepad.getUrlParam('meters') !== 'false'; - this.withSteering = gamepad.getUrlParam('steeringIndex') !== null; - this.angle = gamepad.getUrlParam('angle') || 360; - this.frequency = gamepad.getUrlParam('fps') || 60; - for(const axis of this.AXES) { + clutch: "#2D64B9", + brake: "#A52725", + throttle: "#0CA818", + }; + this.historyLength = +(gamepad.getUrlParam("history") || 5000); + this.withMeters = gamepad.getUrlParam("meters") !== "false"; + this.withSteering = gamepad.getUrlParam("steeringIndex") !== null; + this.angle = gamepad.getUrlParam("angle") || 360; + this.frequency = gamepad.getUrlParam("fps") || 60; + for (const axis of this.AXES) { this[axis] = { - type: (gamepad.getUrlParam(`${axis}Type`) || 'axis').replace('axis', 'axe'), + type: (gamepad.getUrlParam(`${axis}Type`) || "axis").replace( + "axis", + "axe", + ), index: gamepad.getUrlParam(`${axis}Index`), min: gamepad.getUrlParam(`${axis}Min`) || -1, max: gamepad.getUrlParam(`${axis}Max`) || 1, }; - } } @@ -131,7 +139,7 @@ window.gamepad.TemplateClass = class TelemetryTemplate { if (!this.steering.index) { this.$steering.remove(); } else { - this.$telemetry.classList.add('with-steering'); + this.$telemetry.classList.add("with-steering"); } } @@ -160,9 +168,16 @@ window.gamepad.TemplateClass = class TelemetryTemplate { this.scaleChart(); const now = Date.now(); this.chartData = []; - for (let index = 0; index < this.historyLength / this.interval; index++) { - const timestamp = now - (this.historyLength - index * this.interval); - const data = demo ? this.getDemoData() : { clutch: 0, brake: 0, throttle: 0 }; + for ( + let index = 0; + index < this.historyLength / this.interval; + index++ + ) { + const timestamp = + now - (this.historyLength - index * this.interval); + const data = demo + ? this.getDemoData() + : { clutch: 0, brake: 0, throttle: 0 }; this.chartData.push({ timestamp, ...data }); } } @@ -187,7 +202,9 @@ window.gamepad.TemplateClass = class TelemetryTemplate { if (!this.running) return; const gamepad = this.gamepad.getActive(); - const [clutch, brake, throttle, steering] = this.AXES.map((axis) => this.toAxisValue(gamepad, axis)); + const [clutch, brake, throttle, steering] = this.AXES.map((axis) => + this.toAxisValue(gamepad, axis), + ); if (this.withChart) this.drawChart(clutch, brake, throttle); if (this.withMeters) this.updateMeters(clutch, brake, throttle); if (this.withSteering) this.updateSteering(steering); @@ -202,10 +219,38 @@ window.gamepad.TemplateClass = class TelemetryTemplate { * @returns {object} */ getDemoData() { - const clutch = this.withClutch ? Math.max(0, Math.round(Math.sin(this.demoIndex / (1000 / this.interval)) * 100)) : 0; - const brake = this.withBrake ? Math.max(0, Math.round(Math.sin(this.demoIndex / (1000 / this.interval) + 1.5) * 100)) : 0; - const throttle = this.withThrottle ? Math.max(0, Math.round(Math.sin(this.demoIndex / (1000 / this.interval) + 3) * 100)) : 0; - const steering = this.withSteering ? Math.round(Math.sin(this.demoIndex / (1000 / this.interval) + 3) * this.angle) : 0; + const clutch = this.withClutch + ? Math.max( + 0, + Math.round( + Math.sin(this.demoIndex / (1000 / this.interval)) * 100, + ), + ) + : 0; + const brake = this.withBrake + ? Math.max( + 0, + Math.round( + Math.sin(this.demoIndex / (1000 / this.interval) + 1.5) * + 100, + ), + ) + : 0; + const throttle = this.withThrottle + ? Math.max( + 0, + Math.round( + Math.sin(this.demoIndex / (1000 / this.interval) + 3) * + 100, + ), + ) + : 0; + const steering = this.withSteering + ? Math.round( + Math.sin(this.demoIndex / (1000 / this.interval) + 3) * + this.angle, + ) + : 0; if (this.demoIndex++ > 10000) this.demoIndex = 0; return { clutch, brake, throttle, steering }; } @@ -256,14 +301,17 @@ window.gamepad.TemplateClass = class TelemetryTemplate { chartContext.clearRect(0, 0, width, height); for (const axis of this.AXES) { - if (axis === 'steering') continue; + if (axis === "steering") continue; chartContext.beginPath(); for (let index = 0; index < this.chartData.length; index++) { const entry = this.chartData[index]; - const x = (entry.timestamp + this.historyLength - now) / this.historyLength * width; - const y = (101 - (entry[axis] || 0)) * height / 100; - chartContext[index === 0 ? 'moveTo' : 'lineTo'](x, y); + const x = + ((entry.timestamp + this.historyLength - now) / + this.historyLength) * + width; + const y = ((101 - (entry[axis] || 0)) * height) / 100; + chartContext[index === 0 ? "moveTo" : "lineTo"](x, y); } chartContext.strokeStyle = this.chartColors[axis]; @@ -280,10 +328,15 @@ window.gamepad.TemplateClass = class TelemetryTemplate { * @param {number} steering */ updateMeters(clutch, brake, throttle) { - for (const [axis, value] of Object.entries({ clutch, brake, throttle })) { + for (const [axis, value] of Object.entries({ + clutch, + brake, + throttle, + })) { if (value === null) continue; this[`$${axis}Value`].innerHTML = value; - this[`$${axis}Value`].style.opacity = `${Math.round(33 + (value / 1.5))}%`; + this[`$${axis}Value`].style.opacity = + `${Math.round(33 + value / 1.5)}%`; this[`$${axis}Bar`].style.height = `${value}%`; } } @@ -302,7 +355,9 @@ window.gamepad.TemplateClass = class TelemetryTemplate { */ setupWizard() { this.interval = 1000 / 60; - this.$wizardInstructions.querySelector('#wizard-preview').appendChild(this.$telemetry); + this.$wizardInstructions + .querySelector("#wizard-preview") + .appendChild(this.$telemetry); this.withChart = true; this.withMeters = true; @@ -316,84 +371,107 @@ window.gamepad.TemplateClass = class TelemetryTemplate { this.updateDemo(); const $inputs = { - $clutchOption: this.$wizardInstructions.querySelector('#clutch-option'), - $brakeOption: this.$wizardInstructions.querySelector('#brake-option'), - $throttleOption: this.$wizardInstructions.querySelector('#throttle-option'), - $steeringOption: this.$wizardInstructions.querySelector('#steering-option') + $clutchOption: + this.$wizardInstructions.querySelector("#clutch-option"), + $brakeOption: + this.$wizardInstructions.querySelector("#brake-option"), + $throttleOption: + this.$wizardInstructions.querySelector("#throttle-option"), + $steeringOption: + this.$wizardInstructions.querySelector("#steering-option"), }; - const $chartOption = this.$wizardInstructions.querySelector('#chart-option'); - const $historyOption = this.$wizardInstructions.querySelector('#history-option'); - const $metersOption = this.$wizardInstructions.querySelector('#meters-option'); - const $steeringAngleOption = this.$wizardInstructions.querySelector('#steering-angle-option'); - const $fpsOption = this.$wizardInstructions.querySelector('[name=fps-option]'); + const $chartOption = + this.$wizardInstructions.querySelector("#chart-option"); + const $historyOption = + this.$wizardInstructions.querySelector("#history-option"); + const $metersOption = + this.$wizardInstructions.querySelector("#meters-option"); + const $steeringAngleOption = this.$wizardInstructions.querySelector( + "#steering-angle-option", + ); + const $fpsOption = + this.$wizardInstructions.querySelector("[name=fps-option]"); - $inputs.$clutchOption.addEventListener('change', () => { + $inputs.$clutchOption.addEventListener("change", () => { this.withClutch = $inputs.$clutchOption.checked; if (this.withClutch) { - this.$clutch.style.display = ''; + this.$clutch.style.display = ""; } else { - this.$clutch.style.display = 'none'; - for (const data of this.chartData) { data.clutch = 0; } + this.$clutch.style.display = "none"; + for (const data of this.chartData) { + data.clutch = 0; + } } }); - $inputs.$brakeOption.addEventListener('change', () => { + $inputs.$brakeOption.addEventListener("change", () => { this.withBrake = $inputs.$brakeOption.checked; if (this.withBrake) { - this.$brake.style.display = ''; + this.$brake.style.display = ""; } else { - this.$brake.style.display = 'none'; - for (const data of this.chartData) { data.brake = 0; } + this.$brake.style.display = "none"; + for (const data of this.chartData) { + data.brake = 0; + } } }); - $inputs.$throttleOption.addEventListener('change', () => { + $inputs.$throttleOption.addEventListener("change", () => { this.withThrottle = $inputs.$throttleOption.checked; if (this.withThrottle) { - this.$throttle.style.display = ''; + this.$throttle.style.display = ""; } else { - this.$throttle.style.display = 'none'; - for (const data of this.chartData) { data.throttle = 0; } + this.$throttle.style.display = "none"; + for (const data of this.chartData) { + data.throttle = 0; + } } }); - $inputs.$steeringOption.addEventListener('change', () => { + $inputs.$steeringOption.addEventListener("change", () => { this.withSteering = $inputs.$steeringOption.checked; if (this.withSteering) { - this.$steering.style.display = ''; + this.$steering.style.display = ""; } else { - this.$steering.style.display = 'none'; + this.$steering.style.display = "none"; } }); - $chartOption.addEventListener('change', () => { + $chartOption.addEventListener("change", () => { this.withChart = $chartOption.checked; if (this.withChart) { - this.$chart.style.display = ''; + this.$chart.style.display = ""; } else { - this.$chart.style.display = 'none'; + this.$chart.style.display = "none"; } this.setupChart(true); }); - $historyOption.addEventListener('change', () => { + $historyOption.addEventListener("change", () => { this.historyLength = Number.parseInt($historyOption.value) * 1000; this.setupChart(true); }); - $metersOption.addEventListener('change', () => { + $metersOption.addEventListener("change", () => { this.withMeters = $metersOption.checked; if (this.withMeters) { - this.$meters.style.display = ''; + this.$meters.style.display = ""; } else { - this.$meters.style.display = 'none'; + this.$meters.style.display = "none"; } this.setupChart(true); }); - $steeringAngleOption.addEventListener('change', () => { + $steeringAngleOption.addEventListener("change", () => { this.angle = $steeringAngleOption.value; }); - $fpsOption.addEventListener('change', () => { + $fpsOption.addEventListener("change", () => { this.interval = 1000 / Number.parseInt($fpsOption.value); console.log(this.interval); this.setupChart(true); }); - return { $inputs, $chartOption, $historyOption, $metersOption, $steeringAngleOption, $fpsOption }; + return { + $inputs, + $chartOption, + $historyOption, + $metersOption, + $steeringAngleOption, + $fpsOption, + }; } /** @@ -406,9 +484,10 @@ window.gamepad.TemplateClass = class TelemetryTemplate { return new Promise((resolve) => { const interval = window.setInterval(() => { const gamepad = this.gamepad.getActive(); - const pressedButton = index !== undefined - ? gamepad.buttons[index].pressed - : gamepad.buttons.some((button) => button.pressed); + const pressedButton = + index !== undefined + ? gamepad.buttons[index].pressed + : gamepad.buttons.some((button) => button.pressed); if (pressedButton) return; window.clearInterval(interval); resolve(); @@ -425,7 +504,9 @@ window.gamepad.TemplateClass = class TelemetryTemplate { return new Promise((resolve) => { const pressInterval = window.setInterval(() => { const gamepad = this.gamepad.getActive(); - const index = gamepad.buttons.findIndex((button) => button.pressed); + const index = gamepad.buttons.findIndex( + (button) => button.pressed, + ); if (index === -1) return; window.clearInterval(pressInterval); const releaseInterval = window.setInterval(() => { @@ -457,7 +538,10 @@ window.gamepad.TemplateClass = class TelemetryTemplate { value = gamepad.axes[index]; return; } - if (referenceValue !== undefined && Math.abs(gamepad.axes[index] - referenceValue) < 0.5) { + if ( + referenceValue !== undefined && + Math.abs(gamepad.axes[index] - referenceValue) < 0.5 + ) { return; } if (Math.abs(gamepad.axes[index] - value) > 0.05) { @@ -556,21 +640,25 @@ window.gamepad.TemplateClass = class TelemetryTemplate { $historyOption, $metersOption, $steeringAngleOption, - $fpsOption + $fpsOption, } = this.setupWizard(); await this.waitButtonRelease(); await this.waitButtonClick(); return { - ...this.AXES.reduce((options, axis) => Object.assign( - options, - { [`with${this.capitalize(axis)}`]: $inputs[`$${axis}Option`].checked } - ), {}), + ...this.AXES.reduce( + (options, axis) => + Object.assign(options, { + [`with${this.capitalize(axis)}`]: + $inputs[`$${axis}Option`].checked, + }), + {}, + ), chart: $chartOption.checked, history: Number.parseInt($historyOption.value) * 1000, meters: $metersOption.checked, angle: $steeringAngleOption.value, - fps: Number.parseInt($fpsOption.value) + fps: Number.parseInt($fpsOption.value), }; } @@ -586,16 +674,25 @@ window.gamepad.TemplateClass = class TelemetryTemplate { return new Promise((resolve) => { const interval = window.setInterval(async () => { const gamepad = this.gamepad.getActive(); - const buttonIndex = ['button', undefined].includes(type) - ? gamepad.buttons.findIndex((button, index) => button.pressed && Math.abs(button.value - before.buttons[index].value) > distance) + const buttonIndex = ["button", undefined].includes(type) + ? gamepad.buttons.findIndex( + (button, index) => + button.pressed && + Math.abs( + button.value - before.buttons[index].value, + ) > distance, + ) : -1; - const axisIndex = ['axis', undefined].includes(type) - ? gamepad.axes.findIndex((axis, index) => Math.abs(axis - before.axes[index]) > distance) + const axisIndex = ["axis", undefined].includes(type) + ? gamepad.axes.findIndex( + (axis, index) => + Math.abs(axis - before.axes[index]) > distance, + ) : -1; if (buttonIndex === -1 && axisIndex === -1) return; window.clearInterval(interval); resolve({ - type: buttonIndex === -1 ? 'axis' : 'button', + type: buttonIndex === -1 ? "axis" : "button", index: buttonIndex === -1 ? axisIndex : buttonIndex, }); }, 100); @@ -613,7 +710,7 @@ window.gamepad.TemplateClass = class TelemetryTemplate {

Waiting for ${name} activity.

`; const { type, index } = await this.detectActivity(); - if (type === 'button') { + if (type === "button") { this.$wizardInstructions.innerHTML = `

Release the ${name} button.

`; @@ -643,7 +740,7 @@ window.gamepad.TemplateClass = class TelemetryTemplate { this.$wizardInstructions.innerHTML = `

Turn the steering axis all the way to the left.

`; - const { index } = await this.detectActivity('axis', 0.2); + const { index } = await this.detectActivity("axis", 0.2); const leftValue = await this.getAxisPush(index, 0); this.$wizardInstructions.innerHTML = ` @@ -664,7 +761,7 @@ window.gamepad.TemplateClass = class TelemetryTemplate { return Object.entries(options) .filter(([, value]) => value !== undefined && value !== null) .map(([key, value]) => `${key}=${value}`) - .join('&'); + .join("&"); } /** @@ -694,22 +791,35 @@ window.gamepad.TemplateClass = class TelemetryTemplate { * @returns {Promise} */ async wizard() { - this.$wizard.classList.add('active'); + this.$wizard.classList.add("active"); const gamepad = this.gamepad.getActive(); - const { withClutch, withBrake, withThrottle, withSteering, chart, history, meters, angle, fps } = await this.askForOptions(); - const clutch = withClutch && await this.calibratePedal('clutch'); - const brake = withBrake && await this.calibratePedal('brake'); - const throttle = withThrottle && await this.calibratePedal('throttle'); - const steering = withSteering && await this.calibrateSteering(); + const { + withClutch, + withBrake, + withThrottle, + withSteering, + chart, + history, + meters, + angle, + fps, + } = await this.askForOptions(); + const clutch = withClutch && (await this.calibratePedal("clutch")); + const brake = withBrake && (await this.calibratePedal("brake")); + const throttle = + withThrottle && (await this.calibratePedal("throttle")); + const steering = withSteering && (await this.calibrateSteering()); window.location.href = [ `?gamepad=${gamepad.id}&type=telemetry`, this.toOptionsParams({ chart, history, meters, angle, fps }), - withClutch ? this.toPedalParams('clutch', clutch) : null, - withBrake ? this.toPedalParams('brake', brake) : null, - withThrottle ? this.toPedalParams('throttle', throttle) : null, - withSteering ? this.toSteeringParams(steering) : null - ].filter(e => e !== null).join('&'); + withClutch ? this.toPedalParams("clutch", clutch) : null, + withBrake ? this.toPedalParams("brake", brake) : null, + withThrottle ? this.toPedalParams("throttle", throttle) : null, + withSteering ? this.toSteeringParams(steering) : null, + ] + .filter((e) => e !== null) + .join("&"); } }; diff --git a/templates/xbox-one/template.html b/templates/xbox-one/template.html index 0231256..3870584 100644 --- a/templates/xbox-one/template.html +++ b/templates/xbox-one/template.html @@ -22,8 +22,18 @@
- - + +
diff --git a/templates/xbox-one/template.js b/templates/xbox-one/template.js index ffa792e..db976bf 100644 --- a/templates/xbox-one/template.js +++ b/templates/xbox-one/template.js @@ -17,26 +17,41 @@ window.gamepad.TemplateClass = class XboxOneTemplate { } updateButton($button, button) { - if (!$button.matches('.trigger') || !button) return; - $button.style.setProperty('opacity', this.gamepad.useMeterTriggers ? 1 : `${button.value * 100}%`); - $button.style.setProperty('clip-path', this.gamepad.useMeterTriggers ? `inset(${100 - button.value * 100}% 0px 0px 0pc)` : 'none'); + if (!$button.matches(".trigger") || !button) return; + $button.style.setProperty( + "opacity", + this.gamepad.useMeterTriggers ? 1 : `${button.value * 100}%`, + ); + $button.style.setProperty( + "clip-path", + this.gamepad.useMeterTriggers + ? `inset(${100 - button.value * 100}% 0px 0px 0pc)` + : "none", + ); } updateAxis($axis, attribute, axis) { - if (!$axis.matches('.stick')) return; - if (attribute === 'data-axis-x') { - $axis.style.setProperty('margin-left', `${axis * 25}px`); + if (!$axis.matches(".stick")) return; + if (attribute === "data-axis-x") { + $axis.style.setProperty("margin-left", `${axis * 25}px`); this.updateRotate($axis); } - if (attribute === 'data-axis-y') { - $axis.style.setProperty('margin-top', `${axis * 25}px`); + if (attribute === "data-axis-y") { + $axis.style.setProperty("margin-top", `${axis * 25}px`); this.updateRotate($axis); } } updateRotate($axis) { - const rotateX = Number.parseFloat($axis.getAttribute('data-value-y') * 30); - const rotateY = -Number.parseFloat($axis.getAttribute('data-value-x') * 30); - $axis.style.setProperty('transform', `rotateX(${rotateX}deg) rotateY(${rotateY}deg)`); + const rotateX = Number.parseFloat( + $axis.getAttribute("data-value-y") * 30, + ); + const rotateY = -Number.parseFloat( + $axis.getAttribute("data-value-x") * 30, + ); + $axis.style.setProperty( + "transform", + `rotateX(${rotateX}deg) rotateY(${rotateY}deg)`, + ); } };