e712f1c
From 98065821bbf0178981b50515094f565b703fcaa8 Mon Sep 17 00:00:00 2001
e712f1c
From: Scott Talbert <swt@techie.net>
e712f1c
Date: Tue, 13 Sep 2016 13:24:12 +0200
e712f1c
Subject: [PATCH] Fix wxGetKeyState() on non-X11 wxGTK backends (e.g., Wayland)
e712f1c
e712f1c
wxGetKeyState() does not currently work on non-X11 GTK backends, and in some
e712f1c
cases it has been reported to crash.  It seems that the most likely use case
e712f1c
for wxGetKeyState() is to query the modifier keys, so on non-X11 backends, use
e712f1c
GTK+ calls to retrieve the modifier key state.
e712f1c
e712f1c
Non-modifier keys are not currently implemented, update the documentation to
e712f1c
mention this.
e712f1c
e712f1c
Closes https://github.com/wxWidgets/wxWidgets/pull/322
e712f1c
e712f1c
(this is a combined backport of 1033fb048dec849906f76ece25f154e6a61fde4e,
e712f1c
9f9c09e24a7f9d86ea51997bd4c55c1ddb7c3159 and
e712f1c
a18fe083cc91bee442863c8ab7f97d6549f2b75c from master)
e712f1c
---
e712f1c
 interface/wx/utils.h  |  3 +++
e712f1c
 src/unix/utilsx11.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++++++++--
e712f1c
 2 files changed, 63 insertions(+), 2 deletions(-)
e712f1c
e712f1c
diff --git a/interface/wx/utils.h b/interface/wx/utils.h
e712f1c
index 0bac1c0..f127a74 100644
e712f1c
--- a/interface/wx/utils.h
e712f1c
+++ b/interface/wx/utils.h
e712f1c
@@ -372,6 +372,9 @@ wxString wxGetDisplayName();
e712f1c
     Even though there are virtual key codes defined for mouse buttons, they
e712f1c
     cannot be used with this function currently.
e712f1c
 
e712f1c
+    In wxGTK, this function can be only used with modifier keys (@c WXK_ALT, @c
e712f1c
+    WXK_CONTROL and @c WXK_SHIFT) when not using X11 backend currently.
e712f1c
+
e712f1c
     @header{wx/utils.h}
e712f1c
 */
e712f1c
 bool wxGetKeyState(wxKeyCode key);
e712f1c
diff --git a/src/unix/utilsx11.cpp b/src/unix/utilsx11.cpp
e712f1c
index 6b35551..efc0837 100644
e712f1c
--- a/src/unix/utilsx11.cpp
e712f1c
+++ b/src/unix/utilsx11.cpp
e712f1c
@@ -809,7 +809,7 @@ WXKeySym wxCharCodeWXToX(int id)
e712f1c
 // check current state of a key
e712f1c
 // ----------------------------------------------------------------------------
e712f1c
 
e712f1c
-bool wxGetKeyState(wxKeyCode key)
e712f1c
+static bool wxGetKeyStateX11(wxKeyCode key)
e712f1c
 {
e712f1c
     wxASSERT_MSG(key != WXK_LBUTTON && key != WXK_RBUTTON && key !=
e712f1c
         WXK_MBUTTON, wxT("can't use wxGetKeyState() for mouse buttons"));
e712f1c
@@ -851,11 +851,69 @@ bool wxGetKeyState(wxKeyCode key)
e712f1c
     // with the least-significant bit in the byte representing key 8N.
e712f1c
     char key_vector[32];
e712f1c
     XQueryKeymap(pDisplay, key_vector);
e712f1c
-    return key_vector[keyCode >> 3] & (1 << (keyCode & 7));
e712f1c
+    return (key_vector[keyCode >> 3] & (1 << (keyCode & 7))) != 0;
e712f1c
 }
e712f1c
 
e712f1c
 #endif // !defined(__WXGTK__) || defined(GDK_WINDOWING_X11)
e712f1c
 
e712f1c
+// We need to use GDK functions when using wxGTK with a non-X11 backend, the
e712f1c
+// X11 code above can't work in this case.
e712f1c
+#ifdef __WXGTK__
e712f1c
+
e712f1c
+// gdk_keymap_get_modifier_state() is only available since 3.4
e712f1c
+#if GTK_CHECK_VERSION(3,4,0)
e712f1c
+
e712f1c
+#define wxHAS_GETKEYSTATE_GTK
e712f1c
+
e712f1c
+extern GtkWidget *wxGetRootWindow();
e712f1c
+
e712f1c
+static bool wxGetKeyStateGTK(wxKeyCode key)
e712f1c
+{
e712f1c
+    if (gtk_check_version(3,4,0) != NULL)
e712f1c
+        return false;
e712f1c
+
e712f1c
+    GdkDisplay* display = gtk_widget_get_display(wxGetRootWindow());
e712f1c
+    GdkKeymap* keymap = gdk_keymap_get_for_display(display);
e712f1c
+    guint state = gdk_keymap_get_modifier_state(keymap);
e712f1c
+    guint mask = 0;
e712f1c
+    switch (key)
e712f1c
+    {
e712f1c
+        case WXK_ALT:
e712f1c
+            mask = GDK_MOD1_MASK;
e712f1c
+            break;
e712f1c
+
e712f1c
+        case WXK_CONTROL:
e712f1c
+            mask = GDK_CONTROL_MASK;
e712f1c
+            break;
e712f1c
+
e712f1c
+        case WXK_SHIFT:
e712f1c
+            mask = GDK_SHIFT_MASK;
e712f1c
+            break;
e712f1c
+
e712f1c
+        default:
e712f1c
+            wxFAIL_MSG(wxS("Unsupported key, only modifiers can be used"));
e712f1c
+            return false;
e712f1c
+    }
e712f1c
+    return (state & mask) != 0;
e712f1c
+}
e712f1c
+
e712f1c
+#endif // GTK+ 3.4
e712f1c
+#endif // __WXGTK__
e712f1c
+
e712f1c
+bool wxGetKeyState(wxKeyCode key)
e712f1c
+{
e712f1c
+#ifdef wxHAS_GETKEYSTATE_GTK
e712f1c
+    GdkDisplay* display = gtk_widget_get_display(wxGetRootWindow());
e712f1c
+    const char* name = g_type_name(G_TYPE_FROM_INSTANCE(display));
e712f1c
+    if (strcmp(name, "GdkX11Display") != 0)
e712f1c
+    {
e712f1c
+        return wxGetKeyStateGTK(key);
e712f1c
+    }
e712f1c
+#endif // GTK+ 3.4+
e712f1c
+
e712f1c
+    return wxGetKeyStateX11(key);
e712f1c
+}
e712f1c
+
e712f1c
 // ----------------------------------------------------------------------------
e712f1c
 // Launch document with default app
e712f1c
 // ----------------------------------------------------------------------------