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,460 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
MCP Cheat Engine Server - PyAutoGUI Notepad Automation Demo
|
|
4
|
+
|
|
5
|
+
This script demonstrates the complete integration of:
|
|
6
|
+
1. PyAutoGUI for screen automation and keystroke injection
|
|
7
|
+
2. MCP Cheat Engine Server for memory scanning and text location
|
|
8
|
+
3. Process management and window control
|
|
9
|
+
|
|
10
|
+
Workflow:
|
|
11
|
+
1. Launch Notepad using PyAutoGUI
|
|
12
|
+
2. Send "Hello World" text using PyAutoGUI
|
|
13
|
+
3. Find the text in Notepad's memory using MCP tools
|
|
14
|
+
4. Display memory addresses and current text content
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import os
|
|
18
|
+
import sys
|
|
19
|
+
import time
|
|
20
|
+
import logging
|
|
21
|
+
import subprocess
|
|
22
|
+
import psutil
|
|
23
|
+
from typing import Dict, Any, List, Optional
|
|
24
|
+
|
|
25
|
+
# Add server directory to path for MCP integration
|
|
26
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'server'))
|
|
27
|
+
|
|
28
|
+
# Import our PyAutoGUI integration
|
|
29
|
+
from pyautogui_integration import PyAutoGUIController
|
|
30
|
+
from pyautogui_tools import PyAutoGUIToolHandler
|
|
31
|
+
|
|
32
|
+
# Configure logging
|
|
33
|
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
34
|
+
logger = logging.getLogger(__name__)
|
|
35
|
+
|
|
36
|
+
class NotepadAutomationDemo:
|
|
37
|
+
"""Demonstrates PyAutoGUI + MCP integration for Notepad automation"""
|
|
38
|
+
|
|
39
|
+
def __init__(self):
|
|
40
|
+
self.pyautogui_controller = None
|
|
41
|
+
self.pyautogui_handler = None
|
|
42
|
+
self.notepad_process = None
|
|
43
|
+
self.memory_reader = None
|
|
44
|
+
self.target_text = "Hello World from PyAutoGUI and MCP!"
|
|
45
|
+
|
|
46
|
+
def initialize_systems(self) -> bool:
|
|
47
|
+
"""Initialize PyAutoGUI and MCP systems"""
|
|
48
|
+
try:
|
|
49
|
+
# Initialize PyAutoGUI
|
|
50
|
+
self.pyautogui_controller = PyAutoGUIController()
|
|
51
|
+
self.pyautogui_handler = PyAutoGUIToolHandler()
|
|
52
|
+
logger.info("✅ PyAutoGUI systems initialized")
|
|
53
|
+
|
|
54
|
+
# Initialize memory reader
|
|
55
|
+
try:
|
|
56
|
+
from memory.reader import MemoryReader
|
|
57
|
+
self.memory_reader = MemoryReader()
|
|
58
|
+
logger.info("✅ MCP Memory Reader initialized")
|
|
59
|
+
except Exception as e:
|
|
60
|
+
logger.warning(f"⚠️ Memory reader initialization failed: {e}")
|
|
61
|
+
logger.info("Continuing with basic functionality...")
|
|
62
|
+
|
|
63
|
+
return True
|
|
64
|
+
|
|
65
|
+
except Exception as e:
|
|
66
|
+
logger.error(f"❌ System initialization failed: {e}")
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
def launch_notepad(self) -> bool:
|
|
70
|
+
"""Launch Notepad using PyAutoGUI"""
|
|
71
|
+
try:
|
|
72
|
+
logger.info("🚀 Launching Notepad...")
|
|
73
|
+
|
|
74
|
+
# Use PyAutoGUI to open Run dialog
|
|
75
|
+
result = self.pyautogui_controller.key_combination(['win', 'r'])
|
|
76
|
+
if not result.success:
|
|
77
|
+
logger.error(f"Failed to open Run dialog: {result.error}")
|
|
78
|
+
return False
|
|
79
|
+
|
|
80
|
+
time.sleep(1)
|
|
81
|
+
|
|
82
|
+
# Type notepad command
|
|
83
|
+
result = self.pyautogui_controller.type_text("notepad")
|
|
84
|
+
if not result.success:
|
|
85
|
+
logger.error(f"Failed to type notepad: {result.error}")
|
|
86
|
+
return False
|
|
87
|
+
|
|
88
|
+
time.sleep(0.5)
|
|
89
|
+
|
|
90
|
+
# Press Enter to launch
|
|
91
|
+
result = self.pyautogui_controller.press_key("enter")
|
|
92
|
+
if not result.success:
|
|
93
|
+
logger.error(f"Failed to press Enter: {result.error}")
|
|
94
|
+
return False
|
|
95
|
+
|
|
96
|
+
# Wait for Notepad to load
|
|
97
|
+
time.sleep(2)
|
|
98
|
+
|
|
99
|
+
# Find Notepad process
|
|
100
|
+
self.notepad_process = self._find_notepad_process()
|
|
101
|
+
if self.notepad_process:
|
|
102
|
+
logger.info(f"✅ Notepad launched successfully (PID: {self.notepad_process.pid})")
|
|
103
|
+
return True
|
|
104
|
+
else:
|
|
105
|
+
logger.error("❌ Could not find Notepad process")
|
|
106
|
+
return False
|
|
107
|
+
|
|
108
|
+
except Exception as e:
|
|
109
|
+
logger.error(f"❌ Failed to launch Notepad: {e}")
|
|
110
|
+
return False
|
|
111
|
+
|
|
112
|
+
def send_text_to_notepad(self) -> bool:
|
|
113
|
+
"""Send text to Notepad using PyAutoGUI"""
|
|
114
|
+
try:
|
|
115
|
+
logger.info(f"📝 Sending text to Notepad: '{self.target_text}'")
|
|
116
|
+
|
|
117
|
+
# Take a screenshot first to see current state
|
|
118
|
+
screenshot_result = self.pyautogui_controller.take_screenshot()
|
|
119
|
+
if screenshot_result.success:
|
|
120
|
+
logger.info("📷 Screenshot taken for reference")
|
|
121
|
+
|
|
122
|
+
# Click in the Notepad window to ensure focus
|
|
123
|
+
# Get screen center as a safe click location
|
|
124
|
+
screen_info = self.pyautogui_controller.get_screen_info()
|
|
125
|
+
center_x = screen_info.data['width'] // 2
|
|
126
|
+
center_y = screen_info.data['height'] // 2
|
|
127
|
+
|
|
128
|
+
click_result = self.pyautogui_controller.click_mouse(center_x, center_y)
|
|
129
|
+
if click_result.success:
|
|
130
|
+
logger.info("🖱️ Clicked to focus window")
|
|
131
|
+
|
|
132
|
+
time.sleep(0.5)
|
|
133
|
+
|
|
134
|
+
# Type the target text
|
|
135
|
+
type_result = self.pyautogui_controller.type_text(self.target_text, interval=0.02)
|
|
136
|
+
if not type_result.success:
|
|
137
|
+
logger.error(f"Failed to type text: {type_result.error}")
|
|
138
|
+
return False
|
|
139
|
+
|
|
140
|
+
logger.info("✅ Text sent successfully to Notepad")
|
|
141
|
+
|
|
142
|
+
# Add a newline and timestamp for better identification
|
|
143
|
+
self.pyautogui_controller.press_key("enter")
|
|
144
|
+
time.sleep(0.1)
|
|
145
|
+
timestamp_text = f"Timestamp: {time.strftime('%Y-%m-%d %H:%M:%S')}"
|
|
146
|
+
self.pyautogui_controller.type_text(timestamp_text, interval=0.01)
|
|
147
|
+
|
|
148
|
+
time.sleep(1) # Allow text to be processed
|
|
149
|
+
return True
|
|
150
|
+
|
|
151
|
+
except Exception as e:
|
|
152
|
+
logger.error(f"❌ Failed to send text to Notepad: {e}")
|
|
153
|
+
return False
|
|
154
|
+
|
|
155
|
+
def find_text_in_memory(self) -> List[Dict[str, Any]]:
|
|
156
|
+
"""Find the text in Notepad's memory using MCP tools"""
|
|
157
|
+
try:
|
|
158
|
+
logger.info(f"🔍 Searching for text in Notepad memory...")
|
|
159
|
+
|
|
160
|
+
if not self.notepad_process:
|
|
161
|
+
logger.error("No Notepad process found")
|
|
162
|
+
return []
|
|
163
|
+
|
|
164
|
+
# Initialize memory reader for Notepad process
|
|
165
|
+
if self.memory_reader:
|
|
166
|
+
try:
|
|
167
|
+
process_info = {
|
|
168
|
+
'pid': self.notepad_process.pid,
|
|
169
|
+
'name': self.notepad_process.name(),
|
|
170
|
+
'handle': None
|
|
171
|
+
}
|
|
172
|
+
self.memory_reader.set_process(process_info)
|
|
173
|
+
logger.info("🎯 Memory reader attached to Notepad")
|
|
174
|
+
except Exception as e:
|
|
175
|
+
logger.error(f"Failed to attach memory reader: {e}")
|
|
176
|
+
return []
|
|
177
|
+
else:
|
|
178
|
+
logger.error("Memory reader not available")
|
|
179
|
+
return []
|
|
180
|
+
|
|
181
|
+
found_locations = []
|
|
182
|
+
|
|
183
|
+
# Search for our target text
|
|
184
|
+
search_texts = [
|
|
185
|
+
self.target_text,
|
|
186
|
+
"Hello World", # Partial search
|
|
187
|
+
"PyAutoGUI", # Another partial search
|
|
188
|
+
]
|
|
189
|
+
|
|
190
|
+
for search_text in search_texts:
|
|
191
|
+
logger.info(f"🔎 Searching for: '{search_text}'")
|
|
192
|
+
locations = self._search_memory_for_text(search_text)
|
|
193
|
+
|
|
194
|
+
for location in locations:
|
|
195
|
+
found_locations.append({
|
|
196
|
+
'search_term': search_text,
|
|
197
|
+
'address': location['address'],
|
|
198
|
+
'address_hex': f"0x{location['address']:X}",
|
|
199
|
+
'encoding': location['encoding'],
|
|
200
|
+
'content': location['content'],
|
|
201
|
+
'context': location.get('context', ''),
|
|
202
|
+
'size': location.get('size', 0)
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
if locations:
|
|
206
|
+
logger.info(f"✅ Found {len(locations)} occurrences of '{search_text}'")
|
|
207
|
+
else:
|
|
208
|
+
logger.info(f"ℹ️ No occurrences found for '{search_text}'")
|
|
209
|
+
|
|
210
|
+
return found_locations
|
|
211
|
+
|
|
212
|
+
except Exception as e:
|
|
213
|
+
logger.error(f"❌ Memory search failed: {e}")
|
|
214
|
+
return []
|
|
215
|
+
|
|
216
|
+
def _search_memory_for_text(self, search_text: str) -> List[Dict[str, Any]]:
|
|
217
|
+
"""Search for text in process memory"""
|
|
218
|
+
try:
|
|
219
|
+
# Get readable memory regions
|
|
220
|
+
regions = self.memory_reader.get_memory_regions()
|
|
221
|
+
readable_regions = [r for r in regions if r.get('readable', False)]
|
|
222
|
+
|
|
223
|
+
found_locations = []
|
|
224
|
+
search_count = 0
|
|
225
|
+
max_regions = 50 # Limit search to prevent long execution times
|
|
226
|
+
|
|
227
|
+
logger.info(f"📊 Scanning {min(len(readable_regions), max_regions)} memory regions...")
|
|
228
|
+
|
|
229
|
+
for region in readable_regions[:max_regions]:
|
|
230
|
+
search_count += 1
|
|
231
|
+
try:
|
|
232
|
+
# Limit scan size to prevent excessive memory usage
|
|
233
|
+
scan_size = min(region['size'], 1 * 1024 * 1024) # 1MB max per region
|
|
234
|
+
|
|
235
|
+
memory_data = self.memory_reader.read_memory(
|
|
236
|
+
region['base_address'],
|
|
237
|
+
scan_size
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# Search for ASCII text
|
|
241
|
+
ascii_matches = self._find_text_in_bytes(
|
|
242
|
+
memory_data,
|
|
243
|
+
search_text.encode('ascii', errors='ignore'),
|
|
244
|
+
region['base_address'],
|
|
245
|
+
'ascii'
|
|
246
|
+
)
|
|
247
|
+
found_locations.extend(ascii_matches)
|
|
248
|
+
|
|
249
|
+
# Search for Unicode text (UTF-16 LE)
|
|
250
|
+
unicode_matches = self._find_text_in_bytes(
|
|
251
|
+
memory_data,
|
|
252
|
+
search_text.encode('utf-16le'),
|
|
253
|
+
region['base_address'],
|
|
254
|
+
'unicode'
|
|
255
|
+
)
|
|
256
|
+
found_locations.extend(unicode_matches)
|
|
257
|
+
|
|
258
|
+
if search_count % 10 == 0:
|
|
259
|
+
logger.info(f"⏳ Scanned {search_count} regions, found {len(found_locations)} matches so far...")
|
|
260
|
+
|
|
261
|
+
except Exception as e:
|
|
262
|
+
logger.debug(f"Skipped region {hex(region['base_address'])}: {e}")
|
|
263
|
+
continue
|
|
264
|
+
|
|
265
|
+
logger.info(f"🔍 Memory scan completed: {search_count} regions scanned")
|
|
266
|
+
return found_locations
|
|
267
|
+
|
|
268
|
+
except Exception as e:
|
|
269
|
+
logger.error(f"Memory search error: {e}")
|
|
270
|
+
return []
|
|
271
|
+
|
|
272
|
+
def _find_text_in_bytes(self, data: bytes, search_bytes: bytes, base_address: int, encoding: str) -> List[Dict[str, Any]]:
|
|
273
|
+
"""Find text occurrences in a byte array"""
|
|
274
|
+
locations = []
|
|
275
|
+
offset = 0
|
|
276
|
+
|
|
277
|
+
while True:
|
|
278
|
+
pos = data.find(search_bytes, offset)
|
|
279
|
+
if pos == -1:
|
|
280
|
+
break
|
|
281
|
+
|
|
282
|
+
address = base_address + pos
|
|
283
|
+
|
|
284
|
+
# Read context around the found text (64 bytes before and after)
|
|
285
|
+
context_start = max(0, pos - 64)
|
|
286
|
+
context_end = min(len(data), pos + len(search_bytes) + 64)
|
|
287
|
+
context_data = data[context_start:context_end]
|
|
288
|
+
|
|
289
|
+
# Extract readable text from context
|
|
290
|
+
try:
|
|
291
|
+
if encoding == 'ascii':
|
|
292
|
+
content = search_bytes.decode('ascii', errors='ignore')
|
|
293
|
+
context = context_data.decode('ascii', errors='ignore')
|
|
294
|
+
else:
|
|
295
|
+
content = search_bytes.decode('utf-16le', errors='ignore')
|
|
296
|
+
context = context_data.decode('utf-16le', errors='ignore')
|
|
297
|
+
|
|
298
|
+
# Clean up text (remove null bytes and non-printable chars)
|
|
299
|
+
content = ''.join(c for c in content if c.isprintable() or c.isspace()).strip()
|
|
300
|
+
context = ''.join(c for c in context if c.isprintable() or c.isspace()).strip()
|
|
301
|
+
|
|
302
|
+
except Exception:
|
|
303
|
+
content = f"<decode error: {encoding}>"
|
|
304
|
+
context = f"<context decode error>"
|
|
305
|
+
|
|
306
|
+
locations.append({
|
|
307
|
+
'address': address,
|
|
308
|
+
'size': len(search_bytes),
|
|
309
|
+
'encoding': encoding,
|
|
310
|
+
'content': content,
|
|
311
|
+
'context': context,
|
|
312
|
+
'hex_data': context_data[:32].hex() # First 32 bytes as hex
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
offset = pos + 1
|
|
316
|
+
|
|
317
|
+
# Limit results to prevent excessive output
|
|
318
|
+
if len(locations) >= 10:
|
|
319
|
+
break
|
|
320
|
+
|
|
321
|
+
return locations
|
|
322
|
+
|
|
323
|
+
def _find_notepad_process(self) -> Optional[psutil.Process]:
|
|
324
|
+
"""Find the Notepad process"""
|
|
325
|
+
try:
|
|
326
|
+
for proc in psutil.process_iter(['pid', 'name', 'create_time']):
|
|
327
|
+
if proc.info['name'].lower() == 'notepad.exe':
|
|
328
|
+
# Return the most recently created Notepad process
|
|
329
|
+
return proc
|
|
330
|
+
except Exception as e:
|
|
331
|
+
logger.error(f"Error finding Notepad process: {e}")
|
|
332
|
+
return None
|
|
333
|
+
|
|
334
|
+
def display_results(self, found_locations: List[Dict[str, Any]]):
|
|
335
|
+
"""Display the memory search results in a formatted way"""
|
|
336
|
+
print("\n" + "="*80)
|
|
337
|
+
print("🎯 MEMORY SEARCH RESULTS")
|
|
338
|
+
print("="*80)
|
|
339
|
+
|
|
340
|
+
if not found_locations:
|
|
341
|
+
print("❌ No text found in Notepad memory")
|
|
342
|
+
print("This could be due to:")
|
|
343
|
+
print(" • Text might be stored in encrypted/compressed form")
|
|
344
|
+
print(" • Memory regions might not be accessible")
|
|
345
|
+
print(" • Text might be in graphics buffer rather than text buffer")
|
|
346
|
+
return
|
|
347
|
+
|
|
348
|
+
print(f"✅ Found {len(found_locations)} text occurrences in memory")
|
|
349
|
+
print()
|
|
350
|
+
|
|
351
|
+
# Group by search term
|
|
352
|
+
by_search_term = {}
|
|
353
|
+
for location in found_locations:
|
|
354
|
+
term = location['search_term']
|
|
355
|
+
if term not in by_search_term:
|
|
356
|
+
by_search_term[term] = []
|
|
357
|
+
by_search_term[term].append(location)
|
|
358
|
+
|
|
359
|
+
for search_term, locations in by_search_term.items():
|
|
360
|
+
print(f"🔍 Search Term: '{search_term}' - {len(locations)} matches")
|
|
361
|
+
print("-" * 60)
|
|
362
|
+
|
|
363
|
+
for i, loc in enumerate(locations[:5], 1): # Show first 5 matches per term
|
|
364
|
+
print(f" Match #{i}:")
|
|
365
|
+
print(f" 📍 Address: {loc['address_hex']} (decimal: {loc['address']})")
|
|
366
|
+
print(f" 📝 Encoding: {loc['encoding']}")
|
|
367
|
+
print(f" 📄 Content: '{loc['content']}'")
|
|
368
|
+
print(f" 🔍 Context: '{loc['context'][:100]}{'...' if len(loc['context']) > 100 else ''}'")
|
|
369
|
+
print(f" 📊 Size: {loc['size']} bytes")
|
|
370
|
+
print(f" 🔢 Hex Data: {loc['hex_data']}")
|
|
371
|
+
print()
|
|
372
|
+
|
|
373
|
+
if len(locations) > 5:
|
|
374
|
+
print(f" ... and {len(locations) - 5} more matches")
|
|
375
|
+
print()
|
|
376
|
+
|
|
377
|
+
def run_complete_demo(self):
|
|
378
|
+
"""Run the complete Notepad automation demo"""
|
|
379
|
+
print("🤖 MCP Cheat Engine Server + PyAutoGUI Notepad Demo")
|
|
380
|
+
print("="*60)
|
|
381
|
+
print("This demo will:")
|
|
382
|
+
print("1. 🚀 Launch Notepad using PyAutoGUI")
|
|
383
|
+
print("2. 📝 Send 'Hello World' text using PyAutoGUI")
|
|
384
|
+
print("3. 🔍 Find the text in Notepad's memory using MCP")
|
|
385
|
+
print("4. 📊 Display memory addresses and content")
|
|
386
|
+
print()
|
|
387
|
+
|
|
388
|
+
# Step 1: Initialize systems
|
|
389
|
+
print("🔧 Initializing systems...")
|
|
390
|
+
if not self.initialize_systems():
|
|
391
|
+
print("❌ System initialization failed!")
|
|
392
|
+
return False
|
|
393
|
+
|
|
394
|
+
# Step 2: Launch Notepad
|
|
395
|
+
print("\n🚀 Launching Notepad...")
|
|
396
|
+
if not self.launch_notepad():
|
|
397
|
+
print("❌ Failed to launch Notepad!")
|
|
398
|
+
return False
|
|
399
|
+
|
|
400
|
+
# Step 3: Send text
|
|
401
|
+
print("\n📝 Sending text to Notepad...")
|
|
402
|
+
if not self.send_text_to_notepad():
|
|
403
|
+
print("❌ Failed to send text to Notepad!")
|
|
404
|
+
return False
|
|
405
|
+
|
|
406
|
+
# Step 4: Search memory
|
|
407
|
+
print("\n🔍 Searching for text in memory...")
|
|
408
|
+
found_locations = self.find_text_in_memory()
|
|
409
|
+
|
|
410
|
+
# Step 5: Display results
|
|
411
|
+
self.display_results(found_locations)
|
|
412
|
+
|
|
413
|
+
# Step 6: Additional PyAutoGUI demonstration
|
|
414
|
+
print("\n🎮 Additional PyAutoGUI Features Demo:")
|
|
415
|
+
self._demonstrate_additional_features()
|
|
416
|
+
|
|
417
|
+
print("\n✅ Demo completed successfully!")
|
|
418
|
+
return True
|
|
419
|
+
|
|
420
|
+
def _demonstrate_additional_features(self):
|
|
421
|
+
"""Demonstrate additional PyAutoGUI features"""
|
|
422
|
+
try:
|
|
423
|
+
# Get current mouse position
|
|
424
|
+
mouse_pos = self.pyautogui_controller.get_mouse_position()
|
|
425
|
+
if mouse_pos.success:
|
|
426
|
+
print(f"🖱️ Current mouse position: {mouse_pos.data}")
|
|
427
|
+
|
|
428
|
+
# Get screen information
|
|
429
|
+
screen_info = self.pyautogui_controller.get_screen_info()
|
|
430
|
+
if screen_info.success:
|
|
431
|
+
print(f"🖥️ Screen resolution: {screen_info.data['width']}x{screen_info.data['height']}")
|
|
432
|
+
|
|
433
|
+
# Take a final screenshot
|
|
434
|
+
screenshot = self.pyautogui_controller.take_screenshot()
|
|
435
|
+
if screenshot.success and 'file_path' in screenshot.data:
|
|
436
|
+
print(f"📷 Final screenshot saved: {screenshot.data['file_path']}")
|
|
437
|
+
|
|
438
|
+
except Exception as e:
|
|
439
|
+
logger.error(f"Additional features demo error: {e}")
|
|
440
|
+
|
|
441
|
+
def main():
|
|
442
|
+
"""Main entry point"""
|
|
443
|
+
demo = NotepadAutomationDemo()
|
|
444
|
+
|
|
445
|
+
try:
|
|
446
|
+
success = demo.run_complete_demo()
|
|
447
|
+
if success:
|
|
448
|
+
print("\n🎉 All systems working perfectly!")
|
|
449
|
+
print("🔗 PyAutoGUI + MCP Cheat Engine Server integration is complete!")
|
|
450
|
+
else:
|
|
451
|
+
print("\n⚠️ Demo completed with some issues")
|
|
452
|
+
|
|
453
|
+
except KeyboardInterrupt:
|
|
454
|
+
print("\n🛑 Demo interrupted by user")
|
|
455
|
+
except Exception as e:
|
|
456
|
+
print(f"\n💥 Demo failed with error: {e}")
|
|
457
|
+
logger.exception("Demo exception details:")
|
|
458
|
+
|
|
459
|
+
if __name__ == "__main__":
|
|
460
|
+
main()
|