Bug 16364 - Behavior of xmodmap differs when invoked before any key has been pressed
Summary: Behavior of xmodmap differs when invoked before any key has been pressed
Status: RESOLVED FIXED
Alias: None
Product: xorg
Classification: Unclassified
Component: Server/Input/XKB (show other bugs)
Version: 7.3 (2007.09)
Hardware: x86 (IA32) Linux (All)
: medium normal
Assignee: Daniel Stone
QA Contact: Xorg Project Team
URL:
Whiteboard:
Keywords:
Depends on: 12523 24552
Blocks: 16562
  Show dependency treegraph
 
Reported: 2008-06-15 11:32 UTC by Clemens Fuchslocher
Modified: 2010-09-03 13:24 UTC (History)
3 users (show)

See Also:
i915 platform:
i915 features:


Attachments
xkeycaps-correct.png (17.90 KB, image/png)
2008-06-15 11:33 UTC, Clemens Fuchslocher
no flags Details
xmodmap-correct.png (10.31 KB, image/png)
2008-06-15 11:35 UTC, Clemens Fuchslocher
no flags Details
xkeycaps-broken.png (17.97 KB, image/png)
2008-06-15 11:35 UTC, Clemens Fuchslocher
no flags Details
xmodmap-broken.png (9.95 KB, image/png)
2008-06-15 11:35 UTC, Clemens Fuchslocher
no flags Details
xkeycaps-fixed.png (17.90 KB, image/png)
2008-06-15 11:35 UTC, Clemens Fuchslocher
no flags Details
xmodmap-fixed.png (12.30 KB, image/png)
2008-06-15 11:36 UTC, Clemens Fuchslocher
no flags Details

Description Clemens Fuchslocher 2008-06-15 11:32:21 UTC
I have used xmodmap in ~/.xinitrc to add the Super_R key to the mod3 modifier list. This worked well until the X.Org server was updated to a newer version. With this new version the Super_R key is still correctly added to the mod3 modifier list. But now the problem is that this operation affects some other modifier mappings. But only if there was no keystroke before xmodmap gets invoked for the first time. If there was a keystroke then everything works fine. Please see the test cases below.

I am using the X.org server 7.3+10 from Debian testing.


The ~/.xinitrc for the test cases:

    (
        xmessage -geometry +10+10 "Run xmodmap?" &&
        xmodmap -e "add mod3 = Super_R" &&
        xmessage -geometry +10+10 "OK"
    ) &

    exec xterm -geometry x33+200+10 &
    exec twm


Keyboard settings from /etc/X11/xorg.conf:

    Section "InputDevice"
        Identifier "Keyboard"
        Driver "kbd"
        Option "CoreKeyboard"
        Option "XkbRules" "xorg"
        Option "XkbModel" "pc105"
        Option "XkbLayout" "de"
        Option "XkbVariant" "nodeadkeys"
    EndSection


Test case 1: Running xmodmap after a key was pressed: Works fine.

    Please see xmodmap-correct.png and xkeycaps-correct.png

    1. Start X with startx
    2. The xmessage pops up
    3. Press some keys
    4. Click okay with the mouse
    5. Press Alt Gr + ß
    6. Result: \

    $ xmodmap -pm
    xmodmap: up to 3 keys per modifier, (keycodes in parentheses):

    shift       Shift_L (0x32), Shift_R (0x3e)
    lock        Caps_Lock (0x42)
    control     Control_L (0x25), Control_R (0x6d)
    mod1        Alt_L (0x40), Meta_L (0x9c)
    mod2        Num_Lock (0x4d)
    mod3        Super_R (0x74)
    mod4        Super_L (0x7f), Hyper_L (0x80)
    mod5        Mode_switch (0x5d), ISO_Level3_Shift (0x71), ISO_Level3_Shift (0x7c)


Test case 2: Running xmodmap before any key was pressed: Broken.

    Please see xmodmap-broken.png and xkeycaps-broken.png.

    1. Start X with startx
    2. The xmessage pops up
    3. Click okay with the mouse
    4. Press Alt Gr + ß
    5. Result: Ü

    $ xmodmap -pm
    xmodmap: up to 3 keys per modifier, (keycodes in parentheses):

    shift       Shift_L (0x32), Shift_R (0x3e)
    lock        Caps_Lock (0x42)
    control     Control_L (0x25), Control_R (0x6d)
    mod1        Alt_L (0x40), ISO_Level3_Shift (0x71), Meta_L (0x9c)
    mod2        Num_Lock (0x4d)
    mod3        Super_R (0x74)
    mod4        Super_L (0x7f), Hyper_L (0x80)
    mod5        Mode_switch (0x5d), ISO_Level3_Shift (0x7c)


In the second test case the ISO_Level3_Shift (0x71) key is listed on the mod1 modifier list and in the first one this key was assigned to the mod5 modifier list. Moving the ISO_Level3_Shift (0x71) key manually from mod1 to mod5 in the second test case does fix it. See xmodmap-fixed.png and xkeycaps-fixed.png. This manual fix can't be done in the ~/.xinitrc file.

What's going wrong here?
Comment 1 Clemens Fuchslocher 2008-06-15 11:33:09 UTC
Created attachment 17125 [details]
xkeycaps-correct.png
Comment 2 Clemens Fuchslocher 2008-06-15 11:35:09 UTC
Created attachment 17126 [details]
xmodmap-correct.png
Comment 3 Clemens Fuchslocher 2008-06-15 11:35:24 UTC
Created attachment 17127 [details]
xkeycaps-broken.png
Comment 4 Clemens Fuchslocher 2008-06-15 11:35:40 UTC
Created attachment 17128 [details]
xmodmap-broken.png
Comment 5 Clemens Fuchslocher 2008-06-15 11:35:59 UTC
Created attachment 17129 [details]
xkeycaps-fixed.png
Comment 6 Clemens Fuchslocher 2008-06-15 11:36:17 UTC
Created attachment 17130 [details]
xmodmap-fixed.png
Comment 7 Peter Hutterer 2008-07-10 03:23:12 UTC
On Sun, Jun 15, 2008 at 11:32:22AM -0700, bugzilla-daemon@freedesktop.org wrote:
> I have used xmodmap in ~/.xinitrc to add the Super_R key to the mod3 modifier
> list. This worked well until the X.Org server was updated to a newer version.
> With this new version the Super_R key is still correctly added to the mod3
> modifier list. But now the problem is that this operation affects some other
> modifier mappings. But only if there was no keystroke before xmodmap gets
> invoked for the first time. If there was a keystroke then everything works
> fine. Please see the test cases below.

my guess would be the following: changing anything on the keyboard before a
key has been pressed causes a change on the virtual core keyboard (VCK).
when a key is pressed, this keyboard's settings are copied into the VCK, thus
overwriting previous settings on the VCK.

Since this only ever happens on a device switch, this won't happen again if
you only have one keyboard, hence why your approach of setting it after the
key press works.  To verify this, plug in two keyboards, configure them as two
separate devices (using evdev as driver) and then hit a key on one keyboard,
run xmodmap, then see if everything works when you use the other keyboard.
Comment 8 Daniel Stone 2008-07-10 04:38:24 UTC
On Thu, Jul 10, 2008 at 03:23:12AM -0700, bugzilla-daemon@freedesktop.org wrote:
> --- Comment #7 from Peter Hutterer <peter.hutterer@who-t.net>  2008-07-10 03:23:12 PST ---
> On Sun, Jun 15, 2008 at 11:32:22AM -0700, bugzilla-daemon@freedesktop.org
> wrote:
> > I have used xmodmap in ~/.xinitrc to add the Super_R key to the mod3 modifier
> > list. This worked well until the X.Org server was updated to a newer version.
> > With this new version the Super_R key is still correctly added to the mod3
> > modifier list. But now the problem is that this operation affects some other
> > modifier mappings. But only if there was no keystroke before xmodmap gets
> > invoked for the first time. If there was a keystroke then everything works
> > fine. Please see the test cases below.
> 
> my guess would be the following: changing anything on the keyboard before a
> key has been pressed causes a change on the virtual core keyboard (VCK).
> when a key is pressed, this keyboard's settings are copied into the VCK, thus
> overwriting previous settings on the VCK.

Rather.

Peter, would this make sense to you: store the RMLVO names of the two
devices, and if identical, copy the map from core to extended, instead
of creating a new one? Of course, if they differ, create a new map on
extended.
Comment 9 Peter Hutterer 2008-07-10 05:58:25 UTC
> Peter, would this make sense to you: store the RMLVO names of the two
> devices, and if identical, copy the map from core to extended, instead
> of creating a new one? Of course, if they differ, create a new map on
> extended.

This doesn't really fix the root of the problem. The problem is that the map
is changed on the wrong device and later overwritten. Rather than storing
stuff and a conditional copy, it'd be better to ensure that the map is stored
on the right device in the first place. Then we don't have to worry about the
copy. This means modifying the clients, i.e. modifying xkbcomp, xmodmap, and
xwhateverelsethereis. 

The hard bit here is choosing which device to pick if none is specified. I
guess a default policy of "all devices" would be a reasonable, if that doesn't
work, then we can see what does later.
Comment 10 Daniel Stone 2008-07-10 07:13:15 UTC
On Thu, Jul 10, 2008 at 05:58:26AM -0700, bugzilla-daemon@freedesktop.org wrote:
> --- Comment #9 from Peter Hutterer <peter.hutterer@who-t.net>  2008-07-10 05:58:25 PST ---
> > Peter, would this make sense to you: store the RMLVO names of the two
> > devices, and if identical, copy the map from core to extended, instead
> > of creating a new one? Of course, if they differ, create a new map on
> > extended.
> 
> This doesn't really fix the root of the problem. The problem is that the map
> is changed on the wrong device and later overwritten. Rather than storing
> stuff and a conditional copy, it'd be better to ensure that the map is stored
> on the right device in the first place. Then we don't have to worry about the
> copy. This means modifying the clients, i.e. modifying xkbcomp, xmodmap, and
> xwhateverelsethereis. 
> 
> The hard bit here is choosing which device to pick if none is specified. I
> guess a default policy of "all devices" would be a reasonable, if that doesn't
> work, then we can see what does later.

Heh, I think we perceive different problems, then.  IMHO, devices should
come up with a 'reasonable' default, which is more often than not the
core keyboard's current map.  Of course, MPX screws this sideways with a
flagpole, but.
Comment 11 Peter Hutterer 2008-07-23 21:26:40 UTC
> Heh, I think we perceive different problems, then.  IMHO, devices should
> come up with a 'reasonable' default, which is more often than not the
> core keyboard's current map.  Of course, MPX screws this sideways with a
> flagpole, but.

not necessarily, the same rule works for MPX too, except that you have to pick
which core device to use. The attached master is good, and it's picked for you
anyway where needed. So this wouldn't change.
Of couse, with two MDs working in the same app, you're screwed anyway, but -
oh well.

Anyway - to make sure we don't talk about two different things: if xmodmap is
called for the core keyboard, we have to chose either whether you change the
VCK, or the extension devices. If we just change the VCK, it may get
overwritten later. If we change the extension devices, then theirs gets pulled
into the VCK anyway, so we're good. 
So the policy change I see here is "xmodmap for core devices == change all
devices" and "xmodmap for specific device == only this device changes".
That right?
Comment 12 Peter Hutterer 2008-08-26 07:19:11 UTC
Just as an interim solution, we use the following patch in fedora for server 1.5.

From 638cab7e1dc3711f7fb04155bcdabf4b8895cc5e Mon Sep 17 00:00:00 2001
From: Peter Hutterer <peter.hutterer@who-t.net>
Date: Mon, 4 Aug 2008 17:08:36 +0930
Subject: [PATCH] xfree86: force SwitchCoreKeyboard for evdev devices (updated).

If an evdev keyboard device is added through the HAL mechanism, force a
SwitchCoreKeyboard to load the evdev map into the VCK. This way, by the time a
client starts the evdev keymap is already there, leading to less pain lateron.

Works if:
- all keyboards are hotplugged through HAL, and/or
- the xorg.conf keyboard uses the kbd driver.

Has no effect (i.e. busted keymaps) if:
- an evdev keyboard device has been specified in the xorg.conf.
- we don't have a device at startup and plug a device in after starting the
  desktop environment.
- if the device we use isn't the first one reported by HAL.

If HAL isn't set up, this patch is a noop.
---
 hw/xfree86/common/xf86Xinput.c |   31 +++++++++++++++++++++++++++++++
 1 files changed, 31 insertions(+), 0 deletions(-)

diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index 710e787..dacc3dc 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -423,6 +423,37 @@ NewInputDeviceRequest (InputOption *options, DeviceIntPtr *pdev)
         (!is_auto || xf86Info.autoEnableDevices))
         EnableDevice(dev);
 
+    /* XXX: The VCK always starts with built-in defaults for keymap. These
+     * defaults are different to the evdev ones. When the first key is hit on
+     * an extension device, the keymap is copied into the VCK's and any
+     * changes made at runtime to the VCK map are lost.
+     *
+     * Assumption: if we have at least one evdev keyboard device, we can
+     * ignore kbd devices. Force a SwitchCoreKeyboard so the VCK has the same
+     * keymap as we do.
+     *
+     * Next time we hit a key, we don't change the map over anymore (see
+     * SwitchCoreKeyboard), and live happily ever after.
+     * Until we have 2 physical keyboards. Or the first real keyboard isn't
+     * actually the one we use. Oh well.
+     *
+     */
+    if (dev->key)
+    {
+        InputInfoPtr info;
+
+        /* Search if there is one other keyboard that uses evdev. */
+        for (info = xf86InputDevs; info; info = info->next)
+        {
+            if (info != pInfo && info->dev && info->dev->key &&
+                (strcmp(info->drv->driverName, "evdev") == 0))
+                break;
+        }
+
+        if (!info)
+            SwitchCoreKeyboard(dev);
+    }
+
     *pdev = dev;
     return Success;
 
Comment 13 Peter Hutterer 2008-12-17 16:49:09 UTC
Fixed with 9c5dd7337fa93fb1650cc017e523b939dcbf482a: Let the DDX decide on the XkbRulesDefaults.


Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.