#!/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