Copyright (C) 2017, 2021 Bob Proulx bob@proulx.com
This document is licensed under a Creative Commons Attribution-NoDerivatives 4.0 International License .
I recently installed Debian Jessie 8 on a Lenovo ThinkPad X220 laptop.
Most things worked without any special configuration. However the
audio controls and the screen monitor brightness controls did not.
Researching the differences between the X220 and previous models such
as the T60p showed that previously these involved changes to the nvram
but now does not. Previously the tpb
package would handle the
laptop keys. Unfortunately this did not handle the X220 keys.
Using xev
showed that all of the keys produced keycodes. These were
the ones that had no function for me.
keycode 122 XF86AudioLowerVolume
keycode 123 XF86AudioRaiseVolume
keycode 198 XF86AudioMicMute
keycode 156 XF86Launch1
keycode 198 XF86AudioMicMute
keycode 232 XF86MonBrightnessDown
keycode 233 XF86MonBrightnessUp
Using a full Desktop Environment such as Xfce handled the volume up
and down keys through X events but did not handle the monitor
brightness keys nor the others. Most importantly this only worked in
an X Desktop Environment and not an X window manager session such as
using fvwm
or i3
window managers. I am mostly using i3
, a
tiling window manager, these days and I wanted these keys to work
there and everywhere. Which means not using X key events but using
the ACPI key events.
The acpi_listen
program can be used to dump the ACPI events. This
was useful to determine what ACPI events were triggered by those keys.
acpi_listen
Additionally the acpi-support
package was not installed by default.
Plus alsa-utils
is used to implement the functions.
apt-get install acpi-support alsa-utils
I determined the following ACPI events were being created but not handled.
event=video/brightnessdown BRTDN 00000087 00000000
event=video/brightnessup BRTUP 00000086 00000000
event=button/f20 F20 00000080 00000000
event=button/mute MUTE 00000080 00000000
event=button/volumedown VOLDN 00000080 00000000
event=button/volumeup VOLUP 00000080 00000000
I created the following files to handle those events.
/etc/acpi/events/local-thinkpad-micmute
/etc/acpi/events/local-thinkpad-brightnessup
/etc/acpi/events/local-thinkpad-volup
/etc/acpi/events/local-thinkpad-brightnessdown
/etc/acpi/events/local-thinkpad-voldown
/etc/acpi/events/local-thinkpad-mute
/etc/acpi/local-thinkpad-brightness.sh
I have bundled all of these files into one
local-acpi-x220-keys.tar.gz file for
easy download. However I will also list out each file individually
for easy review and individual manual install. These next all go into
the /etc/acpi/events
directory.
File /etc/acpi/events/local-thinkpad-brightnessdown:
event=video/brightnessdown BRTDN 00000087 00000000
action=/etc/acpi/local-thinkpad-brightness.sh down
File /etc/acpi/events/local-thinkpad-brightnessup:
event=video/brightnessup BRTUP 00000086 00000000
action=/etc/acpi/local-thinkpad-brightness.sh up
File /etc/acpi/events/local-thinkpad-micmute:
event=button/f20 F20 00000080 00000000
action=amixer -q sset -- Capture toggle
File /etc/acpi/events/local-thinkpad-mute:
event=button/mute MUTE 00000080 00000000
action=amixer -q sset -- Master toggle
File /etc/acpi/events/local-thinkpad-voldown:
event=button/volumedown VOLDN 00000080 00000000
action=amixer -q sset -- Master 5%%- unmute
File /etc/acpi/events/local-thinkpad-volup:
event=button/volumeup VOLUP 00000080 00000000
action=amixer -q sset -- Master 5%%+ unmute
The functionality needed for the brightness up and down is a little too much for a one-liner in the event file command line definition itself. I created that as a helper script in the /etc/acpi directory just like the other helper utilities there.
This script is ThinkPad X220 specific. At least it is ThinkPad
specific. It makes use of the /sys/class/backlight/intel_backlight
interface which won't generically exist. Therefore it has a check for
that interface and simply exits without doing anything if it does not
exist.
File /etc/acpi/local-thinkpad-brightness.sh (in the /etc/acpi directory):
#!/bin/sh
# Copyright 2017, 2021 Bob Proulx <bob@proulx.com>
#
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved. This file is offered as-is,
# without any warranty.
test -e /sys/class/backlight/intel_backlight/brightness || exit 0
max_brightness=$(cat /sys/class/backlight/intel_backlight/max_brightness)
brightness=$(cat /sys/class/backlight/intel_backlight/brightness)
increment=$((max_brightness / 20)) # a 5% change
case $1 in
up)
new=$(($brightness + $increment))
if [ $new -ge $max_brightness ]; then
new=$max_brightness
fi
;;
down)
new=$(($brightness - $increment))
if [ $new -le 150 ]; then
new=150 # prevent a 0 completely dark display to avoid confusion
fi
;;
esac
echo $new > /sys/class/backlight/intel_backlight/brightness
exit 0
service acpid restart
At this point the laptop keys were all completely functional. I could
make them work in my fvwm
or i3
window managers, in the Xfce
Desktop Environment, or on the Linux text console.
Of course there is one problem. Because the audio mute creates an X
key event which is also handled by the Xfce Desktop Environment, when
using the Xfce Desktop Environment, it means that it gets handled
twice in that environment. Once by the above ACPI handler and once
by the Xfce X event handler. Each toggles the mute. Which means that
in Xfce this key which otherwise works there no longer works there due
to being toggled twice. The same thing happens for volume up and
volume down too but doubling those simply causes more volume or less
volume and does not present itself as a problem. However since I
needed this because I was not using Xfce but using the i3
window manager, this isn't actually a problem for me. It is only a
problem if I flip back to Xfce. In which case I should remove the
audio button control configurations and just leave the monitor
brightness control configurations.
In order to fix the above in Xfce I wish to find a way to disable
Xfce's handling of those X events. Perhaps by preventing those X
events from being sent. I think maybe those are being sent by the use
of acpi_fakekey in acpi-support
. I need to investigate.
To have an OSD (on-screen-display) feedback such as that which is
provided by the tpb
package there is the xosd-bin
package
providing the osd_cat
program. That can be connected to xbindkeys
to present an OSD when these actions are triggered. This works very
well to provide feedback when changing things like screen brightness.
Configure the xbindkeys
program using this ~/.xbindkeysrc
file.
"osd-display-handler"
XF86MonBrightnessUp
"osd-display-handler"
XF86MonBrightnessDown
And the $HOME/bin/osd-display-handler
script is:
#!/bin/sh
# Copyright 2017, 2021 Bob Proulx <bob@proulx.com>
#
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved. This file is offered as-is,
# without any warranty.
if [ ! -e /sys/class/backlight/intel_backlight/brightness ]; then
echo "Error: missing /sys/class/backlight/intel_backlight/brightness" 1>&2
exit 0
fi
max=$(cat /sys/class/backlight/intel_backlight/max_brightness)
bright=$(cat /sys/class/backlight/intel_backlight/brightness)
percent=$(awk -v m=$max -v b=$bright 'BEGIN{printf("%.0f\n",100*b/m);}')
pkill osd_cat
osd_cat -p bottom -i 150 -c blue -d 2 -T "Backlight" -b percentage -P $percent &
exit 0