#!/usr/bin/env perl # # Quick bluetooth device manager. Finds already paired devices and shows a menu # (fzf) to choose which one to connect to or disconnect from. ################################################################################ use feature 'signatures'; use POSIX qw(isatty); # In: $type : str ('Paired', 'Bonded', 'Trusted', 'Connected') # Out: %devs : hash{name:str => mac:str} sub get_bt_devices($type) { my @devlines = `bluetoothctl devices $type | grep '^Device'`; chomp foreach @devlines; my %devs; foreach my $devline (@devlines) { # $devline is like: 'Device DE:E4:38:E5:CF:DC MX Master 3S' my (undef, $mac, $name) = split ' ', $devline, 3; $devs{$name} = $mac; } return \%devs; } # Globals my $PAIRED = get_bt_devices 'Paired'; my $CONNECTED = get_bt_devices 'Connected'; my $MENULINES = join '', map { my $connected_str = $CONNECTED->{$_} ? ' (connected)' : ''; "$_$connected_str\n" } (sort keys %$PAIRED); chomp $MENULINES; sub get_selection($selector) { my $selname = `echo '$MENULINES' | $selector` =~ s/ \(connected\)$//r || exit; chomp $selname; return {name => $selname, mac => $PAIRED->{$selname}}; } sub btconnect($selector) { my $sel = get_selection($selector); my $out; if ($CONNECTED->{$sel->{name}}) { print "Disconnecting from '$sel->{name}' ($sel->{mac})... "; $out = `bluetoothctl disconnect $sel->{mac}`; } else { print "Connecting to '$sel->{name}' ($sel->{mac})... "; $out = `bluetoothctl connect $sel->{mac}`; } print $? ? "ERROR:\n\n$out\n" : "done\n"; } if (isatty(STDIN)) { # Show menu (fzf) and connect using the CLI my $query = join ' ', @ARGV; btconnect("fzf -q '$query'"); } else { # Show menu (wmenu/dmenu) and connect using the GUI btconnect($ENV{WAYLAND_DISPLAY} ? 'wmenu -i' : 'dmenu -i'); }