diff --git a/RHEL.md b/RHEL.md new file mode 100644 index 00000000..c4febe0d --- /dev/null +++ b/RHEL.md @@ -0,0 +1,245 @@ +# Solaar on RHEL 10 + +## Purpose + +This documents the steps required to get **Solaar** running on **RHEL 10** when the package is not available from the normal repositories. + +## Environment + +* OS: RHEL 10 +* Desktop: KDE Plasma on Wayland +* Device class: Logitech Unifying Receiver +* Example mouse: Logitech M720 Triathlon + +## Observed issue + +The following packages were not available from the configured repositories: + +```bash +sudo dnf install solaar xbindkeys xdotool evtest +``` + +DNF returned package-not-found errors for those package names. + +## What worked + +### 1. Confirm the Logitech receiver is detected + +```bash +lsusb | grep -i logitech +``` + +Expected output looked similar to this: + +```text +Bus 001 Device 00X: ID 046d:c52b Logitech, Inc. Unifying Receiver +``` + +### 2. Install required base packages from RHEL and EPEL where available + +Install Python packaging support and device/input tooling first. + +```bash +sudo dnf install python3 python3-pip git libinput evemu +``` + +Also install build and runtime pieces commonly needed for user-space input and HID tools. + +```bash +sudo dnf install python3-devel gcc pkgconf-pkg-config gtk3 python3-gobject +``` + +Note: exact dependency resolution may vary depending on enabled repositories and what is already installed. + +### 3. Clone the Solaar repository + +```bash +mkdir -p ~/dev-repos +cd ~/dev-repos +git clone https://github.com/pwr-Solaar/Solaar.git +cd Solaar +``` + +### 4. Install Solaar to the user environment + +Install it into the user site-packages instead of system-wide. + +```bash +python3 -m pip install --user . +``` + +If upgrading later from the fork or local checkout: + +```bash +python3 -m pip install --user --upgrade . +``` + +### 5. Run Solaar directly from the user-local install path + +```bash +~/.local/bin/solaar +``` + +For CLI inspection: + +```bash +~/.local/bin/solaar show +~/.local/bin/solaar config "M720 Triathlon Multi-Device Mouse" +``` + +### 6. Confirm the receiver and device are visible + +A working example: + +```bash +~/.local/bin/solaar show +``` + +This displayed the Unifying Receiver and the M720 Triathlon, including battery state and configurable features. + +## Automated installer script + +A guided installer script is included in this repository and automates the RHEL workflow in this document while prompting before each major action. + +Run it from the Solaar checkout: + +```bash +./tools/install-rhel.sh +``` + +The script can: + +* check for Logitech receiver visibility with `lsusb` +* install required packages with `dnf` +* create the checkout directory and clone/update Solaar +* install Solaar with `python3 -m pip install --user` +* optionally add a Bash alias for `solaar` +* optionally run `solaar show`, `solaar config`, `libinput debug-events`, and `keyd monitor` +* write a timestamped evidence log in `~/.local/state/solaar/` + +## Wayland note + +On KDE Wayland, Solaar prints a warning similar to: + +```text +rules cannot access modifier keys in Wayland, accessing process only works on GNOME with Solaar Gnome extension installed +``` + +This does **not** prevent basic Solaar usage. It only means some rule-processing features are limited under Wayland, especially outside GNOME. + +## Device-specific issue seen with the M720 + +`solaar show` triggered a traceback when trying to read host-name metadata from the M720 Triathlon: + +```text +UnicodeDecodeError: 'utf-8' codec can't decode bytes in position 12-13: unexpected end of data +``` + +This appears related to Solaar parsing stored host information from the mouse, not to receiver detection itself. + +### Practical workaround + +Use targeted commands that still work, such as: + +```bash +~/.local/bin/solaar config "M720 Triathlon Multi-Device Mouse" +``` + +This successfully showed configurable settings like: + +* scroll wheel direction +* scroll wheel resolution +* pointer speed +* reprogrammable keys +* persistent remappable keys +* diversion settings + +## Verifying input behavior outside Solaar + +To inspect raw input events from the mouse, identify the correct `/dev/input/eventX` node for the mouse on your system and then run: + +```bash +sudo libinput debug-events --device /dev/input/eventX +``` + +This confirmed the mouse was producing: + +* pointer motion +* left and middle button events +* scroll wheel events +* horizontal wheel events +* keyboard-style events for some remapped functions + +## keyd note + +A locally installed `keyd` binary may exist under `/usr/local/bin/keyd` if built from source or installed manually. + +If it is not available in the shell `PATH`, direct invocation may be required for monitoring: + +```bash +sudo /usr/local/bin/keyd monitor +``` + +This can help verify that virtual keyboard and pointer events are being created and that remapped device actions are flowing through the input stack. + +## Recommended quality-of-life alias + +Add a shell alias so Solaar can be launched normally: + +```bash +vi ~/.bashrc +``` + +Append: + +```bash +alias solaar="$HOME/.local/bin/solaar" +``` + +Reload shell config: + +```bash +source ~/.bashrc +``` + +Then launch with: + +```bash +solaar +``` + +## Summary + +The working path on RHEL 10 was: + +1. Confirm the Logitech Unifying Receiver is visible with `lsusb`. +2. Install Python and required development/runtime packages. +3. Clone the Solaar repository. +4. Install Solaar with `python3 -m pip install --user .`. +5. Run Solaar from `~/.local/bin/solaar`. +6. Use `solaar config "M720 Triathlon Multi-Device Mouse"` for stable device configuration. +7. Use `libinput debug-events` and optionally `keyd monitor` to validate the input stack. + +## Commands used + +```bash +lsusb | grep -i logitech +mkdir -p ~/dev-repos +cd ~/dev-repos +git clone https://github.com/pwr-Solaar/Solaar.git +cd Solaar +python3 -m pip install --user . +~/.local/bin/solaar +~/.local/bin/solaar show +~/.local/bin/solaar config "M720 Triathlon Multi-Device Mouse" +sudo libinput debug-events --device /dev/input/eventX +sudo /usr/local/bin/keyd monitor +``` + +## Caveats + +* Package availability in RHEL 10 repositories may differ from Fedora or Debian-based systems. +* Wayland limits certain Solaar rule features. +* `solaar show` may crash on some host-info metadata due to an upstream parsing issue. +* Direct user-local execution from `~/.local/bin/solaar` may be required if no system package exists. +* Replace example paths and event device numbers with the values on your own system. diff --git a/tools/install-rhel.sh b/tools/install-rhel.sh new file mode 100755 index 00000000..65798f82 --- /dev/null +++ b/tools/install-rhel.sh @@ -0,0 +1,164 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_NAME="$(basename "$0")" +LOG_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/solaar" +LOG_FILE="$LOG_DIR/rhel-install-$(date +%Y%m%d-%H%M%S).log" + +mkdir -p "$LOG_DIR" +exec > >(tee -a "$LOG_FILE") 2>&1 + +say() { + printf '\n[%s] %s\n' "$SCRIPT_NAME" "$*" +} + +warn() { + printf '\n[%s] WARNING: %s\n' "$SCRIPT_NAME" "$*" +} + +fail() { + printf '\n[%s] ERROR: %s\n' "$SCRIPT_NAME" "$*" + exit 1 +} + +ask_yes_no() { + local prompt="$1" + local default="${2:-y}" + local answer + + while true; do + if [[ "$default" == "y" ]]; then + read -r -p "$prompt [Y/n]: " answer || true + answer="${answer:-y}" + else + read -r -p "$prompt [y/N]: " answer || true + answer="${answer:-n}" + fi + + case "${answer,,}" in + y|yes) return 0 ;; + n|no) return 1 ;; + *) echo "Please answer y or n." ;; + esac + done +} + +ask_value() { + local prompt="$1" + local default="$2" + local answer + + read -r -p "$prompt [$default]: " answer || true + printf '%s\n' "${answer:-$default}" +} + +run_cmd() { + say "Running: $*" + "$@" +} + +run_sudo() { + say "Running with sudo: $*" + sudo "$@" +} + +if [[ "${EUID}" -eq 0 ]]; then + fail "Do not run as root. Run as your normal user; this script uses sudo when needed." +fi + +say "Log file: $LOG_FILE" +say "This installer follows RHEL.md for RHEL 10-like systems." + +if ask_yes_no "Update dnf metadata first?" y; then + run_sudo dnf makecache +fi + +if ask_yes_no "Check for Logitech USB receiver with lsusb now?" y; then + if lsusb | grep -i logitech; then + say "Logitech device detected." + else + warn "No Logitech USB receiver detected via lsusb right now. You can continue anyway." + ask_yes_no "Continue without receiver detection?" y || fail "Aborted by user." + fi +fi + +BASE_PACKAGES=(python3 python3-pip git libinput evemu) +DEV_PACKAGES=(python3-devel gcc pkgconf-pkg-config gtk3 python3-gobject) + +say "Base packages: ${BASE_PACKAGES[*]}" +say "Build/runtime packages: ${DEV_PACKAGES[*]}" + +if ask_yes_no "Install required packages with dnf?" y; then + run_sudo dnf install -y "${BASE_PACKAGES[@]}" "${DEV_PACKAGES[@]}" +fi + +REPO_PARENT_DEFAULT="$HOME/dev-repos" +REPO_PARENT="$(ask_value "Repository parent directory" "$REPO_PARENT_DEFAULT")" +REPO_URL_DEFAULT="https://github.com/pwr-Solaar/Solaar.git" +REPO_URL="$(ask_value "Git URL for Solaar" "$REPO_URL_DEFAULT")" +REPO_DIR_DEFAULT="$REPO_PARENT/Solaar" +REPO_DIR="$(ask_value "Local checkout directory" "$REPO_DIR_DEFAULT")" + +run_cmd mkdir -p "$REPO_PARENT" + +if [[ -d "$REPO_DIR/.git" ]]; then + say "Existing git checkout found at $REPO_DIR" + if ask_yes_no "Pull latest changes in this repository?" y; then + run_cmd git -C "$REPO_DIR" pull --ff-only + fi +else + run_cmd git clone "$REPO_URL" "$REPO_DIR" +fi + +say "Installing Solaar into user site-packages" +if ask_yes_no "Use upgrade mode for pip install?" n; then + run_cmd python3 -m pip install --user --upgrade "$REPO_DIR" +else + run_cmd python3 -m pip install --user "$REPO_DIR" +fi + +SOLAAR_BIN="$HOME/.local/bin/solaar" +if [[ ! -x "$SOLAAR_BIN" ]]; then + fail "Expected executable not found: $SOLAAR_BIN" +fi + +say "Installed binary: $SOLAAR_BIN" +run_cmd "$SOLAAR_BIN" --help >/dev/null + +if ask_yes_no "Add alias 'solaar=$SOLAAR_BIN' to ~/.bashrc if missing?" y; then + if grep -Fqx "alias solaar=\"$SOLAAR_BIN\"" "$HOME/.bashrc" 2>/dev/null; then + say "Alias already exists in ~/.bashrc" + else + printf '\n# Solaar user-local install\nalias solaar="%s"\n' "$SOLAAR_BIN" >> "$HOME/.bashrc" + say "Alias appended to ~/.bashrc" + fi +fi + +if ask_yes_no "Run 'solaar show' now for validation?" y; then + run_cmd "$SOLAAR_BIN" show || warn "'solaar show' returned a non-zero status." +fi + +if ask_yes_no "Run 'solaar config ' now?" n; then + DEVICE_NAME_DEFAULT="M720 Triathlon Multi-Device Mouse" + DEVICE_NAME="$(ask_value "Device name" "$DEVICE_NAME_DEFAULT")" + run_cmd "$SOLAAR_BIN" config "$DEVICE_NAME" || warn "'solaar config' returned a non-zero status." +fi + +if ask_yes_no "Run libinput debug-events for a specific /dev/input/eventX device?" n; then + EVENT_NODE="$(ask_value "Input event node" "/dev/input/eventX")" + warn "This is a live monitor and may run until interrupted (Ctrl+C)." + run_sudo libinput debug-events --device "$EVENT_NODE" +fi + +if ask_yes_no "Run keyd monitor (/usr/local/bin/keyd) if present?" n; then + if [[ -x /usr/local/bin/keyd ]]; then + warn "This is a live monitor and may run until interrupted (Ctrl+C)." + run_sudo /usr/local/bin/keyd monitor + else + warn "/usr/local/bin/keyd not found; skipping." + fi +fi + +say "Install workflow completed." +say "To use alias in current shell: source ~/.bashrc" +say "Evidence log saved at: $LOG_FILE"