diff --git a/.i3/config b/.i3/config index 83d8d54..de57186 100644 --- a/.i3/config +++ b/.i3/config @@ -53,6 +53,7 @@ bindsym $mod+Shift+c kill bindsym $mod+d exec i3-dmenu-desktop --dmenu='rofi -dmenu' bindsym $mod+F12 exec xscreensaver-command -lock +bindsym $mod+Shift+y exec xinput-toggle -r yubikey -n -e -t 10 # There also is the (new) i3-dmenu-desktop which only displays applications # shipping a .desktop file. It is a wrapper around dmenu, so you need that # installed. @@ -135,7 +136,7 @@ bindsym $mod+Shift+9 move container to workspace 9 bindsym $mod+Shift+0 move container to workspace 10 # reload the configuration file -bindsym $mod+Shift+y reload +bindsym $mod+Shift+t reload # restart i3 inplace (preserves your layout/session, can be used to upgrade i3) bindsym $mod+Shift+r restart # exit i3 (logs you out of your X session) diff --git a/.xinitrc b/.xinitrc index eb85b2c..8de13fe 100644 --- a/.xinitrc +++ b/.xinitrc @@ -34,6 +34,8 @@ if [ -f ~/.xrandrrc ]; then ~/.xrandrrc fi +./xinput-toggle -r yubikey -d + ~/.fehbg & if command -v compton &>/dev/null; then compton -b --config ~/.compton.conf & diff --git a/bin/xinput-toggle b/bin/xinput-toggle new file mode 100755 index 0000000..94529fe --- /dev/null +++ b/bin/xinput-toggle @@ -0,0 +1,181 @@ +#!/bin/bash + +debug() { + # DEBUG comes from the environment + if (( DEBUG )); then + printf '%s\n' "$@" >&2 + fi +} + +is_enabled() { + local id="${1?}" + enabled=$( + xinput list-props "$id" | + grep '\bDevice Enabled\b' | sed 's/.*\(.\)$/\1/' + ) + # xinput returns 0 for disabled and 1 for enabled, so we invert since we + # pass on 0 + return "$(( !enabled ))" +} + +should_disable() { + local id="${1?}" + local force_enable="${2?}" + local force_disable="${3?}" + + if (( force_enable )) && (( force_disable )); then + echo '-d and -e make no sense together' >&2 + exit 3 + fi + + if (( force_enable )); then + return 1 + elif (( force_disable )); then + return 0 + elif is_enabled "$id"; then + return 0 + else + return 1 + fi +} + +get_id_for_device_name() { + local name="${1?}" + xinput list "$name" | sed -n 's/.*id=\([0-9]\+\).*/\1/p' +} + +show_help() { + cat << EOF +Usage: ${0##*/} [-n] + +Enable and disable xinput devices. + + -d disable only, do not toggle + -e enable only, do not toggle + -h show this help page + -i XID only operate on device with xinput id XID + -r REGEX only operate on devices matching name REGEX + -n show results using notify-send in addition to stdout + -p print what we would do, but don't actually do it + -t SECONDS revert enable/disable after SECONDS seconds, ie. if you were + enabling, after SECONDS seconds it will be disabled again. + SECONDS must be an integer greater than 0 +EOF +} + +act_on_device() { + local print="${1?}" + local notify="${2?}" + local timeout="${3?}" + local xinput_action="${4?}" + local our_next_flag="${5?}" + local id="${6?}" + + if (( print )); then + echo "Would $xinput_action device with id $id" + else + xinput -"$xinput_action" "$id" + + if (( notify )); then + notify-send "${xinput_action^}d device with id $id" + fi + + if (( timeout )); then + debug "Added timeout $timeout" + { + sleep "$timeout" + # TODO: Make args_without_timeour_or_force non-global (sigh, + # shell makes this difficult due to pass by value) + "$0" "${args_without_timeout_or_force[@]}" \ + "$our_next_flag" -i "$id" + } & + fi + fi +} + +notify=0 +force_enable=0 +force_disable=0 +timeout=0 +print=0 +only_xid=0 +input_ids=() +args_without_timeout_or_force=() + +while getopts dehi:npr:t: opt; do + # We need to get a list of args without timeout/force for when we execute + # timeout reversions. This is a blacklist of things we should not put in + # the array, since they force enable/disable/name or do the timeout itself. + case "$opt" in + d|e|t|r) + : # Blacklisted + ;; + *) + args_without_timeout_or_force+=( -"$opt" ) + if [[ $OPTARG ]]; then + args_without_timeout_or_force+=( "$OPTARG" ) + fi + ;; + esac + + case "$opt" in + 'd') force_disable=1 ;; + 'e') force_enable=1 ;; + 'n') notify=1 ;; + 'i') only_xid="$OPTARG" ;; + 'h') + show_help + exit 0 + ;; + 'p') print=1 ;; + 'r') regex="$OPTARG" ;; + 't') timeout="$OPTARG" ;; + '?') + show_help >&2 + exit 1 + ;; + esac +done + +if (( only_xid )) && [[ "$regex" ]]; then + echo '-r and -i cannot be currently used together' >&2 + exit 4 +elif ! (( only_xid )) && ! [[ "$regex" ]]; then + echo 'either -r or -i must be passed to filter devices' >&2 + exit 5 +fi + +if (( only_xid )); then + input_ids=( "$only_xid" ) +else + mapfile -t matched_device_names < <( + xinput list | + sed -n 's/.*↳ \(.\+\)id=.*\[slave.*/\1/p' | + sed 's/[\t ]*$//' | + grep -i -- "$regex" + ) + + debug 'Matched device names:' "${matched_device_names[@]}" + + for name in "${matched_device_names[@]}"; do + input_ids+=( "$(get_id_for_device_name "$name")" ) + done +fi + +if (( "${#input_ids[@]}" == 0 )); then + msg='No matching devices found' + echo "$msg" >&2 + (( notify )) && notify-send "$msg" + exit 2 +fi + +for id in "${input_ids[@]}"; do + if should_disable "$id" "$force_enable" "$force_disable"; then + act_on_device "$print" "$notify" "$timeout" disable -e "$id" + else + act_on_device "$print" "$notify" "$timeout" enable -d "$id" + fi +done + +# We may have queued some timeout reversion jobs +wait