Подписывайтесь на наш Telegram и не пропускайте важные новости! Перейти

Undetected Бесплатный макрос Invoker/инвокер + src (update)

Начинающий
Начинающий
Статус
Оффлайн
Регистрация
2 Фев 2020
Сообщения
240
Реакции
18
Всем привет. Выкладываю в открытый доступ небольшую утилиту для Инвокера, которую нашёл в одном из закрытых каналов (спиздил с компа). Продавалась по подписке, но смысла прятать такие приятные вещи не вижу.

Что это?
Исполняемый файл (.exe), написанный на Python. Он не вшивается в клиент игры, а просто эмулирует нажатия клавиш поверх окна Dota 2. Помогает быстрее выкастовать сферы и собрать спеллы одной комбинацией.

Как работает:
При запуске не видно в диспетчере задач. Назначаете горячие клавиши (например, Alt+1, Alt+2) и получаете готовые скиллы без задержек.

Важно:
  1. В комплекте идёт исходный код. Сможете подогнать под себя.
  2. Это макрос, а не чит. Однако технически это нарушение правил Valve, и за его использование аккаунт могут заблокировать (обычно дают предупреждение или бан в матчмейкинге при жалобах). Пользуйтесь на свой страх и риск, на основном акке я бы не советовал запускать.
  3. Файл без какой-либо защиты.

Пожалуйста, авторизуйтесь для просмотра ссылки.


1772997081117.png


source code:
Expand Collapse Copy
import customtkinter as ctk
from customtkinter import *
import tkinter as tk
from tkinter import ttk
import keyboard
import time
import random
import json
import threading
import os
from dataclasses import dataclass
from typing import Dict, List
import queue
import atexit

ctk.set_appearance_mode("dark")
ctk.set_default_color_theme("blue")

@dataclass
class Macro:
    name: str
    hotkey: str
    keys: List[str]
    min_delay: int
    max_delay: int
    include_r: bool = False
    enabled: bool = True

class ModernInvokerMacroGUI:
    def __init__(self):
        self.root = ctk.CTk()
        self.root.title("Invoker Master")
        self.root.geometry("800x700")
     
        self.center_window()
        self.root.overrideredirect(True)
     
        self.macros: Dict[str, Macro] = {}
        self.macro_enabled = True
        self.current_hotkey = None
        self.config_file = "invoker_macros.json"
        self.listening_for_hotkey = False
        self.command_queue = queue.Queue()
        self.is_running = True
        self.worker_thread = None
        self.start_worker()
     
        self.create_custom_title_bar()
        self.load_macros()
        self.create_gui()
        self.start_hotkey_listener()
     
        atexit.register(self.cleanup)
     
    def start_worker(self):
        def worker():
            while self.is_running:
                try:
                    macro = self.command_queue.get(timeout=0.1)
                    if macro and self.macro_enabled and macro.enabled:
                        self.cast_spell(macro)
                except queue.Empty:
                    continue
                except Exception as e:
                    print(f"Worker error: {e}")
                 
        self.worker_thread = threading.Thread(target=worker, daemon=True)
        self.worker_thread.start()
     
    def cleanup(self):
        self.is_running = False
        try:
            keyboard.unhook_all()
        except:
            pass
         
    def center_window(self):
        self.root.update_idletasks()
        width = 800
        height = 700
        x = (self.root.winfo_screenwidth() // 2) - (width // 2)
        y = (self.root.winfo_screenheight() // 2) - (height // 2)
        self.root.geometry(f'{width}x{height}+{x}+{y}')
     
    def create_custom_title_bar(self):
        self.title_bar = ctk.CTkFrame(self.root, height=40, corner_radius=0)
        self.title_bar.pack(fill="x", padx=0, pady=0)
        self.title_bar.pack_propagate(False)
     
        title_frame = ctk.CTkFrame(self.title_bar, fg_color="transparent")
        title_frame.pack(side="left", padx=10)
     
        title_label = ctk.CTkLabel(
            title_frame,
            text="⚡ INVOKER MASTER ⚡",
            font=ctk.CTkFont(size=16, weight="bold")
        )
        title_label.pack(side="left")
     
        buttons_frame = ctk.CTkFrame(self.title_bar, fg_color="transparent")
        buttons_frame.pack(side="right", padx=10)
     
        self.minimize_btn = ctk.CTkButton(
            buttons_frame,
            text="—",
            width=30,
            height=30,
            corner_radius=5,
            fg_color="transparent",
            hover_color=("#2b2b2b", "#2b2b2b"),
            command=self.minimize_window
        )
        self.minimize_btn.pack(side="left", padx=2)
     
        self.close_btn = ctk.CTkButton(
            buttons_frame,
            text="✕",
            width=30,
            height=30,
            corner_radius=5,
            fg_color="transparent",
            hover_color="#C42B1C",
            command=self.on_closing
        )
        self.close_btn.pack(side="left", padx=2)
     
        self.title_bar.bind("<Button-1>", self.start_move)
        self.title_bar.bind("<B1-Motion>", self.on_move)
        title_label.bind("<Button-1>", self.start_move)
        title_label.bind("<B1-Motion>", self.on_move)
     
    def start_move(self, event):
        self.x = event.x
        self.y = event.y
     
    def on_move(self, event):
        deltax = event.x - self.x
        deltay = event.y - self.y
        x = self.root.winfo_x() + deltax
        y = self.root.winfo_y() + deltay
        self.root.geometry(f"+{x}+{y}")
     
    def minimize_window(self):
        self.root.iconify()
     
    def create_gui(self):
        main_container = ctk.CTkFrame(self.root, fg_color="transparent")
        main_container.pack(fill="both", expand=True, padx=15, pady=15)
     
        top_frame = ctk.CTkFrame(main_container, fg_color="transparent")
        top_frame.pack(fill="x", pady=(0, 15))
     
        self.toggle_btn = ctk.CTkButton(
            top_frame,
            text="🟢 MACROS ACTIVE",
            command=self.toggle_macros,
            width=180,
            height=40,
            font=ctk.CTkFont(size=14, weight="bold"),
            fg_color="#2ecc71",
            hover_color="#27ae60"
        )
        self.toggle_btn.pack(side="left", padx=5)
     
        info_frame = ctk.CTkFrame(top_frame, fg_color=("gray75", "gray25"))
        info_frame.pack(side="left", padx=10, fill="x", expand=True)
     
        info_label = ctk.CTkLabel(
            info_frame,
            text="F6 - Toggle Macros | F7 - Hide/Show",
            font=ctk.CTkFont(size=12)
        )
        info_label.pack(padx=10, pady=8)
     
        content_frame = ctk.CTkFrame(main_container)
        content_frame.pack(fill="both", expand=True)
     
        list_frame = ctk.CTkFrame(content_frame)
        list_frame.pack(side="left", fill="both", expand=True, padx=(0, 7))
     
        list_label = ctk.CTkLabel(
            list_frame,
            text="📋 ACTIVE MACROS",
            font=ctk.CTkFont(size=16, weight="bold")
        )
        list_label.pack(pady=(10, 5))
     
        tree_frame = ctk.CTkFrame(list_frame)
        tree_frame.pack(fill="both", expand=True, padx=10, pady=5)
     
        style = ttk.Style()
        style.theme_use('clam')
        style.configure(
            "Custom.Treeview",
            background="#2b2b2b",
            foreground="white",
            fieldbackground="#2b2b2b",
            borderwidth=0,
            rowheight=25
        )
        style.configure(
            "Custom.Treeview.Heading",
            background="#1f538d",
            foreground="white",
            borderwidth=0,
            font=('Arial', 10, 'bold')
        )
        style.map('Custom.Treeview',
                  background=[('selected', '#1f538d')],
                  foreground=[('selected', 'white')])
     
        columns = ('Hotkey', 'Name', 'Keys', 'Delay', 'R', 'Status')
        self.tree = ttk.Treeview(
            tree_frame,
            columns=columns,
            show='headings',
            height=10,
            style="Custom.Treeview"
        )
     
        column_widths = [70, 120, 100, 80, 40, 60]
        column_headers = ['Hotkey', 'Name', 'Keys', 'Delay(ms)', 'R', 'Status']
     
        for col, width, header in zip(columns, column_widths, column_headers):
            self.tree.heading(col, text=header)
            self.tree.column(col, width=width, anchor='center')
     
        scrollbar = ttk.Scrollbar(
            tree_frame,
            orient="vertical",
            command=self.tree.yview
        )
        self.tree.configure(yscrollcommand=scrollbar.set)
     
        self.tree.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")
     
        btn_frame = ctk.CTkFrame(list_frame, fg_color="transparent")
        btn_frame.pack(fill="x", padx=10, pady=10)
     
        self.delete_btn = ctk.CTkButton(
            btn_frame,
            text="🗑️ Delete",
            command=self.delete_macro,
            width=90,
            fg_color="#e74c3c",
            hover_color="#c0392b"
        )
        self.delete_btn.pack(side="left", padx=2)
     
        self.toggle_macro_btn = ctk.CTkButton(
            btn_frame,
            text="🔄 Toggle",
            command=self.toggle_selected_macro,
            width=90,
            fg_color="#f39c12",
            hover_color="#e67e22"
        )
        self.toggle_macro_btn.pack(side="left", padx=2)
     
        self.test_btn = ctk.CTkButton(
            btn_frame,
            text="▶️ Test",
            command=self.test_selected_macro,
            width=90,
            fg_color="#3498db",
            hover_color="#2980b9"
        )
        self.test_btn.pack(side="left", padx=2)
     
        create_frame = ctk.CTkFrame(content_frame)
        create_frame.pack(side="right", fill="both", expand=True, padx=(7, 0))
     
        create_label = ctk.CTkLabel(
            create_frame,
            text="✨ CREATE NEW MACRO",
            font=ctk.CTkFont(size=16, weight="bold")
        )
        create_label.pack(pady=(10, 15))
     
        input_frame = ctk.CTkFrame(create_frame, fg_color="transparent")
        input_frame.pack(fill="x", padx=20)
     
        ctk.CTkLabel(input_frame, text="Macro Name:", font=ctk.CTkFont(size=12)).pack(anchor="w", pady=(0, 2))
        self.name_entry = ctk.CTkEntry(input_frame, height=35, placeholder_text="e.g., Sun Strike")
        self.name_entry.pack(fill="x", pady=(0, 10))
     
        ctk.CTkLabel(input_frame, text="Hotkey:", font=ctk.CTkFont(size=12)).pack(anchor="w", pady=(0, 2))
        hotkey_frame = ctk.CTkFrame(input_frame, fg_color="transparent")
        hotkey_frame.pack(fill="x", pady=(0, 10))
     
        self.hotkey_entry = ctk.CTkEntry(hotkey_frame, height=35, placeholder_text="Click Set")
        self.hotkey_entry.pack(side="left", fill="x", expand=True, padx=(0, 5))
     
        self.set_hotkey_btn = ctk.CTkButton(
            hotkey_frame,
            text="Set",
            command=self.start_hotkey_capture,
            width=60,
            height=35
        )
        self.set_hotkey_btn.pack(side="right")
     
        ctk.CTkLabel(input_frame, text="Keys (comma separated):", font=ctk.CTkFont(size=12)).pack(anchor="w", pady=(0, 2))
        self.keys_entry = ctk.CTkEntry(input_frame, height=35, placeholder_text="q,w,e")
        self.keys_entry.pack(fill="x", pady=(0, 5))
     
        ctk.CTkLabel(
            input_frame,
            text="Example: q,w,e (R will be added automatically if selected)",
            font=ctk.CTkFont(size=10),
            text_color="gray"
        ).pack(anchor="w", pady=(0, 10))
     
        delay_frame = ctk.CTkFrame(input_frame, fg_color="transparent")
        delay_frame.pack(fill="x", pady=(0, 10))
     
        min_frame = ctk.CTkFrame(delay_frame, fg_color="transparent")
        min_frame.pack(side="left", fill="x", expand=True, padx=(0, 5))
     
        ctk.CTkLabel(min_frame, text="Min (ms):", font=ctk.CTkFont(size=12)).pack(anchor="w")
        self.min_delay = ctk.CTkEntry(min_frame, height=35)
        self.min_delay.insert(0, "50")
        self.min_delay.pack(fill="x")
     
        max_frame = ctk.CTkFrame(delay_frame, fg_color="transparent")
        max_frame.pack(side="right", fill="x", expand=True, padx=(5, 0))
     
        ctk.CTkLabel(max_frame, text="Max (ms):", font=ctk.CTkFont(size=12)).pack(anchor="w")
        self.max_delay = ctk.CTkEntry(max_frame, height=35)
        self.max_delay.insert(0, "150")
        self.max_delay.pack(fill="x")
     
        self.include_r_var = ctk.BooleanVar(value=False)
        self.r_checkbox = ctk.CTkCheckBox(
            input_frame,
            text="➕ Add R at the end (Invoke)",
            variable=self.include_r_var,
            font=ctk.CTkFont(size=12)
        )
        self.r_checkbox.pack(anchor="w", pady=(0, 15))
     
        self.create_btn = ctk.CTkButton(
            create_frame,
            text="✨ CREATE MACRO ✨",
            command=self.create_macro,
            height=45,
            font=ctk.CTkFont(size=14, weight="bold"),
            fg_color="#2ecc71",
            hover_color="#27ae60"
        )
        self.create_btn.pack(padx=20, pady=10, fill="x")
     
        self.status_bar = ctk.CTkFrame(self.root, height=30, fg_color=("gray80", "gray20"))
        self.status_bar.pack(fill="x", side="bottom")
        self.status_bar.pack_propagate(False)
     
        self.status_label = ctk.CTkLabel(
            self.status_bar,
            text="✅ Ready",
            font=ctk.CTkFont(size=11)
        )
        self.status_label.pack(side="left", padx=10)
     
        self.macro_count_label = ctk.CTkLabel(
            self.status_bar,
            text=f"📊 Macros: {len(self.macros)}",
            font=ctk.CTkFont(size=11)
        )
        self.macro_count_label.pack(side="right", padx=10)
     
        self.refresh_macro_list()
     
        try:
            keyboard.add_hotkey('f6', self.toggle_macros)
            keyboard.add_hotkey('f7', self.toggle_gui)
        except:
            pass
     
    def start_hotkey_capture(self):
        if self.listening_for_hotkey:
            return
         
        self.listening_for_hotkey = True
        self.hotkey_entry.configure(state="normal")
        self.hotkey_entry.delete(0, "end")
        self.hotkey_entry.insert(0, "Press any key...")
        self.hotkey_entry.configure(state="disabled")
        self.set_hotkey_btn.configure(text="🎯 Listening...", state="disabled")
     
        def on_key(event):
            if not self.listening_for_hotkey:
                return
             
            if event.name in ['f6', 'f7', 'ctrl', 'alt', 'shift']:
                return
             
            self.current_hotkey = event.name
            self.hotkey_entry.configure(state="normal")
            self.hotkey_entry.delete(0, "end")
            self.hotkey_entry.insert(0, event.name)
            self.hotkey_entry.configure(state="disabled")
            self.set_hotkey_btn.configure(text="Set", state="normal")
            self.listening_for_hotkey = False
            try:
                keyboard.unhook(on_key)
            except:
                pass
         
            self.update_status(f"Hotkey set: {event.name}")
         
        keyboard.hook(on_key)
     
    def create_macro(self):
        name = self.name_entry.get().strip()
        hotkey = self.current_hotkey
        keys_str = self.keys_entry.get().strip()
     
        if not hotkey:
            self.show_error("Please set a hotkey")
            return
         
        if not name:
            self.show_error("Please enter a name")
            return
         
        if not keys_str:
            self.show_error("Please enter keys")
            return
         
        if hotkey in self.macros:
            if not self.ask_yes_no("Overwrite", f"Hotkey '{hotkey}' is already used. Overwrite?"):
                return
     
        try:
            min_delay = int(self.min_delay.get())
            max_delay = int(self.max_delay.get())
            if min_delay > max_delay:
                min_delay, max_delay = max_delay, min_delay
            if min_delay < 10:
                min_delay = 10
        except ValueError:
            self.show_error("Invalid delay values")
            return
         
        keys = [k.strip().lower() for k in keys_str.split(',')]
     
        macro = Macro(
            name=name,
            hotkey=hotkey,
            keys=keys,
            min_delay=min_delay,
            max_delay=max_delay,
            include_r=self.include_r_var.get()
        )
     
        self.macros[hotkey] = macro
     
        self.save_macros()
        self.refresh_macro_list()
        self.clear_inputs()
        self.add_macro_hotkey(macro)
     
        self.update_status(f"✅ Macro '{name}' created successfully!")
        self.macro_count_label.configure(text=f"📊 Macros: {len(self.macros)}")
     
    def add_macro_hotkey(self, macro: Macro):
        def callback():
            if self.macro_enabled and macro.enabled:
                self.command_queue.put(macro)
             
        try:
            keyboard.remove_hotkey(macro.hotkey)
        except:
            pass
         
        try:
            keyboard.add_hotkey(macro.hotkey, callback)
        except:
            pass
     
    def cast_spell(self, macro: Macro):
        try:
            time.sleep(0.01)
         
            for i, key in enumerate(macro.keys):
                keyboard.press(key)
                time.sleep(random.uniform(0.03, 0.05))
                keyboard.release(key)
             
                if i < len(macro.keys) - 1:
                    delay = random.randint(macro.min_delay, macro.max_delay) / 1000
                    time.sleep(delay)
         
            if macro.include_r:
                time.sleep(random.uniform(0.075, 0.1))
                keyboard.press('r')
                time.sleep(random.uniform(0.03, 0.05))
                keyboard.release('r')
             
            self.root.after(0, lambda: self.update_status(f"✅ Executed: {macro.name}"))
         
        except Exception as e:
            self.root.after(0, lambda: self.update_status(f"❌ Error: {str(e)}"))
     
    def test_selected_macro(self):
        selection = self.tree.selection()
        if not selection:
            self.show_info("Select a macro to test")
            return
         
        item = self.tree.item(selection[0])
        hotkey = item['values'][0]
     
        if hotkey in self.macros:
            macro = self.macros[hotkey]
            self.command_queue.put(macro)
            self.update_status(f"🧪 Testing: {macro.name}")
     
    def toggle_macros(self):
        self.macro_enabled = not self.macro_enabled
        if self.macro_enabled:
            self.toggle_btn.configure(text="🟢 MACROS ACTIVE", fg_color="#2ecc71", hover_color="#27ae60")
            self.update_status("✅ Macros activated")
        else:
            self.toggle_btn.configure(text="🔴 MACROS INACTIVE", fg_color="#e74c3c", hover_color="#c0392b")
            self.update_status("⏸️ Macros deactivated")
         
    def toggle_selected_macro(self):
        selection = self.tree.selection()
        if selection:
            item = self.tree.item(selection[0])
            hotkey = item['values'][0]
            if hotkey in self.macros:
                self.macros[hotkey].enabled = not self.macros[hotkey].enabled
                self.refresh_macro_list()
                self.save_macros()
             
                status = "enabled" if self.macros[hotkey].enabled else "disabled"
                self.update_status(f"Macro '{self.macros[hotkey].name}' {status}")
             
    def delete_macro(self):
        selection = self.tree.selection()
        if selection:
            item = self.tree.item(selection[0])
            hotkey = item['values'][0]
            if hotkey in self.macros:
                macro_name = self.macros[hotkey].name
             
                try:
                    keyboard.remove_hotkey(hotkey)
                except:
                    pass
                 
                del self.macros[hotkey]
                self.refresh_macro_list()
                self.save_macros()
             
                self.update_status(f"🗑️ Deleted: {macro_name}")
                self.macro_count_label.configure(text=f"📊 Macros: {len(self.macros)}")
             
    def refresh_macro_list(self):
        for item in self.tree.get_children():
            self.tree.delete(item)
         
        for macro in self.macros.values():
            status = "✅" if macro.enabled else "❌"
            keys_str = ','.join(macro.keys)
            delay_str = f"{macro.min_delay}-{macro.max_delay}"
            include_r = "✓" if macro.include_r else "✗"
         
            self.tree.insert('', 'end', values=(
                macro.hotkey, macro.name, keys_str, delay_str, include_r, status
            ))
         
    def clear_inputs(self):
        self.name_entry.delete(0, "end")
        self.hotkey_entry.configure(state="normal")
        self.hotkey_entry.delete(0, "end")
        self.hotkey_entry.configure(state="normal")
        self.hotkey_entry.configure(placeholder_text="Click Set")
        self.keys_entry.delete(0, "end")
        self.min_delay.delete(0, "end")
        self.min_delay.insert(0, "50")
        self.max_delay.delete(0, "end")
        self.max_delay.insert(0, "150")
        self.include_r_var.set(False)
        self.current_hotkey = None
        self.set_hotkey_btn.configure(text="Set", state="normal")
     
    def save_macros(self):
        data = {}
        for hotkey, macro in self.macros.items():
            data[hotkey] = {
                'name': macro.name,
                'keys': macro.keys,
                'min_delay': macro.min_delay,
                'max_delay': macro.max_delay,
                'include_r': macro.include_r,
                'enabled': macro.enabled
            }
         
        try:
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(data, f, indent=2, ensure_ascii=False)
        except Exception as e:
            self.update_status(f"❌ Save error: {str(e)}")
         
    def load_macros(self):
        if os.path.exists(self.config_file):
            try:
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                 
                for hotkey, macro_data in data.items():
                    macro = Macro(
                        name=macro_data['name'],
                        hotkey=hotkey,
                        keys=macro_data['keys'],
                        min_delay=macro_data.get('min_delay', 50),
                        max_delay=macro_data.get('max_delay', 150),
                        include_r=macro_data.get('include_r', False),
                        enabled=macro_data.get('enabled', True)
                    )
                    self.macros[hotkey] = macro
            except Exception as e:
                print(f"Error loading macros: {e}")
             
    def start_hotkey_listener(self):
        for macro in self.macros.values():
            self.add_macro_hotkey(macro)
         
    def toggle_gui(self):
        if self.root.state() == 'normal':
            self.root.withdraw()
            self.update_status("👻 Hidden (F7 to show)")
        else:
            self.root.deiconify()
            self.update_status("👀 Visible")
         
    def update_status(self, message):
        self.status_label.configure(text=f"💫 {message}")
     
    def show_error(self, message):
        self.update_status(f"❌ {message}")
     
    def show_info(self, message):
        self.update_status(f"ℹ️ {message}")
     
    def ask_yes_no(self, title, message):
        dialog = ctk.CTkInputDialog(text=message, title=title)
        return dialog.get_input() is not None
     
    def run(self):
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        self.root.mainloop()
     
    def on_closing(self):
        self.is_running = False
        if self.worker_thread:
            self.worker_thread.join(timeout=0.5)
        self.save_macros()
        self.cleanup()
        self.root.destroy()

if __name__ == "__main__":
    required_packages = ['keyboard', 'customtkinter', 'pillow']
 
    for package in required_packages:
        try:
            __import__(package)
        except ImportError:
            print(f"Installing {package}...")
            os.system(f"pip install {package}")
         
    app = ModernInvokerMacroGUI()
    app.run()
 
Последнее редактирование:
насколько я знаю у доты есть некоторые приколы с детектом эмуляции нажатий и макросов в целом особенно через дефолтный keyboard питона)
risky to use.
 
Обновил. Сделал безопаснее - юзается драйвер ddxoft. Требования - отключить проверку драйверов в винде (целостность памяти вроде).

Пожалуйста, авторизуйтесь для просмотра ссылки.



src:
Expand Collapse Copy
import customtkinter as ctk
from customtkinter import *
import tkinter as tk
from tkinter import ttk, messagebox
import keyboard
import time
import random
import json
import threading
import os
from dataclasses import dataclass
from typing import Dict, List
import queue
import atexit
import ctypes
import urllib.request
import sys

ctk.set_appearance_mode("dark")
ctk.set_default_color_theme("blue")

DLL_NAME = "ddxoft.dll"
DLL_URL = "https://gitlab.com/marsqq/extra-files/-/raw/main/ddxoft.dll"

class DDXoft:
    def __init__(self):
        self.dll = None
        self.available = False
        self.key_map = {
            'q': 301, 'w': 302, 'e': 303, 'r': 304, 'd': 403, 'f': 404,
            'z': 501, 'x': 502, 'c': 503
        }
       
    def load(self, dll_path):
        try:
            self.dll = ctypes.WinDLL(dll_path)
            self.DD_btn = self.dll.DD_btn
            self.DD_btn.argtypes = [ctypes.c_int]
            self.DD_btn.restype = ctypes.c_int
            self.DD_key = self.dll.DD_key
            self.DD_key.argtypes = [ctypes.c_int, ctypes.c_int]
            self.DD_key.restype = ctypes.c_int
            result = self.DD_btn(0)
            if result == 1:
                self.available = True
                return 1
            return -1
        except Exception as e:
            return -2
   
    def tap_key(self, key):
        if not self.available or key not in self.key_map:
            return False
        code = self.key_map[key]
        self.DD_key(code, 1)
        time.sleep(0.01)
        self.DD_key(code, 2)
        return True

ddxoft_instance = DDXoft()

def download_ddx():
    if not os.path.exists(DLL_NAME):
        try:
            urllib.request.urlretrieve(DLL_URL, DLL_NAME)
            return True
        except:
            return False
    return True

def is_admin():
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False

def init_ddxoft():
    try:
        if not is_admin():
            messagebox.showerror("Ошибка", "Запустите от имени администратора")
            return False
        if not os.path.exists(DLL_NAME):
            if not download_ddx():
                messagebox.showerror("Ошибка", "Не удалось загрузить ddxoft.dll")
                return False
        result = ddxoft_instance.load(os.path.abspath(DLL_NAME))
        if result != 1:
            messagebox.showerror("Ошибка", "Не удалось загрузить драйвер ddxoft")
            return False
        return True
    except Exception as e:
        messagebox.showerror("Ошибка", str(e))
        return False

@dataclass
class Macro:
    name: str
    hotkey: str
    keys: List[str]
    min_delay: int
    max_delay: int
    include_r: bool = False
    enabled: bool = True

class ModernInvokerMacroGUI:
    def __init__(self):
        self.root = ctk.CTk()
        self.root.title("Invoker Master")
        self.root.geometry("800x700")
        self.center_window()
        self.root.overrideredirect(True)
       
        self.macros: Dict[str, Macro] = {}
        self.macro_enabled = True
        self.current_hotkey = None
        self.config_file = "invoker_macros.json"
        self.listening_for_hotkey = False
        self.command_queue = queue.Queue()
        self.is_running = True
        self.worker_thread = None
        self.start_worker()
       
        self.create_custom_title_bar()
        self.load_macros()
        self.create_gui()
        self.start_hotkey_listener()
       
        atexit.register(self.cleanup)
       
    def start_worker(self):
        def worker():
            while self.is_running:
                try:
                    macro = self.command_queue.get(timeout=0.1)
                    if macro and self.macro_enabled and macro.enabled:
                        self.cast_spell(macro)
                except queue.Empty:
                    continue
                except:
                    continue
        self.worker_thread = threading.Thread(target=worker, daemon=True)
        self.worker_thread.start()
       
    def cleanup(self):
        self.is_running = False
        try:
            keyboard.unhook_all()
        except:
            pass
           
    def center_window(self):
        self.root.update_idletasks()
        width = 800
        height = 700
        x = (self.root.winfo_screenwidth() // 2) - (width // 2)
        y = (self.root.winfo_screenheight() // 2) - (height // 2)
        self.root.geometry(f'{width}x{height}+{x}+{y}')
       
    def create_custom_title_bar(self):
        self.title_bar = ctk.CTkFrame(self.root, height=40, corner_radius=0)
        self.title_bar.pack(fill="x", padx=0, pady=0)
        self.title_bar.pack_propagate(False)
       
        title_frame = ctk.CTkFrame(self.title_bar, fg_color="transparent")
        title_frame.pack(side="left", padx=10)
       
        title_label = ctk.CTkLabel(
            title_frame,
            text="⚡ INVOKER MASTER ⚡",
            font=ctk.CTkFont(size=16, weight="bold")
        )
        title_label.pack(side="left")
       
        buttons_frame = ctk.CTkFrame(self.title_bar, fg_color="transparent")
        buttons_frame.pack(side="right", padx=10)
       
        self.minimize_btn = ctk.CTkButton(
            buttons_frame,
            text="—",
            width=30,
            height=30,
            corner_radius=5,
            fg_color="transparent",
            hover_color=("#2b2b2b", "#2b2b2b"),
            command=self.minimize_window
        )
        self.minimize_btn.pack(side="left", padx=2)
       
        self.close_btn = ctk.CTkButton(
            buttons_frame,
            text="✕",
            width=30,
            height=30,
            corner_radius=5,
            fg_color="transparent",
            hover_color="#C42B1C",
            command=self.on_closing
        )
        self.close_btn.pack(side="left", padx=2)
       
        self.title_bar.bind("<Button-1>", self.start_move)
        self.title_bar.bind("<B1-Motion>", self.on_move)
        title_label.bind("<Button-1>", self.start_move)
        title_label.bind("<B1-Motion>", self.on_move)
       
    def start_move(self, event):
        self.x = event.x
        self.y = event.y
       
    def on_move(self, event):
        deltax = event.x - self.x
        deltay = event.y - self.y
        x = self.root.winfo_x() + deltax
        y = self.root.winfo_y() + deltay
        self.root.geometry(f"+{x}+{y}")
       
    def minimize_window(self):
        self.root.iconify()
       
    def create_gui(self):
        main_container = ctk.CTkFrame(self.root, fg_color="transparent")
        main_container.pack(fill="both", expand=True, padx=15, pady=15)
       
        top_frame = ctk.CTkFrame(main_container, fg_color="transparent")
        top_frame.pack(fill="x", pady=(0, 15))
       
        self.toggle_btn = ctk.CTkButton(
            top_frame,
            text="🟢 MACROS ACTIVE",
            command=self.toggle_macros,
            width=180,
            height=40,
            font=ctk.CTkFont(size=14, weight="bold"),
            fg_color="#2ecc71",
            hover_color="#27ae60"
        )
        self.toggle_btn.pack(side="left", padx=5)
       
        info_frame = ctk.CTkFrame(top_frame, fg_color=("gray75", "gray25"))
        info_frame.pack(side="left", padx=10, fill="x", expand=True)
       
        info_label = ctk.CTkLabel(
            info_frame,
            text="F6 - Toggle Macros | F7 - Hide/Show",
            font=ctk.CTkFont(size=12)
        )
        info_label.pack(padx=10, pady=8)
       
        content_frame = ctk.CTkFrame(main_container)
        content_frame.pack(fill="both", expand=True)
       
        list_frame = ctk.CTkFrame(content_frame)
        list_frame.pack(side="left", fill="both", expand=True, padx=(0, 7))
       
        list_label = ctk.CTkLabel(
            list_frame,
            text="📋 ACTIVE MACROS",
            font=ctk.CTkFont(size=16, weight="bold")
        )
        list_label.pack(pady=(10, 5))
       
        tree_frame = ctk.CTkFrame(list_frame)
        tree_frame.pack(fill="both", expand=True, padx=10, pady=5)
       
        style = ttk.Style()
        style.theme_use('clam')
        style.configure(
            "Custom.Treeview",
            background="#2b2b2b",
            foreground="white",
            fieldbackground="#2b2b2b",
            borderwidth=0,
            rowheight=25
        )
        style.configure(
            "Custom.Treeview.Heading",
            background="#1f538d",
            foreground="white",
            borderwidth=0,
            font=('Arial', 10, 'bold')
        )
        style.map('Custom.Treeview',
                  background=[('selected', '#1f538d')],
                  foreground=[('selected', 'white')])
       
        columns = ('Hotkey', 'Name', 'Keys', 'Delay', 'R', 'Status')
        self.tree = ttk.Treeview(
            tree_frame,
            columns=columns,
            show='headings',
            height=10,
            style="Custom.Treeview"
        )
       
        column_widths = [70, 120, 100, 80, 40, 60]
        column_headers = ['Hotkey', 'Name', 'Keys', 'Delay(ms)', 'R', 'Status']
       
        for col, width, header in zip(columns, column_widths, column_headers):
            self.tree.heading(col, text=header)
            self.tree.column(col, width=width, anchor='center')
       
        scrollbar = ttk.Scrollbar(
            tree_frame,
            orient="vertical",
            command=self.tree.yview
        )
        self.tree.configure(yscrollcommand=scrollbar.set)
       
        self.tree.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")
       
        btn_frame = ctk.CTkFrame(list_frame, fg_color="transparent")
        btn_frame.pack(fill="x", padx=10, pady=10)
       
        self.delete_btn = ctk.CTkButton(
            btn_frame,
            text="🗑️ Delete",
            command=self.delete_macro,
            width=90,
            fg_color="#e74c3c",
            hover_color="#c0392b"
        )
        self.delete_btn.pack(side="left", padx=2)
       
        self.toggle_macro_btn = ctk.CTkButton(
            btn_frame,
            text="🔄 Toggle",
            command=self.toggle_selected_macro,
            width=90,
            fg_color="#f39c12",
            hover_color="#e67e22"
        )
        self.toggle_macro_btn.pack(side="left", padx=2)
       
        self.test_btn = ctk.CTkButton(
            btn_frame,
            text="▶️ Test",
            command=self.test_selected_macro,
            width=90,
            fg_color="#3498db",
            hover_color="#2980b9"
        )
        self.test_btn.pack(side="left", padx=2)
       
        create_frame = ctk.CTkFrame(content_frame)
        create_frame.pack(side="right", fill="both", expand=True, padx=(7, 0))
       
        create_label = ctk.CTkLabel(
            create_frame,
            text="✨ CREATE NEW MACRO",
            font=ctk.CTkFont(size=16, weight="bold")
        )
        create_label.pack(pady=(10, 15))
       
        input_frame = ctk.CTkFrame(create_frame, fg_color="transparent")
        input_frame.pack(fill="x", padx=20)
       
        ctk.CTkLabel(input_frame, text="Macro Name:", font=ctk.CTkFont(size=12)).pack(anchor="w", pady=(0, 2))
        self.name_entry = ctk.CTkEntry(input_frame, height=35, placeholder_text="e.g., Sun Strike")
        self.name_entry.pack(fill="x", pady=(0, 10))
       
        ctk.CTkLabel(input_frame, text="Hotkey:", font=ctk.CTkFont(size=12)).pack(anchor="w", pady=(0, 2))
        hotkey_frame = ctk.CTkFrame(input_frame, fg_color="transparent")
        hotkey_frame.pack(fill="x", pady=(0, 10))
       
        self.hotkey_entry = ctk.CTkEntry(hotkey_frame, height=35, placeholder_text="Click Set")
        self.hotkey_entry.pack(side="left", fill="x", expand=True, padx=(0, 5))
       
        self.set_hotkey_btn = ctk.CTkButton(
            hotkey_frame,
            text="Set",
            command=self.start_hotkey_capture,
            width=60,
            height=35
        )
        self.set_hotkey_btn.pack(side="right")
       
        ctk.CTkLabel(input_frame, text="Keys (comma separated):", font=ctk.CTkFont(size=12)).pack(anchor="w", pady=(0, 2))
        self.keys_entry = ctk.CTkEntry(input_frame, height=35, placeholder_text="q,w,e")
        self.keys_entry.pack(fill="x", pady=(0, 5))
       
        ctk.CTkLabel(
            input_frame,
            text="Example: q,w,e (R will be added automatically if selected)",
            font=ctk.CTkFont(size=10),
            text_color="gray"
        ).pack(anchor="w", pady=(0, 10))
       
        delay_frame = ctk.CTkFrame(input_frame, fg_color="transparent")
        delay_frame.pack(fill="x", pady=(0, 10))
       
        min_frame = ctk.CTkFrame(delay_frame, fg_color="transparent")
        min_frame.pack(side="left", fill="x", expand=True, padx=(0, 5))
       
        ctk.CTkLabel(min_frame, text="Min (ms):", font=ctk.CTkFont(size=12)).pack(anchor="w")
        self.min_delay = ctk.CTkEntry(min_frame, height=35)
        self.min_delay.insert(0, "50")
        self.min_delay.pack(fill="x")
       
        max_frame = ctk.CTkFrame(delay_frame, fg_color="transparent")
        max_frame.pack(side="right", fill="x", expand=True, padx=(5, 0))
       
        ctk.CTkLabel(max_frame, text="Max (ms):", font=ctk.CTkFont(size=12)).pack(anchor="w")
        self.max_delay = ctk.CTkEntry(max_frame, height=35)
        self.max_delay.insert(0, "150")
        self.max_delay.pack(fill="x")
       
        self.include_r_var = ctk.BooleanVar(value=False)
        self.r_checkbox = ctk.CTkCheckBox(
            input_frame,
            text="➕ Add R at the end (Invoke)",
            variable=self.include_r_var,
            font=ctk.CTkFont(size=12)
        )
        self.r_checkbox.pack(anchor="w", pady=(0, 15))
       
        self.create_btn = ctk.CTkButton(
            create_frame,
            text="✨ CREATE MACRO ✨",
            command=self.create_macro,
            height=45,
            font=ctk.CTkFont(size=14, weight="bold"),
            fg_color="#2ecc71",
            hover_color="#27ae60"
        )
        self.create_btn.pack(padx=20, pady=10, fill="x")
       
        self.status_bar = ctk.CTkFrame(self.root, height=30, fg_color=("gray80", "gray20"))
        self.status_bar.pack(fill="x", side="bottom")
        self.status_bar.pack_propagate(False)
       
        self.status_label = ctk.CTkLabel(
            self.status_bar,
            text="✅ Ready",
            font=ctk.CTkFont(size=11)
        )
        self.status_label.pack(side="left", padx=10)
       
        self.macro_count_label = ctk.CTkLabel(
            self.status_bar,
            text=f"📊 Macros: {len(self.macros)}",
            font=ctk.CTkFont(size=11)
        )
        self.macro_count_label.pack(side="right", padx=10)
       
        self.refresh_macro_list()
       
        keyboard.add_hotkey('f6', self.toggle_macros)
        keyboard.add_hotkey('f7', self.toggle_gui)
       
    def start_hotkey_capture(self):
        if self.listening_for_hotkey:
            return
           
        self.listening_for_hotkey = True
        self.hotkey_entry.configure(state="normal")
        self.hotkey_entry.delete(0, "end")
        self.hotkey_entry.insert(0, "Press any key...")
        self.hotkey_entry.configure(state="disabled")
        self.set_hotkey_btn.configure(text="🎯 Listening...", state="disabled")
       
        def on_key(event):
            if not self.listening_for_hotkey:
                return
               
            key_name = event.name
            if key_name in ['ctrl', 'alt', 'shift', 'ctrl_l', 'ctrl_r', 'alt_l', 'alt_r', 'shift_l', 'shift_r']:
                return
               
            if key_name.isdigit():
                self.current_hotkey = key_name
            elif key_name.startswith('f') and len(key_name) > 1:
                self.current_hotkey = key_name
            elif len(key_name) == 1 and key_name.isalpha():
                self.current_hotkey = key_name.lower()
            else:
                return
               
            self.hotkey_entry.configure(state="normal")
            self.hotkey_entry.delete(0, "end")
            self.hotkey_entry.insert(0, self.current_hotkey)
            self.hotkey_entry.configure(state="disabled")
            self.set_hotkey_btn.configure(text="Set", state="normal")
            self.listening_for_hotkey = False
            keyboard.unhook(on_key)
            self.update_status(f"Hotkey set: {self.current_hotkey}")
           
        keyboard.hook(on_key)
       
    def create_macro(self):
        name = self.name_entry.get().strip()
        hotkey = self.current_hotkey
        keys_str = self.keys_entry.get().strip()
       
        if not hotkey:
            self.show_error("Please set a hotkey")
            return
           
        if not name:
            self.show_error("Please enter a name")
            return
           
        if not keys_str:
            self.show_error("Please enter keys")
            return
           
        if hotkey in self.macros:
            if not self.ask_yes_no("Overwrite", f"Hotkey '{hotkey}' is already used. Overwrite?"):
                return
       
        try:
            min_delay = int(self.min_delay.get())
            max_delay = int(self.max_delay.get())
            if min_delay > max_delay:
                min_delay, max_delay = max_delay, min_delay
            if min_delay < 10:
                min_delay = 10
        except ValueError:
            self.show_error("Invalid delay values")
            return
           
        keys = [k.strip().lower() for k in keys_str.split(',')]
       
        macro = Macro(
            name=name,
            hotkey=hotkey,
            keys=keys,
            min_delay=min_delay,
            max_delay=max_delay,
            include_r=self.include_r_var.get()
        )
       
        self.macros[hotkey] = macro
       
        self.save_macros()
        self.refresh_macro_list()
        self.clear_inputs()
        self.add_macro_hotkey(macro)
       
        self.update_status(f"✅ Macro '{name}' created successfully!")
        self.macro_count_label.configure(text=f"📊 Macros: {len(self.macros)}")
       
    def add_macro_hotkey(self, macro: Macro):
        def callback():
            if self.macro_enabled and macro.enabled:
                self.command_queue.put(macro)
        try:
            keyboard.add_hotkey(macro.hotkey, callback)
        except:
            try:
                keyboard.add_hotkey(macro.hotkey.lower(), callback)
            except:
                pass
       
    def cast_spell(self, macro: Macro):
        try:
            time.sleep(0.01)
            for key in macro.keys:
                ddxoft_instance.tap_key(key)
                time.sleep(random.uniform(macro.min_delay/1000, macro.max_delay/1000))
            if macro.include_r:
                time.sleep(0.05)
                ddxoft_instance.tap_key('r')
            self.update_status(f"✅ Executed: {macro.name}")
        except Exception as e:
            self.update_status(f"❌ Error: {str(e)}")
       
    def test_selected_macro(self):
        selection = self.tree.selection()
        if not selection:
            self.show_info("Select a macro to test")
            return
        item = self.tree.item(selection[0])
        hotkey = item['values'][0]
        if hotkey in self.macros:
            self.command_queue.put(self.macros[hotkey])
            self.update_status(f"🧪 Testing: {self.macros[hotkey].name}")
       
    def toggle_macros(self):
        self.macro_enabled = not self.macro_enabled
        if self.macro_enabled:
            self.toggle_btn.configure(text="🟢 MACROS ACTIVE", fg_color="#2ecc71", hover_color="#27ae60")
            self.update_status("✅ Macros activated")
        else:
            self.toggle_btn.configure(text="🔴 MACROS INACTIVE", fg_color="#e74c3c", hover_color="#c0392b")
            self.update_status("⏸️ Macros deactivated")
           
    def toggle_selected_macro(self):
        selection = self.tree.selection()
        if selection:
            item = self.tree.item(selection[0])
            hotkey = item['values'][0]
            if hotkey in self.macros:
                self.macros[hotkey].enabled = not self.macros[hotkey].enabled
                self.refresh_macro_list()
                self.save_macros()
               
    def delete_macro(self):
        selection = self.tree.selection()
        if selection:
            item = self.tree.item(selection[0])
            hotkey = item['values'][0]
            if hotkey in self.macros:
                keyboard.remove_hotkey(hotkey)
                del self.macros[hotkey]
                self.refresh_macro_list()
                self.save_macros()
                self.update_status(f"🗑️ Deleted")
                self.macro_count_label.configure(text=f"📊 Macros: {len(self.macros)}")
               
    def refresh_macro_list(self):
        for item in self.tree.get_children():
            self.tree.delete(item)
        for macro in self.macros.values():
            status = "✅" if macro.enabled else "❌"
            keys_str = ','.join(macro.keys)
            delay_str = f"{macro.min_delay}-{macro.max_delay}"
            include_r = "✓" if macro.include_r else "✗"
            self.tree.insert('', 'end', values=(macro.hotkey, macro.name, keys_str, delay_str, include_r, status))
           
    def clear_inputs(self):
        self.name_entry.delete(0, "end")
        self.hotkey_entry.configure(state="normal")
        self.hotkey_entry.delete(0, "end")
        self.hotkey_entry.configure(state="normal")
        self.keys_entry.delete(0, "end")
        self.min_delay.delete(0, "end")
        self.min_delay.insert(0, "50")
        self.max_delay.delete(0, "end")
        self.max_delay.insert(0, "150")
        self.include_r_var.set(False)
        self.current_hotkey = None
        self.set_hotkey_btn.configure(text="Set", state="normal")
       
    def save_macros(self):
        data = {}
        for hotkey, macro in self.macros.items():
            data[hotkey] = {
                'name': macro.name,
                'keys': macro.keys,
                'min_delay': macro.min_delay,
                'max_delay': macro.max_delay,
                'include_r': macro.include_r,
                'enabled': macro.enabled
            }
        with open(self.config_file, 'w', encoding='utf-8') as f:
            json.dump(data, f, indent=2, ensure_ascii=False)
           
    def load_macros(self):
        if os.path.exists(self.config_file):
            with open(self.config_file, 'r', encoding='utf-8') as f:
                data = json.load(f)
            for hotkey, macro_data in data.items():
                macro = Macro(
                    name=macro_data['name'],
                    hotkey=hotkey,
                    keys=macro_data['keys'],
                    min_delay=macro_data.get('min_delay', 50),
                    max_delay=macro_data.get('max_delay', 150),
                    include_r=macro_data.get('include_r', False),
                    enabled=macro_data.get('enabled', True)
                )
                self.macros[hotkey] = macro
               
    def start_hotkey_listener(self):
        for macro in self.macros.values():
            self.add_macro_hotkey(macro)
           
    def toggle_gui(self):
        if self.root.state() == 'normal':
            self.root.withdraw()
            self.update_status("👻 Hidden (F7 to show)")
        else:
            self.root.deiconify()
            self.update_status("👀 Visible")
           
    def update_status(self, message):
        self.status_label.configure(text=f"💫 {message}")
       
    def show_error(self, message):
        self.update_status(f"❌ {message}")
       
    def show_info(self, message):
        self.update_status(f"ℹ️ {message}")
       
    def ask_yes_no(self, title, message):
        return messagebox.askyesno(title, message)
       
    def run(self):
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        self.root.mainloop()
       
    def on_closing(self):
        self.is_running = False
        if self.worker_thread:
            self.worker_thread.join(timeout=0.5)
        self.save_macros()
        self.cleanup()
        self.root.destroy()

if __name__ == "__main__":
    required_packages = ['keyboard', 'customtkinter']
    for package in required_packages:
        try:
            __import__(package)
        except ImportError:
            os.system(f"pip install {package}")
    if not init_ddxoft():
        sys.exit(1)
    app = ModernInvokerMacroGUI()
    app.run()
 
Последнее редактирование:
Назад
Сверху Снизу