aboutsummaryrefslogtreecommitdiff
path: root/src/usr/bin/keyboard-leds-trayicons.sh
blob: 18ce82a03a6716e4b4cfd60fa289325b817f862c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/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
bgstack15