Search This Blog

Wednesday, August 18, 2010

Hotkey buttons and udev

As many notebooks out there mine has some hotkey buttons for (de)activate the wifi card, bluetooth controller, webcam, etc. With the buttons sometimes the notebook also has leds to indicate which hardware is activated at the moment, unfortunately my notebook only has leds for wifi and bluetooth, not for the webcam. More unfortunately yet the leds for wifi and bluetooth is the same led but with different color to indicate when only one of them are activated, but I must say Clevo, the manufacturer of my notebooks' barebone, did not make a good choice selecting the colors orange and green :-( It is very difficult to distinguish between the states wifi on / bluetooth off and wifi off / bluetooth on. Even the state wifi on / bluetooth on is not easy to notice. To minimize that problem I created some udev rules and some scripts to open a KDE notification dialog every time they are activated or deactivated. Everybody in Linux "world" must have heard of udev, the system daemon which receives events from the kernel and run programs or scripts based on rules storared in /etc/udev/rules.d or /lib/udev/rules.d. In my case I added my rules to /etc/udev/rules.d:
File /etc/udev/rules.d/50-lvs-rfkill.rules
SUBSYSTEM=="rfkill", RUN+="lvs-rfkill.sh"
File /etc/udev/rules.d/50-lvs-webcam.rules
# Change the idProduct and idVendor attributes to your camera's.
# Use lsusb to find them.
SUBSYSTEM=="video4linux", ATTRS{idProduct}=="0343", ATTRS{idVendor}=="5986", RUN+="lvs-webcam.sh"
Then run this to reload the rules:
Reload udev rules
udevadm control --reload-rules 
Now we need to create the scripts lvs-rfkill.sh and lvs-webcam.sh and give execution permission to them (chmod 755):
File /lib/udev/lvs-rfkill.sh
#!/bin/sh

find_display()
{
    if [ -r "/proc/$1/environ" ]
    then
        perl -ne 'if ( /DISPLAY=([^:]+){0,1}(:\d+)(.\d+){0,1}/ )
         { print "$1$2$3\n"; }' < /proc/$1/environ
    fi

    return 0
}

user_loop()
{
    OLD_DISPLAY=$DISPLAY
    ps -C kwrapper -C kwrapper4 h -o pid,user | while read pid user
    do
        grep -q ksmserver /proc/$pid/cmdline &> /dev/null || continue
        export DISPLAY=$(find_display $pid)
        su - $user -c "$1"
    done
    export DISPLAY=$OLD_DISPLAY
    unset OLD_DISPLAY
    sleep 1
}

title=
msg=
case $RFKILL_TYPE in
    wlan)
        title="Wireless"

        case $ACTION in
            add|change)
                case $RFKILL_STATE in
                    0)
                        msg="Wireless disabled"
                    ;;
                        
                    1)
                        msg="Wireless enabled"
                    ;;

                    2)
                        msg="Wireless disabled by hardware"
                    ;;
                esac
            ;;

            remove)
                msg="Wireless disabled"
            ;;
        esac
    ;;

    bluetooth)
        title="Bluetooth"

        case $ACTION in
            add)
                msg="Bluetooth enabled"
                echo 1 > /sys/$DEVPATH/state
            ;;

            remove)
                msg="Bluetooth disabled"
            ;;
        esac
    ;;
esac

if [ "$msg" != "" ]
then
    user_loop "$(ls /usr/kde/*/bin/kdialog | tail -n 1) \
        --title \"$title\" --passivepopup \"$msg\" 3"
fi
File /lib/udev/lvs-webcam.sh
#!/bin/sh

find_display()
{
    if [ -r "/proc/$1/environ" ]
    then
        perl -ne 'if ( /DISPLAY=([^:]+){0,1}(:\d+)(.\d+){0,1}/ )
            { print "$1$2$3\n"; }' < /proc/$1/environ
    fi

    return 0
}

user_loop()
{
    OLD_DISPLAY=$DISPLAY
    ps -C kwrapper -C kwrapper4 h -o pid,user | while read pid user
    do
        grep -q ksmserver /proc/$pid/cmdline &> /dev/null || continue
        export DISPLAY=$(find_display $pid)
        su - $user -c "$1"
    done
    export DISPLAY=$OLD_DISPLAY
    unset OLD_DISPLAY
    sleep 1
}

title="Webcam"
msg="Webcam"

case $ACTION in
    add)
        msg="$msg enabled"
    ;;

    remove)
        msg="$msg disabled"
    ;;
esac

user_loop "$(ls /usr/kde/*/bin/kdialog | tail -n 1) \
    --title \"$title\" --passivepopup \"$msg\" 3"
Now every time you turn wifi/bluetooth/webcam on/off a notification will appear near KDE's notification tray icon:

No comments: