Add and Safely Test Custom X Compose Sequences
You will add a user-level X Compose rule for a character or key sequence, keep the system rules available, and test the result without changing system files. This guide follows the Compose(5) behaviour installed with libX11 1.8.7 on this machine. Allow about fifteen minutes. You need an X11 client that uses Xlib input methods, a text editor, and a shell. No root access is needed.
The route
Jump straight to the step you need, or tick off Done means at the end.
1. Check the locale and existing configuration
Compose files are read by Xlib clients, not by the shell or the terminal emulator alone. First record the locale that will select the system Compose file:
$ locale
Keep the output available while you work. The system mapping is resolved through /usr/share/X11/locale/compose.dir. On this machine the locale tree is under /usr/share/X11/locale, and the installed manual identifies the system cache as /var/cache/libx11/compose/ and the per-user cache as $HOME/.compose-cache/.
Next check whether a user file already exists:
$ if [ -e "$HOME/.XCompose" ]; then
printf '%s\n' "$HOME/.XCompose exists"
else
printf '%s\n' 'No user Compose file'
fi
Do not overwrite an existing file blindly. If it contains rules you need, make a backup before editing:
$ cp --preserve=mode,timestamps "$HOME/.XCompose" "$HOME/.XCompose.backup"
The copy command above is only for an existing file. If you later need to undo the edit, restore that backup with mv "$HOME/.XCompose.backup" "$HOME/.XCompose", after checking that the destination is the file you intend to replace.
2. Create a small user Compose file
Use ~/.XCompose for a personal change. The file is plain text: comments start with #, each rule has one or more key events, a colon, and a result. Start with an include so the standard locale rules remain available:
include "%L"
# Compose 'o' followed by 'e' to produce the œ character.
<Multi_key> <o> <e> : "œ"
The %L substitution means the locale-specific Compose file selected by Xlib. The other documented substitutions are %H for the user's home directory and %S for the system Compose directory. An include is preferable to copying the large system file: your local file stays reviewable, and ordinary locale rules continue to come from the package.
If your keyboard does not have a Compose key, configure one through your desktop or window manager first. The rule above describes the input sequence after the Compose key has generated the Multi_key event. It does not assign a physical key to Compose.
3. Add a rule with an explicit modifier requirement
Events can name modifier states. A modifier list without ! gives the allowed state constraints; prefixing the list with ! requires an exact match. A tilde means that the modifier must not be present, and None means no modifier may be present.
For a rule that should require Shift on the final key, add a second line such as:
<Multi_key> <a> <!Shift> : "å"
That line uses the literal UTF-8 character in the result. Compose also accepts octal and hexadecimal escapes, for example "\303\245" or "\xe5", but the value is interpreted for the locale in which the file is used. A result can be a string, a keysym, or both. For example, the keysym-only form is:
<Multi_key> <minus> <minus> : emdash
Keysyms omit the XK_ prefix. If you need stable text bytes for a particular locale, use an explicit string rather than relying on Xlib to derive a string from a keysym.
4. Reload the client and test the sequence
Save the file, then start a new Xlib client. Existing clients may have already read or cached their Compose data, so test in a newly opened terminal or text editor rather than assuming an already running window will reload it.
$ printf '%s\n' 'Open a new X11 text-entry window and press Compose, o, e'
The expected result is œ at the insertion point. Test the untouched path as well: an ordinary sequence that was supplied by the locale should still work because of the include "%L" line.
Checkpoint: if the custom sequence works in a new client but not an old one, close and reopen the old client. If neither works, inspect the file for spelling, angle brackets, and the colon separator. The event names are keysyms, not arbitrary labels, and the result must be on the right side of the colon.
5. Use XCOMPOSEFILE for a controlled test
$XCOMPOSEFILE takes precedence over ~/.XCompose. This is useful for a temporary test or for comparing two files without moving your normal configuration. Create a separate file in a directory you control:
$ test -f /path/to/test-compose && printf '%s\n' 'test file exists'
$ XCOMPOSEFILE=/path/to/test-compose xterm
Replace /path/to/test-compose with a real, readable file. The environment variable applies to the program launched by that command and its children. It does not change the system Compose mapping or your home directory. If xterm is not installed, launch another Xlib client that accepts text input with the same environment assignment.
For repeatable experiments, keep the test file under a temporary directory and remove it only after checking that no process still needs it. Do not put a test file in /usr/share/X11/locale; package upgrades own that directory, and editing it would affect other users.
6. Diagnose cache and parsing surprises
Compose data may be compiled and cached. The documented XCOMPOSECACHE variable selects the directory used for cached compiled files. To isolate a cache issue, point a test client at a private writable directory:
$ cache_dir=$(mktemp -d)
$ XCOMPOSECACHE="$cache_dir" XCOMPOSEFILE="$PWD/test-compose" xterm
$ rm -rf "$cache_dir"
The final command deletes the temporary cache and is safe only when the test client has exited. It does not remove your Compose file. If you use this pattern in a script, add cleanup handling so an interrupted test does not leave temporary data behind.
When a rule fails, reduce it to one sequence and test it in a new client. Check that the include file exists, that every event is enclosed in angle brackets, and that a literal < or > in HTML documentation has not been copied as HTML markup into the actual text file. The Compose parser expects the text form shown in the examples.
Done means
~/.XComposecontains an include for%Land only the local rules you need.- The custom sequence works in a newly started Xlib client.
- Existing locale sequences still work.
- Modifier-sensitive rules have been tested with and without the required modifier.
- A failed experiment can be undone by restoring the backup or removing only the user file, without touching system Compose files.