└── btmenu /btmenu: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | _bluetoothctl() { 4 | LC_ALL=C timeout 30 bluetoothctl 5 | } 6 | 7 | mode=connect 8 | 9 | # Name -> MAC 10 | declare -A DEVICES 11 | while read -r _ mac name; do 12 | DEVICES["$name"]=$mac 13 | done < <(echo "devices" | _bluetoothctl | awk '$1 == "Device"') 14 | 15 | notify() { 16 | local msg 17 | local is_error 18 | 19 | msg=${1?BUG: no message} 20 | is_error=${2:-0} 21 | 22 | if command -v notify-send >/dev/null 2>&1; then 23 | notify-send "btmenu" "$msg" # TODO: escaping 24 | fi 25 | 26 | if (( is_error )); then 27 | printf 'ERROR: %s\n' "$msg" >&2 28 | else 29 | printf '%s\n' "$msg" 30 | fi 31 | } 32 | 33 | execute_mode() { 34 | local mode 35 | local name 36 | local mac 37 | local preposition 38 | local expected_to_connect 39 | local retries 40 | 41 | mode=${1?BUG: missing mode} 42 | retries=15 43 | 44 | case $mode in 45 | connect) 46 | preposition=to 47 | expected_to_connect=yes 48 | ;; 49 | disconnect) 50 | preposition=from 51 | expected_to_connect=no 52 | ;; 53 | esac 54 | 55 | if ! (( ${#DEVICES[@]} )); then 56 | notify "No devices found. Are they registered with D-Bus?" 1 57 | return 2 58 | fi 59 | 60 | name=$(printf '%s\n' "${!DEVICES[@]}" | dmenu -p "btmenu" "${dmenu_args[@]}") 61 | [[ $name ]] || return 62 | mac=${DEVICES["$name"]} 63 | 64 | notify "Attempting to $mode $preposition $name" 65 | 66 | while (( retries-- )); do 67 | printf 'power on\n%s %s\n' "$mode" "$mac" | _bluetoothctl 68 | if printf 'info %s\n' "$mac" | 69 | _bluetoothctl | 70 | grep -Pq '^[\t ]+Connected: '"$expected_to_connect"; then 71 | notify "${mode^}ed $preposition $name" 72 | return 0 73 | fi 74 | sleep 1 75 | done 76 | 77 | ret="$?" 78 | notify "Failed to $mode $preposition $name" 1 79 | return "$ret" 80 | } 81 | 82 | i=2 83 | 84 | for arg do 85 | if [[ $arg == :: ]]; then 86 | dmenu_args=( "${@:$i}" ) 87 | break 88 | fi 89 | 90 | case "$arg" in 91 | -d) mode=disconnect ;; 92 | esac 93 | 94 | (( i++ )) 95 | done 96 | 97 | execute_mode "$mode" 98 | --------------------------------------------------------------------------------