diff --git a/install.sh b/install.sh index fb8a50e..5e6da32 100755 --- a/install.sh +++ b/install.sh @@ -1019,11 +1019,21 @@ VOSK_CONFIG mkdir -p "$HOME/.local/bin" # Create vocalinux wrapper script + # Uses 'sg input' to run with input group for keyboard shortcuts on Wayland + # This allows shortcuts to work without logging out after installation cat > "$HOME/.local/bin/vocalinux" << WRAPPER_EOF #!/bin/bash # Wrapper script for Vocalinux that sets required environment variables +# and applies the 'input' group for keyboard shortcuts on Wayland export GI_TYPELIB_PATH=/usr/lib/girepository-1.0 -exec "$VENV_DIR/bin/vocalinux" "\$@" + +# Check if user is in input group but current session doesn't have it +if grep -q "^input:.*\b\$(whoami)\b" /etc/group 2>/dev/null && ! groups | grep -q '\binput\b'; then + # Use sg to run with input group without requiring logout + exec sg input -c "$VENV_DIR/bin/vocalinux \$*" +else + exec "$VENV_DIR/bin/vocalinux" "\$@" +fi WRAPPER_EOF chmod +x "$HOME/.local/bin/vocalinux" print_info "Created wrapper: ~/.local/bin/vocalinux" @@ -1032,8 +1042,16 @@ WRAPPER_EOF cat > "$HOME/.local/bin/vocalinux-gui" << WRAPPER_EOF #!/bin/bash # Wrapper script for Vocalinux GUI that sets required environment variables +# and applies the 'input' group for keyboard shortcuts on Wayland export GI_TYPELIB_PATH=/usr/lib/girepository-1.0 -exec "$VENV_DIR/bin/vocalinux-gui" "\$@" + +# Check if user is in input group but current session doesn't have it +if grep -q "^input:.*\b\$(whoami)\b" /etc/group 2>/dev/null && ! groups | grep -q '\binput\b'; then + # Use sg to run with input group without requiring logout + exec sg input -c "$VENV_DIR/bin/vocalinux-gui \$*" +else + exec "$VENV_DIR/bin/vocalinux-gui" "\$@" +fi WRAPPER_EOF chmod +x "$HOME/.local/bin/vocalinux-gui" print_info "Created wrapper: ~/.local/bin/vocalinux-gui" diff --git a/src/vocalinux/ui/keyboard_backends/evdev_backend.py b/src/vocalinux/ui/keyboard_backends/evdev_backend.py index 8129fd5..4164baa 100644 --- a/src/vocalinux/ui/keyboard_backends/evdev_backend.py +++ b/src/vocalinux/ui/keyboard_backends/evdev_backend.py @@ -76,6 +76,36 @@ def find_keyboard_devices() -> List[str]: return keyboard_devices +def device_has_ctrl_key(device_path: str) -> bool: + """ + Check if a device has Ctrl key capability. + + Args: + device_path: Path to the input device + + Returns: + True if the device can send Ctrl key events + """ + if not EVDEV_AVAILABLE: + return False + + try: + device = InputDevice(device_path) + capabilities = device.capabilities() + device.close() + + # Check if device has EV_KEY capability and supports Ctrl keys + if ecodes.EV_KEY in capabilities: + key_caps = capabilities[ecodes.EV_KEY] + # Check for left or right Ctrl key + if KEY_LEFTCTRL in key_caps or KEY_RIGHTCTRL in key_caps: + return True + except (OSError, IOError): + pass + + return False + + class EvdevKeyboardBackend(KeyboardBackend): """ Keyboard backend using python-evdev. @@ -102,14 +132,23 @@ class EvdevKeyboardBackend(KeyboardBackend): logger.error("python-evdev not available") def is_available(self) -> bool: - """Check if evdev is available.""" + """Check if evdev is available and we can access a keyboard device with Ctrl key.""" if not EVDEV_AVAILABLE: return False - # Check if we can access at least one keyboard device + # Check if we can access at least one keyboard device with Ctrl key capability try: devices = find_keyboard_devices() - return len(devices) > 0 + if not devices: + return False + + # Try to find at least one device with Ctrl key that we can open + for device_path in devices: + if device_has_ctrl_key(device_path): + return True + + # Could not find any accessible device with Ctrl key + return False except Exception: return False @@ -292,4 +331,9 @@ class EvdevKeyboardBackend(KeyboardBackend): # Export availability -__all__ = ["EvdevKeyboardBackend", "EVDEV_AVAILABLE", "find_keyboard_devices"] +__all__ = [ + "EvdevKeyboardBackend", + "EVDEV_AVAILABLE", + "find_keyboard_devices", + "device_has_ctrl_key", +]