Add installation guide for Solaar on RHEL 10 (#3158)
* Add installation guide for Solaar on RHEL 10 Document steps to install and run Solaar on RHEL 10, including environment setup and troubleshooting. * Add interactive RHEL installer script
This commit is contained in:
parent
8cea17fc46
commit
9344466949
|
|
@ -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.
|
||||||
|
|
@ -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 <device name>' 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"
|
||||||
Loading…
Reference in New Issue