diff --git a/scripts/rofi-bluetooth b/scripts/rofi-bluetooth new file mode 100755 index 0000000..626704d --- /dev/null +++ b/scripts/rofi-bluetooth @@ -0,0 +1,311 @@ +#!/usr/bin/env bash +# __ _ _ _ _ _ _ +# _ __ ___ / _(_) | |__ | |_ _ ___| |_ ___ ___ | |_| |__ +# | '__/ _ \| |_| |_____| '_ \| | | | |/ _ \ __/ _ \ / _ \| __| '_ \ +# | | | (_) | _| |_____| |_) | | |_| | __/ || (_) | (_) | |_| | | | +# |_| \___/|_| |_| |_.__/|_|\__,_|\___|\__\___/ \___/ \__|_| |_| +# +# Author: Nick Clyde (clydedroid) +# +# A script that generates a rofi menu that uses bluetoothctl to +# connect to bluetooth devices and display status info. +# +# Inspired by networkmanager-dmenu (https://github.com/firecat53/networkmanager-dmenu) +# Thanks to x70b1 (https://github.com/polybar/polybar-scripts/tree/master/polybar-scripts/system-bluetooth-bluetoothctl) +# +# Depends on: +# Arch repositories: rofi, bluez-utils (contains bluetoothctl) + +# Constants +divider="---------" +goback="Back" + +# Checks if bluetooth controller is powered on +power_on() { + if bluetoothctl show | grep -q "Powered: yes"; then + return 0 + else + return 1 + fi +} + +# Toggles power state +toggle_power() { + if power_on; then + bluetoothctl power off + show_menu + else + if rfkill list bluetooth | grep -q 'blocked: yes'; then + rfkill unblock bluetooth && sleep 3 + fi + bluetoothctl power on + show_menu + fi +} + +# Checks if controller is scanning for new devices +scan_on() { + if bluetoothctl show | grep -q "Discovering: yes"; then + echo "Scan: on" + return 0 + else + echo "Scan: off" + return 1 + fi +} + +# Toggles scanning state +toggle_scan() { + if scan_on; then + kill $(pgrep -f "bluetoothctl scan on") + bluetoothctl scan off + show_menu + else + bluetoothctl scan on & + echo "Scanning..." + sleep 5 + show_menu + fi +} + +# Checks if controller is able to pair to devices +pairable_on() { + if bluetoothctl show | grep -q "Pairable: yes"; then + echo "Pairable: on" + return 0 + else + echo "Pairable: off" + return 1 + fi +} + +# Toggles pairable state +toggle_pairable() { + if pairable_on; then + bluetoothctl pairable off + show_menu + else + bluetoothctl pairable on + show_menu + fi +} + +# Checks if controller is discoverable by other devices +discoverable_on() { + if bluetoothctl show | grep -q "Discoverable: yes"; then + echo "Discoverable: on" + return 0 + else + echo "Discoverable: off" + return 1 + fi +} + +# Toggles discoverable state +toggle_discoverable() { + if discoverable_on; then + bluetoothctl discoverable off + show_menu + else + bluetoothctl discoverable on + show_menu + fi +} + +# Checks if a device is connected +device_connected() { + device_info=$(bluetoothctl info "$1") + if echo "$device_info" | grep -q "Connected: yes"; then + return 0 + else + return 1 + fi +} + +# Toggles device connection +toggle_connection() { + if device_connected $1; then + bluetoothctl disconnect $1 + device_menu "$device" + else + bluetoothctl connect $1 + device_menu "$device" + fi +} + +# Checks if a device is paired +device_paired() { + device_info=$(bluetoothctl info "$1") + if echo "$device_info" | grep -q "Paired: yes"; then + echo "Paired: yes" + return 0 + else + echo "Paired: no" + return 1 + fi +} + +# Toggles device paired state +toggle_paired() { + if device_paired $1; then + bluetoothctl remove $1 + device_menu "$device" + else + bluetoothctl pair $1 + device_menu "$device" + fi +} + +# Checks if a device is trusted +device_trusted() { + device_info=$(bluetoothctl info "$1") + if echo "$device_info" | grep -q "Trusted: yes"; then + echo "Trusted: yes" + return 0 + else + echo "Trusted: no" + return 1 + fi +} + +# Toggles device connection +toggle_trust() { + if device_trusted $1; then + bluetoothctl untrust $1 + device_menu "$device" + else + bluetoothctl trust $1 + device_menu "$device" + fi +} + +# Prints a short string with the current bluetooth status +# Useful for status bars like polybar, etc. +print_status() { + if power_on; then + printf '' + + mapfile -t paired_devices < <(bluetoothctl paired-devices | grep Device | cut -d ' ' -f 2) + counter=0 + + for device in "${paired_devices[@]}"; do + if device_connected $device; then + device_alias=$(bluetoothctl info $device | grep "Alias" | cut -d ' ' -f 2-) + + if [ $counter -gt 0 ]; then + printf ", %s" "$device_alias" + else + printf " %s" "$device_alias" + fi + + ((counter++)) + fi + done + printf "\n" + else + echo "" + fi +} + +# A submenu for a specific device that allows connecting, pairing, and trusting +device_menu() { + device=$1 + + # Get device name and mac address + device_name=$(echo $device | cut -d ' ' -f 3-) + mac=$(echo $device | cut -d ' ' -f 2) + + # Build options + if device_connected $mac; then + connected="Connected: yes" + else + connected="Connected: no" + fi + paired=$(device_paired $mac) + trusted=$(device_trusted $mac) + options="$connected\n$paired\n$trusted\n$divider\n$goback\nExit" + + # Open rofi menu, read chosen option + chosen="$(echo -e "$options" | $rofi_command "$device_name")" + + # Match chosen option to command + case $chosen in + "" | $divider) + echo "No option chosen." + ;; + $connected) + toggle_connection $mac + ;; + $paired) + toggle_paired $mac + ;; + $trusted) + toggle_trust $mac + ;; + $goback) + show_menu + ;; + esac +} + +# Opens a rofi menu with current bluetooth status and options to connect +show_menu() { + # Get menu options + if power_on; then + power="Power: on" + + # Human-readable names of devices, one per line + # If scan is off, will only list paired devices + devices=$(bluetoothctl devices | grep Device | cut -d ' ' -f 3-) + + # Get controller flags + scan=$(scan_on) + pairable=$(pairable_on) + discoverable=$(discoverable_on) + + # Options passed to rofi + options="$devices\n$divider\n$power\n$scan\n$pairable\n$discoverable\nExit" + else + power="Power: off" + options="$power\nExit" + fi + + # Open rofi menu, read chosen option + chosen="$(echo -e "$options" | $rofi_command "Bluetooth")" + + # Match chosen option to command + case $chosen in + "" | $divider) + echo "No option chosen." + ;; + $power) + toggle_power + ;; + $scan) + toggle_scan + ;; + $discoverable) + toggle_discoverable + ;; + $pairable) + toggle_pairable + ;; + *) + device=$(bluetoothctl devices | grep "$chosen") + # Open a submenu if a device is selected + if [[ $device ]]; then device_menu "$device"; fi + ;; + esac +} + +# Rofi command to pipe into, can add any options here +rofi_command="rofi -dmenu -p" + +case "$1" in + --status) + print_status + ;; + *) + show_menu + ;; +esac diff --git a/scripts/rofi-bluetooth.desktop b/scripts/rofi-bluetooth.desktop new file mode 100755 index 0000000..d9ba427 --- /dev/null +++ b/scripts/rofi-bluetooth.desktop @@ -0,0 +1,311 @@ +#!/usr/bin/env bash +# __ _ _ _ _ _ _ +# _ __ ___ / _(_) | |__ | |_ _ ___| |_ ___ ___ | |_| |__ +# | '__/ _ \| |_| |_____| '_ \| | | | |/ _ \ __/ _ \ / _ \| __| '_ \ +# | | | (_) | _| |_____| |_) | | |_| | __/ || (_) | (_) | |_| | | | +# |_| \___/|_| |_| |_.__/|_|\__,_|\___|\__\___/ \___/ \__|_| |_| +# +# Author: Nick Clyde (clydedroid) +# +# A script that generates a rofi menu that uses bluetoothctl to +# connect to bluetooth devices and display status info. +# +# Inspired by networkmanager-dmenu (https://github.com/firecat53/networkmanager-dmenu) +# Thanks to x70b1 (https://github.com/polybar/polybar-scripts/tree/master/polybar-scripts/system-bluetooth-bluetoothctl) +# +# Depends on: +# Arch repositories: rofi, bluez-utils (contains bluetoothctl) + +# Constants +divider="---------" +goback="Back" + +# Checks if bluetooth controller is powered on +power_on() { + if bluetoothctl show | grep -q "Powered: yes"; then + return 0 + else + return 1 + fi +} + +# Toggles power state +toggle_power() { + if power_on; then + bluetoothctl power off + show_menu + else + if rfkill list bluetooth | grep -q 'blocked: yes'; then + rfkill unblock bluetooth && sleep 3 + fi + bluetoothctl power on + show_menu + fi +} + +# Checks if controller is scanning for new devices +scan_on() { + if bluetoothctl show | grep -q "Discovering: yes"; then + echo "Scan: on" + return 0 + else + echo "Scan: off" + return 1 + fi +} + +# Toggles scanning state +toggle_scan() { + if scan_on; then + kill $(pgrep -f "bluetoothctl scan on") + bluetoothctl scan off + show_menu + else + bluetoothctl scan on & + echo "Scanning..." + sleep 5 + show_menu + fi +} + +# Checks if controller is able to pair to devices +pairable_on() { + if bluetoothctl show | grep -q "Pairable: yes"; then + echo "Pairable: on" + return 0 + else + echo "Pairable: off" + return 1 + fi +} + +# Toggles pairable state +toggle_pairable() { + if pairable_on; then + bluetoothctl pairable off + show_menu + else + bluetoothctl pairable on + show_menu + fi +} + +# Checks if controller is discoverable by other devices +discoverable_on() { + if bluetoothctl show | grep -q "Discoverable: yes"; then + echo "Discoverable: on" + return 0 + else + echo "Discoverable: off" + return 1 + fi +} + +# Toggles discoverable state +toggle_discoverable() { + if discoverable_on; then + bluetoothctl discoverable off + show_menu + else + bluetoothctl discoverable on + show_menu + fi +} + +# Checks if a device is connected +device_connected() { + device_info=$(bluetoothctl info "$1") + if echo "$device_info" | grep -q "Connected: yes"; then + return 0 + else + return 1 + fi +} + +# Toggles device connection +toggle_connection() { + if device_connected $1; then + bluetoothctl disconnect $1 + device_menu "$device" + else + bluetoothctl connect $1 + device_menu "$device" + fi +} + +# Checks if a device is paired +device_paired() { + device_info=$(bluetoothctl info "$1") + if echo "$device_info" | grep -q "Paired: yes"; then + echo "Paired: yes" + return 0 + else + echo "Paired: no" + return 1 + fi +} + +# Toggles device paired state +toggle_paired() { + if device_paired $1; then + bluetoothctl remove $1 + device_menu "$device" + else + bluetoothctl pair $1 + device_menu "$device" + fi +} + +# Checks if a device is trusted +device_trusted() { + device_info=$(bluetoothctl info "$1") + if echo "$device_info" | grep -q "Trusted: yes"; then + echo "Trusted: yes" + return 0 + else + echo "Trusted: no" + return 1 + fi +} + +# Toggles device connection +toggle_trust() { + if device_trusted $1; then + bluetoothctl untrust $1 + device_menu "$device" + else + bluetoothctl trust $1 + device_menu "$device" + fi +} + +# Prints a short string with the current bluetooth status +# Useful for status bars like polybar, etc. +print_status() { + if power_on; then + printf '' + + mapfile -t paired_devices < <(bluetoothctl paired-devices | grep Device | cut -d ' ' -f 2) + counter=0 + + for device in "${paired_devices[@]}"; do + if device_connected $device; then + device_alias=$(bluetoothctl info $device | grep "Alias" | cut -d ' ' -f 2-) + + if [ $counter -gt 0 ]; then + printf ", %s" "$device_alias" + else + printf " %s" "$device_alias" + fi + + ((counter++)) + fi + done + printf "\n" + else + echo "" + fi +} + +# A submenu for a specific device that allows connecting, pairing, and trusting +device_menu() { + device=$1 + + # Get device name and mac address + device_name=$(echo $device | cut -d ' ' -f 3-) + mac=$(echo $device | cut -d ' ' -f 2) + + # Build options + if device_connected $mac; then + connected="Connected: yes" + else + connected="Connected: no" + fi + paired=$(device_paired $mac) + trusted=$(device_trusted $mac) + options="$connected\n$paired\n$trusted\n$divider\n$goback\nExit" + + # Open rofi menu, read chosen option + chosen="$(echo -e "$options" | $rofi_command "$device_name")" + + # Match chosen option to command + case $chosen in + "" | $divider) + echo "No option chosen." + ;; + $connected) + toggle_connection $mac + ;; + $paired) + toggle_paired $mac + ;; + $trusted) + toggle_trust $mac + ;; + $goback) + show_menu + ;; + esac +} + +# Opens a rofi menu with current bluetooth status and options to connect +show_menu() { + # Get menu options + if power_on; then + power="Power: on" + + # Human-readable names of devices, one per line + # If scan is off, will only list paired devices + devices=$(bluetoothctl devices | grep Device | cut -d ' ' -f 3-) + + # Get controller flags + scan=$(scan_on) + pairable=$(pairable_on) + discoverable=$(discoverable_on) + + # Options passed to rofi + options="$devices\n$divider\n$power\n$scan\n$pairable\n$discoverable\nExit" + else + power="Power: off" + options="$power\nExit" + fi + + # Open rofi menu, read chosen option + chosen="$(echo -e "$options" | $rofi_command "Bluetooth")" + + # Match chosen option to command + case $chosen in + "" | $divider) + echo "No option chosen." + ;; + $power) + toggle_power + ;; + $scan) + toggle_scan + ;; + $discoverable) + toggle_discoverable + ;; + $pairable) + toggle_pairable + ;; + *) + device=$(bluetoothctl devices | grep "$chosen") + # Open a submenu if a device is selected + if [[ $device ]]; then device_menu "$device"; fi + ;; + esac +} + +# Rofi command to pipe into, can add any options here +rofi_command="rofi -config ~/SudacodeRice/rofi/rofidmenu.rasi -dmenu -p" + +case "$1" in + --status) + print_status + ;; + *) + show_menu + ;; +esac