# Adjust the laptop's screen brightness in Emacs

If you're using i3wm on Linux, how do you adjust the laptop's screen brightness?

Most of the time, I use the laptop with an external monitor. But when I am out, I have no monitors. And it seems no easy way to adjust the brightness in i3wm. Being too bright or dim is terrible for the eyes.

Recently, I found a command-line tool called brightnessctl, which can adjust the brightness in a terminal. Its primary usage would be:

• brightnessctl set +10% to increase the brightness by 10%
• brightnessctl set 10%- to decrease it by 10%

It works, but I want to make it easier to control it. It would be nice if I could do it in Emacs. Then I thought of the text-scale-adjust command in Emacs, the user experience is what I am looking for.

By imitating the command, I came up with a command w/adjust-screen-brightness. Here is how to use it:

1. M-x w/adjust-screen-brightness to invoke the command. By default, the delta percentage is 10%. If you want to change it, prefix the command with an argument. For example, C-u 2 M-x w/adjust-screen-brightness to make it 20%.
2. Hit + or = to increase the brightness by 10% continually, or hit - to decrease it by 10%
3. Hit any other keys to end the command when you're satisfied with the result.

Here is the complete code:

(defun w/adjust-screen-brightness (inc)
"Adjust the screen brightness by INC*10%.

INC may be passed as a numeric prefix argument.

The actual adjustment made depends on the final component of the
key-binding used to invoke the command, with all modifiers removed:

+, =   Increase the height of the default face by one step
-      Decrease the height of the default face by one step

After adjusting, continue to read input events and further adjust
the screen brightness as long as the input event read
\(with all modifiers removed) is one of the above characters.
"
(interactive "p")
(let ((ev last-command-event)
(echo-keystrokes nil))
(let* ((base (event-basic-type ev))
(step (* inc 10))
(cmd (format "brightnessctl set %s%d%%%s" ; +10% or 10%-
(if (or (= ?+ base)
(= ?= base))
"+"
"")
step
(if (= ?- base) "-" ""))))
(shell-command cmd)

(message "Use +,- for further adjustment by %d%%" step)
(set-transient-map
(let ((map (make-sparse-keymap)))
(dolist (mods '(() (control)))
(dolist (key '(?- ?+ ?=)) ;; = is often unshifted +.
(define-key map (vector (append mods (list key)))
(lambda () (interactive)
map)))))
The interesting API here for increasing/decreasing the brightness continually is set-transient-map. It will allow us to set a temporary keymap taking precedence over other keymaps so that I can intercept +, =, and - keys here to invoke the command again and again.