123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- from sys import argv as _argv
- from os import name as _OS_NAME, environ as _env
- from os import listdir as _listdir, mkdir as _mkdir, chown as _chown
- from os.path import exists as _exists, join as _join, isdir as _isdir
- from time import sleep as _sleep
- from typing import Dict as _Dict, Tuple as _Tuple, List as _List
- try:
- from click import echo as _echo, style as _style
- except ImportError:
- print("ERROR Please activate a virtual environment and install requirements.txt")
- exit()
- from pyautogui import mouseDown as _mouse_down, mouseUp as _mouse_up
- from keyboard import press as _key_down, release as _key_up, KeyboardEvent as _KeyboardEvent, add_hotkey as _add_hotkey, hook as _key_hook, write as _key_write
- # Not entirely sure why this doesn't work
- #from mouse import press as mouse_down, release as mouse_up, click as mouse_press, move as mouse_move
- from toml import load as _toml_load
- from asyncio import run as _run, sleep as _asleep
- from asyncio.tasks import gather as _task_group
- def _print_err(msg: str):
- _echo(_style("ERROR", fg="bright_red") + " " + msg)
- def _print_warn(msg: str):
- _echo(_style("WARN ", fg="bright_yellow") + " " + msg)
- def _print_ok(msg: str):
- _echo(_style(" OK ", fg="bright_green") + " " + msg)
- def _print_info(msg: str):
- print(" " + msg)
- def _keyboard_output(msg: str, delay: int=50, hold: int=20):
- _key_write(msg, delay=hold)
- _sleep(delay/1000)
- def _mouse_output(button: str, delay: int=50, hold: int=20):
- _mouse_down(button=button)
- _sleep(hold / 1000)
- _mouse_up(button=button)
- _sleep(hold / 1000)
- _sleep(delay / 1000)
- platform: str = ""
- os_name = _OS_NAME.lower()
- if "linux" in os_name or "posix" in os_name:
- platform = "LINUX"
- elif "windows" in os_name or "nt" in os_name:
- platform = "WINDOWS"
- elif "darwin" in os_name:
- platform = "MACOS"
- else:
- _print_err("Platform 'Linux', 'Windows' or 'MacOS' expected")
- _print_info(f"Platform: {_OS_NAME}")
- exit()
- def _profile_pre_check(profile_name: str):
- if profile_name.endswith(".toml"):
- profile_name = profile_name.removesuffix(".toml")
- if not _exists(profile_name):
- _mkdir(profile_name)
- if "SUDO_USER" in _env:
- _chown(profile_name, int(_env['SUDO_UID']), int(_env['SUDO_GID']))
- if not _exists(_join(profile_name, "keys")):
- _mkdir(_join(profile_name, "keys"))
- if "SUDO_USER" in _env:
- _chown(_join(profile_name, "keys"), int(_env['SUDO_UID']), int(_env['SUDO_GID']))
- def _write_profile(profile_name: str):
- if profile_name.endswith(".toml"):
- profile_name = profile_name.removesuffix(".toml")
- _profile_pre_check(profile_name)
- with open(_join(profile_name, profile_name+".toml"), "w") as f:
- f.writelines("\n".join([
- '# Tyrell :: v0.1-dev :: More human than human',
- '',
- '# Placeholders',
- '',
- "# Enable '{name}', emitting profile name",
- "placeholder_name = 'true'",
- '',
- '# Tick speed',
- '# Value in milliseconds',
- "# Defaults to 20 ticks per second",
- "# Can't be overridden",
- 'tick = 50',
- '',
- '# What is the key to activate/deactivate Tyrell',
- "# This hotkey must be in the format, 'ctrl+shift+a' (user holds ctrl, shift and 'a' at once)",
- "# Can't be overridden",
- "activator = '`'",
- '',
- '# What is the key to display help',
- "# This hotkey must be in the format, 'ctrl+shift+a' (user holds ctrl, shift and 'a' at once)",
- "# Defaults to '?'",
- "# Can't be overridden",
- "helper = 'shift+/'",
- '',
- '# These can be overridden per key-bind',
- '',
- '# Delay between each keys',
- '# Value in milliseconds',
- 'delay = 50',
- '',
- '# Hold delay for each key',
- '# Keys are sent like below:',
- '# 1. key down',
- '# 2. hold delay',
- '# 3. key up',
- '# 4. hold delay',
- '# 5. delay (see above)',
- '# 6. Repeat for keys',
- '# Value in milliseconds',
- 'hold = 20',
- ]))
- if "SUDO_USER" in _env:
- _chown(_join(profile_name, profile_name+".toml"), int(_env['SUDO_UID']), int(_env['SUDO_GID']))
- def _write_example(profile_name: str):
- if profile_name.endswith(".toml"):
- profile_name = profile_name.removesuffix(".toml")
- _profile_pre_check(profile_name)
- with open(_join(profile_name, "keys", "example.toml"), "w") as f:
- f.writelines("\n".join([
- '# Example Key-bind',
- '',
- "# When 'h' is pressed, write 'Hello World!'",
- '',
- '# Key to trigger on',
- "# This hotkey must be in the format, 'ctrl+shift+a' (user holds ctrl, shift and 'a' at once)",
- "key = 'h'",
- '',
- '# Kind of action to perform',
- '# click -> Click a mouse button',
- '# click down -> Click a mouse button down, but never release up',
- '# key -> Type the following keys, pressing each key',
- '# key down -> Press the following keys down, never releasing them',
- '# mirror -> When the mirror key is pressed down so is key or button, on release so are key or button',
- '# See also example_mirror.toml',
- "kind = 'key'",
- '',
- '# Type this',
- "# This is required for 'key' and 'key down' kinds (Optional for 'mirror')",
- "# This hotkey must be in the format, 'ctrl+shift+a' (user holds ctrl, shift and 'a' at once)",
- "# This example will write 'Hello World!'",
- "write = 'shift+h, e, l, l, o, space, shift+w, o, r, l, d, shift+1'",
- '',
- '# If this should repeat X number of ticks',
- "# This is a simple example, it won't use this",
- '# Assuming tick speed is 20ms, this would occur every second',
- '#duration = 50',
- '',
- '# Use this mouse button',
- "# This is a simple example, it won't use this",
- "# This is required for 'click' and 'click down' kinds (Optional for 'mirror')",
- "# There currently is 'left' or 'right'",
- "#button = 'left'",
- '',
- '# Mirror key',
- "# This is a simple example, it won't use this",
- '# This is the key whose state will be mirrored',
- '# See also example_mirror.toml',
- '#',
- "# This hotkey must be in the format, 'ctrl+shift+a' (user holds ctrl, shift and 'a' at once)",
- "# This example will press 'g' when 'h' is down, and release 'g' when 'h' is up",
- "#mirror = 'g'",
- '',
- '# Optional Overrides',
- '',
- '# Override delay between each keys',
- '# Value in milliseconds',
- 'delay = 50',
- '',
- '# Override hold delay for each key',
- '# Keys are sent like below:',
- '# 1. key down',
- '# 2. hold delay',
- '# 3. key up',
- '# 4. hold delay',
- '# 5. delay (see above)',
- '# 6. Repeat for keys',
- '# Value in milliseconds',
- 'hold = 20',
- ]))
- if "SUDO_USER" in _env:
- _chown(_join(profile_name, "keys", "example.toml"), int(_env['SUDO_UID']), int(_env['SUDO_GID']))
- def _write_example_mirror(profile_name: str):
- if profile_name.endswith(".toml"):
- profile_name = profile_name.removesuffix(".toml")
- _profile_pre_check(profile_name)
- with open(_join(profile_name, "keys", "example_mirror.toml"), "w") as f:
- f.writelines("\n".join([
- '# Example Mirror Key-bind',
- '',
- "# Press alt when 'w' is down, and release when 'w' is up",
- "# Use 'z' to toggle on/off",
- '',
- '# Key to toggle',
- "key = 'z'",
- '',
- '# Kind of event',
- "kind = 'mirror'",
- '',
- '# Mirror what key',
- "mirror = 'w'",
- '',
- '# When mirror is down, so will this',
- '# When mirror is up, so will this',
- "write = 'alt'",
- '',
- '# Or a mouse button could be configured',
- "# But this example doesn't",
- "#button = 'right'",
- '',
- '# You could override delay and hold',
- '# Tyrell will turn them off for Mirror kinds automatically',
- ]))
- if "SUDO_USER" in _env:
- _chown(_join(profile_name, "keys", "example_mirror.toml"), int(_env['SUDO_UID']), int(_env['SUDO_GID']))
- class Profile:
- name: str
- placeholders: _Dict[str, bool]
- tick: int
- delay: int
- hold: int
- activator: str
- helper: str
- def __init__(self, name: str):
- # Unify name without extension
- if name.endswith(".toml"):
- self.name = name.removesuffix(".toml")
- else:
- self.name = name
- # Pre-Check
- if not _exists(self.name):
- # Does not exist, new everything
- _write_profile(self.name)
- _write_example(self.name)
- _write_example_mirror(self.name)
- else:
- # Profile config?
- if not _exists(_join(self.name, self.name+".toml")):
- _write_profile(self.name)
- # Do we have keys?
- if not _exists(_join(self.name, "keys")):
- _write_example(self.name)
- _write_example_mirror(self.name)
- # Initial load
- self.reload()
-
- def reload(self):
- # Load toml config
- with open(_join(self.name, self.name+".toml"), "r") as f:
- dat = _toml_load(f)
- self.placeholders = {
- "name": False,
- }
- self.tick = 50
- self.activator = "`"
- self.helper = "shift+/"
- self.delay = 50
- self.hold = 20
- for key in dat:
- val = dat[key]
- if key.startswith("placeholder_"):
- if str(val) in ('true', 'TRUE', 'True', 'T', 't', 'yes', 'YES', 'Yes', 'Y', 'y', '1'):
- self.placeholders[key.removeprefix("placeholder_")] = True
- else:
- self.placeholders[key.removeprefix("placeholder_")] = False
- elif key == "tick":
- self.tick = int(val)
- elif key == "delay":
- self.delay = int(val)
- elif key == "hold":
- self.hold = int(val)
- elif key == "activator":
- self.activator = str(val)
- elif key == "helper":
- self.helper = str(val)
- if __name__ == "__main__":
- if not _exists("_example"):
- p = Profile("_example")
- exit()
- _print_ok("All okay")
|