smart-clicker 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- smart_clicker-0.1.0/PKG-INFO +5 -0
- smart_clicker-0.1.0/setup.cfg +4 -0
- smart_clicker-0.1.0/setup.py +15 -0
- smart_clicker-0.1.0/smart_clicker/__init__.py +7 -0
- smart_clicker-0.1.0/smart_clicker/core.py +114 -0
- smart_clicker-0.1.0/smart_clicker/snipper.py +75 -0
- smart_clicker-0.1.0/smart_clicker.egg-info/PKG-INFO +5 -0
- smart_clicker-0.1.0/smart_clicker.egg-info/SOURCES.txt +9 -0
- smart_clicker-0.1.0/smart_clicker.egg-info/dependency_links.txt +1 -0
- smart_clicker-0.1.0/smart_clicker.egg-info/requires.txt +4 -0
- smart_clicker-0.1.0/smart_clicker.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="smart_clicker",
|
|
5
|
+
version="0.1.0",
|
|
6
|
+
packages=find_packages(),
|
|
7
|
+
install_requires=[
|
|
8
|
+
"pyautogui",
|
|
9
|
+
"opencv-python",
|
|
10
|
+
"keyboard",
|
|
11
|
+
"pillow"
|
|
12
|
+
],
|
|
13
|
+
author="Your Name",
|
|
14
|
+
description="A simple screen automation tool with hotkey snapshot capability.",
|
|
15
|
+
)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import os
|
|
3
|
+
import threading
|
|
4
|
+
import keyboard
|
|
5
|
+
import pyautogui
|
|
6
|
+
from pyautogui import ImageNotFoundException
|
|
7
|
+
from .snipper import take_snapshot
|
|
8
|
+
|
|
9
|
+
class AutoBot:
|
|
10
|
+
def __init__(self):
|
|
11
|
+
self.img_dir = None
|
|
12
|
+
self.target_name = "target.png" # 默认图片名
|
|
13
|
+
self.target_path = None
|
|
14
|
+
self.running = False
|
|
15
|
+
self.stop_event = threading.Event()
|
|
16
|
+
self.worker_thread = None
|
|
17
|
+
|
|
18
|
+
# 配置参数
|
|
19
|
+
self.confidence = 0.8
|
|
20
|
+
self.grayscale = True
|
|
21
|
+
|
|
22
|
+
# 快捷键
|
|
23
|
+
self.hk_snapshot = 'f2' # 截图快捷键
|
|
24
|
+
self.hk_toggle = 'f4' # 开关快捷键
|
|
25
|
+
|
|
26
|
+
def init(self, img_dir, target_filename="target.png", snapshot_key='f2', toggle_key='f4'):
|
|
27
|
+
"""初始化配置"""
|
|
28
|
+
self.img_dir = img_dir
|
|
29
|
+
self.target_name = target_filename
|
|
30
|
+
self.target_path = os.path.join(self.img_dir, self.target_name)
|
|
31
|
+
self.hk_snapshot = snapshot_key
|
|
32
|
+
self.hk_toggle = toggle_key
|
|
33
|
+
|
|
34
|
+
# 确保目录存在
|
|
35
|
+
if not os.path.exists(self.img_dir):
|
|
36
|
+
os.makedirs(self.img_dir)
|
|
37
|
+
|
|
38
|
+
return self # 支持链式调用
|
|
39
|
+
|
|
40
|
+
def _toggle_automation(self):
|
|
41
|
+
"""切换运行状态"""
|
|
42
|
+
self.running = not self.running
|
|
43
|
+
if self.running:
|
|
44
|
+
print(f"\n🚀 自动化已启动! (目标: {self.target_name})")
|
|
45
|
+
# 检查图片是否存在
|
|
46
|
+
if not os.path.exists(self.target_path):
|
|
47
|
+
print(f"⚠️ 警告: 未找到 {self.target_path},请先按 {self.hk_snapshot} 截图!")
|
|
48
|
+
self.running = False
|
|
49
|
+
else:
|
|
50
|
+
print("\n⏸️ 自动化已暂停")
|
|
51
|
+
|
|
52
|
+
def _trigger_snapshot(self):
|
|
53
|
+
"""触发截图流程(需要暂停自动化以防冲突)"""
|
|
54
|
+
was_running = self.running
|
|
55
|
+
if was_running:
|
|
56
|
+
self.running = False
|
|
57
|
+
print("📸 暂停任务以进行截图...")
|
|
58
|
+
|
|
59
|
+
print(">>> 请框选要识别的区域...")
|
|
60
|
+
# 这里的截图需要在主线程或者完全独立的进程中调用,因为 tkinter 在子线程运行会有问题
|
|
61
|
+
# 但 keyboard 的回调通常在一个独立的线程。
|
|
62
|
+
# 这里为了简单,直接调用,若有 GUI 冲突需使用队列通信,但在纯脚本环境下通常可行。
|
|
63
|
+
take_snapshot(self.target_path)
|
|
64
|
+
|
|
65
|
+
if was_running:
|
|
66
|
+
self.running = True
|
|
67
|
+
print("▶️ 恢复任务")
|
|
68
|
+
|
|
69
|
+
def _loop_logic(self):
|
|
70
|
+
"""后台循环查找线程"""
|
|
71
|
+
print(f"🤖 服务已就绪 | 截图: [{self.hk_snapshot}] | 开关: [{self.hk_toggle}]")
|
|
72
|
+
print("按 Ctrl+C 强制退出程序")
|
|
73
|
+
|
|
74
|
+
while not self.stop_event.is_set():
|
|
75
|
+
if self.running and os.path.exists(self.target_path):
|
|
76
|
+
try:
|
|
77
|
+
location = pyautogui.locateCenterOnScreen(
|
|
78
|
+
self.target_path,
|
|
79
|
+
confidence=self.confidence,
|
|
80
|
+
grayscale=self.grayscale
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
if location:
|
|
84
|
+
print(f"✨ 点击坐标: {location}")
|
|
85
|
+
pyautogui.click(location)
|
|
86
|
+
time.sleep(1) # 点击冷却
|
|
87
|
+
|
|
88
|
+
except ImageNotFoundException:
|
|
89
|
+
pass # 没找到是正常的,继续找
|
|
90
|
+
except Exception as e:
|
|
91
|
+
print(f"❌ 错误: {e}")
|
|
92
|
+
|
|
93
|
+
time.sleep(0.1) # 避免CPU占用过高
|
|
94
|
+
|
|
95
|
+
def start(self):
|
|
96
|
+
"""启动监听和循环"""
|
|
97
|
+
if not self.img_dir:
|
|
98
|
+
raise ValueError("请先调用 init('path') 设置目录")
|
|
99
|
+
|
|
100
|
+
# 注册热键
|
|
101
|
+
keyboard.add_hotkey(self.hk_snapshot, self._trigger_snapshot)
|
|
102
|
+
keyboard.add_hotkey(self.hk_toggle, self._toggle_automation)
|
|
103
|
+
|
|
104
|
+
# 启动后台工作线程
|
|
105
|
+
self.worker_thread = threading.Thread(target=self._loop_logic)
|
|
106
|
+
self.worker_thread.daemon = True # 设置为守护线程,主程序退出时自动销毁
|
|
107
|
+
self.worker_thread.start()
|
|
108
|
+
|
|
109
|
+
# 阻塞主线程,保持程序运行,直到用户按 Ctrl+C
|
|
110
|
+
try:
|
|
111
|
+
keyboard.wait()
|
|
112
|
+
except KeyboardInterrupt:
|
|
113
|
+
print("\n👋 程序退出")
|
|
114
|
+
self.stop_event.set()
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import tkinter as tk
|
|
2
|
+
from PIL import ImageGrab
|
|
3
|
+
import os
|
|
4
|
+
import pyautogui
|
|
5
|
+
|
|
6
|
+
class ScreenSnipper:
|
|
7
|
+
def __init__(self, save_path):
|
|
8
|
+
self.save_path = save_path
|
|
9
|
+
self.root = tk.Tk()
|
|
10
|
+
# 设置全屏、无边框、顶层
|
|
11
|
+
self.root.attributes("-fullscreen", True)
|
|
12
|
+
self.root.attributes("-alpha", 0.3) # 透明度
|
|
13
|
+
self.root.attributes("-topmost", True)
|
|
14
|
+
self.root.overrideredirect(True)
|
|
15
|
+
|
|
16
|
+
# 灰色遮罩
|
|
17
|
+
self.canvas = tk.Canvas(self.root, cursor="cross", bg="grey")
|
|
18
|
+
self.canvas.pack(fill="both", expand=True)
|
|
19
|
+
|
|
20
|
+
self.start_x = None
|
|
21
|
+
self.start_y = None
|
|
22
|
+
self.rect = None
|
|
23
|
+
|
|
24
|
+
# 绑定鼠标事件
|
|
25
|
+
self.canvas.bind("<ButtonPress-1>", self.on_button_press)
|
|
26
|
+
self.canvas.bind("<B1-Motion>", self.on_move_press)
|
|
27
|
+
self.canvas.bind("<ButtonRelease-1>", self.on_button_release)
|
|
28
|
+
|
|
29
|
+
# 按 ESC 退出截图
|
|
30
|
+
self.root.bind("<Escape>", lambda e: self.root.destroy())
|
|
31
|
+
|
|
32
|
+
def start_capture(self):
|
|
33
|
+
self.root.mainloop()
|
|
34
|
+
|
|
35
|
+
def on_button_press(self, event):
|
|
36
|
+
self.start_x = event.x
|
|
37
|
+
self.start_y = event.y
|
|
38
|
+
# 创建矩形框
|
|
39
|
+
self.rect = self.canvas.create_rectangle(self.start_x, self.start_y, 1, 1, outline='red', width=3)
|
|
40
|
+
|
|
41
|
+
def on_move_press(self, event):
|
|
42
|
+
cur_x, cur_y = (event.x, event.y)
|
|
43
|
+
self.canvas.coords(self.rect, self.start_x, self.start_y, cur_x, cur_y)
|
|
44
|
+
|
|
45
|
+
def on_button_release(self, event):
|
|
46
|
+
end_x, end_y = (event.x, event.y)
|
|
47
|
+
self.root.destroy() # 关闭遮罩
|
|
48
|
+
|
|
49
|
+
# 计算坐标 (处理从右下往左上拉的情况)
|
|
50
|
+
x1 = min(self.start_x, end_x)
|
|
51
|
+
y1 = min(self.start_y, end_y)
|
|
52
|
+
x2 = max(self.start_x, end_x)
|
|
53
|
+
y2 = max(self.start_y, end_y)
|
|
54
|
+
|
|
55
|
+
if x2 - x1 < 5 or y2 - y1 < 5:
|
|
56
|
+
print("❌ 选区太小,已取消截图")
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
# 截图保存
|
|
60
|
+
try:
|
|
61
|
+
# ImageGrab 截取的是物理屏幕坐标
|
|
62
|
+
img = ImageGrab.grab(bbox=(x1, y1, x2, y2))
|
|
63
|
+
|
|
64
|
+
# 确保目录存在
|
|
65
|
+
if not os.path.exists(os.path.dirname(self.save_path)):
|
|
66
|
+
os.makedirs(os.path.dirname(self.save_path))
|
|
67
|
+
|
|
68
|
+
img.save(self.save_path)
|
|
69
|
+
print(f"✅ 目标图片已更新: {self.save_path}")
|
|
70
|
+
except Exception as e:
|
|
71
|
+
print(f"❌ 截图失败: {e}")
|
|
72
|
+
|
|
73
|
+
def take_snapshot(path):
|
|
74
|
+
snipper = ScreenSnipper(path)
|
|
75
|
+
snipper.start_capture()
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
setup.py
|
|
2
|
+
smart_clicker/__init__.py
|
|
3
|
+
smart_clicker/core.py
|
|
4
|
+
smart_clicker/snipper.py
|
|
5
|
+
smart_clicker.egg-info/PKG-INFO
|
|
6
|
+
smart_clicker.egg-info/SOURCES.txt
|
|
7
|
+
smart_clicker.egg-info/dependency_links.txt
|
|
8
|
+
smart_clicker.egg-info/requires.txt
|
|
9
|
+
smart_clicker.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
smart_clicker
|