Skip to content

Instantly share code, notes, and snippets.

@TonyWhite
Last active October 5, 2021 15:40
Show Gist options
  • Select an option

  • Save TonyWhite/78477d76517461916e7fd98b54f20ff4 to your computer and use it in GitHub Desktop.

Select an option

Save TonyWhite/78477d76517461916e7fd98b54f20ff4 to your computer and use it in GitHub Desktop.
Clevo XSM Keyboard's led
#!/bin/bash
# Backlight - Clevo XSM Keyboard's led
# Copyright (C) 2019-2021 Antonio Bianco
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# Constants DEVICE
STATE="/sys/devices/platform/clevo_xsm_wmi/kb_state"
BRIGHTNESS="/sys/devices/platform/clevo_xsm_wmi/kb_brightness"
ANIMATION="/sys/devices/platform/clevo_xsm_wmi/kb_mode"
COLORS="/sys/devices/platform/clevo_xsm_wmi/kb_color"
MIN_BRIGHTNESS=0
MAX_BRIGHTNESS=9
DEFAULT_BRIGHTNESS=9
MIN_ANIMATION=0
MAX_ANIMATION=7
DEFAULT_ANIMATION=1
# Constants ACTIONS for main menu
ACT_DEVICE_ON="DEVICE_ON"
ACT_DEVICE_OFF="DEVICE_OFF"
ACT_CHANGE_COLOR="CHANGE_COLOR"
ACT_CHANGE_BRIGHTNESS="CHANGE_BRIGHTNESS"
ACT_CHANGE_ANIMATION="CHANGE_ANIMATION"
##########################
# LOCALIZATION WITH #
# zen-sudo LITE EMBEDDED #
##########################
# Default language: en_US
# zen-sudo strings
ZEN_SUDO_NAME="zen-sudo LITE EMBEDDED"
THIS_COMMAND_REQUIRE_ROOT_PERMISSIONS="This command require root permissions"
WORKING_FOLDER="Working folder"
COMMAND_NOT_EXECUTED="Command not executed."
# Colors
DRIVER_COLORS=("black" "red" "yellow" "green" "cyan" "blue" "magenta" "white")
ACCEPTED_COLORS=("Black" "Red" "Yellow" "Green" "Cyan" "Blue" "Magenta" "White")
# Constants ACTIONS for color menu
ACT_CHANGE_LEFT_COLOR="LEFT_COLOR"
ACT_CHANGE_CENTER_COLOR="CENTER_COLOR"
ACT_CHANGE_RIGHT_COLOR="RIGHT_COLOR"
ACT_CHANGE_TOUCHPAD_COLOR="TOUCHPAD_COLOR"
# Text
TXT_TITLE="Keyboard Backlight"
TXT_MUST_BE_ROOT="You must be root!"
TXT_SELECT_ACTION="Select Action"
TXT_BACK="Back"
TXT_EXIT="Exit"
TXT_QUESTION_QUIT="Do you want to exit?"
TXT_DEVICE_ON="Turn ON"
TXT_DEVICE_OFF="Turn OFF"
TXT_CHANGE="Change"
TXT_COLOR="Color"
TXT_CURRENT="Current"
TXT_BRIGHTNESS="Brightness"
TXT_ANIMATION="Animation"
TXT_CHANGE_COLOR="${TXT_CHANGE} ${TXT_COLOR}"
TXT_CHANGE_BRIGHTNESS="${TXT_CHANGE} ${TXT_BRIGHTNESS}"
TXT_CHANGE_ANIMATION="${TXT_CHANGE} ${TXT_ANIMATION}"
TXT_CHANGE_LEFT_COLOR="Left ${TXT_COLOR}"
TXT_CHANGE_CENTER_COLOR="Center ${TXT_COLOR}"
TXT_CHANGE_RIGHT_COLOR="Right ${TXT_COLOR}"
TXT_CHANGE_TOUCHPAD_COLOR="Touchpad ${TXT_COLOR}"
# Import current language. If it fails, en_US will be used
case "`echo ${LANG} | cut -f1 -d ' ' | cut -f1 -d '.'`" in
"it_IT")
# zen-sudo strings
THIS_COMMAND_REQUIRE_ROOT_PERMISSIONS="Questo comando richiede i permessi di root"
WORKING_FOLDER="Cartella di lavoro"
COMMAND_NOT_EXECUTED="Comando non eseguito."
# Colors
ACCEPTED_COLORS=("Nero" "Rosso" "Giallo" "Verde" "Ciano" "Blu" "Magenta" "Bianco")
# Constants ACTIONS for color menu
ACT_CHANGE_LEFT_COLOR="LEFT_COLOR"
ACT_CHANGE_CENTER_COLOR="CENTER_COLOR"
ACT_CHANGE_RIGHT_COLOR="RIGHT_COLOR"
ACT_CHANGE_TOUCHPAD_COLOR="TOUCHPAD_COLOR"
# Text
TXT_TITLE="Retroilluminazione della tastiera"
TXT_MUST_BE_ROOT="Devi essere root!"
TXT_SELECT_ACTION="Scegli l'azione"
TXT_BACK="Indietro"
TXT_EXIT="Esci"
TXT_QUESTION_QUIT="Vuoi uscire dal programma?"
TXT_DEVICE_ON="Accendi"
TXT_DEVICE_OFF="Spegni"
TXT_CHANGE="Cambia"
TXT_COLOR="Colore"
TXT_CURRENT="Corrente"
TXT_BRIGHTNESS="Luminosità"
TXT_ANIMATION="Animazione"
TXT_CHANGE_COLOR="${TXT_CHANGE} ${TXT_COLOR}"
TXT_CHANGE_BRIGHTNESS="${TXT_CHANGE} ${TXT_BRIGHTNESS}"
TXT_CHANGE_ANIMATION="${TXT_CHANGE} ${TXT_ANIMATION}"
TXT_CHANGE_LEFT_COLOR="${TXT_COLOR} a sinistra"
TXT_CHANGE_CENTER_COLOR="${TXT_COLOR} centrale"
TXT_CHANGE_RIGHT_COLOR="${TXT_COLOR} di destra"
TXT_CHANGE_TOUCHPAD_COLOR="${TXT_COLOR} del touchpad"
;;
esac
#################
# MANAGE DEVICE #
#################
function device_on()
{
echo 1 > "${STATE}"
}
function device_off()
{
echo 0 > "${STATE}"
}
# 0 -> OFF
# 1 -> ON
function get_state()
{
cat "${STATE}"
}
# 0 -> MIN
# 9 -> MAX
# Default 9: max brightness
function set_brightness()
{
echo "$1" > "${BRIGHTNESS}"
}
function get_brightness()
{
cat "${BRIGHTNESS}"
}
# From 0 to 7
# Default 1: no animation
function set_animation()
{
echo "$1" > "${ANIMATION}"
}
# Get animation
function get_animation()
{
cat "${ANIMATION}"
}
# Set colors
function set_colors()
{
echo "$1 $2 $3 $4" > "${COLORS}"
}
# Get colors
function get_colors()
{
cat "${COLORS}"
}
#######
# GUI #
#######
function main_menu()
{
while true; do
ACTION=""
if [[ `get_state` == "1" ]]; then
ACTION=`menu_for_device_on`
else
ACTION=`menu_for_device_off`
fi
case "${ACTION}" in
"${ACT_DEVICE_ON}")
device_on
;;
"${ACT_DEVICE_OFF}")
device_off
;;
"${ACT_CHANGE_COLOR}")
menu_change_color
;;
"${ACT_CHANGE_BRIGHTNESS}")
menu_change_brightness
;;
"${ACT_CHANGE_ANIMATION}")
menu_change_animation
;;
"") # Cancel OR window closed
if [[ `exit_question` == true ]]; then
break
fi
;;
*)
`bad_nerd`
;;
esac
done
}
function exit_question()
{
zenity --question \
--ellipsize \
--title="${TXT_TITLE}" \
--text="${TXT_QUESTION_QUIT}"
RESPONSE=`echo $?`
if [[ ${RESPONSE} == 0 ]]; then
echo true
else
echo false
fi
}
# This is main menu when device is on
function menu_for_device_on()
{
ACTION=$(zenity --list \
--title="${TXT_TITLE}" \
--text="${TXT_SELECT_ACTION}" \
--cancel-label="${TXT_EXIT}"\
--hide-header \
--hide-column=1 \
--column="Value" --column="Description" \
"${ACT_CHANGE_COLOR}" "${TXT_CHANGE_COLOR}" \
"${ACT_CHANGE_BRIGHTNESS}" "${TXT_CHANGE_BRIGHTNESS}" \
"${ACT_CHANGE_ANIMATION}" "${TXT_CHANGE_ANIMATION}" \
"${ACT_DEVICE_OFF}" "${TXT_DEVICE_OFF}")
echo "${ACTION}"
}
# This is main menu when device is off
function menu_for_device_off()
{
ACTION=$(zenity --list \
--title="${TXT_TITLE}" \
--text="${TXT_SELECT_ACTION}" \
--cancel-label="${TXT_EXIT}"\
--hide-header \
--hide-column=1 \
--column="Value" --column="Description" \
"${ACT_DEVICE_ON}" "${TXT_DEVICE_ON}")
echo "${ACTION}"
}
# Menu to change color
function menu_change_color()
{
while true; do
ACTION=$(zenity --forms \
--title="${TXT_TITLE}" \
--text="${TXT_CHANGE_COLOR}" \
--cancel-label="${TXT_BACK}"\
--add-combo="${TXT_CHANGE_LEFT_COLOR}" \
--combo-values=`colors_to_combo_values` \
--add-combo="${TXT_CHANGE_CENTER_COLOR}" \
--combo-values=`colors_to_combo_values` \
--add-combo="${TXT_CHANGE_RIGHT_COLOR}" \
--combo-values=`colors_to_combo_values` \
--add-combo="${TXT_CHANGE_TOUCHPAD_COLOR}" \
--combo-values=`colors_to_combo_values`)
if [[ $? == "0" ]]; then
# Read colors from driver
L_COLOR=`echo $(get_colors) | cut -d " " -f 1`
C_COLOR=`echo $(get_colors) | cut -d " " -f 2`
R_COLOR=`echo $(get_colors) | cut -d " " -f 3`
T_COLOR=`echo $(get_colors) | cut -d " " -f 4`
# Read colors from user input and translate for driver
NEW_L_COLOR=`is_accepted_color "$(echo ${ACTION} | cut -d "|" -f 1)"`
NEW_C_COLOR=`is_accepted_color "$(echo ${ACTION} | cut -d "|" -f 2)"`
NEW_R_COLOR=`is_accepted_color "$(echo ${ACTION} | cut -d "|" -f 3)"`
NEW_T_COLOR=`is_accepted_color "$(echo ${ACTION} | cut -d "|" -f 4)"`
if [[ "${NEW_L_COLOR}" != "" ]]; then
L_COLOR="${NEW_L_COLOR}"
fi
if [[ "${NEW_C_COLOR}" != "" ]]; then
C_COLOR="${NEW_C_COLOR}"
fi
if [[ "${NEW_R_COLOR}" != "" ]]; then
R_COLOR="${NEW_R_COLOR}"
fi
if [[ "${NEW_T_COLOR}" != "" ]]; then
C_COLOR="${NEW_T_COLOR}"
fi
set_colors "${L_COLOR}" "${C_COLOR}" "${R_COLOR}" "${T_COLOR}"
else
break
fi
done
}
# Return driver color if $1 is accepted color
function is_accepted_color()
{
PROBE="$1"
RESULT=""
for ((INDEX = 0 ; INDEX < ${#ACCEPTED_COLORS[@]}; INDEX++)); do
COLOR="${ACCEPTED_COLORS[${INDEX}]}"
if [[ "${PROBE}" == "${COLOR}" ]]; then
RESULT="${DRIVER_COLORS[${INDEX}]}"
break
fi
done
echo ${RESULT}
}
# Convert array to zenity combo box values
function colors_to_combo_values()
{
STRING_FOR_ZENITY="${ACCEPTED_COLORS[0]}"
for INDEX in 1 2 3 4 5 6 7; do
STRING_FOR_ZENITY+="|${ACCEPTED_COLORS[$INDEX]}"
done
echo "${STRING_FOR_ZENITY}"
}
# Menu to change brightness
function menu_change_brightness()
{
while true; do
ACTION=$(zenity --forms \
--title="${TXT_TITLE}" \
--text="${TXT_CHANGE_BRIGHTNESS}" \
--cancel-label="${TXT_BACK}"\
--add-combo="${TXT_CURRENT}: `get_brightness`" \
--combo-values=`brightness_to_combo_values`)
if [[ $? == "0" ]]; then
if [[ `is_accepted_brightness "${ACTION}"` == true ]]; then
set_brightness "${ACTION}"
fi
else
break
fi
done
}
# Return true if $1 is accepted brightness value
function is_accepted_brightness()
{
PROBE="$1"
RESULT=false
for ((VALUE = ${MIN_BRIGHTNESS} ; VALUE <= ${MAX_BRIGHTNESS}; VALUE++)); do
if [[ "${PROBE}" == "${VALUE}" ]]; then
RESULT=true
break
fi
done
echo $RESULT
}
# Return zenity combo box values
function brightness_to_combo_values()
{
STRING_FOR_ZENITY="${MIN_BRIGHTNESS}"
for ((VALUE = ${MIN_BRIGHTNESS}+1 ; VALUE <= ${MAX_BRIGHTNESS}; VALUE++)); do
STRING_FOR_ZENITY+="|${VALUE}"
done
echo "${STRING_FOR_ZENITY}"
}
# Menu to change animation
function menu_change_animation()
{
while true; do
ACTION=$(zenity --forms \
--title="${TXT_TITLE}" \
--text="${TXT_CHANGE_ANIMATION}" \
--cancel-label="${TXT_BACK}"\
--add-combo="${TXT_CURRENT}: `get_animation`" \
--combo-values=`animation_to_combo_values`)
if [[ $? == "0" ]]; then
if [[ `is_accepted_animation "${ACTION}"` == true ]]; then
set_animation "${ACTION}"
fi
else
break
fi
done
}
# Return true if $1 is accepted animation value
function is_accepted_animation()
{
PROBE="$1"
RESULT=false
for ((VALUE = ${MIN_ANIMATION} ; VALUE <= ${MAX_ANIMATION}; VALUE++)); do
if [[ "${PROBE}" == "${VALUE}" ]]; then
RESULT=true
break
fi
done
echo $RESULT
}
# Return zenity combo box values
function animation_to_combo_values()
{
STRING_FOR_ZENITY="${MIN_ANIMATION}"
for ((VALUE = ${MIN_ANIMATION}+1 ; VALUE <= ${MAX_ANIMATION}; VALUE++)); do
STRING_FOR_ZENITY+="|${VALUE}"
done
echo "${STRING_FOR_ZENITY}"
}
# Show this for stupid lamers (or drunken developer)
function bad_nerd()
{
zenity --warning \
--ellipsize \
--title="Yo nerd!" \
--text="You have won an IP address to attack!\n127.0.0.1\n\nRemember: It has firewall!"
}
##########################
# zen-sudo LITE EMBEDDED #
##########################
if [[ `whoami` == "root" ]]; then
main_menu
else
if [[ "`cat /proc/${PPID}/comm`" == "sudo" ]]; then # If called from sudo...
COMMAND="$(cat /proc/${PPID}/cmdline | tr '\0' ' ')" # Detect command line
# └────────────┬──────────┘ └────┬────┘
# │ └───────────→ Translate all zero bytes with spaces
# └───────────────────────────────→ Print comand line from parent process
zenity --entry \
--hide-text \
--title="${ZEN_SUDO_NAME}" \
--text="${THIS_COMMAND_REQUIRE_ROOT_PERMISSIONS}:\
\n${COMMAND}\
\n\n${WORKING_FOLDER}:\
\n${PWD}\
\n\n$1" # Showing request with command and current folder
else # If called from user...
export SUDO_ASKPASS="$(realpath "$0")" # I am the guy for the GUI
sudo -A "$(realpath "$0")" "$@" # Request root permissions to myself
SUCCESS="$?" # Read result of sudo: 0 should be great
if [[ "${SUCCESS}" != "0" ]]; then # If wrong with sudo...
zenity --warning\
--ellipsize\
--title="${ZEN_SUDO_NAME}" \
--text="${COMMAND_NOT_EXECUTED}"
fi
fi
fi
@TonyWhite
Copy link
Author

TonyWhite commented Oct 3, 2021

Santech is a rebrand of Clevo laptops. Santech keyboard's backlight needs clevo driver to control leds.
You need to:

  1. download clevo-xsm-wmi driver
  2. Unpack it
  3. Compile
    make
  4. Become root
  5. Copy driver into libs
    cp clevo-xsm-wmi.ko /lib/modules/$(uname -r)/kernel/drivers/platform/x86/clevo-xsm-wmi.ko
  6. Load modules with kernel
    echo clevo-xsm-wmi > /etc/modules-load.d/clevo-xsm-wmi.conf
  7. Probe all modules
    depmod -a
  8. Reboot system
    reboot

Now you can use the script to manage your keyboard's backlight.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment