#!/usr/bin/env sh # File: keyboard-leds-trayicons.sh # License: CC-BY-SA 4.0 # Author: bgstack15 # Startdate: 2020-02-13 15:30 # Title: Substitute for Keyboard LED Indicators # Purpose: For systems that do not show LEDs for capslock and numlock # History: # Usage: # Reference: # some Internet place that demonstrated how to use xset q # some Internet place that showed how to convert the decimal to binary with awk # get_conf comes from framework.sh # Improve: # provide way to change status of capslock by clicking the icon? # Dependencies: # binaries: mktrayicon, awk, xset # little c: https://visualpharm.com/free-icons/c%20letter-595b40b65ba036ed117d1027 # license for icons: Use for free, but link to [icons8](https://icons8.com/license) # CONFIG FILES test -z "${KLT_GLOBAL_CONF}" && KLT_GLOBAL_CONF=/etc/keyboard-leds-trayicons.conf test -z "${KLT_USER_CONF}" && KLT_USER_CONF="${HOME}/.config/keyboard-leds-trayicons.conf" # also accept KLT_CONF # FUNCTIONS get_conf() { # Ripped from framework.sh # call: get_conf "${conffile}" local _infile="$1" local _tmpfile1="$( mktemp )" sed -e 's/^\s*//;s/\s*$//;/^[#$]/d;s/\s*[^\]#.*$//;' "${_infile}" | grep -viE "^$" | while read _line ; do local _left="$( echo "${_line}" | cut -d'=' -f1 )" eval "_thisval=\"\${${_left}}\"" test -z "${_thisval}" && echo "${_line}" >> "${_tmpfile1}" done test -f "${_tmpfile1}" && { . "${_tmpfile1}" 1>/dev/null 2>&1 ; } /bin/rm -rf "${_tmpfile1}" 1>/dev/null 2>&1 } clean_keyboard_leds_trayicons() { { test -e "${capslockicon}" && echo "q" > "${capslockicon}" ; } 1>/dev/null 2>&1 & { test -e "${numlockicon}" && echo "q" > "${numlockicon}" ; } 1>/dev/null 2>&1 & sleep 1 && rm -f "${capslockicon}" "${numlockicon}" "${KLT_KILLFILE}" } get_led_mask() { xset q | awk 'function d2b(d,b) {while(d) {b=d%2b;d=int(d/2)}return(b)} /LED/{print d2b($NF)}' } mask_position_on() { # call: mask_position_on "${LEDS}" "${ledposition}" ___result="$( printf "%08d" "${1}" | tail -c "${2}" | head -c 1 )" ___result=$(( 1 - ___result )) return "${___result}" } is_capslock_on() { # call: get_led_mask | is_capslock_on && echo "yes" read ___ico mask_position_on "${___ico}" "1" } is_numlock_on() { # call: get_led_mask | is_numlock_on && echo "yes" read ___ico mask_position_on "${___ico}" "2" } # LOAD CONFIGS # order is important! The last one called gets precedence. # instead of simply dot-sourcing the conf file, pass it to get_conf which only applies new values, so this process's environment is preserved for thisconf in "${KLT_GLOBAL_CONF}" "${KLT_USER_CONF}" "${KLT_CONF}" ; do test -r "${thisconf}" && get_conf "${thisconf}" done # DEFAULTS in case configs did not have these values test -z "${KLT_CAPS_ON_ICON}" && KLT_CAPS_ON_ICON=capslock-on test -z "${KLT_CAPS_OFF_ICON}" && KLT_CAPS_OFF_ICON=capslock-off test -z "${KLT_CAPS_ON_ICON}" && KLT_CAPS_ON_ICON=numlock-on test -z "${KLT_CAPS_OFF_ICON}" && KLT_CAPS_OFF_ICON=numlock-off test -z "${KLT_KILLFILE}" && KLT_KILLFILE="/tmp/kill-all-leds-trayicons" # INITIALIZATION capslockicon="/var/run/user/$( id -u )/${$}.cap.icon" numlockicon="/var/run/user/$( id -u )/${$}.num.icon" test "ON" = "ON" && { mkfifo "${capslockicon}" mkfifo "${numlockicon}" mktrayicon "${capslockicon}" & mktrayicon "${numlockicon}" & echo "m quit,echo 'q' > ${capslockicon} ; touch "${KLT_KILLFILE}"" > "${capslockicon}" echo "m quit,echo 'q' > ${numlockicon} ; touch "${KLT_KILLFILE}"" > "${numlockicon}" } caps_status_old=-1 num_status_old=-1 rm -f "${KLT_KILLFILE}" trap 'trap "" 2 ; touch "${KLT_KILLFILE}" ' 2 # CTRL-C while ! test -e "${KLT_KILLFILE}" 2>/dev/null ; do x="$( get_led_mask )" caps_status_now=0 num_status_now=0 echo "${x}" | is_capslock_on && caps_status_now=1 echo "${x}" | is_numlock_on && num_status_now=1 if test "${caps_status_now}" != "${caps_status_old}" ; then test -p "${capslockicon}" && case "${caps_status_now}" in 1) test -n "${KLT_DEBUG}" && echo "capslock on (icon file ${KLT_CAPS_ON_ICON})" 1>&2 echo "i ${KLT_CAPS_ON_ICON}" > "${capslockicon}" echo "t capslock on" > "${capslockicon}" ;; 0) test -n "${KLT_DEBUG}" && echo "capslock off (icon file ${KLT_CAPS_OFF_ICON})" 1>&2 echo "i ${KLT_CAPS_OFF_ICON}" > "${capslockicon}" echo "t capslock off" > "${capslockicon}" ;; esac fi if test "${num_status_now}" != "${num_status_old}" ; then test -p "${numlockicon}" && case "${num_status_now}" in 1) test -n "${KLT_DEBUG}" && echo "numlock on (icon file ${KLT_NUM_ON_ICON})" 1>&2 echo "i ${KLT_NUM_ON_ICON}" > "${numlockicon}" echo "t numlock on" > "${numlockicon}" ;; 0) test -n "${KLT_DEBUG}" && echo "numlock off (icon file ${KLT_NUM_OFF_ICON})" 1>&2 echo "i ${KLT_NUM_OFF_ICON}" > "${numlockicon}" echo "t numlock off" > "${numlockicon}" ;; esac fi caps_status_old="${caps_status_now}" num_status_old="${num_status_now}" sleep 0.75 done # safety shutoff clean_keyboard_leds_trayicons