iflow-mcp_bethington-cheat-engine-server-python 0.1.0__py3-none-any.whl
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.
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/METADATA +16 -0
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/RECORD +40 -0
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/WHEEL +5 -0
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/entry_points.txt +2 -0
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/licenses/LICENSE +21 -0
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/top_level.txt +1 -0
- server/cheatengine/__init__.py +19 -0
- server/cheatengine/ce_bridge.py +1670 -0
- server/cheatengine/lua_interface.py +460 -0
- server/cheatengine/table_parser.py +1221 -0
- server/config/__init__.py +20 -0
- server/config/settings.py +347 -0
- server/config/whitelist.py +378 -0
- server/gui_automation/__init__.py +43 -0
- server/gui_automation/core/__init__.py +8 -0
- server/gui_automation/core/integration.py +951 -0
- server/gui_automation/demos/__init__.py +8 -0
- server/gui_automation/demos/basic_demo.py +754 -0
- server/gui_automation/demos/notepad_demo.py +460 -0
- server/gui_automation/demos/simple_demo.py +319 -0
- server/gui_automation/tools/__init__.py +8 -0
- server/gui_automation/tools/mcp_tools.py +974 -0
- server/main.py +519 -0
- server/memory/__init__.py +0 -0
- server/memory/analyzer.py +0 -0
- server/memory/reader.py +0 -0
- server/memory/scanner.py +0 -0
- server/memory/symbols.py +0 -0
- server/process/__init__.py +16 -0
- server/process/launcher.py +608 -0
- server/process/manager.py +185 -0
- server/process/monitors.py +202 -0
- server/process/permissions.py +131 -0
- server/process_whitelist.json +119 -0
- server/pyautogui/__init__.py +0 -0
- server/utils/__init__.py +37 -0
- server/utils/data_types.py +368 -0
- server/utils/formatters.py +430 -0
- server/utils/validators.py +340 -0
- server/window_automation/__init__.py +59 -0
|
@@ -0,0 +1,754 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
PyAutoGUI Integration Demo for MCP Cheat Engine Server
|
|
4
|
+
|
|
5
|
+
This demo showcases all PyAutoGUI functionality integrated into the MCP Cheat Engine Server.
|
|
6
|
+
It demonstrates every feature category with practical examples and real automation tasks.
|
|
7
|
+
|
|
8
|
+
Demo Sections:
|
|
9
|
+
1. Screen Analysis & Capture
|
|
10
|
+
2. Mouse Control & Automation
|
|
11
|
+
3. Keyboard Input & Hotkeys
|
|
12
|
+
4. Advanced Image Recognition
|
|
13
|
+
5. Batch Operations
|
|
14
|
+
6. Real-World Automation Scenarios
|
|
15
|
+
7. Integration with Memory Operations
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
import sys
|
|
20
|
+
import time
|
|
21
|
+
import logging
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import Dict, Any, List
|
|
24
|
+
|
|
25
|
+
# Add project root to path
|
|
26
|
+
project_root = Path(__file__).parent
|
|
27
|
+
if str(project_root) not in sys.path:
|
|
28
|
+
sys.path.insert(0, str(project_root))
|
|
29
|
+
|
|
30
|
+
# Configure logging
|
|
31
|
+
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
33
|
+
|
|
34
|
+
def print_section(title: str, description: str = ""):
|
|
35
|
+
"""Print a formatted section header"""
|
|
36
|
+
print("\n" + "=" * 70)
|
|
37
|
+
print(f"π― {title}")
|
|
38
|
+
print("=" * 70)
|
|
39
|
+
if description:
|
|
40
|
+
print(f"{description}\n")
|
|
41
|
+
|
|
42
|
+
def print_step(step: str, result: str = "", success: bool = True):
|
|
43
|
+
"""Print a formatted step"""
|
|
44
|
+
status = "β
" if success else "β"
|
|
45
|
+
print(f"{status} {step}")
|
|
46
|
+
if result:
|
|
47
|
+
print(f" {result}")
|
|
48
|
+
|
|
49
|
+
def wait_for_user(message: str = "Press Enter to continue..."):
|
|
50
|
+
"""Wait for user input"""
|
|
51
|
+
input(f"\nβΈοΈ {message}")
|
|
52
|
+
|
|
53
|
+
class PyAutoGUIDemo:
|
|
54
|
+
"""Comprehensive PyAutoGUI demonstration"""
|
|
55
|
+
|
|
56
|
+
def __init__(self):
|
|
57
|
+
"""Initialize the demo"""
|
|
58
|
+
try:
|
|
59
|
+
from pyautogui_integration import get_pyautogui_controller, PYAUTOGUI_AVAILABLE
|
|
60
|
+
|
|
61
|
+
if not PYAUTOGUI_AVAILABLE:
|
|
62
|
+
raise ImportError("PyAutoGUI not available")
|
|
63
|
+
|
|
64
|
+
self.controller = get_pyautogui_controller()
|
|
65
|
+
self.demo_data = {}
|
|
66
|
+
|
|
67
|
+
print("π PyAutoGUI Demo Initialized Successfully!")
|
|
68
|
+
|
|
69
|
+
except ImportError as e:
|
|
70
|
+
print(f"β PyAutoGUI not available: {e}")
|
|
71
|
+
print("π¦ Install with: pip install pyautogui pillow opencv-python")
|
|
72
|
+
sys.exit(1)
|
|
73
|
+
|
|
74
|
+
def demo_screen_analysis(self):
|
|
75
|
+
"""Demo: Screen Analysis & Capture"""
|
|
76
|
+
print_section(
|
|
77
|
+
"SCREEN ANALYSIS & CAPTURE",
|
|
78
|
+
"Demonstrating screenshot capture, pixel analysis, and screen information"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# 1. Get screen information
|
|
82
|
+
screen_result = self.controller.get_screen_info()
|
|
83
|
+
if screen_result.success:
|
|
84
|
+
data = screen_result.data
|
|
85
|
+
print_step(
|
|
86
|
+
"Screen Information Retrieved",
|
|
87
|
+
f"Resolution: {data['width']}x{data['height']}, Monitors: {data['monitor_count']}"
|
|
88
|
+
)
|
|
89
|
+
self.demo_data['screen_width'] = data['width']
|
|
90
|
+
self.demo_data['screen_height'] = data['height']
|
|
91
|
+
else:
|
|
92
|
+
print_step("Screen Information", f"Failed: {screen_result.error}", False)
|
|
93
|
+
return
|
|
94
|
+
|
|
95
|
+
# 2. Take full screen screenshot
|
|
96
|
+
screenshot_result = self.controller.take_screenshot()
|
|
97
|
+
if screenshot_result.success:
|
|
98
|
+
data = screenshot_result.data
|
|
99
|
+
print_step(
|
|
100
|
+
"Full Screen Screenshot",
|
|
101
|
+
f"Captured {data['width']}x{data['height']} image, Cache: {data['cache_key']}"
|
|
102
|
+
)
|
|
103
|
+
else:
|
|
104
|
+
print_step("Screenshot", f"Failed: {screenshot_result.error}", False)
|
|
105
|
+
|
|
106
|
+
# 3. Take region screenshot
|
|
107
|
+
region = (100, 100, 400, 300) # 400x300 region at (100,100)
|
|
108
|
+
region_result = self.controller.take_screenshot(region)
|
|
109
|
+
if region_result.success:
|
|
110
|
+
print_step(
|
|
111
|
+
"Region Screenshot",
|
|
112
|
+
f"Captured {region} region: {region_result.data['width']}x{region_result.data['height']}"
|
|
113
|
+
)
|
|
114
|
+
else:
|
|
115
|
+
print_step("Region Screenshot", f"Failed: {region_result.error}", False)
|
|
116
|
+
|
|
117
|
+
# 4. Analyze pixel colors at various points
|
|
118
|
+
test_points = [
|
|
119
|
+
(self.demo_data['screen_width'] // 2, self.demo_data['screen_height'] // 2), # Center
|
|
120
|
+
(0, 0), # Top-left
|
|
121
|
+
(100, 100), # Arbitrary point
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
for x, y in test_points:
|
|
125
|
+
pixel_result = self.controller.get_pixel_color(x, y)
|
|
126
|
+
if pixel_result.success:
|
|
127
|
+
data = pixel_result.data
|
|
128
|
+
print_step(
|
|
129
|
+
f"Pixel Color at ({x}, {y})",
|
|
130
|
+
f"RGB: {data['rgb']}, Hex: {data['hex']}"
|
|
131
|
+
)
|
|
132
|
+
else:
|
|
133
|
+
print_step(f"Pixel at ({x}, {y})", f"Failed: {pixel_result.error}", False)
|
|
134
|
+
|
|
135
|
+
# 5. Coordinate validation
|
|
136
|
+
valid_coords = self.controller.is_on_screen(200, 200)
|
|
137
|
+
invalid_coords = self.controller.is_on_screen(-100, -100)
|
|
138
|
+
|
|
139
|
+
print_step(
|
|
140
|
+
"Coordinate Validation",
|
|
141
|
+
f"(200, 200): {'Valid' if valid_coords.data['on_screen'] else 'Invalid'}, "
|
|
142
|
+
f"(-100, -100): {'Valid' if invalid_coords.data['on_screen'] else 'Invalid'}"
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
wait_for_user("Screenshot and analysis demo complete. Continue to mouse control?")
|
|
146
|
+
|
|
147
|
+
def demo_mouse_control(self):
|
|
148
|
+
"""Demo: Mouse Control & Automation"""
|
|
149
|
+
print_section(
|
|
150
|
+
"MOUSE CONTROL & AUTOMATION",
|
|
151
|
+
"Demonstrating mouse movement, clicking, dragging, and scrolling"
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
# 1. Get current mouse position
|
|
155
|
+
pos_result = self.controller.get_mouse_position()
|
|
156
|
+
if pos_result.success:
|
|
157
|
+
start_pos = (pos_result.data['x'], pos_result.data['y'])
|
|
158
|
+
print_step(
|
|
159
|
+
"Current Mouse Position",
|
|
160
|
+
f"Starting at {start_pos}"
|
|
161
|
+
)
|
|
162
|
+
else:
|
|
163
|
+
print_step("Get Mouse Position", f"Failed: {pos_result.error}", False)
|
|
164
|
+
return
|
|
165
|
+
|
|
166
|
+
print("π Watch your mouse cursor move during this demo!")
|
|
167
|
+
wait_for_user("Ready to start mouse movement demo?")
|
|
168
|
+
|
|
169
|
+
# 2. Absolute movement
|
|
170
|
+
target_positions = [
|
|
171
|
+
(300, 300),
|
|
172
|
+
(500, 200),
|
|
173
|
+
(200, 400),
|
|
174
|
+
(400, 350)
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
for i, (x, y) in enumerate(target_positions, 1):
|
|
178
|
+
move_result = self.controller.move_mouse(x, y, duration=0.8)
|
|
179
|
+
if move_result.success:
|
|
180
|
+
print_step(
|
|
181
|
+
f"Movement {i}",
|
|
182
|
+
f"Moved to ({x}, {y}) in 0.8 seconds"
|
|
183
|
+
)
|
|
184
|
+
time.sleep(0.5)
|
|
185
|
+
else:
|
|
186
|
+
print_step(f"Movement {i}", f"Failed: {move_result.error}", False)
|
|
187
|
+
|
|
188
|
+
# 3. Relative movement
|
|
189
|
+
relative_moves = [(50, 0), (0, 50), (-50, 0), (0, -50)]
|
|
190
|
+
|
|
191
|
+
for i, (dx, dy) in enumerate(relative_moves, 1):
|
|
192
|
+
rel_result = self.controller.move_mouse(dx, dy, duration=0.3, relative=True)
|
|
193
|
+
if rel_result.success:
|
|
194
|
+
print_step(
|
|
195
|
+
f"Relative Move {i}",
|
|
196
|
+
f"Moved by ({dx}, {dy})"
|
|
197
|
+
)
|
|
198
|
+
time.sleep(0.2)
|
|
199
|
+
else:
|
|
200
|
+
print_step(f"Relative Move {i}", f"Failed: {rel_result.error}", False)
|
|
201
|
+
|
|
202
|
+
# 4. Clicking demonstrations
|
|
203
|
+
click_demos = [
|
|
204
|
+
{"button": "left", "clicks": 1, "desc": "Single left click"},
|
|
205
|
+
{"button": "right", "clicks": 1, "desc": "Single right click"},
|
|
206
|
+
{"button": "left", "clicks": 2, "desc": "Double left click"},
|
|
207
|
+
]
|
|
208
|
+
|
|
209
|
+
for demo in click_demos:
|
|
210
|
+
click_result = self.controller.click_mouse(
|
|
211
|
+
button=demo["button"],
|
|
212
|
+
clicks=demo["clicks"]
|
|
213
|
+
)
|
|
214
|
+
if click_result.success:
|
|
215
|
+
print_step(demo["desc"], "Executed successfully")
|
|
216
|
+
time.sleep(0.5)
|
|
217
|
+
else:
|
|
218
|
+
print_step(demo["desc"], f"Failed: {click_result.error}", False)
|
|
219
|
+
|
|
220
|
+
# 5. Drag operation
|
|
221
|
+
drag_start = (250, 250)
|
|
222
|
+
drag_end = (350, 350)
|
|
223
|
+
|
|
224
|
+
drag_result = self.controller.drag_mouse(
|
|
225
|
+
drag_start[0], drag_start[1],
|
|
226
|
+
drag_end[0], drag_end[1],
|
|
227
|
+
duration=1.0
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
if drag_result.success:
|
|
231
|
+
data = drag_result.data
|
|
232
|
+
print_step(
|
|
233
|
+
"Mouse Drag",
|
|
234
|
+
f"Dragged from {data['start_position']} to {data['end_position']}, "
|
|
235
|
+
f"Distance: {data['distance']:.1f}px"
|
|
236
|
+
)
|
|
237
|
+
else:
|
|
238
|
+
print_step("Mouse Drag", f"Failed: {drag_result.error}", False)
|
|
239
|
+
|
|
240
|
+
# 6. Scrolling
|
|
241
|
+
scroll_result_up = self.controller.scroll_mouse(3)
|
|
242
|
+
if scroll_result_up.success:
|
|
243
|
+
print_step("Scroll Up", "Scrolled up 3 clicks")
|
|
244
|
+
|
|
245
|
+
time.sleep(0.5)
|
|
246
|
+
|
|
247
|
+
scroll_result_down = self.controller.scroll_mouse(-5, 400, 300)
|
|
248
|
+
if scroll_result_down.success:
|
|
249
|
+
print_step("Scroll Down", "Scrolled down 5 clicks at (400, 300)")
|
|
250
|
+
|
|
251
|
+
# Return to starting position
|
|
252
|
+
self.controller.move_mouse(start_pos[0], start_pos[1], duration=1.0)
|
|
253
|
+
print_step("Return to Start", f"Moved back to {start_pos}")
|
|
254
|
+
|
|
255
|
+
wait_for_user("Mouse control demo complete. Continue to keyboard automation?")
|
|
256
|
+
|
|
257
|
+
def demo_keyboard_automation(self):
|
|
258
|
+
"""Demo: Keyboard Input & Hotkeys"""
|
|
259
|
+
print_section(
|
|
260
|
+
"KEYBOARD AUTOMATION",
|
|
261
|
+
"Demonstrating text typing, key presses, combinations, and hotkeys"
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
print("β¨οΈ Keyboard input will be sent to the currently focused window!")
|
|
265
|
+
print("π‘ Consider opening a text editor (like Notepad) to see the results clearly.")
|
|
266
|
+
wait_for_user("Ready for keyboard demo? Make sure you have a text editor open!")
|
|
267
|
+
|
|
268
|
+
# 1. Text typing with different speeds
|
|
269
|
+
typing_demos = [
|
|
270
|
+
{"text": "Hello PyAutoGUI Integration! ", "interval": 0.05, "desc": "Slow typing"},
|
|
271
|
+
{"text": "Fast typing demonstration. ", "interval": 0.01, "desc": "Fast typing"},
|
|
272
|
+
{"text": "Normal speed text input.\n", "interval": 0.03, "desc": "Normal typing"},
|
|
273
|
+
]
|
|
274
|
+
|
|
275
|
+
for demo in typing_demos:
|
|
276
|
+
type_result = self.controller.type_text(demo["text"], demo["interval"])
|
|
277
|
+
if type_result.success:
|
|
278
|
+
print_step(
|
|
279
|
+
demo["desc"],
|
|
280
|
+
f"Typed '{demo['text'].strip()}' with {demo['interval']}s interval"
|
|
281
|
+
)
|
|
282
|
+
time.sleep(0.5)
|
|
283
|
+
else:
|
|
284
|
+
print_step(demo["desc"], f"Failed: {type_result.error}", False)
|
|
285
|
+
|
|
286
|
+
time.sleep(1)
|
|
287
|
+
|
|
288
|
+
# 2. Individual key presses
|
|
289
|
+
key_demos = [
|
|
290
|
+
{"key": "tab", "desc": "Tab key"},
|
|
291
|
+
{"key": "space", "presses": 3, "desc": "3 space presses"},
|
|
292
|
+
{"key": "backspace", "presses": 5, "desc": "5 backspace presses"},
|
|
293
|
+
{"key": "enter", "desc": "Enter key"},
|
|
294
|
+
]
|
|
295
|
+
|
|
296
|
+
for demo in key_demos:
|
|
297
|
+
presses = demo.get("presses", 1)
|
|
298
|
+
key_result = self.controller.press_key(demo["key"], presses=presses)
|
|
299
|
+
if key_result.success:
|
|
300
|
+
print_step(
|
|
301
|
+
demo["desc"],
|
|
302
|
+
f"Pressed '{demo['key']}' {presses} time(s)"
|
|
303
|
+
)
|
|
304
|
+
time.sleep(0.3)
|
|
305
|
+
else:
|
|
306
|
+
print_step(demo["desc"], f"Failed: {key_result.error}", False)
|
|
307
|
+
|
|
308
|
+
# 3. Key combinations (hotkeys)
|
|
309
|
+
hotkey_demos = [
|
|
310
|
+
{"keys": ["ctrl", "a"], "desc": "Select All (Ctrl+A)"},
|
|
311
|
+
{"keys": ["ctrl", "c"], "desc": "Copy (Ctrl+C)"},
|
|
312
|
+
{"keys": ["ctrl", "v"], "desc": "Paste (Ctrl+V)"},
|
|
313
|
+
{"keys": ["ctrl", "z"], "desc": "Undo (Ctrl+Z)"},
|
|
314
|
+
{"keys": ["alt", "tab"], "desc": "Alt+Tab (Window Switch)"},
|
|
315
|
+
]
|
|
316
|
+
|
|
317
|
+
for demo in hotkey_demos:
|
|
318
|
+
combo_result = self.controller.key_combination(demo["keys"])
|
|
319
|
+
if combo_result.success:
|
|
320
|
+
print_step(
|
|
321
|
+
demo["desc"],
|
|
322
|
+
f"Executed {'+'.join(demo['keys'])}"
|
|
323
|
+
)
|
|
324
|
+
time.sleep(0.5)
|
|
325
|
+
else:
|
|
326
|
+
print_step(demo["desc"], f"Failed: {combo_result.error}", False)
|
|
327
|
+
|
|
328
|
+
# 4. Key holding
|
|
329
|
+
hold_result = self.controller.hold_key("shift", duration=1.0)
|
|
330
|
+
if hold_result.success:
|
|
331
|
+
print_step(
|
|
332
|
+
"Hold Key Demo",
|
|
333
|
+
"Held Shift key for 1.0 seconds"
|
|
334
|
+
)
|
|
335
|
+
else:
|
|
336
|
+
print_step("Hold Key Demo", f"Failed: {hold_result.error}", False)
|
|
337
|
+
|
|
338
|
+
# 5. Available keys information
|
|
339
|
+
keys_result = self.controller.get_available_keys()
|
|
340
|
+
if keys_result.success:
|
|
341
|
+
data = keys_result.data
|
|
342
|
+
categories = data["categories"]
|
|
343
|
+
print_step(
|
|
344
|
+
"Available Keys",
|
|
345
|
+
f"Total: {data['total_count']} keys across {len(categories)} categories"
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
# Show some examples
|
|
349
|
+
print(" Key Categories:")
|
|
350
|
+
for category, keys in categories.items():
|
|
351
|
+
if keys:
|
|
352
|
+
sample = keys[:3]
|
|
353
|
+
print(f" {category.replace('_', ' ').title()}: {', '.join(sample)}{'...' if len(keys) > 3 else ''}")
|
|
354
|
+
else:
|
|
355
|
+
print_step("Available Keys", f"Failed: {keys_result.error}", False)
|
|
356
|
+
|
|
357
|
+
wait_for_user("Keyboard automation demo complete. Continue to advanced features?")
|
|
358
|
+
|
|
359
|
+
def demo_advanced_features(self):
|
|
360
|
+
"""Demo: Advanced Features"""
|
|
361
|
+
print_section(
|
|
362
|
+
"ADVANCED FEATURES",
|
|
363
|
+
"Demonstrating image templates, batch operations, and configuration"
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
# 1. Configuration management
|
|
367
|
+
print("π§ Configuration Management")
|
|
368
|
+
|
|
369
|
+
# Set pause duration
|
|
370
|
+
pause_result = self.controller.set_pause(0.05)
|
|
371
|
+
if pause_result.success:
|
|
372
|
+
data = pause_result.data
|
|
373
|
+
print_step(
|
|
374
|
+
"Set Pause Duration",
|
|
375
|
+
f"Changed from {data['old_pause']}s to {data['new_pause']}s"
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
# Failsafe management
|
|
379
|
+
failsafe_result = self.controller.set_failsafe(True)
|
|
380
|
+
if failsafe_result.success:
|
|
381
|
+
print_step(
|
|
382
|
+
"Failsafe Setting",
|
|
383
|
+
"Failsafe enabled (move mouse to corner to abort)"
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
# 2. Image template creation
|
|
387
|
+
print("\nπΈ Image Template System")
|
|
388
|
+
|
|
389
|
+
template_region = (100, 100, 200, 150) # 200x150 region
|
|
390
|
+
template_result = self.controller.create_image_template(
|
|
391
|
+
"demo_template",
|
|
392
|
+
template_region[0], template_region[1],
|
|
393
|
+
template_region[2], template_region[3]
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
if template_result.success:
|
|
397
|
+
data = template_result.data
|
|
398
|
+
print_step(
|
|
399
|
+
"Create Image Template",
|
|
400
|
+
f"Template '{data['template_name']}' created from region {data['region']}"
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
# Try to find the template immediately
|
|
404
|
+
find_result = self.controller.find_template_on_screen("demo_template", confidence=0.9)
|
|
405
|
+
if find_result.success:
|
|
406
|
+
match = find_result.data["match"]
|
|
407
|
+
if match["found"]:
|
|
408
|
+
print_step(
|
|
409
|
+
"Find Template",
|
|
410
|
+
f"Template found at ({match['x']}, {match['y']})"
|
|
411
|
+
)
|
|
412
|
+
else:
|
|
413
|
+
print_step(
|
|
414
|
+
"Find Template",
|
|
415
|
+
"Template not found (expected, as screen content changed)"
|
|
416
|
+
)
|
|
417
|
+
else:
|
|
418
|
+
print_step("Find Template", f"Failed: {find_result.error}", False)
|
|
419
|
+
else:
|
|
420
|
+
print_step("Create Template", f"Failed: {template_result.error}", False)
|
|
421
|
+
|
|
422
|
+
wait_for_user("Advanced features demo complete. Continue to practical examples?")
|
|
423
|
+
|
|
424
|
+
def demo_practical_examples(self):
|
|
425
|
+
"""Demo: Practical Automation Examples"""
|
|
426
|
+
print_section(
|
|
427
|
+
"PRACTICAL AUTOMATION EXAMPLES",
|
|
428
|
+
"Real-world automation scenarios using combined PyAutoGUI features"
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
print("π― Example 1: Screenshot Analysis and Auto-Click")
|
|
432
|
+
|
|
433
|
+
# Take screenshot and analyze
|
|
434
|
+
screenshot = self.controller.take_screenshot()
|
|
435
|
+
if screenshot.success:
|
|
436
|
+
width = screenshot.data['width']
|
|
437
|
+
height = screenshot.data['height']
|
|
438
|
+
|
|
439
|
+
# Calculate interesting points
|
|
440
|
+
center = (width // 2, height // 2)
|
|
441
|
+
quarter_point = (width // 4, height // 4)
|
|
442
|
+
|
|
443
|
+
# Get pixel colors at these points
|
|
444
|
+
center_pixel = self.controller.get_pixel_color(center[0], center[1])
|
|
445
|
+
quarter_pixel = self.controller.get_pixel_color(quarter_point[0], quarter_point[1])
|
|
446
|
+
|
|
447
|
+
if center_pixel.success and quarter_pixel.success:
|
|
448
|
+
print_step(
|
|
449
|
+
"Screenshot Analysis",
|
|
450
|
+
f"Center pixel: {center_pixel.data['hex']}, "
|
|
451
|
+
f"Quarter pixel: {quarter_pixel.data['hex']}"
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
# Simulate clicking based on analysis
|
|
455
|
+
print(" Simulating intelligent clicking...")
|
|
456
|
+
self.controller.click_mouse(center[0], center[1])
|
|
457
|
+
time.sleep(0.5)
|
|
458
|
+
self.controller.click_mouse(quarter_point[0], quarter_point[1])
|
|
459
|
+
|
|
460
|
+
print_step("Auto-Click", "Clicked at analyzed positions")
|
|
461
|
+
else:
|
|
462
|
+
print_step("Screenshot Analysis", "Failed to analyze pixels", False)
|
|
463
|
+
|
|
464
|
+
print("\nπ― Example 2: Text Input with Formatting")
|
|
465
|
+
|
|
466
|
+
# Simulate creating formatted text
|
|
467
|
+
formatting_sequence = [
|
|
468
|
+
("Bold Text Example", ["ctrl", "b"]),
|
|
469
|
+
("Italic Text Example", ["ctrl", "i"]),
|
|
470
|
+
("Underlined Text", ["ctrl", "u"]),
|
|
471
|
+
]
|
|
472
|
+
|
|
473
|
+
for text, format_keys in formatting_sequence:
|
|
474
|
+
# Apply formatting
|
|
475
|
+
self.controller.key_combination(format_keys)
|
|
476
|
+
time.sleep(0.1)
|
|
477
|
+
|
|
478
|
+
# Type text
|
|
479
|
+
self.controller.type_text(text + "\n", interval=0.02)
|
|
480
|
+
time.sleep(0.2)
|
|
481
|
+
|
|
482
|
+
# Remove formatting
|
|
483
|
+
self.controller.key_combination(format_keys)
|
|
484
|
+
time.sleep(0.1)
|
|
485
|
+
|
|
486
|
+
print_step("Formatted Text Input", "Applied bold, italic, and underline formatting")
|
|
487
|
+
|
|
488
|
+
print("\nπ― Example 3: Window Navigation Simulation")
|
|
489
|
+
|
|
490
|
+
# Simulate window navigation
|
|
491
|
+
navigation_sequence = [
|
|
492
|
+
(["alt", "tab"], "Switch to next window"),
|
|
493
|
+
(["win", "d"], "Show desktop"),
|
|
494
|
+
(["win", "r"], "Open Run dialog"),
|
|
495
|
+
]
|
|
496
|
+
|
|
497
|
+
for keys, description in navigation_sequence:
|
|
498
|
+
self.controller.key_combination(keys)
|
|
499
|
+
print_step("Window Navigation", description)
|
|
500
|
+
time.sleep(1.0) # Give time for window changes
|
|
501
|
+
|
|
502
|
+
# Press Escape to close any opened dialogs
|
|
503
|
+
self.controller.press_key("escape")
|
|
504
|
+
print_step("Cleanup", "Pressed Escape to close dialogs")
|
|
505
|
+
|
|
506
|
+
print("\nπ― Example 4: Batch Operations Demo")
|
|
507
|
+
|
|
508
|
+
# Simulate batch clicking at calculated positions
|
|
509
|
+
screen_info = self.controller.get_screen_info()
|
|
510
|
+
if screen_info.success:
|
|
511
|
+
width = screen_info.data['width']
|
|
512
|
+
height = screen_info.data['height']
|
|
513
|
+
|
|
514
|
+
# Create a grid of click points
|
|
515
|
+
click_points = []
|
|
516
|
+
for i in range(3):
|
|
517
|
+
for j in range(3):
|
|
518
|
+
x = (width // 4) + (i * width // 6)
|
|
519
|
+
y = (height // 4) + (j * height // 6)
|
|
520
|
+
click_points.append((x, y))
|
|
521
|
+
|
|
522
|
+
print(" Performing grid click pattern...")
|
|
523
|
+
for i, (x, y) in enumerate(click_points):
|
|
524
|
+
self.controller.click_mouse(x, y)
|
|
525
|
+
time.sleep(0.1)
|
|
526
|
+
|
|
527
|
+
print_step("Batch Grid Clicks", f"Clicked {len(click_points)} positions in grid pattern")
|
|
528
|
+
|
|
529
|
+
wait_for_user("Practical examples complete. Continue to performance analysis?")
|
|
530
|
+
|
|
531
|
+
def demo_performance_analysis(self):
|
|
532
|
+
"""Demo: Performance Analysis"""
|
|
533
|
+
print_section(
|
|
534
|
+
"PERFORMANCE ANALYSIS",
|
|
535
|
+
"Measuring performance of various PyAutoGUI operations"
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
performance_tests = [
|
|
539
|
+
{
|
|
540
|
+
"name": "Screenshot Capture",
|
|
541
|
+
"operation": lambda: self.controller.take_screenshot(),
|
|
542
|
+
"iterations": 5
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
"name": "Mouse Position Query",
|
|
546
|
+
"operation": lambda: self.controller.get_mouse_position(),
|
|
547
|
+
"iterations": 10
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
"name": "Pixel Color Reading",
|
|
551
|
+
"operation": lambda: self.controller.get_pixel_color(100, 100),
|
|
552
|
+
"iterations": 10
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
"name": "Mouse Movement",
|
|
556
|
+
"operation": lambda: self.controller.move_mouse(200, 200, duration=0.1),
|
|
557
|
+
"iterations": 5
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
"name": "Key Press",
|
|
561
|
+
"operation": lambda: self.controller.press_key("space"),
|
|
562
|
+
"iterations": 10
|
|
563
|
+
}
|
|
564
|
+
]
|
|
565
|
+
|
|
566
|
+
for test in performance_tests:
|
|
567
|
+
print(f"\nπ Testing {test['name']} ({test['iterations']} iterations)")
|
|
568
|
+
|
|
569
|
+
times = []
|
|
570
|
+
successes = 0
|
|
571
|
+
|
|
572
|
+
for i in range(test['iterations']):
|
|
573
|
+
start_time = time.time()
|
|
574
|
+
result = test['operation']()
|
|
575
|
+
end_time = time.time()
|
|
576
|
+
|
|
577
|
+
duration = (end_time - start_time) * 1000 # Convert to milliseconds
|
|
578
|
+
times.append(duration)
|
|
579
|
+
|
|
580
|
+
if result.success:
|
|
581
|
+
successes += 1
|
|
582
|
+
|
|
583
|
+
time.sleep(0.1) # Small delay between tests
|
|
584
|
+
|
|
585
|
+
# Calculate statistics
|
|
586
|
+
avg_time = sum(times) / len(times)
|
|
587
|
+
min_time = min(times)
|
|
588
|
+
max_time = max(times)
|
|
589
|
+
success_rate = (successes / test['iterations']) * 100
|
|
590
|
+
|
|
591
|
+
print_step(
|
|
592
|
+
f"{test['name']} Performance",
|
|
593
|
+
f"Avg: {avg_time:.1f}ms, Min: {min_time:.1f}ms, Max: {max_time:.1f}ms, "
|
|
594
|
+
f"Success: {success_rate:.0f}%"
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
wait_for_user("Performance analysis complete. Continue to integration demo?")
|
|
598
|
+
|
|
599
|
+
def demo_mcp_integration(self):
|
|
600
|
+
"""Demo: MCP Integration"""
|
|
601
|
+
print_section(
|
|
602
|
+
"MCP INTEGRATION DEMONSTRATION",
|
|
603
|
+
"Showing how PyAutoGUI integrates with MCP Cheat Engine Server"
|
|
604
|
+
)
|
|
605
|
+
|
|
606
|
+
# Import MCP handler for testing
|
|
607
|
+
try:
|
|
608
|
+
from pyautogui_tools import PyAutoGUIToolHandler
|
|
609
|
+
handler = PyAutoGUIToolHandler()
|
|
610
|
+
|
|
611
|
+
if not handler.available:
|
|
612
|
+
print_step("MCP Handler", "Not available", False)
|
|
613
|
+
return
|
|
614
|
+
|
|
615
|
+
print_step("MCP Handler", "Successfully initialized")
|
|
616
|
+
|
|
617
|
+
# Test MCP tool handlers
|
|
618
|
+
mcp_tests = [
|
|
619
|
+
{
|
|
620
|
+
"name": "Screenshot via MCP",
|
|
621
|
+
"handler": handler.handle_screenshot,
|
|
622
|
+
"args": {}
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
"name": "Mouse Position via MCP",
|
|
626
|
+
"handler": handler.handle_mouse_position,
|
|
627
|
+
"args": {}
|
|
628
|
+
},
|
|
629
|
+
{
|
|
630
|
+
"name": "Screen Info via MCP",
|
|
631
|
+
"handler": handler.handle_screen_info,
|
|
632
|
+
"args": {}
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
"name": "Available Keys via MCP",
|
|
636
|
+
"handler": handler.handle_get_available_keys,
|
|
637
|
+
"args": {}
|
|
638
|
+
}
|
|
639
|
+
]
|
|
640
|
+
|
|
641
|
+
print("\nπ§ Testing MCP Tool Handlers:")
|
|
642
|
+
|
|
643
|
+
for test in mcp_tests:
|
|
644
|
+
try:
|
|
645
|
+
result = asyncio.run(test["handler"](test["args"]))
|
|
646
|
+
|
|
647
|
+
if result.get("success", False):
|
|
648
|
+
print_step(test["name"], "Handler working correctly")
|
|
649
|
+
else:
|
|
650
|
+
print_step(test["name"], f"Handler failed: {result.get('error', 'Unknown')}", False)
|
|
651
|
+
|
|
652
|
+
except Exception as e:
|
|
653
|
+
print_step(test["name"], f"Exception: {e}", False)
|
|
654
|
+
|
|
655
|
+
# Show available MCP tools
|
|
656
|
+
from pyautogui_tools import ALL_PYAUTOGUI_TOOLS
|
|
657
|
+
|
|
658
|
+
print(f"\nπ Available MCP Tools: {len(ALL_PYAUTOGUI_TOOLS)}")
|
|
659
|
+
|
|
660
|
+
categories = {
|
|
661
|
+
"Screen": ["screenshot", "pixel_color", "find_image", "screen_info"],
|
|
662
|
+
"Mouse": ["mouse_position", "move_mouse", "click_mouse", "drag_mouse", "scroll_mouse"],
|
|
663
|
+
"Keyboard": ["type_text", "press_key", "key_combination", "hold_key"],
|
|
664
|
+
"Advanced": ["create_template", "find_template", "batch_clicks", "batch_keys"],
|
|
665
|
+
"Config": ["set_pause", "set_failsafe", "get_available_keys", "is_on_screen"]
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
for category, tool_patterns in categories.items():
|
|
669
|
+
matching_tools = [tool for tool in ALL_PYAUTOGUI_TOOLS
|
|
670
|
+
if any(pattern in tool.name for pattern in tool_patterns)]
|
|
671
|
+
print(f" {category}: {len(matching_tools)} tools")
|
|
672
|
+
|
|
673
|
+
print_step("MCP Integration", f"All {len(ALL_PYAUTOGUI_TOOLS)} PyAutoGUI tools available via MCP")
|
|
674
|
+
|
|
675
|
+
except ImportError as e:
|
|
676
|
+
print_step("MCP Integration", f"Import failed: {e}", False)
|
|
677
|
+
except Exception as e:
|
|
678
|
+
print_step("MCP Integration", f"Error: {e}", False)
|
|
679
|
+
|
|
680
|
+
def run_complete_demo(self):
|
|
681
|
+
"""Run the complete demonstration"""
|
|
682
|
+
|
|
683
|
+
print("π PYAUTOGUI INTEGRATION DEMO FOR MCP CHEAT ENGINE SERVER")
|
|
684
|
+
print("=" * 70)
|
|
685
|
+
print("This demo showcases all PyAutoGUI functionality integrated into the")
|
|
686
|
+
print("MCP Cheat Engine Server. Each section demonstrates different capabilities.")
|
|
687
|
+
print("\nβ οΈ WARNING: This demo will control your mouse and keyboard!")
|
|
688
|
+
print("Move your mouse to the top-left corner to trigger failsafe if needed.")
|
|
689
|
+
|
|
690
|
+
continue_demo = input("\nπ Ready to start? (y/N): ").lower().strip()
|
|
691
|
+
if continue_demo != 'y':
|
|
692
|
+
print("Demo cancelled.")
|
|
693
|
+
return
|
|
694
|
+
|
|
695
|
+
try:
|
|
696
|
+
# Run all demo sections
|
|
697
|
+
self.demo_screen_analysis()
|
|
698
|
+
self.demo_mouse_control()
|
|
699
|
+
self.demo_keyboard_automation()
|
|
700
|
+
self.demo_advanced_features()
|
|
701
|
+
self.demo_practical_examples()
|
|
702
|
+
self.demo_performance_analysis()
|
|
703
|
+
self.demo_mcp_integration()
|
|
704
|
+
|
|
705
|
+
# Final summary
|
|
706
|
+
print_section(
|
|
707
|
+
"DEMO COMPLETE! π",
|
|
708
|
+
"All PyAutoGUI functionality has been demonstrated"
|
|
709
|
+
)
|
|
710
|
+
|
|
711
|
+
print("β
Screen capture and analysis")
|
|
712
|
+
print("β
Mouse control and automation")
|
|
713
|
+
print("β
Keyboard input and hotkeys")
|
|
714
|
+
print("β
Advanced image recognition")
|
|
715
|
+
print("β
Batch operations")
|
|
716
|
+
print("β
Performance analysis")
|
|
717
|
+
print("β
MCP integration")
|
|
718
|
+
|
|
719
|
+
print(f"\nπ― Summary:")
|
|
720
|
+
print(f" β’ Screen Resolution: {self.demo_data.get('screen_width', 'N/A')}x{self.demo_data.get('screen_height', 'N/A')}")
|
|
721
|
+
print(f" β’ PyAutoGUI: Fully integrated")
|
|
722
|
+
print(f" β’ MCP Tools: All {len(ALL_PYAUTOGUI_TOOLS) if 'ALL_PYAUTOGUI_TOOLS' in globals() else 'N/A'} tools available")
|
|
723
|
+
print(f" β’ Status: Ready for production use!")
|
|
724
|
+
|
|
725
|
+
print("\nπ The MCP Cheat Engine Server now has complete PyAutoGUI functionality!")
|
|
726
|
+
print(" You can use all these features through MCP tool calls in Claude Desktop.")
|
|
727
|
+
|
|
728
|
+
except KeyboardInterrupt:
|
|
729
|
+
print("\n\nβΉοΈ Demo interrupted by user")
|
|
730
|
+
except Exception as e:
|
|
731
|
+
print(f"\n\nπ₯ Demo error: {e}")
|
|
732
|
+
import traceback
|
|
733
|
+
traceback.print_exc()
|
|
734
|
+
|
|
735
|
+
def main():
|
|
736
|
+
"""Main entry point"""
|
|
737
|
+
try:
|
|
738
|
+
demo = PyAutoGUIDemo()
|
|
739
|
+
demo.run_complete_demo()
|
|
740
|
+
except KeyboardInterrupt:
|
|
741
|
+
print("\nβΉοΈ Demo cancelled by user")
|
|
742
|
+
except Exception as e:
|
|
743
|
+
print(f"β Demo failed to start: {e}")
|
|
744
|
+
import traceback
|
|
745
|
+
traceback.print_exc()
|
|
746
|
+
|
|
747
|
+
if __name__ == "__main__":
|
|
748
|
+
# Handle asyncio import for MCP integration test
|
|
749
|
+
try:
|
|
750
|
+
import asyncio
|
|
751
|
+
except ImportError:
|
|
752
|
+
print("β οΈ asyncio not available - MCP integration test will be skipped")
|
|
753
|
+
|
|
754
|
+
main()
|