#!/usr/bin/env bash # Debian 13 KDE Wayland — macOS-style three-finger drag on bcm5974 trackpads. # Source: https://github.com/lmr97/linux-3-finger-drag set -Eeuo pipefail if (( EUID == 0 )); then echo 'Run as your desktop user, without sudo.' >&2 echo 'The script will request sudo only for system-wide changes.' >&2 exit 1 fi command -v sudo >/dev/null || { echo 'sudo is required.' >&2; exit 1; } command -v systemctl >/dev/null || { echo 'systemd is required.' >&2; exit 1; } if ! grep -qs 'bcm5974' /proc/bus/input/devices; then echo 'Warning: bcm5974 trackpad not detected; this setup targets Apple bcm5974.' >&2 read -r -p 'Continue anyway? [y/N] ' reply [[ "$reply" =~ ^[Yy]$ ]] || exit 1 fi sudo -v sudo apt-get update sudo apt-get install -y git build-essential pkg-config libudev-dev libevdev-dev curl ca-certificates acl # rustup is installed per user so that Cargo does not run as root. if ! command -v cargo >/dev/null 2>&1; then echo 'Installing Rust via rustup (official installer)...' curl --proto '=https' --tlsv1.2 -fsSL https://sh.rustup.rs -o "${TMPDIR:-/tmp}/rustup-3fd-$$.sh" sh "${TMPDIR:-/tmp}/rustup-3fd-$$.sh" -y --profile minimal rm -f "${TMPDIR:-/tmp}/rustup-3fd-$$.sh" fi export PATH="$HOME/.cargo/bin:$PATH" command -v cargo >/dev/null || { echo 'Cargo is not available.' >&2; exit 1; } source_dir="$HOME/linux-3-finger-drag" if [[ -d "$source_dir/.git" ]]; then echo "Using existing checkout: $source_dir" else [[ ! -e "$source_dir" ]] || { echo "Path exists but is not a git checkout: $source_dir" >&2; exit 1; } git clone https://github.com/lmr97/linux-3-finger-drag.git "$source_dir" fi cd "$source_dir" # Pin the version used successfully on this machine, if its tag exists. if git rev-parse -q --verify 'refs/tags/v2.0.0' >/dev/null; then git checkout --detach v2.0.0 elif git rev-parse -q --verify 'refs/tags/2.0.0' >/dev/null; then git checkout --detach 2.0.0 else echo 'Warning: no local v2.0.0 tag; building the existing checkout.' >&2 fi cargo build --release [[ -x target/release/linux-3-finger-drag ]] || { echo 'Expected binary not found.' >&2; exit 1; } sudo install -m 0755 target/release/linux-3-finger-drag /usr/local/bin/linux-3-finger-drag mkdir -p "$HOME/.config/linux-3-finger-drag" "$HOME/.config/systemd/user" config="$HOME/.config/linux-3-finger-drag/3fd-config.json" if [[ ! -e "$config" ]]; then cat > "$config" <<'JSON' { "acceleration": 1.0, "dragEndDelay": 0, "logFile": "stdout", "logLevel": "info", "entryDebounce": 50, "probeDelay": 15, "pressGrace": 75 } JSON else echo "Keeping existing config: $config" fi # Match the device by name, not by unstable /dev/input/eventN. # OWNER is used instead of RUN+=setfacl because the latter failed after reboot. udev_rule='/etc/udev/rules.d/70-linux-3-finger-drag.rules' rule_tmp="$(mktemp)" trap 'rm -f "$rule_tmp"' EXIT cat > "$rule_tmp" </dev/null sudo udevadm control --reload-rules sudo udevadm trigger --action=change --subsystem-match=input --sysname-match='event*' sudo udevadm trigger --action=change --subsystem-match=misc --sysname-match=uinput || true cat > "$HOME/.config/systemd/user/three-finger-drag.service" <<'SERVICE' [Unit] Description=macOS-like Three Finger Drag for Apple Trackpad After=graphical-session.target PartOf=graphical-session.target [Service] Type=exec ExecStart=/usr/local/bin/linux-3-finger-drag Restart=on-failure RestartSec=2 [Install] WantedBy=graphical-session.target SERVICE systemctl --user daemon-reload systemctl --user enable three-finger-drag.service systemctl --user restart three-finger-drag.service echo echo '== Three-Finger Drag status ==' systemctl --user --no-pager --full status three-finger-drag.service || true echo echo 'If permission errors appear, reboot and check:' echo ' journalctl --user -u three-finger-drag.service -b --no-pager -n 50'