Keyboard input - ArchWiki

Jump to content

# Keyboard input

From ArchWiki

Related articles

- Extra keyboard keys
- Input remap utilities

Prerequisite for modifying the key mapping is knowing how a key press results in a symbol:

1. The keyboard sends a scancode to the computer.
2. The Linux kernel maps the scancode to a keycode; see Map scancodes to keycodes.
3. The keyboard layout maps the keycode to a symbol or keysym, depending on what modifier keys are pressed.
   - For the Linux console, see Linux console/Keyboard configuration.
   - For Xorg and Wayland, see Xorg/Keyboard configuration.

Most of your keys should already have a keycode, or at least a scancode. Keys without a scancode are not recognized by the kernel; these can include additional keys from "gaming" keyboards, etc.

In Xorg, some keysyms (e.g. `XF86AudioPlay`, `XF86AudioRaiseVolume` etc.) can be mapped to actions (i.e. launching an external application). See Keyboard shortcuts#Xorg for details.

In Linux console, some keysyms (e.g. `F1` to `F246`) can be mapped to certain actions (e.g. switch to other console or print some sequence of characters). See Console keyboard configuration#Creating a custom keymap for details.

## Identifying scancodes

### Using evtest

The most reliable way to obtain a scancode is to reference the `MSC_SCAN` evdev event produced when the key is pressed [1]. There are multiple evdev API testers, but the most straightforward is evtest(1) from the evtest package:

    # evtest /dev/input/event12

    ...
    Event: time 1434666536.001123, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70053
    Event: time 1434666536.001123, type 1 (EV_KEY), code 69 (KEY_NUMLOCK), value 0
    Event: time 1434666536.001123, -------------- EV_SYN ------------

Tip If you do not know which event number the device of your interest has, you can run `evtest` without parameters and it will show you a list of devices with their event numbers, then you can enter the needed number.

Use the "value" field of `MSC_SCAN`. This example shows that NumLock has scancode 70053 and keycode 69.

### Using showkey

Warning Avoid showkey in favor of evtest. showkey will print incorrect scancodes for most keyboards on non-ancient kernels (≥3.0). Also, showkey will not (or only by luck) display correct scancodes when you're logged in via a network connection.

The traditional way to get a scancode is to use the showkey(1) utility. showkey waits for a key to be pressed, or exits if no keys are pressed within 10 seconds. To use showkey in a graphical environment you need to run it with root rights (e.g. prepend `sudo` before `showkey`). If it does not work as expected or if you don't have root rights, you should switch to a virtual console and run showkey there.

Run the following command (`stty` commands are optional):

    # stty -echo; showkey --scancodes; stty echo

and try to push keyboard keys; you should see scancodes being printed to the output. If you're in a graphical environment the `stty` commands surrounding the `showkey` command are helpful to suppress the terminal output of keyboard input which would otherwise interfere with the output of showkey.

#### Technical background

showkey basically works by opening a virtual console (device file), changing the keyboard mode of the virtual console, reading from the virtual console and printing the read characters in different formats (eg. ascii, decimal, hexadecimal). To find a virtual console, showkey iterates over six options, skipping pseudoterminals. The first and second being the terminal showkey is connected to (1. STDIN file descriptor, 2. controlling terminal) and the third being the active virtual console (/dev/tty0). For example, if showkey is run within a graphical environment it will open the active virtual console (normally /dev/tty7) assuming showkey was run with root rights it needs to read /dev/tty7 because the graphical environment "locked" this console. After opening a virtual console showkey will proceed to change the keyboard mode with the KDSKBMODE ioctl call according to the requested output. For --ascii output the keyboard mode isn't changed (showkey assumes UNICODE or XLATE mode), for --keycodes output the keyboard mode is changed to MEDIUMRAW and for --scancodes output the keyboard mode is changed to RAW.

When an application like showkey reads a virtual console using the RAW keyboard mode and the keyboard is using the HID protocol (most keyboards) the linux kernel will map HID scancodes to linux keycodes to PS/2 set 1 scancodes that are then passed to the application. The translation of HID scancodes to PS/2 set 1 scancodes is probably done because of backwards compatibility with ancient tools that expect PS/2 set 1 scancodes when reading from the console using the RAW keyboard mode. Because of this translation showkey will show incorrect scancodes for most keyboards. But even if the keyboard side (normally the motherboard's keyboard controller) is actually using PS/2 set 1 scancodes, some of those scancodes cannot be used to remap keys unless you use setkeycodes which "corrects" them internally (see this for more details). In contrast evtest will show atkbd scancodes instead of PS/2 scancodes for a PS/2 protocol keyboard which can be used for both setkeycodes and the udev hardware database to remap keys.

### Using dmesg

Note This method only identifies unknown keys.

You can get the scancode of a key by pressing the desired key and looking at the output of dmesg. For example, if you get:

    Unknown key pressed (translated set 2, code 0xa0 on isa0060/serio0

then the scancode you need is `0xa0`.

### Using bpftrace (PS/2 only)

Note This method lets you see raw PS/2 protocol scancodes which you normally do not need. evtest shows the more useful driver scancodes (see Map scancodes to keycodes#setkeycodes modifies user-passed scancodes for more explanation).

To show raw PS/2 scancodes using this method you need to have a non-ancient kernel (≥3.0) that supports eBPF (all modern linux kernels should support it) and have `bpftrace` installed. `bpftrace` needs root rights (e.g. prepend `sudo` before `stdbuf`).

Run the following command (`stty` commands are optional):

    # stty -echo; stdbuf --output=0 bpftrace -e 'kprobe:input_event /arg1 == 4 && arg2 == 3/ { $n=str(((struct input_dev*)arg0)->name); if (!strncmp($n, "AT ", 3) && strcontains($n, "keyboard") ) { printf("%02x ", arg3); } }'; stty echo

and wait until the text `Attaching 1 probe...` appears. You'll then see the raw bytes (scancodes) send from your keyboard while typing. Press `Ctrl+c` to exit the program. The `stty` commands surrounding the `stdbuf` command are helpful to suppress the terminal output of keyboard input which would otherwise interfere with the output of bpftrace.

## Identifying keycodes

The Linux keycodes are defined in `/usr/include/linux/input-event-codes.h` (see the `KEY_` variables).

### Identifying keycodes in console

The keycodes for virtual console are reported by the showkey(1) utility. showkey waits for a key to be pressed and if none are, in a span of 10 seconds, it quits. To execute showkey, you need to be in a virtual console, not in a graphical environment. Run the following command:

    # showkey --keycodes

and try to push keyboard keys; you should see keycodes being printed to the output.

### Identifying keycodes in Xorg

This article or section needs expansion.

Reason: xev also reports keysyms. Mention that you need to focus the "Event Tester" window. (Discuss in Talk:Keyboard input)
Note The Xorg keycodes are incremented by 8 compared to the Linux keycodes.[2]

The keycodes used by Xorg are reported by a utility called xev(1), which is provided by the xorg-xev package. Of course to execute xev, you need to be in a graphical environment, not in the console.

With the following command you can start xev and show only the relevant parts:

    $ xev | awk -F'[ )]+' '/^KeyPress/ { a[NR+2] } NR in a { printf "%-3s %s\n", $5, $8 }'

    38  a
    55  v
    54  c
    50  Shift_L
    133 Super_L
    135 Menu

Xbindkeys is another wrapper to xev that reports keycodes.

If you press a key and nothing appears in the terminal, it means that either the key does not have a scancode, the scancode is not mapped to a keycode, or some other process is capturing the keypress. If you suspect that a process listening to X server is capturing the keypress, you can try running xev from a clean X session:

    $ xinit /usr/bin/xterm -- :1

### Identifying keycodes in Wayland

Although xev works through Xwayland, you can also use wev to access keycodes under pure Wayland.

For example, this command lets you retrieve only key names and their UTF-8 equivalent:

    $ wev | grep 'sym'

## Tips and tricks

### Configuration of VIA compatible keyboards

VIA is a program to remap keys directly into compatible keyboards. In case you have one of those, in order for the keyboard to be picked up by the browser and configure it online, you need to add a custom udev rule changing the permissions of devices accessed through the hidraw driver.

Note This method might pose a security risk.

Create the following udev rule:

    /etc/udev/rules.d/99-via.rules

    ACTION!="remove", KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0666", TAG+="uaccess", TAG+="udev-acl"

Then reload the rules to take effect.

## See also

- kbd-project - official website of the showkeys utility
- Vial - VIA standalone program

Category:

- Keyboard configuration

Hidden category:

- Pages or sections flagged with Template:Expansion

Keyboard input
Add topic