Nevzyn

Untitled

Oct 22nd, 2025
25
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 23.54 KB | None | 0 0
  1. import tkinter as tk
  2. from tkinter import ttk, messagebox, colorchooser
  3. import json
  4. import os
  5. import hashlib
  6. import win32gui
  7. import win32process
  8. import psutil
  9. import pyautogui
  10. from datetime import datetime
  11. import threading
  12. import time
  13. from PIL import Image, ImageTk, ImageDraw
  14. import random
  15. import string
  16.  
  17. class ButtonMapper:
  18. def __init__(self):
  19. self.root = tk.Tk()
  20. self.root.title("Interface Mapper Pro v2.0")
  21. self.root.geometry("400x600")
  22. self.root.attributes('-topmost', True)
  23. self.root.attributes('-alpha', 0.95)
  24.  
  25. # Configurações
  26. self.config_dir = "mapper_configs"
  27. self.current_process = None
  28. self.overlay_windows = []
  29. self.is_active = False
  30. self.edit_mode = False
  31. self.current_config = {}
  32. self.selected_button = None
  33.  
  34. # Proteção e segurança
  35. self.security_token = self.generate_token()
  36. self.click_delay = 0.05 # Delay humanizado
  37. self.last_click_time = 0
  38.  
  39. # Criar diretório de configurações
  40. if not os.path.exists(self.config_dir):
  41. os.makedirs(self.config_dir)
  42.  
  43. self.setup_ui()
  44. self.start_process_monitor()
  45.  
  46. def generate_token(self):
  47. """Gera token único para sessão"""
  48. return ''.join(random.choices(string.ascii_letters + string.digits, k=32))
  49.  
  50. def setup_ui(self):
  51. """Configura interface principal"""
  52. style = ttk.Style()
  53. style.theme_use('clam')
  54.  
  55. # Frame principal
  56. main_frame = ttk.Frame(self.root, padding="10")
  57. main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
  58.  
  59. # Título
  60. title_label = ttk.Label(main_frame, text="🎮 Interface Mapper Pro",
  61. font=('Arial', 14, 'bold'))
  62. title_label.grid(row=0, column=0, columnspan=2, pady=10)
  63.  
  64. # Status do processo
  65. ttk.Label(main_frame, text="Processo Ativo:").grid(row=1, column=0, sticky=tk.W, pady=5)
  66. self.process_label = ttk.Label(main_frame, text="Nenhum", foreground="red")
  67. self.process_label.grid(row=1, column=1, sticky=tk.W, pady=5)
  68.  
  69. # Frame de controles
  70. control_frame = ttk.LabelFrame(main_frame, text="Controles", padding="10")
  71. control_frame.grid(row=2, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=10)
  72.  
  73. # Botão Ativar/Desativar
  74. self.toggle_btn = ttk.Button(control_frame, text="▶ Ativar Mapeamento",
  75. command=self.toggle_mapping, state='disabled')
  76. self.toggle_btn.grid(row=0, column=0, padx=5, pady=5, sticky=(tk.W, tk.E))
  77.  
  78. # Botão Modo Edição
  79. self.edit_btn = ttk.Button(control_frame, text="✏️ Modo Edição",
  80. command=self.toggle_edit_mode, state='disabled')
  81. self.edit_btn.grid(row=0, column=1, padx=5, pady=5, sticky=(tk.W, tk.E))
  82.  
  83. # Botão Adicionar
  84. self.add_btn = ttk.Button(control_frame, text="➕ Adicionar Botão",
  85. command=self.add_button, state='disabled')
  86. self.add_btn.grid(row=1, column=0, padx=5, pady=5, sticky=(tk.W, tk.E))
  87.  
  88. # Botão Limpar
  89. self.clear_btn = ttk.Button(control_frame, text="🗑️ Limpar Tudo",
  90. command=self.clear_all, state='disabled')
  91. self.clear_btn.grid(row=1, column=1, padx=5, pady=5, sticky=(tk.W, tk.E))
  92.  
  93. # Frame de botões mapeados
  94. list_frame = ttk.LabelFrame(main_frame, text="Botões Mapeados", padding="10")
  95. list_frame.grid(row=3, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=10)
  96.  
  97. # Lista de botões
  98. scrollbar = ttk.Scrollbar(list_frame)
  99. scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
  100.  
  101. self.button_listbox = tk.Listbox(list_frame, yscrollcommand=scrollbar.set, height=10)
  102. self.button_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
  103. self.button_listbox.bind('<<ListboxSelect>>', self.on_select_button)
  104. scrollbar.config(command=self.button_listbox.yview)
  105.  
  106. # Frame de propriedades
  107. prop_frame = ttk.LabelFrame(main_frame, text="Propriedades", padding="10")
  108. prop_frame.grid(row=4, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=10)
  109.  
  110. # Controles de tamanho
  111. ttk.Label(prop_frame, text="Largura:").grid(row=0, column=0, sticky=tk.W)
  112. self.width_var = tk.IntVar(value=80)
  113. self.width_scale = ttk.Scale(prop_frame, from_=30, to=200, variable=self.width_var,
  114. command=self.update_button_size)
  115. self.width_scale.grid(row=0, column=1, sticky=(tk.W, tk.E), padx=5)
  116. self.width_label = ttk.Label(prop_frame, text="80")
  117. self.width_label.grid(row=0, column=2)
  118.  
  119. ttk.Label(prop_frame, text="Altura:").grid(row=1, column=0, sticky=tk.W)
  120. self.height_var = tk.IntVar(value=40)
  121. self.height_scale = ttk.Scale(prop_frame, from_=20, to=150, variable=self.height_var,
  122. command=self.update_button_size)
  123. self.height_scale.grid(row=1, column=1, sticky=(tk.W, tk.E), padx=5)
  124. self.height_label = ttk.Label(prop_frame, text="40")
  125. self.height_label.grid(row=1, column=2)
  126.  
  127. # Opacidade
  128. ttk.Label(prop_frame, text="Opacidade:").grid(row=2, column=0, sticky=tk.W)
  129. self.opacity_var = tk.IntVar(value=70)
  130. self.opacity_scale = ttk.Scale(prop_frame, from_=10, to=100, variable=self.opacity_var,
  131. command=self.update_opacity)
  132. self.opacity_scale.grid(row=2, column=1, sticky=(tk.W, tk.E), padx=5)
  133. self.opacity_label = ttk.Label(prop_frame, text="70%")
  134. self.opacity_label.grid(row=2, column=2)
  135.  
  136. # Forma do botão
  137. ttk.Label(prop_frame, text="Forma:").grid(row=3, column=0, sticky=tk.W)
  138. self.shape_var = tk.StringVar(value="rectangle")
  139. shape_combo = ttk.Combobox(prop_frame, textvariable=self.shape_var,
  140. values=["rectangle", "rounded", "circle"], width=15)
  141. shape_combo.grid(row=3, column=1, columnspan=2, sticky=tk.W, padx=5)
  142. shape_combo.bind('<<ComboboxSelected>>', self.update_button_shape)
  143.  
  144. # Cor do botão
  145. self.color_btn = ttk.Button(prop_frame, text="🎨 Cor", command=self.choose_color)
  146. self.color_btn.grid(row=4, column=0, columnspan=3, pady=5)
  147.  
  148. # Botões de ação
  149. action_frame = ttk.Frame(main_frame)
  150. action_frame.grid(row=5, column=0, columnspan=2, pady=10)
  151.  
  152. ttk.Button(action_frame, text="💾 Salvar", command=self.save_config).pack(side=tk.LEFT, padx=5)
  153. ttk.Button(action_frame, text="🔄 Recarregar", command=self.load_config).pack(side=tk.LEFT, padx=5)
  154. ttk.Button(action_frame, text="❌ Remover", command=self.remove_button).pack(side=tk.LEFT, padx=5)
  155.  
  156. # Status bar
  157. self.status_label = ttk.Label(main_frame, text="Pronto", relief=tk.SUNKEN)
  158. self.status_label.grid(row=6, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5)
  159.  
  160. # Configurar grid weights
  161. main_frame.grid_rowconfigure(3, weight=1)
  162. main_frame.grid_columnconfigure(0, weight=1)
  163.  
  164. def start_process_monitor(self):
  165. """Monitora processo ativo"""
  166. def monitor():
  167. while True:
  168. try:
  169. hwnd = win32gui.GetForegroundWindow()
  170. _, pid = win32process.GetWindowThreadProcessId(hwnd)
  171. process = psutil.Process(pid)
  172. process_name = process.name()
  173.  
  174. if process_name not in ['python.exe', 'pythonw.exe', 'cmd.exe']:
  175. if self.current_process != process_name:
  176. self.current_process = process_name
  177. self.root.after(0, self.on_process_changed)
  178. except:
  179. pass
  180.  
  181. time.sleep(1)
  182.  
  183. thread = threading.Thread(target=monitor, daemon=True)
  184. thread.start()
  185.  
  186. def on_process_changed(self):
  187. """Quando processo muda"""
  188. self.process_label.config(text=self.current_process or "Nenhum",
  189. foreground="green" if self.current_process else "red")
  190.  
  191. if self.current_process:
  192. self.toggle_btn.config(state='normal')
  193. self.edit_btn.config(state='normal')
  194. self.add_btn.config(state='normal')
  195. self.clear_btn.config(state='normal')
  196. self.load_config()
  197. else:
  198. self.toggle_btn.config(state='disabled')
  199. self.edit_btn.config(state='disabled')
  200. self.add_btn.config(state='disabled')
  201. self.clear_btn.config(state='disabled')
  202. self.close_overlays()
  203.  
  204. def toggle_mapping(self):
  205. """Ativa/desativa mapeamento"""
  206. if self.is_active:
  207. self.is_active = False
  208. self.toggle_btn.config(text="▶ Ativar Mapeamento")
  209. self.close_overlays()
  210. self.status_label.config(text="Mapeamento desativado")
  211. else:
  212. self.is_active = True
  213. self.toggle_btn.config(text="⏸ Desativar Mapeamento")
  214. self.create_overlays()
  215. self.status_label.config(text="Mapeamento ativado")
  216.  
  217. def toggle_edit_mode(self):
  218. """Ativa/desativa modo edição"""
  219. self.edit_mode = not self.edit_mode
  220. if self.edit_mode:
  221. self.edit_btn.config(text="✅ Sair da Edição")
  222. self.status_label.config(text="Modo edição ativado")
  223. if self.is_active:
  224. self.update_overlays()
  225. else:
  226. self.edit_btn.config(text="✏️ Modo Edição")
  227. self.status_label.config(text="Modo edição desativado")
  228. self.save_config()
  229. if self.is_active:
  230. self.update_overlays()
  231.  
  232. def add_button(self):
  233. """Adiciona novo botão"""
  234. if not self.current_process:
  235. return
  236.  
  237. button_id = f"btn_{len(self.current_config)}"
  238. self.current_config[button_id] = {
  239. 'x': 100 + len(self.current_config) * 20,
  240. 'y': 100 + len(self.current_config) * 20,
  241. 'width': self.width_var.get(),
  242. 'height': self.height_var.get(),
  243. 'color': '#4CAF50',
  244. 'opacity': self.opacity_var.get() / 100,
  245. 'shape': self.shape_var.get(),
  246. 'label': f"Botão {len(self.current_config) + 1}",
  247. 'target_x': 0,
  248. 'target_y': 0
  249. }
  250.  
  251. self.update_button_list()
  252. self.save_config()
  253.  
  254. if self.is_active:
  255. self.update_overlays()
  256.  
  257. self.status_label.config(text=f"Botão adicionado: {button_id}")
  258.  
  259. def create_overlays(self):
  260. """Cria overlays de botões"""
  261. self.close_overlays()
  262.  
  263. for button_id, config in self.current_config.items():
  264. overlay = ButtonOverlay(self, button_id, config)
  265. self.overlay_windows.append(overlay)
  266.  
  267. def update_overlays(self):
  268. """Atualiza overlays existentes"""
  269. if self.is_active:
  270. self.close_overlays()
  271. self.create_overlays()
  272.  
  273. def close_overlays(self):
  274. """Fecha todos os overlays"""
  275. for overlay in self.overlay_windows:
  276. overlay.destroy()
  277. self.overlay_windows = []
  278.  
  279. def update_button_list(self):
  280. """Atualiza lista de botões"""
  281. self.button_listbox.delete(0, tk.END)
  282. for button_id, config in self.current_config.items():
  283. self.button_listbox.insert(tk.END, f"{button_id}: {config['label']}")
  284.  
  285. def on_select_button(self, event):
  286. """Quando seleciona botão na lista"""
  287. selection = self.button_listbox.curselection()
  288. if selection:
  289. index = selection[0]
  290. button_id = list(self.current_config.keys())[index]
  291. self.selected_button = button_id
  292. config = self.current_config[button_id]
  293.  
  294. # Atualizar controles
  295. self.width_var.set(config['width'])
  296. self.height_var.set(config['height'])
  297. self.opacity_var.set(int(config['opacity'] * 100))
  298. self.shape_var.set(config['shape'])
  299.  
  300. def update_button_size(self, value=None):
  301. """Atualiza tamanho do botão"""
  302. self.width_label.config(text=str(self.width_var.get()))
  303. self.height_label.config(text=str(self.height_var.get()))
  304.  
  305. if self.selected_button and self.selected_button in self.current_config:
  306. self.current_config[self.selected_button]['width'] = self.width_var.get()
  307. self.current_config[self.selected_button]['height'] = self.height_var.get()
  308.  
  309. if self.is_active:
  310. self.update_overlays()
  311.  
  312. def update_opacity(self, value=None):
  313. """Atualiza opacidade"""
  314. self.opacity_label.config(text=f"{self.opacity_var.get()}%")
  315.  
  316. if self.selected_button and self.selected_button in self.current_config:
  317. self.current_config[self.selected_button]['opacity'] = self.opacity_var.get() / 100
  318.  
  319. if self.is_active:
  320. self.update_overlays()
  321.  
  322. def update_button_shape(self, event=None):
  323. """Atualiza forma do botão"""
  324. if self.selected_button and self.selected_button in self.current_config:
  325. self.current_config[self.selected_button]['shape'] = self.shape_var.get()
  326.  
  327. if self.is_active:
  328. self.update_overlays()
  329.  
  330. def choose_color(self):
  331. """Escolhe cor do botão"""
  332. if not self.selected_button:
  333. messagebox.showwarning("Aviso", "Selecione um botão primeiro!")
  334. return
  335.  
  336. color = colorchooser.askcolor()[1]
  337. if color:
  338. self.current_config[self.selected_button]['color'] = color
  339.  
  340. if self.is_active:
  341. self.update_overlays()
  342.  
  343. def remove_button(self):
  344. """Remove botão selecionado"""
  345. if not self.selected_button:
  346. messagebox.showwarning("Aviso", "Selecione um botão primeiro!")
  347. return
  348.  
  349. if messagebox.askyesno("Confirmar", f"Remover {self.selected_button}?"):
  350. del self.current_config[self.selected_button]
  351. self.selected_button = None
  352. self.update_button_list()
  353. self.save_config()
  354.  
  355. if self.is_active:
  356. self.update_overlays()
  357.  
  358. def clear_all(self):
  359. """Limpa todos os botões"""
  360. if messagebox.askyesno("Confirmar", "Remover todos os botões?"):
  361. self.current_config = {}
  362. self.selected_button = None
  363. self.update_button_list()
  364. self.save_config()
  365.  
  366. if self.is_active:
  367. self.close_overlays()
  368.  
  369. def save_config(self):
  370. """Salva configuração"""
  371. if not self.current_process:
  372. return
  373.  
  374. config_file = os.path.join(self.config_dir, f"{self.current_process}.json")
  375.  
  376. try:
  377. with open(config_file, 'w') as f:
  378. json.dump(self.current_config, f, indent=2)
  379. self.status_label.config(text="Configuração salva")
  380. except Exception as e:
  381. self.status_label.config(text=f"Erro ao salvar: {e}")
  382.  
  383. def load_config(self):
  384. """Carrega configuração"""
  385. if not self.current_process:
  386. return
  387.  
  388. config_file = os.path.join(self.config_dir, f"{self.current_process}.json")
  389.  
  390. if os.path.exists(config_file):
  391. try:
  392. with open(config_file, 'r') as f:
  393. self.current_config = json.load(f)
  394. self.update_button_list()
  395. self.status_label.config(text="Configuração carregada")
  396. except Exception as e:
  397. self.status_label.config(text=f"Erro ao carregar: {e}")
  398. self.current_config = {}
  399. else:
  400. self.current_config = {}
  401. self.update_button_list()
  402.  
  403. def humanized_click(self, x, y):
  404. """Clique humanizado com proteção"""
  405. current_time = time.time()
  406. if current_time - self.last_click_time < self.click_delay:
  407. time.sleep(self.click_delay)
  408.  
  409. # Adiciona pequena variação aleatória
  410. x += random.randint(-2, 2)
  411. y += random.randint(-2, 2)
  412.  
  413. # Movimento suave do mouse
  414. pyautogui.moveTo(x, y, duration=0.1)
  415. time.sleep(0.05)
  416. pyautogui.click(x, y)
  417.  
  418. self.last_click_time = current_time
  419.  
  420. def run(self):
  421. """Inicia aplicação"""
  422. self.root.mainloop()
  423.  
  424.  
  425. class ButtonOverlay(tk.Toplevel):
  426. """Overlay individual de botão"""
  427.  
  428. def __init__(self, parent, button_id, config):
  429. super().__init__()
  430. self.parent = parent
  431. self.button_id = button_id
  432. self.config = config
  433. self.dragging = False
  434. self.start_x = 0
  435. self.start_y = 0
  436.  
  437. self.setup_window()
  438. self.create_button()
  439.  
  440. def setup_window(self):
  441. """Configura janela overlay"""
  442. self.overrideredirect(True)
  443. self.attributes('-topmost', True)
  444. self.attributes('-alpha', self.config['opacity'])
  445.  
  446. # Posição e tamanho
  447. self.geometry(f"{self.config['width']}x{self.config['height']}+"
  448. f"{self.config['x']}+{self.config['y']}")
  449.  
  450. # Transparência para cliques quando não em modo edição
  451. if not self.parent.edit_mode:
  452. self.attributes('-transparentcolor', 'white')
  453.  
  454. def create_button(self):
  455. """Cria visual do botão"""
  456. self.canvas = tk.Canvas(self, width=self.config['width'],
  457. height=self.config['height'],
  458. highlightthickness=0)
  459. self.canvas.pack(fill=tk.BOTH, expand=True)
  460.  
  461. # Desenha forma do botão
  462. if self.config['shape'] == 'circle':
  463. self.draw_circle()
  464. elif self.config['shape'] == 'rounded':
  465. self.draw_rounded_rect()
  466. else:
  467. self.draw_rectangle()
  468.  
  469. # Adiciona texto
  470. self.canvas.create_text(self.config['width']//2, self.config['height']//2,
  471. text=self.config['label'], fill='white',
  472. font=('Arial', 10, 'bold'))
  473.  
  474. # Bindings
  475. if self.parent.edit_mode:
  476. self.canvas.bind('<Button-1>', self.on_click)
  477. self.canvas.bind('<B1-Motion>', self.on_drag)
  478. self.canvas.bind('<ButtonRelease-1>', self.on_release)
  479. self.canvas.bind('<Button-3>', self.set_target) # Botão direito para definir alvo
  480.  
  481. # Borda de edição
  482. self.canvas.create_rectangle(2, 2, self.config['width']-2,
  483. self.config['height']-2,
  484. outline='yellow', width=2, dash=(5, 5))
  485. else:
  486. self.canvas.bind('<Button-1>', self.on_action_click)
  487.  
  488. def draw_rectangle(self):
  489. """Desenha retângulo"""
  490. self.canvas.create_rectangle(0, 0, self.config['width'],
  491. self.config['height'],
  492. fill=self.config['color'], outline='')
  493.  
  494. def draw_rounded_rect(self):
  495. """Desenha retângulo arredondado"""
  496. radius = 10
  497. x1, y1, x2, y2 = 0, 0, self.config['width'], self.config['height']
  498.  
  499. points = [
  500. x1+radius, y1,
  501. x2-radius, y1,
  502. x2, y1,
  503. x2, y1+radius,
  504. x2, y2-radius,
  505. x2, y2,
  506. x2-radius, y2,
  507. x1+radius, y2,
  508. x1, y2,
  509. x1, y2-radius,
  510. x1, y1+radius,
  511. x1, y1
  512. ]
  513.  
  514. self.canvas.create_polygon(points, fill=self.config['color'],
  515. smooth=True, outline='')
  516.  
  517. def draw_circle(self):
  518. """Desenha círculo"""
  519. size = min(self.config['width'], self.config['height'])
  520. self.canvas.create_oval((self.config['width']-size)//2,
  521. (self.config['height']-size)//2,
  522. (self.config['width']+size)//2,
  523. (self.config['height']+size)//2,
  524. fill=self.config['color'], outline='')
  525.  
  526. def on_click(self, event):
  527. """Início do arraste"""
  528. self.dragging = True
  529. self.start_x = event.x_root - self.winfo_x()
  530. self.start_y = event.y_root - self.winfo_y()
  531.  
  532. def on_drag(self, event):
  533. """Durante o arraste"""
  534. if self.dragging:
  535. x = event.x_root - self.start_x
  536. y = event.y_root - self.start_y
  537. self.geometry(f"+{x}+{y}")
  538.  
  539. # Atualiza configuração
  540. self.config['x'] = x
  541. self.config['y'] = y
  542. self.parent.current_config[self.button_id] = self.config
  543.  
  544. def on_release(self, event):
  545. """Fim do arraste"""
  546. self.dragging = False
  547. self.parent.save_config()
  548.  
  549. def set_target(self, event):
  550. """Define posição alvo para clique"""
  551. x, y = pyautogui.position()
  552. self.config['target_x'] = x
  553. self.config['target_y'] = y
  554. self.parent.current_config[self.button_id] = self.config
  555. self.parent.save_config()
  556.  
  557. # Feedback visual
  558. self.canvas.create_text(self.config['width']//2,
  559. self.config['height']//2 + 15,
  560. text=f"Alvo: {x},{y}", fill='yellow',
  561. font=('Arial', 8), tags='target')
  562. self.after(2000, lambda: self.canvas.delete('target'))
  563.  
  564. def on_action_click(self, event):
  565. """Clique de ação (não edição)"""
  566. if self.config['target_x'] and self.config['target_y']:
  567. # Clique humanizado no alvo
  568. threading.Thread(target=lambda: self.parent.humanized_click(
  569. self.config['target_x'], self.config['target_y']
  570. )).start()
  571.  
  572. # Feedback visual
  573. original_color = self.config['color']
  574. self.canvas.itemconfig(1, fill='white')
  575. self.after(100, lambda: self.canvas.itemconfig(1, fill=original_color))
  576.  
  577.  
  578. def main():
  579. """Função principal"""
  580. try:
  581. # Verifica dependências
  582. import win32gui
  583. import pyautogui
  584. from PIL import Image
  585. except ImportError as e:
  586. print(f"Erro: Instale as dependências necessárias")
  587. print("pip install pywin32 pyautogui pillow psutil")
  588. return
  589.  
  590. # Configurações de segurança do pyautogui
  591. pyautogui.FAILSAFE = True
  592. pyautogui.PAUSE = 0.1
  593.  
  594. # Inicia aplicação
  595. app = ButtonMapper()
  596. app.run()
  597.  
  598.  
  599. if __name__ == "__main__":
  600. main()
Add Comment
Please, Sign In to add comment