xpra icon
Bug tracker and wiki

Opened 3 weeks ago

Last modified 3 weeks ago

#1609 new defect

Command and Control keys on macOS host ends up as the same key on Linux

Reported by: Ray Donnelly Owned by: Ray Donnelly
Priority: major Milestone: 2.2
Component: android Version: trunk
Keywords: Cc:

Description

My host machine that I'm typing on is an MBP 2015 running macOS Sierra. My target machine is Fedora 26 Linux (on Apple hardware for those who care about that licensing detail) running VirtualBox? running OSX 10.9 so my goal is to have the keyboard work as if I were working directly on OSX 10.9 on the MBP.

I managed to hack the code so that the Command and Control keys are 'correctly' detected on OSX 10.9, however the Command key does not work as a modifier so I cannot press it in combination with any other key. Advice on how to debug this would be appreciated.

My hack patch is simple enough (but clearly a hack!):

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,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'
+        elif keycode == 54:
+            keycode = 133
+            keyname = 'Super_R'
         key_event = GTKKeyEvent()
         key_event.modifiers = self._client.mask_to_names(event.state)
         key_event.keyname = keyname or ""

The lack of Command-as-modifier *may* be related to https://bugzilla.gnome.org/show_bug.cgi?id=736125

If anyone wants to see how OSX interprets the key presses this post might help: https://mcmw.abilitynet.org.uk/apple-os-x-10-8-mountain-lion-using-the-on-screen-keyboard/

Is this likely something that can be fixed in the Python code or will it involve changes at the GTK+ level?

Suggestions very welcome. I'm so close to having a great OSX 10.9 development setup, just one pesky little modifier key away!

Change History (8)

comment:1 Changed 3 weeks ago by Ray Donnelly

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?

comment:2 Changed 3 weeks ago by Antoine Martin

Owner: changed from Antoine Martin to Ray Donnelly

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.

Last edited 3 weeks ago by Antoine Martin (previous) (diff)

comment:3 Changed 3 weeks ago by Ray Donnelly

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.

comment:4 Changed 3 weeks ago by Ray Donnelly

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

comment:5 Changed 3 weeks ago by Antoine Martin

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 and Meta_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 from KeyboardBase.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)
Last edited 3 weeks ago by Antoine Martin (previous) (diff)

comment:6 Changed 3 weeks ago by Ray Donnelly

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.

Last edited 3 weeks ago by Ray Donnelly (previous) (diff)

comment:7 Changed 3 weeks ago by Ray Donnelly

.. 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.

Last edited 3 weeks ago by Ray Donnelly (previous) (diff)

comment:8 Changed 3 weeks ago by Antoine Martin

Gotcha, that makes more sense now. I'll take a look.
You're right, we shouldn't be sending mod2 in any case.

Note: See TracTickets for help on using tickets.