Xpra: Ticket #109: keyboard problems with dead keys and dvorak layout

Hello,

I'm using dvorak-fr keyboard layout, which uses a "dead" key as a modifier. For example, to obtain $, I press 8, then release it, then press '. 8 is ISO_Level3_Latch.

When connecting to a Xpra session with this layout, it works for certain keys, but not all of them.

» (8 + n) $ (8 + ') € (8 + g) ù (8 + u) <<< but ìàò work fine!! è (8 + e) £ (8 + y)

Server:

ahuillet@demo:~/xpra/src$ setxkbmap -print
xkb_keymap {
        xkb_keycodes  { include "evdev+aliases(azerty)" };
        xkb_types     { include "complete"      };
        xkb_compat    { include "complete"      };
        xkb_symbols   { include "pc+fr+inet(evdev)"     };
        xkb_geometry  { include "pc(pc104)"     };
};

Local:

arthur@Chani:~$ setxkbmap -print
xkb_keymap {
        xkb_keycodes  { include "evdev+aliases(azerty)" };
        xkb_types     { include "complete"      };
        xkb_compat    { include "complete"      };
        xkb_symbols   { include "pc+fr(dvorak)+inet(evdev)"     };
        xkb_geometry  { include "pc(pc104)"     };
};

Xmodmap outputs are attached.



Mon, 16 Apr 2012 08:38:11 GMT - ahuillet: attachment set

xmodmap -pke on client


Mon, 16 Apr 2012 08:38:22 GMT - ahuillet: attachment set

xmodmap -pm (local)


Mon, 16 Apr 2012 08:39:03 GMT - ahuillet: attachment set

xmodmap -pke on server


Mon, 16 Apr 2012 08:39:13 GMT - ahuillet: attachment set

xmodmap -pm on server


Mon, 16 Apr 2012 08:48:28 GMT - ahuillet:

When I use "xev" to see what happens. When I press the 8 key, I get :

when I press the 8 key, here is what I get:

KeyPress event, serial 36, synthetic NO, window 0x2800001,
    root 0x15a, subw 0x0, time 232923257, (28,84), root:(1058,901),
    state 0x10, keycode 17 (keysym 0xfe04, ISO_Level3_Latch), same_screen YES,
    XLookupString gives 0 bytes:
    XmbLookupString gives 0 bytes:
    XFilterEvent returns: False
KeyRelease event, serial 36, synthetic NO, window 0x2800001,
    root 0x15a, subw 0x0, time 232923449, (28,84), root:(1058,901),
    state 0x90, keycode 17 (keysym 0x60, grave), same_screen YES,
    XLookupString gives 1 bytes: (60) "`"
    XFilterEvent returns: False

The output is *the same* on the client and the server, so no problem here.

Now, locally, I will do ì (works on Xpra) and $ (doesn't work on Xpra) :

KeyPress event, serial 36, synthetic NO, window 0x2800001,
    root 0x15a, subw 0x0, time 233173178, (107,77), root:(1137,894),
    state 0x10, keycode 17 (keysym 0xfe04, ISO_Level3_Latch), same_screen YES,
    XLookupString gives 0 bytes:
    XmbLookupString gives 0 bytes:
    XFilterEvent returns: False
KeyRelease event, serial 36, synthetic NO, window 0x2800001,
    root 0x15a, subw 0x0, time 233173306, (107,77), root:(1137,894),
    state 0x90, keycode 17 (keysym 0x60, grave), same_screen YES,
    XLookupString gives 1 bytes: (60) "`"
    XFilterEvent returns: False
KeyPress event, serial 36, synthetic NO, window 0x2800001,
    root 0x15a, subw 0x0, time 233173338, (107,77), root:(1137,894),
    state 0x90, keycode 55 (keysym 0xec, igrave), same_screen YES,
    XLookupString gives 1 bytes: (ec) "ì"
    XmbLookupString gives 1 bytes: (ec) "ì"
    XFilterEvent returns: False
KeyRelease event, serial 36, synthetic NO, window 0x2800001,
    root 0x15a, subw 0x0, time 233173418, (107,77), root:(1137,894),
    state 0x10, keycode 55 (keysym 0x69, i), same_screen YES,
    XLookupString gives 1 bytes: (69) "i"
    XFilterEvent returns: False
KeyPress event, serial 36, synthetic NO, window 0x2800001,
    root 0x15a, subw 0x0, time 233173626, (107,77), root:(1137,894),
    state 0x10, keycode 17 (keysym 0xfe04, ISO_Level3_Latch), same_screen YES,
    XLookupString gives 0 bytes:
    XmbLookupString gives 0 bytes:
    XFilterEvent returns: False
KeyRelease event, serial 36, synthetic NO, window 0x2800001,
    root 0x15a, subw 0x0, time 233173722, (107,77), root:(1137,894),
    state 0x90, keycode 17 (keysym 0x60, grave), same_screen YES,
    XLookupString gives 1 bytes: (60) "`"
    XFilterEvent returns: False
KeyPress event, serial 36, synthetic NO, window 0x2800001,
    root 0x15a, subw 0x0, time 233173818, (107,77), root:(1137,894),
    state 0x90, keycode 25 (keysym 0x24, dollar), same_screen YES,
    XLookupString gives 1 bytes: (24) "$"
    XmbLookupString gives 1 bytes: (24) "$"
    XFilterEvent returns: False
KeyRelease event, serial 36, synthetic NO, window 0x2800001,
    root 0x15a, subw 0x0, time 233173882, (107,77), root:(1137,894),
    state 0x10, keycode 25 (keysym 0x27, apostrophe), same_screen YES,
    XLookupString gives 1 bytes: (27) "'"
    XFilterEvent returns: False

And on the Xpra session :

KeyPress event, serial 30, synthetic NO, window 0x1400001,
    root 0x131, subw 0x0, time 3882373499, (87,112), root:(88,135),
    state 0x10, keycode 17 (keysym 0xfe04, ISO_Level3_Latch), same_screen YES,
    XLookupString gives 0 bytes:
    XmbLookupString gives 0 bytes:
    XFilterEvent returns: False
KeyRelease event, serial 30, synthetic NO, window 0x1400001,
    root 0x131, subw 0x0, time 3882373606, (87,112), root:(88,135),
    state 0x90, keycode 17 (keysym 0x60, grave), same_screen YES,
    XLookupString gives 1 bytes: (60) "`"
    XFilterEvent returns: False
KeyPress event, serial 30, synthetic NO, window 0x1400001,
    root 0x131, subw 0x0, time 3882373630, (87,112), root:(88,135),
    state 0x90, keycode 31 (keysym 0xec, igrave), same_screen YES,
    XLookupString gives 1 bytes: (ec) "ì"
    XmbLookupString gives 1 bytes: (ec) "ì"
    XFilterEvent returns: False
KeyRelease event, serial 30, synthetic NO, window 0x1400001,
    root 0x131, subw 0x0, time 3882373683, (87,112), root:(88,135),
    state 0x10, keycode 31 (keysym 0x69, i), same_screen YES,
    XLookupString gives 1 bytes: (69) "i"
    XFilterEvent returns: False
KeyPress event, serial 30, synthetic NO, window 0x1400001,
    root 0x131, subw 0x0, time 3882375027, (87,112), root:(88,135),
    state 0x10, keycode 17 (keysym 0xfe04, ISO_Level3_Latch), same_screen YES,
    XLookupString gives 0 bytes:
    XmbLookupString gives 0 bytes:
    XFilterEvent returns: False
KeyRelease event, serial 30, synthetic NO, window 0x1400001,
    root 0x131, subw 0x0, time 3882375099, (87,112), root:(88,135),
    state 0x90, keycode 17 (keysym 0x60, grave), same_screen YES,
    XLookupString gives 1 bytes: (60) "`"
    XFilterEvent returns: False
KeyPress event, serial 30, synthetic NO, window 0x1400001,
    root 0x131, subw 0x0, time 3882375139, (87,112), root:(88,135),
    state 0x90, keycode 48 (keysym 0x27, apostrophe), same_screen YES,
    XLookupString gives 1 bytes: (27) "'"
    XmbLookupString gives 1 bytes: (27) "'"
    XFilterEvent returns: False
KeyRelease event, serial 30, synthetic NO, window 0x1400001,
    root 0x131, subw 0x0, time 3882375219, (87,112), root:(88,135),
    state 0x10, keycode 48 (keysym 0x27, apostrophe), same_screen YES,
    XLookupString gives 1 bytes: (27) "'"
    XFilterEvent returns: False

The only difference is the last-but-one event: it should be a keypress of "dollar", but is "apostrophe".

Is there actually anything wrong with Xpra? ...


Mon, 16 Apr 2012 10:20:46 GMT - Antoine Martin: status changed

Does this patch help? It should set the keyboard model on the server. (dvorak in your case)

Index: src/xpra/xkbhelper.py
===================================================================
--- src/xpra/xkbhelper.py	(revision 724)
+++ src/xpra/xkbhelper.py	(working copy)
@@ -106,13 +106,17 @@
         log.debug("do_set_keymap using xkbmap_print")
         #try to guess the layout by parsing "setxkbmap -print"
         try:
-            sym_re = re.compile("\s*xkb_symbols\s*{\s*include\s*\"([\w\+]*)")
+            sym_re = re.compile("\s*xkb_symbols\s*{\s*include\s*\"([\w\+]*)(\(\w*\))?")
             for line in xkbmap_print.splitlines():
                 m = sym_re.match(line)
                 if m:
                     layout = m.group(1)
-                    log.info("guessing keyboard layout='%s'" % layout)
-                    exec_keymap_command(["setxkbmap", layout])
+                    model = m.group(2)
+                    log.info("guessing keyboard layout='%s', model='%s'", layout, model)
+                    cmd = ["setxkbmap", layout]
+                    if model:
+                        cmd += ["-model", model]
+                    exec_keymap_command(cmd)
                     break
         except Exception, e:
             log.info("error setting keymap: %s" % e)

Mon, 16 Apr 2012 10:40:44 GMT - ahuillet:

The patch, in my case, doesn't work.

What I had to do is the following:

@@ -94,7 +94,7 @@
                 settings[m.group(1)] = m.group(2).strip()
         #construct the command line arguments for setxkbmap:
         args = ["setxkbmap"]
-        for setting in ["rules", "model", "layout"]:
+        for setting in ["rules", "model", "layout", "variant"]:

to get variant set to dvorak... but that doesn't solve the issue.


Mon, 16 Apr 2012 11:15:20 GMT - Antoine Martin: description changed


Mon, 16 Apr 2012 11:16:14 GMT - Antoine Martin:

newer patch - probably worth doing even if this doesn't solve your particular problem:

Index: src/xpra/xkbhelper.py
===================================================================
--- src/xpra/xkbhelper.py	(revision 724)
+++ src/xpra/xkbhelper.py	(working copy)
@@ -106,13 +106,23 @@
         log.debug("do_set_keymap using xkbmap_print")
         #try to guess the layout by parsing "setxkbmap -print"
         try:
-            sym_re = re.compile("\s*xkb_symbols\s*{\s*include\s*\"([\w\+]*)")
+            sym_re = re.compile("\s*xkb_symbols\s*{\s*include\s*\"([\w\+]*)(\((\w*)\))?((\+\w*)\((\w*)\))?")
             for line in xkbmap_print.splitlines():
                 m = sym_re.match(line)
                 if m:
                     layout = m.group(1)
-                    log.info("guessing keyboard layout='%s'" % layout)
-                    exec_keymap_command(["setxkbmap", layout])
+                    variant = m.group(3)
+                    extra_layout = m.group(5)
+                    model = m.group(6)
+                    if extra_layout:
+                        layout += extra_layout
+                    log.info("guessing keyboard layout='%s', variant='%s', model='%s'", layout, variant, model)
+                    cmd = ["setxkbmap", layout]
+                    if variant:
+                        cmd += ["-variant", variant[1:-1]]
+                    if model:
+                        cmd += ["-model", model]
+                    exec_keymap_command(cmd)
                     break
         except Exception, e:
             log.info("error setting keymap: %s" % e)

Mon, 16 Apr 2012 12:31:55 GMT - ahuillet:

It doesn't solve my particular problem.


Mon, 16 Apr 2012 12:53:39 GMT - ahuillet:

Dumping some info on the server side, for ì (working) and è (not working, producing e)

handle_key(1,1,ISO_Level3_Latch,65028,17,['mod2'])
handle_key(1,0,grave,96,17,['mod2', 'mod5'])
handle_key(1,1,igrave,236,31,['mod2', 'mod5'])
handle_key(1,0,i,105,31,['mod2'])
handle_key(1,1,ISO_Level3_Latch,65028,17,['mod2'])
handle_key(1,0,grave,96,17,['mod2', 'mod5'])
handle_key(1,1,egrave,232,93,['mod2', 'mod5'])
handle_key(1,0,e,101,93,['mod2'])

So the server receives correct messages in both cases.


Mon, 16 Apr 2012 13:00:38 GMT - ahuillet:

arthur@Gurney:~$ xmodmap -pke | egrep ' (31|93) '
keycode  31 = i I i I igrave Igrave
keycode  93 = e E e E egrave Egrave

This is on the Xpra session - so the key map looks good.

I have tried the following:

--- a/src/xpra/server.py
+++ b/src/xpra/server.py
@@ -1827,19 +1827,28 @@ class XpraServer(gobject.GObject):
             Does the actual press/unpress for keys
             Either from a packet (_process_key_action) or timeout (_key_repeat_timeout)
         """
-        log.debug("handle_key(%s,%s,%s,%s,%s,%s)", wid, pressed, name, keyval, keycode, modifiers)
+        log.error("handle_key(%s,%s,%s,%s,%s,%s)", wid, pressed, name, keyval, keycode, modifiers)
+        xtest_fake_key(gtk.gdk.display_get_default(), 17, True)
+        xtest_fake_key(gtk.gdk.display_get_default(), 17, False)
+        xtest_fake_key(gtk.gdk.display_get_default(), 31, True)
+        xtest_fake_key(gtk.gdk.display_get_default(), 31, False)
+        xtest_fake_key(gtk.gdk.display_get_default(), 17, True)
+        xtest_fake_key(gtk.gdk.display_get_default(), 17, False)
+        xtest_fake_key(gtk.gdk.display_get_default(), 93, True)
+        xtest_fake_key(gtk.gdk.display_get_default(), 93, False)
+        return

It's stupid but should display ìè every time I press a key. I'm getting ìe. I suspect a bug in XTest. Opened a ticket at https://bugs.freedesktop.org/show_bug.cgi?id=48770


Fri, 04 May 2012 10:09:01 GMT - Antoine Martin:

This adds a method to the native X11 bindings so we can use XSendEvent to send keypresses instead of Xtest. It still needs:

Index: src/wimpiggy/lowlevel/bindings.pyx
===================================================================
--- src/wimpiggy/lowlevel/bindings.pyx	(revision 777)
+++ src/wimpiggy/lowlevel/bindings.pyx	(working copy)
@@ -1157,6 +1157,49 @@
     _ensure_XTest_support(display_source)
     XTestFakeButtonEvent(get_xdisplay_for(display_source), button, is_press, 0)
+def sendKeyEvent(target, root_win, modifiers_mask, keycode, is_press):
+    cdef Display * display
+    display = get_xdisplay_for(target)
+    cdef Window w
+    w = get_xwindow(target)
+    cdef Window root_w
+    root_w = get_xwindow(root_win)
+    cdef XKeyEvent ke
+    cdef XEvent e = <XEvent> e
+    ke.type = KeyPress
+    e.xany.display = display
+    ke.window = w
+    ke.root = root_w
+    ke.subwindow = None
+    ke.time = CurrentTime
+    ke.x = 1
+    ke.y = 1
+    ke.x_root = 1
+    ke.y_root = 1
+    ke.state = 0
+    ke.same_screen = 1
+    ke.keycode = keycode
+    ke.state = modifiers_mask
+    cdef Status s
+    cdef long event_mask
+    event_mask = 0
+    if "shift" in modifiers_mask:
+        event_mask |= ShiftMask
+    if "lock" in modifiers_mask:
+        event_mask |= LockMask
+    if "ctrl" in modifiers_mask:
+        event_mask |= ControlMask
+    if "alt" in modifiers_mask or "meta" in modifiers_mask:
+        event_mask |= Mod1Mask
+    if is_press:
+        event_mask = KeyPressMask
+    else:
+        event_mask = KeyReleaseMask
+    s = XSendEvent(display, w, True, event_mask, &e)
+    if s == 0:
+        raise ValueError, "failed to serialize ClientMessage"
+
+
 ###################################
 # Extension testing
 ###################################

Best reference I found on using XSendEvent to send key presses: xvkbd/events.html


Fri, 22 Jun 2012 10:16:44 GMT - Antoine Martin:

Is this improved with r942? (I would not expect it to)

But at least, no worse?

Will follow up with work on #149


Fri, 22 Jun 2012 11:00:55 GMT - Antoine Martin: owner, status changed


Sun, 24 Jun 2012 06:14:34 GMT - Antoine Martin:

Please see questions above, and can you find a way for me to set the same keymap without re-configuring my X11 server? (or logging in/out or changing DE) How do you set yours? The closest I got was:

setxkbmap -rules base -model pc104 -layout fr -variant dvorak

Which gives me:

xkb_keymap {
	xkb_keycodes  { include "xfree86+aliases(azerty)"	};
	xkb_types     { include "complete"	};
	xkb_compat    { include "complete"	};
	xkb_symbols   { include "pc+fr(dvorak)"	};
	xkb_geometry  { include "pc(pc104)"	};
};

Sun, 24 Jun 2012 16:38:34 GMT - ahuillet:

I use:

setxkbmap -layout fr -variant dvorak

Sun, 24 Jun 2012 16:42:53 GMT - Antoine Martin:

Not much better...

$ setxkbmap -layout fr -variant dvorak
$ setxkbmap -print
xkb_keymap {
	xkb_keycodes  { include "xfree86+aliases(azerty)"	};
	xkb_types     { include "complete"	};
	xkb_compat    { include "complete"	};
	xkb_symbols   { include "pc+fr(dvorak)+inet(pc105)"	};
	xkb_geometry  { include "pc(pc105)"	};
};

vs:

$ setxkbmap -rules base -model pc104 -layout fr -variant dvorak
$ setxkbmap -print
xkb_keymap {
	xkb_keycodes  { include "xfree86+aliases(azerty)"	};
	xkb_types     { include "complete"	};
	xkb_compat    { include "complete"	};
	xkb_symbols   { include "pc+fr(dvorak)"	};
	xkb_geometry  { include "pc(pc104)"	};
};

When what I want is:

xkb_keymap {
        xkb_keycodes  { include "evdev+aliases(azerty)" };
        xkb_types     { include "complete"      };
        xkb_compat    { include "complete"      };
        xkb_symbols   { include "pc+fr(dvorak)+inet(evdev)"     };
        xkb_geometry  { include "pc(pc104)"     };
};

Also, please see comment:10


Sun, 24 Jun 2012 16:47:51 GMT - ahuillet:

I have "evdev" on my *real* X server (which runs without a xorg.conf). And on Xdummy/Xvfb?, I get xfree86 just like you.

r942 *fixes* the issues for me.


Sun, 24 Jun 2012 16:51:20 GMT - Antoine Martin: status, summary changed; keywords, resolution set

might apply to 0.3.x branch

Note: the layout printed above are for my *real* X server too.


Thu, 12 Jul 2012 18:57:21 GMT - Antoine Martin:

This has caused a regression for some... see #164


Sat, 23 Jan 2021 04:45:47 GMT - migration script:

this ticket has been moved to: https://github.com/Xpra-org/xpra/issues/109