This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Compose and Dead Keys
Some text takes more than one key. On a Swedish keyboard, é is typed with the dead acute key followed by E. With a Compose key, © can be Compose, O, C. These are compose sequences. libxkbcommon handles them separately from keymaps, with a compose table and a compose state.
Typing with key-press-text
For text input, this is all you need:
(xkb:key-press-text keyboard-state compose-state keycode)
It returns the text a press of the key types, or nil, with sequences
composed. On a Swedish keyboard with the en_US.UTF-8 table:
| Key pressed | key-press-text |
|---|---|
| dead acute | nil: the sequence has begun |
| E | "é" |
| A | "a" |
| dead acute | nil |
| Q | nil: Q breaks the sequence, which types nothing |
| dead acute, dead acute | nil, then "´" |
Rules:
- Call it once per press, never for releases. It feeds the key to the compose state, so calling it twice for one press feeds the key twice.
- With
update-key, call it before updating the keyboard state for the same press. - Pass
nilas the compose state to get the key's own text, without composing. Do that where the locale has no compose table, and for repeats of a held key, which should type the key again rather than continue a sequence.
Compose tables
A compose-table holds the sequences of a locale. There are two ways to
make one.
From the system: make-compose-table
(xkb:with-compose-table (table context :locale "en_US.UTF-8")
...)
(xkb:make-compose-table context) ; the environment's locale
This reads the system's compose file for the locale, plus the user's
compose file: the file named by the XCOMPOSEFILE environment variable, or
else ~/.XCompose if there is one. The locale defaults to the
environment's: the first of LC_ALL, LC_CTYPE and LANG that is set, or
"C".
The tables come with X11. On Debian and Ubuntu they are in libx11-data,
under /usr/share/X11/locale/. If the locale has no table,
make-compose-table signals an xkb-error. With :errorp nil it returns
nil instead, and leaves the reason to take-log-messages. A nil table
means typing without composing: with-compose-state binds nil for it,
and key-press-text takes nil as no compose state.
(xkb:with-compose-table (table context :errorp nil)
(xkb:with-compose-state (compose table) ; NIL if TABLE is
(xkb:key-press-text state compose keycode)))
From text: make-compose-table-from-string
(xkb:make-compose-table-from-string context
(format nil "<dead_acute> <e> : \"é\" eacute~%~
<Multi_key> <o> <c> : \"©\" copyright~%"))
The text is in the XCompose format, man 5 Compose. Each line is a
sequence of keysym names in angle brackets, a colon, then the result as a
quoted string, a keysym name, or both. An include line can pull in other
files, and in an include, %L stands for the locale's system table. The
:locale argument, "C" by default, decides which file that is:
(xkb:make-compose-table-from-string context
(format nil "include \"%L\"~%<Multi_key> <l> <l> : \"λ\"~%")
:locale "en_US.UTF-8")
A line that does not parse is skipped. libxkbcommon logs why, and
take-log-messages returns it:
(xkb:with-context (context :environment nil)
(let ((table (xkb:make-compose-table-from-string context
(format nil "<Multi_key> <c> <o> : \"©\"~%<Multi_key> <x> : bogus~%"))))
(xkb:take-log-messages context)
;; => ((:ERROR "(input string):2:19: unrecognized keysym \"bogus\" on right-hand side"))
...))
Only text that cannot make a table at all signals an xkb-error.
Compose states
A compose-state tracks one sequence in progress. Make one per keyboard:
(xkb:with-compose-state (compose table)
...)
Reset it with compose-reset when the keyboard focus moves, so that a
sequence does not carry over to another window.
Handling sequences yourself
key-press-text is built on these functions. Use them to show a sequence
in progress, as some text fields do, or to act on the composed keysym.
Feed the compose state the keysym of every key pressed, with
compose-feed. It returns the status after the key:
| Status | Meaning | What to do |
|---|---|---|
:nothing |
no sequence is under way | use the key's own text, from key-text |
:composing |
the key started or continued a sequence | type nothing yet |
:composed |
the key completed a sequence | type compose-text, then call compose-reset |
:cancelled |
the key broke the sequence | type nothing, then call compose-reset |
Keysyms of modifiers, such as Shift_L, leave the status as it was, so
Shift can be pressed in the middle of a sequence.
| Function | Returns |
|---|---|
compose-feed |
the status after feeding a keysym |
compose-status |
the current status, without feeding anything |
compose-text |
the composed text when the status is :composed, else nil |
compose-keysym |
the composed keysym when the status is :composed, else nil |
compose-reset |
nothing; returns the state to :nothing |