initial push...

This commit is contained in:
Maxim Stewart 2020-05-28 13:07:53 -05:00
parent d82d880a17
commit 938aaca361
42 changed files with 1208 additions and 0 deletions

41
README.md Normal file
View File

@ -0,0 +1,41 @@
# Dropper
Remote Mouse is a flask + pyautogui app to control a PC from your phone or any other device.
# Notes
* Need python 2+
* Make sure to change the port in the start script as needed. Have fun!
* For Linux you will need to do sudo -i before running the script.
# Setup
*** Change directory to Remote-Mouse/ or rename the folder before doing so.
``` python3 -m venv venv/ ```
Linux/Mac
``` source bin/activate ```
Windows
``` source bin/Scripts/activate ```
Linux/Mac
``` pip install -r linux-requirements.txt ```
Windows
``` pip install -r windows-requirements.txt ```
``` cd src/ ```
Linux/Mac
``` ./linux-start.sh ```
Windows
``` ./windows-start.sh ```
# Images
![1 Interface.... ](images/pic1.png)
# TODO
* Improve mouse translation and speed stepping...
* Cleanup code/logic.

BIN
images/pic1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

28
linux-requirements.txt Normal file
View File

@ -0,0 +1,28 @@
bcrypt==3.1.7
cffi==1.14.0
Click==7.0
Flask==1.1.1
Flask-Bcrypt==0.7.1
Flask-Login==0.5.0
Flask-SQLAlchemy==2.4.1
Flask-WTF==0.14.3
gunicorn==19.9.0
itsdangerous==1.1.0
Jinja2==2.10.3
MarkupSafe==1.1.1
MouseInfo==0.1.3
Pillow==7.1.2
pkg-resources==0.0.0
PyAutoGUI==0.9.50
pycparser==2.20
PyGetWindow==0.0.8
PyMsgBox==1.0.8
pyperclip==1.8.0
PyRect==0.1.4
PyScreeze==0.1.26
python3-xlib==0.15
PyTweening==1.0.3
six==1.14.0
SQLAlchemy==1.3.11
Werkzeug==0.16.0
WTForms==2.2.1

View File

@ -0,0 +1,14 @@
# Gtk imports
# Python imports
# Application imports
class MessageHandler:
def __init__(self):
print("MessageHandler initialized...")
def createMessageJSON(self, type, text):
return '{"message": { "type": "' + type + '", "text": "' + text + '" } }'

31
src/core/__init__.py Normal file
View File

@ -0,0 +1,31 @@
# Python imports
import secrets
# Lib imports
from flask import Flask
from flask_bcrypt import Bcrypt
from flask_login import current_user, login_user, logout_user, LoginManager
# Apoplication imports
# Configs and 'init'
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///static/db/database.db"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['TITLE'] = 'RemoteMouse'
# For csrf and some other stuff...
app.config['SECRET_KEY'] = secrets.token_hex(32)
login_manager = LoginManager(app)
bcrypt = Bcrypt(app)
from core.models import db, User
db.init_app(app)
from core.forms import RegisterForm, LoginForm
from core import routes

25
src/core/forms.py Normal file
View File

@ -0,0 +1,25 @@
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
from core import User
class RegisterForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=4, max=24)])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired(), Length(min=8)])
confirm_password = PasswordField('Confirm Password',
validators=[DataRequired(), EqualTo('password', message="Passwords must match!")])
submit = SubmitField("Sign Up")
def validate_username(self, username):
user = User.query.filter_by(username=username.data).first()
if user:
raise ValidationError("User exists already! Please use a different name!")
class LoginForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=4, max=24)])
password = PasswordField('Password', validators=[DataRequired(), Length(min=8, max=32)])
submit = SubmitField("Login")

20
src/core/models.py Normal file
View File

@ -0,0 +1,20 @@
from flask_sqlalchemy import SQLAlchemy
from core import app, login_manager
from flask_login import UserMixin
db = SQLAlchemy(app)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model, UserMixin):
username = db.Column(db.String, unique=True, nullable=False)
email = db.Column(db.String, nullable=False)
password = db.Column(db.String, nullable=False)
id = db.Column(db.Integer, primary_key=True, unique=True, autoincrement=True)
def __repr__(self):
return f"['{self.username}', '{self.email}', '{self.password}', '{self.id}']"

85
src/core/routes/Routes.py Normal file
View File

@ -0,0 +1,85 @@
# Python imports
# Lib imports
import pyautogui
from flask import request, render_template
# App imports
from core import app, db # Get from __init__
from core.MessageHandler import MessageHandler # Get simple message processor
msgHandler = MessageHandler()
TITLE = app.config['TITLE']
pyautogui.FAILSAFE = False # If we hit corner, that's ok
pyautogui.MINIMUM_DURATION = 0.5
@app.route('/', methods=['GET', 'POST'])
def home():
if request.method == 'GET':
return render_template('index.html',
title=TITLE)
return render_template('error.html',
title='Error!',
message='Must use GET request type...')
@app.route('/single-click', methods=['GET', 'POST'])
def singleClick():
pyautogui.click()
return ""
@app.route('/double-click', methods=['GET', 'POST'])
def doubleClick():
pyautogui.doubleClick()
return ""
@app.route('/get-coords', methods=['GET', 'POST'])
def getCoords():
x, y = pyautogui.position();
return '{"x": "'+ str(x) +'", "y":"' + str(y) + '"}'
@app.route('/update-coords', methods=['GET', 'POST'])
def updateCoords():
if request.method == 'POST':
try:
x = float( str(request.values['x']).strip() )
y = float( str(request.values['y']).strip() )
# print("\nX: {} Y: {}".format(str(x), str(y)))
pyautogui.moveRel(x, y);
except Exception as e:
print( repr(e) )
return render_template('error.html',
title='Error!',
message='X or Y is not an integer...')
return render_template('error.html',
title='Error!',
message='Must use POST request type...')
@app.route('/send-key', methods=['GET', 'POST'])
def sendKey():
pyautogui.doubleClick()
if request.method == 'POST':
try:
text = str(request.values['text']).strip()
pyautogui.typewrite(text);
# print("\nX: {} Y: {}".format(str(x), str(y)))
# pyautogui.typewrite('Hello world!\n', interval=secs_between_keys) # useful for entering text, newline is Enter
# pyautogui.press(['left', 'left', 'left', 'left']) # Press the left arrow key 4 times.
# pyautogui.keyDown('shift') # Press the Shift key down and hold it.
# pyautogui.keyUp('shift') # Let go of the Shift key.
except Exception as e:
print( repr(e) )
return render_template('error.html',
title='Error!',
message='Key is not a valid input...')
return render_template('error.html',
title='Error!',
message='Must use POST request type...')

View File

@ -0,0 +1 @@
from . import Routes

View File

@ -0,0 +1,471 @@
/*!
* Datepicker for Bootstrap v1.6.4 (https://github.com/eternicode/bootstrap-datepicker)
*
* Copyright 2012 Stefan Petre
* Improvements by Andrew Rowls
* Licensed under the Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/
.datepicker {
padding: 4px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
direction: ltr;
}
.datepicker-inline {
width: 220px;
}
.datepicker.datepicker-rtl {
direction: rtl;
}
.datepicker.datepicker-rtl table tr td span {
float: right;
}
.datepicker-dropdown {
top: 0;
left: 0;
}
.datepicker-dropdown:before {
content: '';
display: inline-block;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-bottom: 7px solid #999;
border-top: 0;
border-bottom-color: rgba(0, 0, 0, 0.2);
position: absolute;
}
.datepicker-dropdown:after {
content: '';
display: inline-block;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid #fff;
border-top: 0;
position: absolute;
}
.datepicker-dropdown.datepicker-orient-left:before {
left: 6px;
}
.datepicker-dropdown.datepicker-orient-left:after {
left: 7px;
}
.datepicker-dropdown.datepicker-orient-right:before {
right: 6px;
}
.datepicker-dropdown.datepicker-orient-right:after {
right: 7px;
}
.datepicker-dropdown.datepicker-orient-bottom:before {
top: -7px;
}
.datepicker-dropdown.datepicker-orient-bottom:after {
top: -6px;
}
.datepicker-dropdown.datepicker-orient-top:before {
bottom: -7px;
border-bottom: 0;
border-top: 7px solid #999;
}
.datepicker-dropdown.datepicker-orient-top:after {
bottom: -6px;
border-bottom: 0;
border-top: 6px solid #fff;
}
.datepicker table {
margin: 0;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.datepicker td,
.datepicker th {
text-align: center;
width: 20px;
height: 20px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
border: none;
}
.table-striped .datepicker table tr td,
.table-striped .datepicker table tr th {
background-color: transparent;
}
.datepicker table tr td.day:hover,
.datepicker table tr td.day.focused {
background: #eee;
cursor: pointer;
}
.datepicker table tr td.old,
.datepicker table tr td.new {
color: #999;
}
.datepicker table tr td.disabled,
.datepicker table tr td.disabled:hover {
background: none;
color: #999;
cursor: default;
}
.datepicker table tr td.highlighted {
background: #d9edf7;
border-radius: 0;
}
.datepicker table tr td.today,
.datepicker table tr td.today:hover,
.datepicker table tr td.today.disabled,
.datepicker table tr td.today.disabled:hover {
background-color: #fde19a;
background-image: -moz-linear-gradient(to bottom, #fdd49a, #fdf59a);
background-image: -ms-linear-gradient(to bottom, #fdd49a, #fdf59a);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a));
background-image: -webkit-linear-gradient(to bottom, #fdd49a, #fdf59a);
background-image: -o-linear-gradient(to bottom, #fdd49a, #fdf59a);
background-image: linear-gradient(to bottom, #fdd49a, #fdf59a);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);
border-color: #fdf59a #fdf59a #fbed50;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #000;
}
.datepicker table tr td.today:hover,
.datepicker table tr td.today:hover:hover,
.datepicker table tr td.today.disabled:hover,
.datepicker table tr td.today.disabled:hover:hover,
.datepicker table tr td.today:active,
.datepicker table tr td.today:hover:active,
.datepicker table tr td.today.disabled:active,
.datepicker table tr td.today.disabled:hover:active,
.datepicker table tr td.today.active,
.datepicker table tr td.today:hover.active,
.datepicker table tr td.today.disabled.active,
.datepicker table tr td.today.disabled:hover.active,
.datepicker table tr td.today.disabled,
.datepicker table tr td.today:hover.disabled,
.datepicker table tr td.today.disabled.disabled,
.datepicker table tr td.today.disabled:hover.disabled,
.datepicker table tr td.today[disabled],
.datepicker table tr td.today:hover[disabled],
.datepicker table tr td.today.disabled[disabled],
.datepicker table tr td.today.disabled:hover[disabled] {
background-color: #fdf59a;
}
.datepicker table tr td.today:active,
.datepicker table tr td.today:hover:active,
.datepicker table tr td.today.disabled:active,
.datepicker table tr td.today.disabled:hover:active,
.datepicker table tr td.today.active,
.datepicker table tr td.today:hover.active,
.datepicker table tr td.today.disabled.active,
.datepicker table tr td.today.disabled:hover.active {
background-color: #fbf069 \9;
}
.datepicker table tr td.today:hover:hover {
color: #000;
}
.datepicker table tr td.today.active:hover {
color: #fff;
}
.datepicker table tr td.range,
.datepicker table tr td.range:hover,
.datepicker table tr td.range.disabled,
.datepicker table tr td.range.disabled:hover {
background: #eee;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
}
.datepicker table tr td.range.today,
.datepicker table tr td.range.today:hover,
.datepicker table tr td.range.today.disabled,
.datepicker table tr td.range.today.disabled:hover {
background-color: #f3d17a;
background-image: -moz-linear-gradient(to bottom, #f3c17a, #f3e97a);
background-image: -ms-linear-gradient(to bottom, #f3c17a, #f3e97a);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a));
background-image: -webkit-linear-gradient(to bottom, #f3c17a, #f3e97a);
background-image: -o-linear-gradient(to bottom, #f3c17a, #f3e97a);
background-image: linear-gradient(to bottom, #f3c17a, #f3e97a);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0);
border-color: #f3e97a #f3e97a #edde34;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
}
.datepicker table tr td.range.today:hover,
.datepicker table tr td.range.today:hover:hover,
.datepicker table tr td.range.today.disabled:hover,
.datepicker table tr td.range.today.disabled:hover:hover,
.datepicker table tr td.range.today:active,
.datepicker table tr td.range.today:hover:active,
.datepicker table tr td.range.today.disabled:active,
.datepicker table tr td.range.today.disabled:hover:active,
.datepicker table tr td.range.today.active,
.datepicker table tr td.range.today:hover.active,
.datepicker table tr td.range.today.disabled.active,
.datepicker table tr td.range.today.disabled:hover.active,
.datepicker table tr td.range.today.disabled,
.datepicker table tr td.range.today:hover.disabled,
.datepicker table tr td.range.today.disabled.disabled,
.datepicker table tr td.range.today.disabled:hover.disabled,
.datepicker table tr td.range.today[disabled],
.datepicker table tr td.range.today:hover[disabled],
.datepicker table tr td.range.today.disabled[disabled],
.datepicker table tr td.range.today.disabled:hover[disabled] {
background-color: #f3e97a;
}
.datepicker table tr td.range.today:active,
.datepicker table tr td.range.today:hover:active,
.datepicker table tr td.range.today.disabled:active,
.datepicker table tr td.range.today.disabled:hover:active,
.datepicker table tr td.range.today.active,
.datepicker table tr td.range.today:hover.active,
.datepicker table tr td.range.today.disabled.active,
.datepicker table tr td.range.today.disabled:hover.active {
background-color: #efe24b \9;
}
.datepicker table tr td.selected,
.datepicker table tr td.selected:hover,
.datepicker table tr td.selected.disabled,
.datepicker table tr td.selected.disabled:hover {
background-color: #9e9e9e;
background-image: -moz-linear-gradient(to bottom, #b3b3b3, #808080);
background-image: -ms-linear-gradient(to bottom, #b3b3b3, #808080);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080));
background-image: -webkit-linear-gradient(to bottom, #b3b3b3, #808080);
background-image: -o-linear-gradient(to bottom, #b3b3b3, #808080);
background-image: linear-gradient(to bottom, #b3b3b3, #808080);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0);
border-color: #808080 #808080 #595959;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td.selected:hover,
.datepicker table tr td.selected:hover:hover,
.datepicker table tr td.selected.disabled:hover,
.datepicker table tr td.selected.disabled:hover:hover,
.datepicker table tr td.selected:active,
.datepicker table tr td.selected:hover:active,
.datepicker table tr td.selected.disabled:active,
.datepicker table tr td.selected.disabled:hover:active,
.datepicker table tr td.selected.active,
.datepicker table tr td.selected:hover.active,
.datepicker table tr td.selected.disabled.active,
.datepicker table tr td.selected.disabled:hover.active,
.datepicker table tr td.selected.disabled,
.datepicker table tr td.selected:hover.disabled,
.datepicker table tr td.selected.disabled.disabled,
.datepicker table tr td.selected.disabled:hover.disabled,
.datepicker table tr td.selected[disabled],
.datepicker table tr td.selected:hover[disabled],
.datepicker table tr td.selected.disabled[disabled],
.datepicker table tr td.selected.disabled:hover[disabled] {
background-color: #808080;
}
.datepicker table tr td.selected:active,
.datepicker table tr td.selected:hover:active,
.datepicker table tr td.selected.disabled:active,
.datepicker table tr td.selected.disabled:hover:active,
.datepicker table tr td.selected.active,
.datepicker table tr td.selected:hover.active,
.datepicker table tr td.selected.disabled.active,
.datepicker table tr td.selected.disabled:hover.active {
background-color: #666666 \9;
}
.datepicker table tr td.active,
.datepicker table tr td.active:hover,
.datepicker table tr td.active.disabled,
.datepicker table tr td.active.disabled:hover {
background-color: #006dcc;
background-image: -moz-linear-gradient(to bottom, #08c, #0044cc);
background-image: -ms-linear-gradient(to bottom, #08c, #0044cc);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0044cc));
background-image: -webkit-linear-gradient(to bottom, #08c, #0044cc);
background-image: -o-linear-gradient(to bottom, #08c, #0044cc);
background-image: linear-gradient(to bottom, #08c, #0044cc);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#08c', endColorstr='#0044cc', GradientType=0);
border-color: #0044cc #0044cc #002a80;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td.active:hover,
.datepicker table tr td.active:hover:hover,
.datepicker table tr td.active.disabled:hover,
.datepicker table tr td.active.disabled:hover:hover,
.datepicker table tr td.active:active,
.datepicker table tr td.active:hover:active,
.datepicker table tr td.active.disabled:active,
.datepicker table tr td.active.disabled:hover:active,
.datepicker table tr td.active.active,
.datepicker table tr td.active:hover.active,
.datepicker table tr td.active.disabled.active,
.datepicker table tr td.active.disabled:hover.active,
.datepicker table tr td.active.disabled,
.datepicker table tr td.active:hover.disabled,
.datepicker table tr td.active.disabled.disabled,
.datepicker table tr td.active.disabled:hover.disabled,
.datepicker table tr td.active[disabled],
.datepicker table tr td.active:hover[disabled],
.datepicker table tr td.active.disabled[disabled],
.datepicker table tr td.active.disabled:hover[disabled] {
background-color: #0044cc;
}
.datepicker table tr td.active:active,
.datepicker table tr td.active:hover:active,
.datepicker table tr td.active.disabled:active,
.datepicker table tr td.active.disabled:hover:active,
.datepicker table tr td.active.active,
.datepicker table tr td.active:hover.active,
.datepicker table tr td.active.disabled.active,
.datepicker table tr td.active.disabled:hover.active {
background-color: #003399 \9;
}
.datepicker table tr td span {
display: block;
width: 23%;
height: 54px;
line-height: 54px;
float: left;
margin: 1%;
cursor: pointer;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.datepicker table tr td span:hover,
.datepicker table tr td span.focused {
background: #eee;
}
.datepicker table tr td span.disabled,
.datepicker table tr td span.disabled:hover {
background: none;
color: #999;
cursor: default;
}
.datepicker table tr td span.active,
.datepicker table tr td span.active:hover,
.datepicker table tr td span.active.disabled,
.datepicker table tr td span.active.disabled:hover {
background-color: #006dcc;
background-image: -moz-linear-gradient(to bottom, #08c, #0044cc);
background-image: -ms-linear-gradient(to bottom, #08c, #0044cc);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0044cc));
background-image: -webkit-linear-gradient(to bottom, #08c, #0044cc);
background-image: -o-linear-gradient(to bottom, #08c, #0044cc);
background-image: linear-gradient(to bottom, #08c, #0044cc);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#08c', endColorstr='#0044cc', GradientType=0);
border-color: #0044cc #0044cc #002a80;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td span.active:hover,
.datepicker table tr td span.active:hover:hover,
.datepicker table tr td span.active.disabled:hover,
.datepicker table tr td span.active.disabled:hover:hover,
.datepicker table tr td span.active:active,
.datepicker table tr td span.active:hover:active,
.datepicker table tr td span.active.disabled:active,
.datepicker table tr td span.active.disabled:hover:active,
.datepicker table tr td span.active.active,
.datepicker table tr td span.active:hover.active,
.datepicker table tr td span.active.disabled.active,
.datepicker table tr td span.active.disabled:hover.active,
.datepicker table tr td span.active.disabled,
.datepicker table tr td span.active:hover.disabled,
.datepicker table tr td span.active.disabled.disabled,
.datepicker table tr td span.active.disabled:hover.disabled,
.datepicker table tr td span.active[disabled],
.datepicker table tr td span.active:hover[disabled],
.datepicker table tr td span.active.disabled[disabled],
.datepicker table tr td span.active.disabled:hover[disabled] {
background-color: #0044cc;
}
.datepicker table tr td span.active:active,
.datepicker table tr td span.active:hover:active,
.datepicker table tr td span.active.disabled:active,
.datepicker table tr td span.active.disabled:hover:active,
.datepicker table tr td span.active.active,
.datepicker table tr td span.active:hover.active,
.datepicker table tr td span.active.disabled.active,
.datepicker table tr td span.active.disabled:hover.active {
background-color: #003399 \9;
}
.datepicker table tr td span.old,
.datepicker table tr td span.new {
color: #999;
}
.datepicker .datepicker-switch {
width: 145px;
}
.datepicker .datepicker-switch,
.datepicker .prev,
.datepicker .next,
.datepicker tfoot tr th {
cursor: pointer;
}
.datepicker .datepicker-switch:hover,
.datepicker .prev:hover,
.datepicker .next:hover,
.datepicker tfoot tr th:hover {
background: #eee;
}
.datepicker .cw {
font-size: 10px;
width: 12px;
padding: 0 2px 0 5px;
vertical-align: middle;
}
.input-append.date .add-on,
.input-prepend.date .add-on {
cursor: pointer;
}
.input-append.date .add-on i,
.input-prepend.date .add-on i {
margin-top: 3px;
}
.input-daterange input {
text-align: center;
}
.input-daterange input:first-child {
-webkit-border-radius: 3px 0 0 3px;
-moz-border-radius: 3px 0 0 3px;
border-radius: 3px 0 0 3px;
}
.input-daterange input:last-child {
-webkit-border-radius: 0 3px 3px 0;
-moz-border-radius: 0 3px 3px 0;
border-radius: 0 3px 3px 0;
}
.input-daterange .add-on {
display: inline-block;
width: auto;
min-width: 16px;
height: 18px;
padding: 4px 5px;
font-weight: normal;
line-height: 18px;
text-align: center;
text-shadow: 0 1px 0 #fff;
vertical-align: middle;
background-color: #eee;
border: 1px solid #ccc;
margin-left: -5px;
margin-right: -5px;
}
/*# sourceMappingURL=bootstrap-datepicker.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,77 @@
/* Elms */
ul, li {
list-style: none;
}
body {
overflow: hidden; /* Used to prevent touch scroll down reloading page. Ref: https://stackoverflow.com/questions/29008194/disabling-androids-chrome-pull-down-to-refresh-feature */
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome, Opera and Firefox */
}
input {
width: 75% !important;
margin: 0 auto !important;
font-size: 200% !important;
background-color: #00000000 !important;
}
/* IDs */
#bg {
position: fixed;
top: 0%;
left: 0%;
width: 100%;
height: 100%;
z-index: -999;
}
#bg img {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
z-index: -999;
}
#canvas {
width: 100%;
min-height: 65em;
background-color: rgba(56, 56, 56, 0.67);
}
#singleClickBtn, #doubleClickBtn {
background-color: #62c462;
border-style: dashed;
border-width: 2px;
overflow: auto;
height: 8em;
font-size: 200%;
color: black;
}
#singleClickBtn:hover,
#doubleClickBtn:hover,
#singleClickBtn:active,
#doubleClickBtn:active {
background-color: rgba(0, 232, 255, 0.5);
cursor: pointer;
}
#sendKeysBtn { width: 8em; }
/* Classes */
/* Other message text colors */
.errorTxt { color: rgb(170, 18, 18); }
.warningTxt { color: rgb(255, 168, 0); }
.successTxt { color: rgb(136, 204, 39); }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
src/core/static/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@ -0,0 +1,22 @@
const doAjax = (actionPath, data, action) => {
let xhttp = new XMLHttpRequest();
xhttp.open("POST", actionPath, true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
// Force return to be JSON NOTE: Use application/xml to force XML
xhttp.overrideMimeType('application/json');
xhttp.send(data);
}
const formatURL = (basePath) => {
url = window.location.href;
if ( url.endsWith('/') )
return url + basePath;
else
return url + '/' + basePath;
}
const fetchData = async (url) => {
let response = null;
response = await fetch(url);
return await response.json();
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,143 @@
// When true, moving the mouse updates coords
const canvas = document.getElementById("canvas");
let isDragging = false;
let runUpdate = false;
let xLast = 0;
let yLast = 0;
let mod = 2;
let px = 0;
let py = 0;
let x1 = 0;
let y1 = 0;
let x2 = 0;
let y2 = 0;
let m = undefined; // slope value
canvas.addEventListener('touchstart', e => { onPress(e); });
canvas.addEventListener('mousedown', e => { onPress(e); });
canvas.addEventListener('touchmove', e => { onMoveing(e); });
canvas.addEventListener('mousemove', e => { onMoveing(e); });
canvas.addEventListener('touchend', e => { onRelease(e); });
canvas.addEventListener('mouseup', e => { onRelease(e); });
// Run update when true every 100 ms
setInterval(function () {
if (runUpdate) {
doAjax("/update-coords", "x=" + px + "&y=" + py, "move");
}
}, 100);
// Update mod
setInterval(function () {
if (runUpdate) {
mod += 1;
}
}, 250);
const onPress = (e) => {
isDragging = true;
runUpdate = true;
xLast = e.offsetX;
yLast = e.offsetY;
updateText(xLast, yLast);
}
const onMoveing = (e) => {
if (isDragging === true) {
x1 = xLast;
y1 = yLast;
if (e.type === 'mousemove') {
x2 = e.offsetX;
y2 = e.offsetY;
xLast = e.offsetX;
yLast = e.offsetY;
} else if (e.type === 'touchmove') {
x2 = parseInt(e.touches[0].clientX, 10);
y2 = parseInt(e.touches[0].clientY, 10);
xLast = parseInt(e.touches[0].clientX, 10);
yLast = parseInt(e.touches[0].clientY, 10);
}
// Calculate the delta of the points
if (x2 > x1) {
px = mod // Is growing
} else {
px = -mod // Is shrinking
}
if (y2 > y1) {
py = mod // Is growing
} else {
py = -mod // Is shrinking
}
m = (y2-y1)/(x2-x1)
if (m === undefined) {
py = 0;
} else if (!isFinite(m)) {
px = 0;
}
if ( (m > 0.05 && m <= 1) && (m > -0.05 && m >= -1) ) {
py = 0;
}
updateText(px, py);
}
}
const onRelease = (e) => {
if (isDragging === true) {
isDragging = false;
runUpdate = false;
mod = 3;
xLast = 0;
yLast = 0;
px = 0;
py = 0;
updateText(px, py);
}
}
const updateText = (x, y) => {
const coordsTxt = "X coords: " + x + ", Y coords: " + y;
document.getElementById("cordsText").innerText = coordsTxt;
}
// Click events
document.getElementById("singleClickBtn").addEventListener('mouseup', e => { onSingleClick(e); });
document.getElementById("singleClickBtn").addEventListener('touchend', e => { onSingleClick(e); });
document.getElementById("doubleClickBtn").addEventListener('mouseup', e => { onDoubleClick(e); });
document.getElementById("doubleClickBtn").addEventListener('touchend', e => { onDoubleClick(e); });
const onSingleClick = (e) => {
doAjax("/single-click", "ref=null", "singleClick");
}
const onDoubleClick = (e) => {
doAjax("/double-click", "ref=null", "doubleClick");
}
// Key input events
// document.getElementById("sendKeysField").addEventListener('input', e => { onSendKeys(e); });
// document.getElementById("sendKeysField").addEventListener('change', e => { onSendKeys(e); });
document.getElementById("sendKeysBtn").addEventListener('mouseup', e => { onSendKeys(e); });
document.getElementById("sendKeysBtn").addEventListener('touchend', e => { onSendKeys(e); });
const onSendKeys = (e) => {
let target = document.getElementById("sendKeysField");
const text = target.value;
doAjax("/send-key", "text=" + text, "sendKeys");
target.value = "";
}

View File

@ -0,0 +1,15 @@
{% extends "layout.html" %}
{% block content %}
<div class="container">
<div class="row">
<div class="col justify-content-center text-center">
<h1 class="errorTxt">{{title}}</h1>
<p>{{message}}</p>
</div>
</div>
</div>
{% endblock content %}
{% block scripts %}
<!-- Created scripts -->
{% endblock scripts %}

View File

@ -0,0 +1,41 @@
{% extends "layout.html" %}
{% block body_header_additional %}
{% endblock body_header_additional %}
{% block body_content %}
<div class="container-auto">
<div class="row">
<div id="singleClickBtn" class="col justify-content-center text-center">
Single-Click
</div>
<div id="doubleClickBtn" class="col justify-content-center text-center">
Double-Click
</div>
</div>
<br/><br/>
<div class="row">
<input id="sendKeysField" type="text" value="" class="form-control" placeholder="Send keys...">
<button id="sendKeysBtn" class="btn btn-success">Send</button>
</div>
</div>
<div id="canvas" class="container-auto">
<div class="row">
<div class="col justify-content-center text-center">
<div id="cordsText" style="font-size: 280%;">
X coords: 0, Y coords: 0
</div>
</div>
</div>
</div>
{% endblock body_content %}
{% block body_footer_additional %}
{% endblock body_footer_additional %}
{% block body_scripts_additional %}
<script src="{{url_for('static', filename='js/ajax.js')}}"></script>
<script src="{{url_for('static', filename='js/events.js')}}"></script>
<script src="{{url_for('static', filename='js/draging.js')}}"></script>
{% endblock body_scripts_additional %}

View File

@ -0,0 +1,84 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
{% if title %}
<title>{{title}}</title>
{% else %}
<title>App</title>
{% endif %}
{% block header_css %}
<!-- Bootstrap CSS -->
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.png') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap/bootstrap.min.css')}}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap/bootstrap-datepicker.css')}}">
<!-- Font Awesome CSS Notes -->
<!-- <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.0/css/all.css" integrity="sha384-lZN37f5QGtY3VHgisS14W3ExzMWZxybE1SJSEsQp9S+oqd12jhcu+A56Ebc1zFSJ" crossorigin="anonymous"> -->
<!-- https://use.fontawesome.com/releases/v5.7.0/webfonts/fa-regular-400.woff2 -->
<!-- https://use.fontawesome.com/releases/v5.7.0/webfonts/ -->
<!-- Site Font Awesome CSS -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/font-awesome/font-awesome-all-v5.7.css')}}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/font-awesome/font-awesome-min-v4.7.0.css')}}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/font-awesome/font-awesome-woff2.css')}}">
<!-- Site CSS -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css')}}">
{% block header_css_additional %}
{% endblock header_css_additional %}
{% endblock %}
{% block header_scripts %}
{% block header_scripts_additional %}
{% endblock header_scripts_additional %}
{% endblock %}
</head>
<body>
<!-- <img id="bg" src="{{ url_for('static', filename='imgs/backgrounds/background.jpg')}}" alt="{{title}} Background Logo" /> -->
{% block body_header %}
{% block body_header_additional %}
{% endblock body_header_additional%}
{% endblock %}
<!-- System flashed messages! -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<div class=flashes>
{% for category, message in messages %}
<li class="alert alert-{{ category }}">{{ message }}</li>
{% endfor %}
</div>
{% endif %}
{% endwith %}
{% block body_content %}
{% block body_content_additional %}
{% endblock body_content_additional%}
{% endblock %}
{% block body_footer %}
{% block body_footer_additional %}
{% endblock body_footer_additional%}
{% endblock %}
{% block body_scripts %}
<!-- For Bootstrap in this exact order... -->
<script src="{{ url_for('static', filename='js/bootstrap/jquery-3.3.1.slim.min.js')}}"></script>
<script src="{{ url_for('static', filename='js/bootstrap/popper.min.js')}}"></script>
<script src="{{ url_for('static', filename='js/bootstrap/bootstrap.min.js')}}"></script>
<!-- For DatePicker -->
<script src="{{ url_for('static', filename='js/bootstrap/moment.min.js')}}"></script>
<script src="{{ url_for('static', filename='js/bootstrap/bootstrap-datepicker.min.js')}}"></script>
{% block body_scripts_additional %}
{% endblock body_scripts_additional%}
{% endblock %}
</body>
</html>

13
src/linux-start.sh Normal file
View File

@ -0,0 +1,13 @@
#!/bin/bash
# set -o xtrace ## To debug scripts
# set -o errexit ## To exit on error
# set -o errunset ## To exit if a variable is referenced but not set
function main() {
source "../venv/bin/activate"
# Note can replace 127.0.0.1 with 0.0.0.0 to make it 'network/internet' accessable...
gunicorn wsgi:app -b 127.0.0.1:8080 # <module>:<app> IE <file>:<flask app variable>
}
main $@;

13
src/windows-start.sh Normal file
View File

@ -0,0 +1,13 @@
#!/bin/bash
# set -o xtrace ## To debug scripts
# set -o errexit ## To exit on error
# set -o errunset ## To exit if a variable is referenced but not set
function main() {
source "../venv/Scripts/activate"
# Note can replace 127.0.0.1 with 0.0.0.0 to make it 'network/internet' accessable...
waitress-serve --listen=127.0.0.1:8080 wsgi:app # <module>:<app> IE <file>:<flask app variable>
}
main $@;

4
src/wsgi.py Normal file
View File

@ -0,0 +1,4 @@
from core import app
if __name__ == '__main__':
app.run(debug=True)

28
windows-requirements.txt Normal file
View File

@ -0,0 +1,28 @@
bcrypt==3.1.7
cffi==1.14.0
Click==7.0
Flask==1.1.1
Flask-Bcrypt==0.7.1
Flask-Login==0.5.0
Flask-SQLAlchemy==2.4.1
Flask-WTF==0.14.3
waitress==1.4.3
itsdangerous==1.1.0
Jinja2==2.10.3
MarkupSafe==1.1.1
MouseInfo==0.1.3
Pillow==7.1.2
pkg-resources==0.0.0
PyAutoGUI==0.9.50
pycparser==2.20
PyGetWindow==0.0.8
PyMsgBox==1.0.8
pyperclip==1.8.0
PyRect==0.1.4
PyScreeze==0.1.26
python3-xlib==0.15
PyTweening==1.0.3
six==1.14.0
SQLAlchemy==1.3.11
Werkzeug==0.16.0
WTForms==2.2.1