diff --git a/.github/workflows/unified-pipeline.yml b/.github/workflows/unified-pipeline.yml index d472ffc..886dbde 100644 --- a/.github/workflows/unified-pipeline.yml +++ b/.github/workflows/unified-pipeline.yml @@ -60,7 +60,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: '3.10' + python-version: '3.13' cache: 'pip' - name: Install linting tools @@ -87,7 +87,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.8', '3.10', '3.11'] + python-version: ['3.8', '3.10', '3.11', '3.13'] steps: - uses: actions/checkout@v4 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f39c5fd..152b885 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ repos: # Code formatting with Black - repo: https://github.com/psf/black - rev: 24.1.1 + rev: 26.1.0 hooks: - id: black language_version: python3 diff --git a/install.sh b/install.sh index 8497478..fb8a50e 100755 --- a/install.sh +++ b/install.sh @@ -656,6 +656,43 @@ install_text_input_tools() { print_warning "Please install 'wtype' manually for Wayland text input support." ;; esac + + # Try to install ydotool as additional fallback for Wayland + # ydotool works better with some compositors (like GNOME) where wtype may fail + print_info "Attempting to install ydotool for better Wayland compatibility..." + case "$DISTRO_FAMILY" in + ubuntu|debian) + if ! apt_package_installed "ydotool"; then + sudo apt install -y ydotool 2>/dev/null || print_info "ydotool not available in repos (optional)" + fi + ;; + fedora) + if command_exists dnf; then + sudo dnf install -y ydotool 2>/dev/null || print_info "ydotool not available in repos (optional)" + fi + ;; + arch) + if ! pacman_package_installed "ydotool"; then + sudo pacman -S --noconfirm ydotool 2>/dev/null || print_info "ydotool not available in repos (optional)" + fi + ;; + esac + + # Add user to input group for ydotool/dotool support + if ! groups | grep -q '\binput\b'; then + print_info "Adding $USER to 'input' group for text injection..." + sudo usermod -aG input "$USER" || print_warning "Failed to add user to input group" + print_warning "You will need to LOG OUT and back in for text injection to work with ydotool/dotool" + fi + + # Install udev rule for ydotool/dotool + if [ ! -f /etc/udev/rules.d/80-dotool.rules ]; then + print_info "Installing udev rule for input device access..." + echo 'KERNEL=="uinput", GROUP="input", MODE="0620", OPTIONS+="static_node=uinput"' \ + | sudo tee /etc/udev/rules.d/80-dotool.rules >/dev/null 2>&1 || print_warning "Failed to install udev rule" + sudo udevadm control --reload 2>/dev/null || true + sudo udevadm trigger 2>/dev/null || true + fi ;; x11|"") @@ -786,9 +823,9 @@ setup_virtual_environment() { fi # Create virtual environment - # Note: We don't use --system-site-packages to avoid conflicts with system packages - # that may be incompatible with Python 3.12+ (e.g., old coverage versions) - python3 -m venv "$VENV_DIR" || { + # Use --system-site-packages to access pre-compiled system packages like PyGObject + # This avoids build failures with Python 3.13+ where PyGObject may not build from source + python3 -m venv --system-site-packages "$VENV_DIR" || { print_error "Failed to create virtual environment. Please check your Python installation." exit 1 } diff --git a/pyproject.toml b/pyproject.toml index e694b52..45a4033 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,6 +31,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Desktop Environment :: Gnome", "Topic :: Multimedia :: Sound/Audio :: Speech", "Topic :: Text Processing", @@ -95,7 +96,7 @@ version = {attr = "vocalinux.version.__version__"} [tool.black] line-length = 100 -target-version = ['py38', 'py39', 'py310', 'py311'] +target-version = ['py38', 'py39', 'py310', 'py311', 'py312', 'py313'] include = '\.pyi?$' exclude = ''' /( diff --git a/src/vocalinux/text_injection/text_injector.py b/src/vocalinux/text_injection/text_injector.py index b7d466f..f7d9fd9 100644 --- a/src/vocalinux/text_injection/text_injector.py +++ b/src/vocalinux/text_injection/text_injector.py @@ -118,15 +118,18 @@ class TextInjector: raise RuntimeError("Missing required dependency: xdotool") else: # Check for wtype or ydotool for Wayland + # Prefer ydotool as it works universally (including GNOME Wayland) wtype_available = shutil.which("wtype") is not None ydotool_available = shutil.which("ydotool") is not None xdotool_available = shutil.which("xdotool") is not None - if wtype_available: - self.wayland_tool = "wtype" - logger.info(f"Using {self.wayland_tool} for Wayland text injection") - elif ydotool_available: + if ydotool_available: self.wayland_tool = "ydotool" + logger.info( + f"Using {self.wayland_tool} for Wayland text injection (universal compatibility)" + ) + elif wtype_available: + self.wayland_tool = "wtype" logger.info(f"Using {self.wayland_tool} for Wayland text injection") elif xdotool_available: # Fallback to xdotool with XWayland