diff --git a/Event/__init__.py b/Event/__init__.py index 9f5cd01..4ed8d78 100644 --- a/Event/__init__.py +++ b/Event/__init__.py @@ -5,7 +5,7 @@ import Event.WindowsEvents as _Event event_cls = _Event.WindowsEvent flag_multiplemonitor = _Event.numofmonitors > 1 -elif system() in ['Linux', 'Darwin']: +elif system() in ['Linux', 'Darwin', 'FreeBSD']: import Event.UniversalEvents as _Event event_cls = _Event.UniversalEvent flag_multiplemonitor = False diff --git a/README.md b/README.md index 168ab5f..acd5731 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,8 @@ chmod -R 770 ~/.qt_material 如果您是开发爱好者,并对本项目感兴趣,欢迎参与项目的共同建设,您可以通过本项目的[**dev**](https://github.com/taojy123/KeymouseGo/tree/dev)分支查看目前的进度,并且可以向本项目的[**dev**](https://github.com/taojy123/KeymouseGo/tree/dev)分支提交 Pull request 来贡献代码。 +注:如果您需要修改应用界面,请修改UIView.ui文件并通过pyuic生成UIVIew.py,控件的初始化等操作请添加到UIFunc.py内。 + 感谢 JetBrains 免费提供开发工具 diff --git a/README_en-US.md b/README_en-US.md index ec85304..d813289 100644 --- a/README_en-US.md +++ b/README_en-US.md @@ -177,6 +177,9 @@ My Email: taojy123@163.com If you are a developer and interested in this project, you can check the progress in branch [**dev**](https://github.com/taojy123/KeymouseGo/tree/dev). and you are welcomed to participating by opening pull request to branch [**dev**](https://github.com/taojy123/KeymouseGo/tree/dev). +注:如果您需要修改应用界面,请修改UIView.ui文件并通过pyuic生成UIVIew.py,控件的初始化等操作请添加到UIFunc.py内。 +Note: If you want to modify the application UI, please modify `UIView.ui` and generate `UIView.py` via `pyuic`. Then add the widget initialization operation in `UIFunc.py`. + Thanks to free develop tool provided by JetBrains diff --git a/Recorder/__init__.py b/Recorder/__init__.py index 7d47501..2fe2f02 100644 --- a/Recorder/__init__.py +++ b/Recorder/__init__.py @@ -5,7 +5,7 @@ if system() == 'Windows': import Recorder.WindowsRecorder as _Recorder _Recorder.globalv.key_combination_trigger = ['lwin', 'lshift', 'rshift', 'lcontrol', 'rcontrol', 'lmenu', 'rmenu'] -elif system() in ['Linux', 'Darwin']: +elif system() in ['Linux', 'Darwin', 'FreeBSD']: import Recorder.UniversalRecorder as _Recorder _Recorder.globalv.key_combination_trigger = ['win', 'shiftright', 'shift', 'ctrlright', 'ctrl', 'altright', 'alt'] else: diff --git a/UIFunc.py b/UIFunc.py index b146a2c..26d8363 100644 --- a/UIFunc.py +++ b/UIFunc.py @@ -114,11 +114,13 @@ def __init__(self, app): self.choice_theme.addItems(list_themes()) # self.choice_theme.addItems(PluginManager.resources_paths) self.stimes.setValue(int(self.config.value("Config/LoopTimes"))) + self.interval.setValue(int(self.config.value("Config/Interval"))) self.mouse_move_interval_ms.setValue(int(self.config.value("Config/Precision"))) self.choice_theme.setCurrentText(self.config.value("Config/Theme")) if self.config.value('Config/Script') is not None and self.config.value('Config/Script') in self.scripts: self.choice_script.setCurrentText(self.config.value('Config/Script')) self.stimes.valueChanged.connect(self.onconfigchange) + self.interval.valueChanged.connect(self.onconfigchange) self.mouse_move_interval_ms.valueChanged.connect(self.onconfigchange) self.mouse_move_interval_ms.valueChanged.connect(Recorder.set_interval) self.choice_theme.currentTextChanged.connect(self.onchangetheme) @@ -126,7 +128,56 @@ def __init__(self, app): self.hotkey_stop.setText(self.config.value("Config/StopHotKey")) self.hotkey_start.setText(self.config.value("Config/StartHotKey")) self.hotkey_record.setText(self.config.value("Config/RecordHotKey")) - + start_time_config = self.config.value("Config/StartTime", "不定时") + if start_time_config == "不定时": + self.checkbox_no_timing_start.setChecked(True) + else: + hour, minute, _ = start_time_config.split(":") + self.combo_start_hour.setCurrentText(hour) + self.combo_start_min.setCurrentText(minute) + self.combo_start_hour.currentTextChanged.connect(self.onconfigchange) + self.combo_start_min.currentTextChanged.connect(self.onconfigchange) + stop_time_config = self.config.value("Config/StopTime", "不定时") + if stop_time_config == "不定时": + self.checkbox_no_timing_stop.setChecked(True) + else: + hour, minute, _ = stop_time_config.split(":") + self.combo_stop_hour.setCurrentText(hour) + self.combo_stop_min.setCurrentText(minute) + self.combo_stop_hour.currentTextChanged.connect(self.onconfigchange) + self.combo_stop_min.currentTextChanged.connect(self.onconfigchange) + self.timer = QTimer(self) + self.timer.timeout.connect(self.check_time) + self.timer.start(1000) # 每秒检查一次时间 + self.last_start_triggered = None # 记录最后一次启动触发时间(格式:"HH:MM") + self.last_stop_triggered = None # 记录最后一次停止触发时间 + + self.checkbox_no_timing_start.stateChanged.connect( + lambda: self._toggle_time_controls( + self.checkbox_no_timing_start, + self.combo_start_hour, + self.combo_start_min + ) + ) + self.checkbox_no_timing_stop.stateChanged.connect( + lambda: self._toggle_time_controls( + self.checkbox_no_timing_stop, + self.combo_stop_hour, + self.combo_stop_min + ) + ) + + # 初始化时根据配置设置控件状态 + self._toggle_time_controls( + self.checkbox_no_timing_start, + self.combo_start_hour, + self.combo_start_min + ) + self._toggle_time_controls( + self.checkbox_no_timing_stop, + self.combo_stop_hour, + self.combo_stop_min + ) self.onchangetheme() @@ -282,12 +333,23 @@ def eventFilter(self, watched, event: QEvent): def onconfigchange(self): self.config.setValue("Config/LoopTimes", self.stimes.value()) + self.config.setValue("Config/Interval", self.interval.value()) self.config.setValue("Config/Precision", self.mouse_move_interval_ms.value()) self.config.setValue("Config/Theme", self.choice_theme.currentText()) self.config.setValue("Config/Script", self.choice_script.currentText()) self.config.setValue("Config/StartHotKey", self.hotkey_start.text()) self.config.setValue("Config/StopHotKey", self.hotkey_stop.text()) self.config.setValue("Config/RecordHotKey", self.hotkey_record.text()) + if self.checkbox_no_timing_start.isChecked(): + start_time = "不定时" + else: + start_time = f"{self.combo_start_hour.currentText()}:{self.combo_start_min.currentText()}:00" + self.config.setValue("Config/StartTime", start_time) + if self.checkbox_no_timing_stop.isChecked(): + stop_time = "不定时" + else: + stop_time = f"{self.combo_stop_hour.currentText()}:{self.combo_stop_min.currentText()}:00" + self.config.setValue("Config/StopTime", stop_time) def onchangelang(self): global scripts_map @@ -344,6 +406,7 @@ def loadconfig(self): 'StopHotKey=f9\n' 'RecordHotKey=f10\n' 'LoopTimes=1\n' + 'Interval=0\n' 'Precision=200\n' 'Language=zh-cn\n' 'Theme=Default\n') @@ -483,3 +546,34 @@ def handle_runscript_status(self, succeed): @Slot(tuple) def cursor_pos_change(self, pos): self.label_cursor_pos.setText(f'Cursor pos: {pos}') + + def check_time(self): + current_time = datetime.datetime.now().strftime("%H:%M") # 仅比较小时和分钟 + if self.checkbox_no_timing_start.isChecked(): + start_time = "不定时" + else: + start_time = f"{self.combo_start_hour.currentText()}:{self.combo_start_min.currentText()}" + + if self.checkbox_no_timing_stop.isChecked(): + stop_time = "不定时" + else: + stop_time = f"{self.combo_stop_hour.currentText()}:{self.combo_stop_min.currentText()}" + + if start_time != "不定时" and current_time == start_time and self.state == State.IDLE and self.last_start_triggered != current_time: + self.OnBtrunButton() + self.last_start_triggered = current_time + + if stop_time != "不定时" and current_time == stop_time and (self.state == State.RUNNING or self.state == State.PAUSE_RUNNING) and self.last_stop_triggered != current_time: + self.tnumrd.setText('broken') + if self.runthread: + self.runthread.resume() + self.update_state(State.IDLE) + self.last_stop_triggered = current_time + + def _toggle_time_controls(self, checkbox, combo_hour, combo_min): + if checkbox.isChecked(): + combo_hour.setEnabled(False) + combo_min.setEnabled(False) + else: + combo_hour.setEnabled(True) + combo_min.setEnabled(True) diff --git a/UIView.py b/UIView.py index 780497f..4c1f2ac 100644 --- a/UIView.py +++ b/UIView.py @@ -19,7 +19,7 @@ QGroupBox, QHBoxLayout, QLabel, QLayout, QMainWindow, QMenuBar, QPushButton, QSizePolicy, QSlider, QSpinBox, QStatusBar, QTextEdit, - QVBoxLayout, QWidget) + QVBoxLayout, QWidget, QCheckBox) import assets_rc class Ui_UIView(object): @@ -167,23 +167,6 @@ def setupUi(self, UIView): self.gridLayout_4 = QGridLayout(self.groupBox_2) self.gridLayout_4.setObjectName(u"gridLayout_4") self.gridLayout_4.setContentsMargins(0, 0, 0, 0) - self.choice_theme = QComboBox(self.groupBox_2) - self.choice_theme.setObjectName(u"choice_theme") - sizePolicy.setHeightForWidth(self.choice_theme.sizePolicy().hasHeightForWidth()) - self.choice_theme.setSizePolicy(sizePolicy) - - self.gridLayout_4.addWidget(self.choice_theme, 3, 1, 1, 1) - - self.label_execute_interval = QLabel(self.groupBox_2) - self.label_execute_interval.setObjectName(u"label_execute_interval") - - self.gridLayout_4.addWidget(self.label_execute_interval, 2, 0, 1, 1) - - self.label_theme = QLabel(self.groupBox_2) - self.label_theme.setObjectName(u"label_theme") - - self.gridLayout_4.addWidget(self.label_theme, 3, 0, 1, 1) - self.mouse_move_interval_ms = QSpinBox(self.groupBox_2) self.mouse_move_interval_ms.setObjectName(u"mouse_move_interval_ms") sizePolicy.setHeightForWidth(self.mouse_move_interval_ms.sizePolicy().hasHeightForWidth()) @@ -192,7 +175,7 @@ def setupUi(self, UIView): self.mouse_move_interval_ms.setMaximum(1000) self.mouse_move_interval_ms.setValue(100) - self.gridLayout_4.addWidget(self.mouse_move_interval_ms, 2, 1, 1, 1) + self.gridLayout_4.addWidget(self.mouse_move_interval_ms, 3, 1, 1, 1) self.gridLayout = QGridLayout() self.gridLayout.setObjectName(u"gridLayout") @@ -216,10 +199,15 @@ def setupUi(self, UIView): self.gridLayout_4.addLayout(self.gridLayout, 0, 1, 1, 1) - self.label_script = QLabel(self.groupBox_2) - self.label_script.setObjectName(u"label_script") + self.label_execute_interval = QLabel(self.groupBox_2) + self.label_execute_interval.setObjectName(u"label_execute_interval") - self.gridLayout_4.addWidget(self.label_script, 0, 0, 1, 1) + self.gridLayout_4.addWidget(self.label_execute_interval, 3, 0, 1, 1) + + self.label_theme = QLabel(self.groupBox_2) + self.label_theme.setObjectName(u"label_theme") + + self.gridLayout_4.addWidget(self.label_theme, 4, 0, 1, 1) self.label_run_times = QLabel(self.groupBox_2) self.label_run_times.setObjectName(u"label_run_times") @@ -235,15 +223,87 @@ def setupUi(self, UIView): self.gridLayout_4.addWidget(self.stimes, 1, 1, 1, 1) + self.choice_theme = QComboBox(self.groupBox_2) + self.choice_theme.setObjectName(u"choice_theme") + sizePolicy.setHeightForWidth(self.choice_theme.sizePolicy().hasHeightForWidth()) + self.choice_theme.setSizePolicy(sizePolicy) + + self.gridLayout_4.addWidget(self.choice_theme, 4, 1, 1, 1) + + self.label_script = QLabel(self.groupBox_2) + self.label_script.setObjectName(u"label_script") + + self.gridLayout_4.addWidget(self.label_script, 0, 0, 1, 1) + + self.label_interval = QLabel(self.groupBox_2) + self.label_interval.setObjectName(u"label_interval") + + self.gridLayout_4.addWidget(self.label_interval, 2, 0, 1, 1) + + self.interval = QSpinBox(self.groupBox_2) + self.interval.setObjectName(u"interval") + sizePolicy.setHeightForWidth(self.interval.sizePolicy().hasHeightForWidth()) + self.interval.setSizePolicy(sizePolicy) + self.interval.setMaximum(1000000000) + + self.gridLayout_4.addWidget(self.interval, 2, 1, 1, 1) + UIView.setCentralWidget(self.centralwidget) self.menubar = QMenuBar(UIView) self.menubar.setObjectName(u"menubar") - self.menubar.setGeometry(QRect(0, 0, 651, 24)) + self.menubar.setGeometry(QRect(0, 0, 651, 21)) UIView.setMenuBar(self.menubar) self.statusbar = QStatusBar(UIView) self.statusbar.setObjectName(u"statusbar") UIView.setStatusBar(self.statusbar) + # 定时开始时间的小时和分钟选择 + self.label_start_time = QLabel(self.groupBox) + self.label_start_time.setText("定时开始时间:") + self.combo_start_hour = QComboBox(self.groupBox) + self.combo_start_min = QComboBox(self.groupBox) + for hour in range(24): + self.combo_start_hour.addItem(f"{hour:02d}") + for minute in range(0, 60, 1): + self.combo_start_min.addItem(f"{minute:02d}") + self.combo_start_hour.setCurrentText("00") + self.combo_start_min.setCurrentText("00") + + # 定时停止时间的小时和分钟选择 + self.label_stop_time = QLabel(self.groupBox) + self.label_stop_time.setText("定时停止时间:") + self.combo_stop_hour = QComboBox(self.groupBox) + self.combo_stop_min = QComboBox(self.groupBox) + for hour in range(24): + self.combo_stop_hour.addItem(f"{hour:02d}") + for minute in range(0, 60, 1): + self.combo_stop_min.addItem(f"{minute:02d}") + self.combo_stop_hour.setCurrentText("00") + self.combo_stop_min.setCurrentText("00") + + # 添加“不定时”复选框 + self.checkbox_no_timing_start = QCheckBox("不定时", self.groupBox) + self.checkbox_no_timing_stop = QCheckBox("不定时", self.groupBox) + + # 开始时间布局 + hbox_start = QHBoxLayout() + hbox_start.addWidget(self.combo_start_hour) + hbox_start.addWidget(QLabel(":")) + hbox_start.addWidget(self.combo_start_min) + hbox_start.addWidget(self.checkbox_no_timing_start) + + # 停止时间布局 + hbox_stop = QHBoxLayout() + hbox_stop.addWidget(self.combo_stop_hour) + hbox_stop.addWidget(QLabel(":")) + hbox_stop.addWidget(self.combo_stop_min) + hbox_stop.addWidget(self.checkbox_no_timing_stop) + + self.gridLayout_3.addWidget(self.label_start_time, 4, 0) + self.gridLayout_3.addLayout(hbox_start, 4, 1) + self.gridLayout_3.addWidget(self.label_stop_time, 5, 0) + self.gridLayout_3.addLayout(hbox_stop, 5, 1) + self.retranslateUi(UIView) QMetaObject.connectSlotsByName(UIView) @@ -266,10 +326,11 @@ def retranslateUi(self, UIView): self.label_cursor_pos.setText(QCoreApplication.translate("UIView", u"Cursor Position:", None)) self.label_volume.setText(QCoreApplication.translate("UIView", u"Volume", None)) self.groupBox_2.setTitle(QCoreApplication.translate("UIView", u"Config", None)) + self.bt_open_script_files.setText(QCoreApplication.translate("UIView", u"...", None)) self.label_execute_interval.setText(QCoreApplication.translate("UIView", u"Mouse precision", None)) self.label_theme.setText(QCoreApplication.translate("UIView", u"Theme", None)) - self.bt_open_script_files.setText(QCoreApplication.translate("UIView", u"...", None)) - self.label_script.setText(QCoreApplication.translate("UIView", u"Script", None)) self.label_run_times.setText(QCoreApplication.translate("UIView", u"Run times", None)) + self.label_script.setText(QCoreApplication.translate("UIView", u"Script", None)) + self.label_interval.setText(QCoreApplication.translate("UIView", u"Interval", None)) # retranslateUi diff --git a/UIView.ui b/UIView.ui index e782f22..af278ac 100644 --- a/UIView.ui +++ b/UIView.ui @@ -265,30 +265,6 @@ 0 - - - - 0 - 0 - - - - - - - - Mouse precision - - - - - - - Theme - - - - @@ -337,10 +313,17 @@ - - + + - Script + Mouse precision + + + + + + + Theme @@ -367,6 +350,43 @@ + + + + + 0 + 0 + + + + + + + + Script + + + + + + + Interval + + + + + + + + 0 + 0 + + + + 1000000000 + + + @@ -376,7 +396,7 @@ 0 0 651 - 24 + 21 diff --git a/Util/RunScriptClass.py b/Util/RunScriptClass.py index f9f1ce0..d56f976 100644 --- a/Util/RunScriptClass.py +++ b/Util/RunScriptClass.py @@ -47,6 +47,7 @@ def __init__(self, frame: QWidget): self.state = State.RUNNING self.script_path = frame.get_script_path() self.runtimes = frame.stimes.value() + self.interval = frame.interval.value() # 更新控件的槽函数 self.logSignal.connect(frame.textlog.append) @@ -96,7 +97,7 @@ def run(self): self.playtuneSignal.emit('end.wav') @logger.catch - def run_script_from_path(self, script_path: str): + def run_script_from_path(self, script_path: str, is_subscript: bool = False): try: running_text = '%s running..' % script_path.split('/')[-1].split('\\')[-1] self.tnumrdSignal.emit(running_text) @@ -119,12 +120,14 @@ def run_script_from_path(self, script_path: str): j = 0 nointerrupt = True logger.debug('Run script..') - - while (j < self.runtimes or self.runtimes == 0) and nointerrupt: + runtimes = 1 if is_subscript else self.runtimes + while (j < runtimes or runtimes == 0) and nointerrupt: logger.debug('===========%d==============' % j) + if j > 0 and self.interval > 0: + self.sleep(self.interval) if self.state == State.IDLE: break - self.tnumrdSignal.emit(f'{running_text}... Looptimes [{j + 1}/{self.runtimes}]') + self.tnumrdSignal.emit(f'{running_text}... Looptimes [{j + 1}/{runtimes}]') nointerrupt = nointerrupt and self.run_script_from_objects(head_object) j += 1 if nointerrupt: @@ -185,7 +188,7 @@ def run_object(self, json_object: JsonObject): pass elif object_type == 'subroutine': for path in json_object.content['path']: - self.run_script_from_path(path) + self.run_script_from_path(path, True) else: # Not supposed to happen logger.error(f'Unexpected event type when running {json_object.content}') @@ -211,7 +214,7 @@ def run(self) -> None: self.run_script_from_path(self.script_path) @logger.catch - def run_script_from_path(self, script_path): + def run_script_from_path(self, script_path, is_subscript: bool = False): for path in script_path: logger.info('Script path:%s' % path) logger.debug('Parse script..') @@ -224,7 +227,8 @@ def run_script_from_path(self, script_path): except Exception as e: logger.error(e) j = 0 - while j < self.run_times or self.run_times == 0: + runtimes = 1 if is_subscript else self.run_times + while j < runtimes or runtimes == 0: logger.info('===========%d==============' % j) self.run_script_from_objects(head_object) if self.flag.value: @@ -264,7 +268,7 @@ def run_object(self, json_object: JsonObject): elif object_type in ['goto', 'custom']: pass elif object_type == 'subroutine': - self.run_script_from_path(json_object.content['path']) + self.run_script_from_path(json_object.content['path'], True) else: # Not supposed to happen logger.error(f'Unexpected event type when running {json_object.content}') diff --git a/archived/config.py b/archived/config.py index 4ac0b53..178c713 100644 --- a/archived/config.py +++ b/archived/config.py @@ -34,6 +34,8 @@ def setdefaultconf(config): config.set('Config', 'Precision', '200') config.set('Config', 'ExecuteSpeed', '100') config.set('Config', 'Language', 'zh-cn') + config.set('Config', 'StartTime', '不定时') + config.set('Config', 'StopTime', '不定时') def getconfig(): if not os.path.exists('../config.ini'): @@ -52,4 +54,6 @@ def saveconfig(newConf): conf.set('Config', 'Precision', str(newConf['precision'])) conf.set('Config', 'ExecuteSpeed', str(newConf['executespeed'])) conf.set('Config', 'Language', str(newConf['language'])) + conf.set('Config', 'StartTime', newConf.get('start_time', '不定时')) + conf.set('Config', 'StopTime', newConf.get('stop_time', '不定时')) conf.write(open('../config.ini', 'w'))