first commit
This commit is contained in:
262
wow.md
Normal file
262
wow.md
Normal file
@@ -0,0 +1,262 @@
|
||||
import sys
|
||||
from PyQt6.QtWidgets import *
|
||||
from PyQt6.QtCore import QThread, pyqtSignal, Qt
|
||||
from PyQt6.QtGui import QIcon
|
||||
import win32gui, win32api, win32con
|
||||
import time, random, json, os
|
||||
|
||||
|
||||
class KeyConfigWidget(QWidget):
|
||||
"""单个按键配置组件"""
|
||||
|
||||
def __init__(self, key_name, default_config):
|
||||
super().__init__()
|
||||
self.key_name = key_name
|
||||
self.config = default_config or {'enabled': False, 'interval': 10, 'jitter': 2}
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
layout = QHBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
# 启用复选框
|
||||
self.checkbox = QCheckBox(f"按键 [{self.key_name}]")
|
||||
self.checkbox.setChecked(self.config['enabled'])
|
||||
layout.addWidget(self.checkbox)
|
||||
|
||||
# 间隔
|
||||
layout.addWidget(QLabel("间隔:"))
|
||||
self.interval_spin = QSpinBox()
|
||||
self.interval_spin.setRange(1, 60)
|
||||
self.interval_spin.setValue(self.config['interval'])
|
||||
layout.addWidget(self.interval_spin)
|
||||
layout.addWidget(QLabel("秒"))
|
||||
|
||||
# 随机延迟
|
||||
layout.addWidget(QLabel("随机:"))
|
||||
self.jitter_spin = QSpinBox()
|
||||
self.jitter_spin.setRange(0, 10)
|
||||
self.jitter_spin.setValue(self.config['jitter'])
|
||||
layout.addWidget(self.jitter_spin)
|
||||
layout.addWidget(QLabel("秒"))
|
||||
|
||||
layout.addStretch()
|
||||
|
||||
# 连接信号
|
||||
self.checkbox.toggled.connect(self.on_toggle)
|
||||
self.on_toggle()
|
||||
|
||||
def on_toggle(self):
|
||||
enabled = self.checkbox.isChecked()
|
||||
self.interval_spin.setEnabled(enabled)
|
||||
self.jitter_spin.setEnabled(enabled)
|
||||
|
||||
def get_config(self):
|
||||
return {
|
||||
'enabled': self.checkbox.isChecked(),
|
||||
'interval': self.interval_spin.value(),
|
||||
'jitter': self.jitter_spin.value()
|
||||
}
|
||||
|
||||
|
||||
class KeyWorker(QThread):
|
||||
"""按键工作线程"""
|
||||
log_signal = pyqtSignal(str)
|
||||
|
||||
def __init__(self, hwnd, key_name, config):
|
||||
super().__init__()
|
||||
self.hwnd = hwnd
|
||||
self.key_name = key_name
|
||||
self.config = config
|
||||
self.running = True
|
||||
|
||||
def run(self):
|
||||
while self.running:
|
||||
if self.config['enabled']:
|
||||
self.press_key()
|
||||
|
||||
# 随机间隔
|
||||
sleep_time = self.config['interval'] + random.uniform(-self.config['jitter'], self.config['jitter'])
|
||||
sleep_time = max(1, sleep_time)
|
||||
|
||||
for _ in range(int(sleep_time * 2)):
|
||||
if not self.running:
|
||||
break
|
||||
time.sleep(0.5)
|
||||
|
||||
def press_key(self):
|
||||
"""发送按键"""
|
||||
if not self.hwnd:
|
||||
return
|
||||
|
||||
key_map = {
|
||||
'空格(跳跃)': win32con.VK_SPACE,
|
||||
'1': 0x31, '2': 0x32, '3': 0x33, '4': 0x34, '5': 0x35
|
||||
}
|
||||
|
||||
vk = key_map.get(self.key_name)
|
||||
if vk:
|
||||
try:
|
||||
win32api.PostMessage(self.hwnd, win32con.WM_KEYDOWN, vk, 0)
|
||||
time.sleep(random.uniform(0.05, 0.15))
|
||||
win32api.PostMessage(self.hwnd, win32con.WM_KEYUP, vk, 0)
|
||||
key_type = "跳跃" if self.key_name == '空格(跳跃)' else f"技能 {self.key_name}"
|
||||
self.log_signal.emit(f"➡️ 执行 {key_type}")
|
||||
except Exception as e:
|
||||
self.log_signal.emit(f"❌ 按键 {self.key_name} 失败: {e}")
|
||||
|
||||
|
||||
class WoWMultiKeyGUI(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.config_file = "wow_multikey_qt.json"
|
||||
self.config = self.load_config()
|
||||
self.workers = {}
|
||||
self.hwnd = None
|
||||
|
||||
self.init_ui()
|
||||
self.find_wow_window()
|
||||
|
||||
def init_ui(self):
|
||||
self.setWindowTitle("WoW多键控制器")
|
||||
self.setGeometry(100, 100, 700, 550)
|
||||
|
||||
central = QWidget()
|
||||
self.setCentralWidget(central)
|
||||
layout = QVBoxLayout(central)
|
||||
|
||||
# 窗口状态
|
||||
self.window_label = QLabel("正在查找窗口...")
|
||||
layout.addWidget(self.window_label)
|
||||
|
||||
self.refresh_btn = QPushButton("刷新窗口")
|
||||
self.refresh_btn.clicked.connect(self.find_wow_window)
|
||||
layout.addWidget(self.refresh_btn)
|
||||
|
||||
# 按键配置
|
||||
self.key_widgets = {}
|
||||
keys = ['空格(跳跃)', '1', '2', '3', '4', '5']
|
||||
|
||||
scroll = QScrollArea()
|
||||
scroll.setWidgetResizable(True)
|
||||
scroll_widget = QWidget()
|
||||
scroll_layout = QVBoxLayout(scroll_widget)
|
||||
|
||||
for key in keys:
|
||||
widget = KeyConfigWidget(key, self.config.get(key))
|
||||
scroll_layout.addWidget(widget)
|
||||
self.key_widgets[key] = widget
|
||||
|
||||
scroll_layout.addStretch()
|
||||
scroll.setWidget(scroll_widget)
|
||||
layout.addWidget(scroll)
|
||||
|
||||
# 按钮
|
||||
btn_layout = QHBoxLayout()
|
||||
self.start_btn = QPushButton("🚀 启动")
|
||||
self.start_btn.clicked.connect(self.start_all)
|
||||
self.stop_btn = QPushButton("⏹ 停止")
|
||||
self.stop_btn.clicked.connect(self.stop_all)
|
||||
self.stop_btn.setEnabled(False)
|
||||
|
||||
btn_layout.addWidget(self.start_btn)
|
||||
btn_layout.addWidget(self.stop_btn)
|
||||
btn_layout.addStretch()
|
||||
layout.addLayout(btn_layout)
|
||||
|
||||
# 日志
|
||||
self.log_text = QTextEdit()
|
||||
self.log_text.setReadOnly(True)
|
||||
self.log_text.setMaximumHeight(150)
|
||||
layout.addWidget(self.log_text)
|
||||
|
||||
# 状态栏
|
||||
self.status_bar = self.statusBar()
|
||||
self.status_bar.showMessage("就绪")
|
||||
|
||||
def load_config(self):
|
||||
if os.path.exists(self.config_file):
|
||||
try:
|
||||
with open(self.config_file, "r") as f:
|
||||
return json.load(f)
|
||||
except:
|
||||
pass
|
||||
return {}
|
||||
|
||||
def save_config(self):
|
||||
config = {key: widget.get_config() for key, widget in self.key_widgets.items()}
|
||||
with open(self.config_file, "w") as f:
|
||||
json.dump(config, f, indent=2)
|
||||
|
||||
def find_wow_window(self):
|
||||
titles = ["魔兽世界", "World of Warcraft"]
|
||||
for title in titles:
|
||||
self.hwnd = win32gui.FindWindow(None, title)
|
||||
if self.hwnd:
|
||||
self.window_label.setText(f"✅ 已找到: {title}")
|
||||
self.log(f"成功绑定窗口: {title}")
|
||||
return
|
||||
self.window_label.setText("❌ 未找到游戏窗口")
|
||||
self.hwnd = None
|
||||
|
||||
def log(self, message):
|
||||
self.log_text.append(f"[{time.strftime('%H:%M:%S')}] {message}")
|
||||
|
||||
def start_all(self):
|
||||
if not self.hwnd:
|
||||
QMessageBox.warning(self, "警告", "未找到游戏窗口!")
|
||||
return
|
||||
|
||||
any_enabled = any(w.get_config()['enabled'] for w in self.key_widgets.values())
|
||||
if not any_enabled:
|
||||
QMessageBox.warning(self, "警告", "请至少启用一个按键!")
|
||||
return
|
||||
|
||||
self.save_config()
|
||||
|
||||
# 启动工作线程
|
||||
for key_name, widget in self.key_widgets.items():
|
||||
config = widget.get_config()
|
||||
if config['enabled']:
|
||||
worker = KeyWorker(self.hwnd, key_name, config)
|
||||
worker.log_signal.connect(self.log)
|
||||
worker.start()
|
||||
self.workers[key_name] = worker
|
||||
|
||||
self.start_btn.setEnabled(False)
|
||||
self.stop_btn.setEnabled(True)
|
||||
self.status_bar.showMessage("🟢 运行中")
|
||||
self.log("🎮 自动按键已启动")
|
||||
|
||||
def stop_all(self):
|
||||
for worker in self.workers.values():
|
||||
worker.running = False
|
||||
worker.wait()
|
||||
|
||||
self.workers.clear()
|
||||
self.start_btn.setEnabled(True)
|
||||
self.stop_btn.setEnabled(False)
|
||||
self.status_bar.showMessage("⏹️ 已停止")
|
||||
self.log("🛑 所有按键已停止")
|
||||
|
||||
def closeEvent(self, event):
|
||||
if self.workers:
|
||||
reply = QMessageBox.question(self, "退出", "确认退出?")
|
||||
if reply == QMessageBox.StandardButton.Yes:
|
||||
self.stop_all()
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
else:
|
||||
event.accept()
|
||||
|
||||
|
||||
def main():
|
||||
app = QApplication(sys.argv)
|
||||
window = WoWMultiKeyGUI()
|
||||
window.show()
|
||||
sys.exit(app.exec())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user