Ver Fonte

Project rewrite

I've officially decided to redesign/rewrite the entire project

It's ok, old code still exists in git, but the newer better code won't
clutter my mind as I redesign it to support the better hotkey format
apollo há 6 dias atrás
pai
commit
d2149b7b7a
4 ficheiros alterados com 309 adições e 636 exclusões
  1. 28 24
      _example/_example.toml
  2. 36 57
      _example/keys/example.toml
  3. 14 24
      _example/keys/example_mirror.toml
  4. 231 531
      tyrell.py

+ 28 - 24
_example/_example.toml

@@ -1,36 +1,40 @@
+# Tyrell :: v0.1-dev :: More human than human
 
 # Placeholders
 
-# Use '{name}' to emit profile name
-placeholder_name = false
-
-# Default Features
+# Enable '{name}', emitting profile name
+placeholder_name = 'true'
 
 # Tick speed
 # Value in milliseconds
-# Defaults to Minecraft's Tick speed (20 ticks per second, 50 ms)
-#
-# This can't be overridden
+# Defaults to 20 ticks per second
+# Can't be overridden
 tick = 50
 
-# Delay in-between keys
+# 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
-#
-# Can be overridden per keybind
 delay = 50
 
-# Hold delay of each key
+# 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
-#
-# Can be overridden per keybind
-hold = 20
-
-# What is the key to activate/deactivate macro
-# This value should be adjusted as needed
-#
-activator = "`"
-
-# What is the key to redisplay "help"
-# Should be adjusted as needed
-#
-helper = "?"
+hold = 20

+ 36 - 57
_example/keys/example.toml

@@ -1,71 +1,50 @@
+# Example Key-bind
 
-# Example Keybind, aka Main Keybind Docs
-#
-# When H is pressed, write "Hello World!"
+# When 'h' is pressed, write 'Hello World!'
 
-# Keybind to trigger on
-# The hotkey must be in the format "ctrl+shift+a, s".
-# This would trigger when the user holds ctrl, shift and "a" at once, releases, and then presses "s".
-# To represent literal commas, pluses, and spaces, use their names ('comma', 'plus', 'space').
-#
-keybind = "h"
+# 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
-# key        ->  Type the following keys (pressing each key)
-# click down ->  Click and never release a mouse button
-# key down   ->  Press the following keys (never releasing them)
-# mirror     ->  When the "mirror" key is pressed fire this keybind also (While the mirror key is down this bind is active, when up, bind is inactive)
+# 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"
+kind = 'key'
 
-# << Optional >>
+# 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'
 
-# Write this out
-# This is required for 'key' and 'key down' kinds (Optional in 'mirror' kinds)
-# The hotkey must be in the format "ctrl+shift+a, s".
-# This would trigger when the user holds ctrl, shift and "a" at once, releases, and then presses "s".
-# To represent literal commas, pluses, and spaces, use their names ('comma', 'plus', 'space').
-#
-# This example: "shift+h, e, l, l, o, space, shift+w, o, r, l, d, shift+1" translates to "Hello World!"
-#
-write = "shift+h, e, l, l, o, space, shift+w, o, r, l, d, shift+1"
-
-# This is commented out because the example doesn't do a repeated thing
-# If this should repeat, like an auto clicker
-# Simply define a duration between clicks (this runs at 20 milliseconds, so 1 full second is 50)
-#
+# 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
 
-# This is commented out so this example works
-# Use this Button
-# This is required for 'click' and 'click down' kinds (Optional in 'mirror' kinds)
-# There is 'left' and 'right'
-#
-#button = "left"
+# 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'
 
-# This is commented out because the example isn't a 'mirror' kind
-# This is the key that will be mirrored (It's down or up states will be mirrored in write or button as defined above)
+# 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
 #
-# The hotkey must be in the format "ctrl+shift+a, s".
-# This would trigger when the user holds ctrl, shift and "a" at once, releases, and then presses "s".
-# To represent literal commas, pluses, and spaces, use their names ('comma', 'plus', 'space').
-#
-# This example: "g" will press the "g" key down when "h" is down, and release "g" when "h" is up
-#
-#mirror = "g"
+# 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'
 
-# << Override >>
+# Optional Overrides
 
-# The below values are set to their defaults
-# These are optional, and only used for this keybind
-
-# Override delay between each key
-# This is how long to wait after sending a key
-# Value in milliseconds (1000/second)
-#
+# Override delay between each keys
+# Value in milliseconds
 delay = 50
 
 # Override hold delay for each key
@@ -75,6 +54,6 @@ delay = 50
 # 3. key up
 # 4. hold delay
 # 5. delay (see above)
-# Value in milliseconds (1000/second)
-#
-hold = 20
+# 6. Repeat for keys
+# Value in milliseconds
+hold = 20

+ 14 - 24
_example/keys/example_mirror.toml

@@ -1,34 +1,24 @@
+# Example Mirror Key-bind
 
-# Mirror exmaple
-#
-# Press Alt when W is down, and release Alt when W is up
-#
-# Use Z to toggle on and off
+# Press alt when 'w' is down, and release when 'w' is up
+# Use 'z' to toggle on/off
 
-# key to toggle
-keybind = "z"
+# Key to toggle
+key = 'z'
 
-# kind of event
-kind = "mirror"
+# Kind of event
+kind = 'mirror'
 
 # Mirror what key
-mirror = "w"
+mirror = 'w'
 
 # When mirror is down, so will this
 # When mirror is up, so will this
-#
-# In this case, alt will be held down when w is (only when toggled on)
-write = "alt"
+write = 'alt'
 
-# Or button could be configured
-#
-# For example: right click when w (down when w is, up when w is)
-#button = "right"
+# Or a mouse button could be configured
+# But this example doesn't
+#button = 'right'
 
-# << REQUIRED >>
-
-# This is needed for "mirror" kinds
-# We don't want delays, so make sure you turn everything off!
-#
-delay = 0
-hold = 0
+# You could override delay and hold
+# Tyrell will turn them off for Mirror kinds automatically

+ 231 - 531
tyrell.py

@@ -1,13 +1,13 @@
 
 from sys import argv as _argv
 
-from os import name as _OS_NAME
-from os import listdir as _listdir
+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
+from typing import Dict as _Dict, Tuple as _Tuple, List as _List
 
 try:
     from click import echo as _echo, style as _style
@@ -25,16 +25,16 @@ 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):
+def _print_err(msg: str):
     _echo(_style("ERROR", fg="bright_red") + " " + msg)
 
-def print_warn(msg: str):
+def _print_warn(msg: str):
     _echo(_style("WARN ", fg="bright_yellow") + " " + msg)
 
-def print_ok(msg: str):
+def _print_ok(msg: str):
     _echo(_style(" OK  ", fg="bright_green") + " " + msg)
 
-def print_info(msg: str):
+def _print_info(msg: str):
     print("      " + msg)
 
 def _keyboard_output(msg: str, delay: int=50, hold: int=20):
@@ -57,538 +57,238 @@ elif "windows" in os_name or "nt" in os_name:
 elif "darwin" in os_name:
     platform = "MACOS"
 else:
-    print_err("Platform 'Linux', 'Windows' or 'MacOS' expected")
-    print_info(f"Platform: {_OS_NAME}")
+    _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():
+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
-    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
+    placeholders: _Dict[str, bool]
+    tick: int
     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
+    activator: str
+    helper: str
+    def __init__(self, name: str):
+        # Unify name without extension
+        if name.endswith(".toml"):
+            self.name = name.removesuffix(".toml")
         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()
+            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:
-            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"]))
+            # 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.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()
-        )
+                        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 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:
+    if not _exists("_example"):
+        p = Profile("_example")
         exit()
+    _print_ok("All okay")