Wrong with these XKB rules files

xkb

I am playing with xkeyboard-config. Currently, I'm trying to understand the rules files.

I've used xkbcomp to get the current keymap from the X server and write it to a file. This keymap is the default keymap, which loads without errors when setxkbmap is run without any arguments. I've then pulled the individual components into their own files, and I've placed the files into a directory structure resembling the xkb config directory structure.

It looks like this:

xkb
├── compat
│   └── current
├── geometry
│   └── current
├── keycodes
│   └── current
├── rules
│   ├── current
│   ├── current.lst
│   └── current.xml
├── symbols
│   └── current
└── types
    └── current

I have created the files in the rules subdirectory myself in an attempt to create a minimal set of rules files capable of loading a single layout.

When I point setxkbmap at this directory and try to load the keymap therin, I get an error, despite not having at all changed the contents of the components.

$ setxkbmap -Ixkb -v 10 -rules current -layout current -model current -variant current
Setting verbose level to 10
locale is C
Warning! Multiple definitions of rules file
         Using command line, ignoring X server
Warning! Multiple definitions of keyboard model
         Using command line, ignoring X server
Warning! Multiple definitions of keyboard layout
         Using command line, ignoring X server
Trying to load rules file ./rules/current...
Trying to load rules file /usr/share/X11/xkb/rules/current...
Trying to load rules file xkb/rules/current...
Success.
Applied rules from current:
rules:      current
model:      current
layout:     current
variant:    current
Trying to build keymap using the following components:
keycodes:   current
types:      current
compat:     current
symbols:    current
geometry:   current
Error loading new keyboard description

If I load the keymap by adding the -print option to setxkbmap, and piping the result into xkbcomp, the keymap is compiled and loaded without any errors.

Since the only things that have substantially changed from how the X server loads the keymap to how I load the keymap are the rules files being used and the organization of the components, I'm presuming that the source of the error resides there. What is wrong with the setup that I have created? Why do I get an error when I try to reload the keymap using setxkbmap?

For reference, the contents of the rules files follow.

xkb/rules/current

! model layout variant = keycodes types compat symbols geometry
  current current current = current current current current current

xkb/rules/current.lst

! layout
  current Current Layout

xkb/rules/current.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xkbConfigRegistry SYSTEM "xkb.dtd">
<xkbConfigRegistry version="1.1">
  <modelList>
    <model>
      <configItem>
        <name>current</name>
        <description>Current Model</description>
        <vendor>Zistack</vendor>
      </configItem>
    </model>
  </modelList>
  <layoutList>
    <layout>
      <configItem>
        <name>current</name>
        <description>Current Layout</description>
        <languageList>
          <iso639Id>eng</iso639Id>
        </languageList>
      </configItem>
      <variantList>
        <variant>
          <configItem>
            <name>current</name>
            <shortDescription>current</shortDescription>
            <description>current</description>
            <languageList>
              <iso639Id>eng</iso639Id>
            </languageList>
          </configItem>
        </variant>
      </variantList>
    </layout>
  </layoutList>
</xkbConfigRegistry>

Best Answer

Your format is off. See section 4.3 in this old doc or the Rules section of this newer version. Doug Palmer's Unreliable Guide is slightly dated but also a good resource.

You attempted:

! model layout variant = keycodes types compat symbols geometry
  current current current = current current current current current

Specifically, the righthand side of the = takes a single argument. On the ! line, the righthand side is a single type of file -- only one of {keycodes, types, compat, symbols, geometry} is allowed. On the other lines, the righthand side is a single argument meaning:

  • a single file found in the type subdirectory (test1)
  • a stanza defined in such a file (test1(foo))
  • an addition to an earlier match (+test2 or +test2(bar))
  • several files/stanzas joined together (test1+test1(foo)+test2(bar)+test3(baz))

The lefthand side is a filter; you can include as many as you want of these.

Basically, the rules build separate filesets for each of those types.

// KEYCODES SECTION
// load keycodes based on model specified
! model = keycodes
  test1  = test1
// ^^^^^^^^^^^^^^ 
//        "if model=test1, 
//         load the default in the file keycodes/test1"

// load keycodes based on layout specified
! layout = keycodes
  test1  = +test1(us)
// ^^^^^^^^^^^^^^
//        "if layout=test1, 
//         also load stanza "us" in the file keycodes/test1"


// all at once
! model layout variant option = keycodes
  test2 test2  test2   test2  = test1+test1(de)+test1(var2)+test1(opt2)
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//        "if model=test2 and layout=test2 and... ,
//         load the default stanza in file keycodes/test1,
//         then load stanza "de" in file keycodes/test1, ...


////////////////
// GEOMETRY SECTION
// load geometry based on model specified
! model = geometry
  test1 = test1
  *     = test3  // any other model

With these rules defined, you can play with setxkbmap -print to see your rules in action:

$ setxkbmap -I/path/to/my/xkb -rules test1 -model test1 -print
xkb_keymap {
        xkb_keycodes  { include "test1" };
        xkb_geometry  { include "test1" };
};
// no xkb_symbols or other sections of the map with only the rules above

$ setxkbmap -I/path/to/my/xkb -rules test2 -model test1 -layout test1 -print
xkb_keymap {
        xkb_keycodes  { include "test1+test1(us)"       };
        xkb_geometry  { include "test1" };
};

$ setxkbmap -I/path/to/my/xkb -rules test2 -model test2 -layout test2 -variant test2 -option test2 -print
xkb_keymap {
        xkb_keycodes  { include "test1+test1(us)+test1(var1)+test1(opt2)" };
        xkb_geometry  { include "test3" };
};

That's the basics of how the rules work, but of course it can get much more complicated.

  • %l and %v are variables with the layout and variant (%m can also be used for the model)
  • %(v) wraps the expansion in parentheses, so %l%(v) yields layout(variant)
  • if multiple layouts/variants are defined, they're accessible as an array, and you'll need to add an index: %l[1] (%l will not work )
  • if multiple layouts/variants are defined, add :2 (or :3 or :4) to restrict the files loaded to the 2nd (or 3rd or 4th) layout

Here's a very basic rules section that will pull in multiple layouts properly:

// setxkbmap -layout foo -variant foo1
! model    layout      =   symbols                                                                                                                                         
   *       *           =   %l%(v)                                                                                                                                                   

// setxkbmap -layout foo,bar -variant foo1,bar1                                                                                                                                                                                     
! model   layout[1]    =   symbols                                                                                                                                         
   *       *           =   %l[1]%(v[1])                                                                                                                                             

// setxkbmap -layout foo,bar -variant foo1,bar1                                                                                                                                                                                     
! model   layout[2]    =   symbols                                                                                                                                                 
   *       *           =   +%l[2]%(v[2]):2                                                                                                                                             

// setxkbmap -layout foo,bar,baz -variant foo1,bar1,baz1                                                                                                                                                                                     
! model   layout[3]    =   symbols                                                                                                                                                 
   *       *           =   +%l[3]%(v[3]):3                                                                                                                                             

// setxkbmap -layout foo,bar,baz,bat -variant foo1,bar1,baz1,bat1                                                                                                                                                                                     
 ! model   layout[4]   =   symbols                                                                                                                                             
   *       *           =   +%l[4]%(v[4]):4

Now you can load testing layouts into setxkbmap and see that they're being added.

$ setxkbmap -I/path/to/my/xkb -rules test -model test1 \
            -layout test1,test2,test3                  \
            -variant test1,testA,testB -print
xkb_keymap {
        xkb_keycodes  { include "test1+test1(us)" };
        xkb_symbols   { include "test1(test1)+test2(testA):2+test3(testB):3" };
        xkb_geometry  { include "test1" };
};
Related Question