Created
July 7, 2026 11:13
-
-
Save zr0n/01366b4ac002d104854d71d52f54067c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import pyautogui | |
| import time | |
| import sys | |
| import pygetwindow as gw | |
| import random | |
| import threading | |
| import keyboard | |
| # Evento global disparado pela hotkey de parada (Ctrl+Alt+X) | |
| stop_event = threading.Event() | |
| # Hotkey que encerra o script de qualquer janela | |
| STOP_HOTKEY = 'ctrl+alt+x' | |
| # Intervalo padrão entre ciclos principais (segundos) | |
| DEFAULT_INTERVAL = 20 | |
| # Apps que devem ser IGNORADOS ao escolher a janela alvo. | |
| # A ideia e interagir em qualquer janela que NAO seja essas. | |
| EXCLUDED_APPS = ('slack', 'discord') | |
| NOTEPAD_BLOCKS = [ | |
| ( | |
| "reuniao de alinhamento amanha as 9h - precisamos definir as prioridades do sprint\n" | |
| "confirmar presenca de todos do time antes de fechar a pauta\n" | |
| "pedir para o pedro preparar os slides com os numeros do ultimo mes\n" | |
| "nao esquecer de incluir o ponto sobre a migracao do banco de dados" | |
| ), | |
| ( | |
| "itens pendentes para revisao antes do deploy de sexta:\n" | |
| "- testes de integracao passando em todos os ambientes\n" | |
| "- checklist de rollback atualizado\n" | |
| "- comunicado enviado para os stakeholders\n" | |
| "- janela de manutencao confirmada com a infra" | |
| ), | |
| ( | |
| "anotacoes da call com o cliente:\n" | |
| "ele quer o relatorio semanal toda segunda antes das 10h\n" | |
| "principal reclamacao: tempo de resposta do suporte esta alto\n" | |
| "sugestao: criar canal dedicado no slack para o cliente tier 1\n" | |
| "proxima reuniao marcada para dia 15, presencial no escritorio deles" | |
| ), | |
| ( | |
| "ideias para refatorar o modulo de autenticacao:\n" | |
| "separar a logica de token em um servico proprio\n" | |
| "adicionar cache para as permissoes do usuario\n" | |
| "rever o timeout da sessao, atualmente esta em 30min o que gera reclamacao\n" | |
| "avaliar se vale migrar para oauth2 nessa sprint ou deixar para o proximo quarter" | |
| ), | |
| ( | |
| "feedback da retrospectiva de hoje:\n" | |
| "o que foi bem: comunicacao melhorou bastante, entregas no prazo\n" | |
| "o que pode melhorar: code review esta demorando mais de 2 dias em media\n" | |
| "acao: definir SLA interno de 24h para reviews\n" | |
| "responsavel: todo o time, acompanhar na daily" | |
| ), | |
| ( | |
| "checklist budget Q3:\n" | |
| "licencas de software - aguardando aprovacao do financeiro\n" | |
| "contratacao de dois devs pleno - headcount aprovado, vaga aberta no linkedin\n" | |
| "upgrade de infra AWS - proposta enviada, retorno esperado para semana que vem\n" | |
| "treinamentos: reservar verba para cursos de certificacao da equipe" | |
| ), | |
| ( | |
| "pontos para discutir no 1on1 de amanha:\n" | |
| "progresso no plano de desenvolvimento individual\n" | |
| "como esta o volume de trabalho, se esta sobrecarregado\n" | |
| "interesse em liderar o projeto de dados no proximo trimestre\n" | |
| "feedback sobre a apresentacao que fez para a diretoria na semana passada" | |
| ), | |
| ( | |
| "documentacao que precisa ser atualizada:\n" | |
| "readme do repositorio principal - instructions de setup estao desatualizadas\n" | |
| "wiki da api: 3 endpoints novos sem documentacao\n" | |
| "runbook de incidente: adicionar os passos para o novo servico de pagamento\n" | |
| "onboarding guide: incluir acesso ao ambiente de staging" | |
| ), | |
| ] | |
| def micro_activity(): | |
| """Pequeno movimento de mouse para manter sinal de atividade contÃnua.""" | |
| dx = random.randint(-12, 12) | |
| dy = random.randint(-12, 12) | |
| pyautogui.moveRel(dx, dy, duration=random.uniform(0.04, 0.10)) | |
| time.sleep(0.04) | |
| pyautogui.moveRel(-dx // 2, -dy // 2, duration=0.04) | |
| def active_sleep(seconds): | |
| """Dorme pelo tempo dado, fazendo micro-atividade de mouse a cada 8-10s. | |
| Interrompe imediatamente se a hotkey de parada for acionada. | |
| """ | |
| elapsed = 0.0 | |
| while elapsed < seconds: | |
| if stop_event.is_set(): | |
| return | |
| chunk = min(random.uniform(8, 10), seconds - elapsed) | |
| # Dorme em pequenos passos para responder rapido a hotkey de parada | |
| slept = 0.0 | |
| while slept < chunk: | |
| if stop_event.is_set(): | |
| return | |
| step = min(0.25, chunk - slept) | |
| time.sleep(step) | |
| slept += step | |
| elapsed += chunk | |
| if elapsed < seconds and not stop_event.is_set(): | |
| micro_activity() | |
| def random_movement_within_window(window, clicks=1, movements=5): | |
| if not window: | |
| return False | |
| margin_x = min(50, window.width // 4) | |
| margin_y = min(50, window.height // 4) | |
| x_min = window.left + margin_x | |
| x_max = window.left + window.width - margin_x | |
| y_min = window.top + margin_y | |
| y_max = window.top + window.height - margin_y | |
| x1 = random.randint(x_min, x_max) | |
| y1 = random.randint(y_min, y_max) | |
| pyautogui.moveTo(x1, y1, duration=random.uniform(0.05, 0.15)) | |
| if clicks > 0: | |
| pyautogui.click() | |
| time.sleep(random.uniform(0.05, 0.12)) | |
| for _ in range(movements - 1): | |
| x = random.randint(x_min, x_max) | |
| y = random.randint(y_min, y_max) | |
| pyautogui.moveTo(x, y, duration=random.uniform(0.05, 0.18)) | |
| time.sleep(random.uniform(0.05, 0.10)) | |
| return True | |
| def find_target_window(): | |
| """Encontra a primeira janela visÃvel que NAO seja de um app excluÃdo. | |
| Ignora Slack/Discord, janelas sem titulo e a propria janela do console. | |
| """ | |
| for win in gw.getAllWindows(): | |
| title = (win.title or '').strip() | |
| if not title: | |
| continue | |
| if not getattr(win, 'visible', True): | |
| continue | |
| # Janela minimizada nao serve como alvo | |
| if getattr(win, 'isMinimized', False): | |
| continue | |
| lowered = title.lower() | |
| if any(app in lowered for app in EXCLUDED_APPS): | |
| continue | |
| # Ignora janelas de sistema / do proprio script | |
| if lowered in ('program manager', 'windows input experience'): | |
| continue | |
| if 'antiafk' in lowered or 'python' in lowered: | |
| continue | |
| return win | |
| return None | |
| def type_text(text): | |
| """Digita texto caractere por caractere com delay variável (rápido).""" | |
| for char in text: | |
| if char == '\n': | |
| pyautogui.press('enter') | |
| time.sleep(random.uniform(0.03, 0.08)) | |
| else: | |
| pyautogui.typewrite(char, interval=0) | |
| time.sleep(random.uniform(0.002, 0.008)) | |
| def open_notepad_and_type(): | |
| block = random.choice(NOTEPAD_BLOCKS) | |
| pyautogui.hotkey('win', 'r') | |
| time.sleep(0.8) | |
| pyautogui.typewrite('notepad', interval=0.02) | |
| pyautogui.press('enter') | |
| time.sleep(2.0) | |
| notepad_window = None | |
| for win in gw.getAllWindows(): | |
| title = win.title or '' | |
| if 'Notepad' in title or 'Bloco de Notas' in title: | |
| notepad_window = win | |
| break | |
| if not notepad_window: | |
| print(" Bloco de Notas nao encontrado, pulando.") | |
| return False | |
| # Clica no centro da janela para garantir foco | |
| cx = notepad_window.left + notepad_window.width // 2 | |
| cy = notepad_window.top + notepad_window.height // 2 | |
| pyautogui.click(cx, cy) | |
| time.sleep(0.4) | |
| type_text(block) | |
| # Adiciona um segundo bloco aleatório às vezes | |
| if random.random() < 0.5: | |
| pyautogui.press('enter') | |
| time.sleep(0.3) | |
| type_text(random.choice(NOTEPAD_BLOCKS)) | |
| time.sleep(random.uniform(0.4, 0.9)) | |
| # Re-encontra a janela para garantir referencia fresca | |
| notepad_window = None | |
| for win in gw.getAllWindows(): | |
| title = win.title or '' | |
| if 'Notepad' in title or 'Bloco de Notas' in title: | |
| notepad_window = win | |
| break | |
| if notepad_window: | |
| notepad_window.activate() | |
| time.sleep(0.6) | |
| pyautogui.hotkey('alt', 'f4') | |
| time.sleep(1.0) | |
| pyautogui.press('tab') | |
| time.sleep(0.2) | |
| pyautogui.press('enter') | |
| time.sleep(0.6) | |
| # Fallback: se ainda estiver aberto, mata o processo | |
| still_open = any( | |
| ('Notepad' in (w.title or '') or 'Bloco de Notas' in (w.title or '')) | |
| for w in gw.getAllWindows() | |
| ) | |
| if still_open: | |
| import subprocess | |
| subprocess.run('taskkill /f /im notepad.exe', shell=True, capture_output=True) | |
| print(" Bloco de Notas fechado via taskkill.") | |
| else: | |
| print(" Bloco de Notas: aberto, digitado e fechado sem salvar.") | |
| return True | |
| def main(): | |
| intervalo = DEFAULT_INTERVAL | |
| if len(sys.argv) > 1: | |
| try: | |
| intervalo = int(sys.argv[1]) | |
| print(f"Intervalo definido para {intervalo} segundos.") | |
| except ValueError: | |
| print(f"Argumento invalido. Usando intervalo padrao de {DEFAULT_INTERVAL} segundos.") | |
| print("Anti-AFK iniciado. Micro-atividade a cada 8-10s + ciclo principal a cada " | |
| f"{intervalo}s.") | |
| print(f"Pressione Ctrl+C ou a hotkey global {STOP_HOTKEY.upper()} para parar.") | |
| # Registra a hotkey global de parada (funciona de qualquer janela) | |
| try: | |
| keyboard.add_hotkey(STOP_HOTKEY, lambda: stop_event.set()) | |
| except Exception as e: | |
| print(f"[AVISO] Nao foi possivel registrar a hotkey {STOP_HOTKEY}: {e}") | |
| print(" Use Ctrl+C para parar.") | |
| ciclo = 0 | |
| proximo_notepad = random.randint(2, 3) | |
| try: | |
| while not stop_event.is_set(): | |
| active_sleep(intervalo) | |
| if stop_event.is_set(): | |
| break | |
| ciclo += 1 | |
| try: | |
| target_window = find_target_window() | |
| if target_window: | |
| print(f"[OK] Alvo: '{target_window.title}' [{time.strftime('%H:%M:%S')}] ciclo {ciclo} - movimentos + Alt+Tab") | |
| try: | |
| target_window.activate() | |
| time.sleep(0.2) | |
| except Exception: | |
| pass | |
| random_movement_within_window(target_window, clicks=1, movements=5) | |
| pyautogui.hotkey('alt', 'tab') | |
| time.sleep(0.25) | |
| pyautogui.hotkey('alt', 'tab') | |
| else: | |
| print(f"[--] Nenhuma janela alvo encontrada [{time.strftime('%H:%M:%S')}] - micro-movimento") | |
| micro_activity() | |
| if ciclo >= proximo_notepad: | |
| print(f"[KB] Bloco de Notas (ciclo {ciclo})...") | |
| open_notepad_and_type() | |
| ciclo = 0 | |
| proximo_notepad = random.randint(2, 3) | |
| if target_window: | |
| try: | |
| target_window.activate() | |
| except Exception: | |
| pass | |
| except Exception as e: | |
| print(f"[ERR] Erro no ciclo {ciclo} (continuando): {e}") | |
| except KeyboardInterrupt: | |
| pass | |
| finally: | |
| try: | |
| keyboard.remove_all_hotkeys() | |
| except Exception: | |
| pass | |
| if stop_event.is_set(): | |
| print(f"\nAnti-AFK encerrado pela hotkey {STOP_HOTKEY.upper()}.") | |
| else: | |
| print("\nAnti-AFK encerrado.") | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment