Skip to content

Commit e663a08

Browse files
committed
fix: prevent hotkey registration from triggering recording
1 parent 56e2f30 commit e663a08

2 files changed

Lines changed: 89 additions & 15 deletions

File tree

src/main.py

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ def __init__(self, startup_mode: bool = False) -> None:
124124
self._cancel_event = threading.Event()
125125
self._worker: _WorkerThread | None = None
126126
self._settings_dlg: SettingsDialog | None = None
127+
self._settings_hotkey_capture_paused = False
127128
self._recording = False
128129
self._enabled = True
129130

@@ -334,6 +335,9 @@ def _on_hotkey_pressed(self) -> None:
334335
if not self._enabled:
335336
return
336337

338+
if self._is_hotkey_capture_active() and not self._recording:
339+
return
340+
337341
if self._worker is not None:
338342
return # Already processing; ignore.
339343

@@ -345,9 +349,27 @@ def _on_hotkey_pressed(self) -> None:
345349

346350
def _on_hotkey_released(self) -> None:
347351
# Hold mode: release during recording → finalize and process.
352+
if self._is_hotkey_capture_active() and not self._recording:
353+
return
348354
if self._recording:
349355
self._finalize_recording()
350356

357+
def _is_hotkey_capture_active(self) -> bool:
358+
return self._settings_dlg is not None and self._settings_dlg.is_hotkey_capture_active()
359+
360+
def _on_settings_hotkey_capture_active_changed(self, active: bool) -> None:
361+
if active:
362+
if self._settings_hotkey_capture_paused or self._recording:
363+
return
364+
self._hotkey.stop()
365+
self._settings_hotkey_capture_paused = True
366+
return
367+
368+
if not self._settings_hotkey_capture_paused:
369+
return
370+
self._make_listener()
371+
self._settings_hotkey_capture_paused = False
372+
351373
# ------------------------------------------------------------------
352374
# Worker result
353375
# ------------------------------------------------------------------
@@ -434,22 +456,33 @@ def _open_settings(self) -> None:
434456
calibrate_fn=self._calibrate,
435457
)
436458
self._settings_dlg = dlg
437-
result = dlg.exec()
438-
if result == SettingsDialog.DialogCode.Accepted:
439-
save_config(dlg.get_config())
440-
self._settings_dlg = None
459+
dlg.hotkey_capture_active_changed.connect(self._on_settings_hotkey_capture_active_changed)
460+
dlg.applied.connect(self._sync_settings_from_disk)
461+
result = SettingsDialog.DialogCode.Rejected
462+
try:
463+
result = dlg.exec()
464+
if result == SettingsDialog.DialogCode.Accepted:
465+
save_config(dlg.get_config())
466+
finally:
467+
self._settings_dlg = None
441468

442-
# Always reload from disk — Apply may have written new values,
443-
# and the user may have changed fields before Cancel.
444-
self._config = load_config()
445-
self._restart_hotkey()
446-
self._rebuild_menu()
469+
# Always reload from disk — Apply may have written new values,
470+
# and the user may have changed fields before Cancel.
471+
self._sync_settings_from_disk()
447472

448473
if result == SettingsDialog.DialogCode.Accepted:
449474
log.info("Settings updated from dialog")
450475
else:
451476
log.info("Settings dialog closed (cancelled); reloaded from disk")
452477

478+
def _sync_settings_from_disk(self) -> None:
479+
old_hotkey = self._config.hotkey
480+
old_mode = self._config.recording_mode
481+
self._config = load_config()
482+
if self._config.hotkey != old_hotkey or self._config.recording_mode != old_mode:
483+
self._restart_hotkey()
484+
self._rebuild_menu()
485+
453486
# ------------------------------------------------------------------
454487
# Shutdown
455488
# ------------------------------------------------------------------

src/settings_dialog.py

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import logging
1111
from typing import Callable
1212

13-
from PySide6.QtCore import Qt, Signal
13+
from PySide6.QtCore import QCoreApplication, QEvent, Qt, Signal
1414
from PySide6.QtGui import QKeyEvent, QMouseEvent
1515
from PySide6.QtWidgets import (
1616
QCheckBox,
@@ -82,6 +82,9 @@ class SettingsDialog(QDialog):
8282
``None`` disables the calibrate button.
8383
"""
8484

85+
hotkey_capture_active_changed = Signal(bool)
86+
applied = Signal()
87+
8588
def __init__(
8689
self,
8790
config: AppConfig,
@@ -168,7 +171,7 @@ def _build_general_tab(self) -> None:
168171
self._hotkey_capture = HotkeyCaptureEdit()
169172
self._hotkey_capture.captured.connect(self._on_hotkey_captured)
170173
self._hotkey_capture.cancelled.connect(self._stop_hotkey_recording)
171-
self._hotkey_record_btn = QPushButton("Record")
174+
self._hotkey_record_btn = QPushButton("Register Hotkey")
172175
self._hotkey_record_btn.setCheckable(True)
173176
self._hotkey_record_btn.clicked.connect(self._on_hotkey_record_clicked)
174177
capture_row = QHBoxLayout()
@@ -224,17 +227,23 @@ def _on_hotkey_preset_chosen(self, index: int) -> None:
224227
self._set_captured_hotkey(hotkey)
225228

226229
def _start_hotkey_recording(self) -> None:
230+
if self._hotkey_capture.is_recording():
231+
return
227232
self._hotkey_record_btn.setChecked(True)
228233
self._hotkey_record_btn.setText("Cancel")
229234
self._hotkey_error.setVisible(False)
235+
self.hotkey_capture_active_changed.emit(True)
230236
self._hotkey_capture.start_recording()
231237

232238
def _stop_hotkey_recording(self) -> None:
239+
if not self._hotkey_capture.is_recording():
240+
return
233241
self._hotkey_record_btn.setChecked(False)
234-
self._hotkey_record_btn.setText("Record")
242+
self._hotkey_record_btn.setText("Register Hotkey")
235243
self._hotkey_capture.stop_recording()
236244
if self._captured_hotkey is not None:
237245
self._hotkey_capture.show_hotkey(self._captured_hotkey)
246+
self.hotkey_capture_active_changed.emit(False)
238247

239248
def _on_hotkey_record_clicked(self, checked: bool) -> None:
240249
if checked:
@@ -554,22 +563,36 @@ def _on_reset(self) -> None:
554563
def _on_apply(self) -> None:
555564
"""Apply: collect and persist without closing."""
556565
with log_duration(log, "Settings apply"):
566+
self._stop_hotkey_recording()
557567
self._collect()
558568
if not self._show_validation_issue():
559569
return
560570
if not self._sync_startup_or_warn():
561571
return
562572
save_config(self._working)
573+
self.applied.emit()
563574
log.info("Settings applied")
564575

565576
# ------------------------------------------------------------------
566577
# Overrides
567578
# ------------------------------------------------------------------
568579

569580
def accept(self) -> None:
581+
self._stop_hotkey_recording()
570582
self._collect()
571583
super().accept()
572584

585+
def reject(self) -> None:
586+
self._stop_hotkey_recording()
587+
super().reject()
588+
589+
def done(self, result: int) -> None:
590+
self._stop_hotkey_recording()
591+
super().done(result)
592+
593+
def is_hotkey_capture_active(self) -> bool:
594+
return self._hotkey_capture.is_recording()
595+
573596
def _show_validation_issue(self) -> bool:
574597
issue = next(iter(validate_config(self._working)), None)
575598
if issue is None:
@@ -673,15 +696,23 @@ def is_recording(self) -> bool:
673696
return self._recording
674697

675698
def start_recording(self) -> None:
699+
if self._recording:
700+
return
676701
self._recording = True
677-
self.setText("press keys or a mouse button…")
702+
self.setText("press the new hotkey…")
678703
self.setFocus(Qt.OtherFocusReason)
704+
app = QCoreApplication.instance()
705+
if app is not None:
706+
app.installEventFilter(self)
679707
self.grabKeyboard()
680-
self.grabMouse()
681708

682709
def stop_recording(self) -> None:
710+
if not self._recording:
711+
return
683712
self._recording = False
684-
self.releaseMouse()
713+
app = QCoreApplication.instance()
714+
if app is not None:
715+
app.removeEventFilter(self)
685716
self.releaseKeyboard()
686717

687718
def show_hotkey(self, hotkey: Hotkey) -> None:
@@ -713,6 +744,16 @@ def mousePressEvent(self, event: QMouseEvent) -> None:
713744
event.accept()
714745
self.captured.emit(Hotkey(_mods_from_qt(event.modifiers()), "mouse", code))
715746

747+
def eventFilter(self, watched, event) -> bool:
748+
if not self._recording or event.type() != QEvent.Type.MouseButtonPress:
749+
return False
750+
code = _mouse_button_to_code(event.button())
751+
if code is None:
752+
return False
753+
event.accept()
754+
self.captured.emit(Hotkey(_mods_from_qt(event.modifiers()), "mouse", code))
755+
return True
756+
716757

717758
def _combo_index(combo: QComboBox, data: str) -> int:
718759
for i in range(combo.count()):

0 commit comments

Comments
 (0)