fix(keyboard): verify Ctrl key capability in evdev backend availability check (#128)

* fix(keyboard): verify Ctrl key capability in evdev backend availability check

The evdev backend's is_available() method was incorrectly returning True
when keyboard devices were found, even if the user lacked permission to
access them or if the accessible devices didn't have Ctrl key capability.

This caused keyboard shortcuts to fail silently on Wayland when the user
wasn't in the 'input' group, as the backend was selected but couldn't
actually monitor keyboard events.

Changes:
- Add device_has_ctrl_key() helper to verify a device supports Ctrl keys
- Update is_available() to check both device accessibility AND Ctrl key
  capability
- Now correctly returns False when no usable keyboard device is found,
  triggering proper error messages about permissions

This ensures users get clear feedback about missing permissions instead
of silently non-working keyboard shortcuts.

* fix(install): use sg command to apply input group without logout

The install.sh script adds the user to the 'input' group for keyboard
shortcuts on Wayland, but this change doesn't take effect until logout.

Updated wrapper scripts to use 'sg input -c ...' to run vocalinux with
the input group applied, even if the user hasn't logged out yet. This
provides a much better user experience as keyboard shortcuts work
immediately after installation.

The wrapper detects if:
1. User is in /etc/group for 'input' group
2. Current session doesn't have the group active
If both conditions are true, it uses 'sg' to apply the group.
This commit is contained in:
Jatin K Malik
2026-02-05 00:04:19 -08:00
committed by GitHub
parent 1fe6b21017
commit ee494f921c
2 changed files with 68 additions and 6 deletions
+20 -2
View File
@@ -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"
@@ -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",
]