Skip to content
Snippets Groups Projects
Commit 399db2b2 authored by jjlustig's avatar jjlustig
Browse files

Initial commit

parents
Branches
No related tags found
No related merge requests found
{
"directory" : "public/vendor"
}
\ No newline at end of file
public/vendor/
node_modules/
language: node_js
node_js:
- "0.12"
- "iojs"
- "0.10"
script:
- npm install -g bower
- $CI_ACTION
env:
matrix:
- CI_ACTION="gulp lint"
uBoard
# Install
Open your mobile browser by scanning the QRCode or enter the URL, then you are able to control your desktop via browser.
## Features
### Passcode protection
## Setup
Get required packages
```
$ npm install
```
This will run `bower install` and install client side libraries into `public/vendor`
After, run
```
$ node server.js
```
To host the uBoard server on the desktop.
## Code structure
The server uses `server.js` and the `socket.io` to change the mouse position and receive keyboard input
The desktop uses `desktop.html` to display the QR code on the desktop window.
For the client side, a mobile device will receive `index.html` and its attached `client.js`. This allows the User to input the keyboard (top half of screen) or move the mouse (bottom half of screen) and emit a WebSocket signal to the server.
## Build for Desktop
You need install node-webkit-builder first
```
$ npm install nw-builder -g
```
You have to check nw.js website and use same io.js version as nw.js did.
```
$ nvm install iojs-1.2.0
$ nvm use iojs
```
To build a smaller package, we only need install essential libraries for production.
Clone a new repository and run following commands:
```
$ npm install --production
$ nwbuild -p osx64 webbymouse -v 0.12.3
```
NOTE: Your desktop OS must have the needed support for the robotjs library.
{
"name": "uBoard",
"description": "",
"homepage": "",
"keywords": [],
"author": "",
"license": "",
"ignore": [
"**/.*",
"node_modules",
"bower_components"
],
"dependencies": {
"bootstrap-material-design": "^0.3.0",
"jquery": "~2.1.3",
"hammerjs": "~2.0.4",
"l20n": "~1.0.2",
"bootstrap": "~3.3.5",
"jquery-qrcode": "*"
}
}
{
"button1": [
"q",
"0",
"0"
],
"button2": [
"w",
"10",
"0"
],
"button3": [
"e",
"20",
"0"
],
"button4": [
"r",
"30",
"0"
],
"button5": [
"t",
"40",
"0"
],
"button6": [
"y",
"50",
"0"
],
"button7": [
"u",
"60",
"0"
],
"button8": [
"i",
"70",
"0"
],
"button9": [
"o",
"80",
"0"
],
"button10": [
"p",
"90",
"0"
],
"button11": [
"a",
"0",
"30"
],
"button12": [
"s",
"10",
"30"
],
"button13": [
"d",
"20",
"30"
],
"button14": [
"f",
"30",
"30"
],
"button15": [
"g",
"40",
"30"
],
"button16": [
"h",
"50",
"30"
],
"button17": [
"j",
"60",
"30"
],
"button18": [
"k",
"70",
"30"
],
"button19": [
"l",
"80",
"30"
],
"button20": [
"z",
"0",
"60"
],
"button21": [
"x",
"10",
"60"
],
"button22": [
"c",
"20",
"60"
],
"button23": [
"v",
"30",
"60"
],
"button24": [
"b",
"40",
"60"
],
"button25": [
"n",
"50",
"60"
],
"button26": [
"m",
"60",
"60"
],
"button0": [
" ",
"70",
"60"
]
}
\ No newline at end of file
{
"button1": [
"q",
"0",
"0"
],
"button2": [
"w",
"10",
"0"
],
"button3": [
"e",
"20",
"0"
],
"button4": [
"r",
"30",
"0"
],
"button5": [
"t",
"40",
"0"
],
"button6": [
"y",
"50",
"0"
],
"button7": [
"u",
"60",
"0"
],
"button8": [
"i",
"70",
"0"
],
"button9": [
"o",
"80",
"0"
],
"button10": [
"p",
"90",
"0"
],
"button11": [
"a",
"0",
"30"
],
"button12": [
"s",
"10",
"30"
],
"button13": [
"d",
"20",
"30"
],
"button14": [
"f",
"30",
"30"
],
"button15": [
"g",
"40",
"30"
],
"button16": [
"h",
"50",
"30"
],
"button17": [
"j",
"60",
"30"
],
"button18": [
"k",
"70",
"30"
],
"button19": [
"l",
"80",
"30"
],
"button20": [
"z",
"0",
"60"
],
"button21": [
"x",
"10",
"60"
],
"button22": [
"c",
"20",
"60"
],
"button23": [
"v",
"30",
"60"
],
"button24": [
"b",
"40",
"60"
],
"button25": [
"n",
"50",
"60"
],
"button26": [
"m",
"60",
"60"
],
"button0": [
" ",
"70",
"60"
]
}
\ No newline at end of file
<DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>UBoard</title>
<link rel="stylesheet" href="public/vendor/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="public/vendor/bootstrap-material-design/dist/css/ripples.min.css">
<link rel="stylesheet" href="public/vendor/bootstrap-material-design/dist/css/material.min.css">
<link rel="stylesheet" href="public/style/main.css">
</head>
<body fullbleed unresolved class="hidden">
<header class="navbar navbar-inverse navbar-fixed-top shadow-z-2" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle pull-left" data-toggle="collapse" data-target="#pushMenu">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#" data-l10n-id="projectName">UBoard</a>
</div>
<div class="collapse navbar-collapse" id="pushMenu">
<ul class="nav navbar-nav">
<li><a href="#" id="passcode"><i class="mdi-notification-vpn-lock"></i> Pass Code</a></li>
</ul>
</div>
</header>
<section id="content" class="well">
<!-- Add your site or application content here -->
<h3 data-l10n-id="hello">Open Mobile browser with</h3>
<p id="desc" data-l10n-id="info_static"></p>
<div id="qrcode"></div>
</section>
<!-- external libraries -->
<script defer src="public/vendor/jquery/dist/jquery.min.js"></script>
<script defer src="public/vendor/jquery-qrcode/jquery.qrcode.min.js"></script>
<script defer src="public/vendor/bootstrap/dist/js/bootstrap.min.js"></script>
<script defer src="public/vendor/bootstrap-material-design/dist/js/ripples.min.js"></script>
<script defer src="public/vendor/bootstrap-material-design/dist/js/material.min.js"></script>
<script defer src="public/js/main.js"></script>
<script defer src="public/js/desktop.js"></script>
</body>
</html>
0 info it worked if it ends with ok
1 verbose cli [ '/Users/Joshua/.nvm/versions/io.js/v3.3.1/bin/iojs',
1 verbose cli '/Users/Joshua/.nvm/versions/io.js/v3.3.1/bin/npm',
1 verbose cli 'install' ]
2 info using npm@2.14.3
3 info using node@v3.3.1
4 verbose readDependencies loading dependencies from /Users/Joshua/Documents/Michigan Classes/EECS/EECS498/UBoard/project/package.json
5 error install Couldn't read dependencies
6 verbose stack Error: Invalid version: "1.0"
6 verbose stack at Object.module.exports.fixVersionField (/Users/Joshua/.nvm/versions/io.js/v3.3.1/lib/node_modules/npm/node_modules/normalize-package-data/lib/fixer.js:186:13)
6 verbose stack at /Users/Joshua/.nvm/versions/io.js/v3.3.1/lib/node_modules/npm/node_modules/normalize-package-data/lib/normalize.js:32:38
6 verbose stack at Array.forEach (native)
6 verbose stack at normalize (/Users/Joshua/.nvm/versions/io.js/v3.3.1/lib/node_modules/npm/node_modules/normalize-package-data/lib/normalize.js:31:15)
6 verbose stack at final (/Users/Joshua/.nvm/versions/io.js/v3.3.1/lib/node_modules/npm/node_modules/read-package-json/read-json.js:338:5)
6 verbose stack at then (/Users/Joshua/.nvm/versions/io.js/v3.3.1/lib/node_modules/npm/node_modules/read-package-json/read-json.js:113:5)
6 verbose stack at /Users/Joshua/.nvm/versions/io.js/v3.3.1/lib/node_modules/npm/node_modules/read-package-json/read-json.js:300:12
6 verbose stack at FSReqWrap.readFileAfterClose [as oncomplete] (evalmachine.<anonymous>:380:3)
7 verbose cwd /Users/Joshua/Documents/Michigan Classes/EECS/EECS498/UBoard/project
8 error Darwin 16.0.0
9 error argv "/Users/Joshua/.nvm/versions/io.js/v3.3.1/bin/iojs" "/Users/Joshua/.nvm/versions/io.js/v3.3.1/bin/npm" "install"
10 error node v3.3.1
11 error npm v2.14.3
12 error Invalid version: "1.0"
13 error If you need help, you may report this error at:
13 error <https://github.com/npm/npm/issues>
14 verbose exit [ 1, true ]
This diff is collapsed.
{
"name":"uBoard",
"version": "1.0",
"main": "desktop.html",
"window": {
"show": true,
"toolbar": false,
"frame": true,
"position": "center",
"width": 480,
"height": 320,
"min_width": 480,
"min_height": 320,
"resizable": false,
"kiosk": false
},
"chromium-args": "--child-clean-exit",
"dependencies": {
"express": "^4.13.3",
"openurl": "^1.1.1",
"robotjs": "^0.4.7",
"socket.io": "^1.3.6"
},
"scripts": {
"start": "node server.js",
"postinstall": "bower install"
}
}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="public/vendor/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="public/vendor/bootstrap-material-design/dist/css/ripples.min.css">
<link rel="stylesheet" href="public/vendor/bootstrap-material-design/dist/css/material.min.css">
<link rel="stylesheet" href="public/style/main.css">
<link rel="stylesheet" href="public/style/gradient.css">
<title>UBoard</title>
</head>
<body>
<header class="navbar navbar-inverse navbar-fixed-top shadow-z-2" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle pull-left" data-toggle="collapse" data-target="#pushMenu">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#" data-l10n-id="projectName">uBoard</a>
</div>
<div class="collapse navbar-collapse" id="pushMenu">
<ul class="nav navbar-nav">
<!--<li>
<div class="togglebutton">
<label class="navbar-item">
<input type="checkbox" name="checkbox" id="fullscreen-toggle" autocomplete="off"></input>
Touchpad <span class="toggle pull-right"></span>
</label>
</div>
</li>-->
<li>
<div class="togglebutton">
<label class="navbar-item">
<input type="checkbox" name="checkbox" id="move-toggle" autocomplete="off"></input>
Move Buttons <span class="toggle pull-right"></span>
</label>
</div>
</li>
<li class="hidden" id="portrait">
<a href="#">
<i class="mdi-communication-stay-current-portrait"></i> Portrait
</a>
</li>
<li class="hidden" id="landscape">
<a href="#">
<i class="mdi-communication-stay-current-landscape"></i> Landscape
</a>
</li>
<li class="divider"></li>
<li><a href="#" id="passcode"><i class="mdi-notification-vpn-lock"></i> Pass Code</a></li>
<li class="divider"></li>
</ul>
</div>
</header>
<div class="wrapper">
<div class = "keyboard" id="keyboard">
</div>
<div class="touchpad" id="touchpad">
</div>
</div>
<!-- The Modal -->
<div id="myModal" class="modal">
<!-- Modal content -->
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">Change Input</h4>
</div>
<div id="modal-body">
<p><input type="text" id="inputText" value=""></p>
</div>
<div id="modal-save">
<button type="button" class="btn btn-default" data-dismiss="modal">Save</button>
</div>
<div id="modal-close">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
<script defer src="/public/vendor/jquery/dist/jquery.min.js"></script>
<script defer src="/public/vendor/bootstrap/dist/js/bootstrap.min.js"></script>
<script defer src="/public/vendor/bootstrap-material-design/dist/js/ripples.min.js"></script>
<script defer src="/public/vendor/bootstrap-material-design/dist/js/material.min.js"></script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/interact.js/1.2.8/interact.min.js"></script>
<script defer src="/socket.io/socket.io.js"></script>
<script defer src="/public/vendor/hammerjs/hammer.min.js"></script>
<script defer src="/public/style/style.js"></script>
<script defer src="/public/js/client.js"></script>
</body>
</html>
/* jshint node: true */
/* global io, Hammer, $ */
'use strict';
//-----GLOBAL STATE VARIABLES-----//
var socket = io();
var move = false; //Toggles moving functionality
var updateKey; // Modal overlay
var modal = document.getElementById('myModal');// Modal textbox
var inputModal = document.getElementById('inputText');
var keyboardWidth = document.getElementById('keyboard').offsetWidth;// Width pixel of display
var keyboardHeight = document.getElementById('keyboard').offsetHeight;// Height pixel of
$("#touchpad").hide();
/*
-----------KEYBOARD CONTROLS---------------
The Following Functions Control the KEYBOARD FUNCTIONALITY
*/
//Purpose: Receives information from the server to update the presentation of the keys on the client
socket.on('updateKeys', function(newVals) {
console.log(newVals);
for (var i = 0; i < newVals.x.length; i++){
var ele = $('#button' + (i+1).toString())
ele.text(newVals.k[i])
ele.css({position:'absolute', left:newVals.x[i] + '%', top:(newVals.y[i]) + '%'});
}
});
//Purpose: Emits the key of keyboard upon click
var emitKey = function(str) {
if (move === false){
socket.emit('string', str);
console.log(str);
}
};
//Purpose: Uses interact.js library to enable keys to move around
interact('.draggable').draggable({
snap: {
targets: [
interact.createSnapGrid({ x: .05*keyboardWidth, y: .1*keyboardHeight })
],
range: Infinity
},
inertia: true, // enable inertial throwing
restrict: {
restriction: "parent", // keep the element within the area of it's parent
endOnly: true,
elementRect: { top: 0, left: 0, bottom: 1, right: 1 }
},
autoScroll: true, // enable autoScroll
onmove: dragMoveListener, // call this function on every dragmove event
onend: function (event) { // call this function on every dragend event
}
});
function dragMoveListener (event) {
if (move === true){
var target = event.target,
// keep the dragged position in the data-x/data-y attributes
x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
// translate the element
target.style.webkitTransform =
target.style.transform =
'translate(' + x + 'px, ' + y + 'px)';
// update the posiion attributes
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
}
}
//Purpose: Event listener on tapping the keys
interact('.draggable').on('tap', function (event) {
emitKey(event.target.innerText);
}).on('hold', function (event) {
if (move == true){
modal.style.display = "block"; //Allows the modal to be displayed to User
updateKey = event.target
inputModal.value = updateKey.innerText
}
});
//Purpose: Updates button with textbox value
$('#modal-save').click(function() {
var newX = parseInt(updateKey.style.left) + updateKey.getAttribute('data-x')/keyboardWidth*100
var newY = parseInt(updateKey.style.top) + updateKey.getAttribute('data-y')/keyboardHeight*100
newX = Math.min(Math.max(0, newX),100).toString()
newY = Math.min(Math.max(0, newY),100).toString()
console.log(newX, newY)
updateKey.innerText = inputModal.value;
socket.emit('saveKey', {
id: updateKey.id,
val: updateKey.innerText,
x: newX,
y: newY });
});
//Purpose: Closes modal when the user clicks on <span> (x)
$('#modal-close').click(function() {
modal.style.display = "none";
});
//Purpose: Used for resizing and gestures
window.dragMoveListener = dragMoveListener;
/*
-----------MOUSE CONTROLS---------------
The Following Functions Control the Mouse
*/
var touchElem = document.getElementById('touchpad');
var delta = null;
var moving = false;
var control = 'touch';
var passcode = '';
var pos = {x: 0, y: 0, cmd: null, pw: ''};
//Purpose: Wrapper Function to send information from client to server via socket
var emitMouse = function(x, y, cmd) {
pos.x = x;
pos.y = y;
pos.cmd = cmd;
pos.pw = passcode;
socket.emit('mouse', pos);
};
//Purpose: Handles touch movement events from the clients
var handlePan = function(eventName, e) {
if (e.type == eventName + 'start') {
delta = null;
moving = true;
console.log('start ' + eventName);
emitMouse(0, 0, eventName + 'start');
}
if (e.type == eventName + 'end') {
delta = null;
moving = false;
emitMouse(0, 0, eventName + 'end');
}
if (moving && delta != null) {
emitMouse(e.deltaX - delta.x, e.deltaY - delta.y, eventName);
}
delta = {x: e.deltaX, y: e.deltaY};
};
//Purpose: Using Hammer.js library to add different touching functionality
var mc = new Hammer.Manager(touchElem);
mc.add(new Hammer.Pan({event: 'move', threshold: 0, pointers: 1, direction: Hammer.DIRECTION_ALL}));
mc.add(new Hammer.Pan({event: 'scroll', threshold: 0, pointers: 2,direction: Hammer.DIRECTION_ALL}));
mc.add(new Hammer.Pan({event: 'drag', threshold: 0, pointers: 3, direction: Hammer.DIRECTION_ALL}));
//Purpose: Tapping functionality
var singleTap = new Hammer.Tap({event: 'click', pointers: 1});
var doubleTap = new Hammer.Tap({event: 'doubleclick', pointers: 1, taps: 2});
var tripleTap = new Hammer.Tap({event: 'tripleclick', pointers: 1, taps: 3});
mc.add([tripleTap, doubleTap, singleTap]);
tripleTap.recognizeWith([doubleTap, singleTap]);
doubleTap.recognizeWith(singleTap);
doubleTap.requireFailure(tripleTap);
singleTap.requireFailure([tripleTap, doubleTap]);
mc.add(new Hammer.Tap({event: 'rightclick', pointers: 2}));
//Purpose: Using Hammer.js event listeners to trigger functionality by sending data to
mc.on('movestart moveend moveup movedown moveleft moveright', function(e) {
handlePan('move', e);
});
mc.on('scrollstart scrollend scrollup scrolldown scrollleft scrollright',
function(e) {
handlePan('scroll', e);
});
mc.on('dragstart dragend dragup dragdown dragleft dragright', function(e) {
handlePan('drag', e);
});
mc.on('click', function(e) {
console.log('click');
emitMouse(0, 0, 'click');
});
mc.on('rightclick', function(e) {
console.info('rightclick');
emitMouse(0, 0, 'rightclick');
});
mc.on('doubleclick', function(e) {
console.log('doubleclick');
emitMouse(0, 0, 'doubleclick');
});
/*
-----------MENU CONTROLS---------------
The Following Functions Control the Main Menu
*/
document.body.requestFullscreen = document.body.requestFullScreen ||
document.body.webkitRequestFullScreen ||
document.body.mozRequestFullScreen ||
document.body.msRequestFullScreen;
document.cancelFullscreen = document.exitFullscreen ||
document.webkitExitFullscreen ||
document.mozCancelFullScreen ||
document.msExitFullscreen;
//PURPOSE: Toggle movement functionality
$('#fullscreen-toggle').click(function() {
if (this.checked) {
$('.draggable').hide();
$('#keyboard').hide();
$("#touchpad").show();
//document.body.requestFullscreen();
} else {
$('.draggable').show();
$('#keyboard').show();
$("#touchpad").hide();
//document.cancelFullscreen();
}
});
//PURPOSE: Toggle movement functionality
$('#move-toggle').click(function() {
if (this.checked) {
move = true;
} else {
move = false;
}
});
//PURPOSE: If password is set, asks user for password
$('#passcode').click(function() {
passcode = prompt('Enter a passcode');
});
//PURPOSE: About the project
$('#about').click(function() {
if (confirm('UBoard: A mobile mouse for Brad')) {
open('https://github.com/jjlustig/EECS498_uBoard');
}
});
{
passcode: ''
}
/* jshint node: true */
/* global $ */
'use strict';
$(document).ready(function() {
// require('./server.js');
// var gui = require('nw.gui');
var os = require('os');
// var config = require('./public/js/config.js');
// var desc = document.getElementById('desc');
// var pw = document.getElementById('passcode');
// show ip address
var ifaces = os.networkInterfaces();
var PORT = 8000;
var url = '';
Object.keys(ifaces).forEach(function(ifname) {
var alias = 0;
ifaces[ifname].forEach(function(iface) {
if ('IPv4' !== iface.family || iface.internal !== false) {
// skip over internal (i.e. 127.0.0.1) and non-ipv4 addresses
return;
}
if (alias >= 1) {
// this single interface has multiple ipv4 addresses
// console.log('ifname + ':' + alias, iface.address);
url = 'http://' + iface.address + ':' + PORT;
//desc.innerHTML = url;
} else {
// this interface has only one ipv4 adress
url = 'http://' + iface.address + ':' + PORT;
//desc.innerHTML = url;
}
alias++;
});
});
console.log(url);
// show QRCode
console.log('listening on ' + url);
$('#qrcode').qrcode({width: 128, height: 128, text: url});
// Reference to window and tray
var win = gui.Window.get();
var tray;
// Get the minimize event
win.on('minimize', function() {
// Hide window
this.hide();
});
// Show tray
tray = new gui.Tray({
tooltip: 'UBoard'
});
var menu = new gui.Menu();
menu.append(new gui.MenuItem({
label: 'About UBoard',
click: function() {
if (confirm('UBoard: A mobile mouse for Brad')) {
gui.Shell.openExternal('https://github.com/jjlustig/EECS498_uBoard');
}
}
}));
menu.append(new gui.MenuItem({type: 'separator'}));
menu.append(new gui.MenuItem({
label: 'Show',
click: function() {
win.show();
}
}));
menu.append(new gui.MenuItem({type: 'separator'}));
menu.append(new gui.MenuItem({
label: 'Close',
click: function() {
win.close();
}
}));
tray.menu = menu;
pw.addEventListener('click', function() {
config.passcode = prompt('Enter a passcode');
});
});
/* global $ */
/**
* Main entry point.
*
* the DOM has been localized and the user sees it in their language.
*
* @class Main
*/
(function() {
'use strict';
// document.addEventListener('DocumentLocalized', function() { // l20n ready
document.body.classList.remove('hidden');
$.material.ripples();
// document.addEventListener('deviceready',
// this.onDeviceReady, false); // cordova ready
// });
}());
\ No newline at end of file
@charset "UTF-8";
/*!
*
* bttn.css - https://ganapativs.github.io/bttn.css
* Version - 0.2.4
* Demo: https://bttn.surge.sh
*
* Licensed under the MIT license - http://opensource.org/licenses/MIT
*
* Copyright (c) 2016 Ganapati V S (@ganapativs)
*
*/
/* standalone - .bttn-gradient */
.bttn-default {
color: #fff;
}
.bttn-primary,
.bttn,
.bttn-lg,
.bttn-md,
.bttn-sm,
.bttn-xs {
color: #1d89ff;
}
.bttn-warning {
color: #feab3a;
}
.bttn-danger {
color: #ff5964;
}
.bttn-success {
color: #28b78d;
}
.bttn-royal {
color: #bd2df5;
}
.bttn,
.bttn-lg,
.bttn-md,
.bttn-sm,
.bttn-xs {
margin: 0;
padding: 0;
border-width: 0;
border-color: transparent;
background: transparent;
font-weight: 400;
cursor: pointer;
position: relative;
}
.bttn-lg {
padding: 8px 15px;
font-size: 24px;
font-family: inherit;
}
.bttn-md {
font-size: 20px;
font-family: inherit;
padding: 5px 12px;
}
.bttn-sm {
padding: 4px 10px;
font-size: 16px;
font-family: inherit;
}
.bttn-xs {
padding: 3px 8px;
font-size: 12px;
font-family: inherit;
}
.bttn-simple,
.bttn-gradient {
margin: 0;
padding: 0;
border-width: 0;
border-color: transparent;
background: transparent;
font-weight: 400;
cursor: pointer;
position: relative;
font-size: 20px;
font-family: inherit;
padding: 5px 12px;
overflow: hidden;
border-width: 0;
border-radius: 4px;
background: rgba(255,255,255,0.4);
color: #fff;
-webkit-transition: all 0.3s cubic-bezier(0.02, 0.01, 0.47, 1);
transition: all 0.3s cubic-bezier(0.02, 0.01, 0.47, 1);
}
.bttn-simple:hover,
.bttn-gradient:hover,
.bttn-simple:focus,
.bttn-gradient:focus {
opacity: 0.75;
}
.bttn-simple.bttn-xs,
.bttn-gradient.bttn-xs {
padding: 3px 8px;
font-size: 12px;
font-family: inherit;
}
.bttn-simple.bttn-sm,
.bttn-gradient.bttn-sm {
padding: 4px 10px;
font-size: 16px;
font-family: inherit;
}
.bttn-simple.bttn-md,
.bttn-gradient.bttn-md {
font-size: 20px;
font-family: inherit;
padding: 5px 12px;
}
.bttn-simple.bttn-lg,
.bttn-gradient.bttn-lg {
padding: 8px 15px;
font-size: 24px;
font-family: inherit;
}
.bttn-simple.bttn-default,
.bttn-gradient.bttn-default {
background: rgba(255,255,255,0.4);
}
.bttn-simple.bttn-primary,
.bttn-gradient.bttn-primary {
background: #1d89ff;
}
.bttn-simple.bttn-warning,
.bttn-gradient.bttn-warning {
background: #feab3a;
}
.bttn-simple.bttn-danger,
.bttn-gradient.bttn-danger {
background: #ff5964;
}
.bttn-simple.bttn-success,
.bttn-gradient.bttn-success {
background: #28b78d;
}
.bttn-simple.bttn-royal,
.bttn-gradient.bttn-royal {
background: #bd2df5;
}
.bttn-gradient {
border-radius: 100px;
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(1, #d6e3ff));
background-image: -webkit-linear-gradient(top, #fff 0%, #d6e3ff 100%);
background-image: linear-gradient(to bottom, #fff 0%, #d6e3ff 100%);
background-image: -webkit-linear-gradient(93deg, #d6e3ff 0%, #fff 100%);
box-shadow: 0 1px 2px rgba(0,0,0,0.25);
color: #1d89ff;
text-shadow: 0 1px 0 rgba(255,255,255,0.25);
}
.bttn-gradient.bttn-default {
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(1, #d6e3ff));
background-image: -webkit-linear-gradient(top, #fff 0%, #d6e3ff 100%);
background-image: linear-gradient(to bottom, #fff 0%, #d6e3ff 100%);
background-image: -webkit-linear-gradient(93deg, #d6e3ff 0%, #fff 100%);
color: #1d89ff;
}
.bttn-gradient.bttn-primary {
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #00bbd4), color-stop(1, #3f51b5));
background-image: -webkit-linear-gradient(top, #00bbd4 0%, #3f51b5 100%);
background-image: linear-gradient(to bottom, #00bbd4 0%, #3f51b5 100%);
background-image: -webkit-linear-gradient(93deg, #3f51b5 0%, #00bbd4 100%);
color: #fff;
}
.bttn-gradient.bttn-warning {
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #feab3a), color-stop(1, #f35626));
background-image: -webkit-linear-gradient(top, #feab3a 0%, #f35626 100%);
background-image: linear-gradient(to bottom, #feab3a 0%, #f35626 100%);
background-image: -webkit-linear-gradient(93deg, #f35626 0%, #feab3a 100%);
color: #fff;
}
.bttn-gradient.bttn-danger {
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #ff97c2), color-stop(1, #e91e63));
background-image: -webkit-linear-gradient(top, #ff97c2 0%, #e91e63 100%);
background-image: linear-gradient(to bottom, #ff97c2 0%, #e91e63 100%);
background-image: -webkit-linear-gradient(93deg, #e91e63 0%, #ff97c2 100%);
color: #fff;
}
.bttn-gradient.bttn-success {
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #9ccc65), color-stop(1, #009688));
background-image: -webkit-linear-gradient(top, #9ccc65 0%, #009688 100%);
background-image: linear-gradient(to bottom, #9ccc65 0%, #009688 100%);
background-image: -webkit-linear-gradient(93deg, #009688 0%, #9ccc65 100%);
color: #fff;
}
.bttn-gradient.bttn-royal {
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #9c27b0), color-stop(1, #512da8));
background-image: -webkit-linear-gradient(top, #9c27b0 0%, #512da8 100%);
background-image: linear-gradient(to bottom, #9c27b0 0%, #512da8 100%);
background-image: -webkit-linear-gradient(93deg, #512da8 0%, #9c27b0 100%);
color: #fff;
}
mark {
background-color: #ff9;
color: #000;
font-style: normal;
font-weight: bold;
}
.hidden {
display: none;
}
body {
padding-top: 50px;
}
@media screen and (max-width: 768px) {
body {
padding-top: 50px;
}
}
.draggable {
/*Button Positioning and Size*/
width: 2%;
height: 2%;
min-height: 20%;
margin: 1%;
margin-top: 3%;
border-radius: 2em;
padding: 4%;
/*Button Coloring*/
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #00bbd4), color-stop(1, #3f51b5));
background-image: -webkit-linear-gradient(top, #00bbd4 0%, #3f51b5 100%);
background-image: linear-gradient(to bottom, #00bbd4 0%, #3f51b5 100%);
background-image: -webkit-linear-gradient(93deg, #3f51b5 0%, #00bbd4 100%);
color: #fff;
/*Text display options*/
display:table-cell;
vertical-align:middle;
/*Stops Browser Action for Chrome and Safari*/
touch-action: none;
-webkit-user-select: none;
-webkit-transform: translate(0px, 0px);
transform: translate(0px, 0px);
}
#drag-me::before {
content: "#" attr(id);
font-weight: bold;
}
#keyboard{
height: 60%;
background-color: white;
position: relative;
}
#touchpad{
flex: 1 1 0px;
background-color: grey;
}
.wrapper{
display: flex;
flex-direction: column;
height: calc(100% - 50px);
width: 100%;
position: fixed;
}
.navbar-item {
display: block;
padding: 5px 5px;
clear: both;
font-weight: 400;
}
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
padding-top: 100px; /* Location of the box */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.6); /* Black w/ opacity */
color: white;
}
/* Modal Content */
.modal-content {
background-color: #fefefe;
margin: auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
}
#inputText {
color: black;
}
#modal-save {
display: inline-block;
background-color: green;
}
#modal-close {
display: inline-block;
background-color: red;
}
//KEYBOARD CODE
//Adds keyboard elements dynamically
document.body.onload = addKeyboard;
function addKeyboard () {
var keys = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
for (var i = 0; i < keys.length; i++) {
// create a new div element
var newDiv = document.createElement("button");
// give class name
newDiv.className = 'draggable';
newDiv.id = "button" + (i+1).toString()
// and give it some content
var key = document.createTextNode(keys[i]);
// add the text node to the newly created div
newDiv.appendChild(key);
// add the newly created element and its content into the DOM
var keyboard = document.getElementById("keyboard");
keyboard.appendChild(newDiv);
//document.body.insertBefore(newDiv, currentDiv);
}
};
$(window).on("load", function() {
$('.draggable').click(function() {
console.log("test");
if (move === false){
var str = this.html();
console.log(str);
}
});
});
\ No newline at end of file
server.js 0 → 100755
'use strict';
//-------External Libraries----------//
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var robot = require('robotjs');
var config = require('./public/js/config.js');
var url = require("openurl");
var fs = require("fs");
//---------GLOBAL STATE VARIABLES ----//
var screenWidth = 1440;
var screenHeight = 900;
var adjustment = 2;
var mouse = null;
var newX = null;
var newY = null;
// Get screen size from NW desktop
try {
var gui = window.require('nw.gui');
gui.Screen.Init();
var screens = gui.Screen.screens;
// XXX: currently only take first screen
var rect = screens[0].bounds;
screenWidth = rect.width;
screenHeight = rect.height;
} catch (e) {
console.log(e);
}
//-------WEB SERVER FUNCTIONALITY -------//
//Purpose: Sends client information when making http request to main entrypoint
app.get('/', function(req, res) {
res.sendFile(__dirname + '/public/client.html');
});
//Purpose: use the public directory to send information
app.use('/public', express.static('public'));
//Purpose: Lets the webserver listen for requests on port 8000
var PORT = 8000;
http.listen(PORT, function() {
console.log('listening on *:' + PORT);
});
//-------MOBILE MOUSE FUNCTIONALITY -------//
//General Connection Configuration
io.on('connection', function(socket) {
socket.broadcast.emit('hi');
console.log('a user connected');
socket.on('disconnect', function() {
console.log('user disconnected');
});
var keys = []
var xpos = []
var ypos = []
var file = fs.readFileSync("configuration.json")
var content = JSON.parse(file)
for (var key in content) {
keys.push(content[key][0]);
xpos.push(content[key][1]);
ypos.push(content[key][2]);
}
//Keyboard Functionality
socket.emit('updateKeys', {k: keys, x: xpos, y: ypos});
socket.on('string', function(str) {
console.log("Trying to type")
robot.typeString(str)
});
socket.on('saveKey', function(key) {
var file = fs.readFileSync("configuration.json")
var configuration = JSON.parse(file)
configuration[key.id] = [key.val, key.x, key.y];
fs.writeFile("./configuration.json", JSON.stringify(configuration, null, 4), 'utf8', error=>{});
});
socket.on('url', function(str) {
console.log("Trying to open url")
url.open(str)
});
//Mouse Functionality
socket.on('mouse', function(pos) {
if (pos.pw) {
if (config.passcode !== pos.pw) { //Password Checker
return;
}
}
if (pos.cmd == 'move') {
mouse = robot.getMousePos(); //Get mouse state
newX = mouse.x + pos.x * adjustment;
newY = mouse.y + pos.y * adjustment;
robot.moveMouse(newX, newY);
mouse = robot.getMousePos(); //Update mouse state
}
else if (pos.cmd == 'scroll'){
mouse = robot.getMousePos(); //Get mouse state
robot.scrollMouse(pos.x*5, pos.y*5);
mouse = robot.getMousePos(); //Update mouse state
}
else if (pos.cmd == 'drag') {
mouse = robot.getMousePos(); //Get mouse state
newX = mouse.x + pos.x * adjustment;
newY = mouse.y + pos.y * adjustment;
robot.dragMouse(newX, newY);
mouse = robot.getMousePos(); //Update mouse state
}
else if (pos.cmd == 'click') {
robot.mouseClick();
} else if (pos.cmd == 'rightclick') {
robot.mouseClick('right');
} else if (pos.cmd == 'scrollstart') {
//robot.mouseToggle('down', 'middle');
} else if (pos.cmd == 'scrollend') {
//robot.mouseToggle('up', 'middle');
} else if (pos.cmd == 'dragstart') {
robot.mouseToggle('down', 'left');
} else if (pos.cmd == 'dragend') {
robot.mouseToggle('up', 'left');
} else if (pos.cmd == 'right') {
robot.keyTap("right");
} else if (pos.cmd == 'left') {
robot.keyTap("left");
} else if (pos.cmd == 'doubleclick') {
robot.mouseClick("left",true);
}
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment