123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- from sys import exit, argv
- from os import name as OS_NAME
- from os import listdir
- from os.path import exists, join, isdir
- from time import sleep
- from typing import Dict
- try:
- from click import echo, 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, on_release as keyboard_hook
- # 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, sleep as asleep
- from asyncio.tasks import gather as task_group
- def print_err(msg):
- echo(style("ERROR", fg="bright_red") + " " + msg)
- def print_warn(msg):
- echo(style("WARN ", fg="bright_yellow") + " " + msg)
- def print_ok(msg):
- echo(style(" OK ", fg="bright_green") + " " + msg)
- def print_info(msg):
- print(" " + msg)
- def keyboard_output(msg: str, delay: int=50, hold: int=20):
- for k in msg:
- if k.isupper():
- k = k.lower()
- key_down('shift')
- key_down(k)
- sleep(hold / 1000)
- key_up(k)
- key_up('shift')
- sleep(hold / 1000)
- elif k in ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')']:
- m = {'!': '1', '@': '2', '#': '3', '$': '4', '%': '5', '^': '6', '&': '7', '*': '8', '(': '9', ')': '0'}
- key_down('shift')
- key_down(m[k])
- sleep(hold / 1000)
- key_up(m[k])
- key_up('shift')
- sleep(hold / 1000)
- elif k in ['\r', '\n']:
- m = {'\r': 'enter', '\n': 'enter'}
- key_down(m[k])
- sleep(hold / 1000)
- key_up(m[k])
- sleep(hold / 1000)
- else:
- key_down(k)
- sleep(hold / 1000)
- key_up(k)
- sleep(hold / 1000)
- 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()
- class Action():
- kind: str
- extra: Dict
- toggled: bool
- delay: int
- max_delay: int
- def __init__(self, kind, extra=None, toggled=False, delay=0):
- self.kind = kind
- self.extra = extra
- self.toggled = toggled
- self.delay = delay
- self.max_delay = delay
- def toggle(self) -> bool:
- self.toggled = not self.toggled
- return self.toggled
- def tick(self) -> bool:
- if not self.toggled:
- if self.delay != self.max_delay:
- self.delay = self.max_delay
- return False
- if self.max_delay != 0:
- self.delay -= 1
- if self.delay <= 0:
- self.delay = self.max_delay
- return True
- return False
- def do(self, delay: int=50, hold: int=20):
- if not self.toggled:
- return
- d = delay
- h = hold
- if self.extra is not None:
- if "delay" in self.extra:
- d = self.extra["delay"]
- if "hold" in self.extra:
- h = self.extra["hold"]
- if self.kind == "click":
- mouse_output(self.extra["button"], d, h)
- elif self.kind == "click down":
- mouse_down(self.extra["button"])
- elif self.kind == "key":
- keyboard_output(self.extra["write"], d, h)
- elif self.kind == "key down":
- key_down(self.extra["write"])
- class Tyrell():
- keybinds: Dict[str, Action]
- toggled: bool
- delay: int
- hold: int
- def __init__(self, profile_name: str):
- self.profile = {
- "delay": 50,
- "hold": 20,
- "tick": 50,
- "placeholder_name": False,
- }
- self.name = profile_name
- if profile_name.endswith(".toml"):
- self.name = profile_name.removesuffix(".toml")
- if exists(self.name+".toml"):
- with open(self.name+".toml", "r") as f:
- try:
- t = toml_load(f)
- except Exception as err:
- print_err(f"Invalid profile '{self.name+'.toml'}'")
- print(err)
- exit()
- self.profile = t
- if "hold" not in self.profile:
- self.profile["hold"] = 20
- if "delay" not in self.profile:
- self.profile["delay"] = 50
- if "tick" not in self.profile:
- self.profile["tick"] = 50
- if "placeholder_name" not in self.profile:
- self.profile["placeholder_name"] = False
- else:
- print_err(f"Invalid profile '{self.name+'.toml'}'")
- exit()
- self.delay = self.profile["delay"]
- self.hold = self.profile["hold"]
- self.keybinds = {}
- self.toggled = False
- def toggle(self, all: bool=False, all_tickers: bool=False, all_notickers: bool=False) -> bool:
- self.toggled = not self.toggled
- if all:
- for key in self.keybinds:
- act = self.keybinds[key]
- act.toggle()
- elif all_tickers:
- for key in self.keybinds:
- act = self.keybinds[key]
- if act.max_delay != 0:
- act.toggle()
- elif all_notickers:
- for key in self.keybinds:
- act = self.keybinds[key]
- if act.max_delay == 0:
- act.toggle()
- return self.toggled
- def disable(self, all: bool=False, all_tickers: bool=False, all_notickers: bool=False):
- self.toggled = False
- if all:
- for key in self.keybinds:
- act = self.keybinds[key]
- act.toggled = False
- elif all_tickers:
- for key in self.keybinds:
- act = self.keybinds[key]
- if act.max_delay != 0:
- act.toggled = False
- elif all_notickers:
- for key in self.keybinds:
- act = self.keybinds[key]
- if act.max_delay == 0:
- act.toggled = False
- def enable(self, all: bool=False, all_tickers: bool=False, all_notickers: bool=False):
- self.toggled = True
- if all:
- for key in self.keybinds:
- act = self.keybinds[key]
- act.toggled = True
- elif all_tickers:
- for key in self.keybinds:
- act = self.keybinds[key]
- if act.max_delay != 0:
- act.toggled = True
- elif all_notickers:
- for key in self.keybinds:
- act = self.keybinds[key]
- if act.max_delay == 0:
- act.toggled = True
- def add_action(self, bind: str, act: Action):
- act.toggled = False
- if "placeholder_name" in self.profile:
- if self.profile["placeholder_name"] and "write" in act.extra:
- act.extra["write"] = act.extra["write"].replace("{name}", self.name)
- self.keybinds[bind] = act
- def remove_action(self, bind: str):
- self.keybinds[bind] = None
- def is_action(self, bind: str) -> bool:
- return self.keybinds[bind] is not None
- def tick(self):
- for key in self.keybinds:
- act = self.keybinds[key]
- if act.tick():
- act.do(self.delay, self.hold)
- def callback(self, event):
- key_name = event.name
- if key_name == "`":
- if self.toggle():
- print_ok("ON")
- else:
- print_ok("OFF")
- elif self.toggled:
- if key_name in self.keybinds:
- act = self.keybinds[key_name]
- if act.max_delay == 0 and act.toggled:
- print_info(f"{key_name} -> {act.kind}")
- act.do(self.delay, self.hold)
- else:
- print_info(f"{key_name} -> {act.kind} = {act.toggle()}")
- self.toggle()
- async def background(self):
- while True:
- self.tick()
- await asleep(self.profile["tick"] / 1000) # 50 ms (20 per second, same as Minecraft)
- async def mainloop(self):
- keyboard_hook(self.callback)
- await task_group(
- self.background()
- )
- if __name__ == "__main__":
- if len(argv) == 1:
- print_err("Missing profile filename")
- print_info("Example: 'tyrell.py Apollo' would look for 'Apollo.toml'")
- print()
- print_info("Profiles allow you to add placeholders,")
- print_info("And defines in a \"global\" sense key delay and hold delay.")
- print()
- exit()
- ty = Tyrell(",".join(argv[1:]))
- if not exists("keys"):
- print_err("Missing 'keys' directory")
- print_info("(Might want some keybinds)")
- exit()
- for ent in listdir("keys"):
- if ent.startswith(".") or not ent.endswith(".toml") or isdir(ent):
- continue
- with open(join("keys", ent), "r") as f:
- t = toml_load(f)
- if "duration" in t:
- ty.add_action(t["keybind"], Action(t["kind"], extra=t, delay=t["duration"]))
- else:
- ty.add_action(t["keybind"], Action(t["kind"], extra=t))
- print(f"{t['keybind']} -> {t['kind']}")
- if len(ty.keybinds) == 0:
- print_err("Missing keybinds")
- print_info("(Might want some keybinds, place them in a 'keys' directory)")
- print_info("( Need an example? Look at 'example.toml')")
- exit()
- ty.enable(all_notickers=True)
- ty.disable()
- try:
- run(ty.mainloop())
- except KeyboardInterrupt:
- exit()
|