From cd6acdea610785546d242d243d1cf85b1ceca490 Mon Sep 17 00:00:00 2001 From: youngkingdom <990708896@qq.com> Date: Wed, 25 Jun 2025 18:18:27 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20POE-AutoFlask=20?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增主程序文件 main.py - 添加项目图标和资源文件 - 实现自动喝药和自定义按键功能 - 添加异常处理和程序打包配置 - 编写项目 README 和依赖列表 --- .gitignore | 5 + POE-AutoFlask.spec | 39 +++++ README.md | 3 + icons/icon.ico | Bin 0 -> 19869 bytes icons/icon.png | Bin 0 -> 6101 bytes main.py | 409 +++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | Bin 0 -> 332 bytes 7 files changed, 456 insertions(+) create mode 100644 .gitignore create mode 100644 POE-AutoFlask.spec create mode 100644 README.md create mode 100644 icons/icon.ico create mode 100644 icons/icon.png create mode 100644 main.py create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8edb971 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +build +dist +.venv +PyQt-Fluent-Widgets +.idea diff --git a/POE-AutoFlask.spec b/POE-AutoFlask.spec new file mode 100644 index 0000000..a30eb47 --- /dev/null +++ b/POE-AutoFlask.spec @@ -0,0 +1,39 @@ +# -*- mode: python ; coding: utf-8 -*- + + +a = Analysis( + ['main.py'], + pathex=[], + binaries=[], + datas=[('icons/icon.png', 'icons')], + hiddenimports=[], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + noarchive=False, + optimize=0, +) +pyz = PYZ(a.pure) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.datas, + [], + name='POE-AutoFlask', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=False, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, + icon=['icons\\icon.ico'], +) diff --git a/README.md b/README.md new file mode 100644 index 0000000..29caeb3 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +pip install -r requirements.txt + +pyinstaller --name=POE-AutoFlask --onefile main.py --noconsole --add-data "icons/icon.png;icons" --icon=icons/icon.ico --clean \ No newline at end of file diff --git a/icons/icon.ico b/icons/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..18fbeebd89e9aecf8cf33b5674cad1be906df5d9 GIT binary patch literal 19869 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 VMzr&NR^|Wz002ovPDHLkV1laI{EGkp literal 0 HcmV?d00001 diff --git a/icons/icon.png b/icons/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..03543c1491f04b1beeae6b25a05d86055e78c5d2 GIT binary patch literal 6101 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 a8&Vg~-8iQS1y_A~07_X)sr-?3$bSH@aa(Qx literal 0 HcmV?d00001 diff --git a/main.py b/main.py new file mode 100644 index 0000000..82546c7 --- /dev/null +++ b/main.py @@ -0,0 +1,409 @@ +import os +import subprocess +import sys +import time +import traceback + +import keyboard +from PyQt5.QtCore import QThread, pyqtSignal, Qt +from PyQt5.QtGui import QKeySequence, QIcon, QIntValidator +from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout, QFormLayout, + QDialog, QMessageBox) +from qfluentwidgets import (ComboBox, LineEdit, CheckBox, PushButton, BodyLabel, StrongBodyLabel, + HeaderCardWidget) +from qfluentwidgets.common import setTheme, Theme + + +# 获取资源文件路径的函数 +def resource_path(relative_path): + """返回打包或开发环境下的资源路径""" + if hasattr(sys, '_MEIPASS'): + return os.path.join(sys._MEIPASS, relative_path) + return os.path.join(os.path.abspath("."), relative_path) + +# KeyListenerOne: 负责功能区1(按“`”键模拟勾选的按键) +class KeyListenerOne(QThread): + def __init__(self, keys_to_send, delay): + super().__init__() + self.running = True # 控制线程运行状态 + self.is_active = True # 由App类控制的全局激活状态 + self.keys_to_send = keys_to_send # 要模拟的按键列表 + self.delay = delay / 1000.0 # 按键之间的延迟(秒) + + def run(self): + # 此线程不再注册F2热键,F2由App类全局管理 + while self.running: + # 只有当全局激活状态为True且“`”键被按下时才执行 + if self.is_active and keyboard.is_pressed('`'): + # 模拟勾选的按键 + for key in self.keys_to_send: + keyboard.write(key) + time.sleep(self.delay) # 按键之间的延迟 + # 功能区1不再需要每轮循环延迟 + time.sleep(0.01) # 避免CPU占用过高 + + def set_active(self, state): + """设置功能区1的激活状态。""" + self.is_active = state + + def stop(self): + """停止线程运行。""" + self.running = False + + +# KeyListenerTwo: 负责功能区2(启停循环自动输入) +class KeyListenerTwo(QThread): + # 添加一个信号,用于在状态改变时通知主UI + status_changed = pyqtSignal(bool) + + def __init__(self, auto_keys, auto_delay, auto_loop_delay, auto_key_trigger): + super().__init__() + self.running = True # 控制线程运行状态 + self.is_active = True # 由App类控制的全局激活状态 + self.individual_auto_toggle = False # 功能区2独立的启停状态 + self.auto_keys = auto_keys # 自动输入的按键列表 + self.auto_delay = auto_delay / 1000.0 # 自动输入按键之间的延迟(秒) + self.auto_loop_delay = auto_loop_delay / 1000.0 # 每轮自动输入循环之间的延迟(秒) + self.auto_key_trigger = auto_key_trigger # 启停自动输入的触发按键 + + def run(self): + # 注册功能区2独立的触发按键 + if self.auto_key_trigger: + # 使用 try-except 避免重复注册热键时出错 + try: + keyboard.add_hotkey(self.auto_key_trigger, self.toggle_individual_auto_typing) + except Exception as e: + print(f"Failed to register hotkey {self.auto_key_trigger}: {e}") + + while self.running: + # 只有当全局激活状态为True且功能区2被独立触发时才执行 + if self.is_active and self.individual_auto_toggle: + # 执行自动输入 + for key in self.auto_keys: + keyboard.write(key) + time.sleep(self.auto_delay) # 自动输入按键之间的延迟 + time.sleep(self.auto_loop_delay) # 每轮自动输入循环后的延迟 + time.sleep(0.01) # 避免CPU占用过高 + + def set_active(self, state): + """设置功能区2的全局激活状态。""" + self.is_active = state + + def toggle_individual_auto_typing(self): + """切换功能区2的独立自动输入状态。""" + self.individual_auto_toggle = not self.individual_auto_toggle + # 发射信号,将新的状态(True为启动,False为停止)传递出去 + self.status_changed.emit(self.individual_auto_toggle) + + def stop(self): + """停止线程运行并取消注册功能区2的触发热键。""" + self.running = False + if self.auto_key_trigger: + try: + # 尝试解绑热键 + keyboard.remove_hotkey(self.auto_key_trigger) + except KeyError: + pass # 忽略热键不存在的错误 + + +# KeyCaptureDialog: 用于捕获用户按键的对话框 +class KeyCaptureDialog(QDialog): + def __init__(self, prompt, max_length=5): + super().__init__() + self.setWindowTitle(prompt) + self.setModal(True) + self.resize(300, 100) + self.keys = [] # 捕获到的按键列表 + self.max_length = max_length # 最大捕获按键数量 + self.label = BodyLabel("请依次按下按键(最多{}个),按 Enter 完成".format(max_length), self) + layout = QVBoxLayout() + layout.addWidget(self.label) + self.setLayout(layout) + self.start_listening() + + def start_listening(self): + self.show() + self.grabKeyboard() # 捕获键盘输入 + + def keyPressEvent(self, event): + key = event.key() + if key in (Qt.Key_Return, Qt.Key_Enter): + self.done(0) # 完成对话框 + return + + if len(self.keys) < self.max_length: + key_seq = event.text() # 获取按键字符 + if key_seq: + self.keys.append(key_seq) + self.keys = list(set(self.keys)) + self.label.setText("已捕获: " + ', '.join(self.keys)) + + def closeEvent(self, event): + self.releaseKeyboard() # 释放键盘捕获 + event.accept() + + +# TriggerCaptureDialog: 用于捕获触发按键的对话框 +class TriggerCaptureDialog(QDialog): + def __init__(self): + super().__init__() + self.setWindowTitle("设置启停按键") + self.setModal(True) + self.resize(300, 100) + self.key = '' + self.label = BodyLabel("请按下用于启停自动输入的按键组合(按 Enter 完成)...", self) + layout = QVBoxLayout() + layout.addWidget(self.label) + self.setLayout(layout) + + def keyPressEvent(self, event): + if event.key() in (Qt.Key_Return, Qt.Key_Enter): + self.done(0) # 完成对话框 + return + + key_seq_str = QKeySequence(event.modifiers() | event.key()).toString(QKeySequence.NativeText) + if key_seq_str and key_seq_str.lower() not in ('enter', 'return'): + self.key = key_seq_str.lower() + self.label.setText(f"已捕获: {self.key}") + + def closeEvent(self, event): + self.releaseKeyboard() # 释放键盘捕获 + event.accept() + + +# App: 主应用程序窗口 +class App(QWidget): + def __init__(self): + super().__init__() + self.setWindowTitle("POE-AutoFlask") + flags = Qt.Window | Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowCloseButtonHint + self.setWindowFlags(flags) + self.setFixedSize(391,543) + self.setWindowIcon(QIcon(resource_path("icons/icon.png"))) + + # UI 元素初始化 + self._global_active = True + self.label = StrongBodyLabel("状态:监听中 (F2 切换)", self) + self.button = PushButton("停止监听 (F2) 切换", self) + self.button.setEnabled(True) + self.button.clicked.connect(self._toggle_global_active) + + # 功能区1的复选框布局 + self.checkbox_layout = QHBoxLayout() + self.checkboxes = [] + self.key_labels = ['1', '2', '3', '4', '5'] + for key in self.key_labels: + checkbox = CheckBox(key) + checkbox.setChecked(True) + self.checkbox_layout.addWidget(checkbox) + self.checkboxes.append(checkbox) + + # 功能区1的按键间延迟设置 + self.delay_combobox = ComboBox() + self.delay_options = ["50 ms", "100 ms", "200 ms", "300 ms", "500 ms", "1000 ms", "2000 ms", "5000 ms"] + self.delay_combobox.addItems(self.delay_options) + self.delay_combobox.setCurrentText("50 ms") + self.delay_combobox.setToolTip("按键之间的延迟") + + # 功能区1的布局 (移除每轮循环延迟) + feature1_text = BodyLabel("按键间延迟(ms):", self) + feature1_form = QHBoxLayout() + feature1_form.addWidget(feature1_text,1) + feature1_form.addWidget(self.delay_combobox,9) + + + feature1_group = HeaderCardWidget() + feature1_group.setBorderRadius(8) + feature1_group.setTitle("按`键自动喝药,可勾选取消") + feature1_layout = QVBoxLayout() + feature1_layout.addLayout(self.checkbox_layout) + feature1_layout.addLayout(feature1_form) + feature1_group.viewLayout.addLayout(feature1_layout) + + # 功能区2的初始化 + self.auto_keys = [] + self.auto_key_trigger = '' + + self.auto_delay_combobox = ComboBox() + self.auto_delay_combobox.addItems(self.delay_options) + self.auto_delay_combobox.setCurrentText("50 ms") + self.auto_delay_combobox.setToolTip("自动输入按键之间的延迟") + + # --- 修改:将每轮循环延迟的 QComboBox 改为 QLineEdit --- + self.auto_loop_delay_input = LineEdit() # 默认1000ms + self.auto_loop_delay_input.setText("1000") + self.auto_loop_delay_input.setValidator(QIntValidator(0, 999999)) # 限制只能输入0到999999的整数 + self.auto_loop_delay_input.setToolTip("每轮自动输入循环之间的延迟 (ms)") + + self.auto_keys_button = PushButton("设置自动输入按键") + self.auto_trigger_button = PushButton("设置启停按键") + + self.auto_keys_button.clicked.connect(self.set_auto_keys) + self.auto_trigger_button.clicked.connect(self.set_auto_trigger) + + self.auto_keys_display = BodyLabel("当前自动输入按键: 无") + self.auto_trigger_display = BodyLabel("当前启停按键: 无") + + self.feature2_widgets_to_disable = [ + self.auto_delay_combobox, + self.auto_loop_delay_input, + self.auto_keys_button, + self.auto_trigger_button, + ] + + # 功能区2的布局 + feature2_form = QFormLayout() + feature2_hLayout = QHBoxLayout() + feature2_hLayout.addWidget(BodyLabel("按键间延迟(ms):", self),1) + feature2_hLayout.addWidget(self.auto_delay_combobox,9) + feature2_form.addRow(feature2_hLayout) + feature2_hLayout2 = QHBoxLayout() + feature2_hLayout2.addWidget(BodyLabel("每轮循环延迟(ms):", self),1) + feature2_hLayout2.addWidget(self.auto_loop_delay_input,9) + feature2_form.addRow(feature2_hLayout2) + feature2_form.addRow(self.auto_keys_button) + feature2_form.addRow(self.auto_keys_display) + feature2_form.addRow(self.auto_trigger_button) + feature2_form.addRow(self.auto_trigger_display) + + feature2_group = HeaderCardWidget() + feature2_group.setBorderRadius(8) + feature2_group.setTitle("设置自定义启停,循环自动输入自定义") + # feature2_group = QGroupBox("功能区2:启停循环自动输入") + feature2_group.viewLayout.addLayout(feature2_form) + self.feature2_group = feature2_group # 保存对group的引用 + + # 主布局 + layout = QVBoxLayout() + layout.addWidget(self.label) + layout.addWidget(feature1_group) + layout.addWidget(feature2_group) + layout.addWidget(self.button) + self.setLayout(layout) + + # 初始化两个独立的监听线程 + self.listener_one = KeyListenerOne(self.get_enabled_keys(), + int(self.delay_combobox.currentText().replace(" ms", ""))) + self.listener_one.start() + + loop_delay_val = int(self.auto_loop_delay_input.text()) if self.auto_loop_delay_input.text() else 1000 + self.listener_two = KeyListenerTwo(self.auto_keys, + int(self.auto_delay_combobox.currentText().replace(" ms", "")), + loop_delay_val, + self.auto_key_trigger) + self.listener_two.status_changed.connect(self._update_feature2_ui_state) + self.listener_two.start() + + keyboard.add_hotkey('f2', self._toggle_global_active) + self._update_status_label() # 初始化状态标签 + + for cb in self.checkboxes: + cb.stateChanged.connect(self.update_keys) + self.delay_combobox.currentTextChanged.connect(self.update_delay) + self.auto_delay_combobox.currentTextChanged.connect(self.update_auto_delay) + self.auto_loop_delay_input.textChanged.connect(self.update_auto_loop_delay) + + def _toggle_global_active(self): + self._global_active = not self._global_active + self.listener_one.set_active(self._global_active) + self.listener_two.set_active(self._global_active) + self._update_status_label() + + def _update_status_label(self): + status_text = "状态:监听中 (F2 切换)" if self._global_active else "状态:已暂停监听 (F2 切换)" + button_text = "暂停所有功能 (F2 切换)" if self._global_active else "启动所有功能 (F2 切换)" + + self.label.setText(status_text) + self.button.setText(button_text) + + def _update_feature2_ui_state(self, is_running): + for widget in self.feature2_widgets_to_disable: + widget.setEnabled(not is_running) + + def get_enabled_keys(self): + return [cb.text() for cb in self.checkboxes if cb.isChecked()] + + def update_keys(self): + self.listener_one.keys_to_send = self.get_enabled_keys() + + def update_delay(self): + self.listener_one.delay = int(self.delay_combobox.currentText().replace(" ms", "")) / 1000.0 + + def update_auto_delay(self): + self.listener_two.auto_delay = int(self.auto_delay_combobox.currentText().replace(" ms", "")) / 1000.0 + + def update_auto_loop_delay(self): + try: + delay_ms = int(self.auto_loop_delay_input.text()) + self.listener_two.auto_loop_delay = delay_ms / 1000.0 + except (ValueError, AttributeError): + self.listener_two.auto_loop_delay = 1.0 + + def set_auto_keys(self): + dialog = KeyCaptureDialog("设置自动输入按键") + dialog.exec_() + self.auto_keys = dialog.keys + self.listener_two.auto_keys = self.auto_keys # 更新功能区2监听线程的按键 + self.auto_keys_display.setText("当前自动输入按键: " + ', '.join(self.auto_keys) if self.auto_keys else "无") + + def set_auto_trigger(self): + dialog = TriggerCaptureDialog() + dialog.exec_() + new_trigger_key = dialog.key + + if new_trigger_key and new_trigger_key != self.auto_key_trigger: + self.auto_key_trigger = new_trigger_key + self.auto_trigger_display.setText( + "当前启停按键: " + self.auto_key_trigger if self.auto_key_trigger else "无") + + self.listener_two.stop() + self.listener_two.wait() + + loop_delay_val = int(self.auto_loop_delay_input.text()) if self.auto_loop_delay_input.text() else 1000 + self.listener_two = KeyListenerTwo(self.auto_keys, + int(self.auto_delay_combobox.currentText().replace(" ms", "")), + loop_delay_val, + self.auto_key_trigger) + self.listener_two.status_changed.connect(self._update_feature2_ui_state) + self.listener_two.start() + elif not new_trigger_key: + self.auto_trigger_display.setText("当前启停按键: 无") + + def closeEvent(self, event): + self.listener_one.stop() + self.listener_one.wait() # 等待线程结束 + self.listener_two.stop() + self.listener_two.wait() # 等待线程结束 + # 在程序退出时全局解绑所有热键,确保清理 + keyboard.unhook_all() + event.accept() + + +# show_exception_dialog: 全局异常处理函数 +def show_exception_dialog(exc_type, exc_value, exc_traceback): + error_msg = ''.join(traceback.format_exception(exc_type, exc_value, exc_traceback)) + msg_box = QMessageBox() + msg_box.setIcon(QMessageBox.Critical) + msg_box.setWindowTitle("程序异常") + msg_box.setText("程序发生异常:\n" + str(exc_value)) + msg_box.setDetailedText(error_msg) + msg_box.setStandardButtons(QMessageBox.Retry | QMessageBox.Close) + result = msg_box.exec_() + if result == QMessageBox.Retry: + python = sys.executable + args = sys.argv[:] + args.insert(0, python) + sys.exit(subprocess.call(args)) + else: + sys.exit(1) + + +# 主程序入口 +if __name__ == '__main__': + sys.excepthook = show_exception_dialog # 设置全局异常处理 + + app = QApplication(sys.argv) + setTheme(Theme.LIGHT) # 设置主题为自动模式 + window = App() + window.show() + sys.exit(app.exec_()) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..a019b184544428dd008e7239a186643e14598850 GIT binary patch literal 332 zcmZXQK?{OF6ols-^ivFXm!&RUJLkz`R4XBwiWcIZujV~PXk&Q`%glUl^z#llqr)8m z1)iKM?>$e74R)LqYpkdj7;!;a56C63I?ezvhMp!_sTZy!%T_yLe07;Y4PMcJ67lhtQ_~(DEAx M-REG{