Hi!
Using i3wm? Have a fancy keyboard with a nice CapsLock LED, but never actually press CapsLock (not as a remapped Ctrl)?
Me too! Let's convert it into a keyboard layout indicator then!
You can use method described below for things other than keyboard layout and for other LEDs. Happy hacking!
Requirements
- 
i3- targeted window manager, we will use its IPC to subscribe to window change event
- 
perlwithAnyEvent::I3- to communicate with i3 IPC
- 
bashwithgrep,sedandxargsutils
- 
brightnessctl- to control LED
- 
xkb-switch- to monitor keyboard layout change event
- 
i3-subscribe.pl- perl script for i3 IPC (source)
- 
toggle_capslock_led.sh- our bash script for toggling LED
- 
i3ipc_capslock_led.sh- our bash script to start listening for window and layout changes
All scripts below are supposed to be put into ~/Scripts directory - change this path if you need to.
General method
We have a bash script, which checks current keyboard layout and turns the LED on when specified layout is active.
We call this script:
- when the layout changes
- when we go to other window (as each window has its own keyboard layout state)
This is the script (toggle_capslock_led.sh) with some comments inside:
#!/usr/bin/env bash
# Lights up capslock LED when specified layout is on.
# Works for LED on all connected keyboards (e.g. laptop's and external one).
# You can also set this to your specific input name, which can be found with: brightnessctl --list
# LED_NAMES="input7::capslock"
LED_NAMES=$(brightnessctl --list | grep '::capslock' | sed 's/Device .\(.*\). of.*/\1/g')
# The layout on which we want LED to be on.
# Get available layout names with: xkb-switch -l
ON_LAYOUT="us"
CURRENT_LAYOUT=$(xkb-switch -p)
VALUE=0
if [[ "$CURRENT_LAYOUT" == "$ON_LAYOUT" ]]; then
  VALUE=1
fi
echo "$LED_NAMES" | while read name; do
  brightnessctl --device="$name" set $VALUE > /dev/null
done
Talking to i3 IPC
Below is the i3-subscribe.pl script for talking to i3 with perl.
To run it you will need to install AnyEvent::I3 for perl.
If you are on NixOS - leave script as it is (it uses nix-shell with perl540Packages.AnyEventI3).
If you aren't on NixOS - replace first two lines with this one: #!/usr/bin/env perl.
#!/usr/bin/env nix-shell
#!nix-shell -i perl -p perl perl540Packages.AnyEventI3
# Subscribe to i3wm events via i3ipc.
# Source: https://faq.i3wm.org/question/5721/how-do-i-subscribe-to-i3-events-using-bash-easily.1.html
#
# Usage example for bash:
# i3subscribe window workspace | while read -r event; do
# ...
# done
BEGIN { $| = 1 } # flush \n
use strict;
use warnings;
use Data::Dumper;
use AnyEvent::I3;
use v5.10;
my $i3 = i3();
$i3->connect->recv or die "Error connecting to i3";
sub subscribe {
    my $ev = $_[0];
    my $dump = $_[1];
    if($i3->subscribe({
        $ev => sub {
            my ($msg) = @_;
            say "$ev:$msg->{'change'}";
            if($dump) {
                print Dumper($msg);
            }
        }
    })->recv->{success}) {
        say "Successfully subscribed to $ev-event";
    }
}
my $nextArg = shift;
if(!$nextArg) {
    say "Subscribe to i3-events";
    say "Usage:   $0 workspace|output|mode|window|barconfig_update|binding [dump]";
    say "Example: $0 workspace dump window binding dump";
    exit 1;
}
while($nextArg) {
    my $arg = $nextArg;
    $nextArg = shift;
    my $dump = 0;
    if($nextArg and $nextArg eq "dump") {
        $dump = 1;
        $nextArg = shift;
    }
    subscribe("$arg", $dump);
}
AE::cv->recv;
Toggle LED
This is i3ipc_capslock_led.sh which starts needed listeners - add this script to autostart and that's it:
#!/usr/bin/env bash
# Executes `toggle_capslock_led.sh` script on window change.
# Source: https://faq.i3wm.org/question/5721/how-do-i-subscribe-to-i3-events-using-bash-easily.1.html
# Run LED switcher on layout change
xkb-switch -W | xargs -I{} ~/Scripts/toggle_capslock_led.sh &
# Run LED switcher on window or workspace change
~/Scripts/i3-subscribe.pl window workspace | while read -r event; do
  ~/Scripts/toggle_capslock_led.sh
done
Bye!
 

 
    
Top comments (0)