Initial commit of WhisperVoice
This commit is contained in:
95
src/core/hotkey_manager.py
Normal file
95
src/core/hotkey_manager.py
Normal file
@@ -0,0 +1,95 @@
|
||||
"""
|
||||
Hotkey Manager Module.
|
||||
======================
|
||||
|
||||
This module wraps the `keyboard` library to provide Global Hotkey functionality.
|
||||
It allows the application to respond to key presses even when it is not in focus
|
||||
(background operation).
|
||||
|
||||
Classes:
|
||||
HotkeyManager: Qt-compatible wrapper for keyboard hooks.
|
||||
"""
|
||||
|
||||
import keyboard
|
||||
import logging
|
||||
from PySide6.QtCore import QObject, Signal
|
||||
from typing import Optional
|
||||
|
||||
class HotkeyManager(QObject):
|
||||
"""
|
||||
Manages global keyboard shortcuts using the `keyboard` library.
|
||||
inherits from QObject to allow Signal/Slot integration with PySide6.
|
||||
|
||||
Signals:
|
||||
triggered: Emitted when the hotkey is pressed.
|
||||
|
||||
Attributes:
|
||||
hotkey (str): The key combination as a string (e.g. "f8", "ctrl+alt+r").
|
||||
is_listening (bool): State of the listener.
|
||||
"""
|
||||
|
||||
triggered = Signal()
|
||||
|
||||
def __init__(self, hotkey: str = "f8"):
|
||||
"""
|
||||
Initialize the HotkeyManager.
|
||||
|
||||
Args:
|
||||
hotkey (str): The global hotkey string description. Default: "f8".
|
||||
"""
|
||||
super().__init__()
|
||||
self.hotkey = hotkey
|
||||
self.is_listening = False
|
||||
self._enabled = True
|
||||
|
||||
def set_enabled(self, enabled: bool):
|
||||
"""Enable or disable the hotkey trigger without unhooking."""
|
||||
self._enabled = enabled
|
||||
logging.info(f"Hotkey listener {'enabled' if enabled else 'suspended'}")
|
||||
|
||||
def start(self):
|
||||
"""Start listening for the hotkey."""
|
||||
self.reload_hotkey()
|
||||
|
||||
def reload_hotkey(self):
|
||||
"""Unregister old hotkey and register new one from Config."""
|
||||
if self.is_listening:
|
||||
self.stop()
|
||||
|
||||
from src.core.config import ConfigManager
|
||||
config = ConfigManager()
|
||||
self.hotkey = config.get("hotkey")
|
||||
|
||||
logging.info(f"Registering global hotkey: {self.hotkey}")
|
||||
try:
|
||||
# We don't suppress=True here because we want the app to see keys during recording
|
||||
# (Wait, actually if we are recording we WANT keyboard to see it,
|
||||
# but usually global hotkeys should be suppressed if we don't want them leaking to other apps)
|
||||
# However, the user is fixing the internal collision.
|
||||
keyboard.add_hotkey(self.hotkey, self.on_press, suppress=False)
|
||||
self.is_listening = True
|
||||
except Exception as e:
|
||||
logging.error(f"Failed to bind hotkey: {e}")
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Stop listening and unregister the hook.
|
||||
Safe to call even if not listening.
|
||||
"""
|
||||
if self.is_listening:
|
||||
try:
|
||||
keyboard.remove_hotkey(self.hotkey)
|
||||
except:
|
||||
pass
|
||||
self.is_listening = False
|
||||
logging.info(f"Unregistered global hotkey: {self.hotkey}")
|
||||
|
||||
def on_press(self):
|
||||
"""
|
||||
Callback triggered internally by the keyboard library when the key is pressed.
|
||||
Emits the Qt `triggered` signal.
|
||||
"""
|
||||
if not self._enabled:
|
||||
return
|
||||
logging.info(f"Hotkey {self.hotkey} detected.")
|
||||
self.triggered.emit()
|
||||
Reference in New Issue
Block a user