From dcf99eadcaad02a6d5f9a76857bf2c3d54cd7be5 Mon Sep 17 00:00:00 2001 From: 4aiman <4aiman@inbox.ru> Date: Sun, 19 Jan 2020 19:10:35 +0300 Subject: [PATCH] Initial commit --- gpcon.js | 165 +++++++++++++++++++++++++++++++++++++++ index.html | 11 +++ main.css | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 399 insertions(+) create mode 100644 gpcon.js create mode 100644 index.html create mode 100644 main.css diff --git a/gpcon.js b/gpcon.js new file mode 100644 index 0000000..ea540d4 --- /dev/null +++ b/gpcon.js @@ -0,0 +1,165 @@ +/* + Copyright 2017 Brian "Beej Jorgensen" Hall + Copyright 2020 4aiman @ github.com + +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. + */ + +let buttons = []; // remembers if button was added +let axes = []; // remembers if axis was added (separate X and Y values) +let axes_c = []; // remembers if axis box was added (combines X and Y of one stick) +let l_stick = 10; // L3 button id (change this to ID of L3 button and it will appear as the left stick) +let r_stick = 11; // R3 button id (change this to ID of R3 button and it will appear as the right stick) + +function onFrame() { // gets repeatedly executed + let gamepads = navigator.getGamepads(); // this gets *all* gamepads that your browser was able to detect + // note: gamepad may stay undetected until you press a button on it + let gp = gamepads[0]; // we start with the 1st gamepad + if (!gp) { // but browsers can detect some NULL devices, so we check if there's really something + for (i = 0; i < gamepads.length; i++) { // cycling and checking every other gamepad seems good enough + gp = gamepads[i]; // we get a gemapad + if (!gp) { // and if there's nothing + continue; // we check the next one + } else { + break; // but if there's a gamepad, we stop and work with what we just got + } + } + } + + if (!gp) { // in case all gamepads are NULL, we just start over + requestAnimationFrame(onFrame); + return; + } + + if (typeof gp === "undefined") { // seems unnecessary, but hey, we need to be sure a gamepad exists + } else { // at this point gamepad is properly detected + let buttdiv = document.getElementById('buttons') // so, we get our container element (see index.html) and add 'buttons' to it + for (j = 0; j < gp.buttons.length; j++) { // we cycle through all detected buttons and add those to a 'buttons' array + if (typeof buttons[j] === "undefined") { // if jth button isn't added yet, we will do just that + if (j>15) {continue;} // just be sure to skip weird non-existing buttons on your gamepad (PS3 Dualshock here) + if (j==l_stick || j==r_stick) continue; // we also need to skip sticks to add those later (if your gamepad doesn't have 'pressable' sticks - comment this line) + + let buttEle = document.createElement('span'); // create a new element (a button) + buttEle.classList.add('button'); // set it's class to 'button', so css can kick in + buttEle.classList.add('button_'+j) // set additional class to allow customization via css + buttEle.setAttribute("id",'button_'+j) // set new button's ID so we can get it later and change it's style + buttdiv.appendChild(buttEle); // add newly created button to the 'container' + + // now to add SVG-generated graphics to some non-round-shaped buttons + if (j==9) {// start + buttEle.innerHTML = ''; + } + if (j==12) {//up + buttEle.innerHTML = ''; + } + if (j==13) {//down + buttEle.innerHTML = ''; + } + if (j==14) {//left + buttEle.innerHTML = ''; + } + if (j==15) {//right + buttEle.innerHTML = ''; + } + buttons[j] = true; // remember that jth button has been added + + } else { // this part kick in when jth button has been added already + let buttEle = document.getElementById('button_'+j); // we get correnponding element in our HTML document + let val = gp.buttons[j].value; // val keeps the value browser got from jth button (can be 0, 1 or smth in-between for analogue buttons) + if (gp.buttons[j].pressed) { // if current button is pressed we can alter it's style + if (j==9) { // the 'start' button (as well as any other non-round-shaped button) has to have it's innerHTML rewritten + buttEle.innerHTML = ''; + } else { // sure, this could've been coded better, but what the heck, it works + if (j<=11) { // buttons with id lower that 12 are usually the round-shaped ones; on-stick buttons go here as well + buttEle.style.background='linear-gradient(to top, rgba(255,255,255,0.5) '+val*100+'%, rgba(170,70,70,0.5) '+val*100+'%)';// gradient really helps to visualize partial presses + } + if (j>=12) {// up + buttEle.innerHTML = ''; + } + if (j==13) {// down + buttEle.innerHTML = ''; + } + if (j==14) {// left + buttEle.innerHTML = ''; + } + if (j==15) {// right + buttEle.innerHTML = ''; + } + } + } else { // if current button is *not* pressed we should revert it's style + if (j==9) {// once again, the 'start' button needs special attention + buttEle.innerHTML = ''; + } else { + if (j<=11) { // round-shaped buttons can be processed similarly + buttEle.style.background='rgba(70,70,70,0.5)'; + } + if (j==12) { // and of cource directional buttons: up + buttEle.innerHTML = ''; + } + if (j==13) {// down + buttEle.innerHTML = ''; + } + if (j==14) {// left + buttEle.innerHTML = ''; + } + if (j==15) {// right + buttEle.innerHTML = ''; + } + } + } + } + } // at this point we're done with the buttons + + for (j = 0; j < gp.axes.length; j++) { // all that is left is to process axes + if (typeof axes[j] === "undefined") { // it's all the same for those except the need to 'combine' X and Y axes + let b = (j)/2|0; // and here's why this 'b' is here: it will be incremented by 1 every other *even* j, thus enabling us to check for *pairs* + if (!axes_c[b]) { // so, if current pair hasn't been registered yet - do it now + let axisEle = document.createElement('div'); // this is a rounded box around the bth stick + axisEle.classList.add('axisbox'); // we can add a basic class for styling purposes + axisEle.classList.add('axisbox_'+b) // and a separete unique class to fine-tune that styling (wish polymer did that) + buttdiv.appendChild(axisEle); // finally add axes box to 'container' + + let buttEle = document.createElement('span'); // butons with l_stick and r_stick ids are being added here + buttEle.classList.add('button'); // same treatments as the other buttons for class + buttEle.classList.add('button_'+(b+l_stick)) // unique class + buttEle.setAttribute("id",'button_'+(b+l_stick)) // and id (needed not only to colorize, but to move around these ones) + axisEle.appendChild(buttEle); // and now to add these 'movable' buttons + buttons[b+l_stick]=0; // also, remeber those buttons are there + axes_c[b] = [0,0]; // as well as those axes pairs + } + axes[j] = 0; // aaannd separate axis + } else { // now this is for moving 'sticks' around + let b = (j)/2|0; // just like before we determine what axes pair is this and + let axisEleL = document.getElementById('button_'+(b+l_stick)); // get the correct id of a button to move + if (b === ((j)/2)|0 ) { // if axis id is odd, then we are dealing with Y axis + axisEleL.style.left = ((gp.axes[j]*1000)/100|0)+6+'px'; + } else { // if it's even - with X axis + axisEleL.style.top = ((gp.axes[j]*1000)/100|0)+6+'px'; + }; + } + } + } + requestAnimationFrame(onFrame); // at the end of a cycle we call onFrame once again +} + +function onLoad() { // this function gets called in an event listener and potentially may perform something else, but meh + requestAnimationFrame(onFrame); // it just calls onFrame for the first time +} + +window.addEventListener('load', onLoad);// and the last (but not least): we need to actually tell our page to execute onLoad whrn the page is ready \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..124bbae --- /dev/null +++ b/index.html @@ -0,0 +1,11 @@ + + + + + + + + +
+ + diff --git a/main.css b/main.css new file mode 100644 index 0000000..4f2ec51 --- /dev/null +++ b/main.css @@ -0,0 +1,223 @@ +body { +/*background:rgba(0,80,80,0.7); */ +} + +.button { + border:1px solid rgba(50,50,50,0.5); + width:25px; + height:25px; + border-radius:13px; + display:inline-block; + background: rgba(70,70,70,0.5); + padding:0px; + margin:px; + text-align:center; + vertical-align:middle; + font-weight: bold; + position:absolute; + text-shadow: 1px 1px 1px rgba(0,0,0,0.25), 0px 1px 1px rgba(0,0,0,0.25), 1px 0px 1px rgba(0,0,0,0.25); +} + +.button_4, .button_5, .button_6, .button_7 { + width:35px; + height:20px; + border-radius:8px; +} + +.button_8 { + width:30px; + height:15px; + border-radius:4px; +} + +.button_9 { + border:0px; + background:transparent; + height:25px; + width:25px; +} + + +.button::after { + position:relative; + color: rgba(250,250,250,0.5); + font-size:13px; +} + +.button_0::after { + content:"✕"; + color: rgba(80,120,200,0.5); + font-size:22px; + top:-4px; +} + +.button_1::after { + content:"○"; + color: rgba(200,120,80,0.5); + font-size:41px; + top:-14px; +} + +.button_2::after { + content:"□"; + color: rgba(250,80,80,0.5); + font-size:35px; + top:-12px; +} + +.button_3::after { + content:"△"; + color: rgba(60,200,100,0.5); + font-size:23px; + top:-3px; +} + +.button_4::after { + content:"L1"; +} + +.button_5::after { + content:"R1"; +} + +.button_6::after { + content:"L2"; +} + +.button_7::after { + content:"R2"; +} + +.button_10::after { + content:"L3"; + top:2px; +} + +.button_11::after { + content:"R3"; + top:2px; +} + +#button_9_border { + position:relative; + top:3px; +} + +.button_12, .button_13, .button_14, .button_15 { + border:0px; + background:transparent; + height:25px; + width:25px; + } + +.button_12 { + left:46px; + top:14px; +} +.button_13 { + left:46px; + top:63px; +} + +.button_14 { + left:21px; + top:39px; +} +.button_15 { + left:70px; + top:39px; +} + +.button_3 { + left:226px; + top:12px; +} +.button_0 { + left:226px; + top:61px; +} + +.button_2 { + left:201px; + top:37px; +} +.button_1 { + left:250px; + top:37px; +} + +.button_4 { + left:2px; + top: 1px; +} +.button_6 { + left:80px; + top: 1px; +} + +.button_5 { + left:260px; + top: 1px; + +} +.button_7 { + left:182px; + top: 1px; +} + +.button_8 { + left:111px; + top:42px; +} + +.button_9 { + left:161px; + top:37px; +} + +.button_10 { + position:relative; + border:1px solid rgba(250,200,150,0.5); +} + +.button_11 { + position:relative; + border:1px solid rgba(250,200,150,0.5); +} + + +#buttons { + position:absolute; + transform: scale(0.9); +} + + +.axisbox { + border-radius:20px; + border:1px solid red; + width:40px; + height:40px; + position:absolute; + top: 65px; + border:1px solid rgba(50,50,50,0.5); + background: rgba(70,70,70,0.5); +} + +.axisbox_0 { + left:105px; +} + +.axisbox_1 { + left:155px; +} + +.axis{ + margin-left:-5px; + margin-top:-5px; + border-radius:5px; + border:1px solid black; + width:10px; + height:10px; + display:block; + position:relative; +} \ No newline at end of file