123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594 |
- from sys import argv as _argv
- from os import name as _OS_NAME
- from os import listdir as _listdir
- 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
- 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()
- class ActionKind(int):
- """
- Actions can be defined to do different things
- Because of this complexity, Actions are separated into
- Mouse Actions:
- - Click (Press mouse button down, then release mouse button up)
- - Click Down (Press mouse button down, never releasing up)
- Keyboard Actions:
- - Key (Press key down, then release key up)
- - Key Down (Press key down, never releasing up)
- Mirror Actions will typically be one of the above (mouse or keyboard actions, typically Click or Key)
- They Mirror a key's state, if it's down: pressing or clicking down, if it's up: releasing up
- """
- NONE = 0
- """ Invalid Action state """
- CLICK = 1
- """ Mouse Action, Click (Press mouse button down, then release mouse button up) """
- CLICK_DOWN = 2
- """ Mouse Action, Click Down (Press mouse button down, never releasing up) """
- KEY = 3
- """ Keyboard Action, Key (Press key down, then release key up) """
- KEY_DOWN = 4
- """ Keyboard Action, Key Down (Press key down, never releasing up) """
- MIRROR = 5
- """ Mirror Actions will typically be one of the above (mouse or keyboard actions, typically Click or Key)
- They Mirror a key's state, if it's down: pressing or clicking down, if it's up: releasing up
- """
- def __init__(self, kind: str | int):
- # Unlike most __init__ methods, this converts a string into a ActionKind (returning the ActionKind)
- if type(kind) is str:
- k = kind.lower().strip()
- if k == "click":
- return ActionKind.CLICK
- elif k == "click down":
- return ActionKind.CLICK_DOWN
- elif k == "key":
- return ActionKind.KEY
- elif k == "key down":
- return ActionKind.KEY_DOWN
- elif k == "mirror":
- return ActionKind.MIRROR
- else:
- return ActionKind.NONE
- elif type(kind) is int:
- if kind == 1:
- return ActionKind.CLICK
- elif kind == 2:
- return ActionKind.CLICK_DOWN
- elif kind == 3:
- return ActionKind.KEY
- elif kind == 4:
- return ActionKind.KEY_DOWN
- elif kind == 5:
- return ActionKind.MIRROR
- else:
- return ActionKind.NONE
-
- def __str__(self) -> str:
- # Converts the ActionKind into a string, mostly for debugging
- if self == ActionKind.CLICK:
- return "click"
- elif self == ActionKind.CLICK_DOWN:
- return "click down"
- elif self == ActionKind.KEY:
- return "key"
- elif self == ActionKind.KEY_DOWN:
- return "key down"
- elif self == ActionKind.MIRROR:
- return "mirror"
- else:
- return f"<ActionKind {int(self)}>"
-
- def is_mouse(self) -> bool:
- """ Is this Action a Mouse Action
- Mouse Actions:
- - Click (Press mouse button down, then release mouse button up)
- - Click Down (Press mouse button down, never releasing up)
- """
- return self == ActionKind.CLICK or self == ActionKind.CLICK_DOWN
-
- def is_keyboard(self) -> bool:
- """ Is this Action a Keyboard Action
-
- Keyboard Actions:
- - Key (Press key down, then release key up)
- - Key Down (Press key down, never releasing up)
- """
- return self == ActionKind.KEY or self == ActionKind.KEY_DOWN
- class Action:
- name: str
- """ Action's can be named to describe and clarify what the Action should do
- i.e. 'auto click' for some Auto Clicker, 'shop' for something that opens a shop (such as '/shop')
- """
- kind: ActionKind
- """ The Kind of Action to do
- See tyrell.ActionKind
- """
- extra: _Dict
- enabled: bool
- delay: int
- max_delay: int
- def __init__(self, name: str, kind: str, extra: _Dict, on: bool=False, delay: int=0):
- self.name = name
- self.kind = ActionKind(kind)
- self.enabled = on
- self.delay = delay
- self.max_delay = delay
-
- def toggle(self) -> bool:
- self.enabled = not self.enabled
- return self.enabled
-
- def enable(self):
- self.enabled = True
-
- def disable(self):
- self.enabled = False
- def is_ticker(self) -> bool:
- """ Actions can be time based or not
- Tickers are: Actions time based will fire after a number of ticks (at a set delay, tick speed)
- All Actions not time based fire only when the selected "keybind" is pressed (where tickers use the "keybind" to toggle them on and off)
- """
- return self.max_delay != 0
-
- def is_mirror(self, key: str) -> bool:
- if self.kind != ActionKind.MIRROR:
- return False
- return key == self.extra["mirror"]
-
- def tick(self) -> bool:
- if not self.is_ticker():
- return False
- if not self.enabled:
- if self.delay != self.max_delay:
- self.delay = self.max_delay
- return False
- self.delay -= 1
- if self.delay <= 0:
- self.delay = self.max_delay
- return True
- return False
-
- def do(self, key: _Tuple[str, int], delay: int=50, hold: int=20):
- if not self.enabled:
- return
- d = delay
- h = hold
- if "delay" in self.extra:
- d = self.extra["delay"]
- if "hold" in self.extra:
- h = self.extra["hold"]
- if self.kind == ActionKind.CLICK:
- _mouse_output(self.extra["button"], d, h)
- elif self.kind == ActionKind.CLICK_DOWN:
- _mouse_down(button=self.extra["button"])
- elif self.kind == ActionKind.KEY:
- _keyboard_output(self.extra["write"], d, h)
- elif self.kind == ActionKind.KEY_DOWN:
- _key_down(self.extra["write"])
- elif self.kind == ActionKind.MIRROR:
- if key[1] == 0: # Up
- if "write" in self.extra: # Key Mirror
- _key_up(self.extra["write"])
- elif "button" in self.extra: # Mouse Mirror
- _mouse_up(button=self.extra["button"])
- elif key[1] == 1: # Down
- if "write" in self.extra: # Key Mirror
- _key_down(self.extra["write"])
- elif "button" in self.extra: # Mouse Mirror
- _mouse_down(button=self.extra["button"])
-
- def do_tick(self, delay: int=50, hold: int=20):
- if self.tick():
- self.do(delay, hold)
- class Tyrell:
- pass
- class OldAction():
- name: str
- kind: str
- extra: _Dict
- toggled: bool
- delay: int
- max_delay: int
- def __init__(self, name, kind, extra=None, toggled=False, delay=0):
- self.name = name
- self.kind = kind
- if extra is not None:
- self.extra = extra
- else:
- self.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 OldTyrell():
- keybinds: _Dict[str, OldAction]
- mirrors: _Dict[str, str] # mirror key -> key in keybinds
- toggled: bool
- delay: int
- hold: int
- def __init__(self, profile_name: str):
- self.profile = {
- "activator": "`",
- "helper": "?",
- "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 not _exists(self.name) or not _isdir(self.name):
- print_err(f"Invalid profile '{self.name}'")
- print_info(f"This should be a directory")
- exit()
- profile_config = _join(self.name, self.name+".toml")
- if _exists(profile_config):
- with open(profile_config, "r") as f:
- try:
- t = _toml_load(f)
- except Exception as err:
- print_err(f"Invalid profile '{self.name}'")
- print_info(f"Invalid '{self.name+'.toml'}' config")
- print(err)
- exit()
- self.profile = t
- if "activator" not in self.profile:
- self.profile["activator"] = "`"
- if "helper" not in self.profile:
- self.profile["helper"] = "?"
- 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}'")
- print_info(f"Missing '{self.name+'.toml'}' config")
- exit()
- self.delay = self.profile["delay"]
- self.hold = self.profile["hold"]
- self.keybinds = {}
- self.mirrors = {}
- self.toggled = False
- if not _exists(_join(self.name, 'keys')):
- print_err(f"Invalid profile '{self.name}'")
- print_info("Missing 'keys' directory (for keybinds)")
- exit()
- else:
- for ent in _listdir(_join(self.name, "keys")):
- if ent.startswith(".") or _isdir(ent) or not ent.endswith(".toml"):
- continue
- with open(_join(self.name, "keys", ent), "r") as f:
- t = _toml_load(f)
- if t["keybind"] == "?" or t["keybind"] == "`":
- continue
- if "duration" in t:
- self.add_action(t["keybind"], OldAction(ent.removesuffix(".toml"), t["kind"], extra=t, delay=t["duration"]))
- else:
- self.add_action(t["keybind"], OldAction(ent.removesuffix(".toml"), t["kind"], extra=t))
- 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: OldAction):
- 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)
- if act.kind == "mirror" and "mirror" in act.extra:
- self.mirrors[act.extra["mirror"]] = bind
- 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 print_help(self):
- print_ok(f"{int(1000 / self.profile['tick'])} ticks per second ({self.profile['tick']} ms per tick)")
- print_ok(f"Name placeholder: {self.profile['placeholder_name']}")
- print_warn(f"{self.profile['activator']} -> Activate/Deactivate")
- print_warn(f"{self.profile['helper']} -> Displays Help")
- for key in self.keybinds:
- act = self.keybinds[key]
- if act.max_delay == 0 and act.toggled:
- print_info(f"{key} -> {act.name}")
- else:
- print_info(f"{key} -> {act.name} = {act.toggled} ({act.max_delay} ticks)")
- print_ok("Please use " + _style("CTRL+C", fg="bright_yellow") + " to stop")
- 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: KeyboardEvent):
- # key_name = event.name
- # #if key_name in self.mirrors:
- # # # key mirrors currently lag
- # # act = self.keybinds[self.mirrors[key_name]]
- # # if act.toggled:
- # # if "write" in act.extra:
- # # if event.event_type == "down":
- # # key_down(act.extra["write"])
- # # else:
- # # key_up(act.extra["write"])
- # # elif "button" in act.extra:
- # # if event.event_type == "down":
- # # mouse_down(button=act.extra["button"])
- # # else:
- # # mouse_up(button=act.extra["button"])
- # #if event.event_type == "up":
- # if key_name == self.profile["activator"]:
- # if self.toggle():
- # print_ok("ON")
- # else:
- # print_ok("OFF")
- # elif self.toggled:
- # #print(f"Name: {event.name}")
- # #print(f"Code: {event.scan_code}")
- # #print(f"Modifiers: {event.modifiers}")
- # if self.profile["helper"] == "?" and "shift" in event.modifiers and event.name == "/" or key_name == self.profile["helper"]:
- # self.print_help()
- # elif 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()
- # print_ok("OFF")
- def callback(self, bind, state=None, mirror_host=None):
- if bind == "__toggle__":
- if self.toggle():
- print_info(_style("ON", fg="bright_green"))
- else:
- print_info(_style("OFF", fg="bright_red"))
- return
- if state == "up" or state == "down":
- act = self.keybinds[mirror_host]
- if act.toggled:
- if act.extra["write"] != None or len(act.extra["write"]) != 0:
- if state == "up":
- print(f"'{bind}' -> {act.name} UP")
- _key_up(act.extra["write"])
- elif state == "down":
- print(f"'{bind}' -> {act.name} DOWN")
- _key_down(act.extra["write"])
- elif act.extra["button"] != None or len(act.extra["button"]) != 0:
- if state == "up":
- print(f"'{bind}' -> {act.name} UP")
- _mouse_up(button=act.extra["button"])
- elif state == "down":
- print(f"'{bind}' -> {act.name} DOWN")
- _mouse_down(button=act.extra["button"])
- return
- if not self.toggled:
- return
- if bind == "__help__":
- self.print_help()
- self.disable()
- print_info(_style("OFF", fg="bright_red"))
- return
- act = self.keybinds[bind]
- if act.toggled:
- print(f"'{bind}' -> {act.name}")
- act.do(self.delay, self.hold)
- elif act.max_delay != 0 or act.kind == "mirror":
- if act.toggle():
- print(f"'{bind}' -> {act.name} " + _style("ON", fg="bright_green"))
- else:
- print(f"'{bind}' -> {act.name} " + _style("OFF", fg="bright_red"))
- self.disable()
- print_info(_style("OFF", fg="bright_red"))
- 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)
- _add_hotkey(41, self.callback, args=["__toggle__"])
- _add_hotkey("shift+?", self.callback, args=["__help__"])
- for bind in self.keybinds:
- act = self.keybinds[bind]
- if act.kind == "key" or act.kind == "key down":
- print(f"hotkey -=> {bind}")
- _add_hotkey(bind, self.callback, args=[bind])
- elif act.kind == "mirror":
- print(f"hotkey -=> {bind} (mirror {act.extra['mirror']})")
- _add_hotkey(bind, self.callback, args=[bind])
- _add_hotkey(bind, self.callback, args=[act.extra["mirror"], "down", bind])
- _add_hotkey(bind, self.callback, args=[act.extra["mirror"], "up", bind], trigger_on_release=True)
- 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 = OldTyrell(",".join(_argv[1:]))
- if len(ty.keybinds) == 0:
- print_err("Missing keybinds")
- print_info("(Might want some keybinds, place them in a 'keys' directory)")
- print_info(f"( Need an example? Look at '{_join('_example', 'keys', 'example.toml')}')")
- exit()
- ty.enable(all_notickers=True)
- ty.disable()
- ty.print_help()
- if ty.name == "_example":
- print_warn("This is the " + _style("example", fg="bright_yellow") + ", please define you're own profile")
- print_info("Please DO NOT EDIT this example profile")
- try:
- _run(ty.mainloop())
- except KeyboardInterrupt:
- exit()
|