149 lines
4.9 KiB
Python
149 lines
4.9 KiB
Python
import json
|
|
import sys
|
|
import os
|
|
import time
|
|
import cv2
|
|
import tkinter as tk
|
|
import ctypes
|
|
|
|
|
|
def enable_dpi_awareness():
|
|
"""Keep screenshot pixels and mouse coordinates in the same coordinate system."""
|
|
try:
|
|
ctypes.windll.shcore.SetProcessDpiAwareness(2)
|
|
except Exception:
|
|
try:
|
|
ctypes.windll.user32.SetProcessDPIAware()
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
enable_dpi_awareness()
|
|
|
|
os.chdir(os.path.dirname(sys.executable)
|
|
if getattr(sys, 'frozen', False)
|
|
else os.path.dirname(__file__))
|
|
|
|
from capture import CaptureOverlay
|
|
from scanner import Scanner
|
|
from actions import move_to
|
|
from gui import LogWindow
|
|
from screenshot_selector import select_from_screenshot
|
|
|
|
|
|
def main():
|
|
log = None
|
|
try:
|
|
with open('config.json') as f:
|
|
config = json.load(f)
|
|
|
|
log = LogWindow()
|
|
if not os.path.exists(config['template_path']):
|
|
log.log('Choose a screenshot, then mark the area to find...')
|
|
if not select_from_screenshot(log.root, config['template_path']):
|
|
log.log('Selection cancelled.')
|
|
return
|
|
|
|
scanner = Scanner(config)
|
|
log.log(f'Template loaded: {scanner.tw}x{scanner.th}')
|
|
sys.stderr.write(f'[DEBUG] Scanner loaded template {scanner.tw}x{scanner.th}\n')
|
|
|
|
recapture_flag = [False]
|
|
clicked = False
|
|
|
|
try:
|
|
import keyboard
|
|
keyboard.add_hotkey('ctrl+shift+r', lambda: recapture_flag.__setitem__(0, True))
|
|
keyboard.add_hotkey(
|
|
'ctrl+shift+s',
|
|
lambda: setattr(log, 'screenshot_requested', True),
|
|
)
|
|
log.log('Ctrl+Shift+S = choose from screenshot')
|
|
log.log('Ctrl+Shift+R = capture from screen')
|
|
sys.stderr.write('[DEBUG] hotkey registered\n')
|
|
except Exception as e:
|
|
log.log(f'Hotkey not available (run as admin?): {e}')
|
|
sys.stderr.write(f'[DEBUG] hotkey failed: {e}\n')
|
|
|
|
log.log('Scanning started')
|
|
sys.stderr.write('[DEBUG] main loop started\n')
|
|
|
|
cycle = 0
|
|
while log.running:
|
|
if log.screenshot_requested:
|
|
log.screenshot_requested = False
|
|
log.log('Choose a screenshot and mark the exact target...')
|
|
if select_from_screenshot(log.root, config['template_path']):
|
|
scanner = Scanner(config)
|
|
clicked = False
|
|
log.log(f'New template loaded: {scanner.tw}x{scanner.th}')
|
|
else:
|
|
log.log('Selection cancelled; keeping the previous template.')
|
|
continue
|
|
|
|
if log.capture_requested or recapture_flag[0]:
|
|
log.capture_requested = False
|
|
recapture_flag[0] = False
|
|
log.log('Recapture: select new area...')
|
|
capture = CaptureOverlay(log.root, config['template_path'])
|
|
if not capture.saved:
|
|
log.log('Recapture cancelled; keeping the previous template.')
|
|
continue
|
|
scanner.template = cv2.imread(config['template_path'])
|
|
if scanner.template is None:
|
|
log.log('Error: new template not saved')
|
|
else:
|
|
scanner.th, scanner.tw = scanner.template.shape[:2]
|
|
log.log('New template saved!')
|
|
|
|
screen = scanner.grab_screen()
|
|
result = scanner.find(screen)
|
|
cycle += 1
|
|
|
|
if result and not clicked:
|
|
x, y = result
|
|
log.log(f'Match: ({x}, {y}) score={scanner.last_score:.3f}')
|
|
sys.stderr.write(f'[MATCH] score={scanner.last_score:.3f}\n')
|
|
move_to(x, y)
|
|
log.log(f'Ctrl+clicked at ({x}, {y})')
|
|
clicked = True
|
|
elif not result:
|
|
clicked = False
|
|
if cycle % 10 == 0:
|
|
sys.stderr.write(f'[SCAN] score={scanner.last_score:.3f} (need {config["confidence"]})\n')
|
|
if scanner.last_score > 0.05:
|
|
log.log(f'Best score: {scanner.last_score:.3f} (need {config["confidence"]})')
|
|
|
|
if not log.running:
|
|
break
|
|
log.update()
|
|
time.sleep(config['scan_interval_ms'] / 1000)
|
|
|
|
except (KeyboardInterrupt, tk.TclError):
|
|
pass
|
|
except Exception as e:
|
|
msg = f'[FATAL] {e}'
|
|
sys.stderr.write(msg + '\n')
|
|
if log is not None:
|
|
try:
|
|
log.log(msg)
|
|
except Exception:
|
|
pass
|
|
raise
|
|
finally:
|
|
try:
|
|
import keyboard
|
|
keyboard.unhook_all_hotkeys()
|
|
except Exception:
|
|
pass
|
|
|
|
if log is not None and log.running:
|
|
try:
|
|
log.log('Stopped')
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|