Xpra: Ticket #2648: AltGr on german keyboard does not work on windows client

When connecting from a Win10 client to a Centos 7 server, AltGr key combinations on a german keyboard don't work. Attaching to the same session from a linux client works fine.

Pressing AltGr yields ISO_Level3_Shift down and up events on the linux client but on windows additional Meta_R events are shown. Short pressing and releasing AltGr produces:

down ISO_Level3_Shift up ISO_Level3_Shift down Meta_R up Meta_R down ISO_Level3_Shift

Log output on Windows:

2020-03-16 10:39:16,677 keyboard layout code 0x407
2020-03-16 10:39:16,677 identified as 'German' : de
[...]
2020-03-16 10:39:21,591 Authentication (password) successful!
2020-03-16 10:39:22,158  keyboard settings: layout=de

Log output on linux:

2020-03-16 10:32:40,812  keyboard settings: rules=evdev, model=pc105, layout=at

The issue is also present when using --no-keyboard-sync.

I attached the client log produced with xpra attach ssh://user@host/ -d keyboard ... when pressing AltGr + q which should produce "@" but actually only results in a "q".

Examples of other important AltGr keys that don't work: AltGr + + = ~ AltGr + < = |



Mon, 16 Mar 2020 11:14:51 GMT - Leo B: attachment set


Mon, 16 Mar 2020 11:16:30 GMT - Leo B: attachment set


Mon, 16 Mar 2020 11:17:10 GMT - Leo B: attachment set


Mon, 16 Mar 2020 11:17:57 GMT - Leo B: attachment set


Mon, 16 Mar 2020 11:28:27 GMT - Leo B: cc set


Mon, 16 Mar 2020 11:49:11 GMT - Antoine Martin: owner changed

Extracted from the attachments (now deleted):

$ setxkbmap -query
	rules:      evdev
	model:      pc105
	layout:     de
$ setxkbmap -print
	xkb_keymap {
	        xkb_keycodes  { include "evdev+aliases(qwertz)" };
	        xkb_types     { include "complete"      };
	        xkb_compat    { include "complete"      };
	        xkb_symbols   { include "pc+de+inet(evdev)"     };
	        xkb_geometry  { include "pc(pc105)"     };
	};

Which one is the correct layout? 'at' or 'de'?


Mon, 16 Mar 2020 11:54:20 GMT - Antoine Martin: attachment set

German keyboard layout


Mon, 16 Mar 2020 11:54:54 GMT - Antoine Martin:

... but on windows additional Meta_R events are shown ...

Yes, we silence those spurious key events.

Does your keyboard look like this? German keyboard layout


Mon, 16 Mar 2020 12:04:00 GMT - Leo B:

'at' and 'de' have the same layout. The linux client reports 'de' and the windows client shows 'at' (most probably because the windows region settings are set to Austria) but both should be identical.

I also tried with with --keyboard-layout=de on windows but it doesn't make a difference.


Mon, 16 Mar 2020 12:05:06 GMT - Leo B:

Yes, that's my type of keyboard.


Mon, 16 Mar 2020 12:14:12 GMT - Leo B:

On my linux box /usr/share/X11/xkb/symbols/at contains:

// based on a keyboard map from an 'xkb/symbols/de' file
default
xkb_symbols "basic" {
    include "de(basic)"
    name[Group1]="German (Austria)";
};
[...]

Mon, 16 Mar 2020 15:55:37 GMT - Antoine Martin: status changed; resolution set

This regression is caused by the fixes for #2301.

You can workaround it by starting the server with:

XPRA_SIMULATE_MODIFIERS=0 xpra start ...

Downgrade your server to 3.0.6 or apply r25663.


Mon, 16 Mar 2020 16:59:36 GMT - Leo B:

Replying to Antoine Martin:

This regression is caused by the fixes for #2301.

You can workaround it by starting the server with:

XPRA_SIMULATE_MODIFIERS=0 xpra start ...

Starting the server with XPRA_SIMULATE_MODIFIERS=0 works. Thanks!

Downgrade your server to 3.0.6 or apply r25663.

Unfortunately applying changeset r25663 on the server doesn't fix the problem.


Mon, 16 Mar 2020 16:59:42 GMT - Leo B: status changed; resolution deleted


Thu, 19 Mar 2020 15:47:54 GMT - Antoine Martin:

Please don't re-open without providing details.


Thu, 19 Mar 2020 16:58:02 GMT - Leo B:

Replying to Antoine Martin:

Please don't re-open without providing details.

Actually I did provide some details: XPRA_SIMULATE_MODIFIERS=0 solves the problem.

I applying changeset r25664 (your backport of r25663) to my server (version 3.0.7) doesn't fix the issue.

So I guess the problem is still present somewhere in do_get_keycode_new().

Please tell me which additional details I should provide.


Sun, 22 Mar 2020 08:00:50 GMT - Antoine Martin: status changed

@leo_b: are you sure that you don't have virtualbox or barrier or something else fumbling your testing? It fooled me into thinking the bug was not fixed when in fact it was the keyboard emulation that was sending the wrong key event to the OS. I had to use a physical keyboard connected to a real PC running windows 10. As long as I get the correct key printed out (ie: bar - |) when I use the GTK_Keyboard_test.exe then things do work when I connect with xpra. Another thing that may cause problems is the keyboard layout detection, adding --keyboard-layout=de to your client command line may fix that.

Please try the latest 3.0.8-RC centos builds from the xpra-beta.repo and if you still have problems, please specify the exact pristine builds used at both ends and attach the server log after running both the client and server with -d keyboard, pressing only the problematic key combinations once each, with a delay in between to make the logs easier to parse.

So, this works perfectly here, ie: for |:

150 client   8 @53.894 AltGr_modifiers(['control'], True) AltGr=mod5, add=['mod5'], clear=['mod1', 'mod2', 'control']
150 client   8 @53.894 mask_to_names(<flags GDK_CONTROL_MASK of type Gdk.ModifierType>) GetKeyState(VK_NUMLOCK)=0, names=['mod5']
151 client   8 @53.895 parse_key_event(<Gdk.EventKey object at 0x000000001cf744f0 (void at 0x0000000007c5c510)>, True)=<GTKKeyEvent object, contents: {'modifiers': ['mod5'], 'keyname': 'Control_L', 'keyval': 65507, 'keycode': 17, 'group': 1, 'string': '', 'pressed': True}>
151 client   8 @53.896 handle_key_action(ClientWindow(1), <GTKKeyEvent object, contents: {'modifiers': ['mod5'], 'keyname': 'Control_L', 'keyval': 65507, 'keycode': 17, 'group': 1, 'string': '', 'pressed': True}>) wid=1
152 client   8 @53.896 key_handled_as_shortcut: shortcut(Control_L)=None
153 client   8 @53.896 process_key_event: Control_L pressed=True, with GetKeyState(VK_RMENU)=-127
158 client   8 @53.897 AltGr_modifiers(['mod2'], True) AltGr=mod5, add=['mod5'], clear=['mod1', 'mod2', 'control']
158 client   8 @53.897 mask_to_names(<flags GDK_MOD2_MASK of type Gdk.ModifierType>) GetKeyState(VK_NUMLOCK)=0, names=['mod5']
158 client   8 @53.897 parse_key_event(<Gdk.EventKey object at 0x000000001cf74c70 (void at 0x0000000007c5c470)>, True)=<GTKKeyEvent object, contents: {'modifiers': ['mod5'], 'keyname': 'Alt_R', 'keyval': 65514, 'keycode': 165, 'group': 1, 'string': '', 'pressed': True}>
158 client   8 @53.897 handle_key_action(ClientWindow(1), <GTKKeyEvent object, contents: {'modifiers': ['mod5'], 'keyname': 'Alt_R', 'keyval': 65514, 'keycode': 165, 'group': 1, 'string': '', 'pressed': True}>) wid=1
158 client   8 @53.897 key_handled_as_shortcut: shortcut(Alt_R)=None
158 client   8 @53.898 process_key_event: Alt_R pressed=True, with GetKeyState(VK_RMENU)=-127
158 client   8 @53.898 AltGr_modifiers(['mod5'], True) AltGr=mod5, add=['mod5'], clear=['mod1', 'mod2', 'control']
158 client   8 @53.898 send_delayed_key() delayed_event=None
158 client   8 @53.898 send_key_action(1, <GTKKeyEvent object, contents: {'modifiers': ['mod5'], 'keyname': '', 'keyval': -1, 'keycode': -1, 'group': -1, 'string': '', 'pressed': True}>)
158 process_key_action(['key-action', 1, b'', True, (b'mod5',), -1, b'', -1, -1]) server keycode=-1
158 filtered_modifiers_set([])=set()
158 filtered_modifiers_set(['mod5'])={'mod5'}
159 make_keymask_match(['mod5']) current mask: set(), wanted: {'mod5'}, ignoring=-1/[''], keys_pressed={}
159 change_mask(set(), False, remove) failed=[]
159 keynames(mod5)={'Mode_switch', 'ISO_Level3_Shift'}, keycodes=[203, 92, 108], nuisance=False, nuisance keys={'mod2', 'lock'}
159 add mod5 with keycode 203 did not work
159  trying to unpress it!
159 change_mask(add) ['mod5'] modifier 'mod5' using keycode 203, success: False
159 change_mask(add) ['mod5'] modifier 'mod5' using keycode 92
159 change_mask({'mod5'}, True, add) failed=[]
378 client   8 @54.121 AltGr_modifiers(['mod2'], True) AltGr=mod5, add=['mod5'], clear=['mod1', 'mod2', 'control']
385 client   8 @54.123 mask_to_names(<flags GDK_MOD2_MASK of type Gdk.ModifierType>) GetKeyState(VK_NUMLOCK)=0, names=['mod5']
387 client   8 @54.124 parse_key_event(<Gdk.EventKey object at 0x000000001cf74c70 (void at 0x0000000007c5c3d0)>, True)=<GTKKeyEvent object, contents: {'modifiers': ['mod5'], 'keyname': 'bar', 'keyval': 124, 'keycode': 226, 'group': 1, 'string': '|', 'pressed': True}>
400 client   8 @54.125 handle_key_action(ClientWindow(1), <GTKKeyEvent object, contents: {'modifiers': ['mod5'], 'keyname': 'bar', 'keyval': 124, 'keycode': 226, 'group': 1, 'string': '|', 'pressed': True}>) wid=1
400 client   8 @54.126 key_handled_as_shortcut: shortcut(bar)=[(['mod1', 'shift'], 'scalereset', ())]
400 client   8 @54.128 send_delayed_key() delayed_event=None
400 client   8 @54.130 send_key_action(1, <GTKKeyEvent object, contents: {'modifiers': ['mod5'], 'keyname': 'bar', 'keyval': 124, 'keycode': 226, 'group': 1, 'string': '|', 'pressed': True}>)
401 set_keyboard_layout_group(1) ignored, value unchanged
401 will try levels: [6, 2, 0, 1, 3, 4, 5, 7]
401 do_get_keycode(226, 'bar', True, ['mod5'], 1)=94 (level=6, shift=False, mode=1)
401 process_key_action(['key-action', 1, b'bar', True, (b'mod5',), 124, b'|', 226, 1]) server keycode=94
402 filtered_modifiers_set(['mod5'])={'mod5'}
402 filtered_modifiers_set(['mod5'])={'mod5'}
402 is_modifier(94) not found
402 handle_key((1, True, 'bar', 124, 94, ['mod5'], False, True))
402 handle keycode pressing    94: key 'bar'
403 fake_key(94, True)
403 scheduling key repeat timer with delay 500 for bar / 94
499 client   8 @54.244 AltGr_modifiers(['mod2'], True) AltGr=mod5, add=['mod5'], clear=['mod1', 'mod2', 'control']
518 client   8 @54.245 mask_to_names(<flags GDK_MOD2_MASK of type Gdk.ModifierType>) GetKeyState(VK_NUMLOCK)=0, names=['mod5']
518 client   8 @54.245 parse_key_event(<Gdk.EventKey object at 0x000000001cf74e00 (void at 0x0000000007c5c5b0)>, False)=<GTKKeyEvent object, contents: {'modifiers': ['mod5'], 'keyname': 'bar', 'keyval': 124, 'keycode': 226, 'group': 1, 'string': '|', 'pressed': False}>
518 client   8 @54.245 handle_key_action(ClientWindow(1), <GTKKeyEvent object, contents: {'modifiers': ['mod5'], 'keyname': 'bar', 'keyval': 124, 'keycode': 226, 'group': 1, 'string': '|', 'pressed': False}>) wid=1
518 client   8 @54.246 key_handled_as_shortcut: shortcut(bar)=[(['mod1', 'shift'], 'scalereset', ())]
518 client   8 @54.246 send_delayed_key() delayed_event=None
519 client   8 @54.246 send_key_action(1, <GTKKeyEvent object, contents: {'modifiers': ['mod5'], 'keyname': 'bar', 'keyval': 124, 'keycode': 226, 'group': 1, 'string': '|', 'pressed': False}>)
519 set_keyboard_layout_group(1) ignored, value unchanged
519 process_key_action(['key-action', 1, b'bar', False, (b'mod5',), 124, b'|', 226, 1]) server keycode=94
519 filtered_modifiers_set(['mod5'])={'mod5'}
519 filtered_modifiers_set(['mod5'])={'mod5'}
519 is_modifier(94) not found
519 handle_key((1, False, 'bar', 124, 94, ['mod5'], False, True))
519 handle keycode unpressing  94: key 'bar'
519 fake_key(94, False)
688 client   8 @54.433 mask_to_names(<flags GDK_MOD1_MASK of type Gdk.ModifierType>) GetKeyState(VK_NUMLOCK)=0, names=['mod1']
689 client   8 @54.433 parse_key_event(<Gdk.EventKey object at 0x000000001cf74d60 (void at 0x0000000007c5c330)>, False)=<GTKKeyEvent object, contents: {'modifiers': ['mod1'], 'keyname': 'Control_L', 'keyval': 65507, 'keycode': 17, 'group': 1, 'string': '', 'pressed': False}>
690 client   8 @54.434 handle_key_action(ClientWindow(1), <GTKKeyEvent object, contents: {'modifiers': ['mod1'], 'keyname': 'Control_L', 'keyval': 65507, 'keycode': 17, 'group': 1, 'string': '', 'pressed': False}>) wid=1
693 client   8 @54.434 key_handled_as_shortcut: shortcut(Control_L)=None
693 client   8 @54.435 process_key_event: Control_L pressed=False, with GetKeyState(VK_RMENU)=1
693 client   8 @54.435 send_delayed_key() delayed_event=None
694 client   8 @54.435 send_key_action(1, <GTKKeyEvent object, contents: {'modifiers': ['mod1'], 'keyname': 'Control_L', 'keyval': 65507, 'keycode': 17, 'group': 1, 'string': '', 'pressed': False}>)
694 client   8 @54.436 mask_to_names(<flags 0 of type Gdk.ModifierType>) GetKeyState(VK_NUMLOCK)=0, names=[]
694 set_keyboard_layout_group(1) ignored, value unchanged
694 client   8 @54.436 parse_key_event(<Gdk.EventKey object at 0x000000001cf74c70 (void at 0x0000000007c5c510)>, False)=<GTKKeyEvent object, contents: {'modifiers': [], 'keyname': 'Alt_R', 'keyval': 65514, 'keycode': 165, 'group': 1, 'string': '', 'pressed': False}>
694 process_key_action(['key-action', 1, b'Control_L', False, (b'mod1',), 65507, b'', 17, 1]) server keycode=37
694 client   8 @54.436 handle_key_action(ClientWindow(1), <GTKKeyEvent object, contents: {'modifiers': [], 'keyname': 'Alt_R', 'keyval': 65514, 'keycode': 165, 'group': 1, 'string': '', 'pressed': False}>) wid=1
694 client   8 @54.437 key_handled_as_shortcut: shortcut(Alt_R)=None
694 filtered_modifiers_set(['mod5'])={'mod5'}
695 client   8 @54.437 process_key_event: Alt_R pressed=False, with GetKeyState(VK_RMENU)=1
695 filtered_modifiers_set(['mod1'])={'mod1'}
695 client   8 @54.437 AltGr_modifiers([], True) AltGr=mod5, add=['mod5'], clear=['mod1', 'mod2', 'control']
695 make_keymask_match(['mod1']) current mask: {'mod5'}, wanted: {'mod1'}, ignoring=37/['Control_L'], keys_pressed={}
695 client   8 @54.437 send_delayed_key() delayed_event=None
695 keynames(mod5)={'Mode_switch', 'ISO_Level3_Shift'}, keycodes=[203, 92, 108], nuisance=False, nuisance keys={'mod2', 'lock'}
695 client   8 @54.437 send_key_action(1, <GTKKeyEvent object, contents: {'modifiers': ['mod5'], 'keyname': '', 'keyval': -1, 'keycode': -1, 'group': -1, 'string': '', 'pressed': False}>)
695 change_mask(remove) ['mod1'] modifier 'mod5' using keycode 92
695 change_mask({'mod5'}, False, remove) failed=[]
696 keynames(mod1)={'Alt_L', 'Alt_R', 'Meta_R', 'Meta_L'}, keycodes=[64, 204, 253, 205], nuisance=False, nuisance keys={'mod2', 'lock'}
696 change_mask(add) ['mod1'] modifier 'mod1' using keycode 64
696 change_mask({'mod1'}, True, add) failed=[]
696 handle_key((1, False, 'Control_L', 65507, 37, ['mod1'], True, True))
696 handle keycode 37: key Control_L was already unpressed, ignoring
696 process_key_action(['key-action', 1, b'', False, (b'mod5',), -1, b'', -1, -1]) server keycode=-1
696 filtered_modifiers_set(['mod1'])={'mod1'}
696 filtered_modifiers_set(['mod5'])={'mod5'}
696 make_keymask_match(['mod5']) current mask: {'mod1'}, wanted: {'mod5'}, ignoring=-1/[''], keys_pressed={}
697 keynames(mod1)={'Alt_L', 'Alt_R', 'Meta_R', 'Meta_L'}, keycodes=[64, 204, 253, 205], nuisance=False, nuisance keys={'mod2', 'lock'}
697 change_mask(remove) ['mod5'] modifier 'mod1' using keycode 64
697 change_mask({'mod1'}, False, remove) failed=[]
697 keynames(mod5)={'Mode_switch', 'ISO_Level3_Shift'}, keycodes=[203, 92, 108], nuisance=False, nuisance keys={'mod2', 'lock'}
697 add mod5 with keycode 203 did not work
697  trying to unpress it!
697 change_mask(add) ['mod5'] modifier 'mod5' using keycode 203, success: False
698 change_mask(add) ['mod5'] modifier 'mod5' using keycode 92
698 change_mask({'mod5'}, True, add) failed=[]
2020-03-22 14:44:26,473 client   8 @56.223 mask_to_names(<flags 0 of type Gdk.ModifierType>) GetKeyState(VK_NUMLOCK)=0, names=[]
2020-03-22 14:44:26,474 filtered_modifiers_set(['mod5'])={'mod5'}
2020-03-22 14:44:26,474 filtered_modifiers_set([])=set()
2020-03-22 14:44:26,474 make_keymask_match(()) current mask: {'mod5'}, wanted: set(), ignoring=None/None, keys_pressed={}
2020-03-22 14:44:26,475 keynames(mod5)={'Mode_switch', 'ISO_Level3_Shift'}, keycodes=[203, 92, 108], nuisance=False, nuisance keys={'mod2', 'lock'}
2020-03-22 14:44:26,475 change_mask(remove) () modifier 'mod5' using keycode 92
2020-03-22 14:44:26,475 change_mask({'mod5'}, False, remove) failed=[]
2020-03-22 14:44:26,475 change_mask(set(), True, add) failed=[]

Summary:

level=6 is correct, that's group=1 and mode=1 (4+2):

$ DISPLAY=:2 xmodmap -pke | grep bar
keycode  94 = less greater less greater bar dead_belowmacron bar

Mon, 23 Mar 2020 13:02:10 GMT - Leo B:

Replying to Antoine Martin:

@leo_b: are you sure that you don't have virtualbox or barrier or something else fumbling your testing?

The server is a bare-metal centos 7 box. Client is a native windows 10 laptop (lenovo x1 gen4). The alternative that works fine is a VirtualBox Linux guest inside this Windows 10 host.

As long as I get the correct key printed out (ie: bar - |) when I use the GTK_Keyboard_test.exe then things do work when I connect with xpra.

A screenshot of GTK_Keyboard_test.exe when pressing AltGr + < (which should result in |) is attached. It seems strange to me that pressing AltGr results in Control_L and Alt_R events.

Another thing that may cause problems is the keyboard layout detection, adding --keyboard-layout=de to your client command line may fix that.

Already tried that. Doesn't make a difference.

Please try the latest 3.0.8-RC centos builds from the xpra-beta.repo and if you still have problems, please specify the exact pristine builds used at both ends and attach the server log after running both the client and server with -d keyboard, pressing only the problematic key combinations once each, with a delay in between to make the logs easier to parse.

$ rpm -qa | fgrep xpra | sort
ffmpeg-xpra-4.2.2-2.el7_7.x86_64
ffmpeg-xpra-devel-4.2.2-2.el7_7.x86_64
libvpx-xpra-1.8.1-1.el7_7.x86_64
libwebp-xpra-1.0.3-1.el7_7.x86_64
libwebp-xpra-devel-1.0.3-1.el7_7.x86_64
pygtkglext-1.1.0-27.xpra3.el7_7.x86_64
python2-pyopengl-3.1.1a1-10xpra1.el7_7.x86_64
python2-rencode-1.0.6-1.xpra1.el7_7.x86_64
python2-xpra-3.0.8-1.20200322r25722xpra2.el7_7.x86_64
python2-xpra-client-3.0.8-1.20200322r25722xpra2.el7_7.x86_64
python2-xpra-server-3.0.8-1.20200322r25722xpra2.el7_7.x86_64
x264-xpra-20190929-1.el7_7.x86_64
x264-xpra-devel-20190929-1.el7_7.x86_64
xorg-x11-drv-dummy-0.3.8-1.xpra2.el7_7.x86_64
xpra-common-3.0.8-1.20200322r25722xpra2.el7_7.noarch
xpra-common-client-3.0.8-1.20200322r25722xpra2.el7_7.noarch
xpra-common-server-3.0.8-1.20200322r25722xpra2.el7_7.noarch

I'll add my tests and the corresponding logs in the next comment.


Mon, 23 Mar 2020 13:03:35 GMT - Leo B: attachment set


Mon, 23 Mar 2020 13:16:46 GMT - Antoine Martin:

As long as I get the correct key printed out (ie: bar - |) when I use the GTK_Keyboard_test.exe then things do work when I connect with xpra.

A screenshot of GTK_Keyboard_test.exe when pressing AltGr + < (which should result in |) is attached. It seems strange to me that pressing AltGr results in Control_L and Alt_R events.

That's just what we get from GTK, and that's why we have workaround code that delays sending the Control_L to see if it isn't immediately followed by a Alt_R, in which case we swallow them both and send AltGr... Anyway, do you get bar shown using this tool or not?

$ rpm -qa | fgrep xpra | sort (..)

What is the full client version?


Mon, 23 Mar 2020 13:25:03 GMT - Leo B:

Replying to Antoine Martin:

A screenshot of GTK_Keyboard_test.exe when pressing AltGr + < (which should result in |) is attached. It seems strange to me that pressing AltGr results in Control_L and Alt_R events.

That's just what we get from GTK, and that's why we have workaround code that delays sending the Control_L to see if it isn't immediately followed by a Alt_R, in which case we swallow them both and send AltGr...

Ah - ok. IC

Anyway, do you get bar shown using this tool or not?

Yes. See

$ rpm -qa | fgrep xpra | sort (..)

What is the full client version?

Currently it is

C:\Program Files\Xpra>xpra_cmd --version
xpra v3.0.7-r25627

But I'll install Xpra-Python3-x86_64_Setup_4.0-r25739.exe before providing the debug logs.


Mon, 23 Mar 2020 14:22:44 GMT - Leo B: attachment set

server log of pressing AltGr? + < = |


Mon, 23 Mar 2020 14:23:07 GMT - Leo B: attachment set

client log of pressing AltGr? + < = |


Mon, 23 Mar 2020 14:37:12 GMT - Leo B:

Replying to Antoine Martin:

Trying to extract the relevant pieces, I noticed a difference here:

2020-03-23 15:01:03,312 do_get_keycode(226, 'bar', True, ['mod5'], 0)=94 (level=4, shift=False, mode=1
2020-03-23 15:01:03,312 process_key_action(['key-action', 1, 'bar', True, ('mod5',), 124, '|', 226, 0]) server keycode=94
2020-03-23 15:01:03,312 filtered_modifiers_set(['mod5'])=set(['mod5'])
2020-03-23 15:01:03,312 filtered_modifiers_set([])=set([])
2020-03-23 15:01:03,313 is_modifier(94) not found
2020-03-23 15:01:03,313 handle_key((1, True, 'bar', 124, 94, [], False, True))
2020-03-23 15:01:03,313 handle keycode pressing    94: key 'bar
2020-03-23 15:01:03,313 fake_key(94, True)

level=6 is correct, that's group=1 and mode=1 (4+2):

level=4 on my system

$ DISPLAY=:101 xmodmap -pke | grep bar
keycode  51 = backslash bar backslash bar
keycode  94 = less greater less greater bar brokenbar bar

Actually < is printed on my system, instead of |.


Mon, 23 Mar 2020 17:05:09 GMT - Antoine Martin:

Got it, I think. The problem is that - for whatever reason - I get:

do_get_keycode(226, 'bar', True, ['mod5'], 1)=94 (level=6, shift=False, mode=1)

The last argument to do_get_keycode is group=1. But you get:

do_get_keycode(226, 'bar', True, ['mod5'], 0)=94 (level=4, shift=False, mode=1

Which is group=0, we match with level=4, but level=4 should still use group=1. Because level=group*4+mode*2+shift*1.

So what we have to do for your key events is to change the layout group on the fly. | may be in the group=0 on windows, but we need group=1 with X11.

That's also why we don't match the bar with level=6, which is a better match than the one with level=4 since you have AltGr pressed (mod5)..

r25745 does that.

r25746 backports it and there are 3.0.8-RC builds with this fix. But this change is pretty large so if there are any regressions then I may just change the default back to XPRA_SIMULATE_MODIFIERS=0 instead.


Mon, 23 Mar 2020 17:37:29 GMT - Leo B:

Replying to Antoine Martin:

r25746 backports it and there are 3.0.8-RC builds with this fix.

The new builds are not available yet on https://xpra.org/beta/CentOS/7/x86_64/

I'll wait for them to appear in the repo and test as soon as they are available.

Thanks for your help! --leo


Mon, 23 Mar 2020 17:43:40 GMT - Antoine Martin:

The new builds are not available yet on

Forgot to upload them, done now!


Mon, 23 Mar 2020 18:22:31 GMT - Leo B:

Replying to Leo B:

Replying to Antoine Martin:

r25746 backports it and there are 3.0.8-RC builds with this fix.

Unfortunately this doesn't work. (using your r25747 on the server)

I attached the server-log when pressing AltGr + < = | as server-r25747.log.


Mon, 23 Mar 2020 18:22:53 GMT - Leo B: attachment set


Tue, 24 Mar 2020 05:28:14 GMT - Antoine Martin:

Unfortunately this doesn't work. (using your r25747 on the server)

Damn. Sorry about that! That's why I don't like backporting big patches, it's more of a risk and I managed to miss the bit where it actually changes the layout group! (the key part..) And since my test systems use group=1, I didn't notice it was missing. r25748 fixes the backport.

Then I figured out a better / simpler way of matching levels: r25749. Also backported in r25750.

New beta posted, this one should work, for real this time.


Tue, 24 Mar 2020 05:32:13 GMT - Antoine Martin:

Tested by temporarily modifying the server to force mode=0 and I got the correct result:

do_get_keycode(226, 'bar', True, ['mod5', 'mod2'], 0)=94 (level=6, shift=False, mode=1)
switching group from 0 to 1

Tue, 24 Mar 2020 06:24:39 GMT - Leo B:

Replying to Antoine Martin:

Then I figured out a better / simpler way of matching levels: r25749. Also backported in r25750.

New beta posted, this one should work, for real this time.

Bummer. :-( r25750 still doesn't work - no change.


Tue, 24 Mar 2020 06:25:00 GMT - Leo B: attachment set


Tue, 24 Mar 2020 06:57:15 GMT - Antoine Martin:

r25750 still doesn't work - no change.

Really sorry about wasting your time like that. I snafued the build.

It's really fixed now. I think. (new build posted at r25751)


Tue, 24 Mar 2020 09:39:31 GMT - Leo B:

Replying to Antoine Martin:

r25750 still doesn't work - no change.

Really sorry about wasting your time like that. I snafued the build.

No problem! I really appreciate your help and your fast response times. Since you are providing beta-RPMs, trying new versions is not much of an issue. :-)

It's really fixed now. I think. (new build posted at r25751)

Bingo! This one works. Thanks a lot! Now I can start convincing my colleagues to switch to xpra while working from home. :-)

cheers, --leo


Tue, 24 Mar 2020 10:26:16 GMT - Antoine Martin: status changed; resolution set

Woohoo! (at last)

Duplicate: #2687


Wed, 20 May 2020 09:00:30 GMT - Antoine Martin:

See also #2769.


Sat, 23 Jan 2021 05:57:01 GMT - migration script:

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