|
@@ -7,7 +7,7 @@ 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
|
|
|
+from typing import Dict as _Dict, Tuple as _Tuple, List as _List, Optional as _Option, Any as _Any
|
|
|
|
|
|
try:
|
|
|
from click import echo as _echo, style as _style
|
|
@@ -15,16 +15,6 @@ 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)
|
|
|
|
|
@@ -37,16 +27,10 @@ def _print_ok(msg: str):
|
|
|
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)
|
|
|
+from pyautogui import LEFT as _LEFT, RIGHT as _RIGHT, MIDDLE as _MIDDLE
|
|
|
+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
|
|
|
|
|
|
-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)
|
|
|
+_BUTTON_MAP: _Dict[str | int, int] = {_LEFT: 1, _MIDDLE:3, _RIGHT: 3, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7}
|
|
|
|
|
|
platform: str = ""
|
|
|
os_name = _OS_NAME.lower()
|
|
@@ -61,6 +45,46 @@ else:
|
|
|
_print_info(f"Platform: {_OS_NAME}")
|
|
|
exit()
|
|
|
|
|
|
+if platform == 'LINUX':
|
|
|
+ # It appears those under LINUX, either don't work or work but play with mouse position
|
|
|
+ from Xlib.display import Display as _Display
|
|
|
+ _display = _Display(_env['DISPLAY'])
|
|
|
+ from Xlib.X import ButtonPress as _ButtonPress, ButtonRelease as _ButtonRelease
|
|
|
+ from Xlib.ext.xtest import fake_input as _fake_input
|
|
|
+ def _mouse_down(button: str | int=_LEFT):
|
|
|
+ assert button in _BUTTON_MAP.keys(), "button argument not in ('left', 'middle', 'right', 1, 2, 3, 4, 5, 6, 7)"
|
|
|
+ btn = _BUTTON_MAP[button]
|
|
|
+ _fake_input(_display, _ButtonPress, btn)
|
|
|
+ _display.sync()
|
|
|
+ def _mouse_up(button: str | int=_LEFT):
|
|
|
+ assert button in _BUTTON_MAP.keys(), "button argument not in ('left', 'middle', 'right', 1, 2, 3, 4, 5, 6, 7)"
|
|
|
+ btn = _BUTTON_MAP[button]
|
|
|
+ _fake_input(_display, _ButtonRelease, btn)
|
|
|
+ _display.sync()
|
|
|
+ def _click(button: str|int=_LEFT):
|
|
|
+ assert button in _BUTTON_MAP.keys(), "button argument not in ('left', 'middle', 'right', 1, 2, 3, 4, 5, 6, 7)"
|
|
|
+ _mouse_down(button)
|
|
|
+ _mouse_up(button)
|
|
|
+else:
|
|
|
+ # We can simply use the mouse module under WINDOWS and MACOS
|
|
|
+ from mouse import press as _mouse_down, release as _mouse_up, click as _click
|
|
|
+
|
|
|
+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 _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)
|
|
|
+
|
|
|
def _profile_pre_check(profile_name: str):
|
|
|
if profile_name.endswith(".toml"):
|
|
|
profile_name = profile_name.removesuffix(".toml")
|
|
@@ -133,6 +157,10 @@ def _write_example(profile_name: str):
|
|
|
'',
|
|
|
"# When 'h' is pressed, write 'Hello World!'",
|
|
|
'',
|
|
|
+ '# Do we want this key-bind active on start-up',
|
|
|
+ "# This is a simple example, it won't use this",
|
|
|
+ '#startup = true',
|
|
|
+ '',
|
|
|
'# Key to trigger on',
|
|
|
"# This hotkey must be in the format, 'ctrl+shift+a' (user holds ctrl, shift and 'a' at once)",
|
|
|
"key = 'h'",
|
|
@@ -203,6 +231,10 @@ def _write_example_mirror(profile_name: str):
|
|
|
"# Press alt when 'w' is down, and release when 'w' is up",
|
|
|
"# Use 'z' to toggle on/off",
|
|
|
'',
|
|
|
+ '# Do we want this key-bind active on start-up',
|
|
|
+ "# This is a simple example, it won't use this",
|
|
|
+ '#startup = true',
|
|
|
+ '',
|
|
|
'# Key to toggle',
|
|
|
"key = 'z'",
|
|
|
'',
|
|
@@ -226,6 +258,63 @@ def _write_example_mirror(profile_name: str):
|
|
|
if "SUDO_USER" in _env:
|
|
|
_chown(_join(profile_name, "keys", "example_mirror.toml"), int(_env['SUDO_UID']), int(_env['SUDO_GID']))
|
|
|
|
|
|
+class Action:
|
|
|
+ # Toggle to determine if this action is 'on' or 'off'
|
|
|
+ state: bool
|
|
|
+ # Key to trigger on (toggle on mirror)
|
|
|
+ key: str
|
|
|
+ # Kind of action to perform ('click', 'click down', 'key', 'key down', 'mirror')
|
|
|
+ kind: str
|
|
|
+ # Optional, keys to send
|
|
|
+ write: _Option[str]
|
|
|
+ # Optional, Repeat X number of ticks
|
|
|
+ duration: _Option[int]
|
|
|
+ # Optional, mouse button to send
|
|
|
+ button: _Option[str]
|
|
|
+ # Optional, Key to mirror
|
|
|
+ mirror: _Option[str]
|
|
|
+ # Optional, Override, Delay between each key (in milliseconds)
|
|
|
+ delay: _Option[int]
|
|
|
+ # Optional, Override, Hold delay for each key (in milliseconds)
|
|
|
+ hold: _Option[int]
|
|
|
+ def __init__(self, data: _Dict[str, _Option[_Any]]):
|
|
|
+ # Validate data!
|
|
|
+ assert 'key' in data, "Action missing 'key'"
|
|
|
+ assert 'kind' in data, "Action missing 'kind'"
|
|
|
+ assert data['kind'] in ('click', 'click down', 'key', 'key down', 'mirror'), f"Action 'kind' is unsupported, got '{data['kind']}'"
|
|
|
+ assert 'write' in data or 'button' in data, "Action missing 'write' or 'button' (one needed)"
|
|
|
+ # Assign class data
|
|
|
+ if 'startup' in data:
|
|
|
+ self.state = True
|
|
|
+ else:
|
|
|
+ self.state = False
|
|
|
+ self.key = str(data['key'])
|
|
|
+ self.kind = str(data['kind'])
|
|
|
+ if 'write' in data:
|
|
|
+ self.write = str(data['write'])
|
|
|
+ else:
|
|
|
+ self.write = None
|
|
|
+ if 'button' in data:
|
|
|
+ self.button = str(data['button'])
|
|
|
+ else:
|
|
|
+ self.button = None
|
|
|
+ if 'mirror' in data:
|
|
|
+ self.mirror = str(data['mirror'])
|
|
|
+ else:
|
|
|
+ self.mirror = None
|
|
|
+ if 'duration' in data:
|
|
|
+ self.duration = int(data['duration'])
|
|
|
+ else:
|
|
|
+ self.duration = None
|
|
|
+ if 'delay' in data:
|
|
|
+ self.delay = int(data['delay'])
|
|
|
+ else:
|
|
|
+ self.delay = None
|
|
|
+ if 'hold' in data:
|
|
|
+ self.hold = int(data['hold'])
|
|
|
+ else:
|
|
|
+ self.hold = None
|
|
|
+
|
|
|
class Profile:
|
|
|
name: str
|
|
|
placeholders: _Dict[str, bool]
|
|
@@ -289,6 +378,8 @@ class Profile:
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
if not _exists("_example"):
|
|
|
+ _print_warn("Missing '_example' profile, creating...")
|
|
|
p = Profile("_example")
|
|
|
+ _print_ok("")
|
|
|
exit()
|
|
|
_print_ok("All okay")
|