Compare commits

...

36 commits

Author SHA1 Message Date
Daniel Bulant
73b03f9cf4
HALT 2020-02-07 17:24:11 +01:00
danbulant
99d943a41a working on DS4 controller 2020-01-05 18:18:41 +01:00
danbulant
a19487d016 User selection, security & welcome page 2019-12-31 15:34:50 +01:00
danbulant
39277042a0 Working on cards 2019-12-30 21:29:12 +01:00
danbulant
6533205341 Start working on cards-list 2019-12-30 20:46:54 +01:00
danbulant
4149e2c868 Add utils 2019-12-30 20:40:22 +01:00
danbulant
38aae4f425 Remove unnecesary logs 2019-12-30 20:40:13 +01:00
danbulant
e7e4fc4340 Remove unnecesary check 2019-12-30 20:40:01 +01:00
danbulant
e39b65860d Better input 2019-12-30 20:39:48 +01:00
danbulant
de92e39f34 Update readme 2019-12-30 20:39:36 +01:00
danbulant
7979ab6f23 Remove old games.js 2019-12-30 20:39:27 +01:00
danbulant
784997b97d Remove version.txt 2019-12-30 20:39:15 +01:00
danbulant
4a63e3e4aa Remove unnecesarry things & code clarity 2019-12-30 20:39:04 +01:00
danbulant
f7071cc281 Install electron-reload 2019-12-30 20:38:45 +01:00
danbulant
4488d1421b Data classes 2019-12-30 20:38:27 +01:00
danbulant
c0d7f3cabf Add fonts 2019-12-30 20:38:05 +01:00
danbulant
ff32867037 Output styles to dist 2019-12-30 20:37:58 +01:00
danbulant
23b3d9cebc Styles 2019-12-30 20:37:46 +01:00
danbulant
3c081d9e30 Prepare for rewrite 2019-12-30 19:01:16 +01:00
danbulant
07bd26a9a6 Move files and prepare for rewrite 2019-12-30 18:59:50 +01:00
Daniel Bulant
8e9015e6ba
No longer in active development (ABANDONED) 2019-12-08 19:01:14 +01:00
danbulant
cabd300089 Testing keybinds (gamepad to keyboard)
Not currently working
2019-06-25 15:06:53 +02:00
danbulant
59db56981b Remove unused require 2019-06-25 14:48:43 +02:00
danbulant
268b15a374 Update keySend 2019-06-25 14:44:13 +02:00
danbulant
fa882c2f97 Testing gamepad to keyboard 2019-06-24 15:19:46 +02:00
danbulant
355c050522 Testing gamepad 2019-06-24 14:57:38 +02:00
danbulant
79fae9716d Merge branch 'master' of https://github.com/danbulant/console-hub 2019-06-24 14:40:21 +02:00
danbulant
b4cede61ca Add backend for sending keyboard presses 2019-06-24 14:40:15 +02:00
danbulant
7a934929ef Disable game menu, no games available at the moment 2019-06-24 14:36:29 +02:00
Daniel Bulant
f3eea955e2
Add requirements 2019-06-24 14:35:59 +02:00
danbulant
115644037d Better words 2019-06-23 17:10:24 +02:00
danbulant
9903a5e044 Merge branch 'master' of https://github.com/danbulant/console-hub 2019-06-23 17:09:27 +02:00
danbulant
e48963d765 update to 0.2.0 2019-06-23 17:09:14 +02:00
danbulant
4e350d6ff2 Fix links 2019-06-23 17:02:38 +02:00
danbulant
ed430cc7c5 Fix links 2019-06-23 17:02:11 +02:00
danbulant
19209efdf0 Fix node checker 2019-06-23 16:49:16 +02:00
76 changed files with 7159 additions and 1506 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
node_modules

View file

@ -1,10 +1,29 @@
# console-hub [![Build Status](https://travis-ci.org/danbulant/console-hub.svg?branch=master)](https://travis-ci.org/danbulant/console-hub)
Hub application to be controlled with controller (gamepad) through gamepad HTML5 API
# DEVELOPMENT HALTED
No further development is planned for console-hub. If you still want to use the code, feel free to do so, but this project won't be maintained anymore.
---
Below readme is old and won't work. Also, the current version won't do anything else than just allow switching between accounts on main screen.
# DEVELOPMENT
Console hub is currently under heavy rewrite, so it might not be working. Do not report bugs directly - contact me at discord (http://go-dan.tk/discord) instead.
## Installation
Installation can be done both with electron and on normal websites.
### Electron
#### Requirements
To run electron version, you must have the following:
* Java 8 runtime
* Node (10+)
* Other will be installed automatically via project.json
If you have installed node.js and electron, you can build the app yourself.
For packaging, I personally use (and prefer) [electron-packager](https://github.com/electron-userland/electron-packager).
Use all files in the repository (`electron-packager .`)
@ -21,8 +40,9 @@ Because of legal issues (Copyright, cannot upload publicly), fonts and styles ar
If you did everything correctly, Console hub now have all required files to run offline.
## Demo
### GitHub
A github demo is accesible on [GitHub.io](https://console.danbulant.eu/console-hub/html/index.html), where is available latest development.
**No demo is available, as new rewrite uses node's require**
### ~~GitHub~~
~~A github demo is accesible on [GitHub.io](https://console.danbulant.eu/console-hub/html/index.html), where is available latest development.~~
## Features
For feature/bugs that are currently worked on, please see our (kanban table)[https://trello.com/b/DlwuRuwZ/console-hub]

74
controller.js Normal file
View file

@ -0,0 +1,74 @@
var dualShock = require('./dist/dualshock-controller/src/dualshock');
var controller = dualShock({
config: "dualshock4-generic-driver"
});
controller.on('error', err => console.log(err));
function setExtras(obj){
controller.setExtras(obj);
}
var connected = false;
controller.on('connected', () => {
connected = true;
});
controller.on("disconnected", ()=>{
connected = false;
})
function isConnected(){
return connected;
}
//add event handlers:
// controller.on('left:move', data => console.log('left Moved: ' + data.x + ' | ' + data.y));
// controller.on('right:move', data => console.log('right Moved: ' + data.x + ' | ' + data.y));
// controller.on('square:press', () => console.log('square press'));
// controller.on('square:release', () => console.log('square release'));
//sixasis motion events:
//the object returned from each of the movement events is as follows:
//{
// direction : values can be: 1 for right, forward and up. 2 for left, backwards and down.
// value : values will be from 0 to 120 for directions right, forward and up and from 0 to -120 for left, backwards and down.
//}
function on(event, handler){
controller.on(event, handler);
}
module.exports = {
on,
isConnected,
setExtras
}
// controller.on('touchpad:x1:active', () => console.log('touchpad one finger active'));
// controller.on('touchpad:x2:active', () => console.log('touchpad two fingers active'));
// controller.on('touchpad:x2:inactive', () => console.log('touchpad back to single finger'));
// controller.on('touchpad:x1', data => console.log('touchpad x1:', data.x, data.y));
// controller.on('touchpad:x2', data => console.log('touchpad x2:', data.x, data.y));
// //right-left movement
// controller.on('rightLeft:motion', data => console.log(data));
// //forward-back movement
// controller.on('forwardBackward:motion', data => console.log(data));
// //up-down movement
// controller.on('upDown:motion', data => console.log(data));
// //controller status
// //as of version 0.6.2 you can get the battery %, if the controller is connected and if the controller is charging
// controller.on('battery:change', data => console.log(data));
// controller.on('connection:change', data => console.log(data));
// controller.on('charging:change', data => console.log(data));

2
dist/css/styles.min.css vendored Normal file
View file

@ -0,0 +1,2 @@
@import url("https://fonts.googleapis.com/css?family=Open+Sans&display=swap");@font-face{font-family:'Gilroy-bold';src:url("../../dist/fonts/Gilroy-ExtraBold.otf")}body{margin:0;padding:0;background-color:#0e6cc4;overflow-x:hidden;overflow-y:hidden}.title--main{margin:0;padding:0;position:fixed;left:45px;top:100px;font-size:4rem;color:white;font-family:'Gilroy-bold'}.view{width:100%}.title--description{margin:0;padding:0;position:fixed;left:80px;top:175px;font-size:1.3rem;color:white;font-family:'Open Sans', sans-serif}.title--main.middle,.title--description.middle{left:50%;top:50%}.user-cards-list{z-index:99;width:100%;height:30vh;margin-top:30vh;display:-webkit-box;display:-ms-flexbox;display:flex}.user-cards-list .card{z-index:99;margin:5px;font-family:'Open Sans', sans-serif;width:30vh;height:30vh;background-size:30vh 30vh;font-size:2rem;color:white;border:5px solid transparent}.user-cards-list .card .name{margin-top:-15px;padding-left:5px;font-size:43px}.user-cards-list .card img{height:100%;width:100%}.user-cards-list .card p{margin:0}.user-cards-list .card.selected{border:5px solid white}.user-cards-list .card:first-child{margin-left:auto}.user-cards-list .card:last-child{margin-right:auto}.box{z-index:1;position:fixed;top:0;-webkit-transform:rotate(80deg);transform:rotate(80deg);left:0}.wave{position:fixed;top:0;left:0;opacity:.4;position:absolute;top:3%;left:10%;background:#0af;width:3000px;height:2600px;margin-left:-150px;margin-top:-250px;-webkit-transform-origin:50% 48%;transform-origin:50% 48%;border-radius:43%;-webkit-animation:drift 9000ms infinite linear;animation:drift 9000ms infinite linear}.wave.-three{-webkit-animation:drift 8500ms infinite linear;animation:drift 8500ms infinite linear;position:fixed;background-color:#77daff}.wave.-two{-webkit-animation:drift 8000ms infinite linear;animation:drift 8000ms infinite linear;opacity:.1;background:black;position:fixed}.box:after{content:'';display:block;left:0;top:0;width:100%;height:100%;z-index:11;-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}@-webkit-keyframes drift{from{-webkit-transform:rotate(0deg);transform:rotate(0deg)}from{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes drift{from{-webkit-transform:rotate(0deg);transform:rotate(0deg)}from{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}
/*# sourceMappingURL=styles.min.css.map */

9
dist/css/styles.min.css.map vendored Normal file
View file

@ -0,0 +1,9 @@
{
"version": 3,
"mappings": "AAQA,OAAO,CAAC,qEAAI,CACZ,UAAU,CACR,WAAW,CAAE,aAAa,CAC1B,GAAG,CAAE,4CAA4C,CAGnD,AAAA,IAAI,AAAC,CACH,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CACX,gBAAgB,CAAE,OAAO,CACzB,UAAU,CAAC,MAAM,CACjB,UAAU,CAAC,MAAM,CACjB,AAED,AAAA,YAAY,AAAC,CACX,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CACV,QAAQ,CAAE,KAAK,CACf,IAAI,CAAE,IAAI,CACV,GAAG,CAAE,KAAK,CACV,SAAS,CAAE,IAAI,CACf,KAAK,CAAE,KAAK,CACZ,WAAW,CAAE,aAAa,CAC3B,AACD,AAAA,KAAK,AAAC,CACJ,KAAK,CAAE,IAAI,CACZ,AACD,AAAA,mBAAmB,AAAC,CAClB,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CACV,QAAQ,CAAE,KAAK,CACf,IAAI,CAAE,IAAI,CACV,GAAG,CAAE,KAAK,CACV,SAAS,CAAE,MAAM,CACjB,KAAK,CAAE,KAAK,CACZ,WAAW,CAAE,uBAAuB,CACrC,AAED,AAAA,YAAY,AAAA,OAAO,CAAE,mBAAmB,AAAA,OAAO,AAAC,CAC9C,IAAI,CAAE,GAAG,CACT,GAAG,CAAE,GAAG,CACT,AAED,AAAA,gBAAgB,AAAC,CACf,OAAO,CAAE,EAAE,CACX,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,UAAU,CAAE,IAAI,CAChB,OAAO,CAAE,IAAI,CAmCd,AAxCD,AAME,gBANc,CAMd,KAAK,AAAC,CACJ,OAAO,CAAE,EAAE,CACX,MAAM,CAAE,GAAG,CACX,WAAW,CAAE,uBAAuB,CACpC,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,eAAe,CAAE,SAAS,CAC1B,SAAS,CAAE,IAAI,CACf,KAAK,CAAE,KAAK,CACZ,MAAM,CAAE,qBAAqB,CAa9B,AA5BH,AAgBI,gBAhBY,CAMd,KAAK,CAUH,KAAK,AAAC,CACJ,UAAU,CAAE,KAAK,CACjB,YAAY,CAAE,GAAG,CACjB,SAAS,CAAE,IAAI,CAChB,AApBL,AAqBI,gBArBY,CAMd,KAAK,CAeH,GAAG,AAAC,CACF,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,CACZ,AAxBL,AAyBI,gBAzBY,CAMd,KAAK,CAmBH,CAAC,AAAC,CACA,MAAM,CAAE,CAAC,CACV,AA3BL,AA6BE,gBA7Bc,CA6Bd,KAAK,AAAA,SAAS,AAAC,CAGb,MAAM,CAAE,eAAe,CACxB,AAjCH,AAkCE,gBAlCc,CAkCd,KAAK,AAAA,YAAY,AAAC,CAChB,WAAW,CAAE,IAAI,CAClB,AApCH,AAqCE,gBArCc,CAqCd,KAAK,AAAA,WAAW,AAAC,CACf,YAAY,CAAE,IAAI,CACnB,AAGH,AAAA,IAAI,AAAC,CACH,OAAO,CAAE,CAAC,CACX,QAAQ,CAAE,KAAK,CACf,GAAG,CAAE,CAAC,CACN,SAAS,CAAE,aAAa,CACxB,IAAI,CAAE,CAAC,CACP,AAED,AAAA,KAAK,AAAC,CACL,QAAQ,CAAE,KAAK,CACf,GAAG,CAAE,CAAC,CACN,IAAI,CAAE,CAAC,CACN,OAAO,CAAE,EAAE,CACX,QAAQ,CAAE,QAAQ,CAClB,GAAG,CAAE,EAAE,CACP,IAAI,CAAE,GAAG,CACT,UAAU,CAAE,IAAI,CAChB,KAAK,CAAE,MAAM,CACb,MAAM,CAAE,MAAM,CACd,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,MAAM,CAClB,gBAAgB,CAAE,OAAO,CACzB,aAAa,CAAE,GAAG,CAClB,SAAS,CAAE,4BAA4B,CACxC,AAED,AAAA,KAAK,AAAA,OAAO,AAAC,CACX,SAAS,CAAE,4BAA4B,CACxC,QAAQ,CAAE,KAAK,CACf,gBAAgB,CAAE,OAAO,CACzB,AAED,AAAA,KAAK,AAAA,KAAK,AAAC,CACT,SAAS,CAAE,4BAA4B,CACvC,OAAO,CAAE,EAAE,CACX,UAAU,CAAE,KAAK,CAClB,QAAQ,CAAE,KAAK,CACf,AAED,AAAA,IAAI,AAAA,MAAM,AAAC,CACT,OAAO,CAAE,EAAE,CACX,OAAO,CAAE,KAAK,CACd,IAAI,CAAE,CAAC,CACP,GAAG,CAAE,CAAC,CACN,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,OAAO,CAAE,EAAE,CACX,SAAS,CAAE,oBAAoB,CAChC,AAED,UAAU,CAAV,KAAU,CACR,IAAI,CAAG,SAAS,CAAE,YAAY,CAC9B,IAAI,CAAG,SAAS,CAAE,cAAc",
"sources": [
"../../html/views/styles.scss"
],
"names": [],
"file": "styles.min.css"
}

View file

@ -0,0 +1,9 @@
root = true
[*]
indent_style = space
indent_size = 4
charset = utf-8
trim_trailing_whitespace = true
end_of_line = lf
insert_final_newline = true

6
dist/dualshock-controller/.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
node_modules
*.log
coverage
*.iml
*.idea
.DS_Store

6
dist/dualshock-controller/.travis.yml vendored Normal file
View file

@ -0,0 +1,6 @@
language: node_js
node_js:
- "6.9.2"
before_script:
install: echo "node-hid installation will fail in travis. Overiding `npm install`"
compiler: clang

194
dist/dualshock-controller/README.md vendored Normal file
View file

@ -0,0 +1,194 @@
node-dualshock-controller
=========================
[![Build Status](https://travis-ci.org/rdepena/node-dualshock-controller.png?branch=master)](https://travis-ci.org/rdepena/node-dualshock-controller) [![Code Climate](https://codeclimate.com/github/rdepena/node-dualshock-controller.png)](https://codeclimate.com/github/rdepena/node-dualshock-controller)
`dualshock-controller` Eventing API layer over HID for the Sony DualShock 3 and DualShock 4 controllers
## Installation:
#### OSX/Windows:
```bash
npm install dualshock-controller
```
#### Linux:
Review the [Linux support](#linux-support) section.
## Using the DualShock library
`Important: THE CONTROLLER WILL NOT SEND ANY DATA IF YOU DO NOT PRESS THE PS BUTTON.`
Also, to use the touchpad, rumble and LED capabilities of the controller you
must connect the controller to your computer using a micro-USB cable.
~~~~ javascript
var dualShock = require('dualshock-controller');
//pass options to init the controller.
var controller = dualShock(
{
//you can use a ds4 by uncommenting this line.
//config: "dualshock4-generic-driver",
//if the above configuration doesn't work for you,
//try uncommenting the following line instead.
//config: "dualshock4-alternate-driver"
//if using ds4 comment this line.
config: "dualShock3",
//smooths the output from the acelerometers (moving averages) defaults to true
accelerometerSmoothing: true,
//smooths the output from the analog sticks (moving averages) defaults to false
analogStickSmoothing: false
});
//make sure you add an error event handler
controller.on('error', err => console.log(err));
//DualShock 4 control rumble and light settings for the controller
controller.setExtras({
rumbleLeft: 0, // 0-255 (Rumble left intensity)
rumbleRight: 0, // 0-255 (Rumble right intensity)
red: 0, // 0-255 (Red intensity)
green: 75, // 0-255 (Blue intensity)
blue: 225, // 0-255 (Green intensity)
flashOn: 40, // 0-255 (Flash on time)
flashOff: 10 // 0-255 (Flash off time)
});
//DualShock 3 control rumble and light settings for the controller
controller.setExtras({
rumbleLeft: 0, // 0-1 (Rumble left on/off)
rumbleRight: 0, // 0-255 (Rumble right intensity)
led: 2 // 2 | 4 | 8 | 16 (Leds 1-4 on/off, bitmasked)
});
//add event handlers:
controller.on('left:move', data => console.log('left Moved: ' + data.x + ' | ' + data.y));
controller.on('right:move', data => console.log('right Moved: ' + data.x + ' | ' + data.y));
controller.on('connected', () => console.log('connected'));
controller.on('square:press', ()=> console.log('square press'));
controller.on('square:release', () => console.log('square release'));
//sixasis motion events:
//the object returned from each of the movement events is as follows:
//{
// direction : values can be: 1 for right, forward and up. 2 for left, backwards and down.
// value : values will be from 0 to 120 for directions right, forward and up and from 0 to -120 for left, backwards and down.
//}
//DualShock 4 TouchPad
//finger 1 is x1 finger 2 is x2
controller.on('touchpad:x1:active', () => console.log('touchpad one finger active'));
controller.on('touchpad:x2:active', () => console.log('touchpad two fingers active'));
controller.on('touchpad:x2:inactive', () => console.log('touchpad back to single finger'));
controller.on('touchpad:x1', data => console.log('touchpad x1:', data.x, data.y));
controller.on('touchpad:x2', data => console.log('touchpad x2:', data.x, data.y));
//right-left movement
controller.on('rightLeft:motion', data => console.log(data));
//forward-back movement
controller.on('forwardBackward:motion', data => console.log(data));
//up-down movement
controller.on('upDown:motion', data => console.log(data));
//controller status
//as of version 0.6.2 you can get the battery %, if the controller is connected and if the controller is charging
controller.on('battery:change', data => console.log(data));
controller.on('connection:change', data => console.log(data));
controller.on('charging:change', data => console.log(data));
~~~~
## <a name="linux-support"></a> Linux support:
In order to provide Rumble/Gyro and LED support for all platforms the linux specific joystick implementation has been removed. This means you will need to:
* [Install node-hid build requirements](#node-hid-build)
* [Install node-hid with hidraw support](#node-hid-hidraw)
* [create udev rules](#create-udev-rules)
#### <a name="node-hid-build"></a> Install node-hid build requirements
To build node-hid you will need to install:
* libudev-dev
* libusb-1.0-0
* libusb-1.0-0-dev
* build-essential
* git
* node-gyp
* node-pre-gyp
Using apt-get:
```bash
sudo apt-get install libudev-dev libusb-1.0-0 libusb-1.0-0-dev build-essential git
```
```bash
npm install -g node-gyp node-pre-gyp
```
#### <a name="node-hid-hidraw"></a> Install node-hid with hidraw support
Once you have run the installation scripts above you can install the node-dualshock module, then replace the installed node-hid with hidraw support enabled node-hid:
```bash
npm install dualshock-controller
```
```bash
npm install node-hid --driver=hidraw --build-from-source
```
#### <a name="create-udev-rules"></a> Create udev rules
You will need to create a udev rule to be able to access the hid stream as a non root user.
Write the following file in `/etc/udev/rules.d/61-dualshock.rules`
```
SUBSYSTEM=="input", GROUP="input", MODE="0666"
SUBSYSTEM=="usb", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0268", MODE:="666", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0664", GROUP="plugdev"
SUBSYSTEM=="input", GROUP="input", MODE="0666"
SUBSYSTEM=="usb", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="05c4", MODE:="666", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0664", GROUP="plugdev"
```
Reload the rules `sudo udevadm control --reload-rules`, then disconnect/connect the controller.
The MIT License (MIT)
Copyright (c) 2017 Ricardo de Pena
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.

View file

@ -0,0 +1,35 @@
These json files are used to map the controller:
=========================
## To add a new controller:
Use DeviceDiscoveryHelp.js in the examples folder, using node-hid you can obtain the values you need to create a controller.json file and leverage the library to wire it up.
### To connect the right controller
the vendorId and the productId need to be set to the right values, you can use node-hid to determine what these are.
### Analogs are mapped as:
~~~~ js
"analogSticks" : [
{
"name" : "left",
"x" : 7,
"y" : 6
},
{
"name" : "right",
"x" : 9,
"y" : 8
}
]
### Buttons are usually grouped by a block but should be added as:
~~~~ js
"buttons" : [
{
"name": name of the button used for events,
"buttonBlock": int representing the button block,
"buttonValue": bit value,
"analogPin" : int representing the pin used for analog.
},
]

View file

@ -0,0 +1,244 @@
{
"vendorId" : 1356,
"productId" : 616,
"analogSticks" : [
{
"name" : "left",
"x" : 6,
"y" : 7,
"joystickXNumber" : 0,
"joystickYNumber" : 1
},
{
"name" : "right",
"x" : 8,
"y" : 9,
"joystickXNumber" : 2,
"joystickYNumber" : 3
}
],
"buttons" : [
{
"name": "l2",
"buttonBlock": 3,
"buttonValue": "0x01",
"analogPin" : 18,
"joystickNumber": 8
},
{
"name": "r2",
"buttonBlock": 3,
"buttonValue": "0x02",
"analogPin" : 19,
"joystickNumber" : 9
},
{
"name": "l1",
"buttonBlock": 3,
"buttonValue": "0x04",
"analogPin" : 20,
"joystickNumber" : 10
},
{
"name":"r1",
"buttonBlock": 3,
"buttonValue": "0x08",
"analogPin" : 21,
"joystickNumber" : 11
},
{
"name": "triangle",
"buttonBlock": 3,
"buttonValue": "0x10",
"analogPin" : 22,
"joystickNumber" : 12
},
{
"name": "circle",
"buttonBlock": 3,
"buttonValue": "0x20",
"analogPin" : 23,
"joystickNumber" : 13
},
{
"name": "x",
"buttonBlock": 3,
"buttonValue": "0x40",
"analogPin" : 24,
"joystickNumber" : 14
},
{
"name": "square",
"buttonBlock": 3,
"buttonValue": "0x80",
"analogPin": 25,
"joystickNumber" : 15
},
{
"name": "select",
"buttonBlock": 2,
"buttonValue": "0x1",
"joystickNumber" : 0
},
{
"name": "leftAnalogBump",
"buttonBlock": 2,
"buttonValue": "0x2",
"joystickNumber" : 1
},
{
"name": "rightAnalogBump",
"buttonBlock": 2,
"buttonValue": "0x4",
"joystickNumber" : 2
},
{
"name": "start",
"buttonBlock": 2,
"buttonValue": "0x08",
"joystickNumber" : 3
},
{
"name": "dpadUp",
"buttonBlock": 2,
"buttonValue": "0x10",
"analogPin": 14,
"joystickNumber" : 4
},
{
"name": "dpadRight",
"buttonBlock": 2,
"buttonValue": "0x20",
"analogPin": 15,
"joystickNumber" : 5
},
{
"name": "dpadDown",
"buttonBlock": 2,
"buttonValue" : "0x40",
"analogPin" : 16,
"joystickNumber" : 6
},
{
"name": "dpadLeft",
"buttonBlock": 2,
"buttonValue": "0x80",
"analogPin": 17,
"joystickNumber" : 7
},
{
"name": "psxButton",
"buttonBlock":4,
"buttonValue": "0x01",
"joystickNumber" : 16
}
],
"motionInputs": [
{
"name" : "rightLeft",
"directionPin" : 41,
"valuePin" : 42
},
{
"name" : "forwardBackward",
"directionPin" : 43,
"valuePin" : 44
},
{
"name" : "upDown",
"directionPin" : 45,
"valuePin" : 46
},
{
"name" : "yaw",
"directionPin" : 47,
"valuePin" : 48
}
],
"status": [
{
"name" : "charging",
"pin" : 29,
"states" : [
{
"value" : 0,
"state" : "Charging"
},
{
"value" : 2,
"state" : "Charging"
},
{
"value" : 3,
"state" : "Not Charging"
}
]
},
{
"name" : "battery",
"pin" : 30,
"states" : [
{
"value" : 238,
"state" : "Charging"
},
{
"value" : 0,
"state" : "No charge"
},
{
"value" : 1,
"state" : "20%"
},
{
"value" : 2,
"state" : "40%"
},
{
"value" : 3,
"state" : "60%"
},
{
"value" : 4,
"state" : "80%"
},
{
"value" : 5,
"state" : "100%"
}
]
},
{
"name" : "connection",
"pin" : 31,
"states" : [
{
"value" : 18,
"state" : "Usb"
},
{
"value" : 22,
"state" : "Bluetooth"
},
{
"value" : 20,
"state" : "Rumbling"
}
]
}
],
"output": {
"defaultBuffer":[
1, 0, 254, 0, 254, 0, 0, 0, 0, 0, 0,
255, 39, 16, 0, 50, 255, 39, 16, 0, 50, 255,
39, 16, 0, 50, 255, 39, 16, 0, 50, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0
],
"indexes": {
"rumbleLeft": 3,
"rumbleRight": 5,
"led": 10
}
}
}

View file

@ -0,0 +1,177 @@
{
"vendorId" : 1356,
"productId" : 2508,
"analogSticks" : [
{
"name" : "left",
"x" : 1,
"y" : 2
},
{
"name" : "right",
"x" : 3,
"y" : 4
}
],
"buttons" : [
{
"name": "l2",
"buttonBlock": 6,
"buttonValue": "0x04",
"analogPin" : 8
},
{
"name": "r2",
"buttonBlock": 6,
"buttonValue": "0x08",
"analogPin" : 9
},
{
"name": "l1",
"buttonBlock": 6,
"buttonValue": "0x01"
},
{
"name": "r1",
"buttonBlock": 6,
"buttonValue": "0x02"
},
{
"name": "leftAnalogBump",
"buttonBlock": 6,
"buttonValue": "0x04"
},
{
"name": "rightAnalogBump",
"buttonBlock": 6,
"buttonValue": "0x08"
},
{
"name": "psxButton",
"buttonBlock": 7,
"buttonValue": "0x01"
},
{
"name": "touchPad",
"buttonBlock": 7,
"buttonValue": "0x02"
},
{
"name": "square",
"buttonBlock": 5,
"buttonValue": "0x10"
},
{
"name": "triangle",
"buttonBlock": 5,
"buttonValue": "0x80"
},
{
"name": "circle",
"buttonBlock": 5,
"buttonValue": "0x40"
},
{
"name": "x",
"buttonBlock": 5,
"buttonValue": "0x20"
},
{
"name": "dpadUp",
"buttonBlock": 5,
"buttonValue": "0x00",
"mask": "0xF"
},
{
"name": "dpadUpRight",
"buttonBlock": 5,
"buttonValue": "0x01",
"mask": "0xF"
},
{
"name": "dpadRight",
"buttonBlock": 5,
"buttonValue": "0x02",
"mask": "0xF"
},
{
"name": "dpadDownRight",
"buttonBlock": 5,
"buttonValue": "0x03",
"mask": "0xF"
},
{
"name": "dpadDown",
"buttonBlock": 5,
"buttonValue" : "0x04",
"mask": "0xF"
},
{
"name": "dpadDownLeft",
"buttonBlock": 5,
"buttonValue" : "0x05",
"mask": "0xF"
},
{
"name": "dpadLeft",
"buttonBlock": 5,
"buttonValue": "0x06",
"mask": "0xF"
},
{
"name": "dpadUpLeft",
"buttonBlock": 5,
"buttonValue": "0x07",
"mask": "0xF"
},
{
"name": "share",
"buttonBlock": 6,
"buttonValue": "0x10"
},
{
"name": "options",
"buttonBlock": 6,
"buttonValue": "0x20"
},
{
"name": "leftStick",
"buttonBlock": 6,
"buttonValue": "0x40"
},
{
"name": "rightStick",
"buttonBlock": 6,
"buttonValue": "0x80"
}
],
"motionInputs" : [],
"status" : [],
"output": {
"defaultBuffer":[
5,255,4,0,0,0,0,0,0,0,0
],
"indexes": {
"rumbleLeft": 4,
"rumbleRight": 5,
"red": 6,
"green": 7,
"blue": 8,
"flashOn": 9,
"flashOff": 10
}
},
"touchPad": [{
"name":"x1",
"activePin": 35,
"dataPinA": 37,
"dataPinB": 36,
"dataPinC": 38
},{
"name": "x2",
"activePin": 39,
"dataPinA": 41,
"dataPinB": 40,
"dataPinC": 42
}]
}

View file

@ -0,0 +1,177 @@
{
"vendorId" : 1356,
"productId" : 1476,
"analogSticks" : [
{
"name" : "left",
"x" : 1,
"y" : 2
},
{
"name" : "right",
"x" : 3,
"y" : 4
}
],
"buttons" : [
{
"name": "l2",
"buttonBlock": 6,
"buttonValue": "0x04",
"analogPin" : 8
},
{
"name": "r2",
"buttonBlock": 6,
"buttonValue": "0x08",
"analogPin" : 9
},
{
"name": "l1",
"buttonBlock": 6,
"buttonValue": "0x01"
},
{
"name": "r1",
"buttonBlock": 6,
"buttonValue": "0x02"
},
{
"name": "leftAnalogBump",
"buttonBlock": 6,
"buttonValue": "0x04"
},
{
"name": "rightAnalogBump",
"buttonBlock": 6,
"buttonValue": "0x08"
},
{
"name": "psxButton",
"buttonBlock": 7,
"buttonValue": "0x01"
},
{
"name": "touchPad",
"buttonBlock": 7,
"buttonValue": "0x02"
},
{
"name": "square",
"buttonBlock": 5,
"buttonValue": "0x10"
},
{
"name": "triangle",
"buttonBlock": 5,
"buttonValue": "0x80"
},
{
"name": "circle",
"buttonBlock": 5,
"buttonValue": "0x40"
},
{
"name": "x",
"buttonBlock": 5,
"buttonValue": "0x20"
},
{
"name": "dpadUp",
"buttonBlock": 5,
"buttonValue": "0x00",
"mask": "0xF"
},
{
"name": "dpadUpRight",
"buttonBlock": 5,
"buttonValue": "0x01",
"mask": "0xF"
},
{
"name": "dpadRight",
"buttonBlock": 5,
"buttonValue": "0x02",
"mask": "0xF"
},
{
"name": "dpadDownRight",
"buttonBlock": 5,
"buttonValue": "0x03",
"mask": "0xF"
},
{
"name": "dpadDown",
"buttonBlock": 5,
"buttonValue" : "0x04",
"mask": "0xF"
},
{
"name": "dpadDownLeft",
"buttonBlock": 5,
"buttonValue" : "0x05",
"mask": "0xF"
},
{
"name": "dpadLeft",
"buttonBlock": 5,
"buttonValue": "0x06",
"mask": "0xF"
},
{
"name": "dpadUpLeft",
"buttonBlock": 5,
"buttonValue": "0x07",
"mask": "0xF"
},
{
"name": "share",
"buttonBlock": 6,
"buttonValue": "0x10"
},
{
"name": "options",
"buttonBlock": 6,
"buttonValue": "0x20"
},
{
"name": "leftStick",
"buttonBlock": 6,
"buttonValue": "0x40"
},
{
"name": "rightStick",
"buttonBlock": 6,
"buttonValue": "0x80"
}
],
"motionInputs" : [],
"status" : [],
"output": {
"defaultBuffer":[
5,255,4,0,0,0,0,0,0,0,0
],
"indexes": {
"rumbleLeft": 4,
"rumbleRight": 5,
"red": 6,
"green": 7,
"blue": 8,
"flashOn": 9,
"flashOff": 10
}
},
"touchPad": [{
"name":"x1",
"activePin": 35,
"dataPinA": 37,
"dataPinB": 36,
"dataPinC": 38
},{
"name": "x2",
"activePin": 39,
"dataPinA": 41,
"dataPinB": 40,
"dataPinC": 42
}]
}

View file

@ -0,0 +1,195 @@
{
"vendorId" : 1356,
"productId" : 1476,
"analogSticks" : [
{
"name" : "left",
"x" : 1,
"y" : 2,
"joystickXNumber" : 0,
"joystickYNumber" : 1
},
{
"name" : "right",
"x" : 3,
"y" : 4,
"joystickXNumber" : 2,
"joystickYNumber" : 5
},
{
"name" : "l2Analog",
"x" : 100,
"joystickXNumber" : 3
},
{
"name" : "r2Analog",
"x" : 101,
"joystickXNumber" : 4
}
],
"buttons" : [
{
"name": "l2",
"buttonBlock": 6,
"buttonValue": "0x04",
"analogPin" : 8,
"joystickNumber": 6
},
{
"name": "r2",
"buttonBlock": 6,
"buttonValue": "0x08",
"analogPin" : 9,
"joystickNumber": 7
},
{
"name": "l1",
"buttonBlock": 6,
"buttonValue": "0x01",
"joystickNumber": 4
},
{
"name": "r1",
"buttonBlock": 6,
"buttonValue": "0x02",
"joystickNumber": 5
},
{
"name": "psxButton",
"buttonBlock": 7,
"buttonValue": "0x01",
"joystickNumber": 12
},
{
"name": "touchPad",
"buttonBlock": 7,
"buttonValue": "0x02",
"joystickNumber": 13
},
{
"name": "square",
"buttonBlock": 5,
"buttonValue": "0x10",
"joystickNumber": 0
},
{
"name": "triangle",
"buttonBlock": 5,
"buttonValue": "0x80",
"joystickNumber": 3
},
{
"name": "circle",
"buttonBlock": 5,
"buttonValue": "0x40",
"joystickNumber": 2
},
{
"name": "x",
"buttonBlock": 5,
"buttonValue": "0x20",
"joystickNumber": 1
},
{
"name": "dpadUp",
"buttonBlock": 5,
"buttonValue": "0x00",
"mask": "0xF"
},
{
"name": "dpadUpRight",
"buttonBlock": 5,
"buttonValue": "0x01",
"mask": "0xF"
},
{
"name": "dpadRight",
"buttonBlock": 5,
"buttonValue": "0x02",
"mask": "0xF"
},
{
"name": "dpadDownRight",
"buttonBlock": 5,
"buttonValue": "0x03",
"mask": "0xF"
},
{
"name": "dpadDown",
"buttonBlock": 5,
"buttonValue" : "0x04",
"mask": "0xF"
},
{
"name": "dpadDownLeft",
"buttonBlock": 5,
"buttonValue" : "0x05",
"mask": "0xF"
},
{
"name": "dpadLeft",
"buttonBlock": 5,
"buttonValue": "0x06",
"mask": "0xF"
},
{
"name": "dpadUpLeft",
"buttonBlock": 5,
"buttonValue": "0x07",
"mask": "0xF"
},
{
"name": "share",
"buttonBlock": 6,
"buttonValue": "0x10",
"joystickNumber": 8
},
{
"name": "options",
"buttonBlock": 6,
"buttonValue": "0x20",
"joystickNumber": 9
},
{
"name": "leftStick",
"buttonBlock": 6,
"buttonValue": "0x40",
"joystickNumber": 10
},
{
"name": "rightStick",
"buttonBlock": 6,
"buttonValue": "0x80",
"joystickNumber": 11
}
],
"motionInputs" : [],
"status" : [],
"output": {
"defaultBuffer":[
5,255,4,0,0,0,0,0,0,0,0
],
"indexes": {
"rumbleLeft": 4,
"rumbleRight": 5,
"red": 6,
"green": 7,
"blue": 8,
"flashOn": 9,
"flashOff": 10
}
},
"touchPad": [{
"name":"x1",
"activePin": 35,
"dataPinA": 37,
"dataPinB": 36,
"dataPinC": 38
},{
"name": "x2",
"activePin": 39,
"dataPinA": 41,
"dataPinB": 40,
"dataPinC": 42
}]
}

View file

@ -0,0 +1,8 @@
Examples:
=========================
## Don't use this code as a starting point.
I do things here that are not neccesary, you are better off looking at the readme in root as it has a cleaner implementation, this is here just so you can test it right away.
If you'd like to see more examples for the DualShock 4, feel free to check out
[ds-examples](https://github.com/itaisteinherz/ds-examples).

View file

@ -0,0 +1,61 @@
var printcontrollerEvents = function(controller, controllerConfiguration) {
'use strict';
controller.on('left:move', function(data) {
console.log('left Moved');
console.log(data);
});
controller.on('right:move', function(data) {
console.log('right Moved');
console.log(data);
});
controller.on('connected', function() {
console.log('connected');
});
controller.on('error', function(data) {
console.log(data);
});
var pressed = function(data) {
console.log(data + ": press");
};
var released = function(data) {
console.log(data + ": release");
};
var analog = function(data) {
console.log(data + ": analog");
};
var hold = function(data) {
console.log(data + ": hold");
};
var motion = function(motionInput, data) {
console.log(motionInput);
console.log(data);
};
//subscribe to all the buttons:
for (var i = 0; i < controllerConfiguration.buttons.length; i++) {
controller.on(controllerConfiguration.buttons[i].name + ":press", pressed);
controller.on(controllerConfiguration.buttons[i].name + ":release", released);
controller.on(controllerConfiguration.buttons[i].name + ":analog", analog);
controller.on(controllerConfiguration.buttons[i].name + ":hold", hold);
}
//subscribe to all the status events:
if (controllerConfiguration.status && controllerConfiguration.status.length) {
for (i = 0; i < controllerConfiguration.status.length; i++) {
controller.on(controllerConfiguration.status[i].name + ":change", console.log);
}
}
//subscribe to the motion events.
controller.on('rightLeft' + ':motion', function(data) {
motion('rightLeft', data);
});
controller.on('forwardBackward' + ':motion', function(data) {
motion('forwardBackward', data);
});
controller.on('upDown' + ':motion', function(data) {
motion('upDown', data);
});
};
module.exports = printcontrollerEvents;

View file

@ -0,0 +1,52 @@
'use strict';
var dualShock = require('./../src/dualshock.js');
var dualShock3;
//init the controller
dualShock3 = dualShock({
analogStickSmoothing: false,
config: "dualShock3",
logging: true
});
// //for a client implementation we do not need this, this is only to test the inputs.
var controllerConfiguration = require('./../controllerConfigurations/dualShock3');
// //init the print events
var consolePrintEvents = require('./consolePrintControllerEvents')(dualShock3, controllerConfiguration);
dualShock3.on("dpadup:press", () => {
dualShock3.setExtras({
led: 2
});
});
dualShock3.on("dpadright:press", () => {
dualShock3.setExtras({
led: 4
});
});
dualShock3.on("dpaddown:press", () => {
dualShock3.setExtras({
led: 8
});
});
dualShock3.on("dpadleft:press", () => {
dualShock3.setExtras({
led: 16
});
});
dualShock3.on("r2:analog", (d) => {
dualShock3.setExtras({
rumbleRight: d
});
});
dualShock3.on("l2:press", (d) => {
dualShock3.setExtras({
rumbleLeft: 1
});
});

View file

@ -0,0 +1,59 @@
'use strict';
var dualShock = require('./../src/dualshock.js');
var dualShock4 = dualShock({
config: "dualShock4",
logging: true
});
//for a client implementation we do not need this, this is only to test the inputs.
var controllerConfiguration = require('./../controllerConfigurations/dualShock4');
//init the print events
var consolePrintEvents = require('./consolePrintControllerEvents')(dualShock4, controllerConfiguration);
dualShock4.on("dpadup:press", () => {
dualShock4.setExtras({
red: 255
});
});
dualShock4.on("dpadright:press", () => {
dualShock4.setExtras({
green: 255
});
});
dualShock4.on("dpaddown:press", () => {
dualShock4.setExtras({
blue: 255
});
});
dualShock4.on("dpadleft:press", () => {
dualShock4.setExtras({
red: 255,
green: 255,
blue: 255
});
});
dualShock4.on("x:press", (d) => {
dualShock4.setExtras({
red: 255,
flashOn: 50,
flashOff: 10
});
});
dualShock4.on("r2:analog", (d) => {
dualShock4.setExtras({
rumbleRight: d
});
});
dualShock4.on("l2:analog", (d) => {
dualShock4.setExtras({
rumbleLeft: d
});
});

View file

@ -0,0 +1,12 @@
var HID = require('node-hid');
console.log(HID.devices());
var controller = new HID.HID(1356, 616);
controller.on('data', function(data) {
for (var i = 0; i < data.length; i++) {
if (i === 30) {
console.log(i + " " + data[i]);
}
}
});

View file

@ -0,0 +1,6 @@
var joystick = require('joystick'),
controller = new joystick(0, 256, 500);
controller.on('button', console.log);
controller.on('axis', console.log);

67
dist/dualshock-controller/gruntfile.js vendored Normal file
View file

@ -0,0 +1,67 @@
const files = ['gruntfile.js',
'src/*.js',
'src/inputProcessors/*.js',
'test/*.js',
'examples/*.js'
];
module.exports = function(grunt) {
grunt.initConfig({
watch: {
files: files,
tasks: ['default']
},
jshint: {
files: files,
options: {
reporterOutput: "",
esnext: true,
node: true,
globals: {
describe: true,
it: true,
beforeEach: true
}
}
},
mochaTest: {
test: {
options: {
reporter: 'spec'
},
src: ['test/*.js']
}
},
jsbeautifier: {
files: files,
options: {
js: {
braceStyle: "collapse",
breakChainedMethods: false,
e4x: false,
evalCode: false,
indentChar: " ",
indentLevel: 0,
indentSize: 4,
indentWithTabs: false,
jslintHappy: false,
keepArrayIndentation: false,
keepFunctionIndentation: false,
maxPreserveNewlines: 10,
preserveNewlines: true,
spaceBeforeConditional: true,
spaceInParen: false,
unescapeStrings: false,
wrapLineLength: 0
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-mocha-test');
grunt.loadNpmTasks('grunt-jsbeautifier');
grunt.registerTask('test', ['jshint', 'mochaTest']);
grunt.registerTask('default', ['jshint', 'mochaTest', 'jsbeautifier']);
};

47
dist/dualshock-controller/package.json vendored Normal file
View file

@ -0,0 +1,47 @@
{
"name": "dualshock-controller",
"version": "1.1.1",
"description": "Eventing API layer over HID for the Sony DualShock 3 and DualShock 4 controllers ",
"main": "./src/dualshock.js",
"dependencies": {
"node-hid": "^0.5.0"
},
"devDependencies": {
"grunt": "^1.0.1",
"grunt-cli": "^1.2.0",
"grunt-contrib-jshint": "^1.1.0",
"grunt-contrib-watch": "^1.0.0",
"grunt-mocha-test": "^0.13.2",
"mocha": "^3.2.0",
"sinon": "^1.8",
"nyc": "^10.0.0",
"grunt-jsbeautifier": "^0.2.7",
"jshint": "^2.5.0",
"mockery": "^2.0.0"
},
"scripts": {
"test": "grunt test",
"coverage": "nyc npm test"
},
"engines": {
"node": ">=6.9.2"
},
"repository": {
"type": "git",
"url": "https://github.com/rdepena/node-dualshock-controller.git"
},
"author": "ricardo de pena",
"license": "MIT",
"readmeFilename": "README.md",
"keywords": [
"ps3",
"controller",
"gamepad",
"dualshock",
"dualshock3",
"dualshock4",
"dual shock 3",
"dual shock 4",
"node-hid"
]
}

BIN
dist/dualshock-controller/src/HID.node vendored Normal file

Binary file not shown.

View file

@ -0,0 +1,51 @@
'use strict';
// Module dependencies.
var dsutilities = require('./utilities'),
Smoothing = require('./smoothing'),
config = require('./config');
//Proccess Analog stick events.
var Analogs = function(controller) {
var varianceThreshhold = 1,
smoothInput = config.getOptions().analogStickSmoothing,
outputSmoothing = new Smoothing(smoothInput),
analogSticks = config.getControllerConfig().analogSticks;
//Private methods
var processStick = function(analogStick, data) {
var currentValue = {
x: data[analogStick.x],
y: data[analogStick.y]
},
previousValue = {
x: outputSmoothing.readLastPosition(analogStick.name + 'x'),
y: outputSmoothing.readLastPosition(analogStick.name + 'y')
};
//we only raise an event if both
if (dsutilities.isWithinVariance(previousValue.x, currentValue.x, varianceThreshhold) ||
dsutilities.isWithinVariance(previousValue.y, currentValue.y, varianceThreshhold)) {
currentValue.x = outputSmoothing.smooth(analogStick.name + 'x', currentValue.x);
currentValue.y = outputSmoothing.smooth(analogStick.name + 'y', currentValue.y);
// Update and emit
if (controller[analogStick.name]) {
controller[analogStick.name].x = currentValue.x;
controller[analogStick.name].y = currentValue.y;
}
controller.emit(analogStick.name + ':move', currentValue);
}
};
// Public methods
//process all the analog events.
this.process = function(data) {
for (var i = 0; i < analogSticks.length; i++) {
processStick(analogSticks[i], data);
}
};
};
module.exports = Analogs;

104
dist/dualshock-controller/src/buttons.js vendored Normal file
View file

@ -0,0 +1,104 @@
'use strict';
// Module dependencies.
var config = require('./config'),
dsutilities = require('./utilities');
//Proccess button events.
var Buttons = function(controller) {
var buttons = config.getControllerConfig().buttons;
// convert strings to numbers, e.g. "0x01" to 0x01
// must be converted because JSON doesn't allow numbers with leading zeros
buttons.forEach(function(button) {
if (typeof button.buttonValue == "string") {
button.buttonValue = parseInt(button.buttonValue);
}
if (typeof button.mask == "string") {
button.mask = parseInt(button.mask);
} else if (!(button.mask instanceof Number)) {
button.mask = 0xFF;
}
//generate event name aliases:
button.eventPrefixes = dsutilities.generateEventPrefixAliases(button.name);
});
var buffer = {};
//Private methods
var emitEvent = function(button, eventText, data) {
button.eventPrefixes.forEach(function(eventPrefix) {
controller.emit(eventPrefix + eventText, data);
});
};
var processButton = function(button, data) {
//make sure the data contains a value for the specified block
//and bitwise operation for the button value
var block = data[button.buttonBlock] & button.mask;
var hit = (block & button.buttonValue) == button.buttonValue;
var value = 0;
var state = 0; // 0: up, 1: down, 2: hold
// special case for the dualshock 4's dpadUp button as it causes the
// lower 8 bits of it's block to be zeroed
if (!button.buttonValue) {
hit = !block;
}
// special case for dualshock 4's dpad - they are not bitmasked values as
// they cannot be pressed together - ie. up, left and upleft are three
// different values - upleft is not equal to up & left
if (button.buttonBlock == 5 && block < 0x08) {
hit = block == button.buttonValue;
}
if (hit) {
value = 1;
//if the button is in the released state.
if (!buffer[button.name]) {
state = 1;
buffer[button.name] = true;
emitEvent(button, ':press', button.name);
} else {
state = 2;
emitEvent(button, ':hold', button.name);
}
//send the analog data
if (button.analogPin && data[button.analogPin]) {
emitEvent(button, ':analog', data[button.analogPin]);
}
} else if (buffer[button.name]) {
//button was pressed and is not released
buffer[button.name] = false;
//button is no longer pressed, emit a analog 0 event.
if (button.analogPin) {
emitEvent(button, ':analog', 0);
}
//emit the released event.
emitEvent(button, ':release', button.name);
}
if (controller[button.name]) {
controller[button.name].value = value;
controller[button.name].state = state;
}
};
// Public methods
//process all the analog events.
this.process = function(data) {
for (var i = 0; i < buttons.length; i++) {
processButton(buttons[i], data);
}
};
};
module.exports = Buttons;

56
dist/dualshock-controller/src/config.js vendored Normal file
View file

@ -0,0 +1,56 @@
'use strict';
// Module dependencies.
// we will expose these objects via the manager.
var options,
controllerConfig;
//provides access to the current options and configs.
var config = {
setOptions: function(opts) {
//no options were passed
options = opts || {};
// Defaults:
var defaultValues = {
config: "dualShock3",
accelerometerSmoothing: true,
analogStickSmoothing: false,
logging: false,
forceNodeHid: false,
linuxJoystickId: 0
};
for (var name in defaultValues) {
if (defaultValues.hasOwnProperty(name)) {
var target = options[name];
var orig = defaultValues[name];
if (!target) {
options[name] = orig;
}
}
}
var controllerConfiguration;
//use passed config or load from built-in configs
if (typeof options.config === "object") {
controllerConfiguration = options.config;
} else {
controllerConfiguration = require('./../controllerConfigurations/' + options.config);
}
//set the current controllerConfiguration
config.setControllerConfig(controllerConfiguration);
},
getOptions: function() {
return options;
},
setControllerConfig: function(config) {
controllerConfig = config;
},
getControllerConfig: function() {
return controllerConfig;
}
};
module.exports = config;

View file

@ -0,0 +1,167 @@
// Module dependencies.
const util = require('util'),
dsutilities = require('./utilities'),
Emitter = require('events').EventEmitter,
Gyro = require('./gyro'),
Analogs = require('./analogs'),
Buttons = require('./buttons'),
Status = require('./status'),
HID = require('./HID'),
config = require('./config'),
TouchPad = require('./touchpad');
//generic controller object, it will need a controller Configuration with a buttons array passed into its connect function.
const Controller = function() {
'use strict';
Emitter.call(this);
const controllerConfig = config.getControllerConfig(),
options = config.getOptions(),
indexes = controllerConfig.output.indexes,
analogs = new Analogs(this),
buttons = new Buttons(this),
gyro = new Gyro(this),
status = new Status(this),
touchPad = new TouchPad(this);
let device = null;
[{
type: 'analogSticks',
properties: [{
name: 'x',
initialValue: 0
}, {
name: 'y',
initialValue: 0
}]
}, {
type: 'buttons',
properties: [{
name: 'state',
initialValue: 0
}, {
name: 'value',
initialValue: 0
}]
}, {
type: 'motionInputs',
properties: [{
name: 'value',
initialValue: 0
}, {
name: 'direction',
initialValue: 0
}]
}, {
type: 'status',
properties: [{
name: 'state',
initialValue: ''
}]
}].forEach(function(setup) {
const entities = controllerConfig[setup.type],
properties = setup.properties;
if (entities.length) {
entities.forEach(function(entity) {
this[entity.name] = properties.reduce(function(accum, property) {
return (accum[property.name] = property.initialValue, accum);
}, {});
}, this);
}
}, this);
//Private methods
//emit an error event or log it to the console.
const handleException = function(ex) {
//if exception was generated within our stream
if (this && this.emit) {
this.emit('error', ex);
} else {
dsutilities.warn(ex);
throw (ex);
}
};
//process data from HID connected device.
const processFrame = function(data) {
if (controllerConfig.motionInputs) {
gyro.process(data);
}
if (controllerConfig.analogSticks) {
analogs.process(data);
}
if (controllerConfig.buttons) {
buttons.process(data);
}
if (controllerConfig.status) {
status.process(data);
}
if (controllerConfig.touchPad) {
touchPad.process(data);
}
};
const isController = function(device) {
var vendor = (device.vendorId == controllerConfig.vendorId);
var product = (device.productId == controllerConfig.productId || device.productId == 2508);
return vendor && product;
};
// Public methods
this.connect = function() {
dsutilities.warn('connect method is deprecated, controller now connects upon declaration.');
};
this.disconnect = function() {
if (device && device.close) {
device.close();
}
this.emit('disconnecting');
dsutilities.warn('node dualshock disconnecting');
};
// Used to set controller rumble and light
this.setExtras = function(data) {
let buff = controllerConfig.output.defaultBuffer.slice();
Object.keys(data).forEach(k => {
buff[indexes[k]] = data[k];
});
device.write(buff);
};
//connect to the controller.
if (typeof options.device === 'undefined') {
dsutilities.warn('node dualshock connecting');
var devices = HID.devices();
const deviceMeta = devices
.filter(isController)[0];
if (deviceMeta) {
device = new HID.HID(deviceMeta.path);
console.log(device);
device.on('data', processFrame.bind(this));
device.on('error', handleException.bind(this));
} else {
handleException(new Error(`device with Vendor ID:${controllerConfig.vendorId} Product ID:${controllerConfig.productId} not found`));
}
} else {
// Allow user-specified device
device = options.device;
console.log("Custom device: ", device);
device.on('data', processFrame.bind(this));
device.on('error', handleException.bind(this));
}
//subscribe to the exit event:
process.on('exit', this.disconnect.bind(this));
};
//need to inherit from event emiter.
util.inherits(Controller, Emitter);
module.exports = Controller;

View file

@ -0,0 +1,22 @@
// Module dependencies.
var Controller = require('./controller'),
config = require('./config');
// This is the app entry point.
// options you can pass:
// {
// config : "File from controllerConfigurations" or a JS object containing configuration,
// accelerometerSmoothing : true/false, this will activate motion/acelerometer output smoothing. true by default.
// analogStickSmoothing : true/false, this will activate analog thumb stick smoothing
// }
var dualShock = function(options) {
'use strict';
//set the current options
config.setOptions(options);
//returns the controller.
return new Controller();
};
module.exports = dualShock;

72
dist/dualshock-controller/src/gyro.js vendored Normal file
View file

@ -0,0 +1,72 @@
'use strict';
// Module dependencies.
var dsutilities = require('./utilities'),
Smoothing = require('./smoothing'),
config = require('./config');
//Proccess button events.
var motionProcessor = function(controller) {
var varianceThreshhold = 1,
smoothInput = config.getOptions().accelerometerSmoothing,
outputSmoothing = new Smoothing(smoothInput),
motionInputs = config.getControllerConfig().motionInputs;
//generate event name aliases:
motionInputs.forEach(function(motionAxis) {
motionAxis.eventPrefixes = dsutilities.generateEventPrefixAliases(motionAxis.name);
});
//Private methods
//data corrections so that each dirrection has a 0 throug x value
var correctData = function(motionAxis, data) {
var value;
//ensuring that both directions start from 0 and move to -x or x;
if (data[motionAxis.directionPin] === 1) {
//we need the values to be from 0 to x.
value = 255 - data[motionAxis.valuePin];
} else if (data[motionAxis.directionPin] === 2) {
//going in the oposite direction, we need to values to be from 0 to -x;
value = data[motionAxis.valuePin] * -1;
}
//return an object with both value and dirrection.
return {
direction: data[motionAxis.directionPin],
value: value
};
};
//process the axis movement.
var processAxis = function(motionAxis, data) {
//every motion will have a dirrection and a value
var motionValue = correctData(motionAxis, data),
lastPosition = outputSmoothing.readLastPosition(motionAxis.name);
//check if the values are within variance
if (dsutilities.isWithinVariance(lastPosition, motionValue.value, varianceThreshhold)) {
motionValue.value = outputSmoothing.smooth(motionAxis.name, motionValue.value);
// Don't assign motionValue directly to controller[motionAxis.name],
// this will break the reference.
if (controller[motionAxis.name]) {
controller[motionAxis.name].value = motionValue.value;
controller[motionAxis.name].direction = motionValue.direction;
}
motionAxis.eventPrefixes.forEach(function(eventPrefix) {
controller.emit(eventPrefix + ':motion', motionValue);
});
}
};
// Public methods
//process all configured motion inputs.
this.process = function(data) {
for (var i = 0; i < motionInputs.length; i++) {
processAxis(motionInputs[i], data);
}
};
};
module.exports = motionProcessor;

View file

@ -0,0 +1,50 @@
// Module dependencies.
//smooths data with moving average
var outputSmoothing = function(smoothInput) {
'use strict';
var buffer = {},
maxFrames = 5;
// Public methods
this.readLastPosition = function(motionAxisName) {
var axisBuffer = buffer[motionAxisName];
return axisBuffer ? axisBuffer[axisBuffer.length - 1] : null;
};
this.addToBuffer = function(motionAxisName, value) {
if (buffer[motionAxisName]) {
//add the current value to the buffer
buffer[motionAxisName].push(value);
//remove the head of the buffer
if (buffer[motionAxisName].length > maxFrames) {
buffer[motionAxisName].shift();
}
} else {
//create an array with the value.
buffer[motionAxisName] = [value];
}
};
//smooth using a moving average.
this.smooth = function(motionAxisName, value) {
this.addToBuffer(motionAxisName, value);
var axisBuffer = buffer[motionAxisName],
sum = 0,
smoothedVal = value;
if (smoothInput) {
for (var i = 0; i < axisBuffer.length; i++) {
sum += axisBuffer[i];
}
smoothedVal = Math.floor(sum / axisBuffer.length);
}
return smoothedVal;
};
};
module.exports = outputSmoothing;

36
dist/dualshock-controller/src/status.js vendored Normal file
View file

@ -0,0 +1,36 @@
'use strict';
// Module dependencies.
var config = require('./config');
//Proccess button events.
var Status = function(controller) {
var buffer = {},
status = config.getControllerConfig().status;
var processControllerStatus = function(category, data) {
var state;
for (var i = 0; i < category.states.length; i++) {
if (data[category.pin] === category.states[i].value) {
state = category.states[i].state;
}
}
if (buffer[category.name] !== state) {
if (controller[category.name]) {
controller[category.name].state = state;
}
controller.emit(category.name + ':change', state);
}
buffer[category.name] = state;
};
this.process = function(data) {
for (var i = 0; i < status.length; i++) {
processControllerStatus(status[i], data);
}
};
};
module.exports = Status;

View file

@ -0,0 +1,52 @@
const config = require('./config');
function genpBufferFromConf(tpAxis) {
return {
name: tpAxis.name,
active: false,
data: {
x: 0,
y: 0
}
};
}
module.exports = function TouchPad(controller) {
const touchPad = config.getControllerConfig().touchPad;
let pBuffer = {};
function processIsActive(buffer, tpAxis) {
const active = buffer[tpAxis.activePin] < 128;
const axisBuffer = pBuffer[tpAxis.name];
const evt = active ? 'active' : 'inactive';
if (active !== axisBuffer.active) {
controller.emit(`touchpad:${tpAxis.name}:${evt}`);
}
axisBuffer.active = active;
}
function processData(buffer, tpAxis) {
const axisBuffer = pBuffer[tpAxis.name];
if (axisBuffer.active) {
axisBuffer.data.x = ((buffer[tpAxis.dataPinA] & 15) << 8 | buffer[tpAxis.dataPinB]);
axisBuffer.data.y = buffer[tpAxis.dataPinC] << 4 | ((buffer[tpAxis.dataPinA] & 240) >> 4);
controller.emit(`touchpad:${tpAxis.name}`, axisBuffer.data);
}
}
this.process = function process(buffer) {
for (let i = 0; i < touchPad.length; i++) {
//if we have not built a pBuffer profile for this axis lets build it.
if (!pBuffer[touchPad[i].name]) {
pBuffer[touchPad[i].name] = genpBufferFromConf(touchPad[i]);
}
processIsActive(buffer, touchPad[i]);
processData(buffer, touchPad[i]);
}
};
};

View file

@ -0,0 +1,34 @@
'use strict';
// Module dependencies.
var config = require('./config');
var unique = function unique(x) {
var result = [];
for (var i = 0; i < x.length; i++) {
if ((result.indexOf(x[i]) < 0)) {
result.push(x[i]);
}
}
return result;
};
//provide a few utility functions.
module.exports = {
//reduces noise from the controller
isWithinVariance: function(x, y, varianceThreshhold) {
return Math.abs(x - y) > varianceThreshhold;
},
warn: function(message) {
if (config.getOptions().logging) {
console.log(message);
}
},
generateEventPrefixAliases: function(eventPrefix) {
return unique([
eventPrefix,
eventPrefix.toLowerCase()
]);
}
};

View file

@ -0,0 +1,84 @@
// Module dependencies.
var Analogs = require('../src/analogs'),
assert = require('assert'),
sinon = require('sinon'),
EventEmitter = require('events').EventEmitter,
config = require('../src/config');
describe('the Analogs component', function() {
'use strict';
var mockConfig = [{
"name": "analog",
"x": 0,
"y": 1
}],
instance = [{
name: 'process'
}],
dataA = [50, 65],
dataB = [0, 0],
analogs,
emitter,
spy;
beforeEach(function() {
emitter = new EventEmitter();
config.setOptions({
analogStickSmoothing: false
});
config.setControllerConfig({
analogSticks: mockConfig
});
analogs = new Analogs(emitter);
spy = new sinon.spy();
});
describe('object instance', function() {
it('should have the following shape', function() {
//make sure we find these functions.
instance.forEach(function(method) {
assert.equal(typeof analogs[method.name], 'function');
});
});
});
describe('move events', function() {
it('should invoke the move event', function() {
emitter.on('analog:move', spy);
analogs.process(dataA);
assert.equal(spy.called, true);
});
it('should not invoke the move event', function() {
emitter.on('analog:move', spy);
analogs.process(dataB);
assert.equal(spy.called, false);
});
it('should invoke the move event with zero', function() {
analogs.process(dataA);
emitter.on('analog:move', spy);
analogs.process(dataB);
assert.equal(spy.called, true);
});
});
describe('return values', function() {
it('should return the analog values', function() {
emitter.on('analog:move', spy);
analogs.process(dataA);
var expectedValue = {
x: 50,
y: 65
},
spyArgument = spy.args[0][0];
assert.equal(expectedValue.x, spyArgument.x);
assert.equal(expectedValue.y, spyArgument.y);
assert.equal(spy.called, true);
});
});
});

View file

@ -0,0 +1,178 @@
// Module dependencies.
var Buttons = require('../src/buttons'),
assert = require('assert'),
sinon = require('sinon'),
EventEmitter = require('events').EventEmitter,
config = require('../src/config');
describe('the Buttons component', function() {
'use strict';
var mockConfig = [{
"name": "buttonName",
"buttonBlock": 0,
"buttonValue": "0x08",
"analogPin": 1
}, {
"name": "dpadUp",
"buttonBlock": 5,
"buttonValue": "0x00",
"mask": "0xF"
}, {
"name": "dpadDown",
"buttonBlock": 5,
"buttonValue": "0x01",
"mask": "0xF"
}],
instance = [{
name: 'process'
}],
dataA = [8, 170],
dataB = [0, 0],
buttons,
emitter,
spy,
spyLowerCaseEvents;
beforeEach(function() {
emitter = new EventEmitter();
config.setControllerConfig({
buttons: mockConfig
});
buttons = new Buttons(emitter);
spy = new sinon.spy();
spyLowerCaseEvents = new sinon.spy();
});
describe('object instance', function() {
it('should have the following shape', function() {
//make sure we find these functions.
instance.forEach(function(method) {
assert.equal(typeof buttons[method.name], 'function');
});
});
});
describe('press events', function() {
it('should envoke the buttonName:press', function() {
emitter.on('buttonName:press', spy);
emitter.on('buttonname:press', spyLowerCaseEvents);
buttons.process(dataA);
assert.equal(spy.called, true);
assert.equal(spyLowerCaseEvents.called, true);
});
it('should not envoke the buttonName:press', function() {
emitter.on('buttonName:release', spy);
emitter.on('buttonname:release', spyLowerCaseEvents);
buttons.process(dataB);
assert.equal(spy.called, false);
assert.equal(spyLowerCaseEvents.called, false);
});
});
describe('release events', function() {
it('should envoke the buttonName:release', function() {
emitter.on('buttonName:release', spy);
emitter.on('buttonname:release', spyLowerCaseEvents);
buttons.process(dataA);
buttons.process(dataB);
assert.equal(spy.called, true);
assert.equal(spyLowerCaseEvents.called, true);
});
it('should not envoke the buttonName:release', function() {
emitter.on('buttonName:release', spy);
emitter.on('buttonname:release', spyLowerCaseEvents);
buttons.process(dataA);
assert.equal(spy.called, false);
assert.equal(spyLowerCaseEvents.called, false);
});
});
describe('button hold', function() {
it('should raise the hold event', function() {
emitter.on('buttonName:hold', spy);
emitter.on('buttonname:hold', spyLowerCaseEvents);
buttons.process(dataA);
buttons.process(dataA);
assert.equal(spy.args[0][0], 'buttonName');
assert.equal(spy.called, true);
assert.equal(spyLowerCaseEvents.called, true);
});
it('should not raise the hold event', function() {
emitter.on('buttonName:hold', spy);
emitter.on('buttonname:hold', spyLowerCaseEvents);
buttons.process(dataB);
buttons.process(dataB);
assert.equal(spy.called, false);
assert.equal(spyLowerCaseEvents.called, false);
});
});
describe('button analog', function() {
it('should raise the analog event', function() {
emitter.on('buttonName:analog', spy);
emitter.on('buttonname:analog', spyLowerCaseEvents);
buttons.process(dataA);
assert.equal(spy.args[0][0], dataA[1]);
assert.equal(spy.called, true);
assert.equal(spyLowerCaseEvents.called, true);
});
it('should not raise the analog event', function() {
emitter.on('buttonName:analog', spy);
emitter.on('buttonname:analog', spyLowerCaseEvents);
buttons.process(dataB);
assert.equal(spy.called, false);
assert.equal(spyLowerCaseEvents.called, false);
});
});
describe('ps4 dpad up button', function() {
it('should emit the dpadUp:press event', function() {
emitter.on('dpadUp:press', spy);
emitter.on('dpadup:press', spyLowerCaseEvents);
buttons.process([0, 0, 0, 0, 0, 0]);
assert.equal(spy.called, true);
assert.equal(spyLowerCaseEvents.called, true);
});
it('should not emit the dpadDown:press event', function() {
emitter.on('dpadDown:press', spy);
emitter.on('dpaddown:press', spyLowerCaseEvents);
buttons.process([0, 0, 0, 0, 0, 0]);
assert.equal(spy.called, false);
assert.equal(spyLowerCaseEvents.called, false);
});
});
describe('ps4 dpad down button', function() {
it('should emit the dpadDown:press event', function() {
emitter.on('dpadDown:press', spy);
emitter.on('dpaddown:press', spyLowerCaseEvents);
buttons.process([0, 0, 0, 0, 0, parseInt("00001001", 2)]);
assert.equal(spy.called, true);
assert.equal(spyLowerCaseEvents.called, true);
});
it('should not emit the dpadUp:press event', function() {
emitter.on('dpadUp:press', spy);
emitter.on('dpadup:press', spyLowerCaseEvents);
buttons.process([0, 0, 0, 0, 0, parseInt("00001001", 2)]);
assert.equal(spy.called, false);
assert.equal(spyLowerCaseEvents.called, false);
});
});
});

View file

@ -0,0 +1,91 @@
'use strict';
var assert = require('assert');
describe('The Config component', function() {
var mockConfig = {
vendorId: 1556,
productId: 616,
output: []
},
mockOptions = {
config: 'dualShock3',
accelerometerSmoothing: true,
logging: false
},
instance = [{
name: 'setOptions'
}, {
name: 'getOptions'
}, {
name: 'setControllerConfig'
}, {
name: 'getControllerConfig'
}],
defaultOptionsInstance = [{
name: 'config'
}, {
name: 'accelerometerSmoothing'
}, {
name: 'analogStickSmoothing'
}],
configA,
configB;
beforeEach(function() {
configA = require('../src/config');
configB = require('../src/config');
});
describe('object instance', function() {
it('should have the following shape', function() {
instance.forEach(function(method) {
assert.equal(typeof configA[method.name], 'function');
});
});
});
describe('option methods', function() {
it('should be able to save options', function() {
configA.setOptions(mockOptions);
assert.equal(configA.getOptions(), mockOptions);
});
it('should provide a single object accross instances', function() {
configA.setOptions(mockOptions);
assert.equal(configA.getOptions(), configB.getOptions());
});
});
describe('controllerConfig methods', function() {
it('should be able to save controllerConfig settings', function() {
configA.setControllerConfig(mockConfig);
//change the object
mockConfig.vendorId = 22;
assert.equal(configA.getControllerConfig(), mockConfig);
});
it('should provide a single object accross instances', function() {
configA.setControllerConfig(mockConfig);
assert.equal(configA.getControllerConfig(), configB.getControllerConfig());
});
});
describe('default values', function() {
beforeEach(function() {
configA.setOptions();
});
it('should apply default values', function() {
var ops = configA.getOptions();
defaultOptionsInstance.forEach(function(property) {
assert.notEqual(ops[property.name], void 0);
});
});
it('should load default config', function() {
var controllerConfig = configA.getControllerConfig();
assert.notEqual(controllerConfig, null);
assert.notEqual(controllerConfig, void 0);
});
});
});

View file

@ -0,0 +1,158 @@
var assert = require('assert'),
Emitter = require('events').EventEmitter,
config = require('../src/config'),
mockery = require('mockery');
function Device() {
Emitter.call(this);
}
Device.prototype = Object.create(Emitter.prototype, {
constructor: {
value: Device
},
close: {
value: function() {}
}
});
var config = {
analogSticks: [{
name: 'foo',
x: 0,
y: 1
}],
buttons: [{
name: 'bar',
buttonBlock: 0,
buttonValue: 0x08,
analogPin: 1
}],
motionInputs: [{
name: 'baz',
directionPin: 0,
valuePin: 1
}],
status: [{
name: 'quz',
pin: 5,
states: [{
value: 0,
state: 'Charging'
}, {
value: 2,
state: 'Charging'
}, {
value: 3,
state: '40%'
}]
}],
output: []
};
var analogs = config.analogSticks;
var buttons = config.buttons;
var motions = config.motionInputs;
var status = config.status;
describe('the DualShock component', function() {
//enable mockery and mock node-hid:
mockery.enable();
var nodeHidMock = {
HID: function(vendor, productId) {
return {
on: function() {
//could use this at some point. nothing atm.
}
};
}
};
//register mock node-hid.
mockery.registerMock('node-hid', nodeHidMock);
//once mockery is up we can require the dualshock module.
var DualShock = require('./../src/dualshock.js'),
controller, device;
before(function() {
device = new Device();
controller = DualShock({
config: config,
device: device
});
});
//disable mockery so it does not interfere with other tests.
after(function() {
mockery.deregisterMock('node-hid');
mockery.disable();
});
beforeEach(function() {
controller.removeAllListeners(Object.keys(controller._events));
});
describe('analog properties', function() {
analogs.forEach(function(analog) {
it(analog.name, function() {
assert.equal(controller[analog.name].x, 0);
assert.equal(controller[analog.name].y, 0);
device.emit('data', [100, 100]);
assert.equal(controller[analog.name].x, 100);
assert.equal(controller[analog.name].y, 100);
});
});
});
describe('button properties', function() {
buttons.forEach(function(button) {
it(button.name, function() {
assert.equal(controller[button.name].value, 0);
assert.equal(controller[button.name].state, 0);
device.emit('data', [8, 170]);
assert.equal(controller[button.name].value, 1);
assert.equal(controller[button.name].state, 1);
device.emit('data', [8, 170]);
assert.equal(controller[button.name].value, 1);
assert.equal(controller[button.name].state, 2);
device.emit('data', [0, 0]);
assert.equal(controller[button.name].value, 0);
assert.equal(controller[button.name].state, 0);
});
});
});
describe('motion properties', function() {
motions.forEach(function(motion) {
it(motion.name, function() {
assert.equal(controller[motion.name].value, 0);
assert.equal(controller[motion.name].direction, 0);
device.emit('data', [1, 233]);
assert.equal(controller[motion.name].value, 22);
assert.equal(controller[motion.name].direction, 1);
});
});
});
describe('status properties', function() {
status.forEach(function(stat) {
it(stat.name, function() {
device.emit('data', [0, 0, 0, 0, 1, 3]);
assert.equal(controller[stat.name].state, '40%');
device.emit('data', [0, 0, 0, 0, 1, 2]);
assert.equal(controller[stat.name].state, 'Charging');
});
});
});
});

View file

@ -0,0 +1,78 @@
// Module dependencies.
var Gyro = require('../src/gyro'),
assert = require('assert'),
sinon = require('sinon'),
EventEmitter = require('events').EventEmitter,
config = require('../src/config');
describe('the Gyro component', function() {
'use strict';
var mockConfig = [{
name: "dirrection",
directionPin: 0,
valuePin: 1
}],
instance = [{
name: 'process'
}],
dataA = [1, 130],
dataB = [2, 130],
emitter,
spy,
gyro;
beforeEach(function() {
emitter = new EventEmitter();
spy = sinon.spy();
config.setOptions({
accelerometerSmoothing: false
});
config.setControllerConfig({
motionInputs: mockConfig
});
gyro = new Gyro(emitter);
});
describe('object instance', function() {
it('should have the following shape', function() {
//make sure we find these functions.
instance.forEach(function(method) {
assert.equal(typeof gyro[method.name], 'function');
});
});
});
describe('process()', function() {
it('should envoke the dirrection:motion event with positive values', function() {
emitter.on('dirrection:motion', spy);
gyro.process(dataA);
assert.equal(spy.called, true);
var expectedValue = {
direction: 1,
value: 125
},
spyArgument = spy.args[0][0];
assert.equal(spyArgument.direction, expectedValue.direction);
assert.equal(spyArgument.value, expectedValue.value);
});
it('should envoke the dirrection event with negative values.', function() {
emitter.on('dirrection:motion', spy);
gyro.process(dataB);
assert.equal(spy.called, true);
var expectedValue = {
direction: 2,
value: -130
},
spyArgument = spy.args[0][0];
assert.equal(spyArgument.direction, expectedValue.direction);
assert.equal(spyArgument.value, expectedValue.value);
});
});
});

View file

@ -0,0 +1,71 @@
// Module dependencies.
var Smoothing = require('../src/smoothing'),
assert = require('assert');
describe('the smoothing component', function() {
'use strict';
var smoothing,
nonSmoothing,
//an instance should have the following functions.
instance = [{
name: 'readLastPosition'
}, {
name: 'addToBuffer'
}, {
name: 'smooth'
}];
beforeEach(function() {
smoothing = new Smoothing(true);
nonSmoothing = new Smoothing(false);
for (var i = 0; i < 5; i++) {
nonSmoothing.addToBuffer('testNonSmoothing', i);
smoothing.addToBuffer('one', i);
smoothing.addToBuffer('two', i + 1);
smoothing.addToBuffer('testSmoothing', i);
}
});
describe('object instance', function() {
it('should have the following shape', function() {
//make sure we find these functions.
instance.forEach(function(method) {
assert.equal(typeof smoothing[method.name], 'function');
});
});
});
describe('addToBuffer()', function() {
it('should add values to the buffer', function() {
smoothing.addToBuffer('one', 6);
smoothing.addToBuffer('two', 7);
assert.equal(smoothing.readLastPosition('one'), 6);
assert.equal(smoothing.readLastPosition('two'), 7);
});
});
describe('readLastPosition()', function() {
it('should handle buffers for different objects', function() {
assert.equal(smoothing.readLastPosition('one'), 4);
assert.equal(smoothing.readLastPosition('two'), 5);
});
});
describe('smooth()', function() {
it('should return expected values when smoothing', function() {
//with the data set smoothing of 6 should be 3.
assert.equal(smoothing.smooth('testSmoothing', 6), 3);
//with the data set smoothing of 8 should be 4.
assert.equal(smoothing.smooth('testSmoothing', 8), 4);
});
it('should return expected values when not smoothing', function() {
//with smoothing turned off 9 should return 9
assert.equal(nonSmoothing.smooth('testNonSmoothing', 9), 9);
//with smoothing turned off 6 should return 6
assert.equal(nonSmoothing.smooth('testNonSmoothing', 6), 6);
});
});
});

View file

@ -0,0 +1,60 @@
// Module dependencies.
var Status = require('../src/status'),
assert = require('assert'),
sinon = require('sinon'),
EventEmitter = require('events').EventEmitter,
config = require('../src/config');
describe('the status component', function() {
var mockConfig = [{
"name": "chargingState",
"pin": 0,
"states": [{
"value": 0,
"state": "Charging"
}, {
"value": 2,
"state": "Charging"
}, {
"value": 3,
"state": "40%"
}]
}],
dataA = [0, 0],
dataB = [0, 3],
instance = [{
name: 'process'
}],
status,
emitter,
spy;
beforeEach(function() {
emitter = new EventEmitter();
spy = sinon.spy();
config.setControllerConfig({
status: mockConfig
});
status = new Status(emitter, mockConfig);
});
describe('object instance', function() {
it('should have the following shape', function() {
//make sure we find these functions.
instance.forEach(function(method) {
assert.equal(typeof status[method.name], 'function');
});
});
});
describe('process()', function() {
it('process should return an object with the expected values', function() {
emitter.on('chargingState:change', spy);
status.process(dataA);
var spyArgument = spy.args[0][0];
assert.equal(typeof spyArgument, 'string');
assert.equal(spyArgument, 'Charging');
spyArgument = null;
});
});
});

BIN
dist/fonts/Gilroy-ExtraBold.otf vendored Normal file

Binary file not shown.

BIN
dist/fonts/Gilroy-Light.otf vendored Normal file

Binary file not shown.

BIN
dist/icons/plus.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

View file

@ -1,141 +0,0 @@
mainMenuItems = ['games', 'settings', 'account', 'store', 'files'];
gameMenuItems = ['slimey', 'test2'];
settingMenuItems = ['fullscreen', 'auto-update'];
settingMenuItemValues = [0,1];
selected = 1;
var menuType = 'horizontal';
var looper = 1;
function updateSettings(){
looper = 1;
settingMenuItems.forEach(function(name){
$("#option-" + settingMenuItems[looper - 1] + " label input").prop( "checked", settingMenuItemValues[looper - 1]);
looper++;
})
looper = 1;
}
setInterval(updateSettings, 400);
function select(){
if(start == true){
showMainMenu();
return;
}
if(window.menu == 1){
if(selected == 1){
window.menu = 2;
window.selected = 1;
$(".button-main.selected").removeClass("selected");
$(".button-main-container.selected").removeClass("selected");
menuType = 'horizontal';
selectGameMenuItem();
} else if(selected == 2){
window.selected = 1
window.menu = 3;
$(".button-main.selected").removeClass("selected");
$(".button-main-container.selected").removeClass("selected");
menuType = 'vertical';
selectSettingMenuItem();
}
} else if(window.menu == 3) {
$("#option-" + settingMenuItems[selected - 1] + " label input").prop( "checked", !$("#option-" + settingMenuItems[selected - 1] + " label input").prop( "checked") );
settingMenuItemValues[selected - 1] = $("#option-" + settingMenuItems[selected - 1] + " label input").prop( "checked");
if(settingMenuItems[selected - 1] == 'fullscreen'){
sendFullscreen(settingMenuItemValues[selected - 1]);
}
} else if(window.menu == 2){
if(selected == 1){
$("#game-slimey .game-preview").css('transition', '0.5s width, 0.5s height, 0.5s max-height, 0.3s top, 0.3s left, 0.5s opacity');
$("#game-slimey .game-preview").css('-webkit-transition', '0.5s width, 0.5s height, 0.5s max-height, 0.3s top, 0.3s left, 0.5s opacity');
$("#game-slimey .game-preview").css('-moz-transition', '0.5s width, 0.5s height, 0.5s max-height, 0.3s top, 0.3s left, 0.5s opacity');
$("#game-slimey .game-preview").width($(document).width());
$("#game-slimey .game-preview").height("auto");
var gamePosition = $("#game-slimey .game-preview").position();
$("#game-slimey .game-preview").css("left", gamePosition.left);
$("#game-slimey .game-preview").css("top", gamePosition.top);
$("#game-slimey .game-preview").css("position", "fixed");
$("#game-slimey .game-preview").css("z-index", "990");
$("#game-slimey .game-preview").css("left", 0);
$("#game-slimey .game-preview").css("top", 0);
$("#game-slimey .game-preview").css("opacity", 0);
setTimeout(() => {
$("#game-slimey .game-preview").attr("style", '');
$("#game-slimey .game-preview").hide();
startGame(0);
}, 500);
}
}
}
function deselect(){
if(menu == 2 || menu == 3){
$(".selected").removeClass("selected");
switch(menu){
case 2:
window.selected = 1;
break;
case 3:
window.selected = 2;
break;
}
window.menu = 1;
menuType = 'horizontal';
selectMainMenuItem();
} else if(menu == 1){
showStartMenu();
}
}
function callMenuItem(){
switch(menu){
case 1:
selectMainMenuItem();
break;
case 2:
selectGameMenuItem();
break;
case 3:
selectSettingMenuItem();
break;
}
}
function selectSettingMenuItem(){
if(selected > settingMenuItems.length){
selected = 1;
} else if(selected < 1){
selected = settingMenuItems.length;
}
console.log("Selected item no. " + selected);
$(".option.selected").removeClass("selected");
$("#option-" + settingMenuItems[selected - 1]).addClass("selected");
}
function selectGameMenuItem(){
if(selected > gameMenuItems.length){
selected = 1;
} else if(selected < 1){
selected = gameMenuItems.length;
}
console.log("Selected item no. " + selected);
$(".game.selected").removeClass("selected");
$("#game-" + gameMenuItems[selected - 1]).addClass("selected");
$(".game").width((function(offset, width){
return $(".game .game-preview:eq(" + offset + ")").width();
}));
}
function selectMainMenuItem(){
if(selected > mainMenuItems.length){
selected = 1;
} else if(selected < 1){
selected = mainMenuItems.length;
}
$(".menu-item").addClass("hidden");
console.log("Selected item no. " + selected);
$(".button-main.selected").removeClass("selected");
$(".button-main-container.selected").removeClass("selected");
$("#" + mainMenuItems[selected - 1]).addClass("selected");
$("#" + mainMenuItems[selected - 1] + "-view").removeClass("hidden");
$(".button-main-container:has(.selected)").addClass("selected");
if(selected == 1){
$(".game").width((function(offset, width){
return $(".game .game-preview:eq(" + offset + ")").width();
}));
}
}

File diff suppressed because it is too large Load diff

297
html/gamepad/input.js Normal file
View file

@ -0,0 +1,297 @@
/**
* (C) Daniel Bulant
* This file IS NOT subject to the LICENSE.
* Permission is hereby granted by Daniel Bulant to be used exclusively in console-hub (unless otherwise stated).
* Want to use this script? Contact me at admin@danbulant.eu
*/
class EventEmitter {
constructor() {
var delegate = document.createDocumentFragment();
[
'addEventListener',
'dispatchEvent',
'removeEventListener'
].forEach(f =>
this[f] = (...xs) => delegate[f](...xs)
)
}
}
class Controls extends EventEmitter {
players = [];
binds = {};
gamepads = 0;
gamepadArray = {};
axisMinimum = 0.7;
constructor() {
super();
this.isChrome = !!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime);
//Gamepad support
if (!this.hasGamepads()) {
console.log("Gamepads not supported!");
} else {
this.initGamepads();
}
var player = this.addPlayer();
console.log("(DEFAULT) Player joined using Keyboard");
player.controlledBy = {
type: "keyboard",
id: 1
}
this.defaultBindings(player, "KEY1");
var interval = setInterval(this.update, 1000 / 60, this, this.binds);//update the properties at 60FPS
this.listenForKeys();
}
listenForKeys() {
this.keys = {};
window.onkeyup = e => { this.keys[e.key] = false; if (e.key == "Tab") { e.preventDefault() } }
window.onkeydown = e => { this.keys[e.key] = true; if (e.key == "Tab") { e.preventDefault() } }
}
update(controls, bindings) {
controls.players.forEach((player) => {
var gamepad = {};
if (player.controlledBy.type == "controller") {
gamepad = navigator.getGamepads()[player.controlledBy.id];
}
var binds = bindings[player.id];
for (var bind in binds) {
if (!binds.hasOwnProperty(bind)) continue;
var isPressed = controls.checkPressed(binds[bind], gamepad);
if (isPressed && isPressed != player[bind + "Pressed"]) {
var event = new Event(player.id + "-" + bind);
event.player = player;
event.bindings = binds;
controls.dispatchEvent(event);
}
if (isPressed) {
var event = new Event("while_" + player.id + "-" + bind);
event.player = player;
event.bindings = binds;
controls.dispatchEvent(event);
}
player[bind + "Pressed"] = isPressed;
}
});
}
while(player, event, callback) {
return this.addEventListener("while_" + player + "-" + event, callback);
}
on(player, event, callback) {
return this.addEventListener(player + "-" + event, callback);
}
once(player, event, callback) {
var controls = this;
return this.addEventListener(player + "-" + event, function cb(e) {
controls.removeEventListener(e.type, cb);
callback(e);
});
}
checkPressed(str, gamepad) {
var bind = this.parseBind(str);
if (bind.type == "button") {
return gamepad.buttons[bind.value].pressed;
}
if (bind.type == "key") {
return this.keys[bind.value] == true;
}
if (bind.type == "unknown") {
return null;
}
if (bind.type == "axis") {
var value = gamepad.axes[bind.value];
if (bind.axis == "+") {
return value > this.axisMinimum;
} else if (bind.axis == "-") {
return value < -this.axisMinimum;
}
}
return null;
}
parseBind(str) {
var bind = {};
if (str.substr(0, 1) == "b") {
bind.type = "button";
} else if (str.substr(0, 1) == "a") {
bind.type = "axis";
} else if (str.substr(0, 1) == "k") {
bind.type = "key";
str = str.substr(1);//remove the -
} else {
bind.type = "unknown";
}
str = str.substr(1);
if (bind.type == "axis") {
bind.axis = str.substr(str.length - 1);
str = str.substr(0, str.length - 1);
} else {
bind.axis = null;
}
bind.value = str;
return bind;
}
initGamepads() {
var controls = this;
window.addEventListener("gamepadconnected", function (e) {
console.log("Player joined using %s", e.gamepad.id);
controls.gamepads++;
controls.gamepadArray[e.gamepad.index] = e.gamepad;
var player = controls.addPlayer();
player.controlledBy = {
type: "controller",
id: e.gamepad.index
}
controls.defaultBindings(player, "DS4");
});
window.addEventListener("gamepaddisconnected", function (e) {
console.log("Player %d disconnected", e.gamepad.index);
controls.gamepads--;
controls.gamepadArray[e.gamepad.index] = undefined;
controls.removeBindings()
});
}
defaultBindings(player, type) {
var binding = {};
switch (type) {
case "DS4":
binding = {
home: "b16",
action: "b0",
jump: "b1",
forward: "a1-",
backward: "a1+",
left: "a0-",
right: "a0+",
options: "b9",
cancel: "b1"
}
break;
case "KEY1":
binding = {
home: "k-Tab",
action: "k-Enter",
jump: "k- ",
forward: "k-w",
backward: "k-s",
left: "k-a",
right: "k-d",
options: "k-Escape",
cancel: "k-Backspace"
}
break;
}
this.binds[player.id] = binding
}
/**
* Try vibrating
* @param {*} player player which controller is to be vibrated
* @param {*} length ms to vibrate
* @param {*} weak percents to vibrate
* @param {*} strong percents to vibrate
* @returns {Boolean} if vibration was possible (is supported)
*/
vibrate(player, length = 200, weak = 100, strong = 100) {
try {
if (player.controlledBy.type == "controller") {
navigator.getGamepads()[player.controlledBy.id].vibrationActuator.playEffect("dual-rumble", {
startDelay: 0,
duration: length,
weakMagnitude: weak / 100,
strongMagnitude: strong / 100
});
return true;
} else {
return false;
}
} catch (e) {
console.log(e);
return false;
}
}
/**
* DEBUG
*/
reportOnGamepad() {
var gp = navigator.getGamepads()[0];
var html = "";
html += "id: " + gp.id + "<br/>";
for (var i = 0; i < gp.buttons.length; i++) {
html += "Button " + (i + 1) + ": ";
if (gp.buttons[i].pressed) html += " pressed";
html += "<br/>";
}
for (var i = 0; i < gp.axes.length; i += 2) {
html += "Stick " + (Math.ceil(i / 2) + 1) + ": " + gp.axes[i] + ", " + gp.axes[i + 1] + "<br/>";
}
document.getElementById("gamepadDisplay").innerHTML = html;
}
hasGamepads() {
return "getGamepads" in navigator;
}
playerCount() {
return this.players.length;
}
addPlayer() {
var player = this.players[this.players.length] = {};
player.id = this.players.length;
player.forwardPressed = false;
player.backwardPressed = false;
player.rightPressed = false;
player.leftPressed = false;
player.jumpPressed = false;
player.actionPressed = false;
player.homePressed = false;
player.optionsPressed = false;
player.controlledBy = null;
return player;
}
addBinding(player, key, action) {
if (!this.binds[player]) this.binds[player] = {};
if (!this.binds[player][key]) this.binds[player][key] = [];
this.binds[player][key][this.binds[player][key].length] = action;
return this;//chaining
}
removeBinding(player, key, action = null) {
if (action = null) {
this.binds[player][key] = [];
} else {
this.removeItem(this.binds[player][key], action);
}
return this;
}
removeBindings(player) {
this.binds[player] = {};
}
removeItem(arr) {
var what, a = arguments, L = a.length, ax;
while (L > 1 && arr.length) {
what = a[--L];
while ((ax = arr.indexOf(what)) !== -1) {
arr.splice(ax, 1);
}
}
return arr;
}
}

79
html/gamepad/keyboard.js Normal file
View file

@ -0,0 +1,79 @@
$(document).keypress((event) => {
if(event.which == 39){//RIGHT
if(menuType == 'horizontal'){
goRight();
}
} else if(event.which == 40){//DOWN
if(menuType != 'horizontal'){
goRight();
}
} else if(event.which == 37){//LEFT
if(menuType == 'horizontal'){
goLeft();
}
} else if(event.which == 38){//UP
if(menuType != 'horizontal'){
goLeft();
}
} else if(event.which == 13){
select();
event.preventDefault();
} else if(event.which == 27){
deselect();
event.preventDefault();
}
})
var keyBinds = new Map();
keyBinds.set('button_1', 'enter')//set button_1 (A) as enter
var pressed = [];
var gameLooper = 0;
//Sending keys from gamepad
function changeToGame(){
//Called when game is running
//reset events
gamepad.off('press', 'start');
gamepad.off('press', 'd_pad_left');
gamepad.off('press', 'd_pad_right');
gamepad.off('press', 'button_1');
gamepad.off('press', 'button_2');
//add custom ones
keyBinds.forEach((val, key) => {
gamepad.on('press', key, () => {
sendKeys([], val);
})
})
// gameLooper = setInterval(() => {
// if(pressed == []) return;
// sendKeys(pressed);
// pressed = [];
// }, 100);
}
function changeToMenu(){
clearInterval(gameLooper); //stop sending keys
//Called when game is stopped
//reset events
gamepad.off('press', 'start');
gamepad.off('press', 'd_pad_left');
gamepad.off('press', 'd_pad_right');
gamepad.off('press', 'button_1');
gamepad.off('press', 'button_2');
//restore original events
gamepad.on('press', 'start', () => {
showMainMenu();
});
gamepad.on('press', 'd_pad_left', () => {
goLeft();
});
gamepad.on('press', 'd_pad_right', () => {
goRight();
});
gamepad.on('press', 'button_1', () => {
select();
});
gamepad.on('press', 'button_2', () => {
deselect();
});
}

View file

@ -0,0 +1,40 @@
//Only to be used for PS4 (Dualshock 4) controllers
var dualShock = require('../../dist/dualshock-controller/src/dualshock');
try {
var controller = dualShock({
config: "dualshock4-generic-driver"
});
controller.on('error', err => console.log(err));
function setExtras(obj) {
controller.setExtras(obj);
}
var connected = false;
controller.on('connected', () => {
connected = true;
});
controller.on("disconnected", () => {
connected = false;
})
function isConnected() {
return connected;
}
function on(event, handler) {
controller.on(event, handler);
}
module.exports = {
on,
isConnected,
setExtras
}
} catch (e) {
console.error(e);
module.exports = {
isConnected: ()=>{return false}
}
}

View file

@ -1,10 +0,0 @@
function startGame(int){
if(int == 0){//SLIMEY JUMP
var game = document.createElement('iframe');
game.id = 'frame';
game.src = "https://v6p9d9t4.ssl.hwcdn.net/html/1493204/index.html";
game.style.position = 'fixed';
game.style.width = '100%';
game.style.zIndex = '990';
}
}

View file

@ -1,185 +0,0 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Console hub (ALPHA)</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"><!-- include material icons -->
<link rel="stylesheet" href="styles.min.css"><!-- include custom stylesheet -->
</head>
<body>
<div class="welcome-main">
<h1 class="title-font">Welcome</h1>
<h5 class="glow" id="welcome-continue">Press <b>START</b> to procceed</h5>
</div>
<nav>
<div class="profile">
Not loged in
</div>
<div class="info">
<i class="material-icons">
network_wifi
</i>
<span class="time" id="time">
00:00
</span>
</div>
</nav>
<div id="selection" class="menu hidden">
<div id="games-view" class="menu-item hidden">
<h1 class="title-font">Games</h1>
<div class="previews">
<div class="game" id="game-slimey">
<img src="https://console.danbulant.eu/games/slimey.png" class="game-preview">
<span>Slimey, JUMP</span>
</div>
<div class="game" id="game-test2">
<img src="https://cdn.supercell.com/supercell.com/190617073222/supercell.com/files/styles/hero_image_narrow/public/hero_bg_brawlstars_.jpg?itok=yifeFssz&timestamp=1544532809" class="game-preview">
<span>Brawl stars</span>
</div>
</div>
</div>
<div id="settings-view" class="menu-item hidden">
<h1 class="title-font">Settings</h1>
<div class="switch-label option switchable" id="option-fullscreen">
<span>Fullscreen</span>
<label class="switch">
<input type="checkbox">
<span class="slider round"></span>
</label>
</div>
<div class="switch-label option switchable" id="option-auto-update">
<span>Auto updates</span>
<label class="switch">
<input type="checkbox" checked>
<span class="slider round"></span>
</label>
</div>
</div>
<div id="account-view" class="menu-item hidden">
<h1 class="title-font">Account</h1>
<p>You aren't signed in</p>
<button>Login/register</button>
</div>
<div id="store-view" class="menu-item hidden">
<h1 class="title-font">Store</h1>
<p>Not available in ALHPA stage</p>
</div>
<div id="files-view" class="menu-item hidden">
<h1 class="title-font">Files</h1>
<p class="path"></p>
<div id="files-list-container">
<ul id="files-list">
</ul>
</div>
</div>
</div>
<div id="dialog" class="hidden">
<h1 id="dialog-title">TITLE</h1>
<p id="dialog-text">TEXT</p>
<div id="dialog-buttons">
<button id="dialog-button_1">OK</button>
</div>
</div>
<div id="main-menu" class="main hidden">
<div class="button-main-container">
<div class="button-main selected" id="games">
<div class="button-menu" id="games-menu">
<i class="material-icons">
videogame_asset
</i>
</div>
<span>
Games
</span>
</div>
</div>
<div class="button-main-container">
<div class="button-main " id="settings">
<div class="button-menu" id="settings-menu">
<i class="material-icons">
settings
</i>
</div>
<span>
Settings
</span>
</div>
</div>
<div class="button-main-container">
<div class="button-main " id="account">
<div class="button-menu" id="account-menu">
<i class="material-icons">
account_box
</i>
</div>
<span>
Account
</span>
</div>
</div>
<div class="button-main-container">
<div class="button-main " id="store">
<div class="button-menu" id="store-menu">
<i class="material-icons">
local_grocery_store
</i>
</div>
<span>
Store
</span>
</div>
</div>
<div class="button-main-container">
<div class="button-main " id="files">
<div class="button-menu" id="files-menu">
<i class="material-icons">
folder_open
</i>
</div>
<span>
Files
</span>
</div>
</div>
</div>
<div id="back" class="back-arrow hidden">
<i class="material-icons circle">
arrow_back
</i>
<span id="back-text">back</span>
</div>
<div id="snackbar"></div>
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
<script src="jquery.min.js"></script>
<script>if (window.module) module = window.module;</script>
<script src="gamepad.js"></script>
<script src="functions.js"></script>
<script src="script.js"></script>
<script src="onlineChecker.js"></script>
<script src="filesystem.js"></script>
<script src="node.js"></script>
<script src="keyboard.js"></script>
<script>
</script>
</body>
</html>

View file

@ -1,25 +0,0 @@
$(document).keypress((event) => {
if(event.which == 39){//RIGHT
if(menuType == 'horizontal'){
goRight();
}
} else if(event.which == 40){//DOWN
if(menuType != 'horizontal'){
goRight();
}
} else if(event.which == 37){//LEFT
if(menuType == 'horizontal'){
goLeft();
}
} else if(event.which == 38){//UP
if(menuType != 'horizontal'){
goLeft();
}
} else if(event.which == 13){
select();
event.preventDefault();
} else if(event.which == 27){
deselect();
event.preventDefault();
}
})

View file

@ -1,37 +1,30 @@
if(typeof module !== undefined){
var wifi, wifiQuality;
// In renderer process (web page).
const { ipcRenderer } = require('electron')
// In renderer process (web page).
const { ipcRenderer } = require('electron')
ipcRenderer.on('wifi', (event, arg) => {
wifi = arg;
wifi = wifi;
})
ipcRenderer.on('wifiQuality', (event, arg) => {
wifiQuality = arg;
wifiQuality = wifiQuality;
})
ipcRenderer.on('fullscreen', (event, arg) => {
console.log("Fullscreen now " + arg);
settingMenuItemValues[0] = arg;
})
function sendFullscreen(bool){
console.log("Sending fullscreen " + bool);
ipcRenderer.send('fullscreen', bool);
}
ipcRenderer.send('get-data', 'wifi');
ipcRenderer.send('get-data', 'wifiQuality');
var files = null;
ipcRenderer.on('listFiles', (event, arg) => {
console.log(arg);
files = arg;
refreshFiles();
})
var loc = window.location.pathname;
var dir = loc.substring(1, loc.lastIndexOf('/'));//fix file:///, only on node
ipcRenderer.send('listFiles', dir);
} else {
//no NODE integration, propably browser access
$("div:has(#files)").hide();//Disable file system preview
mainMenuItems.slice("files");
var wifi, wifiQuality;
ipcRenderer.on('wifi', (event, arg) => {
wifi = arg;
wifi = wifi;
});
ipcRenderer.on('wifiQuality', (event, arg) => {
wifiQuality = arg;
wifiQuality = wifiQuality;
});
ipcRenderer.on('fullscreen', (event, arg) => {
console.log("Fullscreen now " + arg);
settingMenuItemValues[0] = arg;
});
ipcRenderer.send('get-data', 'wifi');
ipcRenderer.send('get-data', 'wifiQuality');
function sendKeys(arg, arg2){
ipcRenderer.send('sendKeys', arg, arg2);
return true;
}
var loc = window.location.pathname;
var dir = loc.substring(1, loc.lastIndexOf('/'));
ipcRenderer.send('listFiles', dir);

View file

@ -13,10 +13,8 @@ function updateIndicator() {
} else {
$('.info i').html('signal_wifi_0_bar');
}
console.log('Wifi quality is ' + wifiQuality + '%')
} else {
$('.info i').html('signal_wifi_off');
console.log('offline');
}
}

View file

@ -1,10 +1,6 @@
var start = true;
var screen = 0;
var menu = 0;
var gamepads = 0;
const gamepad = new Gamepad();
var toastCancel;
var today = new Date();
var time = today.getHours() + ":" + today.getMinutes();
function pad(num, size){ return ('00000000000000' + num).substr(-size); }
@ -15,90 +11,27 @@ setInterval((function(){
$("#time").html(time);
}), 1000);
function toast(string) {
clearTimeout(toastCancel);
var x = document.getElementById("snackbar");
x.className = "show";
x.innerHTML = string;
toastCancel = setTimeout(function(){ x.className = x.className.replace("show", ""); }, 3000);
}
function showWelcomeText(){
var x = document.getElementById("welcome-continue");
if(gamepads > 0){
x.innerHTML = "Press <b>START</b> to procceed";
} else {
x.innerHTML = "Connect your gamepad!";
}
}
function showMainMenu(){
window.start = false;
window.screen = 1;
window.menu = 1;
goRight();
goLeft();
$(".game").width((function(offset, width){
return $(".game .game-preview:eq(" + offset + ")").width();
}));
$("#main-menu").removeClass('hidden');
$("#selection").removeClass("hidden");
$(".welcome-main").addClass("hide");
setTimeout(1000, (function(){$(".welcome-main").hide();}));
}
function showStartMenu(){
window.start = true;
window.screen = 0;
window.menu = 0;
$("#main-menu").addClass('hidden');
$("#selection").addClass("hidden");
$(".welcome-main").removeClass("hide");
$(".welcome-main").show();
}
gamepad.on('connect', e => {
gamepads++;
showWelcomeText();
toast(`Player ${e.index + 1} has connected`);
console.log(`controller ${e.index} connected!`);
});
gamepad.on('disconnect', e => {
toast(`Player ${e.index + 1} has disconnected`);
gamepads --;
console.log(`controller ${e.index} disconnected!`);
});
gamepad.on('press', 'start', () => {
showMainMenu();
});
gamepad.on('press', 'd_pad_left', () => {
goLeft();
});
gamepad.on('press', 'd_pad_right', () => {
goRight();
});
gamepad.on('press', 'button_1', () => {
select();
});
gamepad.on('press', 'button_2', () => {
deselect();
});
function goLeft(){
if(menu == 1 || menu == 2 || menu == 3){
selected--;
callMenuItem();
}
console.log("Going left");
}
function goRight(){
if(menu == 1 || menu == 2 || menu == 3){
selected++;
callMenuItem();
}
console.log("Going right");
}
var leftCounter = 0;
var rightCounter = 0;

1
html/styles.min.css vendored

File diff suppressed because one or more lines are too long

View file

@ -1,479 +0,0 @@
/*
* VARS
*/
$unselected: rgb(182,182,182);
$selected: white;
/*
* FONTS
*/
@font-face {
font-family: 'Open sans';
src: url('https://console.danbulant.eu/open-sans/OpenSans-Regular.ttf');//online version
}
@font-face {
font-family: 'Gilroy-bold';
src: url('https://console.danbulant.eu/Gilroy-ExtraBold.otf');//online version, if you want offline, put fonts in this folder and change the link here
}
body {
background: #5d75ad;
background: linear-gradient(216deg, #6b89cf, #3a3766);
background-size: 400% 400%;
-webkit-animation: BackgroundGradient 33s ease infinite;
-moz-animation: BackgroundGradient 33s ease infinite;
-o-animation: BackgroundGradient 33s ease infinite;
animation: BackgroundGradient 33s ease infinite;
}
/*
* Background
*/
@-webkit-keyframes BackgroundGradient {
0%{background-position:0% 22%}
50%{background-position:100% 79%}
100%{background-position:0% 22%}
}
@-moz-keyframes BackgroundGradient {
0%{background-position:0% 22%}
50%{background-position:100% 79%}
100%{background-position:0% 22%}
}
@-o-keyframes BackgroundGradient {
0%{background-position:0% 22%}
50%{background-position:100% 79%}
100%{background-position:0% 22%}
}
@keyframes BackgroundGradient {
0%{background-position:0% 22%}
50%{background-position:100% 79%}
100%{background-position:0% 22%}
}
/*
* Main menu
*/
.main {
display: block;
position: fixed;
bottom: 40px;
left: 10px;
.button-main-container {
display: inline-block;
height: 120px;
.button-main {
transition: 0.5s margin-top;
margin-top: 20px;
color: $unselected;
span {
padding-left: 10px;
}
.button-menu {
margin-left: 5px;
margin-right: 5px;
padding-left: 45px;
padding-right: 45px;
border-radius: 5px;
height: 100px;
width: 100px;
color: white;
background: #414E92;
.material-icons {
font-size: 100px;
}
}
}
}
}
.button-main-container .button-main.selected{
color: white;
margin-top: 0px;
.button-menu{
background: #3D7BFF;
box-shadow: 0px 0px 5px rgba(61, 123, 255, 0.8);
}
}
html {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
body {
padding: 0;
margin: 0;
width: 100%;
height: 95%;
}
font-family: 'Open Sans', sans-serif;
}
.hidden {
display: none !important;
}
.title-font {
font-family: 'Gilroy-bold', 'Open Sans', sans-serif;
}
/*
* Tab views
*/
#selection {
position: absolute;
top: 50px;
left: 15px;
width: calc(100% - 15px);
.menu-item {
color: white;
h1 {
font-family: 'Gilroy-bold', 'Open Sans', sans-serif;
padding: 10px;
font-size: 50px;
margin: 0;
}
}
#games-view {
.previews {
height: 150px;
.game {
height: auto;
text-align: justify;
height: 150px;
.game-preview {
height: 130px;
border-radius: 5px;
// Now in JS
// -webkit-transition: 0.5s width, 0.5s height, 0.5s max-height, 0.3s top, 0.3s left, 0.5s opacity;
// -moz-transition: 0.5s width, 0.5s height, 0.5s max-height, 0.3s top, 0.3s left, 0.5s opacity;
// transition: 0.5s width, 0.5s height, 0.5s max-height, 0.3s top, 0.3s left, 0.5s opacity;
}
font-size: 20px;
display: inline-block;
color: $unselected;
opacity: 1;
// -webkit-transition: 0.5s width, 0.5s height, 0.5s max-height, 0.3s top, 0.3s left, 0.5s opacity;
// -moz-transition: 0.5s width, 0.5s height, 0.5s max-height, 0.3s top, 0.3s left, 0.5s opacity;
// transition: 0.5s width, 0.5s height, 0.5s max-height, 0.3s top, 0.3s left, 0.5s opacity;
}
.game.selected {
height: 190px;
color: $selected;
.game-preview {
height: 170px;
-webkit-box-shadow: 0px 27px 72px -32px rgba(0,0,0,0.51);
-moz-box-shadow: 0px 27px 72px -32px rgba(0,0,0,0.51);
box-shadow: 0px 27px 72px -32px rgba(0,0,0,0.51);
}
}
}
}
#files-view {
overflow-y: hidden;
overflow-x: hidden;
height: 500px;
#files-list-container {
::-webkit-scrollbar {
width: 7px;
}
::-webkit-scrollbar-button {
height: 0px;
}
::-webkit-scrollbar-thumb {
background: rgba(255,255,255,0.2);
border-radius: 50px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(255,255,255,0.4);
}
::-webkit-scrollbar-thumb:active {
background: rgba(255,255,255,0.5);
}
width: 100%;
height: 95%;
overflow-y: auto;
overflow-x: hidden;
margin: 0;
ul {
border-top: 1px solid rgba(255,255,255,0.2);
border-bottom: 1px solid rgba(255,255,255,0.2);
height: 80%;
width: 100%;
overflow-x: hidden;
list-style-type: none;
padding-left: 0;
li {
vertical-align: middle;
padding-top: 11px;
padding-left: 15px;
height: 36px;
}
li:not(:first-child){
border-top: 1px solid rgba(255,255,255,0.2);
}
.selected {
background: rgba(255,255,255,0.4);
}
}
}
}
}
/*
* Information panel, marked as 'nav'
*/
nav {
z-index:999;
display: flex;
justify-content: space-between;
padding: 10px;
position: fixed;
top: 0;
left: 0;
height: 30px;
width: calc(100% - 20px);
.profile {
left: 0;
}
.info {
right: 0;
}
div {
display: inline;
color: white;
}
}
/*
* Dialog
*/
#dialog {
display: block;
position: fixed;
z-index: 998;
}
/*
* Account
*/
#account-view {
button {
color: white;
background-color: transparent;
border: 1px solid white;
border-radius: 40px;
font-size: 20px;
}
}
/*
* Settings page
*/
#settings-view {
.option {
color: $unselected;
}
.option.selected {
color: $selected;
}
.option.switchable {
.switch .slider{
width: 52px;
height: 25px;
}
.switch .slider:before {
width: 18px;
height: 18px;
}
}
}
/*
* Startup
*/
.welcome-main {
color: white;
width: 500px;
margin-left: auto;
margin-right: auto;
position: relative;
top: 50%;
transform: translateY(-50%);
//fade out transition
-webkit-transition: opacity 1s ease-in-out;
-moz-transition: opacity 1s ease-in-out;
-ms-transition: opacity 1s ease-in-out;
-o-transition: opacity 1s ease-in-out;
transition: opacity 1s ease-in-out;
h1 {
font-size: 100px;
margin: 0;
}
h5 {
margin-top: 0;
b {
}
}
}
.welcome-main.hide {
opacity: 0;
}
.glow {
color: #fff;
text-align: center;
-webkit-animation: glow 1s ease-in-out infinite alternate;
-moz-animation: glow 1s ease-in-out infinite alternate;
animation: glow 1s ease-in-out infinite alternate;
}
$innerGlowColor: #fff;
$outerGlowColorLight: #fff;//#e60073
$outerGlowColorDark: #969696;//#ff4da6
$GlowSize: 1px;
@-webkit-keyframes glow {
from {
text-shadow: 0 0 $GlowSize*1 $innerGlowColor, 0 0 $GlowSize*2 $innerGlowColor, 0 0 $GlowSize*3 $outerGlowColorLight, 0 0 $GlowSize*4 $outerGlowColorLight, 0 0 $GlowSize*5 $outerGlowColorLight, 0 0 $GlowSize*6 $outerGlowColorLight, 0 0 $GlowSize*7 $outerGlowColorLight;
}
to {
text-shadow: 0 0 $GlowSize*2 $innerGlowColor, 0 0 $GlowSize*3 $outerGlowColorDark, 0 0 $GlowSize*4 $outerGlowColorDark, 0 0 $GlowSize*5 $outerGlowColorDark, 0 0 $GlowSize*6 $outerGlowColorDark, 0 0 $GlowSize*7 $outerGlowColorDark, 0 0 $GlowSize*8 $outerGlowColorDark;
}
}
/*
* UI
*/
$MainColor: #fff;
$SecondaryColor: #fff;
$OutlineColor: rgb(196, 213, 1);
.back-arrow {
position: fixed;
bottom: 20px;
left: 20px;
color: $OutlineColor;
.circle {
border-radius: 50%;
border: 1px solid $OutlineColor;
}
vertical-align: middle;
font-weight: normal;
font-style: normal;
font-size: 24px;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased;
}
/*
* Snackbar / toast messages
*/
/* The snackbar - position it at the bottom and in the middle of the screen */
#snackbar {
visibility: hidden; /* Hidden by default. Visible on click */
min-width: 250px; /* Set a default minimum width */
margin-left: -125px; /* Divide value of min-width by 2 */
//background-color: #333; /* Black background color */
color: #fff; /* White text color */
text-align: center; /* Centered text */
border-radius: 2px; /* Rounded borders */
padding: 16px; /* Padding */
position: fixed; /* Sit on top of the screen */
z-index: 100; /* Add a z-index if needed */
left: 50%; /* Center the snackbar */
bottom: 15px; /* 30px from the bottom */
}
/* Show the snackbar when clicking on a button (class added with JavaScript) */
#snackbar.show {
visibility: visible; /* Show the snackbar */
/* Add animation: Take 0.5 seconds to fade in and out the snackbar.
However, delay the fade out process for 2.5 seconds */
-webkit-animation: snackbarFadein 0.5s, snackbarFadeout 0.5s 2.5s;
animation: snackbarFadein 0.5s, snackbarFadeout 0.5s 2.5s;
}
/* Animations to fade the snackbar in and out */
@-webkit-keyframes snackbarFadein {
from {bottom: 0; opacity: 0;}
to {bottom: 30px; opacity: 1;}
}
@keyframes snackbarFadein {
from {bottom: 0; opacity: 0;}
to {bottom: 30px; opacity: 1;}
}
@-webkit-keyframes snackbarFadeout {
from {bottom: 30px; opacity: 1;}
to {bottom: 0; opacity: 0;}
}
@keyframes snackbarFadeout {
from {bottom: 30px; opacity: 1;}
to {bottom: 0; opacity: 0;}
}
/*
* Switches / sliders
*/
/* The switch - the box around the slider */
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}
/* Hide default HTML checkbox */
.switch input {
opacity: 0;
width: 0;
height: 0;
}
/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}
input:checked + .slider {
background-color: #2196F3;
}
input:focus + .slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked + .slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}
/* Rounded sliders */
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}

33
html/utils.js Normal file
View file

@ -0,0 +1,33 @@
const User = require("./views/data/user");
const Card = require("./views/data/card");
function removeChildNodes(node){
while (node.firstChild) {
node.removeChild(node.firstChild);
}
}
function getUsers() {
var user = new User;
user.name = "Add";
user.avatar = "../../dist/icons/plus.png";
var user2 = new User;
user2.name = "Test";
user2.avatar = "https://api.adorable.io/avatars/285/test";
return [user, user2];
}
function usersToCards(users){
var cards = [];
users.forEach((u, i)=>{
cards[i] = u.getCard();
})
return cards;
}
module.exports = {
removeChildNodes,
getUsers,
usersToCards
}

View file

@ -1 +0,0 @@
01

View file

@ -0,0 +1,9 @@
class Achievment {
time = new Date;
name = "";
game = 0;
image = "";
text = "";
}
module.exports = Achievment;

View file

@ -0,0 +1,6 @@
class Action {
button = null;
text = "";
}
module.exports = Action;

View file

@ -0,0 +1,7 @@
class Button {
icon = "";
player = -1;
type = "";
}
module.exports = Button;

8
html/views/data/card.js Normal file
View file

@ -0,0 +1,8 @@
class Card {
name = "";
image = "";
action = "";
onclick(){}
}
module.exports = Card;

View file

@ -0,0 +1,7 @@
const User = require("./user");
class CurrentUser extends User {
}
module.exports = CurrentUser;

13
html/views/data/game.js Normal file
View file

@ -0,0 +1,13 @@
class Game {
name = "";
image = "";
run(){
console.log("Game running");
this.exit();
}
exit(){
global.menu.show();
}
}
module.exports = Game;

20
html/views/data/user.js Normal file
View file

@ -0,0 +1,20 @@
const Card = require("./card");
class User {
name = [];
username = "";
friends = [];
avatar = "";
achievments = {};
getCard(){
var card = new Card;
card.name = this.name;
card.image = this.avatar;
card.action = false;
return card;
}
}
module.exports = User;

31
html/views/index.html Normal file
View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Console hub</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"><!-- include material icons -->
<link rel="stylesheet" href="../../dist/css/styles.min.css"><!-- include custom stylesheet -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self' https://fonts.googleapis.com http://dist.danbulant.eu 'unsafe-inline';
font-src *;
img-src *">
</head>
<body>
<div class='box'>
<div class='wave -one'></div>
<div class='wave -two'></div>
<div class='wave -three'></div>
</div>
<div id="view">
</div>
<script>
if (typeof module === 'object') {window.module = module; module = undefined;}
</script>
<script src="../dep/jquery.min.js"></script>
<script>if (window.module) module = window.module;</script>
<script src="main.js"></script>
</body>
</html>

7
html/views/main.js Normal file
View file

@ -0,0 +1,7 @@
const gamepadConnected = require("./menu/connected");
const welcome = require("./menu/welcome");
console.log("Console-hub alpha");
welcome();

View file

@ -1,16 +1,16 @@
{
"short_name": "Console hub",
"name": "Console hub beta",
"icons": [
{
"src": "/favicon.ico",
"type": "image/ico"
}
],
"start_url": "/",
"background_color": "#5d75ad",
"display": "standalone",
"orientation": "landscape",
"scope": "/",
"theme_color": "#5d75ad"
}
{
"short_name": "Console hub",
"name": "Console hub beta",
"icons": [
{
"src": "/favicon.ico",
"type": "image/ico"
}
],
"start_url": "/",
"background_color": "#5d75ad",
"display": "standalone",
"orientation": "landscape",
"scope": "/",
"theme_color": "#5d75ad"
}

View file

@ -0,0 +1,67 @@
const utils = require("../../utils");
const gui = require("./gui");
const Gamepad = require("../../gamepad/gamepad");
const gamepad = new Gamepad;
const controller = require("../../gamepad/ps4controller");
function gamepadConnected(){
console.log("Gamepad connected");
var view = document.getElementById("view");
utils.removeChildNodes(view);
gui.showTitle("Your profile");
gui.showDescription("Select or add your Pushr account to continue");
const users = utils.getUsers();
var max = users.length - 1;
var cards = utils.usersToCards(users);
gui.renderUserCardList(cards);
var selected = 0;
if(controller.isConnected()){
controller.setExtras({
rumbleLeft: 0, // 0-255 (Rumble left intensity)
rumbleRight: 0, // 0-255 (Rumble right intensity)
red: 0, // 0-255 (Red intensity)
green: 75, // 0-255 (Blue intensity)
blue: 225, // 0-255 (Green intensity)
});
}
gamepad.on("press", "d_pad_right", () => {
if(selected < max){
selected++;
gui.renderSelectedUserCard(selected, selected - 1);
}
});
gamepad.on("press", "d_pad_left", () => {
if (selected > 0){
selected--;
gui.renderSelectedUserCard(selected, selected + 1);
}
});
gamepad.on("press", "stick_axis_left", e => {
if(e.value[0] < -0.3){
if (selected > 0){
selected--;
gui.renderSelectedUserCard(selected, selected + 1);
}
} else if (e.value[0] > 0.3) {
if (selected < max) {
selected++;
gui.renderSelectedUserCard(selected, selected - 1);
}
}
});
gamepad.on("press", "button_1", () => {
gamepad.off("press", "d_pad_left");
gamepad.off("press", "d_pad_right");
gamepad.off("press", "stick_axis_left");
gamepad.off("press", "stick_axis_right");
console.log("Loged in as ", users[selected]);
});
}
module.exports = gamepadConnected;

105
html/views/menu/gui.js Normal file
View file

@ -0,0 +1,105 @@
function showTitle(title) {
var view = document.getElementById("view");
var t = document.createElement("h1");
t.classList.add("title--main");
t.innerText = title;
view.appendChild(t);
}
function showTitleInMiddle(title) {
var view = document.getElementById("view");
var t = document.createElement("h1");
t.classList.add("title--main");
t.classList.add("middle");
t.innerText = title;
view.appendChild(t);
t.style.marginLeft = "-" + (t.offsetWidth / 2) + "px";
}
function showDescription(desc) {
var view = document.getElementById("view");
var t = document.createElement("h2");
t.classList.add("title--description");
t.innerText = desc;
view.appendChild(t);
}
function showDescriptionInMiddle(desc) {
var view = document.getElementById("view");
var t = document.createElement("h2");
t.classList.add("title--description");
t.classList.add("middle");
t.innerText = desc;
view.appendChild(t);
t.style.marginLeft = "-" + (t.offsetWidth / 2) + "px";
t.style.marginTop = (document.querySelector(".title--main").offsetHeight) + "px";
}
global.cards = [];
global.currentCard = -1;
function getCard(card){
var t = document.createElement("div");
var title = document.createElement("span");
title.innerText = card.name;
var image = document.createElement("img");
image.src = card.image;
global.cards[global.cards.length] = card;
t.appendChild(title);
t.appendChild(image);
return t;
}
function renderSelectedUserCard(selected, previous) {
var prev = document.querySelectorAll(".user-cards-list .card")[previous];
prev.classList.remove("selected");
var card = document.querySelectorAll(".user-cards-list .card")[selected];
card.classList.add("selected");
}
function renderUserCardList(cards){
var view = document.getElementById("view");
var list = document.createElement("div");
view.appendChild(list);
list.classList.add("user-cards-list");
cards.forEach((card, i)=>{
var c = document.createElement("div");
c.classList.add("card");
var img = document.createElement("img");
img.src = card.image;
c.appendChild(img);
var text = document.createElement("p");
text.innerText = card.name;
text.classList.add("name");
c.appendChild(text);
list.appendChild(c);
});
renderSelectedUserCard(0,0);
}
function showAction(action, side){
}
module.exports = {
showTitle,
showDescription,
getCard,
renderUserCardList,
showAction,
renderSelectedUserCard,
showTitleInMiddle,
showDescriptionInMiddle
}

View file

@ -0,0 +1,18 @@
const utils = require("../../utils");
const gui = require("./gui");
const Gamepad = require("../../gamepad/gamepad");
const gamepad = new Gamepad;
const connected = require("./connected");
function welcome(){
gui.showTitleInMiddle("Welcome to Console-hub");
gui.showDescriptionInMiddle("Press home button to start");
gamepad.on("press", "vendor", ()=>{
gamepad.off('press', 'vendor');
connected();
});
}
module.exports = welcome;

147
html/views/styles.scss Normal file
View file

@ -0,0 +1,147 @@
/*
* VARS
*/
$unselected: rgb(182,182,182);
$selected: white;
/*
* FONTS
*/
@import url('https://fonts.googleapis.com/css?family=Open+Sans&display=swap');
@font-face {
font-family: 'Gilroy-bold';
src: url('../../dist/fonts/Gilroy-ExtraBold.otf');//online version, if you want offline, put fonts in this folder and change the link here
}
body {
margin: 0;
padding: 0;
background-color: #0e6cc4;
overflow-x:hidden;
overflow-y:hidden;
}
.title--main {
margin: 0;
padding: 0;
position: fixed;
left: 45px;
top: 100px;
font-size: 4rem;
color: white;
font-family: 'Gilroy-bold';
}
.view {
width: 100%;
}
.title--description {
margin: 0;
padding: 0;
position: fixed;
left: 80px;
top: 175px;
font-size: 1.3rem;
color: white;
font-family: 'Open Sans', sans-serif;
}
.title--main.middle, .title--description.middle {
left: 50%;
top: 50%;
}
.user-cards-list {
z-index: 99;
width: 100%;
height: 30vh;
margin-top: 30vh;
display: flex;
.card {
z-index: 99;
margin: 5px;
font-family: 'Open Sans', sans-serif;
width: 30vh;
height: 30vh;
background-size: 30vh 30vh;
font-size: 2rem;
color: white;
border: 5px solid transparent;
.name {
margin-top: -15px;
padding-left: 5px;
font-size: 43px;
}
img {
height: 100%;
width: 100%;
}
p {
margin: 0;
}
}
.card.selected {
// margin-top: -5px;
// margin-left: -5px;
border: 5px solid white;
}
.card:first-child {
margin-left: auto;
}
.card:last-child {
margin-right: auto;
}
}
.box {
z-index: 1;
position: fixed;
top: 0;
transform: rotate(80deg);
left: 0;
}
.wave {
position: fixed;
top: 0;
left: 0;
opacity: .4;
position: absolute;
top: 3%;
left: 10%;
background: #0af;
width: 3000px;
height: 2600px;
margin-left: -150px;
margin-top: -250px;
transform-origin: 50% 48%;
border-radius: 43%;
animation: drift 9000ms infinite linear;
}
.wave.-three {
animation: drift 8500ms infinite linear;
position: fixed;
background-color: #77daff;
}
.wave.-two {
animation: drift 8000ms infinite linear;
opacity: .1;
background: black;
position: fixed;
}
.box:after {
content: '';
display: block;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 11;
transform: translate3d(0, 0, 0);
}
@keyframes drift {
from { transform: rotate(0deg); }
from { transform: rotate(360deg); }
}

36
main.js
View file

@ -1,4 +1,5 @@
const { dialog, Menu, app, BrowserWindow } = require('electron');
require('electron-reload')(__dirname);
var fs = require('fs');
var path = require('path');
var files = require('./files');
@ -27,14 +28,13 @@ function createWindow () {
width: 800,
height: 600,
frame: true,
fullScreen: true,
webPreferences: {
nodeIntegration: true,
nodeIntegrationInWorker: true,
webSecurity: false
nodeIntegrationInWorker: true
}
})
win.setTitle('Console hub (ALPHA) DEV');
win.setProgressBar(1.1);
win.setTitle('Console hub (ALPHA)');
win.setFullScreenable(true);
var template = [{
label: "Application",
@ -47,7 +47,7 @@ function createWindow () {
buttons: ['ok'],
title: 'About app',
message: 'Console hub (ALPHA) dev version.',
detail: 'Nightly developer version, alpha stage. Accounts disabled.\n(c) Daniel Bulant',
detail: 'Nightly developer version, alpha stage. \n(c) Daniel Bulant',
};
dialog.showMessageBox(null, options, (response) => {
@ -124,17 +124,16 @@ function createWindow () {
const menu = Menu.buildFromTemplate(template);
win.setAutoHideMenuBar(true);
Menu.setApplicationMenu(menu);
win.loadFile('html/index.html')
win.webContents.once('dom-ready', () => {
// win.webContents.openDevTools() //debug tools
win.setProgressBar(0);
})
win.loadFile('html/views/index.html')
win.maximize();
win.on('enter-full-screen', () => {
console.log('Entered fullscreen');
win.webContents.send('fullscreen', true);
win.setMenuBarVisibility(false)
})
win.on('enter-full-html-screen', () => {
console.log('Entered html fullscreen');
win.webContents.send('fullscreen', true);
@ -150,9 +149,11 @@ function createWindow () {
win.webContents.send('fullscreen', false);
win.setMenuBarVisibility(true)
})
win.on('closed', () => {
win = null
})
}
app.on('ready', createWindow)
@ -166,13 +167,22 @@ ipcMain.on('get-data', (event, arg) => {
event.reply('wifiQuality', wifiQuality);
}
})
ipcMain.on('set-load', (event, arg) => {
win.setProgressBar(arg);
})
ipcMain.on('fullscreen', (event, arg) => {
console.log('Setting to fullscreen ' + arg);
win.setFullScreen(arg);
})
function sendKeybinding (win, modifiers, keyCode) {
win.webContents.sendInputEvent({ type: 'keyDown', modifiers: modifiers, keyCode: keyCode })
win.webContents.sendInputEvent({ type: 'char', modifiers: modifiers, keyCode: keyCode })
win.webContents.sendInputEvent({ type: 'keyUp', modifiers: modifiers, keyCode: keyCode })
}
ipcMain.on('sendKeys', (event, modifiers, keyCode) => {
console.log('Sending keys: '+keyCode + " with modifiers " + modifiers);
sendKeybinding(win, modifiers, keyCode);
})
ipcMain.on('listFiles', (event, arg) => {
console.log('Listing all files and directories in ' + arg);
dirs = [];

2840
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "console-hub",
"version": "0.1.0",
"version": "0.2.0",
"main": "main.js",
"scripts": {
"start": "electron ."
@ -16,6 +16,8 @@
"electron-packager": "^14.0.0"
},
"dependencies": {
"electron-reload": "^1.5.0",
"node-hid": "^1.0.0",
"node-wifi": "^2.0.5"
}
}