Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import tkinter as tk
- from tkinter import ttk, messagebox, colorchooser
- import json
- import os
- import hashlib
- import win32gui
- import win32process
- import psutil
- import pyautogui
- from datetime import datetime
- import threading
- import time
- from PIL import Image, ImageTk, ImageDraw
- import random
- import string
- class ButtonMapper:
- def __init__(self):
- self.root = tk.Tk()
- self.root.title("Interface Mapper Pro v2.0")
- self.root.geometry("400x600")
- self.root.attributes('-topmost', True)
- self.root.attributes('-alpha', 0.95)
- # Configurações
- self.config_dir = "mapper_configs"
- self.current_process = None
- self.overlay_windows = []
- self.is_active = False
- self.edit_mode = False
- self.current_config = {}
- self.selected_button = None
- # Proteção e segurança
- self.security_token = self.generate_token()
- self.click_delay = 0.05 # Delay humanizado
- self.last_click_time = 0
- # Criar diretório de configurações
- if not os.path.exists(self.config_dir):
- os.makedirs(self.config_dir)
- self.setup_ui()
- self.start_process_monitor()
- def generate_token(self):
- """Gera token único para sessão"""
- return ''.join(random.choices(string.ascii_letters + string.digits, k=32))
- def setup_ui(self):
- """Configura interface principal"""
- style = ttk.Style()
- style.theme_use('clam')
- # Frame principal
- main_frame = ttk.Frame(self.root, padding="10")
- main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
- # Título
- title_label = ttk.Label(main_frame, text="🎮 Interface Mapper Pro",
- font=('Arial', 14, 'bold'))
- title_label.grid(row=0, column=0, columnspan=2, pady=10)
- # Status do processo
- ttk.Label(main_frame, text="Processo Ativo:").grid(row=1, column=0, sticky=tk.W, pady=5)
- self.process_label = ttk.Label(main_frame, text="Nenhum", foreground="red")
- self.process_label.grid(row=1, column=1, sticky=tk.W, pady=5)
- # Frame de controles
- control_frame = ttk.LabelFrame(main_frame, text="Controles", padding="10")
- control_frame.grid(row=2, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=10)
- # Botão Ativar/Desativar
- self.toggle_btn = ttk.Button(control_frame, text="▶ Ativar Mapeamento",
- command=self.toggle_mapping, state='disabled')
- self.toggle_btn.grid(row=0, column=0, padx=5, pady=5, sticky=(tk.W, tk.E))
- # Botão Modo Edição
- self.edit_btn = ttk.Button(control_frame, text="✏️ Modo Edição",
- command=self.toggle_edit_mode, state='disabled')
- self.edit_btn.grid(row=0, column=1, padx=5, pady=5, sticky=(tk.W, tk.E))
- # Botão Adicionar
- self.add_btn = ttk.Button(control_frame, text="➕ Adicionar Botão",
- command=self.add_button, state='disabled')
- self.add_btn.grid(row=1, column=0, padx=5, pady=5, sticky=(tk.W, tk.E))
- # Botão Limpar
- self.clear_btn = ttk.Button(control_frame, text="🗑️ Limpar Tudo",
- command=self.clear_all, state='disabled')
- self.clear_btn.grid(row=1, column=1, padx=5, pady=5, sticky=(tk.W, tk.E))
- # Frame de botões mapeados
- list_frame = ttk.LabelFrame(main_frame, text="Botões Mapeados", padding="10")
- list_frame.grid(row=3, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=10)
- # Lista de botões
- scrollbar = ttk.Scrollbar(list_frame)
- scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
- self.button_listbox = tk.Listbox(list_frame, yscrollcommand=scrollbar.set, height=10)
- self.button_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
- self.button_listbox.bind('<<ListboxSelect>>', self.on_select_button)
- scrollbar.config(command=self.button_listbox.yview)
- # Frame de propriedades
- prop_frame = ttk.LabelFrame(main_frame, text="Propriedades", padding="10")
- prop_frame.grid(row=4, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=10)
- # Controles de tamanho
- ttk.Label(prop_frame, text="Largura:").grid(row=0, column=0, sticky=tk.W)
- self.width_var = tk.IntVar(value=80)
- self.width_scale = ttk.Scale(prop_frame, from_=30, to=200, variable=self.width_var,
- command=self.update_button_size)
- self.width_scale.grid(row=0, column=1, sticky=(tk.W, tk.E), padx=5)
- self.width_label = ttk.Label(prop_frame, text="80")
- self.width_label.grid(row=0, column=2)
- ttk.Label(prop_frame, text="Altura:").grid(row=1, column=0, sticky=tk.W)
- self.height_var = tk.IntVar(value=40)
- self.height_scale = ttk.Scale(prop_frame, from_=20, to=150, variable=self.height_var,
- command=self.update_button_size)
- self.height_scale.grid(row=1, column=1, sticky=(tk.W, tk.E), padx=5)
- self.height_label = ttk.Label(prop_frame, text="40")
- self.height_label.grid(row=1, column=2)
- # Opacidade
- ttk.Label(prop_frame, text="Opacidade:").grid(row=2, column=0, sticky=tk.W)
- self.opacity_var = tk.IntVar(value=70)
- self.opacity_scale = ttk.Scale(prop_frame, from_=10, to=100, variable=self.opacity_var,
- command=self.update_opacity)
- self.opacity_scale.grid(row=2, column=1, sticky=(tk.W, tk.E), padx=5)
- self.opacity_label = ttk.Label(prop_frame, text="70%")
- self.opacity_label.grid(row=2, column=2)
- # Forma do botão
- ttk.Label(prop_frame, text="Forma:").grid(row=3, column=0, sticky=tk.W)
- self.shape_var = tk.StringVar(value="rectangle")
- shape_combo = ttk.Combobox(prop_frame, textvariable=self.shape_var,
- values=["rectangle", "rounded", "circle"], width=15)
- shape_combo.grid(row=3, column=1, columnspan=2, sticky=tk.W, padx=5)
- shape_combo.bind('<<ComboboxSelected>>', self.update_button_shape)
- # Cor do botão
- self.color_btn = ttk.Button(prop_frame, text="🎨 Cor", command=self.choose_color)
- self.color_btn.grid(row=4, column=0, columnspan=3, pady=5)
- # Botões de ação
- action_frame = ttk.Frame(main_frame)
- action_frame.grid(row=5, column=0, columnspan=2, pady=10)
- ttk.Button(action_frame, text="💾 Salvar", command=self.save_config).pack(side=tk.LEFT, padx=5)
- ttk.Button(action_frame, text="🔄 Recarregar", command=self.load_config).pack(side=tk.LEFT, padx=5)
- ttk.Button(action_frame, text="❌ Remover", command=self.remove_button).pack(side=tk.LEFT, padx=5)
- # Status bar
- self.status_label = ttk.Label(main_frame, text="Pronto", relief=tk.SUNKEN)
- self.status_label.grid(row=6, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5)
- # Configurar grid weights
- main_frame.grid_rowconfigure(3, weight=1)
- main_frame.grid_columnconfigure(0, weight=1)
- def start_process_monitor(self):
- """Monitora processo ativo"""
- def monitor():
- while True:
- try:
- hwnd = win32gui.GetForegroundWindow()
- _, pid = win32process.GetWindowThreadProcessId(hwnd)
- process = psutil.Process(pid)
- process_name = process.name()
- if process_name not in ['python.exe', 'pythonw.exe', 'cmd.exe']:
- if self.current_process != process_name:
- self.current_process = process_name
- self.root.after(0, self.on_process_changed)
- except:
- pass
- time.sleep(1)
- thread = threading.Thread(target=monitor, daemon=True)
- thread.start()
- def on_process_changed(self):
- """Quando processo muda"""
- self.process_label.config(text=self.current_process or "Nenhum",
- foreground="green" if self.current_process else "red")
- if self.current_process:
- self.toggle_btn.config(state='normal')
- self.edit_btn.config(state='normal')
- self.add_btn.config(state='normal')
- self.clear_btn.config(state='normal')
- self.load_config()
- else:
- self.toggle_btn.config(state='disabled')
- self.edit_btn.config(state='disabled')
- self.add_btn.config(state='disabled')
- self.clear_btn.config(state='disabled')
- self.close_overlays()
- def toggle_mapping(self):
- """Ativa/desativa mapeamento"""
- if self.is_active:
- self.is_active = False
- self.toggle_btn.config(text="▶ Ativar Mapeamento")
- self.close_overlays()
- self.status_label.config(text="Mapeamento desativado")
- else:
- self.is_active = True
- self.toggle_btn.config(text="⏸ Desativar Mapeamento")
- self.create_overlays()
- self.status_label.config(text="Mapeamento ativado")
- def toggle_edit_mode(self):
- """Ativa/desativa modo edição"""
- self.edit_mode = not self.edit_mode
- if self.edit_mode:
- self.edit_btn.config(text="✅ Sair da Edição")
- self.status_label.config(text="Modo edição ativado")
- if self.is_active:
- self.update_overlays()
- else:
- self.edit_btn.config(text="✏️ Modo Edição")
- self.status_label.config(text="Modo edição desativado")
- self.save_config()
- if self.is_active:
- self.update_overlays()
- def add_button(self):
- """Adiciona novo botão"""
- if not self.current_process:
- return
- button_id = f"btn_{len(self.current_config)}"
- self.current_config[button_id] = {
- 'x': 100 + len(self.current_config) * 20,
- 'y': 100 + len(self.current_config) * 20,
- 'width': self.width_var.get(),
- 'height': self.height_var.get(),
- 'color': '#4CAF50',
- 'opacity': self.opacity_var.get() / 100,
- 'shape': self.shape_var.get(),
- 'label': f"Botão {len(self.current_config) + 1}",
- 'target_x': 0,
- 'target_y': 0
- }
- self.update_button_list()
- self.save_config()
- if self.is_active:
- self.update_overlays()
- self.status_label.config(text=f"Botão adicionado: {button_id}")
- def create_overlays(self):
- """Cria overlays de botões"""
- self.close_overlays()
- for button_id, config in self.current_config.items():
- overlay = ButtonOverlay(self, button_id, config)
- self.overlay_windows.append(overlay)
- def update_overlays(self):
- """Atualiza overlays existentes"""
- if self.is_active:
- self.close_overlays()
- self.create_overlays()
- def close_overlays(self):
- """Fecha todos os overlays"""
- for overlay in self.overlay_windows:
- overlay.destroy()
- self.overlay_windows = []
- def update_button_list(self):
- """Atualiza lista de botões"""
- self.button_listbox.delete(0, tk.END)
- for button_id, config in self.current_config.items():
- self.button_listbox.insert(tk.END, f"{button_id}: {config['label']}")
- def on_select_button(self, event):
- """Quando seleciona botão na lista"""
- selection = self.button_listbox.curselection()
- if selection:
- index = selection[0]
- button_id = list(self.current_config.keys())[index]
- self.selected_button = button_id
- config = self.current_config[button_id]
- # Atualizar controles
- self.width_var.set(config['width'])
- self.height_var.set(config['height'])
- self.opacity_var.set(int(config['opacity'] * 100))
- self.shape_var.set(config['shape'])
- def update_button_size(self, value=None):
- """Atualiza tamanho do botão"""
- self.width_label.config(text=str(self.width_var.get()))
- self.height_label.config(text=str(self.height_var.get()))
- if self.selected_button and self.selected_button in self.current_config:
- self.current_config[self.selected_button]['width'] = self.width_var.get()
- self.current_config[self.selected_button]['height'] = self.height_var.get()
- if self.is_active:
- self.update_overlays()
- def update_opacity(self, value=None):
- """Atualiza opacidade"""
- self.opacity_label.config(text=f"{self.opacity_var.get()}%")
- if self.selected_button and self.selected_button in self.current_config:
- self.current_config[self.selected_button]['opacity'] = self.opacity_var.get() / 100
- if self.is_active:
- self.update_overlays()
- def update_button_shape(self, event=None):
- """Atualiza forma do botão"""
- if self.selected_button and self.selected_button in self.current_config:
- self.current_config[self.selected_button]['shape'] = self.shape_var.get()
- if self.is_active:
- self.update_overlays()
- def choose_color(self):
- """Escolhe cor do botão"""
- if not self.selected_button:
- messagebox.showwarning("Aviso", "Selecione um botão primeiro!")
- return
- color = colorchooser.askcolor()[1]
- if color:
- self.current_config[self.selected_button]['color'] = color
- if self.is_active:
- self.update_overlays()
- def remove_button(self):
- """Remove botão selecionado"""
- if not self.selected_button:
- messagebox.showwarning("Aviso", "Selecione um botão primeiro!")
- return
- if messagebox.askyesno("Confirmar", f"Remover {self.selected_button}?"):
- del self.current_config[self.selected_button]
- self.selected_button = None
- self.update_button_list()
- self.save_config()
- if self.is_active:
- self.update_overlays()
- def clear_all(self):
- """Limpa todos os botões"""
- if messagebox.askyesno("Confirmar", "Remover todos os botões?"):
- self.current_config = {}
- self.selected_button = None
- self.update_button_list()
- self.save_config()
- if self.is_active:
- self.close_overlays()
- def save_config(self):
- """Salva configuração"""
- if not self.current_process:
- return
- config_file = os.path.join(self.config_dir, f"{self.current_process}.json")
- try:
- with open(config_file, 'w') as f:
- json.dump(self.current_config, f, indent=2)
- self.status_label.config(text="Configuração salva")
- except Exception as e:
- self.status_label.config(text=f"Erro ao salvar: {e}")
- def load_config(self):
- """Carrega configuração"""
- if not self.current_process:
- return
- config_file = os.path.join(self.config_dir, f"{self.current_process}.json")
- if os.path.exists(config_file):
- try:
- with open(config_file, 'r') as f:
- self.current_config = json.load(f)
- self.update_button_list()
- self.status_label.config(text="Configuração carregada")
- except Exception as e:
- self.status_label.config(text=f"Erro ao carregar: {e}")
- self.current_config = {}
- else:
- self.current_config = {}
- self.update_button_list()
- def humanized_click(self, x, y):
- """Clique humanizado com proteção"""
- current_time = time.time()
- if current_time - self.last_click_time < self.click_delay:
- time.sleep(self.click_delay)
- # Adiciona pequena variação aleatória
- x += random.randint(-2, 2)
- y += random.randint(-2, 2)
- # Movimento suave do mouse
- pyautogui.moveTo(x, y, duration=0.1)
- time.sleep(0.05)
- pyautogui.click(x, y)
- self.last_click_time = current_time
- def run(self):
- """Inicia aplicação"""
- self.root.mainloop()
- class ButtonOverlay(tk.Toplevel):
- """Overlay individual de botão"""
- def __init__(self, parent, button_id, config):
- super().__init__()
- self.parent = parent
- self.button_id = button_id
- self.config = config
- self.dragging = False
- self.start_x = 0
- self.start_y = 0
- self.setup_window()
- self.create_button()
- def setup_window(self):
- """Configura janela overlay"""
- self.overrideredirect(True)
- self.attributes('-topmost', True)
- self.attributes('-alpha', self.config['opacity'])
- # Posição e tamanho
- self.geometry(f"{self.config['width']}x{self.config['height']}+"
- f"{self.config['x']}+{self.config['y']}")
- # Transparência para cliques quando não em modo edição
- if not self.parent.edit_mode:
- self.attributes('-transparentcolor', 'white')
- def create_button(self):
- """Cria visual do botão"""
- self.canvas = tk.Canvas(self, width=self.config['width'],
- height=self.config['height'],
- highlightthickness=0)
- self.canvas.pack(fill=tk.BOTH, expand=True)
- # Desenha forma do botão
- if self.config['shape'] == 'circle':
- self.draw_circle()
- elif self.config['shape'] == 'rounded':
- self.draw_rounded_rect()
- else:
- self.draw_rectangle()
- # Adiciona texto
- self.canvas.create_text(self.config['width']//2, self.config['height']//2,
- text=self.config['label'], fill='white',
- font=('Arial', 10, 'bold'))
- # Bindings
- if self.parent.edit_mode:
- self.canvas.bind('<Button-1>', self.on_click)
- self.canvas.bind('<B1-Motion>', self.on_drag)
- self.canvas.bind('<ButtonRelease-1>', self.on_release)
- self.canvas.bind('<Button-3>', self.set_target) # Botão direito para definir alvo
- # Borda de edição
- self.canvas.create_rectangle(2, 2, self.config['width']-2,
- self.config['height']-2,
- outline='yellow', width=2, dash=(5, 5))
- else:
- self.canvas.bind('<Button-1>', self.on_action_click)
- def draw_rectangle(self):
- """Desenha retângulo"""
- self.canvas.create_rectangle(0, 0, self.config['width'],
- self.config['height'],
- fill=self.config['color'], outline='')
- def draw_rounded_rect(self):
- """Desenha retângulo arredondado"""
- radius = 10
- x1, y1, x2, y2 = 0, 0, self.config['width'], self.config['height']
- points = [
- x1+radius, y1,
- x2-radius, y1,
- x2, y1,
- x2, y1+radius,
- x2, y2-radius,
- x2, y2,
- x2-radius, y2,
- x1+radius, y2,
- x1, y2,
- x1, y2-radius,
- x1, y1+radius,
- x1, y1
- ]
- self.canvas.create_polygon(points, fill=self.config['color'],
- smooth=True, outline='')
- def draw_circle(self):
- """Desenha círculo"""
- size = min(self.config['width'], self.config['height'])
- self.canvas.create_oval((self.config['width']-size)//2,
- (self.config['height']-size)//2,
- (self.config['width']+size)//2,
- (self.config['height']+size)//2,
- fill=self.config['color'], outline='')
- def on_click(self, event):
- """Início do arraste"""
- self.dragging = True
- self.start_x = event.x_root - self.winfo_x()
- self.start_y = event.y_root - self.winfo_y()
- def on_drag(self, event):
- """Durante o arraste"""
- if self.dragging:
- x = event.x_root - self.start_x
- y = event.y_root - self.start_y
- self.geometry(f"+{x}+{y}")
- # Atualiza configuração
- self.config['x'] = x
- self.config['y'] = y
- self.parent.current_config[self.button_id] = self.config
- def on_release(self, event):
- """Fim do arraste"""
- self.dragging = False
- self.parent.save_config()
- def set_target(self, event):
- """Define posição alvo para clique"""
- x, y = pyautogui.position()
- self.config['target_x'] = x
- self.config['target_y'] = y
- self.parent.current_config[self.button_id] = self.config
- self.parent.save_config()
- # Feedback visual
- self.canvas.create_text(self.config['width']//2,
- self.config['height']//2 + 15,
- text=f"Alvo: {x},{y}", fill='yellow',
- font=('Arial', 8), tags='target')
- self.after(2000, lambda: self.canvas.delete('target'))
- def on_action_click(self, event):
- """Clique de ação (não edição)"""
- if self.config['target_x'] and self.config['target_y']:
- # Clique humanizado no alvo
- threading.Thread(target=lambda: self.parent.humanized_click(
- self.config['target_x'], self.config['target_y']
- )).start()
- # Feedback visual
- original_color = self.config['color']
- self.canvas.itemconfig(1, fill='white')
- self.after(100, lambda: self.canvas.itemconfig(1, fill=original_color))
- def main():
- """Função principal"""
- try:
- # Verifica dependências
- import win32gui
- import pyautogui
- from PIL import Image
- except ImportError as e:
- print(f"Erro: Instale as dependências necessárias")
- print("pip install pywin32 pyautogui pillow psutil")
- return
- # Configurações de segurança do pyautogui
- pyautogui.FAILSAFE = True
- pyautogui.PAUSE = 0.1
- # Inicia aplicação
- app = ButtonMapper()
- app.run()
- if __name__ == "__main__":
- main()
Add Comment
Please, Sign In to add comment