fix: thread-safe hotkey handling
- Add HotkeyHandler class with pyqtSignal - Fix QMetaObject.invokeMethod error - Proper thread safety for keyboard hotkeys
This commit is contained in:
parent
d387a4714a
commit
fa0b0c87b5
|
|
@ -15,7 +15,7 @@ if str(project_root) not in sys.path:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PyQt6.QtWidgets import QApplication
|
from PyQt6.QtWidgets import QApplication
|
||||||
from PyQt6.QtCore import Qt
|
from PyQt6.QtCore import Qt, QObject, pyqtSignal
|
||||||
PYQT_AVAILABLE = True
|
PYQT_AVAILABLE = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
PYQT_AVAILABLE = False
|
PYQT_AVAILABLE = False
|
||||||
|
|
@ -35,6 +35,11 @@ from core.plugin_manager import PluginManager
|
||||||
from core.overlay_window import OverlayWindow
|
from core.overlay_window import OverlayWindow
|
||||||
|
|
||||||
|
|
||||||
|
class HotkeyHandler(QObject):
|
||||||
|
"""Signal bridge for thread-safe hotkey handling."""
|
||||||
|
toggle_signal = pyqtSignal()
|
||||||
|
|
||||||
|
|
||||||
class EUUtilityApp:
|
class EUUtilityApp:
|
||||||
"""Main application controller."""
|
"""Main application controller."""
|
||||||
|
|
||||||
|
|
@ -42,6 +47,7 @@ class EUUtilityApp:
|
||||||
self.app = None
|
self.app = None
|
||||||
self.overlay = None
|
self.overlay = None
|
||||||
self.plugin_manager = None
|
self.plugin_manager = None
|
||||||
|
self.hotkey_handler = None
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""Start the application."""
|
"""Start the application."""
|
||||||
|
|
@ -53,6 +59,9 @@ class EUUtilityApp:
|
||||||
if hasattr(Qt, 'AA_EnableHighDpiScaling'):
|
if hasattr(Qt, 'AA_EnableHighDpiScaling'):
|
||||||
self.app.setAttribute(Qt.ApplicationAttribute.AA_EnableHighDpiScaling)
|
self.app.setAttribute(Qt.ApplicationAttribute.AA_EnableHighDpiScaling)
|
||||||
|
|
||||||
|
# Create hotkey handler (must be in main thread)
|
||||||
|
self.hotkey_handler = HotkeyHandler()
|
||||||
|
|
||||||
# Initialize plugin manager
|
# Initialize plugin manager
|
||||||
print("Loading plugins...")
|
print("Loading plugins...")
|
||||||
self.plugin_manager = PluginManager(None)
|
self.plugin_manager = PluginManager(None)
|
||||||
|
|
@ -62,6 +71,9 @@ class EUUtilityApp:
|
||||||
self.overlay = OverlayWindow(self.plugin_manager)
|
self.overlay = OverlayWindow(self.plugin_manager)
|
||||||
self.plugin_manager.overlay = self.overlay
|
self.plugin_manager.overlay = self.overlay
|
||||||
|
|
||||||
|
# Connect hotkey signal
|
||||||
|
self.hotkey_handler.toggle_signal.connect(self._on_toggle_signal)
|
||||||
|
|
||||||
# Setup global hotkey
|
# Setup global hotkey
|
||||||
self._setup_hotkey()
|
self._setup_hotkey()
|
||||||
|
|
||||||
|
|
@ -75,20 +87,20 @@ class EUUtilityApp:
|
||||||
"""Setup global hotkey."""
|
"""Setup global hotkey."""
|
||||||
if KEYBOARD_AVAILABLE:
|
if KEYBOARD_AVAILABLE:
|
||||||
try:
|
try:
|
||||||
keyboard.add_hotkey('ctrl+shift+u', self._toggle_overlay)
|
keyboard.add_hotkey('ctrl+shift+u', self._on_hotkey_pressed)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to register hotkey: {e}")
|
print(f"Failed to register hotkey: {e}")
|
||||||
|
|
||||||
def _toggle_overlay(self):
|
def _on_hotkey_pressed(self):
|
||||||
"""Toggle overlay visibility."""
|
"""Called when hotkey is pressed (from keyboard thread)."""
|
||||||
|
# Emit signal to main thread
|
||||||
|
if self.hotkey_handler:
|
||||||
|
self.hotkey_handler.toggle_signal.emit()
|
||||||
|
|
||||||
|
def _on_toggle_signal(self):
|
||||||
|
"""Handle toggle signal in main thread."""
|
||||||
if self.overlay:
|
if self.overlay:
|
||||||
# Use Qt's thread-safe method
|
self.overlay.toggle_overlay()
|
||||||
from PyQt6.QtCore import QMetaObject, Qt
|
|
||||||
QMetaObject.invokeMethod(
|
|
||||||
self.overlay,
|
|
||||||
"toggle_overlay",
|
|
||||||
Qt.ConnectionType.QueuedConnection
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue