Files
voculinux/src/vocalinux/ui/action_handler.py
T
Jatin K MalikandGitHub f468be627d feat: comprehensive bug fixes and feature improvements (#30)
Major improvements and fixes:

🐛 Bug Fixes:
- Fix VOSK model download URL (v0.42 -> v0.22 for large model)
- Fix resource path resolution across different installation methods
- Fix missing error handling for audio library imports
- Fix text injection return value handling
- Fix test compatibility issues with updated imports

✨ New Features:
- Add centralized ResourceManager for consistent resource access
- Add ActionHandler for voice commands (delete, undo, redo, select, etc.)
- Add keyboard shortcut support for text injection
- Add comprehensive dependency checking with helpful error messages
- Add resource validation with detailed reporting

🔧 Improvements:
- Eliminate code duplication in resource path finding
- Enhance error handling with user-friendly messages
- Improve Wayland/X11 compatibility
- Add proper return type annotations
- Enhance test coverage and fix failing tests

📁 New Files:
- src/vocalinux/utils/resource_manager.py - Centralized resource management
- src/vocalinux/ui/action_handler.py - Voice command action processing
- src/vocalinux/utils/__init__.py - Utils package initialization

🧪 Testing:
- All tests now pass (76 passed, 28 skipped)
- Updated test mocks for new architecture
- Fixed import issues in test files

This makes VocaLinux production-ready with robust error handling,
complete feature implementation, and improved maintainability.
2025-06-23 17:26:03 -05:00

130 lines
4.5 KiB
Python

"""
Action handler for Vocalinux voice commands.
This module handles special voice commands like "delete that", "undo", etc.
"""
import logging
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from ..text_injection.text_injector import TextInjector
logger = logging.getLogger(__name__)
class ActionHandler:
"""
Handles special voice command actions.
This class processes action commands from the speech recognition system
and performs the appropriate actions like deleting text, undoing, etc.
"""
def __init__(self, text_injector: "TextInjector"):
"""
Initialize the action handler.
Args:
text_injector: The text injector instance for performing actions
"""
self.text_injector = text_injector
self.last_injected_text = ""
# Map actions to handler methods
self.action_handlers = {
"delete_last": self._handle_delete_last,
"undo": self._handle_undo,
"redo": self._handle_redo,
"select_all": self._handle_select_all,
"select_line": self._handle_select_line,
"select_word": self._handle_select_word,
"select_paragraph": self._handle_select_paragraph,
"cut": self._handle_cut,
"copy": self._handle_copy,
"paste": self._handle_paste,
}
def handle_action(self, action: str) -> bool:
"""
Handle a voice command action.
Args:
action: The action to perform
Returns:
True if the action was handled successfully, False otherwise
"""
logger.debug(f"Handling action: {action}")
handler = self.action_handlers.get(action)
if handler:
try:
return handler()
except Exception as e:
logger.error(f"Error handling action '{action}': {e}")
return False
else:
logger.warning(f"Unknown action: {action}")
return False
def set_last_injected_text(self, text: str):
"""
Set the last injected text for undo/delete operations.
Args:
text: The last text that was injected
"""
self.last_injected_text = text
def _handle_delete_last(self) -> bool:
"""Handle 'delete that' command by sending backspace keys."""
if not self.last_injected_text:
logger.debug("No text to delete")
return True
# Send backspace keys for each character in the last injected text
backspaces = "\b" * len(self.last_injected_text)
success = self.text_injector.inject_text(backspaces)
if success:
logger.debug(f"Deleted {len(self.last_injected_text)} characters")
self.last_injected_text = ""
return success
def _handle_undo(self) -> bool:
"""Handle 'undo' command by sending Ctrl+Z."""
return self.text_injector._inject_keyboard_shortcut("ctrl+z")
def _handle_redo(self) -> bool:
"""Handle 'redo' command by sending Ctrl+Y."""
return self.text_injector._inject_keyboard_shortcut("ctrl+y")
def _handle_select_all(self) -> bool:
"""Handle 'select all' command by sending Ctrl+A."""
return self.text_injector._inject_keyboard_shortcut("ctrl+a")
def _handle_select_line(self) -> bool:
"""Handle 'select line' command by sending Home+Shift+End."""
return self.text_injector._inject_keyboard_shortcut("Home+shift+End")
def _handle_select_word(self) -> bool:
"""Handle 'select word' command by sending Ctrl+Shift+Right."""
return self.text_injector._inject_keyboard_shortcut("ctrl+shift+Right")
def _handle_select_paragraph(self) -> bool:
"""Handle 'select paragraph' command by sending Ctrl+Shift+Down."""
return self.text_injector._inject_keyboard_shortcut("ctrl+shift+Down")
def _handle_cut(self) -> bool:
"""Handle 'cut' command by sending Ctrl+X."""
return self.text_injector._inject_keyboard_shortcut("ctrl+x")
def _handle_copy(self) -> bool:
"""Handle 'copy' command by sending Ctrl+C."""
return self.text_injector._inject_keyboard_shortcut("ctrl+c")
def _handle_paste(self) -> bool:
"""Handle 'paste' command by sending Ctrl+V."""
return self.text_injector._inject_keyboard_shortcut("ctrl+v")