195 lines
5.8 KiB
Bash
195 lines
5.8 KiB
Bash
#!/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
|
|
temporary_config=
|
|
temporary_override=
|
|
trap '[[ -z $temporary_config ]] || rm -f -- "$temporary_config"; [[ -z $temporary_override ]] || rm -f -- "$temporary_override"' EXIT
|
|
|
|
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()
|
|
{
|
|
local name
|
|
for name in minimum_anchor_age_ms minimum_pause_ms minimum_tap_ms maximum_tap_ms; do
|
|
[[ ${!name} =~ ^0*([0-9]{1,4})$ ]] || die "${name//_/ } must be an integer between 0 and 2000"
|
|
printf -v "$name" '%d' "$((10#${BASH_REMATCH[1]}))"
|
|
(( ${!name} <= 2000 )) || die "${name//_/ } must not exceed 2000 ms"
|
|
done
|
|
(( maximum_tap_ms >= 1 && minimum_tap_ms <= maximum_tap_ms )) || \
|
|
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 || [[ -n $key ]]; 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
|
|
}
|
|
|
|
print_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"
|
|
}
|
|
|
|
write_config()
|
|
{
|
|
mkdir -p "$(dirname -- "$config_file")"
|
|
temporary_config=$(mktemp "${config_file}.XXXXXX")
|
|
print_config > "$temporary_config"
|
|
chmod 0644 "$temporary_config"
|
|
}
|
|
|
|
write_override()
|
|
{
|
|
[[ -r $template_file ]] || die "installed plugin was not found"
|
|
mkdir -p "$(dirname -- "$override_file")"
|
|
temporary_override=$(mktemp "${override_file}.XXXXXX")
|
|
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_override" || die "installed plugin has an unsupported format"
|
|
chmod 0644 "$temporary_override"
|
|
}
|
|
|
|
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
|
|
print_config
|
|
;;
|
|
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
|
|
# Stage both files before replacing either: a bad template must not save settings.
|
|
mv -f -- "$temporary_config" "$config_file"
|
|
mv -f -- "$temporary_override" "$override_file"
|
|
;;
|
|
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
|
|
mv -f -- "$temporary_override" "$override_file"
|
|
else
|
|
rm -f -- "$override_file"
|
|
fi
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
;;
|
|
*)
|
|
usage >&2
|
|
exit 2
|
|
;;
|
|
esac
|