Browse Source

initial push...

master
Maxim Stewart 1 year ago
parent
commit
938aaca361
  1. 41
      README.md
  2. BIN
      images/pic1.png
  3. 28
      linux-requirements.txt
  4. 14
      src/core/MessageHandler.py
  5. 31
      src/core/__init__.py
  6. 25
      src/core/forms.py
  7. 20
      src/core/models.py
  8. 85
      src/core/routes/Routes.py
  9. 1
      src/core/routes/__init__.py
  10. 471
      src/core/static/css/bootstrap/bootstrap-datepicker.css
  11. 12
      src/core/static/css/bootstrap/bootstrap.min.css
  12. 5
      src/core/static/css/font-awesome/font-awesome-all-v5.7.css
  13. 4
      src/core/static/css/font-awesome/font-awesome-min-v4.7.0.css
  14. 1
      src/core/static/css/font-awesome/font-awesome-woff2.css
  15. 77
      src/core/static/css/main.css
  16. BIN
      src/core/static/css/webfonts/fa-brands-400.ttf
  17. BIN
      src/core/static/css/webfonts/fa-brands-400.woff
  18. BIN
      src/core/static/css/webfonts/fa-brands-400.woff2
  19. BIN
      src/core/static/css/webfonts/fa-regular-400.ttf
  20. BIN
      src/core/static/css/webfonts/fa-regular-400.woff
  21. BIN
      src/core/static/css/webfonts/fa-regular-400.woff2
  22. BIN
      src/core/static/css/webfonts/fa-solid-900.ttf
  23. BIN
      src/core/static/css/webfonts/fa-solid-900.woff
  24. BIN
      src/core/static/css/webfonts/fa-solid-900.woff2
  25. BIN
      src/core/static/db/database.db
  26. BIN
      src/core/static/favicon.png
  27. BIN
      src/core/static/imgs/backgrounds/background.jpg
  28. BIN
      src/core/static/imgs/circle.png
  29. 22
      src/core/static/js/ajax.js
  30. 9
      src/core/static/js/bootstrap/bootstrap-datepicker.min.js
  31. 7
      src/core/static/js/bootstrap/bootstrap.min.js
  32. 2
      src/core/static/js/bootstrap/jquery-3.3.1.slim.min.js
  33. 7
      src/core/static/js/bootstrap/moment.min.js
  34. 5
      src/core/static/js/bootstrap/popper.min.js
  35. 143
      src/core/static/js/events.js
  36. 15
      src/core/templates/error.html
  37. 41
      src/core/templates/index.html
  38. 84
      src/core/templates/layout.html
  39. 13
      src/linux-start.sh
  40. 13
      src/windows-start.sh
  41. 4
      src/wsgi.py
  42. 28
      windows-requirements.txt

41
README.md

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

28
linux-requirements.txt

@ -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

14
src/core/MessageHandler.py

@ -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

@ -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

@ -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

@ -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

@ -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...')

1
src/core/routes/__init__.py

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

471
src/core/static/css/bootstrap/bootstrap-datepicker.css

@ -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 */

12
src/core/static/css/bootstrap/bootstrap.min.css

File diff suppressed because one or more lines are too long

5
src/core/static/css/font-awesome/font-awesome-all-v5.7.css

File diff suppressed because one or more lines are too long

4
src/core/static/css/font-awesome/font-awesome-min-v4.7.0.css

File diff suppressed because one or more lines are too long

1
src/core/static/css/font-awesome/font-awesome-woff2.css

File diff suppressed because one or more lines are too long

77
src/core/static/css/main.css

@ -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); }

BIN
src/core/static/css/webfonts/fa-brands-400.ttf

Binary file not shown.

BIN
src/core/static/css/webfonts/fa-brands-400.woff

Binary file not shown.

BIN
src/core/static/css/webfonts/fa-brands-400.woff2

Binary file not shown.

BIN
src/core/static/css/webfonts/fa-regular-400.ttf

Binary file not shown.

BIN
src/core/static/css/webfonts/fa-regular-400.woff

Binary file not shown.

BIN
src/core/static/css/webfonts/fa-regular-400.woff2

Binary file not shown.

BIN
src/core/static/css/webfonts/fa-solid-900.ttf

Binary file not shown.

BIN
src/core/static/css/webfonts/fa-solid-900.woff

Binary file not shown.

BIN
src/core/static/css/webfonts/fa-solid-900.woff2

Binary file not shown.

BIN
src/core/static/db/database.db

Binary file not shown.

BIN
src/core/static/favicon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
src/core/static/imgs/backgrounds/background.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 KiB

BIN
src/core/static/imgs/circle.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

22
src/core/static/js/ajax.js

@ -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();
}

9
src/core/static/js/bootstrap/bootstrap-datepicker.min.js

File diff suppressed because one or more lines are too long

7
src/core/static/js/bootstrap/bootstrap.min.js

File diff suppressed because one or more lines are too long

2
src/core/static/js/bootstrap/jquery-3.3.1.slim.min.js

File diff suppressed because one or more lines are too long

7
src/core/static/js/bootstrap/moment.min.js

File diff suppressed because one or more lines are too long

5
src/core/static/js/bootstrap/popper.min.js

File diff suppressed because one or more lines are too long

143
src/core/static/js/events.js

@ -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 = "";
}

15
src/core/templates/error.html

@ -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 %}

41
src/core/templates/index.html

@ -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 %}

84
src/core/templates/layout.html

@ -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

@ -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 [email protected];

13
src/windows-start.sh

@ -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 [email protected];

4
src/wsgi.py

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

28
windows-requirements.txt

@ -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
Loading…
Cancel
Save