Keyboard Settings under X
5 November 2020
The keyboard in Linux has separate settings when running under X and when not. Under X, there are a number of utilities (xmodmap, xvkbd, xbindkeys, and so on) which can be used to get additional functionality. Community-driven window managers also often give functionality to remap keys, but these are less portable and should be avoided for any bindings not specific to the window manager itself.
Keyboard Layout (console)
Under openrc, the console keyboard layout is managed by the
keymaps
service. The keyboard settings are in
/etc/conf.d/keymaps
, and (on my system) there is a
line keymap="us"
which should be
keymap="uk"
.
In order to update the changes, we need to restart the
keymaps
service,
rc-update add keymaps boot
rc-service keymaps restart
Keyboard Layout with xkb
To set the keyboard layout when X starts, add the following
line to your .xinitrc
.
setxkbmap -layout gb
XKB can be used for sophisticated remapping of the keyboard, but the rules it requires are more complex than for xmodmap (described below).
Remapping keys with xmodmap
If you want to augment your keyboard layout by remapping some keys, you should use the tool xmodmap. From the manual,
The xmodmap program is used to edit and display the keyboard modifier map and keymap table that are used by client applications to convert event keycodes into keysyms. It is usually run from the user's session startup script to configure the keyboard according to personal tastes.
To see the syntax for xmodmap, and to set yourself up with a config file, run:
# Initalise a config file
xmodmap -pke > $HOME/.xmodmaprc
You can remove lines you don’t want to change, but you should keep a backup of the original configuration in case you make a mistake. The syntax of each line is like the following:
keycode 65 = space space Return BackSpace
The left hand side refers to a “keycode”. This is an integer which determines a key on your keyboard. To see which keycode is sent when you press a particular key, run the xev command. For example, if I open xev and press the space bar, I see the output:
KeyPress event, serial 33, synthetic NO, window 0x3000001,
root 0x17e, subw 0x0, time 193595320, (116,168), root:(1077,718),
state 0x0, keycode 65 (keysym 0x20, space), same_screen YES,
XLookupString gives 1 bytes: (20) " "
XmbLookupString gives 1 bytes: (20) " "
XFilterEvent returns: False
The output can be very hard to read, because it processes
every input it receives (including mouse movements). We see that
the space bar has keycode 65, and keysym “space”. The line
keycode 65 = space
tells xmodmap to process the
space bar as a “space” key press. If we changed it to
keycode 65 = h
, then pressing the space bar would
be equivalent to pressing the h key.
The extra columns refer to when certain modifier keys are
pressed. Column 1 refers to pressing key
with no
modifiers. Column 2 refers to Shift+key
, column 3
is Mode_switch+key
, and column 4 is
Mode_switch+Shift+key
. Shift is the normal shift
key on your keyboard, and Mode_switch is a special key
designated for changing keyboard layout - normally the AltGr key
on your keyboard, if it has one.
So, for a normal letter on the keyboard, the line might look something like this:
keycode 31 = i I i I rightarrow idotless rightarrow
columns beyond the first four are non-standard (see the
manual). This key behaves like the usual I key on your keyboard
- if Shift is pressed, it sends I
, and if not then
it sends i
. It ignores the Mode_switch key. To see
a line that takes advantage of Mode_switch, recall the example
from above:
keycode 65 = space space Return BackSpace
So key 65 (the space bar) reports a “space” keysym if Mode_switch is not pressed, and otherwise reports Return, unless Shift is pressed, in which case it reports BackSpace. In case your keyboard does not have an AltGr key, or you don’t like its position, you can remap it like so:
keycode 66 = Mode_switch NoSymbol Mode_switch
This snippet sets my Caps Lock key to be Mode_switch, but I don’t use that key anyway so it’s not big loss. My final xmodmaprc looks like so:
keycode 43 = h H Left Left
keycode 44 = j J Down Page_Down
keycode 45 = k K Up Page_Up
keycode 46 = l L Right Right
keycode 65 = space space Return BackSpace
keycode 66 = Mode_switch NoSymbol Mode_switch
To source this file on startup, add the following line to your xinitrc file.
xmodmap $HOME/.xmodmaprc
Binding keys to scripts with xbindkeys
For jobs more complex than simply remapping keys, you should
use xbindkeys
. With this tool, a specific key or
key sequence can be mapped to an arbitrary command or script.
When xbindkeys
is run, it reads the default
configuration file at $HOME/xbindkeysrc
. You can
generate a default file with helpful comments by running
xbindkeys --defaults
.
The required syntax is:
"cmd"
key
Application: Multimedia Keys
My volume keys (Mute, Up, Down) do not work out of the box, so here is an example to fix them.
To find the key, I first run xbindkeys -k
or
xev
. Pressing each of Fn+F1-6, I get:
XF86AudioMute
XF86AudioLowerVolume
XF86AudioRaiseVolume
XF86AudioMicMute
XF86MonBrightnessDown
XF86MonBrightnessUp
If you get something like “No response” or “Focusin/Focusout”, then an application is intercepting the key press. For example, when xbindkeys is running, I get no response. Your window manager may be swallowing the keys instead. Unfortunately, you have to find out what application is responsible by yourself.
Brightness
Once you have identified the appropriate key, you need a
shell command which will adjust the volume/brightness. For
brightness, we can use the xbrightness
tool:
# $HOME/.xbindkeysrc
"xbacklight -inc 10"
XF86MonBrightnessUp
"xbacklight -dec 10"
XF86MonBrightnessDown
Volume
For volume, I have PulseAudio installed on my system so I use
the tool pactl
to adjust the volume. For the sinks
(speakers), we have:
$ pactl list short sinks
0 alsa_output.pci-0000_00_03.0.hdmi-stereo module-alsa-card.c s16le 2ch 44100Hz IDLE
1 alsa_output.pci-0000_00_1b.0.analog-stereo module-alsa-card.c s16le 2ch 44100Hz IDLE
$ pactl list short sources
0 alsa_output.pci-0000_00_03.0.hdmi-stereo.monitor module-alsa-card.c s16le 2ch 44100Hz RUNNING
1 alsa_output.pci-0000_00_1b.0.analog-stereo.monitor module-alsa-card.c s16le 2ch 44100Hz RUNNING
2 alsa_input.pci-0000_00_1b.0.analog-stereo module-alsa-card.c s16le 2ch 44100Hz RUNNING
You can probably identify the correct card by reading the short name - I am interested in the analog input and output channels. The configuration will therefore be:
# $HOME/.xbindkeysrc
"pactl set-sink-mute alsa_output.pci-0000_00_1b.0.analog-stereo toggle"
XF86AudioMute
"pactl set-sink-volume alsa_output.pci-0000_00_1b.0.analog-stereo -10%"
XF86AudioLowerVolume
"pactl set-sink-volume alsa_output.pci-0000_00_1b.0.analog-stereo +10%"
XF86AudioRaiseVolume
"pactl set-source-mute alsa_input.pci-0000_00_1b.0.analog-stereo toggle"
XF86AudioMicMute
Screenshots
There is a very nice and simple program named scrot that takes screenshots. I am accustomed to the PrintScreen button taking a screenshot of the current window, and Shift+PrintScreen taking an “interactive” screenshot (where you draw a rectangle on the screen).
The following setup will do exactly that, with screenshots
being sent to your home directory by default. To send them to a
special folder, check out man scrot
.
# $HOME/.xbindkeysrc
"scrot"
Print
"scrot -s"
Shift+Print