You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
AutoClick/main.py

216 lines
7.4 KiB

import pyautogui
import cv2
import numpy as np
import time
import threading
from pynput import keyboard
import os
class MacImageClicker:
def __init__(self):
self.is_monitoring = False
self.target_image = None
self.confidence_threshold = 0.95
self.hotkey = keyboard.Key.f8
self.check_interval = 0.000001
# macOS 特定设置
pyautogui.FAILSAFE = True
pyautogui.PAUSE = 0.1
# 查找目标图片
self.target_image_path = self.find_target_image()
def find_target_image(self):
"""在项目根目录查找目标图片"""
current_dir = os.getcwd()
image_files = []
# 查找所有可能的图片文件
for file in os.listdir(current_dir):
if file.lower().endswith(('.png', '.jpg', '.jpeg')):
image_files.append(file)
if not image_files:
print("在项目根目录未找到任何图片文件 (png, jpg, jpeg)")
return None
# 优先选择包含 target 关键字的图片
target_files = [f for f in image_files if 'target' in f.lower()]
if target_files:
selected = target_files[0]
else:
selected = image_files[0]
full_path = os.path.join(current_dir, selected)
print(f"找到目标图片: {selected}")
return full_path
def load_target_image(self):
"""加载目标图片"""
if not self.target_image_path:
print("未找到目标图片文件")
return False
try:
self.target_image = cv2.imread(self.target_image_path)
if self.target_image is not None:
print(f"成功加载目标图片: {os.path.basename(self.target_image_path)}")
print(f"图片尺寸: {self.target_image.shape[1]}x{self.target_image.shape[0]}")
return True
else:
print("图片加载失败,可能是格式不支持")
return False
except Exception as e:
print(f"加载图片时出错: {e}")
return False
def get_screenshot(self):
"""获取屏幕截图 - macOS 版本"""
try:
# 使用 pyautogui 截图,在 macOS 上兼容性更好
screenshot = pyautogui.screenshot()
screenshot_cv = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
return screenshot_cv
except Exception as e:
print(f"截图失败: {e}")
return None
def find_and_click(self):
"""在屏幕上查找目标图片并点击"""
if self.target_image is None:
return False
try:
# 获取屏幕截图
screenshot = self.get_screenshot()
if screenshot is None:
return False
# 模板匹配
result = cv2.matchTemplate(screenshot, self.target_image, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
# 调试信息(可选,可以注释掉以减少输出)
# print(f"当前匹配度: {max_val:.3f}")
if max_val >= self.confidence_threshold:
# 计算目标中心位置
h, w = self.target_image.shape[:2]
center_x = max_loc[0] + w // 2
center_y = max_loc[1] + h // 2
# 先记录当前位置
current_pos = pyautogui.position()
print(f"📍 从当前位置 ({current_pos.x}, {current_pos.y}) 移动到目标位置 ({center_x}, {center_y})")
pyautogui.moveTo(center_x, center_y, duration=0.0001)
# 执行点击
pyautogui.click()
print(f"✅ 已点击位置: ({center_x}, {center_y}), 相似度: {max_val:.3f}")
return True
except Exception as e:
print(f"查找或点击时出错: {e}")
return False
def monitoring_loop(self):
"""监控循环"""
print("监控线程启动")
while True:
if self.is_monitoring:
self.find_and_click()
time.sleep(self.check_interval)
def toggle_monitoring(self):
"""切换监控状态"""
self.is_monitoring = not self.is_monitoring
if self.is_monitoring:
# 开启监控时确保图片已加载
if self.target_image is None:
if not self.load_target_image():
self.is_monitoring = False
print("❌ 无法加载目标图片,监控未开启")
return
status = "🟢 开启" if self.is_monitoring else "🔴 关闭"
print(f"监控状态: {status}")
if self.is_monitoring:
print("开始监控屏幕,寻找目标图片...")
def on_press(self, key):
"""键盘按下事件"""
if key == self.hotkey:
self.toggle_monitoring()
elif key == keyboard.Key.esc:
# ESC 键退出程序
print("退出程序")
os._exit(0)
def check_mac_permissions(self):
"""检查 macOS 权限"""
try:
# 尝试截图来测试权限
test_screenshot = pyautogui.screenshot()
print("✅ 屏幕录制权限: 已授权")
return True
except Exception:
print("❌ 屏幕录制权限: 未授权")
print("请前往: 系统设置 > 隐私与安全性 > 屏幕录制")
print("为终端或您使用的 IDE 开启屏幕录制权限")
return False
def start(self):
"""启动程序"""
print("🖥 macOS 图像点击工具")
print("=" * 40)
# 检查权限
if not self.check_mac_permissions():
return
# 查找并加载目标图片
if not self.load_target_image():
print("请确保项目根目录有图片文件 (png, jpg, jpeg)")
return
print(f"🎯 目标图片: {os.path.basename(self.target_image_path)}")
print(f"📏 相似度阈值: {self.confidence_threshold}")
print(f"🎹 控制快捷键:")
print(f" - F8: 开启/关闭监控")
print(f" - ESC: 退出程序")
print("=" * 40)
print("等待指令...")
# 启动监控线程
monitor_thread = threading.Thread(target=self.monitoring_loop, daemon=True)
monitor_thread.start()
# 启动键盘监听
try:
with keyboard.Listener(on_press=self.on_press) as listener:
listener.join()
except KeyboardInterrupt:
print("\n程序被用户中断")
except Exception as e:
print(f"程序出错: {e}")
if __name__ == "__main__":
# 确保程序在 macOS 上运行
import platform
if platform.system() != 'Darwin':
print("警告: 这个工具是针对 macOS 优化的")
print("但检测到您正在运行:", platform.system())
print("继续运行可能遇到兼容性问题")
response = input("是否继续? (y/n): ")
if response.lower() != 'y':
exit()
clicker = MacImageClicker()
clicker.start()