Closed totaam closed 6 years ago
Small update, the right Command button change is ineffectual and shouldn't have been included in my patch. I'll save that for another day, hopefully after Xpra is added to the Anaconda Distribution (and MSYS2).
Here is the corrected hacky patch:
diff --git a/trunk/src/xpra/client/gtk_base/gtk_client_window_base.py b/trunk/src/xpra/client/gtk_base/gtk_client_window_base.py --- a/trunk/src/xpra/client/gtk_base/gtk_client_window_base.py (revision 16558) +++ b/trunk/src/xpra/client/gtk_base/gtk_client_window_base.py (working copy) @@ -1358,6 +1358,10 @@ keycode = event.hardware_keycode keyname = gdk.keyval_name(keyval) keyname = KEY_TRANSLATIONS.get((keyname, keyval, keycode), keyname) + # mac hacks + if keycode == 55: + keycode = 133 + keyname = 'Super_L' key_event = GTKKeyEvent() key_event.modifiers = self._client.mask_to_names(event.state) key_event.keyname = keyname or ""
I know this isn't related to this ticket, but I was wondering how well Xpra is working on GTK+3 and Python 3?
Are you using
--swap-keys=no
as per #1608? Could it just be that the swap-keys code is incomplete? It swaps the modifiers (control vs command) but not the actual key presses for those keys. Maybe we should be swapping those (similar to your changes) when swap-keys is enabled, that looks like a bug.I've used xpra with virtualbox before, and I had found that virtualbox was messing up some key events.. so that could be interfering. Maybe we should try to get the keyboard to work reliably from macos to a test application first (xev, whatever), then add virtualbox into the mix? If we do need the GTK patch (looks easy to apply to GTK2), I would need a simple test case to verify what it does or doesn't do.
I don't think I was using
---swap-keys
when I ran into the not-a-modifier issue (because #1608 prevented me passing that option).I will use xev later to debug further.
Hi Antoine,
I managed to bodge and hack enough code to get the correct result. Here is my complete patch. If you have pointers about how to do this properly then I will try to do that.
svn diff --git Index: src/xpra/client/gtk_base/gtk_client_window_base.py =================================================================== diff --git a/trunk/src/xpra/client/gtk_base/gtk_client_window_base.py b/trunk/src/xpra/client/gtk_base/gtk_client_window_base.py --- a/trunk/src/xpra/client/gtk_base/gtk_client_window_base.py (revision 16562) +++ b/trunk/src/xpra/client/gtk_base/gtk_client_window_base.py (working copy) @@ -1358,6 +1358,13 @@ keycode = event.hardware_keycode keyname = gdk.keyval_name(keyval) keyname = KEY_TRANSLATIONS.get((keyname, keyval, keycode), keyname) + # mac hacks + if keycode == 55: + keycode = 133 + keyname = 'Super_L' + if keycode == 54: + keycode = 134 + keyname = 'Super_R' key_event = GTKKeyEvent() key_event.modifiers = self._client.mask_to_names(event.state) key_event.keyname = keyname or "" Index: src/xpra/gtk_common/gtk_util.py =================================================================== diff --git a/trunk/src/xpra/gtk_common/gtk_util.py b/trunk/src/xpra/gtk_common/gtk_util.py --- a/trunk/src/xpra/gtk_common/gtk_util.py (revision 16562) +++ b/trunk/src/xpra/gtk_common/gtk_util.py (working copy) @@ -758,6 +758,7 @@ gdk.SHIFT_MASK : "SHIFT", gdk.LOCK_MASK : "LOCK", gdk.CONTROL_MASK : "CONTROL", + gdk.META_MASK : "META", gdk.MOD1_MASK : "MOD1", gdk.MOD2_MASK : "MOD2", gdk.MOD3_MASK : "MOD3", Index: src/xpra/platform/darwin/keyboard.py =================================================================== diff --git a/trunk/src/xpra/platform/darwin/keyboard.py b/trunk/src/xpra/platform/darwin/keyboard.py --- a/trunk/src/xpra/platform/darwin/keyboard.py (revision 16562) +++ b/trunk/src/xpra/platform/darwin/keyboard.py (working copy) @@ -116,7 +116,7 @@ def set_modifier_mappings(self, mappings): KeyboardBase.set_modifier_mappings(self, mappings) - self.meta_modifier = self.modifier_keys.get("Meta_L") or self.modifier_keys.get("Meta_R") + self.meta_modifier = self.modifier_keys.get("Super_L") or self.modifier_keys.get("Super_R") self.control_modifier = self.modifier_keys.get("Control_L") or self.modifier_keys.get("Control_R") self.num_lock_modifier = self.modifier_keys.get("Num_Lock") log("set_modifier_mappings(%s) meta=%s, control=%s, numlock=%s", mappings, self.meta_modifier, self.control_modifier, self.num_lock_modifier) @@ -155,6 +155,8 @@ def mask_to_names(self, mask): names = KeyboardBase.mask_to_names(self, mask) + if bool(mask & META_MASK): + names.append(self.meta_modifier) if self.swap_keys and self.meta_modifier is not None and self.control_modifier is not None: meta_on = bool(mask & META_MASK) meta_set = self.meta_modifier in names
Comments:
- the first part that switches keycodes around, can we make this conditional on "swap-keys" being set? (you are running with it enabled, right?) and shouldn't it swap the other keys back too? (see updated patch below) - and maybe we should just enhance the
KEY_TRANSLATIONS
mechanism so it can be used to modify the keycode too (it would make the code more generic - no big deal, just a thought)- adding meta to gtk_util: makes sense, merged in r16564
- the last part changes the meta modifier - so what happens to the modifier for
Meta_L
andMeta_R
? does it never fire? Shouldn't this also be conditional on "swap-keys"? And rather than adding the meta modifier to "names", shouldn't this value be correct already fromKeyboardBase.mask_to_names
- in which case, maybe the modifier map is wrong...I'll try to play with this on macos when I get a chance.
--- xpra/client/gtk_base/gtk_client_window_base.py (revision 16553) +++ xpra/client/gtk_base/gtk_client_window_base.py (working copy) @@ -1357,6 +1357,19 @@ keyval = event.keyval keycode = event.hardware_keycode keyname = gdk.keyval_name(keyval) + if OSX and self._client.swap_keys: + if keycode==55: + keycode = 133 + keyname = 'Super_L' + elif keycode==54: + keycode = 134 + keyname = 'Super_R' + elif keycode==133: + keycode = 55 + keyname = "Meta_L" + elif keycode==134: + keycode = 54 + keyname = "Meta_R" keyname = KEY_TRANSLATIONS.get((keyname, keyval, keycode), keyname) key_event = GTKKeyEvent() key_event.modifiers = self._client.mask_to_names(event.state)
Previously, swap keys swapped Control_L with Meta_L and Control_R with Meta_R but that leads to mod2 being set and that's numlock and set always anyway so Meta_L and Meta_R seem best avoided.
I avoid Meta_L and Meta_R by using Super_L and Super_R instead (I got these keynames and keycodes from
xev -event keyboard
running CentOS6 via VirtualBox directly on the macBook Pro).I always run with
--swap-keys=no
, and my patch is probably not--swap-keys=yes
friendly. I can try to make it work under that setting too though.
.. so I'm not really doing the same thing as swap-keys here. It's orthogonal to that (or should be anyway). I am remapping how the command button is interpreted in order to avoid numlock/mod2 confusion.
Gotcha, that makes more sense now. I'll take a look. You're right, we shouldn't be sending mod2 in any case.
apple-keyboard-layout.jpg
(416.6 KiB)apple keyboard layout
First, there was a bug in the keyswap code which could end up generating spurious key events server side, fixed in r16809. Also, regarding your question about GTK3 and Python3, please see #1568.
Layout
Collecting some debugging data as per Keyboard.
With a mac mini and an Apple keyboard that looks like this one: [[Image(apple-keyboard-layout.jpg)]]
Num Lock
I don't see any problems with numlock (just a minor improvement in r16810), it gets toggled with this key event:
parse_key_event(<gtk.gdk.Event at 0x11e37b9e0: GDK_KEY_PRESS keyval=Escape>, True)=<GTKKeyEvent object, contents: \ {'modifiers': ['mod2'], 'group': 0, 'string': '\x1b', 'keyname': 'Escape', 'pressed': True, 'keyval': 65307, 'keycode': 71}> (..) toggling numlock
And no other modifiers end up triggering mod2. Maybe you just got confused by the fact that it is always present?
Key Events
As for the actual modifiers, I see the following key events:
- ctrl_l:
parse_key_event(<gtk.gdk.Event at 0x11e37bda0: GDK_KEY_PRESS keyval=Control_L>, True)=<GTKKeyEvent object, contents: \ {'modifiers': ['mod2'], 'group': 0, 'string': '', 'keyname': 'Control_L', 'pressed': True, 'keyval': 65507, 'keycode': 59}>
- alt_l (option_l):
client 7: parse_key_event(<gtk.gdk.Event at 0x11e37be68: GDK_KEY_PRESS keyval=Alt_L>, True)=<GTKKeyEvent object, contents: \ {'modifiers': ['mod2'], 'group': 1, 'string': '', 'keyname': 'Alt_L', 'pressed': True, 'keyval': 65513, 'keycode': 58}>
- command_l:
parse_key_event(<gtk.gdk.Event at 0x11e37bf08: GDK_KEY_PRESS keyval=Meta_L>, True)=<GTKKeyEvent object, contents: \ {'modifiers': ['mod2'], 'group': 0, 'string': '', 'keyname': 'Meta_L', 'pressed': True, 'keyval': 65511, 'keycode': 55}>
- command_r:
parse_key_event(<gtk.gdk.Event at 0x11e37ba30: GDK_KEY_PRESS keyval=Meta_R>, True)=<GTKKeyEvent object, contents: \ {'modifiers': ['mod2'], 'group': 0, 'string': '', 'keyname': 'Meta_R', 'pressed': True, 'keyval': 65512, 'keycode': 54}>
- alt_r:
parse_key_event(<gtk.gdk.Event at 0x11e37bda0: GDK_KEY_PRESS keyval=Alt_R>, True)=<GTKKeyEvent object, contents: \ {'modifiers': ['mod2'], 'group': 1, 'string': '', 'keyname': 'Alt_R', 'pressed': True, 'keyval': 65514, 'keycode': 61}>
- control_r:
parse_key_event(<gtk.gdk.Event at 0x11e37bd78: GDK_KEY_PRESS keyval=Control_R>, True)=<GTKKeyEvent object, contents: \ {'modifiers': ['mod2'], 'group': 0, 'string': '', 'keyname': 'Control_R', 'pressed': True, 'keyval': 65508, 'keycode': 62}>
I did plug in a non-apple standard keyboard, and found that alt and cmd were reversed!
xmodmap
$ DISPLAY=:100 xmodmap -pm xmodmap: up to 4 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), Alt_R (0x71), Alt_L (0x7d), Meta_L (0x9c) mod2 Num_Lock (0x4d) mod3 Super_L (0x73), Super_R (0x74), Super_L (0x7f) mod4 Hyper_L (0x80), Hyper_R (0x85) mod5 Mode_switch (0x8), ISO_Level3_Shift (0x7c)
So we have two keys mapped to the same modifier (mod1). And both will be swapped with control when "swap-keys" is enabled. So r16812 always swaps "Alt" for "Super" (hardcoded for now). r16811 also improves the consistency of the keymap data provided by the server side. (should be optional) Both changesets are bigger because of extra docstrings and we're trying harder to support legacy data formats.
With these changes in place, I can see:
- with swap keys: meta, super, control
- without swap keys: control, super, alt (slight difference as one emits "Alt" and the other "Meta"... but since those are both mapped to the same modifier, this should be fine)
Part of the problem is that we're relying on a default keymap then translating the macos key events to make them fit. Maybe it would be better to define a better keymap? Who uses "Hyper" anyway? Then we could have "Alt" and "Meta" mapped to separate modifiers for example.
@Ray Donnelly: does that work for you? A new beta macos build here: [http://xpra.org/beta/osx/] If not, please explain how I can reproduce the problem - I never use those keys for anything, so xev is as far as I got!
Not heard back, closing.
I am having a similar problem with xpra-2.2.4, so this fix did not help me. I do not use swap-keys.
Client: macOS High Sierra 10.13.2 (17C88), xpra-2.2.4 Server: CentOS Linux release 7.3.1611 (Core) Relevant Xpra settings: --swap-keys no --debug=keyboard,scroll
In X11 (XQuartz), I have the setting "Option keys send Alt_L and Alt_R" checked. I don't know if this affects Xpra, but I figured I'd mention it.
I think the fundamental problem is that the modifier flags (mod1, mod2, etc.) are sometimes being interpreted according to the mapping received from the server, rather than using the appropriate mapping for the client. In --swap-keys mode you are reading the META_MASK and CONTROL_MASK rather than interpreting the modifier flags directly, so --swap-keys avoids this problem.
Running xmodmap -pm on my Mac yields this, which looks quite different for me than it does for you in comment:9:
shift Shift_L (0x40), Shift_R (0x44) lock Caps_Lock (0x41) control Control_L (0x43), Control_R (0x46) mod1 Alt_L (0x42), Alt_R (0x45) mod2 Meta_L (0x3f), Meta_R (0x47) mod3 mod4 mod5
If I type Command-A, below is what appears in the log generated by Xpra. You can see that the Command key sets the mask as "flags GDK_MOD2_MASK | GDK_META_MASK". Meanwhile, Xpra thinks that "meta mod=mod1" and "num lock mod=mod2" (because this is the mapping set on the server).
2018-02-06 13:00:06,010 mask_to_names(<flags 0 of type GdkModifierType>)=['mod2'] 2018-02-06 13:00:06,010 parse_key_event(<gtk.gdk.Event at 0x10b687f30: GDK_KEY_PRESS keyval=Meta_L>, True)=<GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 0, 'string': '', 'keyname': 'Meta_L', 'pressed': True, 'keyval': 65511, 'keycode': 55}> 2018-02-06 13:00:06,010 handle_key_action(GLClientWindow(6 : gtk2.GLWindowBacking(6, (178, 178), None)), <GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 0, 'string': '', 'keyname': 'Meta_L', 'pressed': True, 'keyval': 65511, 'keycode': 55}>) wid=6 2018-02-06 13:00:06,011 send_key_action(6, <GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 0, 'string': '', 'keyname': 'Meta_L', 'pressed': True, 'keyval': 65511, 'keycode': 55}>) 2018-02-06 13:00:06,305 mask_to_names names=['mod2'], meta mod=mod1, control mod=control, num lock mod=mod2, num lock state=True 2018-02-06 13:00:06,306 mask_to_names(<flags GDK_MOD2_MASK | GDK_META_MASK of type GdkModifierType>)=['mod2'] 2018-02-06 13:00:06,306 parse_key_event(<gtk.gdk.Event at 0x10b687f30: GDK_KEY_PRESS keyval=a>, True)=<GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 0, 'string': 'a', 'keyname': 'a', 'pressed': True, 'keyval': 97, 'keycode': 0}> 2018-02-06 13:00:06,306 handle_key_action(GLClientWindow(6 : gtk2.GLWindowBacking(6, (178, 178), None)), <GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 0, 'string': 'a', 'keyname': 'a', 'pressed': True, 'keyval': 97, 'keycode': 0}>) wid=6 2018-02-06 13:00:06,306 send_key_action(6, <GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 0, 'string': 'a', 'keyname': 'a', 'pressed': True, 'keyval': 97, 'keycode': 0}>) 2018-02-06 13:00:06,408 mask_to_names names=['mod2'], meta mod=mod1, control mod=control, num lock mod=mod2, num lock state=True 2018-02-06 13:00:06,409 mask_to_names(<flags GDK_MOD2_MASK | GDK_META_MASK of type GdkModifierType>)=['mod2'] 2018-02-06 13:00:06,409 parse_key_event(<gtk.gdk.Event at 0x10b687f30: GDK_KEY_RELEASE keyval=a>, False)=<GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 0, 'string': 'a', 'keyname': 'a', 'pressed': False, 'keyval': 97, 'keycode': 0}> 2018-02-06 13:00:06,409 handle_key_action(GLClientWindow(6 : gtk2.GLWindowBacking(6, (178, 178), None)), <GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 0, 'string': 'a', 'keyname': 'a', 'pressed': False, 'keyval': 97, 'keycode': 0}>) wid=6 2018-02-06 13:00:06,409 send_key_action(6, <GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 0, 'string': 'a', 'keyname': 'a', 'pressed': False, 'keyval': 97, 'keycode': 0}>) 2018-02-06 13:00:06,666 mask_to_names names=['mod2'], meta mod=mod1, control mod=control, num lock mod=mod2, num lock state=True 2018-02-06 13:00:06,666 mask_to_names(<flags GDK_MOD2_MASK | GDK_META_MASK of type GdkModifierType>)=['mod2'] 2018-02-06 13:00:06,666 parse_key_event(<gtk.gdk.Event at 0x10b687f30: GDK_KEY_RELEASE keyval=Meta_L>, False)=<GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 0, 'string': '', 'keyname': 'Meta_L', 'pressed': False, 'keyval': 65511, 'keycode': 55}> 2018-02-06 13:00:06,666 handle_key_action(GLClientWindow(6 : gtk2.GLWindowBacking(6, (178, 178), None)), <GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 0, 'string': '', 'keyname': 'Meta_L', 'pressed': False, 'keyval': 65511, 'keycode': 55}>) wid=6 2018-02-06 13:00:06,666 send_key_action(6, <GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 0, 'string': '', 'keyname': 'Meta_L', 'pressed': False, 'keyval': 65511, 'keycode': 55}>)
Here's the output of xev through Xpra when I type Command-A. An Alt keypress is generated but the "state" field of the 'a' keypress remains as 0x10 (num lock/mod2 set, no other modifiers; no expected 'mod1' for 'Alt' modifier).
You can also see that the events are actually getting reordered: I typed Command-down, a-down, a-up, Command-up, but xev shows Alt-down, Alt-up, a-down, a-up. I think this might have something to do with the mod2 getting muddled up with num lock? At some point xpra interpreted the mod2 from Command as setting Num Lock, which was already set, so it had to generate a synthetic KeyRelease event?
KeyPress event, serial 36, synthetic NO, window 0x1000001, root 0x25d, subw 0x0, time 80082287, (160,161), root:(160,206), state 0x10, keycode 64 (keysym 0xffe9, Alt_L), same_screen YES, XLookupString gives 0 bytes: XmbLookupString gives 0 bytes: XFilterEvent returns: False KeyRelease event, serial 36, synthetic NO, window 0x1000001, root 0x25d, subw 0x0, time 80082535, (160,161), root:(160,206), state 0x18, keycode 64 (keysym 0xffe9, Alt_L), same_screen YES, XLookupString gives 0 bytes: XFilterEvent returns: False KeyPress event, serial 36, synthetic NO, window 0x1000001, root 0x25d, subw 0x0, time 80082536, (160,161), root:(160,206), state 0x10, keycode 38 (keysym 0x61, a), same_screen YES, XLookupString gives 1 bytes: (61) "a" XmbLookupString gives 1 bytes: (61) "a" XFilterEvent returns: False KeyRelease event, serial 36, synthetic NO, window 0x1000001, root 0x25d, subw 0x0, time 80082536, (160,161), root:(160,206), state 0x10, keycode 38 (keysym 0x61, a), same_screen YES, XLookupString gives 1 bytes: (61) "a" XFilterEvent returns: False
The other problem I'm having is with the Option (Alt) key. (If this is a separate issue I can file a separate ticket for it.)
On macOS Option is typically used to type accented characters. When I type Option keys in Xpra, it allows the Mac to turn the keystroke into an accented character rather than grabbing the raw keystroke.
When I type Option-A, here's what appears in the xpra log. You can see that xpra sends 'keyname':'aring' (Swedish 'a' with a ring over it: 'å') instead of just sending 'a' with the modifier.
2018-02-06 13:48:02,486 parse_key_event(<gtk.gdk.Event at 0x10b74daf8: GDK_KEY_PRESS keyval=Alt_L>, True)=<GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 1, 'string': '', 'keyname': 'Alt_L', 'pressed': True, 'keyval': 65513, 'keycode': 58}> 2018-02-06 13:48:02,486 handle_key_action(GLClientWindow(6 : gtk2.GLWindowBacking(6, (178, 178), None)), <GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 1, 'string': '', 'keyname': 'Alt_L', 'pressed': True, 'keyval': 65513, 'keycode': 58}>) wid=6 2018-02-06 13:48:02,487 swap keys: translating key '<GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 1, 'string': '', 'keyname': 'Alt_L', 'pressed': True, 'keyval': 65513, 'keycode': 58}>' to (115, 'Super_L') 2018-02-06 13:48:02,487 send_key_action(6, <GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 1, 'string': '', 'keyname': 'Super_L', 'pressed': True, 'keyval': 65513, 'keycode': 115}>) 2018-02-06 13:48:02,917 mask_to_names names=['mod1'], meta mod=mod1, control mod=control, num lock mod=mod2, num lock state=True 2018-02-06 13:48:02,918 mask_to_names(<flags GDK_MOD1_MASK of type GdkModifierType>)=['mod1', 'mod2'] 2018-02-06 13:48:02,918 parse_key_event(<gtk.gdk.Event at 0x10b74daf8: GDK_KEY_PRESS keyval=aring>, True)=<GTKKeyEvent object, contents: {'modifiers': ['mod1', 'mod2'], 'group': 1, 'string': '\xc3\xa5', 'keyname': 'aring', 'pressed': True, 'keyval': 229, 'keycode': 0}> 2018-02-06 13:48:02,919 handle_key_action(GLClientWindow(6 : gtk2.GLWindowBacking(6, (178, 178), None)), <GTKKeyEvent object, contents: {'modifiers': ['mod1', 'mod2'], 'group': 1, 'string': '\xc3\xa5', 'keyname': 'aring', 'pressed': True, 'keyval': 229, 'keycode': 0}>) wid=6 2018-02-06 13:48:02,919 send_key_action(6, <GTKKeyEvent object, contents: {'modifiers': ['mod1', 'mod2'], 'group': 1, 'string': '\xc3\xa5', 'keyname': 'aring', 'pressed': True, 'keyval': 229, 'keycode': 0}>) 2018-02-06 13:48:03,117 mask_to_names names=['mod1'], meta mod=mod1, control mod=control, num lock mod=mod2, num lock state=True 2018-02-06 13:48:03,117 mask_to_names(<flags GDK_MOD1_MASK of type GdkModifierType>)=['mod1', 'mod2'] 2018-02-06 13:48:03,117 parse_key_event(<gtk.gdk.Event at 0x10b74daf8: GDK_KEY_RELEASE keyval=aring>, False)=<GTKKeyEvent object, contents: {'modifiers': ['mod1', 'mod2'], 'group': 1, 'string': '\xc3\xa5', 'keyname': 'aring', 'pressed': False, 'keyval': 229, 'keycode': 0}> 2018-02-06 13:48:03,118 handle_key_action(GLClientWindow(6 : gtk2.GLWindowBacking(6, (178, 178), None)), <GTKKeyEvent object, contents: {'modifiers': ['mod1', 'mod2'], 'group': 1, 'string': '\xc3\xa5', 'keyname': 'aring', 'pressed': False, 'keyval': 229, 'keycode': 0}>) wid=6 2018-02-06 13:48:03,118 send_key_action(6, <GTKKeyEvent object, contents: {'modifiers': ['mod1', 'mod2'], 'group': 1, 'string': '\xc3\xa5', 'keyname': 'aring', 'pressed': False, 'keyval': 229, 'keycode': 0}>) 2018-02-06 13:48:03,541 mask_to_names names=['mod1'], meta mod=mod1, control mod=control, num lock mod=mod2, num lock state=True 2018-02-06 13:48:03,542 mask_to_names(<flags GDK_MOD1_MASK of type GdkModifierType>)=['mod1', 'mod2'] 2018-02-06 13:48:03,542 parse_key_event(<gtk.gdk.Event at 0x10b74daf8: GDK_KEY_RELEASE keyval=Alt_L>, False)=<GTKKeyEvent object, contents: {'modifiers': ['mod1', 'mod2'], 'group': 0, 'string': '', 'keyname': 'Alt_L', 'pressed': False, 'keyval': 65513, 'keycode': 58}> 2018-02-06 13:48:03,542 handle_key_action(GLClientWindow(6 : gtk2.GLWindowBacking(6, (178, 178), None)), <GTKKeyEvent object, contents: {'modifiers': ['mod1', 'mod2'], 'group': 0, 'string': '', 'keyname': 'Alt_L', 'pressed': False, 'keyval': 65513, 'keycode': 58}>) wid=6 2018-02-06 13:48:03,542 swap keys: translating key '<GTKKeyEvent object, contents: {'modifiers': ['mod1', 'mod2'], 'group': 0, 'string': '', 'keyname': 'Alt_L', 'pressed': False, 'keyval': 65513, 'keycode': 58}>' to (115, 'Super_L') 2018-02-06 13:48:03,543 send_key_action(6, <GTKKeyEvent object, contents: {'modifiers': ['mod1', 'mod2'], 'group': 0, 'string': '', 'keyname': 'Super_L', 'pressed': False, 'keyval': 65513, 'keycode': 115}>) 2018-02-06 13:48:05,960 mask_to_names names=[], meta mod=mod1, control mod=control, num lock mod=mod2, num lock state=True 2018-02-06 13:48:05,960 mask_to_names(<flags GDK_BUTTON1_MASK of type GdkModifierType>)=['mod2']
And here's the output of xev through Xpra when I type Option-a. You can see there's some similar weirdness going on where Super_L gets pressed and released before the 'a'. And then, of course, 'aring' instead of 'a'.
KeyPress event, serial 55, synthetic NO, window 0x1000001, root 0x25d, subw 0x0, time 348575285, (167,167), root:(192,498), state 0x2010, keycode 127 (keysym 0xffeb, Super_L), same_screen YES, XKeysymToKeycode returns keycode: 115 XLookupString gives 0 bytes: XmbLookupString gives 0 bytes: XFilterEvent returns: False KeyRelease event, serial 55, synthetic NO, window 0x1000001, root 0x25d, subw 0x0, time 348575653, (167,167), root:(192,498), state 0x2030, keycode 127 (keysym 0xffeb, Super_L), same_screen YES, XKeysymToKeycode returns keycode: 115 XLookupString gives 0 bytes: XFilterEvent returns: False KeyPress event, serial 55, synthetic NO, window 0x1000001, root 0x25d, subw 0x0, time 348575653, (167,167), root:(192,498), state 0x2010, keycode 113 (keysym 0xffea, Alt_R), same_screen YES, XLookupString gives 0 bytes: XmbLookupString gives 0 bytes: XFilterEvent returns: False KeyPress event, serial 55, synthetic NO, window 0x1000001, root 0x25d, subw 0x0, time 348575653, (167,167), root:(192,498), state 0x2018, keycode 38 (keysym 0xe5, aring), same_screen YES, XLookupString gives 2 bytes: (c3 a5) "å" XmbLookupString gives 2 bytes: (c3 a5) "å" XFilterEvent returns: False KeyRelease event, serial 55, synthetic NO, window 0x1000001, root 0x25d, subw 0x0, time 348575653, (167,167), root:(192,498), state 0x2018, keycode 38 (keysym 0xe5, aring), same_screen YES, XLookupString gives 2 bytes: (c3 a5) "å" XFilterEvent returns: False KeyRelease event, serial 55, synthetic NO, window 0x1000001, root 0x25d, subw 0x0, time 348577206, (167,167), root:(192,498), state 0x18, keycode 113 (keysym 0xffea, Alt_R), same_screen YES, XLookupString gives 0 bytes: XFilterEvent returns: False
In X11 (XQuartz), I have the setting "Option keys send Alt_L and Alt_R" checked. I don't know if this affects Xpra, but I figured I'd mention it. It shouldn't. Xpra uses the native API only, not X11. But thanks for mentioning it.
I think the fundamental problem is that the modifier flags (mod1, mod2, etc.) are sometimes being interpreted according to the mapping received from the server, rather than using the appropriate mapping for the client. Could be.
Running xmodmap -pm on my Mac yields this, which looks quite different for me than it does for you in comment:9 We care about the xmodmap in use by the server. This one you generated on the client using X11 is probably irrelevant. The modifier definitions seen by the client won't be going through X11 at all so they could be completely different, or not.
I think this might have something to do with the mod2 getting muddled up with num lock? At some point xpra interpreted the mod2 from Command as setting Num Lock, which was already set, so it had to generate a synthetic KeyRelease event? That would make sense. Having the server's "-d keyboard" log would tell us for sure why it decided to do that. Can you attach it here?
The other problem I'm having is with the Option (Alt) key. Is the key that gets printed or used the right one? Is the only problem the spurious
Super_L
press + release?
xpra.log
(160.5 KiB)xpra client log
xev.log
(21.5 KiB)output of xev, corresponds to xpra.log
Attached are the logs from the xpra client on my mac. Here's what I did:
- Started xev on server
- Started xpra client on Mac (logging starts here)
- Moused into xev
- Ctrl-A, Cmd-A, Option-A
- Ctrl-E, Cmd-E, Option-E
- Ctrl-M, Cmd-M, Option-M
- Moused out of xev
The other problem I'm having is with the Option (Alt) key. Is the key that gets printed or used the right one? Is the only problem the spurious Super_L press + release?
The main problem with the Option key is that it's sending accented characters with an Alt modifier rather than the raw character with Alt modifier. Option-a produces Alt-å, Option-e produces Alt-´, and Option-m produces Alt-µ.
You can see in the example in the log that the Option-e (which on Mac is a combination key for the acute accent ´) actually affects the next character Ctrl-m, causing it to be sent as Ctrl-ḿ.
I would expect the Mac special keyboard handling of the Option key to be disabled in Xpra, and just send Alt-a, Alt-e, and Alt-m to be interpreted by the server.
(BTW, I think I just noticed that the first Ctrl-a in my xpra/xev logs produced the combination Ctrl-á. I think I must have had an acute accent ´ queued up before I started capturing.)
I still don't see any server log.
xpra.2.log
(727.1 KiB)xpra server log
Whoops, I missed that you wanted a server log. Attached.
The test procedure was a little different in that I hit a few un-modified keystrokes before and after the modified keystrokes.
- Moused into xev
- A, Ctrl-A, Cmd-A, Option-A, A
- E, Ctrl-E, Cmd-E, Option-E, E
- M, Ctrl-M, Cmd-M, Option-M, M
- Moused around
- Ctrl-A, Cmd-A, Option-A
- Ctrl-E, Cmd-E, Option-E
- Ctrl-M, Cmd-M, Option-M
- Moused out
Thanks!
Fixes in r19088 + r19089 + r19090.
@emclain / Ray Donnelly: please try the latest 2.3 beta builds from [https://xpra.org/beta/osx/]. (ideally both the Python3 builds and the regular ones)
Not heard back, closing.
Issue migrated from trac ticket # 1609
component: platforms | priority: major | resolution: worksforme
2017-07-30 00:31:57: RayDonn created the issue