XKM File Format Description Version 15 1. Introduction The XKM file format is the exchange format for XKB keyboard descriptions between the server and xkbcomp. Usually, the server forks off xkbcomp, xkbcomp compiles the XKM format from the given parameters. The resulting XKM file is put into a directory readable by the server and then parsed. The XKM format is little more than a binary dump of various XKB-specific structures and hence tied to the ABI of the server. ❧❧❧❧❧❧❧❧❧❧❧ 1.1 About this file format description This description was produced by analyzing the XKM parsing code. Parts of the file description present in the original format specification may be missing. This description thus cannot be a reference document for XKM implementations. No description of the meaning of the various fields is given here. Refer to the XKB protocol specification for more details. ❧❧❧❧❧❧❧❧❧❧❧ 2. Notations used in this document Notation for structures: ┌─── Name of struct name of field: type or fixed value of field name of field: type or fixed value of field └─── Data types are identical to those used in the X Protocol specification except where noted otherwise. Structs specific to XKM are prefixed with XKM, defines specific to the XKB protocol specification are prefixed with Xkb and their value is equivalent to that in the protocol specification. Multiple instances of a given type are denoted in the following form: name of field: LISTofFIELDTYPE Length specifiers for such fields are usually prefixed with num_. For example, a struct containing a num_foo of 8 and a 'foo' field contains 8 structures of type 'foo'. Variable length padding is specified as pad(x), where x is the length of the data to be padded out to a multiple of 4 bytes. For example, given an x of 10, pad(x) would be the remaining 2 bytes to pad the whole struct to 12 bytes. A special notation is a variable content struct. In this case, the contents of the struct depend on the value of one or more specific fields. ┌─── Name of struct field: type or fixed value of field field: type or fixed value of field ─── field ⇒ value 1 ⇒ specific field: type specific field: type ─── field ⇒ value 2 ⇒ specific field: type specific field: type └─── This notation denotes that if field is of value 1, this struct contains the specific fields listed underneath value 1. ❧❧❧❧❧❧❧❧❧❧❧ 3. XKM Format The XKM format is a binary format with structs usually being padded to a multiple of 4 bytes. No provisions for endianness are provided, the parser is left to guess the endianness of the XKM file. ❧❧❧❧❧❧❧❧❧❧❧ 3.1 Common data types ┌─── XKMCountedString count: CARD16 string: count * CHAR pad: pad(count + 2) └─── XKMCountedString is used for user-readable identifiers. Prime example are the level names and the section names ("complete", "evdev(inet)", etc.) ┌─── XKMGroupBits: CARD8 group1 0x1 group2 0x2 group3 0x4 group4 0x8 └─── ❧❧❧❧❧❧❧❧❧❧❧ 3.2 Header and Table of Contents ┌─── XKMHeader version: CARD8 identifier1: 'm' identifier2: 'k' idenfifier3: 'x' └─── The XKM file format has a 4 byte header identifying the file and the XKM version. The header is followed by the table of contents indicating the sections present in this file. ┌─── XKMFileInfo type: CARD8 min_keycode: CARD8 max_keycode: CARD8 num_sectioninfo: CARD8 present: CARD16 pad: CARD16 sectioninfo: LISTofXKMSectionInfo └─── min_keycode and max_keycode specify the keycode range for this keyboard descriptions. The core protocol requires min_keycode always be equal to or greater than 8. ┌─── XKMSectionInfo type: CARD16 XkmTypesIndex 0 XkmCompatMapIndex 1 XkmSymbolsIndex 2 XkmIndicatorsIndex 3 XkmKeyNamesIndex 4 XkmGeometryIndex 5 XkmVirtualModsIndex 6 format: CARD16 size: CARD16 offset: CARD16 └─── Describes the section found in a chunk of a file. This struct is found _twice_ in the file per section, once as part of the XKMFileInfo, once at the beginning of the actual section (see offset). The type specifies the type of the section, the section is to be parsed according to this type. Size and offset specify the size in bytes and the offset into the file in bytes, respectively. 3.3 Sections Each section resides at the offset specified in the XKMFileInfo sectioninfo. ❧❧❧❧❧❧❧❧❧❧❧ 3.3.1 XKMTypes An XKMTypes section describes the key types defined in a layout. Roughly speaking, a key type defines how many levels a given key has and which modifiers change to a particular level. ┌─── XKMTypesSection section_info: XKMSectionInfo name: XKMCountedString num_types: CARD16 pad: CARD16 types: LISTofXKMKeyType └─── ┌─── XKMKeyType real_mods: CARD8 num_levels: CARD8 virt_mods: CARD16 num_map_entries: CARD8 num_level_names: CARD8 perserve: CARD8 pad: CARD8 map_entries: LISTofXKMKTMapEntry name: XKMCountedString mods: LISTofXKMModsDesc level_names: LISXTofXKMCountedString └─── The num_map_entries specifies the number of structs in both map_entries and mods. mods is only present if preserve is TRUE. ┌─── XKMKTMapEntry level: CARD8 real_mods: CARD8 virt_mods: CARD16 └─── ┌─── XKMModsDesc real_mods: CARD8 pad: CARD8 virt_mods: CARD16 └─── ❧❧❧❧❧❧❧❧❧❧❧ 3.3.2 XKMCompatMap An XKMCompatMap section describes the actions a keyboard may trigger. This ranges from the TerminateServer action to simple modifier bits. ┌─── XKMCompatMap section_info: XKMSectionInfo name: XKMCountedString num_si: CARD16 group_mask: XKMGroupBits pad: CARD8 si: LISTofXKMSymInterpreterDesc groups: LISTofXKMModsDesc └─── One XKMModsDesc is present for each bit set in group_mask. ┌─── XKMSymInterpretDesc sym: CARD32 mods: CARD8 match: CARD8 virtual_mod: CARD8 flags: CARD8 action_type: CARD8 action_data: XKMActionData └─── Where the action is 7 bytes of CARD8 whose content is determined by action_type. ┌─── XKMActionData: pad0: CARD8 pad1: CARD16 pad2: CARD32 ─── action_type ⇒ XkbSA_SetMods || action_type ⇒ XkbSA_LatchMods || action_type ⇒ XkbSA_LockMods ⇒ flags: CARD8 mask: CARD8 real_mods: CARD8 vmods1: CARD8 vmods2: CARD8 pad: CARD16 ─── action_type ⇒ XkbSA_SetGroup || action_type ⇒ XkbSA_LatchGroup || action_type ⇒ XkbSA_LockGroup ⇒ flags: CARD8 group_XXX: CARD8 pad0: CARD8 pad1: CARD32 ─── action_type ⇒ XkbSA_MovePtr ⇒ flags: CARD8 high_XXX: CARD8 low_XXX: CARD8 high_YYY: CARD8 low_YYY: CARD8 pad: CARD16 ─── action_type ⇒ XkbSA_PtrBtn || action_type ⇒ XkbSA_LockPtrBtn ⇒ flags: CARD8 count: CARD8 button: CARD8 pad: CARD32 ─── action_type ⇒ XkbSA_DeviceBtn || action_type ⇒ XkbSA_LockLockPtrBtn ⇒ flags: CARD8 count: CARD8 button: CARD8 device: CARD8 pad0: CARD8 pad1: CARD16 ─── action_type ⇒ XkbSA_SetPtrDflt ⇒ flags: CARD8 affect: CARD8 valueXXX: CARD8 pad0: CARD32 ─── action_type ⇒ XkbSA_ISOLock ⇒ flags: CARD8 mask: CARD8 real_mods: CARD8 group_XXX: CARD8 affect: CARD8 vmods1: CARD8 vmods1: CARD8 ─── action_type ⇒ XkbSA_SwitchScreen ⇒ flags: CARD8 screenXXX: CARD8 pad0: CARD8 pad1: CARD32 ─── action_type ⇒ XkbSA_SetControls || action_type ⇒ XkbSA_LockControls ⇒ flags: CARD8 ctrls3: CARD8 ctrls2: CARD8 ctrls1: CARD8 ctrls0: CARD8 pad: CARD16 ─── action_type ⇒ XkbSA_RedirectKey ⇒ new_key: CARD8 mods_mask: CARD8 mods: CARD8 vmods_mask0: CARD8 vmods_mask1: CARD8 vmods0: CARD8 vmods1: CARD8 ─── action_type ⇒ XkbSA_DeviceValuator ⇒ device: CARD8 v1_what: CARD8 v1_idx: CARD8 v1_value: CARD8 v2_what: CARD8 v2_idx: CARD8 v2_value: CARD8 pad: CARD8 ─── action_type ⇒ XkbSA_XFree86Private || action_type ⇒ XkbSA_Terminate ⇒ pad0: CARD8 pad1: CARD16 pad2: CARD32 ─── action_type ⇒ XkbSA_ActionMessage ⇒ press_msg: BOOL release_msg: BOOL gen_event: BOOL message: 4 * CHAR └─── Note: XkbSA_ActionMessage is currently unsupported and the contents are ignored. ❧❧❧❧❧❧❧❧❧❧❧ 3.3.3 XkmSymbols The symbols in a keymap define the actual keysyms each key may produce. ┌─── XKMSymbols section_info: XKMSectionInfo name: XKMCountedString min_keycode: CARD8 max_keycode: CARD8 group_names_mask: XKMGroupBits num_vmod_maps: CARD8 group_names: LISTofXKMCountedString keysyms: XKMKeysymMapDesc vmod_maps: XKMVModMapDesc └─── One group_name is present for each bit set in group_names_mask. The number of keysyms present is max_keycode - min_keycode + 1. ┌─── XKMKeysymMapDesc width: CARD8 num_groups: CARD8 modifier_map: CARD8 flags: CARD8 names: LISTofXKMCountedString syms: LISTofCARD32 behavior: XKMBehaviorDesc └─── Presence of names is conditional on the XkmKeyHasTypes flag. The number of strings is equal to the number of group bits in group_names_mask in the preceding XKMSymbols section. The number of elements in syms is equal to width * num_groups. Presence of behavior is conditional on the XkmKeyHasBehavior flag. ┌─── XKMKeyBehaviorDesc type: CARD8 data: CARD8 pad: CARD16 └─── ┌─── XKMVModMapDesc key: CARD8 pad: CARD8 vmods: CARD16 └─── ❧❧❧❧❧❧❧❧❧❧❧ 3.3.4 XKMIndicators ┌─── XKMIndicators section_info: XKMSectionInfo name: XKMCountedString num_indicators: CARD8 pad0: CARD8 pad1: CARD16 indicators: LISTofXKMIndicatorMapDesc └─── ┌─── XKMIndicatorMapDesc name: XKMCountedString indicator: CARD8 flags: CARD8 which_mods: CARD8 real_mods: CARD8 vmods: CARD16 which_groups: CARD8 groups: CARD8 ctrls: CARD32 └─── ❧❧❧❧❧❧❧❧❧❧❧ 3.3.5 XKMKeyNames ┌─── XKMKeyNames section_info: XKMSectionInfo name: XKMCountedString min_keycode: CARD8 max_keycode: CARD8 num_aliases: CARD8 pad: CARD8 keynames: LISTofXKMKeyname aliases: LISTofXKMKeyAlias └─── keynames contains max_keycode - min_keycode + 1 entries. ┌─── XkmKeyname name: 4 * CHAR8 └─── ┌─── XkmKeyAlias real: XkmKeyname alias: XkmKeyname └─── ❧❧❧❧❧❧❧❧❧❧❧ 3.3.5 XKMGeometry ┌─── XKMGeometry section_info: XKMSectionInfo name: XKMCountedString width_mm: CARD16 height_mm: CARD16 base_color_ndx: CARD8 label_color_ndx: CARD8 num_properties: CARD16 num_colors: CARD16 num_shapes: CARD16 num_sections: CARD16 num_doodads: CARD16 num_key_aliases: CARD16 pad: CARD16 label_font: XKMCountedString properties: LISTofXKMGeomProperty colors: LISTofXKMCountedString shapes: LISTofXKMGeomShape sections: LISTofXKMGeomSection doodads: LISTofXKMGeomDoodad key_aliases: LISTofXKMKeyAlias └─── ┌─── XKMGeomProperty name: XKMCountedString value: XKMCountedString └─── ┌─── XKMGeomShape name: XKMCountedString num_outlines: CARD8 primary_idx: CARD8 approx_idx: CARD8 pad: CARD8 outlines: LISTofXKMOutlineDesc └─── ┌─── XKMOutlineDesc num_points: CARD8 corner_radius: CARD8 pad: CARD16 points: LISTofXKMPointDesc └─── ┌─── XKMPointDesc x: INT16 y: INT16 └─── ┌─── XKMGeomSection name: XKMCountedString top: INT16 left: INT16 width: CARD16 height: CARD16 angle: INT16 priority: CARD8 num_rows: CARD8 num_doodads: CARD8 num_overlays: CARD8 pad: CARD16 rows: LISTofXKMRowDesc doodads: LISTofXKMGeomDoodad overlays: LISTofXKMGeomOverlay └─── ┌─── XKMRowDesc top: INT16 left: INT16 num_keys: CARD8 vertical: BOOL pad: CARD16 keys: XKMKeyDesc └─── ┌─── XKMKeyDesc name: XKMKeyname gap: INT16 shape_idx: CARD8 color_idx: CARD8 └─── ┌─── XKMGeomDoodad name: XKMCountedString type: CARD8 priority: CARD8 top: INT16 left: INT16 pad1: CARD16 pad2: CARD32 pad3: CARD32 ─── type ⇒ XkbOutlineDoodad || type ⇒ XkbSolideDoodad ⇒ type: CARD8 priority: CARD8 top: INT16 left: INT16 angle: INT16 color_idx: CARD8 shape_idx: CARD8 pad0: CARD16 pad1: CARD32 ─── type ⇒ XkbTextDoodad ⇒ type: CARD8 priority: CARD8 top: INT16 left: INT16 angle: INT16 width: CARD16 height: CARD16 color_idx: CARD8 pad0: CARD8 pad1: CARD16 text: XKMCountedString font: XKMCountedString ─── type ⇒ XkbIndicatorDoodad ⇒ type: CARD8 priority: CARD8 top: INT16 left: INT16 shape_idx: CARD8 on_color_idx: CARD8 off_color_idx: CARD8 pad0: CARD8 pad1: CARD16 pad2: CARD32 ─── type ⇒ XkbLogoDoodad ⇒ type: CARD8 priority: CARD8 top: INT16 left: INT16 angle: INT16 color_idx: CARD8 shape_idx: CARD8 pad0: CARD16 pad1: CARD32 logo_name: XKMCountedString └─── WARNING: XKMGeomDoodad has variable length depending on the type. NOTE: The current server implementation does not use all fields of all structures. ┌─── XKMOverlayDesc name: XKMCountedString num_rows: CARD8 pad0: CARD8 pad1: CARD16 rows: LISTofXKMOverlayRowDesc └─── ┌─── XKMOverlayRowDesc name: XKMCountedString row_under: CARD8 num_keys: CARD8 pad: CARD16 keys: LISTofXKMOverlayKeyDesc └─── ┌─── XKMOverlayKeyDesc over: XKMKeyname under: XKMKeyname └─── ❧❧❧❧❧❧❧❧❧❧❧ 3.3.6 XKMVirtualMods ┌─── XKMOverlayRowDesc section_info: XKMSectionInfo name: XKMCountedString bound_mask: SETofVMODBITS named_mask: SETofVMODBITS vmods: LISTofCARD8 pad: pad(vmods) names: LISTofXKMCountedString └─── VMODBITS: CARD16 Number of elements in vmods is equal to the number of bits set in bound_mask. The padding completes vmods to a multiple of 4 byte units. Number of elements in names is equal to the number of bits set in named_mask.