console-fb-realizer — realize a user-space virtual terminal on a framebuffer
console-fb-realizer [--display-only] {--kernel-vt filename} {--vtfont filename} {--font-medium-r filename} {--font-medium-o filename} {--font-medium-i filename} {--font-bold-r filename} {--font-bold-o filename} {--font-bold-i filename} {fbname} {eventname} {kbdmapname} {vcname}
console-fb-realizer is the I/O back-end for a (user-space) virtual terminal, that realizes that virtual terminal with a framebuffer device and an event device.
It opens the character/attribute buffer file
and the input FIFO
vcname/display.
These are the "master side" interfaces of the user-space virtual terminal,
as detailed in
console-terminal-emulator(1).
vcname/input
It also opens the framebuffer device
fbname and the event device
eventname.
These are the concrete devices with which the user-space virtual terminal
is to be realized.
It is the user's responsibility to ensure that these refer to the same,
single, physical user station.
It then enters a loop where it simultaneously:
(unless the --display-only option is used) writes all data received from the input device to the input FIFO for the virtual terminal, translating to the abstract keyboard; and
renders the contents of the character/attribute buffer file for the virtual terminal on the framebuffer.
Setting up multiple user stations is a simple matter of running multiple console-fb-realizer processes, each using the individual framebuffer and input event devices for a particular user station. Multiplexing one realizer across multiple virtual terminals is done with an intermediary such as console-multiplexor(1).
In the simplest use case, fbname and
eventname are wholly dedicated to this realizer, and
are not shared with anything else.
On Linux, this can be the case as long as fbname and
eventname are not also used by the kernel virtual
terminal subsystem (or another program such as an X server).
This will definitely be the case if the kernel has been compiled not to have a
virtual terminal subsystem in the first place (and no X server has been
instructed to use the same devices).
If the framebuffer and input event devices are also used by the kernel virtual
terminal subsystem, however, then the --kernel-vt
command-line option must be used to specify the
filename of an appropriate kernel VT device.
This device is used to negotiate, with the kernel VT subsystem and other
cooperating systems (such as an X server), shared access to the framebuffer and
to the input event subsystem.
Neither FreeBSD nor PC-BSD provide direct access to raw framebuffer and input
event devices; they are mediated through the kernel virtual terminal subsystem
and one must use a kernel virtual terminal device as both
fbname and eventname.
console-fb-realizer switches the framebuffer device into
graphics mode, the line discipline to raw mode, and the keyboard driver to
deliver raw keycodes, for the duration; switching them back to their saved
prior settings upon its termination.
Virtual terminal display buffers have faint, boldface, italic, strikethrough, and underline attributes for character cells. Only faint, boldface, and italic involve font support, mapping to four font weights (light, medium, demibold, and bold) and two slants (upright and italic). Strikethrough and underline attributes are rendered not through font selection but by overwriting the non-strikethrough non-underline glphys with appropriate horizontal lines. If faint and demibold weights are unavailable, the faint attribute is emulated by shading the foreground and background colours towards black. If bold weight is unavailable, the bold attribute is rendered by overlaying a glyph with a shifted copy of itself. If italic stroke is unavailable, the italic attribute is rendered as oblique by shifting the upright glyph. (Oblique is not the same as italic, note, and is often an inferior substitute for it.)
Fonts are loaded from font files, which may be either in the FreeBSD/PC-BSD
"vtfont" format or in the straight 8 by 16 unadorned bitmap format used by
FreeBSD's "syscons".
(To convert an Adobe BDF format font file to "vtfont" format, use the FreeBSD
vtfontcvt(1)
utility.)
Font files are specified by the filename in the
--vtfont ,
--font-medium-r ,
--font-medium-o ,
--font-medium-i ,
--font-bold-r ,
--font-bold-o , and
--font-bold-i
command-line options.
Fonts must be monospace fonts with a height of 8, 14, 15, or 16 and a width of
8, 9, 12, or 16.
All glyphs are rendered in a 16 by 16 bounding square, with 8 by 8 pixel
fonts doubled to 16 by 16 pixels.
The weight and slant are encoded via these command-line options, because not all supported font formats include meta-information about weight and slant in the file itself (usually it is encoded in the filename). The "vtfont" format does, however. It has glyph sets for two different combinations of weight and slant (upright and upright bold) To load both sets of glyphs, one can load the font with the --font-medium-r and the --font-bold-r command-line options. Each option individually loads only those glyphs that match the weight and slant that the option specifies, providing fine-grained control of what glyphs are used from what "vtfont" font. To load all glyphs from the font with the appropriate weights and slants, without the repetition, use the --vtfont command-line option.
With no fonts loaded, and for any characters which cannot be found in the loaded fonts, console-fb-realizer "greeks" its output, falling back to displaying a blank for any whitespace characters, a box for any C0 or C1 control characters, and a block for all other characters. Such "greeking" is of course illegible; and it is recommended that sufficient fonts be loaded in order to render at least the whole of Microsoft's Windows Glyph List 4. (One might be tempted to simply cover the OpenType W1G character set instead. Bear in mind that the W1G character set does not include line drawing, block, arrow, and other characters that are commonly employed by TUI systems to draw UI widgets; whereas WGL4 does.)
Fonts are loaded at program initialization and remain loaded thereafter. To change fonts, it is necessary to stop and restart console-fb-realizer. This does not, of course, affect the operation of the terminal emulator or the processes using the terminal.
The input event device provides a sequence of keycode numbers, with attached press/release flags. These are translated to keyboard actions through use of a loadable keyboard map. Unfortunately, Linux and the BSDs do not agree on a single set of keycode numbers, and cannot share one another's keyboard layout definitions. So the realizer first translates the non-portable Linux and BSD keycodes into a common set. It is this common set that is actually used in key maps.
The map is stored in the file kbdmapname
in machine-readable form.
FreeBSD/PC-BSD keymaps can be compiled from the BSD
kbdmap(5)
human-readable form to this machine-readable form with the
console-convert-kbdmap(1)
command.
In machine-readable form, a map is a simple succession of map entries, representing 17 "rows" of 16 "columns" per row, in row-major order. Each map entry comprises twenty-four big-endian 32-bit integers.
A map entry describes two things: a set of possible actions to be taken when the key is pressed and released, and how to select which action based upon the momentary keyboard modifier state. Keyboard modifiers comprise (in ISO 9995-1 terminology) modifiers for level 2, level 3, and group 2; for caps, num, and shift locks; and for super, alt, and control. What keys act as these modifiers is of course determined by the keyboard layout: but often the level 2 modifiers are the shift keys; the level 3 modifier is the "Option" (Apple keyboards) or "AltGr" (IBM PC/AT keyboards) key; and super is the "Command"/'Apple" (Apple keyboards), "Meta" (Sun keyboards), or "Windows" (Microsoft keyboards) key.
The selection class code is first in each entry, and the code values are here designated by their UCS-4 code points.
p' (U+00000070, "plain")The keyboard modifier state is entirely ignored and the first action is always chosen.
s' (U+00000073, "shiftable")When selecting an action, the sense of the level2 modifier state is inverted by the shift lock state. Shift lock operates like the typewriter facility of that name, locking on until either level2 modifier key is pressed. This is generally used for non-alphabetic keys that obey shift lock but not caps lock.
c' (U+00000063, "capsable")When selecting an action, the sense of the level2 modifier state is inverted by the OR-combined caps lock and shift lock states. This is generally used for alphabetic keys that obey caps lock and shift lock.
n' (U+0000006E, "numable")When selecting an action, the sense of the level2 modifier state is inverted by the OR-combined num lock and shift lock states. This is generally used for auxiliary keys that obey num lock and shift lock.
f' (U+00000066, "funcable")When selecting an action, the sense of the level2 modifier state is inverted by the shift lock state, and the level3 modifier state is replaced by the alt state. This is generally used for function block keys that obey shift lock but not caps lock.
The next seven 32-bit numbers are reserved, and should be set to zero. The actions, chosen according to the selection class, are the remaining sixteen 32-bit numbers. These denote the actions for various combinations of modifiers: none, level2, control, control+level2, level3, level2+level3, control+level3, control+level2+level3, group2, group2+level2, group2+control, group2+control+level2, group2+level3, group2+level2+level3, group2+control+level3, and group2+control+level2+level3, with inversions and replacements as aforementioned.
The most significant byte denotes the action type and the interpretation of the remainder of the action. (These are, intentionally, similar to the input protocol used by console-terminal-emulator(1), aimed at making debugging and trace analysis simpler. They are two distinct and separate protocols, however.)
0x00xxxxxxNo-operation, Take no action. This is used for keys that have no action in the key map.
0x01nnnnnn
UCS-3 key.
On press or autorepeat,
a unicode character message for the code point nnnnnn is sent to the input FIFO.
0x03nnnncc
Modifier key.
Modifiers do not autorepeat.
On press or release,
the modifier key nnnn is enacted against the current keyboard modifier state
according to the cc command.
0x01Momentary. The modifier is on when the key is pressed, and off when the key is released.
0x02Latching. Pressing the key latches the modifier on until a non-modifier key is pressed.
0x03Locking. Pressing the key locks the modifier on; releasing and pressing it again locks it back off.
0x0Annnnxx
Session selection key.
On press or autorepeat,
a session selection message for the session number nnnn is sent to the input FIFO.
0x0Cnnnnxx
Consumer key.
On press or autorepeat,
a consumer key message for the consumer key number nnnn is sent to the input FIFO.
0x0Ennnnxx
Extended key.
On press or autorepeat,
an extended key message for the extended key number nnnn is sent to the input FIFO.
0x0Fnnnnxx
Function key.
On press or autorepeat,
a function key message for the function key number nnnn is sent.
This is used for keyboard layouts where the function key block has a large number
of actual keys.
The terminal emulator, and processes connected to the terminal, will see
function keys with modifiers.
0x1Fnnnnxx
Unmodifiable function key.
On press or autorepeat,
a function key message for the function key number nnnn is sent.
The accompanying keyboard modifier state does not incorporate the level or
group modifiers, which will never be seen by the terminal emulator or processes
connected to the terminal.
This is used for keyboard layouts where the function key block has a small
number of actual keys and the level+group modifiers are used "locally"
(within the realizer) to simulate a larger key block.
Keyboard maps are tailored, of course, to country, layout (QWERTY, AZERTY, Dvorak, Maltron, and so forth), and the physical layout of the keyboard (104 keys, 109 keys, 124 keys, and so forth). Here are some example keymap entries:
0x00000063,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x01000073,
0x01000053,
0x01000013,
0x01000013,
0x010000DF,
0x010000A7,
0x01000013,
0x01000013.
0x01000073,
0x01000053,
0x01000013,
0x01000013,
0x010000DF,
0x010000A7,
0x01000013,
0x01000013.
'S' on the U.S. International IBM PC/AT keyboard, QWERTY layout.
It varies according to caps lock, and produces 'ß' and
'§' with the level 3 modifier.
The control modifier always produces DC3 (U+0013).
0x00000066,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x0E0F0100,
0x1F000D00,
0x1F001900,
0x1F002500,
0x0A000100,
0x0A000D00,
0x0A001900,
0x0A002500.
0x0E0F0100,
0x1F000D00,
0x1F001900,
0x1F002500,
0x0A000100,
0x0A000D00,
0x0A001900,
0x0A002500.
F1 on the U.S. International IBM PC/AT keyboard, QWERTY layout. It ignores level 3, varying according to the level 2, alt, and control modifiers to produce either PAD_F1, F13, F25, and F37 or session switch commands for sessions 1, 13, 25, and 37. See console-terminal-emulator(1) for why the base, unmodified, key is the PAD_F1 key, not the F1 key.
So-called "dead" keys are otherwise ordinary UCS-3 keys in a keyboard map, except that they denote Unicode combining characters; i.e. characters in the "Me" ("Mark, Enclosing") and "Mn" ("Mark, Non-spacing") Unicode code point categories. console-fb-realizer remembers such "dead" keys, without transmitting them to the input FIFO as they are pressed (or autorepeated). It attempts to combine them with the next non-combining character keypress. In this respect it behaves mostly according to ISO/IEC 9995-3 and DIN/EN 2137:
console-fb-realizer implements the extra so-called "peculiar" combinations given by the ISO and DIN standards (and also found in several other national keyboard standards). These are applied before attempting any Unicode composition. Most of these involve:
COMBINING SHORT STROKE OVERLAY (U+0335)
In ISO 9995-3 keyboard layouts this is
Group2+Level3+C08
(Shift+Option, Option+'K' on
the U.S. International keyboard).
Unicode does not define any compositions using this combining character.
COMBINING LONG SOLIDUS OVERLAY (U+0338)
In ISO 9995-3 keyboard layouts this is
Group2+Level3+C09
(Shift+Option, Option+'L'
on the U.S. International keyboard).
Unicode also defines compositions using this combining character.
The ISO 9995-3 compositions overlap in only one case, which is the same in both
ISO 9995-3 and Unicode.
The ISO and DIN standards define "peculiar" combinations with the space character that generate standalone accents. Any sequence of "dead" keys followed by Space generates a sequence of precomposed non-combining accent characters that correspond to the combining characters.
The ISO and DIN standards are not specific about Unicode combining characters. console-fb-realizer applies the "canonical" composition rules given by Unicode, attempting to produce a stream of input characters in Unicode Normalized Form C. Any leftover combining characters that cannot be precomposed are treated as if combined with Space, and emitted before the composed character. This differs from Unicode Normalization, where leftover combining characters always follow the "starter" character. Having leftover combining characters precede the composed character both mimicks the existing behaviour of "dead" keys on several systems and is least surprising to the typist as it (roughly) preserves typed order. (Typed order is not entirely preserved; the "dead" keys are sorted by Unicode combining class as a side-effect of NFC composition.)
Not all input is in Unicode Normalized Form C.
The ISO and DIN standards define a "pass-through" mechanism that allows a
typist to enter combining characters as-is: any sequence of "dead" keys
followed by the Zero-Width Non-Joiner (entered as
Group2+Level2+A03 in ISO 9995-3 keyboard
layouts; which is Shift+Option,
Shift+Space on the U.S. International keyboard)
generates that sequence of non-combining characters in typed order.
Full Unicode Normalization is not performed. In particular, if the typist enters a precomposed character after the "dead" keys, it is not decomposed before the composition rules are applied. This is done in order not to surprise the typist. Full Unicode NFD decomposition followed by Unicode NFC composition could result in different leftover combining characters in some cases. It also would perform various one-way transformations.
console-fb-realizer only requires sufficient privileges to access the framebuffer, the input device, the display buffer file, and the FIFO. Superuser privileges are not necessary. The recommended configuration is that the file and the FIFO are (respectively) readable and writable by a dedicated unprivileged user or group.
It does not attempt to create the file or FIFO if they do not exist, because this would create them with the wrong owner and group; and it thus requires no write access to their containing directory.