[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: XKB problem with x-terminal

On Fri, Dec 09, 2005 at 11:22:30PM +0200, Simo Kauppi wrote:
> On Thu, Dec 08, 2005 at 09:34:26PM +0100, Almut Behrens wrote:
> > On Wed, Dec 07, 2005 at 02:16:09PM +0200, Simo Kauppi wrote:
> > > Is there a way to compile keyboard definitions for X and save them
> > > somewhere, where XServer can read them, when it starts?
> > 
> > $ xkbcomp -xkm :0 keymap.xkm
> > Then, simply transfer the resulting keymap.xkm to your thinclient,
> > where you can make the X server load it upon startup using the option
> > "-xkbmap keymap.xkm".
> Thanks a lot, I hadn't figured this one out. Unfortunately, if I start X
> with -xkbmap keymap.xkm, it says it doesn't like it!
> If I start X with -xkbdb keymap.xkm, it doesn't complain, but the
> keyboard doesn't behave properly :(

Not too surprising.  That option's value is assigned to some variable
XkbDB (in xc/programs/Xserver/xkb/xkbInit.c) which isn't used anywhere
else beyond this assignment, in the entire X sources.  Whatever that's
supposed to do, it isn't implemented yet ;)

The fact that -xkbmap doesn't work as advertised, isn't too surprising
either, 'cos I was telling rubbish  (yeah, next time, Almut reminds
herself to actually verify the stuff she's claiming...)

Well actually, this option does work, kind of, but not in a manner as
straightforward as on might expect.  However, I knew for sure I once
had it working already, so I've played around with it some more... 
Well, found lots of weird things.  But don't worry, I won't bore you
with the details.  Just a brief description of how I finally got it
working, after lots of strace'ing and poking around in the X sources.

All in all, I can't help getting the impression, that Simo and me are
to the only two people in this world who have ever tried to make use of
this -xkbmap option :)

My main observations:

* you can't keep the X server from wanting to call xkbcomp, even in the
presence of a perfectly valid compiled xkbmap.  At least, I dunno how.

* even though the output of the xkbcomp run isn't really used in this
case (AFAICT), it is good to have it succeed, superficially.  In case
of any failures in this step, a couple of other things are being tried
which eventually lead to a complete failure of the whole shebang.

* you are expected to specify the bare name of the keymap (without the
.xkm extension);  the X server looks for the map in certain predefined
directories (which do vary depending on which UID the server is started as)

* unless you have a dot in the keymap name, the X server deletes the
map before reading it.  No kidding.  This seems to be because the
path of the temporary output file (created during the useless run of
xkbcomp) is being set to where the real keymap is expected to be found.
And tempfile cleanup happens before the actual "-xkbmap"-related code
gets a chance to read it...  Luckily, there's some odd "sanitizing"
being applied to the tempfile name (replacing '.' by '_').  That allows
us to play tricks here:

1: 6929  execve("/usr/bin/X11/XFree86", ["/usr/X11R6/bin/X", ":1", "-xkbmap", "default.map"], [/* 14 vars */]) = 0
2: 6930  execve("/usr/X11R6/lib/X11/xkb/xkbcomp", ["/usr/X11R6/lib/X11/xkb/xkbcomp", "-w", "1", "-R/usr/X11R6/lib/X11/xkb", "-xkm", "-em1", "The XKEYBOARD keymap compiler (x"..., "-emp", "> ", "-eml", "Errors from xkbcomp are not fata"..., "keymap/default.map", "compiled/default_map.xkm"], [/* 14 vars */]) = 0
3: 6931  lstat64("/usr/X11R6/lib/X11/xkb/compiled/default_map.xkm", 0xbffffa1c) = -1 ENOENT (No such file or directory)
4: 6931  stat64("/usr/X11R6/lib/X11/xkb/keymap/default.map", {st_mode=S_IFREG|0644, st_size=7804, ...}) = 0
5: 6931  open("/usr/X11R6/lib/X11/xkb/keymap/default.map", O_RDONLY|O_LARGEFILE) = 6
6: 6931  open("/usr/X11R6/lib/X11/xkb/compiled/default_map.xkm", O_WRONLY|O_CREAT|O_LARGEFILE, 0100644) = 7
7: 6929  open("/usr/X11R6/lib/X11/xkb/compiled/default_map.xkm", O_RDONLY) = 6
8: 6929  unlink("/usr/X11R6/lib/X11/xkb/compiled/default_map.xkm") = 0
9: 6929  open("/usr/X11R6/lib/X11/xkb/compiled/default.map.xkm", O_RDONLY) = 6

These are the relevant lines from the strace output when running X with
"-xbkmap default.map" (line numbers prepended).  As you can see, for
some calls it uses "default_map" in place of "default.map".

The open() in line 9 apparently is what finally makes things work.
The open() of the tempfile in line 7 has to succeed, too, or else weird
things happen, and the real open() in line 9 never takes place.  Line 8
shows that tempfile cleanup now is no longer deleting the real file.

So, to summarize, here's what I did:

* moved away the original /usr/X11R6/lib/X11/xkb directory (a link to
/etc/X11/xkb, normally), preventing X from accessing anything in there.

* uncommented all 'Option "Xkb*"' entries in XF86Config-4/xorg.conf.

* created a dummy replacement for xkbcomp. This is just a simple script
which copies the precompiled keymap to the tempfile location where X is
expecting to find it -- hereby simulating a successful compile run:

  $base = "/usr/X11R6/lib/X11/xkb/";
  $dest = pop @ARGV;            # of the 12 args that xkbcomp is called
  $src  = $base . pop @ARGV;    # with, the last two are of interest...
  $dest = "$base$dest" if $dest !~ m|^/|;
  system 'cp', $src, $dest;     # create expected output
  exit 0                        # always succeed

(If you want your thinclient to be really thin, i.e. without perl, you
could of course rewrite this in shell, or even replace it with just a
single cp call. Once you've figured out where the files are supposed
to be placed, you no longer need the flexibility of the script...)

* created a new xkb directory, containing just the following:

-rwxr-xr-x root/root   313 /usr/X11R6/lib/X11/xkb/xkbcomp
drwxr-xr-x root/root     0 /usr/X11R6/lib/X11/xkb/keymap/
-rw-r--r-- root/root  7804 /usr/X11R6/lib/X11/xkb/keymap/default.map
drwxr-xr-x root/root     0 /usr/X11R6/lib/X11/xkb/compiled/
lrwxrwxrwx root/root     0 /usr/X11R6/lib/X11/xkb/compiled/default.map.xkm -> /usr/X11R6/lib/X11/xkb/keymap/default.map
lrwxrwxrwx root/root     0 /var/tmp/default.map.xkm -> /usr/X11R6/lib/X11/xkb/keymap/default.map

(xkbcomp is the above script. default.map is the compiled keymap.
The map in /var/tmp/ is used when X is run as a regular user.)

That's it.  I created a new clean user account, and started the "thin"
X with "-xkbmap default.map".  No more error messages from X, and my
usual german keyboard layout (which I had previously extracted using
"xkbcomp -xkm :0 default.map") works without a hitch -- to my surprise
even all my specially xmodmap'ed windows and "web" keys...

I'm not saying this is way to do it -- just that it worked for me :)
Tried with various versions of X from woody's XFree86 to Xorg-6.8.2.

Let me know whether it works for you, too, Simo.  I'm afraid I won't be
able to help, if not, though -- just out of curiosity...


(...and I said, I wouldn't bore you with details... Well.)

Reply to: