three-finger-drag.sh
· 4.2 KiB · Bash
Sin formato
#!/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" <<EOF_RULE
# Apple bcm5974 touchpad and uinput access for the desktop user.
ACTION=="add|change", SUBSYSTEM=="input", KERNEL=="event*", ATTRS{name}=="bcm5974", OWNER="$(id -un)", MODE="0600"
ACTION=="add|change", SUBSYSTEM=="misc", KERNEL=="uinput", OWNER="$(id -un)", MODE="0600"
EOF_RULE
sudo install -m 0644 "$rule_tmp" "$udev_rule"
sudo modprobe uinput
printf 'uinput\n' | sudo tee /etc/modules-load.d/three-finger-drag.conf >/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'
| 1 | #!/usr/bin/env bash |
| 2 | # Debian 13 KDE Wayland — macOS-style three-finger drag on bcm5974 trackpads. |
| 3 | # Source: https://github.com/lmr97/linux-3-finger-drag |
| 4 | set -Eeuo pipefail |
| 5 | |
| 6 | if (( EUID == 0 )); then |
| 7 | echo 'Run as your desktop user, without sudo.' >&2 |
| 8 | echo 'The script will request sudo only for system-wide changes.' >&2 |
| 9 | exit 1 |
| 10 | fi |
| 11 | |
| 12 | command -v sudo >/dev/null || { echo 'sudo is required.' >&2; exit 1; } |
| 13 | command -v systemctl >/dev/null || { echo 'systemd is required.' >&2; exit 1; } |
| 14 | if ! grep -qs 'bcm5974' /proc/bus/input/devices; then |
| 15 | echo 'Warning: bcm5974 trackpad not detected; this setup targets Apple bcm5974.' >&2 |
| 16 | read -r -p 'Continue anyway? [y/N] ' reply |
| 17 | [[ "$reply" =~ ^[Yy]$ ]] || exit 1 |
| 18 | fi |
| 19 | |
| 20 | sudo -v |
| 21 | sudo apt-get update |
| 22 | sudo apt-get install -y git build-essential pkg-config libudev-dev libevdev-dev curl ca-certificates acl |
| 23 | |
| 24 | # rustup is installed per user so that Cargo does not run as root. |
| 25 | if ! command -v cargo >/dev/null 2>&1; then |
| 26 | echo 'Installing Rust via rustup (official installer)...' |
| 27 | curl --proto '=https' --tlsv1.2 -fsSL https://sh.rustup.rs -o "${TMPDIR:-/tmp}/rustup-3fd-$$.sh" |
| 28 | sh "${TMPDIR:-/tmp}/rustup-3fd-$$.sh" -y --profile minimal |
| 29 | rm -f "${TMPDIR:-/tmp}/rustup-3fd-$$.sh" |
| 30 | fi |
| 31 | export PATH="$HOME/.cargo/bin:$PATH" |
| 32 | command -v cargo >/dev/null || { echo 'Cargo is not available.' >&2; exit 1; } |
| 33 | |
| 34 | source_dir="$HOME/linux-3-finger-drag" |
| 35 | if [[ -d "$source_dir/.git" ]]; then |
| 36 | echo "Using existing checkout: $source_dir" |
| 37 | else |
| 38 | [[ ! -e "$source_dir" ]] || { echo "Path exists but is not a git checkout: $source_dir" >&2; exit 1; } |
| 39 | git clone https://github.com/lmr97/linux-3-finger-drag.git "$source_dir" |
| 40 | fi |
| 41 | |
| 42 | cd "$source_dir" |
| 43 | # Pin the version used successfully on this machine, if its tag exists. |
| 44 | if git rev-parse -q --verify 'refs/tags/v2.0.0' >/dev/null; then |
| 45 | git checkout --detach v2.0.0 |
| 46 | elif git rev-parse -q --verify 'refs/tags/2.0.0' >/dev/null; then |
| 47 | git checkout --detach 2.0.0 |
| 48 | else |
| 49 | echo 'Warning: no local v2.0.0 tag; building the existing checkout.' >&2 |
| 50 | fi |
| 51 | cargo build --release |
| 52 | [[ -x target/release/linux-3-finger-drag ]] || { echo 'Expected binary not found.' >&2; exit 1; } |
| 53 | sudo install -m 0755 target/release/linux-3-finger-drag /usr/local/bin/linux-3-finger-drag |
| 54 | |
| 55 | mkdir -p "$HOME/.config/linux-3-finger-drag" "$HOME/.config/systemd/user" |
| 56 | config="$HOME/.config/linux-3-finger-drag/3fd-config.json" |
| 57 | if [[ ! -e "$config" ]]; then |
| 58 | cat > "$config" <<'JSON' |
| 59 | { |
| 60 | "acceleration": 1.0, |
| 61 | "dragEndDelay": 0, |
| 62 | "logFile": "stdout", |
| 63 | "logLevel": "info", |
| 64 | "entryDebounce": 50, |
| 65 | "probeDelay": 15, |
| 66 | "pressGrace": 75 |
| 67 | } |
| 68 | JSON |
| 69 | else |
| 70 | echo "Keeping existing config: $config" |
| 71 | fi |
| 72 | |
| 73 | # Match the device by name, not by unstable /dev/input/eventN. |
| 74 | # OWNER is used instead of RUN+=setfacl because the latter failed after reboot. |
| 75 | udev_rule='/etc/udev/rules.d/70-linux-3-finger-drag.rules' |
| 76 | rule_tmp="$(mktemp)" |
| 77 | trap 'rm -f "$rule_tmp"' EXIT |
| 78 | cat > "$rule_tmp" <<EOF_RULE |
| 79 | # Apple bcm5974 touchpad and uinput access for the desktop user. |
| 80 | ACTION=="add|change", SUBSYSTEM=="input", KERNEL=="event*", ATTRS{name}=="bcm5974", OWNER="$(id -un)", MODE="0600" |
| 81 | ACTION=="add|change", SUBSYSTEM=="misc", KERNEL=="uinput", OWNER="$(id -un)", MODE="0600" |
| 82 | EOF_RULE |
| 83 | sudo install -m 0644 "$rule_tmp" "$udev_rule" |
| 84 | |
| 85 | sudo modprobe uinput |
| 86 | printf 'uinput\n' | sudo tee /etc/modules-load.d/three-finger-drag.conf >/dev/null |
| 87 | sudo udevadm control --reload-rules |
| 88 | sudo udevadm trigger --action=change --subsystem-match=input --sysname-match='event*' |
| 89 | sudo udevadm trigger --action=change --subsystem-match=misc --sysname-match=uinput || true |
| 90 | |
| 91 | cat > "$HOME/.config/systemd/user/three-finger-drag.service" <<'SERVICE' |
| 92 | [Unit] |
| 93 | Description=macOS-like Three Finger Drag for Apple Trackpad |
| 94 | After=graphical-session.target |
| 95 | PartOf=graphical-session.target |
| 96 | |
| 97 | [Service] |
| 98 | Type=exec |
| 99 | ExecStart=/usr/local/bin/linux-3-finger-drag |
| 100 | Restart=on-failure |
| 101 | RestartSec=2 |
| 102 | |
| 103 | [Install] |
| 104 | WantedBy=graphical-session.target |
| 105 | SERVICE |
| 106 | |
| 107 | systemctl --user daemon-reload |
| 108 | systemctl --user enable three-finger-drag.service |
| 109 | systemctl --user restart three-finger-drag.service |
| 110 | |
| 111 | echo |
| 112 | echo '== Three-Finger Drag status ==' |
| 113 | systemctl --user --no-pager --full status three-finger-drag.service || true |
| 114 | echo |
| 115 | echo 'If permission errors appear, reboot and check:' |
| 116 | echo ' journalctl --user -u three-finger-drag.service -b --no-pager -n 50' |
| 117 |