diff --git a/1.0.2/__builtins__.py b/1.0.2/__builtins__.py new file mode 100644 index 0000000..7d6fa47 --- /dev/null +++ b/1.0.2/__builtins__.py @@ -0,0 +1,79 @@ +# Python imports +import builtins, threading + +# Lib imports + +# Application imports +from utils.pyautogui_control import ControlMixin + + + +# NOTE: Threads WILL NOT die with parent's destruction. +def threaded_wrapper(fn): + def wrapper(*args, **kwargs): + threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start() + return wrapper + +# NOTE: Threads WILL die with parent's destruction. +def daemon_threaded_wrapper(fn): + def wrapper(*args, **kwargs): + threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start() + return wrapper + + + + +class EndpointRegistry(): + def __init__(self): + self._endpoints = {} + + def register(self, rule, **options): + def decorator(f): + self._endpoints[rule] = f + return f + + return decorator + + def get_endpoints(self): + return self._endpoints + +class Pyautogui_Controller(ControlMixin): + def __init__(self): + pass + + + +keys_json = { + "keys": { + "row1": { + "pKeys": ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'], + "sKeys": ['~', '@', '#', '$', '%', '&', '-', '_', '(', ')'], + }, + "row2": { + "pKeys": ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'], + "sKeys": ['\\', '/', '|', ':', '{', '}', '[', ']', '<', '>'], + }, + "row3": { + "pKeys": ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', "'"], + "sKeys": ['=', '+', '"', '*', '^', '`', ';', '!', '', ''], + }, + "row4": { + "pKeys": ['z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '?'], + "sKeys": ['', '', '', '', '', '', '', '', '', ''] + }, + } +} + + + +# NOTE: Just reminding myself we can add to builtins two different ways... +# __builtins__.update({"event_system": Builtins()}) +builtins.app_name = "Mouse Keyboard" +builtins.endpoint_registry = EndpointRegistry() +builtins.typwriter = Pyautogui_Controller() +builtins.threaded = threaded_wrapper +builtins.daemon_threaded = daemon_threaded_wrapper +builtins.keys_set = keys_json +builtins.trace_debug = False +builtins.debug = False +builtins.app_settings = None diff --git a/1.0.2/__init__.py b/1.0.2/__init__.py new file mode 100644 index 0000000..cd8371b --- /dev/null +++ b/1.0.2/__init__.py @@ -0,0 +1,3 @@ +""" + Base module +""" diff --git a/1.0.2/__main__.py b/1.0.2/__main__.py new file mode 100644 index 0000000..87d25a0 --- /dev/null +++ b/1.0.2/__main__.py @@ -0,0 +1,42 @@ +#!/usr/bin/python3 + + +# Python imports +import argparse, faulthandler, traceback +from setproctitle import setproctitle + +import tracemalloc +tracemalloc.start() + + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + +# Application imports +from app import Application + + +if __name__ == "__main__": + """ Set process title, get arguments, and create GTK main thread. """ + + try: + # import web_pdb + # web_pdb.set_trace() + + setproctitle('Mouse Keyboard') + faulthandler.enable() # For better debug info + parser = argparse.ArgumentParser() + # Add long and short arguments + parser.add_argument("--new-tab", "-t", default="", help="Open a file into new tab.") + parser.add_argument("--new-window", "-w", default="", help="Open a file into a new window.") + + # Read arguments (If any...) + args, unknownargs = parser.parse_known_args() + + Application(args, unknownargs) + Gtk.main() + except Exception as e: + traceback.print_exc() + quit() diff --git a/1.0.2/app.py b/1.0.2/app.py new file mode 100644 index 0000000..d80a172 --- /dev/null +++ b/1.0.2/app.py @@ -0,0 +1,20 @@ +# Python imports +import inspect + + +# Gtk imports + + +# Application imports +from __builtins__ import * +from core.window import Window + + + + +class Application(object): + def __init__(self, args, unknownargs): + try: + Window(args, unknownargs) + except Exception as e: + raise diff --git a/1.0.2/core/__init__.py b/1.0.2/core/__init__.py new file mode 100644 index 0000000..1509597 --- /dev/null +++ b/1.0.2/core/__init__.py @@ -0,0 +1,3 @@ +""" + Core module +""" diff --git a/1.0.2/core/columns/__init__.py b/1.0.2/core/columns/__init__.py new file mode 100644 index 0000000..5acbeb8 --- /dev/null +++ b/1.0.2/core/columns/__init__.py @@ -0,0 +1,3 @@ +from .left_column import Left_Column +from .keys_column import Keys_Column +from .right_column import Right_Column diff --git a/1.0.2/core/columns/keys_column.py b/1.0.2/core/columns/keys_column.py new file mode 100644 index 0000000..904450b --- /dev/null +++ b/1.0.2/core/columns/keys_column.py @@ -0,0 +1,64 @@ +# Python imports + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + +# Application imports +from ..widgets.key import Key + + + +class KeyboardRowMatchError(Exception): + pass + + +class Keys_Column(Gtk.Box): + """docstring for Keys_Column.""" + + def __init__(self): + super(Keys_Column, self).__init__() + + self.setup_styling() + self.setup_signals() + self.setup_key_buttons() + + self.show_all() + + + def setup_styling(self): + self.set_orientation(1) # HORIZONTAL = 0, VERTICAL = 1 + self.set_property("homogeneous", True) + self.set_hexpand(True) + + def setup_signals(self): + pass + + def setup_key_buttons(self): + keys = keys_set["keys"] + children = keys.keys() + + for child in children: + pKeys = keys[child]["pKeys"] + sKeys = keys[child]["sKeys"] + + row_box = self.add_row() + if len(pKeys) == len(sKeys): + for i in range(9): + pkey = pKeys[i] + sKey = sKeys[i] + row_box.add(Key(pkey, sKey)) + else: + raise KeyboardRowMatchError("A row in keys_json has missmatched pKeys and sKeys lengths.") + + row_box = self.add_row() + for key in ['Symbols', 'Space', 'Backspace']: + row_box.add(Key(key, key)) + + def add_row(self): + row_box = Gtk.Box() + row_box.set_property("homogeneous", True) + self.add(row_box) + + return row_box diff --git a/1.0.2/core/columns/left_column.py b/1.0.2/core/columns/left_column.py new file mode 100644 index 0000000..a5d2540 --- /dev/null +++ b/1.0.2/core/columns/left_column.py @@ -0,0 +1,37 @@ +# Python imports + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + +# Application imports + + + + +class Left_Column(Gtk.Button): + """docstring for Left_Column.""" + + def __init__(self): + super(Left_Column, self).__init__() + + self.setup_styling() + self.setup_signals() + self.show_all() + + + def setup_styling(self): + self.set_label("Caps") + + def setup_signals(self): + self.connect("released", self._clicked) + + def _clicked(self, widget = None): + key_columns = self.get_parent().get_children()[1] + limit = len(key_columns.get_children()) - 1 + + for i, row in enumerate(key_columns.get_children()): + if not i == limit: + for key in row: + key.emit("toggle-caps", ()) diff --git a/1.0.2/core/columns/right_column.py b/1.0.2/core/columns/right_column.py new file mode 100644 index 0000000..eba6e2a --- /dev/null +++ b/1.0.2/core/columns/right_column.py @@ -0,0 +1,31 @@ +# Python imports + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + +# Application imports + + + + +class Right_Column(Gtk.Button): + """docstring for Right_Column.""" + + def __init__(self): + super(Right_Column, self).__init__() + + self.setup_styling() + self.setup_signals() + self.show_all() + + + def setup_styling(self): + self.set_label("Enter") + + def setup_signals(self): + self.connect("released", self._clicked) + + def _clicked(self, widget = None): + typwriter.enter() diff --git a/1.0.2/core/container.py b/1.0.2/core/container.py new file mode 100644 index 0000000..d8aaac0 --- /dev/null +++ b/1.0.2/core/container.py @@ -0,0 +1,37 @@ +# Python imports + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + +# Application imports +from .columns import Left_Column, Keys_Column, Right_Column +from .signals_mixin import SignalsMixin + + + +class Container(SignalsMixin, Gtk.Box): + """docstring for Container.""" + + def __init__(self): + super(Container, self).__init__() + + self.setup_custom_event_signals() + self.setup_styling() + self.add_columns() + + self.show_all() + + + def setup_styling(self): + self.set_orientation(0) # HORIZONTAL = 0, VERTICAL = 1 + self.set_vexpand(True) + + def setup_signals(self): + pass + + def add_columns(self): + self.add(Left_Column()) + self.add(Keys_Column()) + self.add(Right_Column()) diff --git a/1.0.2/core/signals_mixin.py b/1.0.2/core/signals_mixin.py new file mode 100644 index 0000000..40e540a --- /dev/null +++ b/1.0.2/core/signals_mixin.py @@ -0,0 +1,17 @@ +# Python imports + +# Lib imports +from gi.repository import GObject + + +# Application imports +from .widgets.key import Key + + + + +class SignalsMixin: + """docstring for SignalsMixin.""" + + def setup_custom_event_signals(self): + GObject.signal_new('toggle-caps', Key, GObject.SIGNAL_RUN_LAST, GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,)) diff --git a/1.0.2/core/widgets/__init__.py b/1.0.2/core/widgets/__init__.py new file mode 100644 index 0000000..1678cd7 --- /dev/null +++ b/1.0.2/core/widgets/__init__.py @@ -0,0 +1,3 @@ +""" + Widgets module +""" diff --git a/1.0.2/core/widgets/key.py b/1.0.2/core/widgets/key.py new file mode 100644 index 0000000..5d06eff --- /dev/null +++ b/1.0.2/core/widgets/key.py @@ -0,0 +1,34 @@ +# Python imports + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + +# Application imports + + +class Key(Gtk.Button): + def __init__(self, primary = "NULL", secondary = "NULL"): + super(Key, self).__init__() + + self._primary_symbol = primary + self._secondary_symbol = secondary + self._is_upper = False + + self.set_label(self._primary_symbol) + + self.setup_signals() + + + def toggle_caps(self, widget = None, eve = None): + self._is_upper = not self._is_upper + self.set_label(self._primary_symbol.upper()) if self._is_upper else self.set_label(self._primary_symbol.lower()) + + def setup_signals(self): + self.connect("released", self._clicked) + self.connect("toggle-caps", self.toggle_caps) + + def _clicked(self, widget = None): + key = self.get_label().strip() + typwriter.type(key) diff --git a/1.0.2/core/window.py b/1.0.2/core/window.py new file mode 100644 index 0000000..2b15909 --- /dev/null +++ b/1.0.2/core/window.py @@ -0,0 +1,36 @@ +# Python imports + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + +# Application imports +from .container import Container + + + +class Window(Gtk.ApplicationWindow): + """docstring for Window.""" + + def __init__(self, args, unknownargs): + super(Window, self).__init__() + + self.setup_styling() + self.setup_signals() + self.add(Container()) + + self.show_all() + + + def setup_styling(self): + # self.set_icon_from_file("/usr/share/bulkr/bulkr.png") + self.set_title(app_name) + self.set_default_size(800, 200) + self.set_type_hint(3) # 3 = TOOLBAR + self.set_gravity(8) # 5 = CENTER, 8 = SOUTH + self.set_position(1) # 1 = CENTER, 4 = CENTER_ALWAYS + self.stick() + + def setup_signals(self): + self.connect("delete-event", Gtk.main_quit) diff --git a/1.0.2/resources/Main_Window.glade b/1.0.2/resources/Main_Window.glade new file mode 100644 index 0000000..7931fad --- /dev/null +++ b/1.0.2/resources/Main_Window.glade @@ -0,0 +1,436 @@ + + + + + + + + + + + + False + Mouse Board + center + 260 + icon.png + toolbar + True + True + False + center + + + True + False + vertical + + + True + False + + + True + False + + + True + True + 0 + + + + + 520 + True + False + + + True + True + gtk-go-forward + False + False + Autotype Field... + + + True + True + 0 + + + + + Type + True + True + True + + + + False + True + 1 + + + + + False + True + 1 + + + + + True + False + + + True + True + 2 + + + + + False + True + 0 + + + + + True + False + + + True + False + vertical + + + True + False + 10 + 10 + Special Characters + + + + + + False + True + 0 + + + + + True + False + in + + + True + False + + + True + False + vertical + 10 + start + + + + + + + + + + True + True + 1 + + + + + False + True + 0 + + + + + popoutkeyboard + True + False + 5 + vertical + True + + + + + + + + + + + + + + + + + + + + + False + True + 1 + + + + + True + False + 10 + 10 + vertical + + + True + False + start + + + Del + True + True + True + + + + True + True + 0 + + + + + Ctrl + True + True + True + + + + True + True + 1 + + + + + Shift + True + True + True + + + + True + True + 2 + + + + + Alt + True + True + True + + + + True + True + 3 + + + + + PrtSc + True + True + False + + + + True + True + 4 + + + + + gtk-add + True + True + True + True + + + True + True + 5 + + + + + False + True + 0 + + + + + True + True + in + + + True + False + + + True + True + commands + + + + + + Commands + + + + 0 + + + + + + + + + + + True + True + 1 + + + + + + True + False + True + + + Up + True + True + True + + + + 1 + 0 + + + + + Down + True + True + True + + + + 1 + 2 + + + + + Left + True + True + True + + + + 0 + 1 + + + + + Right + True + True + True + + + + 2 + 1 + + + + + + + + + + + + + + + + + + + + False + True + 2 + + + + + False + True + 2 + + + + + True + True + 1 + + + + + + diff --git a/1.0.2/resources/icon.png b/1.0.2/resources/icon.png new file mode 100644 index 0000000..bcf986e Binary files /dev/null and b/1.0.2/resources/icon.png differ diff --git a/1.0.2/resources/stylesheet.css b/1.0.2/resources/stylesheet.css new file mode 100644 index 0000000..f219141 --- /dev/null +++ b/1.0.2/resources/stylesheet.css @@ -0,0 +1,8 @@ +/* * { + background: rgba(0, 0, 0, 0.14); + color: rgba(255, 255, 255, 1); +} + +#popoutkeyboard { + background-color: rgba(0, 65, 125, 1); +} */ diff --git a/1.0.2/utils/__init__.py b/1.0.2/utils/__init__.py new file mode 100644 index 0000000..a8e5edd --- /dev/null +++ b/1.0.2/utils/__init__.py @@ -0,0 +1,3 @@ +""" + Utils module +""" diff --git a/1.0.2/utils/logger.py b/1.0.2/utils/logger.py new file mode 100644 index 0000000..c33444f --- /dev/null +++ b/1.0.2/utils/logger.py @@ -0,0 +1,56 @@ +# Python imports +import os, logging + +# Application imports + + +class Logger: + """ + Create a new logging object and return it. + :note: + NOSET # Don't know the actual log level of this... (defaulting or literally none?) + Log Levels (From least to most) + Type Value + CRITICAL 50 + ERROR 40 + WARNING 30 + INFO 20 + DEBUG 10 + :param loggerName: Sets the name of the logger object. (Used in log lines) + :param createFile: Whether we create a log file or just pump to terminal + + :return: the logging object we created + """ + + def __init__(self, config_path: str, _ch_log_lvl = logging.CRITICAL, _fh_log_lvl = logging.INFO): + self._CONFIG_PATH = config_path + self.global_lvl = logging.DEBUG # Keep this at highest so that handlers can filter to their desired levels + self.ch_log_lvl = _ch_log_lvl # Prety much the only one we ever change + self.fh_log_lvl = _fh_log_lvl + + def get_logger(self, loggerName: str = "NO_LOGGER_NAME_PASSED", createFile: bool = True) -> logging.Logger: + log = logging.getLogger(loggerName) + log.setLevel(self.global_lvl) + + # Set our log output styles + fFormatter = logging.Formatter('[%(asctime)s] %(pathname)s:%(lineno)d %(levelname)s - %(message)s', '%m-%d %H:%M:%S') + cFormatter = logging.Formatter('%(pathname)s:%(lineno)d] %(levelname)s - %(message)s') + + ch = logging.StreamHandler() + ch.setLevel(level=self.ch_log_lvl) + ch.setFormatter(cFormatter) + log.addHandler(ch) + + if createFile: + folder = self._CONFIG_PATH + file = f"{folder}/application.log" + + if not os.path.exists(folder): + os.mkdir(folder) + + fh = logging.FileHandler(file) + fh.setLevel(level=self.fh_log_lvl) + fh.setFormatter(fFormatter) + log.addHandler(fh) + + return log diff --git a/1.0.2/utils/pyautogui_control.py b/1.0.2/utils/pyautogui_control.py new file mode 100644 index 0000000..f3a58c3 --- /dev/null +++ b/1.0.2/utils/pyautogui_control.py @@ -0,0 +1,102 @@ +# Python imports +import pyautogui + +# Gtk imports + +# Application imports + + +# Let piautogui make updates as quick as it can... +pyautogui.FAILSAFE = False # If we hit corner, that's ok +pyautogui.MINIMUM_DURATION = 0 +pyautogui.PAUSE = 0 + + +class ControlMixin: + + def type(self, key): + pyautogui.typewrite(key) + + + def enter(self, widget = None, data = None): + pyautogui.press("enter") + + + # def typeString(self, widget = None, data = None): + # text = self.autoTypeField.get_text() + # for char in text: + # self.do_insert(char) + # + # def insert(self, widget = None, data = None, key = None): + # if not key: + # key = widget.get_label().strip() + # + # if self.is_keypress_type(key): + # return + # + # if self.isCapsLockOn: + # key = key.upper() + # + # self.do_insert(key) + # + # + # def do_insert(self, key): + # if self.isCtrlOn or self.isShiftOn or self.isAltOn: + # self.set_hotkeys() + # + # pyautogui.typewrite(key) + # + # if self.isCtrlOn or self.isShiftOn or self.isAltOn: + # self.unset_hotkeys() + # + # + # def is_keypress_type(self, key): + # if key in ["Esc", "Tab", "Space", "Del", "Up", "Down", "Left", "Right", "PrtSc"]: + # pyautogui.press(key.lower()) + # return True + # + # for i in range(1, 13): + # fkey = 'F' + str(i) + # if key == fkey: + # pyautogui.press(key.lower()) + # return True + # + # return False + # + # + # def set_hotkeys(self): + # if self.isCtrlOn: + # pyautogui.keyDown('ctrl') + # if self.isShiftOn: + # pyautogui.keyDown('shiftleft') + # pyautogui.keyDown('shiftright') + # if self.isAltOn: + # pyautogui.keyDown('alt') + # + # + # def unset_hotkeys(self): + # pyautogui.keyUp('ctrl') + # pyautogui.keyUp('shiftleft') + # pyautogui.keyUp('shiftright') + # pyautogui.keyUp('alt') + # + # + # def toggleCaps(self, widget, data=None): + # self.isCapsLockOn = False if self.isCapsLockOn else True + # + # def tgglCtrl(self, widget, data=None): + # self.isCtrlOn = False if self.isCtrlOn else True + # + # def tgglShift(self, widget, data=None): + # self.isShiftOn = False if self.isShiftOn else True + # + # def tgglAlt(self, widget, data=None): + # self.isAltOn = False if self.isAltOn else True + # + # + # def enter(self, widget, data=None): + # pyautogui.press("enter") + # + # + # def backspace(self, widget, data=None): + # pyautogui.press("backspace")