Add per-tool settings and gesture customization

This commit is contained in:
ajp_anton
2026-09-05 05:02:34 +00:00
parent d6f30c5735
commit 38142b9499
26 changed files with 1383 additions and 83 deletions
+192
View File
@@ -0,0 +1,192 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MIT
set -euo pipefail
root=${TOUCHPAD_HOLD_TAP_TEST_ROOT:-}
config_file="$root/etc/touchpad-hold-tap.conf"
override_file="$root/etc/libinput/plugins/90-touchpad-hold-tap.lua"
template_file="$root/usr/lib64/libinput/plugins/90-touchpad-hold-tap.lua"
if [[ ! -e $template_file ]]; then
template_file="$root/usr/lib/libinput/plugins/90-touchpad-hold-tap.lua"
fi
minimum_anchor_age_ms=100
minimum_pause_ms=100
minimum_tap_ms=10
maximum_tap_ms=150
output_event=BTN_MIDDLE
die()
{
printf 'touchpad-hold-tap-config: %s\n' "$*" >&2
exit 1
}
require_root()
{
if [[ -z $root && $EUID -ne 0 ]]; then
die "this operation must be run as root"
fi
}
validate()
{
[[ $minimum_anchor_age_ms =~ ^[0-9]+$ ]] || die "minimum anchor age must be an integer"
[[ $minimum_pause_ms =~ ^[0-9]+$ ]] || die "minimum pause must be an integer"
[[ $minimum_tap_ms =~ ^[0-9]+$ ]] || die "minimum tap duration must be an integer"
[[ $maximum_tap_ms =~ ^[0-9]+$ ]] || die "maximum tap duration must be an integer"
(( minimum_anchor_age_ms <= 2000 )) || die "minimum anchor age must not exceed 2000 ms"
(( minimum_pause_ms <= 2000 )) || die "minimum pause must not exceed 2000 ms"
(( maximum_tap_ms >= 1 && minimum_tap_ms <= maximum_tap_ms && maximum_tap_ms <= 2000 )) || \
die "tap durations must be between 0 and 2000 ms, with a positive maximum and minimum not exceeding maximum"
[[ $output_event =~ ^(BTN|KEY)_[A-Z0-9_]+$ ]] || \
die "output event must be an evdev BTN_* or KEY_* name"
}
read_config()
{
if [[ ! -r $config_file ]]; then
return 0
fi
while IFS='=' read -r key value; do
case $key in
MINIMUM_ANCHOR_AGE_MS) minimum_anchor_age_ms=$value ;;
MINIMUM_PAUSE_MS) minimum_pause_ms=$value ;;
MINIMUM_TAP_MS) minimum_tap_ms=$value ;;
MAXIMUM_TAP_MS) maximum_tap_ms=$value ;;
OUTPUT_EVENT) output_event=$value ;;
''|'#'*) ;;
*) die "unknown setting: $key" ;;
esac
done < "$config_file"
validate
}
write_config()
{
mkdir -p "$(dirname -- "$config_file")"
local temporary
temporary=$(mktemp "${config_file}.XXXXXX")
trap 'rm -f -- "$temporary"' RETURN
printf 'MINIMUM_ANCHOR_AGE_MS=%s\nMINIMUM_PAUSE_MS=%s\nMINIMUM_TAP_MS=%s\nMAXIMUM_TAP_MS=%s\nOUTPUT_EVENT=%s\n' \
"$minimum_anchor_age_ms" "$minimum_pause_ms" "$minimum_tap_ms" "$maximum_tap_ms" \
"$output_event" > "$temporary"
chmod 0644 "$temporary"
mv -f -- "$temporary" "$config_file"
trap - RETURN
}
write_override()
{
[[ -r $template_file ]] || die "installed plugin was not found"
mkdir -p "$(dirname -- "$override_file")"
local temporary
temporary=$(mktemp "${override_file}.XXXXXX")
trap 'rm -f -- "$temporary"' RETURN
awk -v age="$minimum_anchor_age_ms" -v pause="$minimum_pause_ms" \
-v mintap="$minimum_tap_ms" \
-v maxtap="$maximum_tap_ms" \
-v output="$output_event" '
/^local settings = / {
print "local settings = {"
print " minimum_anchor_age_ms = " age ","
print " minimum_pause_ms = " pause ","
print " minimum_tap_ms = " mintap ","
print " maximum_tap_ms = " maxtap ","
print " output_event = \"" output "\","
print "}"
replaced = 1
next
}
{ print }
END { if (!replaced) exit 1 }
' "$template_file" > "$temporary" || die "installed plugin has an unsupported format"
chmod 0644 "$temporary"
mv -f -- "$temporary" "$override_file"
trap - RETURN
}
usage()
{
cat <<'EOF'
Usage:
touchpad-hold-tap-config show
touchpad-hold-tap-config set [--minimum-anchor-age-ms N] [--minimum-pause-ms N] [--minimum-tap-ms N] [--maximum-tap-ms N] [--output-event NAME]
touchpad-hold-tap-config reset
touchpad-hold-tap-config refresh
EOF
}
command=${1:-}
case $command in
show)
[[ $# -eq 1 ]] || die "show takes no arguments"
read_config
printf 'MINIMUM_ANCHOR_AGE_MS=%s\nMINIMUM_PAUSE_MS=%s\nMINIMUM_TAP_MS=%s\nMAXIMUM_TAP_MS=%s\nOUTPUT_EVENT=%s\n' \
"$minimum_anchor_age_ms" "$minimum_pause_ms" "$minimum_tap_ms" "$maximum_tap_ms" \
"$output_event"
;;
set)
shift
read_config
while [[ $# -gt 0 ]]; do
case $1 in
--minimum-anchor-age-ms)
[[ $# -ge 2 ]] || die "$1 requires a value"
minimum_anchor_age_ms=$2
shift 2
;;
--minimum-pause-ms)
[[ $# -ge 2 ]] || die "$1 requires a value"
minimum_pause_ms=$2
shift 2
;;
--minimum-tap-ms)
[[ $# -ge 2 ]] || die "$1 requires a value"
minimum_tap_ms=$2
shift 2
;;
--maximum-tap-ms)
[[ $# -ge 2 ]] || die "$1 requires a value"
maximum_tap_ms=$2
shift 2
;;
--output-event)
[[ $# -ge 2 ]] || die "$1 requires a value"
output_event=$2
shift 2
;;
*) die "unknown option: $1" ;;
esac
done
require_root
validate
write_config
write_override
;;
reset)
[[ $# -eq 1 ]] || die "reset takes no arguments"
require_root
rm -f -- "$config_file" "$override_file"
;;
refresh)
[[ $# -eq 1 ]] || die "refresh takes no arguments"
require_root
if [[ -e $config_file ]]; then
read_config
write_override
else
rm -f -- "$override_file"
fi
;;
-h|--help)
usage
;;
*)
usage >&2
exit 2
;;
esac